From ad25ee36f00172f7d53242dc77c69fff7ced0755 Mon Sep 17 00:00:00 2001 From: Xingyuan Mo Date: Sun, 17 Dec 2023 13:29:01 +0200 Subject: [PATCH 0001/2255] wifi: ath10k: fix NULL pointer dereference in ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev() We should check whether the WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT tlv is present before accessing it, otherwise a null pointer deference error will occur. Fixes: dc405152bb64 ("ath10k: handle mgmt tx completion event") Signed-off-by: Xingyuan Mo Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231208043433.271449-1-hdthky0@gmail.com --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 6b6aa3c36744..0ce08e9a0a3d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -851,6 +851,10 @@ ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev(struct ath10k *ar, struct sk_buff *skb, } ev = tb[WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } arg->desc_id = ev->desc_id; arg->status = ev->status; From f5e6c0c4b0877e0ec0221df6c0041c0f39b6ce0f Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Sun, 17 Dec 2023 13:29:02 +0200 Subject: [PATCH 0002/2255] wifi: ath11k: refactor ath11k_wmi_tlv_parse_alloc() Since 'ath11k_wmi_tlv_parse_alloc()' always operates on 'skb->data, skb->len' tuple, it may be simplified to pass the only 'skb' argument instead (which also implies refactoring of 'ath11k_pull_bcn_tx_status_ev()' and 'ath11k_pull_chan_info_ev()' in the same way). Compile tested only. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://msgid.link/20231214161117.75145-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath11k/testmode.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.c | 73 +++++++++++----------- drivers/net/wireless/ath/ath11k/wmi.h | 4 +- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index 43bb23265d34..302d66092b97 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c @@ -198,7 +198,7 @@ static void ath11k_tm_wmi_event_segmented(struct ath11k_base *ab, u32 cmd_id, u16 length; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse ftm event tlv: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 8a65fa04b48d..89514899fcd5 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -238,8 +238,8 @@ static int ath11k_wmi_tlv_parse(struct ath11k_base *ar, const void **tb, (void *)tb); } -const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, - size_t len, gfp_t gfp) +const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, + struct sk_buff *skb, gfp_t gfp) { const void **tb; int ret; @@ -248,7 +248,7 @@ const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, if (!tb) return ERR_PTR(-ENOMEM); - ret = ath11k_wmi_tlv_parse(ab, tb, ptr, len); + ret = ath11k_wmi_tlv_parse(ab, tb, skb->data, skb->len); if (ret) { kfree(tb); return ERR_PTR(ret); @@ -3930,7 +3930,7 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk struct ath11k_vif *arvif; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5003,7 +5003,7 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf const struct wmi_vdev_start_resp_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5102,7 +5102,7 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n"); - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5278,7 +5278,7 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n"); - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5634,7 +5634,7 @@ static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff * const struct wmi_peer_delete_resp_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5666,7 +5666,7 @@ static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab, const struct wmi_vdev_delete_resp_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5686,15 +5686,15 @@ static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab, return 0; } -static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, void *evt_buf, - u32 len, u32 *vdev_id, - u32 *tx_status) +static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, + struct sk_buff *skb, + u32 *vdev_id, u32 *tx_status) { const void **tb; const struct wmi_bcn_tx_status_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5722,7 +5722,7 @@ static int ath11k_pull_vdev_stopped_param_tlv(struct ath11k_base *ab, struct sk_ const struct wmi_vdev_stopped_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5876,7 +5876,7 @@ static int ath11k_pull_mgmt_tx_compl_param_tlv(struct ath11k_base *ab, const struct wmi_mgmt_tx_compl_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6052,7 +6052,7 @@ static int ath11k_pull_scan_ev(struct ath11k_base *ab, struct sk_buff *skb, const struct wmi_scan_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6085,7 +6085,7 @@ static int ath11k_pull_peer_sta_kickout_ev(struct ath11k_base *ab, struct sk_buf const struct wmi_peer_sta_kickout_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6112,7 +6112,7 @@ static int ath11k_pull_roam_ev(struct ath11k_base *ab, struct sk_buff *skb, const struct wmi_roam_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6153,14 +6153,14 @@ 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); From 504130491026be9cf19f9de562172d340a06a2bb Mon Sep 17 00:00:00 2001 From: Wenli Looi Date: Sun, 17 Dec 2023 13:29:02 +0200 Subject: [PATCH 0003/2255] wifi: ath9k: delete some unused/duplicate macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rate macros are for AR9002 and not correct for AR9003. The AGC 3 macros are unused and have incorrect values, at least for QCN5502, where AR_AGC3_BASE should be 0x2de00. This change does not appear to affect the final binary. Signed-off-by: Wenli Looi Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20230629231625.951744-3-wlooi@ucalgary.ca --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 9 --------- drivers/net/wireless/ath/ath9k/reg_aic.h | 4 ---- 2 files changed, 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 57e2b4c89125..ad72a30b67c3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -851,8 +851,6 @@ #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN 0x0000000e #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN_S 1 -#define AR_PHY_POWER_TX_RATE1 0x9934 -#define AR_PHY_POWER_TX_RATE2 0x9938 #define AR_PHY_POWER_TX_RATE_MAX 0x993c #define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 #define PHY_AGC_CLR 0x10000000 @@ -1041,13 +1039,6 @@ #define AR_PHY_TX_IQCAL_STATUS_B2_FAILED 0x00000001 -/* - * AGC 3 Register Map - */ -#define AR_AGC3_BASE 0xce00 - -#define AR_PHY_RSSI_3 (AR_AGC3_BASE + 0x180) - /* GLB Registers */ #define AR_GLB_BASE 0x20000 #define AR_GLB_GPIO_CONTROL (AR_GLB_BASE) diff --git a/drivers/net/wireless/ath/ath9k/reg_aic.h b/drivers/net/wireless/ath/ath9k/reg_aic.h index 955147ab48a2..f50994910eae 100644 --- a/drivers/net/wireless/ath/ath9k/reg_aic.h +++ b/drivers/net/wireless/ath/ath9k/reg_aic.h @@ -17,10 +17,6 @@ #ifndef REG_AIC_H #define REG_AIC_H -#define AR_SM_BASE 0xa200 -#define AR_SM1_BASE 0xb200 -#define AR_AGC_BASE 0x9e00 - #define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0) #define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) #define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) From 27ce06d018cec6a5042069fb21b000753dd147d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0004/2255] wifi: ath9k: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff Johnson Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20231117093056.873834-11-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath9k/ahb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 9bfaadfa6c00..1a6697b6e3b4 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -144,7 +144,7 @@ static int ath_ahb_probe(struct platform_device *pdev) return ret; } -static int ath_ahb_remove(struct platform_device *pdev) +static void ath_ahb_remove(struct platform_device *pdev) { struct ieee80211_hw *hw = platform_get_drvdata(pdev); @@ -155,13 +155,11 @@ static int ath_ahb_remove(struct platform_device *pdev) free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); } - - return 0; } static struct platform_driver ath_ahb_driver = { .probe = ath_ahb_probe, - .remove = ath_ahb_remove, + .remove_new = ath_ahb_remove, .driver = { .name = "ath9k", }, From d6b27eb997ef9a2aa51633b3111bc4a04748e6d3 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0005/2255] wifi: ath9k: fix LNA selection in ath_ant_try_scan() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 'ath_ant_try_scan()', (most likely) the 2nd LNA's signal strength should be used in comparison against RSSI when selecting first LNA as the main one. Compile tested only. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20231211172502.25202-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath9k/antenna.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 988222cea9df..acc84e6711b0 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -643,7 +643,7 @@ static void ath_ant_try_scan(struct ath_ant_comb *antcomb, conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { + antcomb->rssi_lna2) { /* set to A-B */ conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; From d2eb318f4b6be1176e87ac3f9f8cc976be1c014b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0006/2255] wifi: ath10k: use flexible array in struct wmi_host_mem_chunks Currently struct wmi_host_mem_chunks defines: struct host_memory_chunk items[1]; Per the guidance in [1] this should be a flexible array. However there is a documented requirement: some fw revisions require at least 1 chunk regardless of count To satisfy this requirement, follow the guidance from [2] and wrap the array in a union which contains both the flexible array and a single instance of the underlying struct. Since the footprint of the struct is unchanged, no additional driver changes are required. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays [2] https://lore.kernel.org/linux-wireless/202308301529.AC90A9EF98@keescook/ Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-1-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9146df98fcee..833ce0251a2c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3069,7 +3069,10 @@ struct host_memory_chunk { struct wmi_host_mem_chunks { __le32 count; /* some fw revisions require at least 1 chunk regardless of count */ - struct host_memory_chunk items[1]; + union { + struct host_memory_chunk item; + DECLARE_FLEX_ARRAY(struct host_memory_chunk, items); + }; } __packed; struct wmi_init_cmd { From 72ca7c4073ac126be1c2341644838ef5f146b36b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0007/2255] wifi: ath10k: use flexible arrays for WMI start scan TLVs Currently ath10k defines the following struct: struct wmi_start_scan_tlvs { u8 tlvs[0]; } __packed; Per the guidance in [1] this should be a flexible array. However, a direct replace to u8 tlvs[] results in the compilation error: flexible array member in a struct with no named members This is because C99 6.7.2.1 (16) requires that a structure containing a flexible array member must have more than one named member. So rather than defining a separate struct wmi_start_scan_tlvs which contains the flexible tlvs[] array, just define the tlvs[] array where struct wmi_start_scan_tlvs is being used. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-2-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.c | 8 ++++---- drivers/net/wireless/ath/ath10k/wmi.h | 11 ++--------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 88befe92f95d..4d5aadbc7159 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -6927,14 +6927,14 @@ void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, } static void -ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs, +ath10k_wmi_put_start_scan_tlvs(u8 *tlvs, const struct wmi_start_scan_arg *arg) { struct wmi_ie_data *ie; struct wmi_chan_list *channels; struct wmi_ssid_list *ssids; struct wmi_bssid_list *bssids; - void *ptr = tlvs->tlvs; + void *ptr = tlvs; int i; if (arg->n_channels) { @@ -7012,7 +7012,7 @@ ath10k_wmi_op_gen_start_scan(struct ath10k *ar, cmd = (struct wmi_start_scan_cmd *)skb->data; ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); + ath10k_wmi_put_start_scan_tlvs(cmd->tlvs, arg); cmd->burst_duration_ms = __cpu_to_le32(0); @@ -7041,7 +7041,7 @@ ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar, cmd = (struct wmi_10x_start_scan_cmd *)skb->data; ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); + ath10k_wmi_put_start_scan_tlvs(cmd->tlvs, arg); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n"); return skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 833ce0251a2c..52a409ff94e7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3218,23 +3218,16 @@ struct wmi_start_scan_common { __le32 scan_ctrl_flags; } __packed; -struct wmi_start_scan_tlvs { - /* TLV parameters. These includes channel list, ssid list, bssid list, - * extra ies. - */ - u8 tlvs[0]; -} __packed; - struct wmi_start_scan_cmd { struct wmi_start_scan_common common; __le32 burst_duration_ms; - struct wmi_start_scan_tlvs tlvs; + u8 tlvs[]; } __packed; /* This is the definition from 10.X firmware branch */ struct wmi_10x_start_scan_cmd { struct wmi_start_scan_common common; - struct wmi_start_scan_tlvs tlvs; + u8 tlvs[]; } __packed; struct wmi_ssid_arg { From 26eb704a46f89d50a58ccb22b317b73ee85fa233 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0008/2255] wifi: ath10k: remove struct wmi_pdev_chanlist_update_event Currently struct wmi_pdev_chanlist_update_event defines: struct wmi_channel channel_list[1]; Per the guidance in [1] this should be a flexible array. However during conversion it was discovered that this struct is not used, so just remove the entire struct. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-3-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 52a409ff94e7..37a7d421bd86 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4256,13 +4256,6 @@ struct wmi_peer_sta_ps_state_chg_event { __le32 peer_ps_state; } __packed; -struct wmi_pdev_chanlist_update_event { - /* number of channels */ - __le32 num_chan; - /* array of channels */ - struct wmi_channel channel_list[1]; -} __packed; - #define WMI_MAX_DEBUG_MESG (sizeof(u32) * 32) struct wmi_debug_mesg_event { From b0c0794b05ec07a150bd39be3d43854a9dd93cad Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0009/2255] wifi: ath10k: remove unused template structs Currently both the wmi_bcn_tmpl_cmd and wmi_prb_tmpl_cmd structs define: u8 data[1]; Per the guidance in [1] both instances of this should be flexible arrays. However during conversion it was discovered that neither of these structs are actually used, so just remove them. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-4-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 37a7d421bd86..e16410e348ca 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5782,30 +5782,6 @@ struct wmi_bcn_prb_info { /* app IE */ } __packed; -struct wmi_bcn_tmpl_cmd { - /* unique id identifying the VDEV, generated by the caller */ - __le32 vdev_id; - /* TIM IE offset from the beginning of the template. */ - __le32 tim_ie_offset; - /* beacon probe capabilities and IEs */ - struct wmi_bcn_prb_info bcn_prb_info; - /* beacon buffer length */ - __le32 buf_len; - /* variable length data */ - u8 data[1]; -} __packed; - -struct wmi_prb_tmpl_cmd { - /* unique id identifying the VDEV, generated by the caller */ - __le32 vdev_id; - /* beacon probe capabilities and IEs */ - struct wmi_bcn_prb_info bcn_prb_info; - /* beacon buffer length */ - __le32 buf_len; - /* Variable length data */ - u8 data[1]; -} __packed; - enum wmi_sta_ps_mode { /* enable power save for the given STA VDEV */ WMI_STA_PS_MODE_DISABLED = 0, From cb188e862c1ce195ce8beaac10b554c33847f4c8 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0010/2255] wifi: ath10k: use flexible array in struct wmi_tdls_peer_capabilities Currently struct wmi_tdls_peer_capabilities defines: struct wmi_channel peer_chan_list[1]; Per the guidance in [1] this should be a flexible array, and at one point Gustavo was trying to fix this [2], but had questions about the correct behavior when the associated peer_chan_len is 0. I have been unable to determine if firmware requires that at least one record be present even if peer_chan_len is 0. But since that is the current behavior, follow the example from [3] and replace the one-element array with a union that contains both a flexible array and a single instance of the array element. This results in a struct that has the same footprint as the original, so no other driver changes are required. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays [2] https://lore.kernel.org/linux-wireless/626ae2e7-66f8-423b-b17f-e75c1a6d29b3@embeddedor.com/ [3] https://lore.kernel.org/linux-wireless/202308301529.AC90A9EF98@keescook/ Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-5-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e16410e348ca..b64b6e214bae 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -7162,7 +7162,13 @@ struct wmi_tdls_peer_capabilities { __le32 is_peer_responder; __le32 pref_offchan_num; __le32 pref_offchan_bw; - struct wmi_channel peer_chan_list[1]; + union { + /* to match legacy implementation allocate room for + * at least one record even if peer_chan_len is 0 + */ + struct wmi_channel peer_chan_min_allocation; + DECLARE_FLEX_ARRAY(struct wmi_channel, peer_chan_list); + }; } __packed; struct wmi_10_4_tdls_peer_update_cmd { From 6b9923f1f6d1b57a2ae932540a6273a0face54fe Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0011/2255] wifi: ath10k: remove duplicate memset() in 10.4 TDLS peer update In [1] it was identified that in ath10k_wmi_10_4_gen_tdls_peer_update() the memset(skb->data, 0, sizeof(*cmd)) is unnecessary since function ath10k_wmi_alloc_skb() already zeroes skb->data, so remove it. No functional changes, compile tested only. [1] https://lore.kernel.org/linux-wireless/626ae2e7-66f8-423b-b17f-e75c1a6d29b3@embeddedor.com/ Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-6-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4d5aadbc7159..0cfd9484c45e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -8918,8 +8918,6 @@ ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar, if (!skb) return ERR_PTR(-ENOMEM); - memset(skb->data, 0, sizeof(*cmd)); - cmd = (struct wmi_10_4_tdls_peer_update_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); ether_addr_copy(cmd->peer_macaddr.addr, arg->addr); From f4c2a9d62213cf7004db5c74ce12d26d63a23629 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 0012/2255] wifi: ath12k: add string type to search board data in board-2.bin for WCN7850 Currently ath12k only supports string type with bus, chip id and board id such as "bus=ahb,qmi-chip-id=1,qmi-board-id=4" for AHB bus chip and "bus=pci,qmi-chip-id=0,qmi-board-id=255" for PCI bus chip in board-2.bin. For WCN7850, it is not enough to distinguish all different chips. Add a new string type which includes bus, chip id, board id, vendor, device, subsystem-vendor and subsystem-device for WCN7850. ath12k will first load board-2.bin and searches in it for the board data with the above parameters. If matched with one board data, ath12k downloads it to firmware. And if not, downloads board.bin instead. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 27 ++++++++++++++++++++------ drivers/net/wireless/ath/ath12k/core.h | 13 +++++++++++++ drivers/net/wireless/ath/ath12k/pci.c | 10 ++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 6c01b282fcd3..b8027f76a02e 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -114,11 +114,26 @@ static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, scnprintf(variant, sizeof(variant), ",variant=%s", ab->qmi.target.bdf_ext); - scnprintf(name, name_len, - "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", - ath12k_bus_str(ab->hif.bus), - ab->qmi.target.chip_id, - ab->qmi.target.board_id, variant); + switch (ab->id.bdf_search) { + case ATH12K_BDF_SEARCH_BUS_AND_BOARD: + scnprintf(name, name_len, + "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", + ath12k_bus_str(ab->hif.bus), + ab->id.vendor, ab->id.device, + ab->id.subsystem_vendor, + ab->id.subsystem_device, + ab->qmi.target.chip_id, + ab->qmi.target.board_id, + variant); + break; + default: + scnprintf(name, name_len, + "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", + ath12k_bus_str(ab->hif.bus), + ab->qmi.target.chip_id, + ab->qmi.target.board_id, variant); + break; + } ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot using board name '%s'\n", name); @@ -356,7 +371,7 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab, return 0; } -#define BOARD_NAME_SIZE 100 +#define BOARD_NAME_SIZE 200 int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) { char boardname[BOARD_NAME_SIZE]; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 8458dc292821..385fda03e913 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -55,6 +55,11 @@ #define ATH12K_RECONFIGURE_TIMEOUT_HZ (10 * HZ) #define ATH12K_RECOVER_START_TIMEOUT_HZ (20 * HZ) +enum ath12k_bdf_search { + ATH12K_BDF_SEARCH_DEFAULT, + ATH12K_BDF_SEARCH_BUS_AND_BOARD, +}; + enum wme_ac { WME_AC_BE, WME_AC_BK, @@ -793,6 +798,14 @@ struct ath12k_base { /* true means radio is on */ bool rfkill_radio_on; + struct { + enum ath12k_bdf_search bdf_search; + u32 vendor; + u32 device; + u32 subsystem_vendor; + u32 subsystem_device; + } id; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index f0d2e2d8719c..76438b3afd55 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1310,6 +1310,15 @@ static int ath12k_pci_probe(struct pci_dev *pdev, goto err_free_core; } + ath12k_dbg(ab, ATH12K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + + ab->id.vendor = pdev->vendor; + ab->id.device = pdev->device; + ab->id.subsystem_vendor = pdev->subsystem_vendor; + ab->id.subsystem_device = pdev->subsystem_device; + switch (pci_dev->device) { case QCN9274_DEVICE_ID: ab_pci->msi_config = &ath12k_msi_config[0]; @@ -1333,6 +1342,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, } break; case WCN7850_DEVICE_ID: + ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD; ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; From 7173972a2eb1107ae3dc076f1cd27abce132e027 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 0013/2255] wifi: ath12k: add fallback board name without variant while searching board-2.bin Currently a variant value read from DT or SMBIOS is considered while searching board-2.bin, this may fail because not all board-2.bin files contains that symbol. Add fallback board name which removes variant value and searches again in board-2.bin when fails to increase boot up success rate. dmesg log after this patch: [169547.248472] ath12k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262,variant=test' [169547.248565] ath12k_pci 0000:05:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 180324 [169547.248568] ath12k_pci 0000:05:00.0: board name [169547.248570] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248571] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248572] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248574] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248575] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248576] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [169547.248577] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 [169547.248578] ath12k_pci 0000:05:00.0: board name [169547.248579] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248581] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248582] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248583] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248584] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248585] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [169547.248587] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 ard-id=266 [169547.248588] ath12k_pci 0000:05:00.0: board name [169547.248589] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248590] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248591] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248592] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248594] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248595] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 31 38 2c 71 6d 69 2d 62 chip-id=18,qmi-b [169547.248596] ath12k_pci 0000:05:00.0: 00000060: 6f 61 72 64 2d 69 64 3d 32 36 36 oard-id=266 [169547.248597] ath12k_pci 0000:05:00.0: failed to fetch board data for bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262,variant=test from ath12k/WCN7850/hw2.0/board-2.bin [169547.248476] ath12k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [169547.248634] ath12k_pci 0000:05:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 180324 [169547.248636] ath12k_pci 0000:05:00.0: board name [169547.248637] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248638] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248639] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248641] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248642] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248643] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [169547.248645] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 [169547.248646] ath12k_pci 0000:05:00.0: boot found match for name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [169547.248647] ath12k_pci 0000:05:00.0: boot found board data for 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [169547.248649] ath12k_pci 0000:05:00.0: using board api 2 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 48 ++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index b8027f76a02e..672aa174704b 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -104,13 +104,13 @@ int ath12k_core_resume(struct ath12k_base *ab) return 0; } -static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, - size_t name_len) +static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, + size_t name_len, bool with_variant) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; - if (ab->qmi.target.bdf_ext[0] != '\0') + if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", ab->qmi.target.bdf_ext); @@ -140,6 +140,18 @@ static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, return 0; } +static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, true); +} + +static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, false); +} + const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, const char *file) { @@ -343,7 +355,7 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, out: if (!bd->data || !bd->len) { - ath12k_err(ab, + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to fetch board data for %s from %s\n", boardname, filepath); ret = -ENODATA; @@ -374,11 +386,14 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab, #define BOARD_NAME_SIZE 200 int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) { - char boardname[BOARD_NAME_SIZE]; + char boardname[BOARD_NAME_SIZE], fallback_boardname[BOARD_NAME_SIZE]; + char *filename, filepath[100]; int bd_api; int ret; - ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); + filename = ATH12K_BOARD_API2_FILE; + + ret = ath12k_core_create_board_name(ab, boardname, sizeof(boardname)); if (ret) { ath12k_err(ab, "failed to create board name: %d", ret); return ret; @@ -389,10 +404,29 @@ int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) if (!ret) goto success; + ret = ath12k_core_create_fallback_board_name(ab, fallback_boardname, + sizeof(fallback_boardname)); + if (ret) { + ath12k_err(ab, "failed to create fallback board name: %d", ret); + return ret; + } + + ret = ath12k_core_fetch_board_data_api_n(ab, bd, fallback_boardname); + if (!ret) + goto success; + bd_api = 1; ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_DEFAULT_BOARD_FILE); if (ret) { - ath12k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n", + ath12k_core_create_firmware_path(ab, filename, + filepath, sizeof(filepath)); + ath12k_err(ab, "failed to fetch board data for %s from %s\n", + boardname, filepath); + if (memcmp(boardname, fallback_boardname, strlen(boardname))) + ath12k_err(ab, "failed to fetch board data for %s from %s\n", + fallback_boardname, filepath); + + ath12k_err(ab, "failed to fetch board.bin from %s\n", ab->hw_params->fw.dir); return ret; } From 97474e5f54243be13d72cbda50624f0114213c7d Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 0014/2255] wifi: ath12k: remove unused ATH12K_BD_IE_BOARD_EXT Currently ATH12K_BD_IE_BOARD_EXT is not used, so remove it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index d2622bfef942..130d99f7e426 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -245,7 +245,6 @@ enum ath12k_bd_ie_board_type { enum ath12k_bd_ie_type { /* contains sub IEs of enum ath12k_bd_ie_board_type */ ATH12K_BD_IE_BOARD = 0, - ATH12K_BD_IE_BOARD_EXT = 1, }; struct ath12k_hw_regs { From 511207452221a94242664be47c4ceb63d5c6b293 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 0015/2255] wifi: ath12k: add support to search regdb data in board-2.bin for WCN7850 Currently ath12k only downloads the same regdb.bin file for all WCN7850 chips, actually ath12k needs to distinguish all different WCN7850 chips. This is to re-use the string type which includes bus, chip id, board id, vendor, device, subsystem-vendor, subsystem-device and variant for WCN7850 to distinguish different regdb in board-2.bin. ath12k will first load board-2.bin and search in it for the regdb data with the above parameters. If matched with one regdb data, download it to firmware. And if not, download regdb.bin instead. Add enum value ATH12K_BD_IE_REGDB and enum type ath12k_bd_ie_regdb_type to distinguish regdb data and board data since they are in the same file board-2.bin. Test log: [ 3833.091948] ath12k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [ 3833.092072] ath12k_pci 0000:05:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 205316 [ 3833.092079] ath12k_pci 0000:05:00.0: board name [ 3833.092083] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092088] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 31 -id=1 [ 3833.092091] ath12k_pci 0000:05:00.0: board name [ 3833.092095] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092099] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 32 -id=2 [ 3833.092102] ath12k_pci 0000:05:00.0: board name [ 3833.092105] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092109] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 33 -id=3 [ 3833.092112] ath12k_pci 0000:05:00.0: board name [ 3833.092116] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [ 3833.092119] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [ 3833.092123] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [ 3833.092126] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [ 3833.092130] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [ 3833.092133] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [ 3833.092137] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 2c 76 61 72 69 61 ard-id=266,varia [ 3833.092140] ath12k_pci 0000:05:00.0: 00000070: 6e 74 3d 48 50 5f 47 38 5f 4c 61 6e 63 69 61 31 nt=HP_G8_Lancia1 [ 3833.092144] ath12k_pci 0000:05:00.0: 00000080: 35 5 [ 3833.092147] ath12k_pci 0000:05:00.0: board name [ 3833.092150] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [ 3833.092154] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [ 3833.092157] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [ 3833.092161] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [ 3833.092165] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [ 3833.092168] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [ 3833.092172] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 ard-id=266 [ 3833.092206] ath12k_pci 0000:05:00.0: board name [ 3833.092209] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [ 3833.092213] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [ 3833.092216] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [ 3833.092220] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [ 3833.092223] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [ 3833.092227] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [ 3833.092230] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 [ 3833.092234] ath12k_pci 0000:05:00.0: boot found match regdb data for name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [ 3833.092238] ath12k_pci 0000:05:00.0: board name [ 3833.092241] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092245] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 31 31 -id=11 [ 3833.092248] ath12k_pci 0000:05:00.0: board name [ 3833.092251] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092255] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 32 32 -id=22 [ 3833.092258] ath12k_pci 0000:05:00.0: board name [ 3833.092261] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092265] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 33 33 -id=33 [ 3833.092268] ath12k_pci 0000:05:00.0: boot found regdb data for 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [ 3833.092272] ath12k_pci 0000:05:00.0: fetched regdb Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 96 +++++++++++++++++++------- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/hw.h | 19 +++++ drivers/net/wireless/ath/ath12k/qmi.c | 3 +- 4 files changed, 92 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 672aa174704b..80fce8099bdf 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -186,7 +186,9 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, struct ath12k_board_data *bd, const void *buf, size_t buf_len, const char *boardname, - int bd_ie_type) + int ie_id, + int name_id, + int data_id) { const struct ath12k_fw_ie *hdr; bool name_match_found; @@ -196,7 +198,7 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, name_match_found = false; - /* go through ATH12K_BD_IE_BOARD_ elements */ + /* go through ATH12K_BD_IE_BOARD_/ATH12K_BD_IE_REGDB_ elements */ while (buf_len > sizeof(struct ath12k_fw_ie)) { hdr = buf; board_ie_id = le32_to_cpu(hdr->id); @@ -207,48 +209,50 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, buf += sizeof(*hdr); if (buf_len < ALIGN(board_ie_len, 4)) { - ath12k_err(ab, "invalid ATH12K_BD_IE_BOARD length: %zu < %zu\n", + ath12k_err(ab, "invalid %s length: %zu < %zu\n", + ath12k_bd_ie_type_str(ie_id), buf_len, ALIGN(board_ie_len, 4)); ret = -EINVAL; goto out; } - switch (board_ie_id) { - case ATH12K_BD_IE_BOARD_NAME: + if (board_ie_id == name_id) { ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "board name", "", board_ie_data, board_ie_len); if (board_ie_len != strlen(boardname)) - break; + goto next; ret = memcmp(board_ie_data, boardname, strlen(boardname)); if (ret) - break; + goto next; name_match_found = true; ath12k_dbg(ab, ATH12K_DBG_BOOT, - "boot found match for name '%s'", + "boot found match %s for name '%s'", + ath12k_bd_ie_type_str(ie_id), boardname); - break; - case ATH12K_BD_IE_BOARD_DATA: + } else if (board_ie_id == data_id) { if (!name_match_found) /* no match found */ - break; + goto next; ath12k_dbg(ab, ATH12K_DBG_BOOT, - "boot found board data for '%s'", boardname); + "boot found %s for '%s'", + ath12k_bd_ie_type_str(ie_id), + boardname); bd->data = board_ie_data; bd->len = board_ie_len; ret = 0; goto out; - default: - ath12k_warn(ab, "unknown ATH12K_BD_IE_BOARD found: %d\n", + } else { + ath12k_warn(ab, "unknown %s id found: %d\n", + ath12k_bd_ie_type_str(ie_id), board_ie_id); - break; } - +next: /* jump over the padding */ board_ie_len = ALIGN(board_ie_len, 4); @@ -265,7 +269,10 @@ 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; From 52f8c45fa36df0754b4562b7b535be8475304ebe Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 0016/2255] wifi: ath12k: support default regdb while searching board-2.bin for WCN7850 Sometimes board-2.bin does not have the regdb data which matches the parameters such as vendor, device, subsystem-vendor, subsystem-device etc. Add default regdb data with only 'bus=%s' into board-2.bin for WCN7850, then ath12k uses 'bus=pci' to search regdb data in board-2.bin for WCN7850. [ 46.114895] ath12k_pci 0000:03:00.0: boot using board name 'bus=pci,vendor=17cb,device=1107,subsystem-vendor=17cb,subsystem-device=3378,qmi-chip-id=2,qmi-board-id=260' [ 46.118167] ath12k_pci 0000:03:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 380280 [ 46.118173] ath12k_pci 0000:03:00.0: board name [ 46.118176] ath12k_pci 0000:03:00.0: 00000000: 62 75 73 3d 70 63 69 bus=pci [ 46.118179] ath12k_pci 0000:03:00.0: failed to fetch regdb data for bus=pci,vendor=17cb,device=1107,subsystem-vendor=17cb,subsystem-device=3378,qmi-chip-id=2,qmi-board-id=260 from ath12k/WCN7850/hw2.0/board-2.bin [ 46.118239] ath12k_pci 0000:03:00.0: boot using board name 'bus=pci' [ 46.119842] ath12k_pci 0000:03:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 380280 [ 46.119847] ath12k_pci 0000:03:00.0: board name [ 46.119849] ath12k_pci 0000:03:00.0: 00000000: 62 75 73 3d 70 63 69 bus=pci [ 46.119852] ath12k_pci 0000:03:00.0: boot found match regdb data for name 'bus=pci' [ 46.119855] ath12k_pci 0000:03:00.0: boot found regdb data for 'bus=pci' [ 46.119857] ath12k_pci 0000:03:00.0: fetched regdb Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-6-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 53 +++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 80fce8099bdf..d73e2d33a41e 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -105,7 +105,8 @@ int ath12k_core_resume(struct ath12k_base *ab) } static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, - size_t name_len, bool with_variant) + size_t name_len, bool with_variant, + bool bus_type_mode) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; @@ -116,15 +117,20 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, switch (ab->id.bdf_search) { case ATH12K_BDF_SEARCH_BUS_AND_BOARD: - scnprintf(name, name_len, - "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", - ath12k_bus_str(ab->hif.bus), - ab->id.vendor, ab->id.device, - ab->id.subsystem_vendor, - ab->id.subsystem_device, - ab->qmi.target.chip_id, - ab->qmi.target.board_id, - variant); + if (bus_type_mode) + scnprintf(name, name_len, + "bus=%s", + ath12k_bus_str(ab->hif.bus)); + else + scnprintf(name, name_len, + "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", + ath12k_bus_str(ab->hif.bus), + ab->id.vendor, ab->id.device, + ab->id.subsystem_vendor, + ab->id.subsystem_device, + ab->qmi.target.chip_id, + ab->qmi.target.board_id, + variant); break; default: scnprintf(name, name_len, @@ -143,13 +149,19 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, size_t name_len) { - return __ath12k_core_create_board_name(ab, name, name_len, true); + return __ath12k_core_create_board_name(ab, name, name_len, true, false); } static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name, size_t name_len) { - return __ath12k_core_create_board_name(ab, name, name_len, false); + return __ath12k_core_create_board_name(ab, name, name_len, false, false); +} + +static int ath12k_core_create_bus_type_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, false, true); } const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, @@ -453,7 +465,7 @@ 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", From e7ab40b733094dfc50dad58bbce81f544af1d8cc Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 09:26:46 -0800 Subject: [PATCH 0017/2255] wifi: ath12k: Make QMI message rules const Commit ff6d365898d4 ("soc: qcom: qmi: use const for struct qmi_elem_info") allows QMI message encoding/decoding rules to be const, so do that for ath12k. Compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231217-ath12k-qmi_elem_info-const-v1-1-7ebb0de0a2b6@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 64 +++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index f29291064e20..536856234f3b 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -17,7 +17,7 @@ #define PLATFORM_CAP_PCIE_GLOBAL_RESET 0x08 #define ATH12K_QMI_MAX_CHUNK_SIZE 2097152 -static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { +static const struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, @@ -61,7 +61,7 @@ static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -511,7 +511,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -528,7 +528,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -753,7 +753,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -789,7 +789,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -821,7 +821,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -863,7 +863,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, @@ -890,7 +890,7 @@ static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -930,7 +930,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, @@ -957,7 +957,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -975,7 +975,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, @@ -983,7 +983,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1009,7 +1009,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1026,7 +1026,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1042,7 +1042,7 @@ static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -1068,7 +1068,7 @@ static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1094,7 +1094,7 @@ static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1348,7 +1348,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, @@ -1483,7 +1483,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1501,7 +1501,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -1525,7 +1525,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1542,7 +1542,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1595,7 +1595,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1630,7 +1630,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, @@ -1654,7 +1654,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1671,7 +1671,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1706,7 +1706,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1724,7 +1724,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -1862,7 +1862,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1879,14 +1879,14 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, }, }; -static struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, From 9496d62f3877bc0f97b415bc04af98d092878026 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Wed, 3 Jan 2024 09:23:46 +0800 Subject: [PATCH 0018/2255] wifi: rtw89: pci: use DBI function for 8852AE/8852BE/8851BE Sometimes driver can't use kernel API pci_read/write_config_byte to access the PCI config space of above address 0x100 due to the negotiated PCI setting. 8852AE/8852BE/8851BE provide another way called DBI function, which belongs to WiFi mac and could access all PCI config space for this case. Link: https://lore.kernel.org/linux-wireless/79fe81b7db7148b9a7da2353c16d70fb@realtek.com/T/#t Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240103012346.6822-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 69 +++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/pci.h | 1 + 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 769f1ce62ebc..9943ed856248 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1907,22 +1907,87 @@ static int rtw89_write16_mdio_clr(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u return 0; } +static int rtw89_dbi_write8(struct rtw89_dev *rtwdev, u16 addr, u8 data) +{ + u16 addr_2lsb = addr & B_AX_DBI_2LSB; + u16 write_addr; + u8 flag; + int ret; + + write_addr = addr & B_AX_DBI_ADDR_MSK; + write_addr |= u16_encode_bits(BIT(addr_2lsb), B_AX_DBI_WREN_MSK); + rtw89_write8(rtwdev, R_AX_DBI_WDATA + addr_2lsb, data); + rtw89_write16(rtwdev, R_AX_DBI_FLAG, write_addr); + rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_WFLAG >> 16); + + ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10, + 10 * RTW89_PCI_WR_RETRY_CNT, false, + rtwdev, R_AX_DBI_FLAG + 2); + if (ret) + rtw89_err(rtwdev, "failed to write DBI register, addr=0x%X\n", + addr); + + return ret; +} + +static int rtw89_dbi_read8(struct rtw89_dev *rtwdev, u16 addr, u8 *value) +{ + u16 read_addr = addr & B_AX_DBI_ADDR_MSK; + u8 flag; + int ret; + + rtw89_write16(rtwdev, R_AX_DBI_FLAG, read_addr); + rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_RFLAG >> 16); + + ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10, + 10 * RTW89_PCI_WR_RETRY_CNT, false, + rtwdev, R_AX_DBI_FLAG + 2); + if (ret) { + rtw89_err(rtwdev, "failed to read DBI register, addr=0x%X\n", + addr); + return ret; + } + + read_addr = R_AX_DBI_RDATA + (addr & 3); + *value = rtw89_read8(rtwdev, read_addr); + + return 0; +} + static int rtw89_pci_write_config_byte(struct rtw89_dev *rtwdev, u16 addr, u8 data) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; struct pci_dev *pdev = rtwpci->pdev; + int ret; - return pci_write_config_byte(pdev, addr, data); + ret = pci_write_config_byte(pdev, addr, data); + if (!ret) + return 0; + + if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) + ret = rtw89_dbi_write8(rtwdev, addr, data); + + return ret; } static int rtw89_pci_read_config_byte(struct rtw89_dev *rtwdev, u16 addr, u8 *value) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; struct pci_dev *pdev = rtwpci->pdev; + int ret; - return pci_read_config_byte(pdev, addr, value); + ret = pci_read_config_byte(pdev, addr, value); + if (!ret) + return 0; + + if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) + ret = rtw89_dbi_read8(rtwdev, addr, value); + + return ret; } static int rtw89_pci_config_byte_set(struct rtw89_dev *rtwdev, u16 addr, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index ca5de77fee90..1fb7c209fa0d 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -42,6 +42,7 @@ #define B_AX_DBI_WFLAG BIT(16) #define B_AX_DBI_WREN_MSK GENMASK(15, 12) #define B_AX_DBI_ADDR_MSK GENMASK(11, 2) +#define B_AX_DBI_2LSB GENMASK(1, 0) #define R_AX_DBI_WDATA 0x1094 #define R_AX_DBI_RDATA 0x1098 From ac770f07a93bd70d1f371ade465e2fe282d19fa0 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 3 Jan 2024 09:41:13 +0800 Subject: [PATCH 0019/2255] wifi: rtw89: 8852b: update TX power tables to R36 Update TX power tables to RF version R36. Mainly update configurations for Canada 5.9 GHz (U-NII 4) according to IC (Industry Canada) certification. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240103014114.9558-1-pkshih@realtek.com --- .../wireless/realtek/rtw89/rtw8852b_table.c | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c index d2ce16e98bac..07945d06dc59 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c @@ -16936,7 +16936,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_WW][8] = 52, [0][0][1][0][RTW89_WW][10] = 52, [0][0][1][0][RTW89_WW][12] = 52, - [0][0][1][0][RTW89_WW][14] = 1, + [0][0][1][0][RTW89_WW][14] = 52, [0][0][1][0][RTW89_WW][15] = 52, [0][0][1][0][RTW89_WW][17] = 52, [0][0][1][0][RTW89_WW][19] = 52, @@ -16954,10 +16954,10 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_WW][42] = 28, [0][0][1][0][RTW89_WW][44] = 28, [0][0][1][0][RTW89_WW][46] = 28, - [0][0][1][0][RTW89_WW][48] = 78, - [0][0][1][0][RTW89_WW][50] = 78, - [0][0][1][0][RTW89_WW][52] = 78, - [0][1][1][0][RTW89_WW][0] = 1, + [0][0][1][0][RTW89_WW][48] = 76, + [0][0][1][0][RTW89_WW][50] = 76, + [0][0][1][0][RTW89_WW][52] = 76, + [0][1][1][0][RTW89_WW][0] = 30, [0][1][1][0][RTW89_WW][2] = 32, [0][1][1][0][RTW89_WW][4] = 30, [0][1][1][0][RTW89_WW][6] = 30, @@ -16982,9 +16982,9 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_WW][42] = 16, [0][1][1][0][RTW89_WW][44] = 16, [0][1][1][0][RTW89_WW][46] = 16, - [0][1][1][0][RTW89_WW][48] = 56, - [0][1][1][0][RTW89_WW][50] = 56, - [0][1][1][0][RTW89_WW][52] = 56, + [0][1][1][0][RTW89_WW][48] = 50, + [0][1][1][0][RTW89_WW][50] = 50, + [0][1][1][0][RTW89_WW][52] = 50, [0][0][2][0][RTW89_WW][0] = 42, [0][0][2][0][RTW89_WW][2] = 42, [0][0][2][0][RTW89_WW][4] = 42, @@ -17038,9 +17038,9 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_WW][42] = 16, [0][1][2][0][RTW89_WW][44] = 16, [0][1][2][0][RTW89_WW][46] = 16, - [0][1][2][0][RTW89_WW][48] = 58, - [0][1][2][0][RTW89_WW][50] = 58, - [0][1][2][0][RTW89_WW][52] = 58, + [0][1][2][0][RTW89_WW][48] = 50, + [0][1][2][0][RTW89_WW][50] = 52, + [0][1][2][0][RTW89_WW][52] = 52, [0][1][2][1][RTW89_WW][0] = 14, [0][1][2][1][RTW89_WW][2] = 14, [0][1][2][1][RTW89_WW][4] = 14, @@ -17066,9 +17066,9 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_WW][42] = 4, [0][1][2][1][RTW89_WW][44] = 4, [0][1][2][1][RTW89_WW][46] = 4, - [0][1][2][1][RTW89_WW][48] = 58, - [0][1][2][1][RTW89_WW][50] = 58, - [0][1][2][1][RTW89_WW][52] = 58, + [0][1][2][1][RTW89_WW][48] = 50, + [0][1][2][1][RTW89_WW][50] = 52, + [0][1][2][1][RTW89_WW][52] = 52, [1][0][2][0][RTW89_WW][1] = 42, [1][0][2][0][RTW89_WW][5] = 42, [1][0][2][0][RTW89_WW][9] = 52, @@ -17095,8 +17095,8 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_WW][36] = 50, [1][1][2][0][RTW89_WW][39] = 16, [1][1][2][0][RTW89_WW][43] = 16, - [1][1][2][0][RTW89_WW][47] = 68, - [1][1][2][0][RTW89_WW][51] = 66, + [1][1][2][0][RTW89_WW][47] = 62, + [1][1][2][0][RTW89_WW][51] = 62, [1][1][2][1][RTW89_WW][1] = 16, [1][1][2][1][RTW89_WW][5] = 16, [1][1][2][1][RTW89_WW][9] = 28, @@ -17109,8 +17109,8 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_WW][36] = 36, [1][1][2][1][RTW89_WW][39] = 4, [1][1][2][1][RTW89_WW][43] = 4, - [1][1][2][1][RTW89_WW][47] = 68, - [1][1][2][1][RTW89_WW][51] = 66, + [1][1][2][1][RTW89_WW][47] = 62, + [1][1][2][1][RTW89_WW][51] = 62, [2][0][2][0][RTW89_WW][3] = 42, [2][0][2][0][RTW89_WW][11] = 52, [2][0][2][0][RTW89_WW][18] = 52, @@ -17227,7 +17227,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_MEXICO][14] = 78, [0][0][1][0][RTW89_CN][14] = 58, [0][0][1][0][RTW89_QATAR][14] = 58, - [0][0][1][0][RTW89_UK][14] = 1, + [0][0][1][0][RTW89_UK][14] = 58, [0][0][1][0][RTW89_FCC][15] = 76, [0][0][1][0][RTW89_ETSI][15] = 58, [0][0][1][0][RTW89_MKK][15] = 76, @@ -17435,7 +17435,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][48] = 78, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, - [0][0][1][0][RTW89_IC][48] = 127, + [0][0][1][0][RTW89_IC][48] = 76, [0][0][1][0][RTW89_KCC][48] = 127, [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CHILE][48] = 127, @@ -17447,7 +17447,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][50] = 78, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, - [0][0][1][0][RTW89_IC][50] = 127, + [0][0][1][0][RTW89_IC][50] = 76, [0][0][1][0][RTW89_KCC][50] = 127, [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CHILE][50] = 127, @@ -17459,7 +17459,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][52] = 78, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, - [0][0][1][0][RTW89_IC][52] = 127, + [0][0][1][0][RTW89_IC][52] = 76, [0][0][1][0][RTW89_KCC][52] = 127, [0][0][1][0][RTW89_ACMA][52] = 127, [0][0][1][0][RTW89_CHILE][52] = 127, @@ -17479,7 +17479,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_MEXICO][0] = 50, [0][1][1][0][RTW89_CN][0] = 46, [0][1][1][0][RTW89_QATAR][0] = 46, - [0][1][1][0][RTW89_UK][0] = 1, + [0][1][1][0][RTW89_UK][0] = 46, [0][1][1][0][RTW89_FCC][2] = 68, [0][1][1][0][RTW89_ETSI][2] = 46, [0][1][1][0][RTW89_MKK][2] = 48, @@ -17771,7 +17771,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_FCC][48] = 56, [0][1][1][0][RTW89_ETSI][48] = 127, [0][1][1][0][RTW89_MKK][48] = 127, - [0][1][1][0][RTW89_IC][48] = 127, + [0][1][1][0][RTW89_IC][48] = 50, [0][1][1][0][RTW89_KCC][48] = 127, [0][1][1][0][RTW89_ACMA][48] = 127, [0][1][1][0][RTW89_CHILE][48] = 127, @@ -17783,7 +17783,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_FCC][50] = 56, [0][1][1][0][RTW89_ETSI][50] = 127, [0][1][1][0][RTW89_MKK][50] = 127, - [0][1][1][0][RTW89_IC][50] = 127, + [0][1][1][0][RTW89_IC][50] = 50, [0][1][1][0][RTW89_KCC][50] = 127, [0][1][1][0][RTW89_ACMA][50] = 127, [0][1][1][0][RTW89_CHILE][50] = 127, @@ -17795,7 +17795,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_FCC][52] = 56, [0][1][1][0][RTW89_ETSI][52] = 127, [0][1][1][0][RTW89_MKK][52] = 127, - [0][1][1][0][RTW89_IC][52] = 127, + [0][1][1][0][RTW89_IC][52] = 50, [0][1][1][0][RTW89_KCC][52] = 127, [0][1][1][0][RTW89_ACMA][52] = 127, [0][1][1][0][RTW89_CHILE][52] = 127, @@ -18107,7 +18107,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][48] = 78, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, - [0][0][2][0][RTW89_IC][48] = 127, + [0][0][2][0][RTW89_IC][48] = 78, [0][0][2][0][RTW89_KCC][48] = 127, [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CHILE][48] = 127, @@ -18119,7 +18119,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][50] = 78, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, - [0][0][2][0][RTW89_IC][50] = 127, + [0][0][2][0][RTW89_IC][50] = 78, [0][0][2][0][RTW89_KCC][50] = 127, [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CHILE][50] = 127, @@ -18131,7 +18131,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][52] = 78, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, - [0][0][2][0][RTW89_IC][52] = 127, + [0][0][2][0][RTW89_IC][52] = 78, [0][0][2][0][RTW89_KCC][52] = 127, [0][0][2][0][RTW89_ACMA][52] = 127, [0][0][2][0][RTW89_CHILE][52] = 127, @@ -18443,7 +18443,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_FCC][48] = 58, [0][1][2][0][RTW89_ETSI][48] = 127, [0][1][2][0][RTW89_MKK][48] = 127, - [0][1][2][0][RTW89_IC][48] = 127, + [0][1][2][0][RTW89_IC][48] = 50, [0][1][2][0][RTW89_KCC][48] = 127, [0][1][2][0][RTW89_ACMA][48] = 127, [0][1][2][0][RTW89_CHILE][48] = 127, @@ -18455,7 +18455,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_FCC][50] = 58, [0][1][2][0][RTW89_ETSI][50] = 127, [0][1][2][0][RTW89_MKK][50] = 127, - [0][1][2][0][RTW89_IC][50] = 127, + [0][1][2][0][RTW89_IC][50] = 52, [0][1][2][0][RTW89_KCC][50] = 127, [0][1][2][0][RTW89_ACMA][50] = 127, [0][1][2][0][RTW89_CHILE][50] = 127, @@ -18467,7 +18467,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_FCC][52] = 58, [0][1][2][0][RTW89_ETSI][52] = 127, [0][1][2][0][RTW89_MKK][52] = 127, - [0][1][2][0][RTW89_IC][52] = 127, + [0][1][2][0][RTW89_IC][52] = 52, [0][1][2][0][RTW89_KCC][52] = 127, [0][1][2][0][RTW89_ACMA][52] = 127, [0][1][2][0][RTW89_CHILE][52] = 127, @@ -18779,7 +18779,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_FCC][48] = 58, [0][1][2][1][RTW89_ETSI][48] = 127, [0][1][2][1][RTW89_MKK][48] = 127, - [0][1][2][1][RTW89_IC][48] = 127, + [0][1][2][1][RTW89_IC][48] = 50, [0][1][2][1][RTW89_KCC][48] = 127, [0][1][2][1][RTW89_ACMA][48] = 127, [0][1][2][1][RTW89_CHILE][48] = 127, @@ -18791,7 +18791,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_FCC][50] = 58, [0][1][2][1][RTW89_ETSI][50] = 127, [0][1][2][1][RTW89_MKK][50] = 127, - [0][1][2][1][RTW89_IC][50] = 127, + [0][1][2][1][RTW89_IC][50] = 52, [0][1][2][1][RTW89_KCC][50] = 127, [0][1][2][1][RTW89_ACMA][50] = 127, [0][1][2][1][RTW89_CHILE][50] = 127, @@ -18803,7 +18803,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_FCC][52] = 58, [0][1][2][1][RTW89_ETSI][52] = 127, [0][1][2][1][RTW89_MKK][52] = 127, - [0][1][2][1][RTW89_IC][52] = 127, + [0][1][2][1][RTW89_IC][52] = 52, [0][1][2][1][RTW89_KCC][52] = 127, [0][1][2][1][RTW89_ACMA][52] = 127, [0][1][2][1][RTW89_CHILE][52] = 127, @@ -18959,7 +18959,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][47] = 78, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, - [1][0][2][0][RTW89_IC][47] = 127, + [1][0][2][0][RTW89_IC][47] = 78, [1][0][2][0][RTW89_KCC][47] = 127, [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CHILE][47] = 127, @@ -18971,7 +18971,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][51] = 70, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, - [1][0][2][0][RTW89_IC][51] = 127, + [1][0][2][0][RTW89_IC][51] = 78, [1][0][2][0][RTW89_KCC][51] = 127, [1][0][2][0][RTW89_ACMA][51] = 127, [1][0][2][0][RTW89_CHILE][51] = 127, @@ -19127,7 +19127,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_FCC][47] = 68, [1][1][2][0][RTW89_ETSI][47] = 127, [1][1][2][0][RTW89_MKK][47] = 127, - [1][1][2][0][RTW89_IC][47] = 127, + [1][1][2][0][RTW89_IC][47] = 62, [1][1][2][0][RTW89_KCC][47] = 127, [1][1][2][0][RTW89_ACMA][47] = 127, [1][1][2][0][RTW89_CHILE][47] = 127, @@ -19139,7 +19139,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_FCC][51] = 66, [1][1][2][0][RTW89_ETSI][51] = 127, [1][1][2][0][RTW89_MKK][51] = 127, - [1][1][2][0][RTW89_IC][51] = 127, + [1][1][2][0][RTW89_IC][51] = 62, [1][1][2][0][RTW89_KCC][51] = 127, [1][1][2][0][RTW89_ACMA][51] = 127, [1][1][2][0][RTW89_CHILE][51] = 127, @@ -19295,7 +19295,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_FCC][47] = 68, [1][1][2][1][RTW89_ETSI][47] = 127, [1][1][2][1][RTW89_MKK][47] = 127, - [1][1][2][1][RTW89_IC][47] = 127, + [1][1][2][1][RTW89_IC][47] = 62, [1][1][2][1][RTW89_KCC][47] = 127, [1][1][2][1][RTW89_ACMA][47] = 127, [1][1][2][1][RTW89_CHILE][47] = 127, @@ -19307,7 +19307,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_FCC][51] = 66, [1][1][2][1][RTW89_ETSI][51] = 127, [1][1][2][1][RTW89_MKK][51] = 127, - [1][1][2][1][RTW89_IC][51] = 127, + [1][1][2][1][RTW89_IC][51] = 62, [1][1][2][1][RTW89_KCC][51] = 127, [1][1][2][1][RTW89_ACMA][51] = 127, [1][1][2][1][RTW89_CHILE][51] = 127, @@ -19391,7 +19391,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][49] = 64, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, - [2][0][2][0][RTW89_IC][49] = 127, + [2][0][2][0][RTW89_IC][49] = 74, [2][0][2][0][RTW89_KCC][49] = 127, [2][0][2][0][RTW89_ACMA][49] = 127, [2][0][2][0][RTW89_CHILE][49] = 127, @@ -19475,7 +19475,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_FCC][49] = 58, [2][1][2][0][RTW89_ETSI][49] = 127, [2][1][2][0][RTW89_MKK][49] = 127, - [2][1][2][0][RTW89_IC][49] = 127, + [2][1][2][0][RTW89_IC][49] = 66, [2][1][2][0][RTW89_KCC][49] = 127, [2][1][2][0][RTW89_ACMA][49] = 127, [2][1][2][0][RTW89_CHILE][49] = 127, @@ -19559,7 +19559,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_FCC][49] = 58, [2][1][2][1][RTW89_ETSI][49] = 127, [2][1][2][1][RTW89_MKK][49] = 127, - [2][1][2][1][RTW89_IC][49] = 127, + [2][1][2][1][RTW89_IC][49] = 66, [2][1][2][1][RTW89_KCC][49] = 127, [2][1][2][1][RTW89_ACMA][49] = 127, [2][1][2][1][RTW89_CHILE][49] = 127, @@ -20723,9 +20723,9 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_WW][42] = 14, [0][1][RTW89_WW][44] = 14, [0][1][RTW89_WW][46] = 14, - [0][1][RTW89_WW][48] = 20, - [0][1][RTW89_WW][50] = 20, - [0][1][RTW89_WW][52] = 20, + [0][1][RTW89_WW][48] = 16, + [0][1][RTW89_WW][50] = 16, + [0][1][RTW89_WW][52] = 16, [1][0][RTW89_WW][0] = 34, [1][0][RTW89_WW][2] = 34, [1][0][RTW89_WW][4] = 34, @@ -20779,9 +20779,9 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_WW][42] = 16, [1][1][RTW89_WW][44] = 16, [1][1][RTW89_WW][46] = 16, - [1][1][RTW89_WW][48] = 32, - [1][1][RTW89_WW][50] = 32, - [1][1][RTW89_WW][52] = 32, + [1][1][RTW89_WW][48] = 28, + [1][1][RTW89_WW][50] = 30, + [1][1][RTW89_WW][52] = 30, [2][0][RTW89_WW][0] = 44, [2][0][RTW89_WW][2] = 44, [2][0][RTW89_WW][4] = 44, @@ -20835,9 +20835,9 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_WW][42] = 16, [2][1][RTW89_WW][44] = 16, [2][1][RTW89_WW][46] = 16, - [2][1][RTW89_WW][48] = 44, - [2][1][RTW89_WW][50] = 44, - [2][1][RTW89_WW][52] = 44, + [2][1][RTW89_WW][48] = 40, + [2][1][RTW89_WW][50] = 40, + [2][1][RTW89_WW][52] = 40, [0][0][RTW89_FCC][0] = 52, [0][0][RTW89_ETSI][0] = 24, [0][0][RTW89_MKK][0] = 26, @@ -21141,7 +21141,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][48] = 32, [0][0][RTW89_ETSI][48] = 127, [0][0][RTW89_MKK][48] = 127, - [0][0][RTW89_IC][48] = 127, + [0][0][RTW89_IC][48] = 42, [0][0][RTW89_KCC][48] = 127, [0][0][RTW89_ACMA][48] = 127, [0][0][RTW89_CHILE][48] = 127, @@ -21153,7 +21153,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][50] = 32, [0][0][RTW89_ETSI][50] = 127, [0][0][RTW89_MKK][50] = 127, - [0][0][RTW89_IC][50] = 127, + [0][0][RTW89_IC][50] = 42, [0][0][RTW89_KCC][50] = 127, [0][0][RTW89_ACMA][50] = 127, [0][0][RTW89_CHILE][50] = 127, @@ -21165,7 +21165,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][52] = 32, [0][0][RTW89_ETSI][52] = 127, [0][0][RTW89_MKK][52] = 127, - [0][0][RTW89_IC][52] = 127, + [0][0][RTW89_IC][52] = 40, [0][0][RTW89_KCC][52] = 127, [0][0][RTW89_ACMA][52] = 127, [0][0][RTW89_CHILE][52] = 127, @@ -21477,7 +21477,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_FCC][48] = 20, [0][1][RTW89_ETSI][48] = 127, [0][1][RTW89_MKK][48] = 127, - [0][1][RTW89_IC][48] = 127, + [0][1][RTW89_IC][48] = 16, [0][1][RTW89_KCC][48] = 127, [0][1][RTW89_ACMA][48] = 127, [0][1][RTW89_CHILE][48] = 127, @@ -21489,7 +21489,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_FCC][50] = 20, [0][1][RTW89_ETSI][50] = 127, [0][1][RTW89_MKK][50] = 127, - [0][1][RTW89_IC][50] = 127, + [0][1][RTW89_IC][50] = 16, [0][1][RTW89_KCC][50] = 127, [0][1][RTW89_ACMA][50] = 127, [0][1][RTW89_CHILE][50] = 127, @@ -21501,7 +21501,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_FCC][52] = 20, [0][1][RTW89_ETSI][52] = 127, [0][1][RTW89_MKK][52] = 127, - [0][1][RTW89_IC][52] = 127, + [0][1][RTW89_IC][52] = 16, [0][1][RTW89_KCC][52] = 127, [0][1][RTW89_ACMA][52] = 127, [0][1][RTW89_CHILE][52] = 127, @@ -21813,7 +21813,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][48] = 44, [1][0][RTW89_ETSI][48] = 127, [1][0][RTW89_MKK][48] = 127, - [1][0][RTW89_IC][48] = 127, + [1][0][RTW89_IC][48] = 54, [1][0][RTW89_KCC][48] = 127, [1][0][RTW89_ACMA][48] = 127, [1][0][RTW89_CHILE][48] = 127, @@ -21825,7 +21825,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][50] = 44, [1][0][RTW89_ETSI][50] = 127, [1][0][RTW89_MKK][50] = 127, - [1][0][RTW89_IC][50] = 127, + [1][0][RTW89_IC][50] = 54, [1][0][RTW89_KCC][50] = 127, [1][0][RTW89_ACMA][50] = 127, [1][0][RTW89_CHILE][50] = 127, @@ -21837,7 +21837,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][52] = 44, [1][0][RTW89_ETSI][52] = 127, [1][0][RTW89_MKK][52] = 127, - [1][0][RTW89_IC][52] = 127, + [1][0][RTW89_IC][52] = 52, [1][0][RTW89_KCC][52] = 127, [1][0][RTW89_ACMA][52] = 127, [1][0][RTW89_CHILE][52] = 127, @@ -22149,7 +22149,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_FCC][48] = 32, [1][1][RTW89_ETSI][48] = 127, [1][1][RTW89_MKK][48] = 127, - [1][1][RTW89_IC][48] = 127, + [1][1][RTW89_IC][48] = 28, [1][1][RTW89_KCC][48] = 127, [1][1][RTW89_ACMA][48] = 127, [1][1][RTW89_CHILE][48] = 127, @@ -22161,7 +22161,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_FCC][50] = 32, [1][1][RTW89_ETSI][50] = 127, [1][1][RTW89_MKK][50] = 127, - [1][1][RTW89_IC][50] = 127, + [1][1][RTW89_IC][50] = 30, [1][1][RTW89_KCC][50] = 127, [1][1][RTW89_ACMA][50] = 127, [1][1][RTW89_CHILE][50] = 127, @@ -22173,7 +22173,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_FCC][52] = 32, [1][1][RTW89_ETSI][52] = 127, [1][1][RTW89_MKK][52] = 127, - [1][1][RTW89_IC][52] = 127, + [1][1][RTW89_IC][52] = 30, [1][1][RTW89_KCC][52] = 127, [1][1][RTW89_ACMA][52] = 127, [1][1][RTW89_CHILE][52] = 127, @@ -22486,7 +22486,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ETSI][48] = 127, [2][0][RTW89_MKK][48] = 127, [2][0][RTW89_IC][48] = 127, - [2][0][RTW89_KCC][48] = 127, + [2][0][RTW89_KCC][48] = 66, [2][0][RTW89_ACMA][48] = 127, [2][0][RTW89_CHILE][48] = 127, [2][0][RTW89_UKRAINE][48] = 127, @@ -22498,7 +22498,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ETSI][50] = 127, [2][0][RTW89_MKK][50] = 127, [2][0][RTW89_IC][50] = 127, - [2][0][RTW89_KCC][50] = 127, + [2][0][RTW89_KCC][50] = 66, [2][0][RTW89_ACMA][50] = 127, [2][0][RTW89_CHILE][50] = 127, [2][0][RTW89_UKRAINE][50] = 127, @@ -22510,7 +22510,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ETSI][52] = 127, [2][0][RTW89_MKK][52] = 127, [2][0][RTW89_IC][52] = 127, - [2][0][RTW89_KCC][52] = 127, + [2][0][RTW89_KCC][52] = 66, [2][0][RTW89_ACMA][52] = 127, [2][0][RTW89_CHILE][52] = 127, [2][0][RTW89_UKRAINE][52] = 127, @@ -22821,7 +22821,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_FCC][48] = 44, [2][1][RTW89_ETSI][48] = 127, [2][1][RTW89_MKK][48] = 127, - [2][1][RTW89_IC][48] = 127, + [2][1][RTW89_IC][48] = 40, [2][1][RTW89_KCC][48] = 127, [2][1][RTW89_ACMA][48] = 127, [2][1][RTW89_CHILE][48] = 127, @@ -22833,7 +22833,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_FCC][50] = 44, [2][1][RTW89_ETSI][50] = 127, [2][1][RTW89_MKK][50] = 127, - [2][1][RTW89_IC][50] = 127, + [2][1][RTW89_IC][50] = 40, [2][1][RTW89_KCC][50] = 127, [2][1][RTW89_ACMA][50] = 127, [2][1][RTW89_CHILE][50] = 127, @@ -22845,7 +22845,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_FCC][52] = 44, [2][1][RTW89_ETSI][52] = 127, [2][1][RTW89_MKK][52] = 127, - [2][1][RTW89_IC][52] = 127, + [2][1][RTW89_IC][52] = 40, [2][1][RTW89_KCC][52] = 127, [2][1][RTW89_ACMA][52] = 127, [2][1][RTW89_CHILE][52] = 127, From e52fafea56b22df97d7adda31f6ad213437246b1 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 3 Jan 2024 09:41:14 +0800 Subject: [PATCH 0020/2255] wifi: rtw89: 8851b: update TX power tables to R37 Update TX power tables to RF version R37. Mainly update configurations for Canada 5.9 GHz (U-NII 4) according to IC (Industry Canada) certification. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240103014114.9558-2-pkshih@realtek.com --- .../wireless/realtek/rtw89/rtw8851b_table.c | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index 8cb5bde8f625..522883c8dfb9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -5345,7 +5345,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][48] = 72, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, - [0][0][1][0][RTW89_IC][48] = 127, + [0][0][1][0][RTW89_IC][48] = 72, [0][0][1][0][RTW89_KCC][48] = 127, [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CN][48] = 127, @@ -5353,7 +5353,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][50] = 72, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, - [0][0][1][0][RTW89_IC][50] = 127, + [0][0][1][0][RTW89_IC][50] = 72, [0][0][1][0][RTW89_KCC][50] = 127, [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CN][50] = 127, @@ -5361,7 +5361,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][52] = 72, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, - [0][0][1][0][RTW89_IC][52] = 127, + [0][0][1][0][RTW89_IC][52] = 72, [0][0][1][0][RTW89_KCC][52] = 127, [0][0][1][0][RTW89_ACMA][52] = 127, [0][0][1][0][RTW89_CN][52] = 127, @@ -5793,7 +5793,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][48] = 74, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, - [0][0][2][0][RTW89_IC][48] = 127, + [0][0][2][0][RTW89_IC][48] = 74, [0][0][2][0][RTW89_KCC][48] = 127, [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CN][48] = 127, @@ -5801,7 +5801,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][50] = 76, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, - [0][0][2][0][RTW89_IC][50] = 127, + [0][0][2][0][RTW89_IC][50] = 76, [0][0][2][0][RTW89_KCC][50] = 127, [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CN][50] = 127, @@ -5809,7 +5809,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][52] = 76, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, - [0][0][2][0][RTW89_IC][52] = 127, + [0][0][2][0][RTW89_IC][52] = 76, [0][0][2][0][RTW89_KCC][52] = 127, [0][0][2][0][RTW89_ACMA][52] = 127, [0][0][2][0][RTW89_CN][52] = 127, @@ -6361,7 +6361,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][47] = 84, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, - [1][0][2][0][RTW89_IC][47] = 127, + [1][0][2][0][RTW89_IC][47] = 84, [1][0][2][0][RTW89_KCC][47] = 127, [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CN][47] = 127, @@ -6369,7 +6369,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][51] = 84, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, - [1][0][2][0][RTW89_IC][51] = 127, + [1][0][2][0][RTW89_IC][51] = 84, [1][0][2][0][RTW89_KCC][51] = 127, [1][0][2][0][RTW89_ACMA][51] = 127, [1][0][2][0][RTW89_CN][51] = 127, @@ -6649,7 +6649,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][49] = 74, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, - [2][0][2][0][RTW89_IC][49] = 127, + [2][0][2][0][RTW89_IC][49] = 74, [2][0][2][0][RTW89_KCC][49] = 127, [2][0][2][0][RTW89_ACMA][49] = 127, [2][0][2][0][RTW89_CN][49] = 127, @@ -7975,7 +7975,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][48] = 42, [0][0][RTW89_ETSI][48] = 127, [0][0][RTW89_MKK][48] = 127, - [0][0][RTW89_IC][48] = 127, + [0][0][RTW89_IC][48] = 42, [0][0][RTW89_KCC][48] = 127, [0][0][RTW89_ACMA][48] = 127, [0][0][RTW89_CN][48] = 127, @@ -7983,7 +7983,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][50] = 42, [0][0][RTW89_ETSI][50] = 127, [0][0][RTW89_MKK][50] = 127, - [0][0][RTW89_IC][50] = 127, + [0][0][RTW89_IC][50] = 42, [0][0][RTW89_KCC][50] = 127, [0][0][RTW89_ACMA][50] = 127, [0][0][RTW89_CN][50] = 127, @@ -7991,7 +7991,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][52] = 40, [0][0][RTW89_ETSI][52] = 127, [0][0][RTW89_MKK][52] = 127, - [0][0][RTW89_IC][52] = 127, + [0][0][RTW89_IC][52] = 40, [0][0][RTW89_KCC][52] = 127, [0][0][RTW89_ACMA][52] = 127, [0][0][RTW89_CN][52] = 127, @@ -8423,7 +8423,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][48] = 52, [1][0][RTW89_ETSI][48] = 127, [1][0][RTW89_MKK][48] = 127, - [1][0][RTW89_IC][48] = 127, + [1][0][RTW89_IC][48] = 52, [1][0][RTW89_KCC][48] = 127, [1][0][RTW89_ACMA][48] = 127, [1][0][RTW89_CN][48] = 127, @@ -8431,7 +8431,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][50] = 52, [1][0][RTW89_ETSI][50] = 127, [1][0][RTW89_MKK][50] = 127, - [1][0][RTW89_IC][50] = 127, + [1][0][RTW89_IC][50] = 52, [1][0][RTW89_KCC][50] = 127, [1][0][RTW89_ACMA][50] = 127, [1][0][RTW89_CN][50] = 127, @@ -8439,7 +8439,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][52] = 52, [1][0][RTW89_ETSI][52] = 127, [1][0][RTW89_MKK][52] = 127, - [1][0][RTW89_IC][52] = 127, + [1][0][RTW89_IC][52] = 52, [1][0][RTW89_KCC][52] = 127, [1][0][RTW89_ACMA][52] = 127, [1][0][RTW89_CN][52] = 127, @@ -8871,7 +8871,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][48] = 64, [2][0][RTW89_ETSI][48] = 127, [2][0][RTW89_MKK][48] = 127, - [2][0][RTW89_IC][48] = 127, + [2][0][RTW89_IC][48] = 64, [2][0][RTW89_KCC][48] = 127, [2][0][RTW89_ACMA][48] = 127, [2][0][RTW89_CN][48] = 127, @@ -8879,7 +8879,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][50] = 64, [2][0][RTW89_ETSI][50] = 127, [2][0][RTW89_MKK][50] = 127, - [2][0][RTW89_IC][50] = 127, + [2][0][RTW89_IC][50] = 64, [2][0][RTW89_KCC][50] = 127, [2][0][RTW89_ACMA][50] = 127, [2][0][RTW89_CN][50] = 127, @@ -8887,7 +8887,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][52] = 60, [2][0][RTW89_ETSI][52] = 127, [2][0][RTW89_MKK][52] = 127, - [2][0][RTW89_IC][52] = 127, + [2][0][RTW89_IC][52] = 60, [2][0][RTW89_KCC][52] = 127, [2][0][RTW89_ACMA][52] = 127, [2][0][RTW89_CN][52] = 127, @@ -11055,7 +11055,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][48] = 72, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, - [0][0][1][0][RTW89_IC][48] = 127, + [0][0][1][0][RTW89_IC][48] = 72, [0][0][1][0][RTW89_KCC][48] = 127, [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CN][48] = 127, @@ -11063,7 +11063,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][50] = 72, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, - [0][0][1][0][RTW89_IC][50] = 127, + [0][0][1][0][RTW89_IC][50] = 72, [0][0][1][0][RTW89_KCC][50] = 127, [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CN][50] = 127, @@ -11071,7 +11071,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][52] = 72, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, - [0][0][1][0][RTW89_IC][52] = 127, + [0][0][1][0][RTW89_IC][52] = 72, [0][0][1][0][RTW89_KCC][52] = 127, [0][0][1][0][RTW89_ACMA][52] = 127, [0][0][1][0][RTW89_CN][52] = 127, @@ -11503,7 +11503,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][48] = 74, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, - [0][0][2][0][RTW89_IC][48] = 127, + [0][0][2][0][RTW89_IC][48] = 74, [0][0][2][0][RTW89_KCC][48] = 127, [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CN][48] = 127, @@ -11511,7 +11511,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][50] = 74, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, - [0][0][2][0][RTW89_IC][50] = 127, + [0][0][2][0][RTW89_IC][50] = 74, [0][0][2][0][RTW89_KCC][50] = 127, [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CN][50] = 127, @@ -11519,7 +11519,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][52] = 74, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, - [0][0][2][0][RTW89_IC][52] = 127, + [0][0][2][0][RTW89_IC][52] = 74, [0][0][2][0][RTW89_KCC][52] = 127, [0][0][2][0][RTW89_ACMA][52] = 127, [0][0][2][0][RTW89_CN][52] = 127, @@ -12071,7 +12071,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][47] = 80, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, - [1][0][2][0][RTW89_IC][47] = 127, + [1][0][2][0][RTW89_IC][47] = 80, [1][0][2][0][RTW89_KCC][47] = 127, [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CN][47] = 127, @@ -12079,7 +12079,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][51] = 80, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, - [1][0][2][0][RTW89_IC][51] = 127, + [1][0][2][0][RTW89_IC][51] = 80, [1][0][2][0][RTW89_KCC][51] = 127, [1][0][2][0][RTW89_ACMA][51] = 127, [1][0][2][0][RTW89_CN][51] = 127, @@ -12359,7 +12359,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][49] = 72, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, - [2][0][2][0][RTW89_IC][49] = 127, + [2][0][2][0][RTW89_IC][49] = 72, [2][0][2][0][RTW89_KCC][49] = 127, [2][0][2][0][RTW89_ACMA][49] = 127, [2][0][2][0][RTW89_CN][49] = 127, @@ -13685,7 +13685,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][48] = 40, [0][0][RTW89_ETSI][48] = 127, [0][0][RTW89_MKK][48] = 127, - [0][0][RTW89_IC][48] = 127, + [0][0][RTW89_IC][48] = 40, [0][0][RTW89_KCC][48] = 127, [0][0][RTW89_ACMA][48] = 127, [0][0][RTW89_CN][48] = 127, @@ -13693,7 +13693,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][50] = 42, [0][0][RTW89_ETSI][50] = 127, [0][0][RTW89_MKK][50] = 127, - [0][0][RTW89_IC][50] = 127, + [0][0][RTW89_IC][50] = 42, [0][0][RTW89_KCC][50] = 127, [0][0][RTW89_ACMA][50] = 127, [0][0][RTW89_CN][50] = 127, @@ -13701,7 +13701,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][52] = 38, [0][0][RTW89_ETSI][52] = 127, [0][0][RTW89_MKK][52] = 127, - [0][0][RTW89_IC][52] = 127, + [0][0][RTW89_IC][52] = 38, [0][0][RTW89_KCC][52] = 127, [0][0][RTW89_ACMA][52] = 127, [0][0][RTW89_CN][52] = 127, @@ -14133,7 +14133,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][48] = 52, [1][0][RTW89_ETSI][48] = 127, [1][0][RTW89_MKK][48] = 127, - [1][0][RTW89_IC][48] = 127, + [1][0][RTW89_IC][48] = 52, [1][0][RTW89_KCC][48] = 127, [1][0][RTW89_ACMA][48] = 127, [1][0][RTW89_CN][48] = 127, @@ -14141,7 +14141,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][50] = 52, [1][0][RTW89_ETSI][50] = 127, [1][0][RTW89_MKK][50] = 127, - [1][0][RTW89_IC][50] = 127, + [1][0][RTW89_IC][50] = 52, [1][0][RTW89_KCC][50] = 127, [1][0][RTW89_ACMA][50] = 127, [1][0][RTW89_CN][50] = 127, @@ -14149,7 +14149,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][52] = 50, [1][0][RTW89_ETSI][52] = 127, [1][0][RTW89_MKK][52] = 127, - [1][0][RTW89_IC][52] = 127, + [1][0][RTW89_IC][52] = 50, [1][0][RTW89_KCC][52] = 127, [1][0][RTW89_ACMA][52] = 127, [1][0][RTW89_CN][52] = 127, @@ -14581,7 +14581,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][48] = 62, [2][0][RTW89_ETSI][48] = 127, [2][0][RTW89_MKK][48] = 127, - [2][0][RTW89_IC][48] = 127, + [2][0][RTW89_IC][48] = 62, [2][0][RTW89_KCC][48] = 127, [2][0][RTW89_ACMA][48] = 127, [2][0][RTW89_CN][48] = 127, @@ -14589,7 +14589,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][50] = 62, [2][0][RTW89_ETSI][50] = 127, [2][0][RTW89_MKK][50] = 127, - [2][0][RTW89_IC][50] = 127, + [2][0][RTW89_IC][50] = 62, [2][0][RTW89_KCC][50] = 127, [2][0][RTW89_ACMA][50] = 127, [2][0][RTW89_CN][50] = 127, @@ -14597,7 +14597,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][52] = 60, [2][0][RTW89_ETSI][52] = 127, [2][0][RTW89_MKK][52] = 127, - [2][0][RTW89_IC][52] = 127, + [2][0][RTW89_IC][52] = 60, [2][0][RTW89_KCC][52] = 127, [2][0][RTW89_ACMA][52] = 127, [2][0][RTW89_CN][52] = 127, From 9225b9734670090d02690d768a15c3d376bdc5e7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 5 Jan 2024 14:42:21 +0800 Subject: [PATCH 0021/2255] wifi: rtw89: phy: move bb_gain_info used by WiFi 6 chips to union WiFi 7 chips use different bb_gain_info struct, so move existing struct to a union in advance. This doesn't change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064228.36580-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 4 +++- drivers/net/wireless/realtek/rtw89/phy.c | 8 ++++---- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 ++-- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 ++-- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ea6df859ba15..8c5b831c3a37 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4824,7 +4824,9 @@ struct rtw89_dev { struct rtw89_env_monitor_info env_monitor; struct rtw89_dig_info dig; struct rtw89_phy_ch_info ch_info; - struct rtw89_phy_bb_gain_info bb_gain; + union { + struct rtw89_phy_bb_gain_info ax; + } bb_gain; struct rtw89_phy_efuse_gain efuse_gain; struct rtw89_phy_ul_tb_info ul_tb_info; struct rtw89_antdiv_info antdiv; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index bafc7b1cc104..b2729c2550db 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -929,7 +929,7 @@ static void rtw89_phy_cfg_bb_gain_error(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 type = arg.type; u8 path = arg.path; u8 gband = arg.gain_band; @@ -968,7 +968,7 @@ static void rtw89_phy_cfg_bb_rpl_ofst(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 rxsc_start = arg.rxsc_start; u8 bw = arg.bw; u8 path = arg.path; @@ -1050,7 +1050,7 @@ static void rtw89_phy_cfg_bb_gain_bypass(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 type = arg.type; u8 path = arg.path; u8 gband = arg.gain_band; @@ -1077,7 +1077,7 @@ static void rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 type = arg.type; u8 path = arg.path; u8 gband = arg.gain_band; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 5c167a9278ce..b5cf093146cb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -901,7 +901,7 @@ static void rtw8851b_set_gain_error(struct rtw89_dev *rtwdev, enum rtw89_subband subband, enum rtw89_rf_path path) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 gain_band = rtw89_subband_to_bb_gain_band(subband); s32 val; u32 reg; @@ -987,7 +987,7 @@ next: static void rtw8851b_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 band = rtw89_subband_to_bb_gain_band(subband); u32 val; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index de887a35f3fb..ab60cc11a385 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -988,7 +988,7 @@ static void rtw8852b_set_gain_error(struct rtw89_dev *rtwdev, enum rtw89_subband subband, enum rtw89_rf_path path) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 gain_band = rtw89_subband_to_bb_gain_band(subband); s32 val; u32 reg; @@ -1086,7 +1086,7 @@ next: static void rtw8852b_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 band = rtw89_subband_to_bb_gain_band(subband); u32 val; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 8618d0204f66..9a9b7103caeb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -842,7 +842,7 @@ static void rtw8852c_set_gain_error(struct rtw89_dev *rtwdev, enum rtw89_subband subband, enum rtw89_rf_path path) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 gain_band = rtw89_subband_to_bb_gain_band(subband); s32 val; u32 reg; From 0edcdd82337a6bd028cbf8869a9a6fa12e21b484 Mon Sep 17 00:00:00 2001 From: Chung-Hsuan Hung Date: Fri, 5 Jan 2024 14:42:22 +0800 Subject: [PATCH 0022/2255] wifi: rtw89: phy: add parser to support RX gain dynamic setting flow Add RX gain offset dynamic setting flow according to different bands and bandwidths. RX gain offset values will be different according to different channel bands, therefore, this dynamic mechanism is needed while channel is changed. Add this to parse data from the element of firmware file, and then we can use them easier at runtime. Signed-off-by: Chung-Hsuan Hung Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064228.36580-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 64 +++++++ drivers/net/wireless/realtek/rtw89/phy.c | 11 +- drivers/net/wireless/realtek/rtw89/phy.h | 36 ++++ drivers/net/wireless/realtek/rtw89/phy_be.c | 175 ++++++++++++++++++++ 4 files changed, 281 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 8c5b831c3a37..1b74ba9e1a8b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4605,6 +4605,48 @@ enum rtw89_phy_bb_gain_band { RTW89_BB_GAIN_BAND_NR, }; +enum rtw89_phy_gain_band_be { + RTW89_BB_GAIN_BAND_2G_BE = 0, + RTW89_BB_GAIN_BAND_5G_L_BE = 1, + RTW89_BB_GAIN_BAND_5G_M_BE = 2, + RTW89_BB_GAIN_BAND_5G_H_BE = 3, + RTW89_BB_GAIN_BAND_6G_L0_BE = 4, + RTW89_BB_GAIN_BAND_6G_L1_BE = 5, + RTW89_BB_GAIN_BAND_6G_M0_BE = 6, + RTW89_BB_GAIN_BAND_6G_M1_BE = 7, + RTW89_BB_GAIN_BAND_6G_H0_BE = 8, + RTW89_BB_GAIN_BAND_6G_H1_BE = 9, + RTW89_BB_GAIN_BAND_6G_UH0_BE = 10, + RTW89_BB_GAIN_BAND_6G_UH1_BE = 11, + + RTW89_BB_GAIN_BAND_NR_BE, +}; + +enum rtw89_phy_bb_bw_be { + RTW89_BB_BW_20_40 = 0, + RTW89_BB_BW_80_160_320 = 1, + + RTW89_BB_BW_NR_BE, +}; + +enum rtw89_bw20_sc { + RTW89_BW20_SC_20M = 1, + RTW89_BW20_SC_40M = 2, + RTW89_BW20_SC_80M = 4, + RTW89_BW20_SC_160M = 8, + RTW89_BW20_SC_320M = 16, +}; + +enum rtw89_cmac_table_bw { + RTW89_CMAC_BW_20M = 0, + RTW89_CMAC_BW_40M = 1, + RTW89_CMAC_BW_80M = 2, + RTW89_CMAC_BW_160M = 3, + RTW89_CMAC_BW_320M = 4, + + RTW89_CMAC_BW_NR, +}; + enum rtw89_phy_bb_rxsc_num { RTW89_BB_RXSC_NUM_40 = 9, /* SC: 0, 1~8 */ RTW89_BB_RXSC_NUM_80 = 13, /* SC: 0, 1~8, 9~12 */ @@ -4627,6 +4669,27 @@ struct rtw89_phy_bb_gain_info { [RTW89_BB_RXSC_NUM_160]; }; +struct rtw89_phy_bb_gain_info_be { + s8 lna_gain[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE][RF_PATH_MAX] + [LNA_GAIN_NUM]; + s8 tia_gain[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE][RF_PATH_MAX] + [TIA_GAIN_NUM]; + s8 lna_gain_bypass[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE] + [RF_PATH_MAX][LNA_GAIN_NUM]; + s8 lna_op1db[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE] + [RF_PATH_MAX][LNA_GAIN_NUM]; + s8 tia_lna_op1db[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE] + [RF_PATH_MAX][LNA_GAIN_NUM + 1]; + s8 rpl_ofst_20[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_20M]; + s8 rpl_ofst_40[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_40M]; + s8 rpl_ofst_80[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_80M]; + s8 rpl_ofst_160[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_160M]; +}; + struct rtw89_phy_efuse_gain { bool offset_valid; bool comp_valid; @@ -4826,6 +4889,7 @@ struct rtw89_dev { struct rtw89_phy_ch_info ch_info; union { struct rtw89_phy_bb_gain_info ax; + struct rtw89_phy_bb_gain_info_be be; } bb_gain; struct rtw89_phy_efuse_gain efuse_gain; struct rtw89_phy_ul_tb_info ul_tb_info; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index b2729c2550db..5e65d1e9a2c8 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1108,10 +1108,10 @@ rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev, } } -static void rtw89_phy_config_bb_gain(struct rtw89_dev *rtwdev, - const struct rtw89_reg2_def *reg, - enum rtw89_rf_path rf_path, - void *extra_data) +static void rtw89_phy_config_bb_gain_ax(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, + void *extra_data) { const struct rtw89_chip_info *chip = rtwdev->chip; union rtw89_phy_bb_gain_arg arg = { .addr = reg->addr }; @@ -1425,7 +1425,7 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev) bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table; if (bb_gain_table) rtw89_phy_init_reg(rtwdev, bb_gain_table, - rtw89_phy_config_bb_gain, NULL); + chip->phy_def->config_bb_gain, NULL); rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0); } @@ -5476,6 +5476,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, + .config_bb_gain = rtw89_phy_config_bb_gain_ax, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_ax, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_ax, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 3e379077c6ca..70943117242e 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -509,6 +509,10 @@ struct rtw89_phy_gen_def { const struct rtw89_ccx_regs *ccx; const struct rtw89_physts_regs *physts; const struct rtw89_cfo_regs *cfo; + void (*config_bb_gain)(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, + void *extra_data); void (*set_txpwr_byrate)(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, @@ -664,6 +668,38 @@ enum rtw89_phy_bb_gain_band rtw89_subband_to_bb_gain_band(enum rtw89_subband sub } } +static inline +enum rtw89_phy_gain_band_be rtw89_subband_to_gain_band_be(enum rtw89_subband subband) +{ + switch (subband) { + default: + case RTW89_CH_2G: + return RTW89_BB_GAIN_BAND_2G_BE; + case RTW89_CH_5G_BAND_1: + return RTW89_BB_GAIN_BAND_5G_L_BE; + case RTW89_CH_5G_BAND_3: + return RTW89_BB_GAIN_BAND_5G_M_BE; + case RTW89_CH_5G_BAND_4: + return RTW89_BB_GAIN_BAND_5G_H_BE; + case RTW89_CH_6G_BAND_IDX0: + return RTW89_BB_GAIN_BAND_6G_L0_BE; + case RTW89_CH_6G_BAND_IDX1: + return RTW89_BB_GAIN_BAND_6G_L1_BE; + case RTW89_CH_6G_BAND_IDX2: + return RTW89_BB_GAIN_BAND_6G_M0_BE; + case RTW89_CH_6G_BAND_IDX3: + return RTW89_BB_GAIN_BAND_6G_M1_BE; + case RTW89_CH_6G_BAND_IDX4: + return RTW89_BB_GAIN_BAND_6G_H0_BE; + case RTW89_CH_6G_BAND_IDX5: + return RTW89_BB_GAIN_BAND_6G_H1_BE; + case RTW89_CH_6G_BAND_IDX6: + return RTW89_BB_GAIN_BAND_6G_UH0_BE; + case RTW89_CH_6G_BAND_IDX7: + return RTW89_BB_GAIN_BAND_6G_UH1_BE; + } +} + enum rtw89_rfk_flag { RTW89_RFK_F_WRF = 0, RTW89_RFK_F_WM = 1, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index 63eeeea72b68..b65de183156b 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -78,6 +78,180 @@ static const struct rtw89_cfo_regs rtw89_cfo_regs_be = { .valid_0_mask = B_DCFO_OPT_EN_V1, }; +union rtw89_phy_bb_gain_arg_be { + u32 addr; + struct { + u8 type; +#define BB_GAIN_TYPE_SUB0_BE GENMASK(3, 0) +#define BB_GAIN_TYPE_SUB1_BE GENMASK(7, 4) + u8 path_bw; +#define BB_GAIN_PATH_BE GENMASK(3, 0) +#define BB_GAIN_BW_BE GENMASK(7, 4) + u8 gain_band; + u8 cfg_type; + } __packed; +} __packed; + +static void +rtw89_phy_cfg_bb_gain_error_be(struct rtw89_dev *rtwdev, + union rtw89_phy_bb_gain_arg_be arg, u32 data) +{ + struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 bw_type = u8_get_bits(arg.path_bw, BB_GAIN_BW_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + u8 gband = arg.gain_band; + u8 type = arg.type; + int i; + + switch (type) { + case 0: + for (i = 0; i < 4; i++, data >>= 8) + gain->lna_gain[gband][bw_type][path][i] = data & 0xff; + break; + case 1: + for (i = 4; i < 7; i++, data >>= 8) + gain->lna_gain[gband][bw_type][path][i] = data & 0xff; + break; + case 2: + for (i = 0; i < 2; i++, data >>= 8) + gain->tia_gain[gband][bw_type][path][i] = data & 0xff; + break; + default: + rtw89_warn(rtwdev, + "bb gain error {0x%x:0x%x} with unknown type: %d\n", + arg.addr, data, type); + break; + } +} + +static void +rtw89_phy_cfg_bb_rpl_ofst_be(struct rtw89_dev *rtwdev, + union rtw89_phy_bb_gain_arg_be arg, u32 data) +{ + struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 type_sub0 = u8_get_bits(arg.type, BB_GAIN_TYPE_SUB0_BE); + u8 type_sub1 = u8_get_bits(arg.type, BB_GAIN_TYPE_SUB1_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + u8 gband = arg.gain_band; + u8 ofst = 0; + int i; + + switch (type_sub1) { + case RTW89_CMAC_BW_20M: + gain->rpl_ofst_20[gband][path][0] = (s8)data; + break; + case RTW89_CMAC_BW_40M: + for (i = 0; i < RTW89_BW20_SC_40M; i++, data >>= 8) + gain->rpl_ofst_40[gband][path][i] = data & 0xff; + break; + case RTW89_CMAC_BW_80M: + for (i = 0; i < RTW89_BW20_SC_80M; i++, data >>= 8) + gain->rpl_ofst_80[gband][path][i] = data & 0xff; + break; + case RTW89_CMAC_BW_160M: + if (type_sub0 == 0) + ofst = 0; + else + ofst = RTW89_BW20_SC_80M; + + for (i = 0; i < RTW89_BW20_SC_80M; i++, data >>= 8) + gain->rpl_ofst_160[gband][path][i + ofst] = data & 0xff; + break; + default: + rtw89_warn(rtwdev, + "bb rpl ofst {0x%x:0x%x} with unknown type_sub1: %d\n", + arg.addr, data, type_sub1); + break; + } +} + +static void +rtw89_phy_cfg_bb_gain_op1db_be(struct rtw89_dev *rtwdev, + union rtw89_phy_bb_gain_arg_be arg, u32 data) +{ + struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 bw_type = u8_get_bits(arg.path_bw, BB_GAIN_BW_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + u8 gband = arg.gain_band; + u8 type = arg.type; + int i; + + switch (type) { + case 0: + for (i = 0; i < 4; i++, data >>= 8) + gain->lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + case 1: + for (i = 4; i < 7; i++, data >>= 8) + gain->lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + case 2: + for (i = 0; i < 4; i++, data >>= 8) + gain->tia_lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + case 3: + for (i = 4; i < 8; i++, data >>= 8) + gain->tia_lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + default: + rtw89_warn(rtwdev, + "bb gain op1db {0x%x:0x%x} with unknown type: %d\n", + arg.addr, data, type); + break; + } +} + +static void rtw89_phy_config_bb_gain_be(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, + void *extra_data) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + union rtw89_phy_bb_gain_arg_be arg = { .addr = reg->addr }; + struct rtw89_efuse *efuse = &rtwdev->efuse; + u8 bw_type = u8_get_bits(arg.path_bw, BB_GAIN_BW_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + + if (bw_type >= RTW89_BB_BW_NR_BE) + return; + + if (arg.gain_band >= RTW89_BB_GAIN_BAND_NR_BE) + return; + + if (path >= chip->rf_path_num) + return; + + if (arg.addr >= 0xf9 && arg.addr <= 0xfe) { + rtw89_warn(rtwdev, "bb gain table with flow ctrl\n"); + return; + } + + switch (arg.cfg_type) { + case 0: + rtw89_phy_cfg_bb_gain_error_be(rtwdev, arg, reg->data); + break; + case 1: + rtw89_phy_cfg_bb_rpl_ofst_be(rtwdev, arg, reg->data); + break; + case 2: + /* ignore BB gain bypass */ + break; + case 3: + rtw89_phy_cfg_bb_gain_op1db_be(rtwdev, arg, reg->data); + break; + case 4: + /* This cfg_type is only used by rfe_type >= 50 with eFEM */ + if (efuse->rfe_type < 50) + break; + fallthrough; + default: + rtw89_warn(rtwdev, + "bb gain {0x%x:0x%x} with unknown cfg type: %d\n", + arg.addr, reg->data, arg.cfg_type); + break; + } +} + struct rtw89_byr_spec_ent_be { struct rtw89_rate_desc init; u8 num_of_idx; @@ -644,6 +818,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, + .config_bb_gain = rtw89_phy_config_bb_gain_be, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_be, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_be, From cac432a08537b5becabfbbdbdea1eb6cfe28df14 Mon Sep 17 00:00:00 2001 From: Chung-Hsuan Hung Date: Fri, 5 Jan 2024 14:42:23 +0800 Subject: [PATCH 0023/2255] wifi: rtw89: 8922a: set RX gain along with set_channel operation Set values of LNA, TIA and RPL gain compensation read from firmware file when channel is changed. Signed-off-by: Chung-Hsuan Hung Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064228.36580-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 0e7300cc6d9e..717e42be6793 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -600,6 +600,189 @@ static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) return 0; } +struct rtw8922a_bb_gain { + u32 gain_g[BB_PATH_NUM_8922A]; + u32 gain_a[BB_PATH_NUM_8922A]; + u32 gain_g_mask; + u32 gain_a_mask; +}; + +static const struct rtw89_reg_def rpl_comp_bw160[RTW89_BW20_SC_160M] = { + { .addr = 0x41E8, .mask = 0xFF00}, + { .addr = 0x41E8, .mask = 0xFF0000}, + { .addr = 0x41E8, .mask = 0xFF000000}, + { .addr = 0x41EC, .mask = 0xFF}, + { .addr = 0x41EC, .mask = 0xFF00}, + { .addr = 0x41EC, .mask = 0xFF0000}, + { .addr = 0x41EC, .mask = 0xFF000000}, + { .addr = 0x41F0, .mask = 0xFF} +}; + +static const struct rtw89_reg_def rpl_comp_bw80[RTW89_BW20_SC_80M] = { + { .addr = 0x41F4, .mask = 0xFF}, + { .addr = 0x41F4, .mask = 0xFF00}, + { .addr = 0x41F4, .mask = 0xFF0000}, + { .addr = 0x41F4, .mask = 0xFF000000} +}; + +static const struct rtw89_reg_def rpl_comp_bw40[RTW89_BW20_SC_40M] = { + { .addr = 0x41F0, .mask = 0xFF0000}, + { .addr = 0x41F0, .mask = 0xFF000000} +}; + +static const struct rtw89_reg_def rpl_comp_bw20[RTW89_BW20_SC_20M] = { + { .addr = 0x41F0, .mask = 0xFF00} +}; + +static const struct rtw8922a_bb_gain bb_gain_lna[LNA_GAIN_NUM] = { + { .gain_g = {0x409c, 0x449c}, .gain_a = {0x406C, 0x446C}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, + { .gain_g = {0x409c, 0x449c}, .gain_a = {0x406C, 0x446C}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40a0, 0x44a0}, .gain_a = {0x4070, 0x4470}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, + { .gain_g = {0x40a0, 0x44a0}, .gain_a = {0x4070, 0x4470}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40a4, 0x44a4}, .gain_a = {0x4074, 0x4474}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, + { .gain_g = {0x40a4, 0x44a4}, .gain_a = {0x4074, 0x4474}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40a8, 0x44a8}, .gain_a = {0x4078, 0x4478}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, +}; + +static const struct rtw8922a_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { + { .gain_g = {0x4054, 0x4454}, .gain_a = {0x4054, 0x4454}, + .gain_g_mask = 0x7FC0000, .gain_a_mask = 0x1FF}, + { .gain_g = {0x4058, 0x4458}, .gain_a = {0x4054, 0x4454}, + .gain_g_mask = 0x1FF, .gain_a_mask = 0x3FE00 }, +}; + +struct rtw8922a_bb_gain_bypass { + u32 gain_g[BB_PATH_NUM_8922A]; + u32 gain_a[BB_PATH_NUM_8922A]; + u32 gain_mask_g; + u32 gain_mask_a; +}; + +static void rtw8922a_set_rpl_gain(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 gain_band = rtw89_subband_to_gain_band_be(chan->subband_type); + u32 reg_path_ofst = 0; + u32 mask; + s32 val; + u32 reg; + int i; + + if (path == RF_PATH_B) + reg_path_ofst = 0x400; + + for (i = 0; i < RTW89_BW20_SC_160M; i++) { + reg = rpl_comp_bw160[i].addr | reg_path_ofst; + mask = rpl_comp_bw160[i].mask; + val = gain->rpl_ofst_160[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < RTW89_BW20_SC_80M; i++) { + reg = rpl_comp_bw80[i].addr | reg_path_ofst; + mask = rpl_comp_bw80[i].mask; + val = gain->rpl_ofst_80[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < RTW89_BW20_SC_40M; i++) { + reg = rpl_comp_bw40[i].addr | reg_path_ofst; + mask = rpl_comp_bw40[i].mask; + val = gain->rpl_ofst_40[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < RTW89_BW20_SC_20M; i++) { + reg = rpl_comp_bw20[i].addr | reg_path_ofst; + mask = rpl_comp_bw20[i].mask; + val = gain->rpl_ofst_20[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } +} + +static void rtw8922a_set_lna_tia_gain(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 gain_band = rtw89_subband_to_gain_band_be(chan->subband_type); + enum rtw89_phy_bb_bw_be bw_type; + s32 val; + u32 reg; + u32 mask; + int i; + + bw_type = chan->band_width <= RTW89_CHANNEL_WIDTH_40 ? + RTW89_BB_BW_20_40 : RTW89_BB_BW_80_160_320; + + for (i = 0; i < LNA_GAIN_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_gain_lna[i].gain_g[path]; + mask = bb_gain_lna[i].gain_g_mask; + } else { + reg = bb_gain_lna[i].gain_a[path]; + mask = bb_gain_lna[i].gain_a_mask; + } + val = gain->lna_gain[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < TIA_GAIN_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_gain_tia[i].gain_g[path]; + mask = bb_gain_tia[i].gain_g_mask; + } else { + reg = bb_gain_tia[i].gain_a[path]; + mask = bb_gain_tia[i].gain_a_mask; + } + val = gain->tia_gain[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } +} + +static void rtw8922a_set_gain(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_lna_tia_gain(rtwdev, chan, path, phy_idx); + rtw8922a_set_rpl_gain(rtwdev, chan, path, phy_idx); +} + +static void rtw8922a_ctrl_ch(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_gain(rtwdev, chan, RF_PATH_A, phy_idx); + rtw8922a_set_gain(rtwdev, chan, RF_PATH_B, phy_idx); +} + +static void rtw8922a_set_channel_bb(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_ctrl_ch(rtwdev, chan, phy_idx); +} + +static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_mac_idx mac_idx, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_channel_bb(rtwdev, chan, phy_idx); +} + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -610,6 +793,7 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { #endif static const struct rtw89_chip_ops rtw8922a_chip_ops = { + .set_channel = rtw8922a_set_channel, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, .pwr_on_func = rtw8922a_pwr_on_func, From d16f34b084d9734644932ca17812baec56fb0041 Mon Sep 17 00:00:00 2001 From: Cheng-Chieh Hsieh Date: Fri, 5 Jan 2024 14:42:24 +0800 Subject: [PATCH 0024/2255] wifi: rtw89: 8922a: update the register used in DIG and the DIG flow DIG standing for dynamic initial gain that is used to adjust RX coverage, and PD lower threshold is packet detection power level by received signal strength to avoid false detection of the WiFi packet. Because of the hardware is different between WiFi 7 and 6 ICs, we adjust flow and add register definition for 8922A. Signed-off-by: Cheng-Chieh Hsieh Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064228.36580-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 6 ++++- drivers/net/wireless/realtek/rtw89/reg.h | 4 +++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 25 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 5e65d1e9a2c8..37fc1a7e888f 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -4551,6 +4551,9 @@ static void rtw89_phy_dig_set_rxb_idx(struct rtw89_dev *rtwdev, u8 rxb_idx) static void rtw89_phy_dig_set_igi_cr(struct rtw89_dev *rtwdev, const struct rtw89_agc_gaincode_set set) { + if (!rtwdev->hal.support_igi) + return; + rtw89_phy_dig_set_lna_idx(rtwdev, set.lna_idx); rtw89_phy_dig_set_tia_idx(rtwdev, set.tia_idx); rtw89_phy_dig_set_rxb_idx(rtwdev, set.rxb_idx); @@ -4606,7 +4609,8 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi, s8 cck_cca_th; u32 pd_val = 0; - under_region += PD_TH_SB_FLTR_CMP_VAL; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) + under_region += PD_TH_SB_FLTR_CMP_VAL; switch (cbw) { case RTW89_CHANNEL_WIDTH_40: diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 8456e2b0c14f..61ba52d5990e 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7910,10 +7910,12 @@ #define R_PATH0_P20_FOLLOW_BY_PAGCUGC 0x46A0 #define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V1 0x4C24 #define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V2 0x46E8 +#define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V3 0x41C8 #define B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH0_S20_FOLLOW_BY_PAGCUGC 0x46A4 #define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V1 0x4C28 #define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V2 0x46EC +#define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V3 0x41CC #define B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH0_RXB_INIT_V1 0x46A8 #define B_PATH0_RXB_INIT_IDX_MSK_V1 GENMASK(14, 10) @@ -7958,10 +7960,12 @@ #define R_PATH1_P20_FOLLOW_BY_PAGCUGC 0x4774 #define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V1 0x4CE8 #define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V2 0x47A8 +#define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V3 0x45C8 #define B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH1_S20_FOLLOW_BY_PAGCUGC 0x4778 #define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V1 0x4CEC #define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V2 0x47AC +#define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V3 0x45CC #define B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH1_G_TIA0_LNA6_OP1DB_V1 0x4778 #define B_PATH1_G_TIA0_LNA6_OP1DB_V1 GENMASK(7, 0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 717e42be6793..070d0c716659 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -119,6 +119,30 @@ static const struct rtw89_imr_table rtw8922a_imr_cmac_table = { .n_regs = ARRAY_SIZE(rtw8922a_imr_cmac_regs), }; +static const struct rtw89_dig_regs rtw8922a_dig_regs = { + .seg0_pd_reg = R_SEG0R_PD_V2, + .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK, + .pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1, + .bmode_pd_reg = R_BMODE_PDTH_EN_V2, + .bmode_cca_rssi_limit_en = B_BMODE_PDTH_LIMIT_EN_MSK_V1, + .bmode_pd_lower_bound_reg = R_BMODE_PDTH_V2, + .bmode_rssi_nocca_low_th_mask = B_BMODE_PDTH_LOWER_BOUND_MSK_V1, + .p0_lna_init = {R_PATH0_LNA_INIT_V1, B_PATH0_LNA_INIT_IDX_MSK}, + .p1_lna_init = {R_PATH1_LNA_INIT_V1, B_PATH1_LNA_INIT_IDX_MSK}, + .p0_tia_init = {R_PATH0_TIA_INIT_V1, B_PATH0_TIA_INIT_IDX_MSK_V1}, + .p1_tia_init = {R_PATH1_TIA_INIT_V1, B_PATH1_TIA_INIT_IDX_MSK_V1}, + .p0_rxb_init = {R_PATH0_RXB_INIT_V1, B_PATH0_RXB_INIT_IDX_MSK_V1}, + .p1_rxb_init = {R_PATH1_RXB_INIT_V1, B_PATH1_RXB_INIT_IDX_MSK_V1}, + .p0_p20_pagcugc_en = {R_PATH0_P20_FOLLOW_BY_PAGCUGC_V3, + B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p0_s20_pagcugc_en = {R_PATH0_S20_FOLLOW_BY_PAGCUGC_V3, + B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p1_p20_pagcugc_en = {R_PATH1_P20_FOLLOW_BY_PAGCUGC_V3, + B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p1_s20_pagcugc_en = {R_PATH1_S20_FOLLOW_BY_PAGCUGC_V3, + B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, +}; + static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, @@ -834,6 +858,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, .dig_table = NULL, + .dig_regs = &rtw8922a_dig_regs, .tssi_dbw_table = NULL, .support_chanctx_num = 1, .support_bands = BIT(NL80211_BAND_2GHZ) | From 0377e2a77201f22bb7336b5671f3f43fc094b44a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 5 Jan 2024 14:44:07 +0800 Subject: [PATCH 0025/2255] wifi: rtw89: phy: ignore special data from BB parameter file BB parameter file is a list of tuple {addr, val} with conditional hardware version. However, tuples within a condition can't be empty, so insert a special dummy tuple for this case. Then, ignore this tuple when writing. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064407.36750-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/phy.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 1b74ba9e1a8b..662425ba395b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -32,6 +32,7 @@ extern const struct ieee80211_ops rtw89_ops; #define MASKDWORD 0xffffffff #define RFREG_MASK 0xfffff #define INV_RF_DATA 0xffffffff +#define BYPASS_CR_DATA 0xbabecafe #define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2) #define RTW89_FORBID_BA_TIMER round_jiffies_relative(HZ * 4) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 37fc1a7e888f..3efc6bbdf624 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -905,6 +905,8 @@ static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev, udelay(5); else if (reg->addr == 0xf9) udelay(1); + 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); } From c207e14d9328a97635dd78090e4296ef97149a2d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 5 Jan 2024 14:44:22 +0800 Subject: [PATCH 0026/2255] wifi: rtw89: 8922a: add NCTL pre-settings for WiFi 7 chips NCTL standing for nano-controller is used to assist RF calibration. Basically, we write settings from a table, but format of the table can't describe register mask and additional conditions, so add a function to set this kind of settings. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064422.36812-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 14 +++++++++++--- drivers/net/wireless/realtek/rtw89/phy.h | 8 ++++++++ drivers/net/wireless/realtek/rtw89/phy_be.c | 19 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 17 +++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 3efc6bbdf624..e9baa939d987 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1469,11 +1469,9 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio) kfree(rf_reg_info); } -static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) +static void rtw89_phy_preinit_rf_nctl_ax(struct rtw89_dev *rtwdev) { - struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; const struct rtw89_chip_info *chip = rtwdev->chip; - const struct rtw89_phy_table *nctl_table; u32 val; int ret; @@ -1493,6 +1491,15 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) 1000, false, rtwdev); if (ret) rtw89_err(rtwdev, "failed to poll nctl block\n"); +} + +static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) +{ + struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_phy_table *nctl_table; + + rtw89_phy_preinit_rf_nctl(rtwdev); nctl_table = elm_info->rf_nctl ? elm_info->rf_nctl : chip->nctl_table; rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL); @@ -5483,6 +5490,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_ax = { .physts = &rtw89_physts_regs_ax, .cfo = &rtw89_cfo_regs_ax, .config_bb_gain = rtw89_phy_config_bb_gain_ax, + .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_ax, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_ax, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_ax, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 70943117242e..5347aba994df 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -513,6 +513,7 @@ struct rtw89_phy_gen_def { const struct rtw89_reg2_def *reg, enum rtw89_rf_path rf_path, void *extra_data); + void (*preinit_rf_nctl)(struct rtw89_dev *rtwdev); void (*set_txpwr_byrate)(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, @@ -795,6 +796,13 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, u8 ru, u8 ntx, u8 ch); +static inline void rtw89_phy_preinit_rf_nctl(struct rtw89_dev *rtwdev) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + + phy->preinit_rf_nctl(rtwdev); +} + static inline void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index b65de183156b..0f61d86c5e8f 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -252,6 +252,24 @@ static void rtw89_phy_config_bb_gain_be(struct rtw89_dev *rtwdev, } } +static void rtw89_phy_preinit_rf_nctl_be(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_mask(rtwdev, R_GOTX_IQKDPK_C0, B_GOTX_IQKDPK, 0x3); + rtw89_phy_write32_mask(rtwdev, R_GOTX_IQKDPK_C1, B_GOTX_IQKDPK, 0x3); + rtw89_phy_write32_mask(rtwdev, R_IQKDPK_HC, B_IQKDPK_HC, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CLK_GCK, B_CLK_GCK, 0x00fffff); + rtw89_phy_write32_mask(rtwdev, R_IOQ_IQK_DPK, B_IOQ_IQK_DPK_CLKEN, 0x3); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_RST, B_IQK_DPK_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_PRST, B_IQK_DPK_PRST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_PRST_C1, B_IQK_DPK_PRST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TXRFC, B_TXRFC_RST, 0x1); + + if (rtwdev->dbcc_en) { + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_RST_C1, B_IQK_DPK_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TXRFC_C1, B_TXRFC_RST, 0x1); + } +} + struct rtw89_byr_spec_ent_be { struct rtw89_rate_desc init; u8 num_of_idx; @@ -819,6 +837,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_be = { .physts = &rtw89_physts_regs_be, .cfo = &rtw89_cfo_regs_be, .config_bb_gain = rtw89_phy_config_bb_gain_be, + .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_be, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_be, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 61ba52d5990e..dc237f12dc5e 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7588,13 +7588,20 @@ #define R_PD_CTRL 0x0C3C #define B_PD_HIT_DIS BIT(9) #define R_IOQ_IQK_DPK 0x0C60 +#define B_IOQ_IQK_DPK_CLKEN GENMASK(1, 0) #define B_IOQ_IQK_DPK_EN BIT(1) #define R_GNT_BT_WGT_EN 0x0C6C #define B_GNT_BT_WGT_EN BIT(21) +#define R_IQK_DPK_RST 0x0C6C +#define R_IQK_DPK_RST_C1 0x1C6C +#define B_IQK_DPK_RST BIT(0) #define R_TX_COLLISION_T2R_ST 0x0C70 #define B_TX_COLLISION_T2R_ST_M GENMASK(25, 20) #define R_TXGATING 0x0C74 #define B_TXGATING_EN BIT(4) +#define R_TXRFC 0x0C7C +#define R_TXRFC_C1 0x1C7C +#define B_TXRFC_RST GENMASK(23, 21) #define R_PD_ARBITER_OFF 0x0C80 #define B_PD_ARBITER_OFF BIT(31) #define R_SNDCCA_A1 0x0C9C @@ -7624,6 +7631,8 @@ #define R_CTLTOP 0x1008 #define B_CTLTOP_ON BIT(23) #define B_CTLTOP_VAL GENMASK(15, 12) +#define R_CLK_GCK 0x1008 +#define B_CLK_GCK GENMASK(24, 0) #define R_EDCCA_RPT_SEL_BE 0x10CC #define R_S0_HW_SI_DIS 0x1200 #define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) @@ -7771,6 +7780,8 @@ #define B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0 BIT(13) #define R_DBCC_80P80_SEL_EVM_RPT2 0x2A10 #define B_DBCC_80P80_SEL_EVM_RPT2_EN BIT(0) +#define R_IQKDPK_HC 0x2AB8 +#define B_IQKDPK_HC BIT(28) #define R_P1_EN_SOUND_WO_NDP 0x2D7C #define B_P1_EN_SOUND_WO_NDP BIT(1) #define R_EDCCA_RPT_A_BE 0x2E38 @@ -8630,6 +8641,12 @@ #define B_DACKN0_V GENMASK(21, 14) #define R_DACKN1_CTL 0xC224 #define B_DACKN1_V GENMASK(21, 14) +#define R_GOTX_IQKDPK_C0 0xE464 +#define R_GOTX_IQKDPK_C1 0xE564 +#define B_GOTX_IQKDPK GENMASK(28, 27) +#define R_IQK_DPK_PRST 0xE4AC +#define R_IQK_DPK_PRST_C1 0xE5AC +#define B_IQK_DPK_PRST BIT(27) /* WiFi CPU local domain */ #define R_AX_WDT_CTRL 0x0040 From ce84ecbdc16877b70b3bb3c59ee4991d148f7b61 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 5 Jan 2024 14:44:33 +0800 Subject: [PATCH 0027/2255] wifi: rtw89: phy: add BB wrapper of TX power for WiFi 7 chips TX power is controlled by BB layer basically, but it should interact with MAC layer, so these registers are put on MAC register domain and called BB wrapper, which contains TX power for each MAC ID, OFDMA RU power, and consideration of power type table. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064433.36870-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 2 + drivers/net/wireless/realtek/rtw89/phy.h | 9 ++ drivers/net/wireless/realtek/rtw89/phy_be.c | 106 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 47 +++++++++ 4 files changed, 164 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index e9baa939d987..69debc156edb 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -4966,6 +4966,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_physts_parsing_init(rtwdev); rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); + rtw89_phy_bb_wrap_init(rtwdev); rtw89_phy_edcca_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); rtw89_phy_antdiv_init(rtwdev); @@ -5491,6 +5492,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_ax = { .cfo = &rtw89_cfo_regs_ax, .config_bb_gain = rtw89_phy_config_bb_gain_ax, .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_ax, + .bb_wrap_init = NULL, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_ax, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_ax, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 5347aba994df..2ffd33b078b2 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -514,6 +514,7 @@ struct rtw89_phy_gen_def { enum rtw89_rf_path rf_path, void *extra_data); void (*preinit_rf_nctl)(struct rtw89_dev *rtwdev); + void (*bb_wrap_init)(struct rtw89_dev *rtwdev); void (*set_txpwr_byrate)(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, @@ -803,6 +804,14 @@ static inline void rtw89_phy_preinit_rf_nctl(struct rtw89_dev *rtwdev) phy->preinit_rf_nctl(rtwdev); } +static inline void rtw89_phy_bb_wrap_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + + if (phy->bb_wrap_init) + phy->bb_wrap_init(rtwdev); +} + static inline void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index 0f61d86c5e8f..e8ce29de1c52 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -270,6 +270,111 @@ static void rtw89_phy_preinit_rf_nctl_be(struct rtw89_dev *rtwdev) } } +static +void rtw89_phy_bb_wrap_pwr_by_macid_init(struct rtw89_dev *rtwdev) +{ + u32 macid_idx, cr, base_macid_lmt, max_macid = 32; + + base_macid_lmt = R_BE_PWR_MACID_LMT_BASE; + + for (macid_idx = 0; macid_idx < 4 * max_macid; macid_idx += 4) { + cr = base_macid_lmt + macid_idx; + rtw89_write32(rtwdev, cr, 0x03007F7F); + } +} + +static +void rtw89_phy_bb_wrap_tx_path_by_macid_init(struct rtw89_dev *rtwdev) +{ + int i, max_macid = 32; + u32 cr = R_BE_PWR_MACID_PATH_BASE; + + for (i = 0; i < max_macid; i++, cr += 4) + rtw89_write32(rtwdev, cr, 0x03C86000); +} + +static void rtw89_phy_bb_wrap_tpu_set_all(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) +{ + u32 addr; + + for (addr = R_BE_PWR_BY_RATE; addr <= R_BE_PWR_BY_RATE_END; addr += 4) + rtw89_write32(rtwdev, addr, 0); + for (addr = R_BE_PWR_RULMT_START; addr <= R_BE_PWR_RULMT_END; addr += 4) + rtw89_write32(rtwdev, addr, 0); + for (addr = R_BE_PWR_RATE_OFST_CTRL; addr <= R_BE_PWR_RATE_OFST_END; addr += 4) + rtw89_write32(rtwdev, addr, 0); + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_REF_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_LMT_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_LMTBF, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_LMTBF_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_RATE_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_BYRATE_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_RULMT, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_RULMT_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_SW, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_SW_DB, 0); +} + +static +void rtw89_phy_bb_wrap_listen_path_en_init(struct rtw89_dev *rtwdev) +{ + u32 addr; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL); + if (ret) + return; + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_LISTEN_PATH, RTW89_MAC_1); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_LISTEN_PATH_EN, 0x2); +} + +static void rtw89_phy_bb_wrap_force_cr_init(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) +{ + u32 addr; + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FORCE_LMT, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_LMT_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RATE_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_RULMT, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RU_ENON, 0); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RU_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FORCE_MACID, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_MACID_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_COEX_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_COEX_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_RATE_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_FORCE_PWR_BY_RATE_EN, 0); +} + +static void rtw89_phy_bb_wrap_ftm_init(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) +{ + u32 addr; + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FTM, mac_idx); + rtw89_write32(rtwdev, addr, 0xE4E431); + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FTM_SS, mac_idx); + rtw89_write32_mask(rtwdev, addr, 0x7, 0); +} + +static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) +{ + enum rtw89_mac_idx mac_idx = RTW89_MAC_0; + + rtw89_phy_bb_wrap_pwr_by_macid_init(rtwdev); + rtw89_phy_bb_wrap_tx_path_by_macid_init(rtwdev); + rtw89_phy_bb_wrap_listen_path_en_init(rtwdev); + rtw89_phy_bb_wrap_force_cr_init(rtwdev, mac_idx); + rtw89_phy_bb_wrap_ftm_init(rtwdev, mac_idx); + rtw89_phy_bb_wrap_tpu_set_all(rtwdev, mac_idx); +} + struct rtw89_byr_spec_ent_be { struct rtw89_rate_desc init; u8 num_of_idx; @@ -838,6 +943,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_be = { .cfo = &rtw89_cfo_regs_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, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_be, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index dc237f12dc5e..a03fb3784d1c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5822,6 +5822,9 @@ #define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2) #define B_BE_R_MACID_ACQ_CHK_EN BIT(0) +#define R_BE_PWR_MACID_PATH_BASE 0x0E500 +#define R_BE_PWR_MACID_LMT_BASE 0x0ED00 + #define R_BE_CMAC_FUNC_EN 0x10000 #define R_BE_CMAC_FUNC_EN_C1 0x14000 #define B_BE_CMAC_CRPRT BIT(31) @@ -7178,12 +7181,56 @@ #define R_BE_PWR_MODULE 0x11900 #define R_BE_PWR_MODULE_C1 0x15900 +#define R_BE_PWR_LISTEN_PATH 0x11988 +#define B_BE_PWR_LISTEN_PATH_EN GENMASK(31, 28) + +#define R_BE_PWR_REF_CTRL 0x11A20 +#define B_BE_PWR_REF_CTRL_OFDM GENMASK(9, 1) +#define B_BE_PWR_REF_CTRL_CCK GENMASK(18, 10) +#define B_BE_PWR_OFST_LMT_DB GENMASK(27, 19) +#define R_BE_PWR_OFST_LMTBF 0x11A24 +#define B_BE_PWR_OFST_LMTBF_DB GENMASK(8, 0) +#define R_BE_PWR_FORCE_LMT 0x11A28 +#define B_BE_PWR_FORCE_LMT_ON BIT(6) + +#define R_BE_PWR_RATE_CTRL 0x11A2C +#define B_BE_PWR_OFST_BYRATE_DB GENMASK(8, 0) +#define B_BE_FORCE_PWR_BY_RATE_EN BIT(19) +#define B_BE_FORCE_PWR_BY_RATE_VAL GENMASK(28, 20) #define R_BE_PWR_RATE_OFST_CTRL 0x11A30 +#define R_BE_PWR_RATE_OFST_END 0x11A38 +#define R_BE_PWR_RULMT_START 0x12048 +#define R_BE_PWR_RULMT_END 0x120e4 + +#define R_BE_PWR_BOOST 0x11A40 +#define B_BE_PWR_CTRL_SEL BIT(16) +#define B_BE_PWR_FORCE_RATE_ON BIT(29) +#define R_BE_PWR_OFST_RULMT 0x11A44 +#define B_BE_PWR_OFST_RULMT_DB GENMASK(17, 9) +#define B_BE_PWR_FORCE_RU_ON BIT(18) +#define B_BE_PWR_FORCE_RU_ENON BIT(28) +#define R_BE_PWR_FORCE_MACID 0x11A48 +#define B_BE_PWR_FORCE_MACID_ON BIT(9) + +#define R_BE_PWR_REG_CTRL 0x11A50 +#define B_BE_PWR_BT_EN BIT(23) + +#define R_BE_PWR_COEX_CTRL 0x11A54 +#define B_BE_PWR_BT_VAL GENMASK(8, 0) +#define B_BE_PWR_FORCE_COEX_ON GENMASK(29, 27) + +#define R_BE_PWR_OFST_SW 0x11AE8 +#define B_BE_PWR_OFST_SW_DB GENMASK(27, 24) + +#define R_BE_PWR_FTM 0x11B00 +#define R_BE_PWR_FTM_SS 0x11B04 + #define R_BE_PWR_BY_RATE 0x11E00 #define R_BE_PWR_BY_RATE_MAX 0x11FA8 #define R_BE_PWR_LMT 0x11FAC #define R_BE_PWR_LMT_MAX 0x12040 +#define R_BE_PWR_BY_RATE_END 0x12044 #define R_BE_PWR_RU_LMT 0x12048 #define R_BE_PWR_RU_LMT_MAX 0x120E4 From 6bd232192261f199d3801ecb246bd7d722a6e2d5 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 5 Jan 2024 14:44:40 +0800 Subject: [PATCH 0028/2255] wifi: rtw89: phy: set channel_info for WiFi 7 chips The channel_info is hardware settings to reflect operational status, such as scale factor, report unit, buffer matrix size, RU size and so on. Then, we can get desired reports to do further tuning. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240105064440.36926-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 2 ++ drivers/net/wireless/realtek/rtw89/phy.h | 9 +++++++++ drivers/net/wireless/realtek/rtw89/phy_be.c | 12 ++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 11 +++++++++++ 4 files changed, 34 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 69debc156edb..926a4459ea4f 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -4968,6 +4968,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_phy_cfo_init(rtwdev); rtw89_phy_bb_wrap_init(rtwdev); rtw89_phy_edcca_init(rtwdev); + rtw89_phy_ch_info_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); rtw89_phy_antdiv_init(rtwdev); rtw89_chip_rfe_gpio(rtwdev); @@ -5493,6 +5494,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_ax = { .config_bb_gain = rtw89_phy_config_bb_gain_ax, .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_ax, .bb_wrap_init = NULL, + .ch_info_init = NULL, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_ax, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_ax, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 2ffd33b078b2..a16bff77661f 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -515,6 +515,7 @@ struct rtw89_phy_gen_def { void *extra_data); void (*preinit_rf_nctl)(struct rtw89_dev *rtwdev); void (*bb_wrap_init)(struct rtw89_dev *rtwdev); + void (*ch_info_init)(struct rtw89_dev *rtwdev); void (*set_txpwr_byrate)(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, @@ -812,6 +813,14 @@ static inline void rtw89_phy_bb_wrap_init(struct rtw89_dev *rtwdev) phy->bb_wrap_init(rtwdev); } +static inline void rtw89_phy_ch_info_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + + if (phy->ch_info_init) + phy->ch_info_init(rtwdev); +} + static inline void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index e8ce29de1c52..6849438a5f3c 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -375,6 +375,17 @@ static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) rtw89_phy_bb_wrap_tpu_set_all(rtwdev, mac_idx); } +static void rtw89_phy_ch_info_init_be(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_mask(rtwdev, R_CHINFO_SEG, B_CHINFO_SEG_LEN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CHINFO_SEG, B_CHINFO_SEG, 0xf); + rtw89_phy_write32_mask(rtwdev, R_CHINFO_DATA, B_CHINFO_DATA_BITMAP, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_ELM_SRC, B_CHINFO_ELM_BITMAP, 0x40303); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_ELM_SRC, B_CHINFO_SRC, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_TYPE_SCAL, B_CHINFO_TYPE, 0x3); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_TYPE_SCAL, B_CHINFO_SCAL, 0x0); +} + struct rtw89_byr_spec_ent_be { struct rtw89_rate_desc init; u8 num_of_idx; @@ -944,6 +955,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_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, + .ch_info_init = rtw89_phy_ch_info_init_be, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_be, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index a03fb3784d1c..b411bf726849 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7512,9 +7512,14 @@ #define B_UPD_P0_EN BIT(31) #define R_SPOOF_CG 0x00B4 #define B_SPOOF_CG_EN BIT(17) +#define R_CHINFO_SEG 0x00B4 +#define B_CHINFO_SEG_LEN GENMASK(2, 0) +#define B_CHINFO_SEG GENMASK(16, 7) #define R_DFS_FFT_CG 0x00B8 #define B_DFS_CG_EN BIT(1) #define B_DFS_FFT_EN BIT(0) +#define R_CHINFO_DATA 0x00C0 +#define B_CHINFO_DATA_BITMAP GENMASK(22, 0) #define R_ANAPAR_PW15 0x030C #define B_ANAPAR_PW15 GENMASK(31, 24) #define B_ANAPAR_PW15_H GENMASK(27, 24) @@ -8154,6 +8159,12 @@ #define B_PATH1_5MDET_SB2 BIT(8) #define B_PATH1_5MDET_SB0 BIT(6) #define B_PATH1_5MDET_TH GENMASK(5, 0) +#define R_CHINFO_ELM_SRC 0x4D84 +#define B_CHINFO_ELM_BITMAP GENMASK(22, 0) +#define B_CHINFO_SRC GENMASK(31, 30) +#define R_CHINFO_TYPE_SCAL 0x4D88 +#define B_CHINFO_TYPE GENMASK(2, 1) +#define B_CHINFO_SCAL BIT(8) #define R_RPL_BIAS_COMP 0x4DF0 #define B_RPL_BIAS_COMP_MASK GENMASK(7, 0) #define R_RPL_PATHAB 0x4E0C From 6aeaa379291bac24be568808da5e305d975d8860 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 20 Dec 2023 14:18:31 +0000 Subject: [PATCH 0029/2255] wifi: rtw89: mac: Fix spelling mistakes "notfify" -> "notify" There are two spelling mistakes in rtw89_err error messages. Fix these and also add space between [ERR] and message text. Signed-off-by: Colin Ian King Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231220141831.10063-1-colin.i.king@gmail.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index be30c9346293..4befbe06cd15 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1616,7 +1616,7 @@ static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable) if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) { ret = rtw89_fw_h2c_notify_dbcc(rtwdev, true); if (ret) { - rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n", + rtw89_err(rtwdev, "%s:[ERR] notify dbcc1 fail %d\n", __func__, ret); return ret; } @@ -1625,7 +1625,7 @@ static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable) if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) { ret = rtw89_fw_h2c_notify_dbcc(rtwdev, false); if (ret) { - rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n", + rtw89_err(rtwdev, "%s:[ERR] notify dbcc1 fail %d\n", __func__, ret); return ret; } From 8d101b15f86dae41fcf1afe448d5a52c1956c465 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 3 Jan 2024 15:01:55 +0800 Subject: [PATCH 0030/2255] wifi: rtw88: 8822ce: refine power parameters for RFE type 5 Refine the power parameters for better step response especially at high current ramp case that is caused by power inductor variation. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240103070155.119488-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/pci.c | 4 ++++ drivers/net/wireless/realtek/rtw88/reg.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 2bfc0e822b8d..9986a4cb37eb 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1450,6 +1450,7 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) { struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; struct pci_dev *pdev = rtwpci->pdev; const struct rtw_intf_phy_para *para; u16 cut; @@ -1498,6 +1499,9 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) rtw_err(rtwdev, "failed to set PCI cap, ret = %d\n", ret); } + + if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 5) + rtw_write32_mask(rtwdev, REG_ANAPARSW_MAC_0, BIT_CF_L_V2, 0x1); } static int __maybe_unused rtw_pci_suspend(struct device *dev) diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 1634f03784f1..b122f226924b 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -557,6 +557,9 @@ #define REG_RFE_INV16 0x0cbe #define BIT_RFE_BUF_EN BIT(3) +#define REG_ANAPARSW_MAC_0 0x1010 +#define BIT_CF_L_V2 GENMASK(29, 28) + #define REG_ANAPAR_XTAL_0 0x1040 #define BIT_XCAP_0 GENMASK(23, 10) #define REG_CPU_DMEM_CON 0x1080 From d55cb6d8a99441aff55cb9ce663a07f7f1667e83 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:22 +0100 Subject: [PATCH 0031/2255] wifi: rtl8xxxu: remove assignment of priv->vif in rtl8xxxu_bss_info_changed() priv->vif gets already set in rtl8xxxu_add_interface, there is no need to set it also in rtl8xxxu_bss_info_changed(). Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-2-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 180907319e8c..f82b51383377 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5004,7 +5004,6 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw); - priv->vif = vif; priv->rssi_level = RTL8XXXU_RATR_STA_INIT; priv->fops->update_rate_mask(priv, ramask, 0, sgi, From 2bbd7d584046038ce655e476628bb15e1460fac6 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:23 +0100 Subject: [PATCH 0032/2255] wifi: rtl8xxxu: prepare supporting two virtual interfaces To prepare for concurrent mode, add an array ("vifs") to rtl8xxxu_priv to keep track of both interfaces. Keep the old priv->vif as long there are still users of it and let priv->vifs[0] point to the same location. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-3-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 ++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 4695fb4e2d2d..b63fe084de92 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1897,6 +1897,8 @@ struct rtl8xxxu_priv { * is supported and no iface_combinations are provided. */ struct ieee80211_vif *vif; + + struct ieee80211_vif *vifs[2]; struct delayed_work ra_watchdog; struct work_struct c2hcmd_work; struct sk_buff_head c2hcmd_queue; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index f82b51383377..0e20e7b4552b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6569,10 +6569,12 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, int ret; u8 val8; - if (!priv->vif) + if (!priv->vif) { priv->vif = vif; - else + priv->vifs[0] = vif; + } else { return -EOPNOTSUPP; + } switch (vif->type) { case NL80211_IFTYPE_STATION: @@ -6622,8 +6624,10 @@ static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, dev_dbg(&priv->udev->dev, "%s\n", __func__); - if (priv->vif) + if (priv->vif) { priv->vif = NULL; + priv->vifs[0] = NULL; + } } static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) From 7f444692cde83c1455682c2d0d2c9a666422b867 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:24 +0100 Subject: [PATCH 0033/2255] wifi: rtl8xxxu: support setting linktype for both interfaces To prepare for concurrent mode, enhance the set_linktype function to be able to set the linktype in the MSR register for both hardware ports. Until the users of set_linktype can handle multiple interfaces, use port_num = 0. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-4-martin.kaistra@linutronix.de --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 0e20e7b4552b..f8572659e99e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -1633,33 +1633,41 @@ rtl8xxxu_gen1_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) } static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv, - enum nl80211_iftype linktype) + enum nl80211_iftype linktype, int port_num) { - u8 val8; - - val8 = rtl8xxxu_read8(priv, REG_MSR); - val8 &= ~MSR_LINKTYPE_MASK; + u8 val8, type; switch (linktype) { case NL80211_IFTYPE_UNSPECIFIED: - val8 |= MSR_LINKTYPE_NONE; + type = MSR_LINKTYPE_NONE; break; case NL80211_IFTYPE_ADHOC: - val8 |= MSR_LINKTYPE_ADHOC; + type = MSR_LINKTYPE_ADHOC; break; case NL80211_IFTYPE_STATION: - val8 |= MSR_LINKTYPE_STATION; + type = MSR_LINKTYPE_STATION; break; case NL80211_IFTYPE_AP: - val8 |= MSR_LINKTYPE_AP; + type = MSR_LINKTYPE_AP; break; default: - goto out; + return; + } + + switch (port_num) { + case 0: + val8 = rtl8xxxu_read8(priv, REG_MSR) & 0x0c; + val8 |= type; + break; + case 1: + val8 = rtl8xxxu_read8(priv, REG_MSR) & 0x03; + val8 |= type << 2; + break; + default: + return; } rtl8xxxu_write8(priv, REG_MSR, val8); -out: - return; } static void @@ -4236,7 +4244,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) } rtl8xxxu_set_mac(priv); - rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION); /* * Configure initial WMAC settings @@ -4964,7 +4971,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_ASSOC) { dev_dbg(dev, "Changed ASSOC: %i!\n", vif->cfg.assoc); - rtl8xxxu_set_linktype(priv, vif->type); + rtl8xxxu_set_linktype(priv, vif->type, 0); if (vif->cfg.assoc) { u32 ramask; @@ -6610,7 +6617,7 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, ret = -EOPNOTSUPP; } - rtl8xxxu_set_linktype(priv, vif->type); + rtl8xxxu_set_linktype(priv, vif->type, 0); ether_addr_copy(priv->mac_addr, vif->addr); rtl8xxxu_set_mac(priv); From a047e46a7b98de384a158b25a05dc09aa7d70c5f Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:25 +0100 Subject: [PATCH 0034/2255] wifi: rtl8xxxu: 8188e: convert usage of priv->vif to priv->vifs[0] The driver currently does not support AP or concurrent mode for 8188e, so just use priv->vifs[0] instead of priv->vif for now. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-5-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c index 6d0f975f891b..cbeac9386ae5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c @@ -1699,7 +1699,7 @@ void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *s /* We only use macid 0, so only the first item is relevant. * AP mode will use more of them if it's ever implemented. */ - if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION) + if (!priv->vifs[0] || priv->vifs[0]->type == NL80211_IFTYPE_STATION) items = 1; for (macid = 0; macid < items; macid++) { From 00add60cad3c9690ac0f9d4f6685f96ccd607670 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:26 +0100 Subject: [PATCH 0035/2255] wifi: rtl8xxxu: support setting mac address register for both interfaces To prepare for concurrent mode, enhance rtl8xxxu_set_mac() to write the mac address of the respective interface to REG_MACID or REG_MACID1. Remove the call to rtl8xxxu_set_mac() from the init function as we set it in rtl8xxxu_add_interface() later anyway. Until rtl8xxxu_add_interface() can handle both interfaces, call rtl8xxxu_set_mac() with port_num = 0. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-6-martin.kaistra@linutronix.de --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index f8572659e99e..02cf04455478 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3580,15 +3580,25 @@ void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); } -static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv) +static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv, int port_num) { int i; u16 reg; - reg = REG_MACID; + switch (port_num) { + case 0: + reg = REG_MACID; + break; + case 1: + reg = REG_MACID1; + break; + default: + WARN_ONCE("%s: invalid port_num\n", __func__); + return -EINVAL; + } for (i = 0; i < ETH_ALEN; i++) - rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]); + rtl8xxxu_write8(priv, reg + i, priv->vifs[port_num]->addr[i]); return 0; } @@ -4243,8 +4253,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff); } - rtl8xxxu_set_mac(priv); - /* * Configure initial WMAC settings */ @@ -6619,7 +6627,7 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, rtl8xxxu_set_linktype(priv, vif->type, 0); ether_addr_copy(priv->mac_addr, vif->addr); - rtl8xxxu_set_mac(priv); + rtl8xxxu_set_mac(priv, 0); return ret; } From 9aa776209ca31695bead52674ad943848ccc97d5 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:27 +0100 Subject: [PATCH 0036/2255] wifi: rtl8xxxu: extend wifi connected check to both interfaces There are multiple places in the code where the current connection status of wifi is checked. The driver will support two interfaces soon and either one of them (or both) could be connected. Convert all uses of (vif && vif->cfg.assoc) to a new helper function rtl8xxxu_is_assoc() which checks both interfaces. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-7-martin.kaistra@linutronix.de --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 02cf04455478..a87e6f92c03b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6043,18 +6043,20 @@ void rtl8723bu_update_bt_link_info(struct rtl8xxxu_priv *priv, u8 bt_info) btcoex->bt_busy = false; } +static inline bool rtl8xxxu_is_assoc(struct rtl8xxxu_priv *priv) +{ + return (priv->vifs[0] && priv->vifs[0]->cfg.assoc) || + (priv->vifs[1] && priv->vifs[1]->cfg.assoc); +} + static void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) { - struct ieee80211_vif *vif; struct rtl8xxxu_btcoex *btcoex; - bool wifi_connected; - vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->cfg.assoc); - if (!wifi_connected) { + if (!rtl8xxxu_is_assoc(priv)) { rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); rtl8723bu_set_coex_with_type(priv, 0); } else if (btcoex->has_sco || btcoex->has_hid || btcoex->has_a2dp) { @@ -6072,15 +6074,11 @@ void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) static void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) { - struct ieee80211_vif *vif; struct rtl8xxxu_btcoex *btcoex; - bool wifi_connected; - vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->cfg.assoc); - if (wifi_connected) { + if (rtl8xxxu_is_assoc(priv)) { u32 val32 = 0; u32 high_prio_tx = 0, high_prio_rx = 0; @@ -7103,7 +7101,7 @@ static void rtl8xxxu_track_cfo(struct rtl8xxxu_priv *priv) int cfo_khz_a, cfo_khz_b, cfo_average; int crystal_cap; - if (!priv->vif || !priv->vif->cfg.assoc) { + if (!rtl8xxxu_is_assoc(priv)) { /* Reset */ cfo->adjust = true; From 80fd8687db41b1e04f78c37137d090f2165cca6e Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:28 +0100 Subject: [PATCH 0037/2255] wifi: rtl8xxxu: extend check for matching bssid to both interfaces The driver will support two interfaces soon, which both can be in station mode, so extend the check, whether cfo information should be parsed, to cover both interfaces. For better code readability put the lines with priv->vifs[port_num] in a separate function. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-8-martin.kaistra@linutronix.de --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index a87e6f92c03b..63e7634eb0f1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5706,6 +5706,16 @@ static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) rtl8xxxu_send_beacon_frame(hw, vif); } +static inline bool rtl8xxxu_is_packet_match_bssid(struct rtl8xxxu_priv *priv, + struct ieee80211_hdr *hdr, + int port_num) +{ + return priv->vifs[port_num] && + priv->vifs[port_num]->type == NL80211_IFTYPE_STATION && + priv->vifs[port_num]->cfg.assoc && + ether_addr_equal(priv->vifs[port_num]->bss_conf.bssid, hdr->addr2); +} + void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv, struct ieee80211_rx_status *rx_status, struct rtl8723au_phy_stats *phy_stats, @@ -5722,12 +5732,10 @@ void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv, rx_status->signal = priv->fops->cck_rssi(priv, phy_stats); } else { bool parse_cfo = priv->fops->set_crystal_cap && - priv->vif && - priv->vif->type == NL80211_IFTYPE_STATION && - priv->vif->cfg.assoc && !crc_icv_err && !ieee80211_is_ctl(hdr->frame_control) && - ether_addr_equal(priv->vif->bss_conf.bssid, hdr->addr2); + (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) || + rtl8xxxu_is_packet_match_bssid(priv, hdr, 1)); if (parse_cfo) { priv->cfo_tracking.cfo_tail[0] = phy_stats->path_cfotail[0]; @@ -5762,12 +5770,10 @@ static void jaguar2_rx_parse_phystats_type1(struct rtl8xxxu_priv *priv, bool crc_icv_err) { bool parse_cfo = priv->fops->set_crystal_cap && - priv->vif && - priv->vif->type == NL80211_IFTYPE_STATION && - priv->vif->cfg.assoc && !crc_icv_err && !ieee80211_is_ctl(hdr->frame_control) && - ether_addr_equal(priv->vif->bss_conf.bssid, hdr->addr2); + (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) || + rtl8xxxu_is_packet_match_bssid(priv, hdr, 1)); u8 pwdb_max = 0; int rx_path; From f86dd8eaf8da84ee5b803d90b8c311d7e2725d0b Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:29 +0100 Subject: [PATCH 0038/2255] wifi: rtl8xxxu: don't parse CFO, if both interfaces are connected in STA mode If both interfaces are in STATION mode and both are connected to an AP, there might be conflicting CFO values for the two connections. Ignore the CFO information in this case. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-9-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 63e7634eb0f1..0eaafaf95ba2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5716,6 +5716,14 @@ static inline bool rtl8xxxu_is_packet_match_bssid(struct rtl8xxxu_priv *priv, ether_addr_equal(priv->vifs[port_num]->bss_conf.bssid, hdr->addr2); } +static inline bool rtl8xxxu_is_sta_sta(struct rtl8xxxu_priv *priv) +{ + return (priv->vifs[0] && priv->vifs[0]->cfg.assoc && + priv->vifs[0]->type == NL80211_IFTYPE_STATION) && + (priv->vifs[1] && priv->vifs[1]->cfg.assoc && + priv->vifs[1]->type == NL80211_IFTYPE_STATION); +} + void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv, struct ieee80211_rx_status *rx_status, struct rtl8723au_phy_stats *phy_stats, @@ -5734,6 +5742,7 @@ void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv, bool parse_cfo = priv->fops->set_crystal_cap && !crc_icv_err && !ieee80211_is_ctl(hdr->frame_control) && + !rtl8xxxu_is_sta_sta(priv) && (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) || rtl8xxxu_is_packet_match_bssid(priv, hdr, 1)); @@ -5772,6 +5781,7 @@ static void jaguar2_rx_parse_phystats_type1(struct rtl8xxxu_priv *priv, bool parse_cfo = priv->fops->set_crystal_cap && !crc_icv_err && !ieee80211_is_ctl(hdr->frame_control) && + !rtl8xxxu_is_sta_sta(priv) && (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) || rtl8xxxu_is_packet_match_bssid(priv, hdr, 1)); u8 pwdb_max = 0; From 3ff7a05996f901a7a10068b42e9dc8435f908a4c Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:30 +0100 Subject: [PATCH 0039/2255] wifi: rtl8xxxu: support setting bssid register for multiple interfaces To prepare for concurrent mode, enhance rtl8xxxu_set_bssid() to write the BSSID of the respective interface to REG_BSSID or REG_BSSID1. Like done with rtl8xxxu_set_mac(), call rtl8xxxu_set_bssid() with port_num = 0, until the callers also support multiple interfaces. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-10-martin.kaistra@linutronix.de --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 0eaafaf95ba2..71d9d48ef214 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3603,14 +3603,24 @@ static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv, int port_num) return 0; } -static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid) +static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid, int port_num) { int i; u16 reg; dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid); - reg = REG_BSSID; + switch (port_num) { + case 0: + reg = REG_BSSID; + break; + case 1: + reg = REG_BSSID1; + break; + default: + WARN_ONCE("%s: invalid port_num\n", __func__); + return -EINVAL; + } for (i = 0; i < ETH_ALEN; i++) rtl8xxxu_write8(priv, reg + i, bssid[i]); @@ -5068,7 +5078,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_BSSID) { dev_dbg(dev, "Changed BSSID!\n"); - rtl8xxxu_set_bssid(priv, bss_conf->bssid); + rtl8xxxu_set_bssid(priv, bss_conf->bssid, 0); } if (changed & BSS_CHANGED_BASIC_RATES) { @@ -5097,7 +5107,7 @@ static int rtl8xxxu_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct device *dev = &priv->udev->dev; dev_dbg(dev, "Start AP mode\n"); - rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid); + rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid, 0); rtl8xxxu_write16(priv, REG_BCN_INTERVAL, vif->bss_conf.beacon_int); priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, 0, true); From 43532c050f8eec4056a21978fdb5b958e1477553 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:31 +0100 Subject: [PATCH 0040/2255] wifi: rtl8xxxu: support multiple interfaces in set_aifs() In concurrent mode supported by this driver, both interfaces will use the same channel and same wireless mode. It is therefore possible to get the wireless mode by checking the first connected interface. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-11-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 71d9d48ef214..3adbcc4bccb5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4913,14 +4913,20 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time) u8 aifs, aifsn, sifs; int i; - if (priv->vif) { + for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { + if (!priv->vifs[i]) + continue; + struct ieee80211_sta *sta; rcu_read_lock(); - sta = ieee80211_find_sta(priv->vif, priv->vif->bss_conf.bssid); + sta = ieee80211_find_sta(priv->vifs[i], priv->vifs[i]->bss_conf.bssid); if (sta) wireless_mode = rtl8xxxu_wireless_mode(priv->hw, sta); rcu_read_unlock(); + + if (wireless_mode) + break; } if (priv->hw->conf.chandef.chan->band == NL80211_BAND_5GHZ || From 05b22e9b7d84253f765cde01cb09d144094b61c9 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:32 +0100 Subject: [PATCH 0041/2255] wifi: rtl8xxxu: support multiple interfaces in update_beacon_work_callback() As we only want to support AP mode/sending beacons on port 0, it is enough to replace priv->vif with priv->vifs[0]. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-12-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 3adbcc4bccb5..aeac40a892ff 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5712,7 +5712,7 @@ static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) struct rtl8xxxu_priv *priv = container_of(work, struct rtl8xxxu_priv, update_beacon_work); struct ieee80211_hw *hw = priv->hw; - struct ieee80211_vif *vif = priv->vif; + struct ieee80211_vif *vif = priv->vifs[0]; if (!vif) { WARN_ONCE(true, "no vif to update beacon\n"); From 6b76638287055791e74b32c401a39ea1b91e7158 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:33 +0100 Subject: [PATCH 0042/2255] wifi: rtl8xxxu: support multiple interfaces in configure_filter() As we only want to support AP mode/sending beacons on port 0, change from priv->vif to priv->vifs[0] in the check for AP mode. Additionally, if we are in AP mode, don't filter RX beacon and probe response frames to still allow working STATION mode on the other interface. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-13-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index aeac40a892ff..16a87e1cef61 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6794,8 +6794,8 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, else rcr |= RCR_CHECK_BSSID_BEACON | RCR_CHECK_BSSID_MATCH; - if (priv->vif && priv->vif->type == NL80211_IFTYPE_AP) - rcr &= ~RCR_CHECK_BSSID_MATCH; + if (priv->vifs[0] && priv->vifs[0]->type == NL80211_IFTYPE_AP) + rcr &= ~(RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON); if (*total_flags & FIF_CONTROL) rcr |= RCR_ACCEPT_CTRL_FRAME; From 3f9baa99f8429ea6f56e7cc8d881c027518e9573 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:34 +0100 Subject: [PATCH 0043/2255] wifi: rtl8xxxu: support multiple interfaces in watchdog_callback() Check first whether priv->vifs[0] exists and is of type STATION, then go to priv->vifs[1]. Make sure to call refresh_rate_mask for both interfaces. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-14-martin.kaistra@linutronix.de --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 16a87e1cef61..5f33171010b2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7200,11 +7200,15 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) { struct ieee80211_vif *vif; struct rtl8xxxu_priv *priv; + int i; priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); - vif = priv->vif; + for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { + vif = priv->vifs[i]; + + if (!vif || vif->type != NL80211_IFTYPE_STATION) + continue; - if (vif && vif->type == NL80211_IFTYPE_STATION) { int signal; struct ieee80211_sta *sta; @@ -7215,22 +7219,21 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) dev_dbg(dev, "%s: no sta found\n", __func__); rcu_read_unlock(); - goto out; + continue; } rcu_read_unlock(); signal = ieee80211_ave_rssi(vif); - priv->fops->report_rssi(priv, 0, + priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), rtl8xxxu_signal_to_snr(signal)); - if (priv->fops->set_crystal_cap) - rtl8xxxu_track_cfo(priv); - rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); } -out: + if (priv->fops->set_crystal_cap) + rtl8xxxu_track_cfo(priv); + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); } From eef55f1545c92c7181d5083453dee1296298ad3e Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:35 +0100 Subject: [PATCH 0044/2255] wifi: rtl8xxxu: support multiple interfaces in {add,remove}_interface() Add a custom struct to store in vif->drv_priv with a reference to port_num and fill it when a new interface is added. Choose a free port_num for the newly added interface. As we only want to support AP mode/sending beacons on port 0, only change the beacon settings if a new interface is actually assigned to port 0. Call set_linktype() and set_mac() with the appropriate port_num. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-15-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++ .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 54 +++++++++++-------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index b63fe084de92..9d272da373a3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1921,6 +1921,10 @@ struct rtl8xxxu_sta_info { u8 macid; }; +struct rtl8xxxu_vif { + int port_num; +}; + struct rtl8xxxu_rx_urb { struct urb urb; struct ieee80211_hw *hw; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 5f33171010b2..9ea37f47ae57 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6610,28 +6610,33 @@ error: static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; - int ret; + int port_num; u8 val8; - if (!priv->vif) { - priv->vif = vif; - priv->vifs[0] = vif; - } else { + if (!priv->vifs[0]) + port_num = 0; + else if (!priv->vifs[1]) + port_num = 1; + else return -EOPNOTSUPP; - } switch (vif->type) { case NL80211_IFTYPE_STATION: - rtl8xxxu_stop_tx_beacon(priv); + if (port_num == 0) { + rtl8xxxu_stop_tx_beacon(priv); - val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); - val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE | - BEACON_DISABLE_TSF_UPDATE; - rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); - ret = 0; + val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE | + BEACON_DISABLE_TSF_UPDATE; + rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); + } break; case NL80211_IFTYPE_AP: + if (port_num == 1) + return -EOPNOTSUPP; + rtl8xxxu_write8(priv, REG_BEACON_CTRL, BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID); rtl8xxxu_write8(priv, REG_ATIMWND, 0x0c); /* 12ms */ @@ -6648,31 +6653,32 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, val8 = rtl8xxxu_read8(priv, REG_CCK_CHECK); val8 &= ~BIT_BCN_PORT_SEL; rtl8xxxu_write8(priv, REG_CCK_CHECK, val8); - - ret = 0; break; default: - ret = -EOPNOTSUPP; + return -EOPNOTSUPP; } - rtl8xxxu_set_linktype(priv, vif->type, 0); - ether_addr_copy(priv->mac_addr, vif->addr); - rtl8xxxu_set_mac(priv, 0); + priv->vifs[port_num] = vif; + priv->vif = vif; + rtlvif->port_num = port_num; - return ret; + rtl8xxxu_set_linktype(priv, vif->type, port_num); + ether_addr_copy(priv->mac_addr, vif->addr); + rtl8xxxu_set_mac(priv, port_num); + + return 0; } static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; dev_dbg(&priv->udev->dev, "%s\n", __func__); - if (priv->vif) { - priv->vif = NULL; - priv->vifs[0] = NULL; - } + priv->vif = NULL; + priv->vifs[rtlvif->port_num] = NULL; } static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) @@ -7662,6 +7668,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, if (ret) goto err_set_intfdata; + hw->vif_data_size = sizeof(struct rtl8xxxu_vif); + hw->wiphy->max_scan_ssids = 1; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; if (priv->fops->max_macid_num) From 073401c3b6b9eaea027240baf07f2b84dd2d2d26 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:36 +0100 Subject: [PATCH 0045/2255] wifi: rtl8xxxu: support multiple interfaces in bss_info_changed() Call set_linktype and set_bssid now with correct port_num. Call stop_tx_beacon only for port 0, as we don't support beacons on port 1. Explicit changes to BEACON will only happen for AP type interfaces, so we don't need an additional check there. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-16-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 9ea37f47ae57..ae71730d7a9b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4983,6 +4983,7 @@ static void rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u64 changed) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; struct ieee80211_sta *sta; @@ -4995,7 +4996,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_ASSOC) { dev_dbg(dev, "Changed ASSOC: %i!\n", vif->cfg.assoc); - rtl8xxxu_set_linktype(priv, vif->type, 0); + rtl8xxxu_set_linktype(priv, vif->type, rtlvif->port_num); if (vif->cfg.assoc) { u32 ramask; @@ -5042,7 +5043,8 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); - rtl8xxxu_stop_tx_beacon(priv); + if (rtlvif->port_num == 0) + rtl8xxxu_stop_tx_beacon(priv); /* joinbss sequence */ rtl8xxxu_write16(priv, REG_BCN_PSR_RPT, @@ -5084,7 +5086,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_BSSID) { dev_dbg(dev, "Changed BSSID!\n"); - rtl8xxxu_set_bssid(priv, bss_conf->bssid, 0); + rtl8xxxu_set_bssid(priv, bss_conf->bssid, rtlvif->port_num); } if (changed & BSS_CHANGED_BASIC_RATES) { From 61fdbd9e2a9d74c716bf4d9684653de5efdee691 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:37 +0100 Subject: [PATCH 0046/2255] wifi: rtl8xxxu: support multiple interface in start_ap() Call set_bssid() with the correct port_num now. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-17-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index ae71730d7a9b..11439579584c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5111,11 +5111,12 @@ error: static int rtl8xxxu_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; dev_dbg(dev, "Start AP mode\n"); - rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid, 0); + rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid, rtlvif->port_num); rtl8xxxu_write16(priv, REG_BCN_INTERVAL, vif->bss_conf.beacon_int); priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, 0, true); From 5ce0d7e8aee03e73b35f0fe1f1ebbdd4e45776f3 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:38 +0100 Subject: [PATCH 0047/2255] wifi: rtl8xxxu: add macids for STA mode Until now, the driver only assigned a dedicated macid for connections made in AP mode, in STA mode the return value of rtl8xxxu_get_macid() was simply 0. To differentiate between port 0 and 1, when both are in STA mode, allocate a second macid (with value 1) and set sta_info->macid according to the used port_num in rtl8xxxu_sta_add(). Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-18-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 9d272da373a3..6a58897446f4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1774,6 +1774,7 @@ struct rtl8xxxu_cfo_tracking { #define RTL8XXXU_HW_LED_CONTROL 2 #define RTL8XXXU_MAX_MAC_ID_NUM 128 #define RTL8XXXU_BC_MC_MACID 0 +#define RTL8XXXU_BC_MC_MACID1 1 struct rtl8xxxu_priv { struct ieee80211_hw *hw; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 11439579584c..09de60251a36 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4053,10 +4053,13 @@ static inline u8 rtl8xxxu_get_macid(struct rtl8xxxu_priv *priv, { struct rtl8xxxu_sta_info *sta_info; - if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION || !sta) + if (!sta) return 0; sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + if (!sta_info) + return 0; + return sta_info->macid; } @@ -4536,6 +4539,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8188e_ra_info_init_all(&priv->ra_info); set_bit(RTL8XXXU_BC_MC_MACID, priv->mac_id_map); + set_bit(RTL8XXXU_BC_MC_MACID1, priv->mac_id_map); exit: return ret; @@ -7375,6 +7379,7 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; if (vif->type == NL80211_IFTYPE_AP) { @@ -7384,6 +7389,17 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, rtl8xxxu_refresh_rate_mask(priv, 0, sta, true); priv->fops->report_connect(priv, sta_info->macid, H2C_MACID_ROLE_STA, true); + } else { + switch (rtlvif->port_num) { + case 0: + sta_info->macid = RTL8XXXU_BC_MC_MACID; + break; + case 1: + sta_info->macid = RTL8XXXU_BC_MC_MACID1; + break; + default: + break; + } } return 0; From f232e9d91bb84817c60c051a3e3b56dd2721a7b3 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:39 +0100 Subject: [PATCH 0048/2255] wifi: rtl8xxxu: remove obsolete priv->vif Now that all uses of priv->vif have been converted to priv->vifs[] remove the old attribute. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-19-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 5 ----- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 -- 2 files changed, 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 6a58897446f4..c5e6d8f7d26b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1893,11 +1893,6 @@ struct rtl8xxxu_priv { u8 rssi_level; DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS); DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS); - /* - * Only one virtual interface permitted because only STA mode - * is supported and no iface_combinations are provided. - */ - struct ieee80211_vif *vif; struct ieee80211_vif *vifs[2]; struct delayed_work ra_watchdog; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 09de60251a36..07cfce55a519 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6666,7 +6666,6 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, } priv->vifs[port_num] = vif; - priv->vif = vif; rtlvif->port_num = port_num; rtl8xxxu_set_linktype(priv, vif->type, port_num); @@ -6684,7 +6683,6 @@ static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, dev_dbg(&priv->udev->dev, "%s\n", __func__); - priv->vif = NULL; priv->vifs[rtlvif->port_num] = NULL; } From b837f78fbffa5f8e7e7c59879db54793abf161ec Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:40 +0100 Subject: [PATCH 0049/2255] wifi: rtl8xxxu: add hw crypto support for AP mode Add a custom function for allocating entries in the sec cam. This allows us to store multiple keys with the same keyidx. The maximum number of sec cam entries for 8188f is 16 according to the vendor driver. Add the number to rtl8xxxu_fileops, so that other chips which might support more entries, can set a different number there. Set the bssid as mac address for group keys instead of just using the ethernet broadcast address and use BIT(6) in the sec cam ctrl entry for differentiating them from pairwise keys like in the vendor driver. Add the TXDESC_EN_DESC_ID bit and the hw_key_idx to tx broadcast/multicast packets in AP mode. Finally, allow the usage of rtl8xxxu_set_key() for AP mode. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-20-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 5 ++ .../realtek/rtl8xxxu/rtl8xxxu_8188f.c | 1 + .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 48 +++++++++++++++---- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index c5e6d8f7d26b..62e6318bc092 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -498,6 +498,7 @@ struct rtl8xxxu_txdesc40 { #define DESC_RATE_ID_SHIFT 16 #define DESC_RATE_ID_MASK 0xf #define TXDESC_NAVUSEHDR BIT(20) +#define TXDESC_EN_DESC_ID BIT(21) #define TXDESC_SEC_RC4 0x00400000 #define TXDESC_SEC_AES 0x00c00000 #define TXDESC_PKT_OFFSET_SHIFT 26 @@ -1775,6 +1776,7 @@ struct rtl8xxxu_cfo_tracking { #define RTL8XXXU_MAX_MAC_ID_NUM 128 #define RTL8XXXU_BC_MC_MACID 0 #define RTL8XXXU_BC_MC_MACID1 1 +#define RTL8XXXU_MAX_SEC_CAM_NUM 64 struct rtl8xxxu_priv { struct ieee80211_hw *hw; @@ -1908,6 +1910,7 @@ struct rtl8xxxu_priv { char led_name[32]; struct led_classdev led_cdev; DECLARE_BITMAP(mac_id_map, RTL8XXXU_MAX_MAC_ID_NUM); + DECLARE_BITMAP(cam_map, RTL8XXXU_MAX_SEC_CAM_NUM); }; struct rtl8xxxu_sta_info { @@ -1919,6 +1922,7 @@ struct rtl8xxxu_sta_info { struct rtl8xxxu_vif { int port_num; + u8 hw_key_idx; }; struct rtl8xxxu_rx_urb { @@ -1993,6 +1997,7 @@ struct rtl8xxxu_fileops { u16 max_aggr_num; u8 supports_ap:1; u16 max_macid_num; + u16 max_sec_cam_num; u32 adda_1t_init; u32 adda_1t_path_on; u32 adda_2t_path_on_a; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 1e1c8fa194cb..574a5fe95154 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -1751,6 +1751,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .max_aggr_num = 0x0c14, .supports_ap = 1, .max_macid_num = 16, + .max_sec_cam_num = 16, .adda_1t_init = 0x03c00014, .adda_1t_path_on = 0x03c00014, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 07cfce55a519..fb2bb042683a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4559,8 +4559,10 @@ static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv, * This is a bit of a hack - the lower bits of the cipher * suite selector happens to match the cipher index in the CAM */ - addr = key->keyidx << CAM_CMD_KEY_SHIFT; + addr = key->hw_key_idx << CAM_CMD_KEY_SHIFT; ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID; + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + ctrl |= BIT(6); for (j = 5; j >= 0; j--) { switch (j) { @@ -5546,13 +5548,14 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct rtl8xxxu_tx_urb *tx_urb; struct ieee80211_sta *sta = NULL; struct ieee80211_vif *vif = tx_info->control.vif; + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct device *dev = &priv->udev->dev; u32 queue, rts_rate; u16 pktlen = skb->len; int tx_desc_size = priv->fops->tx_desc_size; u8 macid; int ret; - bool ampdu_enable, sgi = false, short_preamble = false; + bool ampdu_enable, sgi = false, short_preamble = false, bmc = false; if (skb_headroom(skb) < tx_desc_size) { dev_warn(dev, @@ -5594,10 +5597,14 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, tx_desc->txdw0 = TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT; if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || - is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) { tx_desc->txdw0 |= TXDESC_BROADMULTICAST; + bmc = true; + } + tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT); + macid = rtl8xxxu_get_macid(priv, sta); if (tx_info->control.hw_key) { switch (tx_info->control.hw_key->cipher) { @@ -5612,6 +5619,10 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, default: break; } + if (bmc && rtlvif->hw_key_idx != 0xff) { + tx_desc->txdw1 |= TXDESC_EN_DESC_ID; + macid = rtlvif->hw_key_idx; + } } /* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */ @@ -5655,7 +5666,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, else rts_rate = 0; - macid = rtl8xxxu_get_macid(priv, sta); priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, ampdu_enable, rts_rate, macid); @@ -6667,6 +6677,7 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, priv->vifs[port_num] = vif; rtlvif->port_num = port_num; + rtlvif->hw_key_idx = 0xff; rtl8xxxu_set_linktype(priv, vif->type, port_num); ether_addr_copy(priv->mac_addr, vif->addr); @@ -6843,11 +6854,19 @@ static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts) return 0; } +static int rtl8xxxu_get_free_sec_cam(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + + return find_first_zero_bit(priv->cam_map, priv->fops->max_sec_cam_num); +} + static int rtl8xxxu_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 rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; u8 mac_addr[ETH_ALEN]; @@ -6859,9 +6878,6 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n", __func__, cmd, key->cipher, key->keyidx); - if (vif->type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - if (key->keyidx > 3) return -EOPNOTSUPP; @@ -6885,7 +6901,7 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ether_addr_copy(mac_addr, sta->addr); } else { dev_dbg(dev, "%s: group key\n", __func__); - eth_broadcast_addr(mac_addr); + ether_addr_copy(mac_addr, vif->bss_conf.bssid); } val16 = rtl8xxxu_read16(priv, REG_CR); @@ -6899,16 +6915,28 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - key->hw_key_idx = key->keyidx; + + retval = rtl8xxxu_get_free_sec_cam(hw); + if (retval < 0) + return -EOPNOTSUPP; + + key->hw_key_idx = retval; + + if (vif->type == NL80211_IFTYPE_AP && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + rtlvif->hw_key_idx = key->hw_key_idx; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; rtl8xxxu_cam_write(priv, key, mac_addr); + set_bit(key->hw_key_idx, priv->cam_map); retval = 0; break; case DISABLE_KEY: rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000); val32 = CAM_CMD_POLLING | CAM_CMD_WRITE | - key->keyidx << CAM_CMD_KEY_SHIFT; + key->hw_key_idx << CAM_CMD_KEY_SHIFT; rtl8xxxu_write32(priv, REG_CAM_CMD, val32); + rtlvif->hw_key_idx = 0xff; + clear_bit(key->hw_key_idx, priv->cam_map); retval = 0; break; default: From 69abad618efd17e50bc6f880332ab36b660b0b34 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:41 +0100 Subject: [PATCH 0050/2255] wifi: rtl8xxxu: make supporting AP mode only on port 0 transparent When the driver is used for concurrent mode, both virtual interfaces can be set to station or AP mode, though only one can be in AP mode at the same time. In order to keep the code simple, use only hw port 0 for AP mode. When an interface is added in AP mode which would be assigned to port 1, use a switch_port function to transparently swap the mapping between virtual interface and hw port. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-21-martin.kaistra@linutronix.de --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 91 ++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index fb2bb042683a..911155843655 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6624,6 +6624,91 @@ error: return ret; } +static void rtl8xxxu_switch_ports(struct rtl8xxxu_priv *priv) +{ + u8 macid[ETH_ALEN], bssid[ETH_ALEN], macid_1[ETH_ALEN], bssid_1[ETH_ALEN]; + u8 msr, bcn_ctrl, bcn_ctrl_1, atimwnd[2], atimwnd_1[2]; + struct rtl8xxxu_vif *rtlvif; + struct ieee80211_vif *vif; + u8 tsftr[8], tsftr_1[8]; + int i; + + msr = rtl8xxxu_read8(priv, REG_MSR); + bcn_ctrl = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + bcn_ctrl_1 = rtl8xxxu_read8(priv, REG_BEACON_CTRL_1); + + for (i = 0; i < ARRAY_SIZE(atimwnd); i++) + atimwnd[i] = rtl8xxxu_read8(priv, REG_ATIMWND + i); + for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++) + atimwnd_1[i] = rtl8xxxu_read8(priv, REG_ATIMWND_1 + i); + + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + tsftr[i] = rtl8xxxu_read8(priv, REG_TSFTR + i); + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + tsftr_1[i] = rtl8xxxu_read8(priv, REG_TSFTR1 + i); + + for (i = 0; i < ARRAY_SIZE(macid); i++) + macid[i] = rtl8xxxu_read8(priv, REG_MACID + i); + + for (i = 0; i < ARRAY_SIZE(bssid); i++) + bssid[i] = rtl8xxxu_read8(priv, REG_BSSID + i); + + for (i = 0; i < ARRAY_SIZE(macid_1); i++) + macid_1[i] = rtl8xxxu_read8(priv, REG_MACID1 + i); + + for (i = 0; i < ARRAY_SIZE(bssid_1); i++) + bssid_1[i] = rtl8xxxu_read8(priv, REG_BSSID1 + i); + + /* disable bcn function, disable update TSF */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, (bcn_ctrl & + (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE); + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, (bcn_ctrl_1 & + (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE); + + /* switch msr */ + msr = (msr & 0xf0) | ((msr & 0x03) << 2) | ((msr & 0x0c) >> 2); + rtl8xxxu_write8(priv, REG_MSR, msr); + + /* write port0 */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1 & ~BEACON_FUNCTION_ENABLE); + for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++) + rtl8xxxu_write8(priv, REG_ATIMWND + i, atimwnd_1[i]); + for (i = 0; i < ARRAY_SIZE(tsftr_1); i++) + rtl8xxxu_write8(priv, REG_TSFTR + i, tsftr_1[i]); + for (i = 0; i < ARRAY_SIZE(macid_1); i++) + rtl8xxxu_write8(priv, REG_MACID + i, macid_1[i]); + for (i = 0; i < ARRAY_SIZE(bssid_1); i++) + rtl8xxxu_write8(priv, REG_BSSID + i, bssid_1[i]); + + /* write port1 */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl & ~BEACON_FUNCTION_ENABLE); + for (i = 0; i < ARRAY_SIZE(atimwnd); i++) + rtl8xxxu_write8(priv, REG_ATIMWND_1 + i, atimwnd[i]); + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + rtl8xxxu_write8(priv, REG_TSFTR1 + i, tsftr[i]); + for (i = 0; i < ARRAY_SIZE(macid); i++) + rtl8xxxu_write8(priv, REG_MACID1 + i, macid[i]); + for (i = 0; i < ARRAY_SIZE(bssid); i++) + rtl8xxxu_write8(priv, REG_BSSID1 + i, bssid[i]); + + /* write bcn ctl */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1); + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl); + + vif = priv->vifs[0]; + priv->vifs[0] = priv->vifs[1]; + priv->vifs[1] = vif; + + /* priv->vifs[0] is NULL here, based on how this function is currently + * called from rtl8xxxu_add_interface(). + * When this function will be used in the future for a different + * scenario, please check whether vifs[0] or vifs[1] can be NULL and if + * necessary add code to set port_num = 1. + */ + rtlvif = (struct rtl8xxxu_vif *)priv->vifs[1]->drv_priv; + rtlvif->port_num = 1; +} + static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -6651,8 +6736,10 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, } break; case NL80211_IFTYPE_AP: - if (port_num == 1) - return -EOPNOTSUPP; + if (port_num == 1) { + rtl8xxxu_switch_ports(priv); + port_num = 0; + } rtl8xxxu_write8(priv, REG_BEACON_CTRL, BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID); From 1cd165adf314f6bf25cde58f02f4ff51d01730b0 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 22 Dec 2023 11:14:42 +0100 Subject: [PATCH 0051/2255] wifi: rtl8xxxu: declare concurrent mode support for 8188f Everything is in place now for concurrent mode, we can tell the system that we support it. We will allow a maximum of 2 virtual interfaces, one of them can be in AP mode. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20231222101442.626837-22-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../realtek/rtl8xxxu/rtl8xxxu_8188f.c | 1 + .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 62e6318bc092..803c76b3209c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1992,6 +1992,7 @@ struct rtl8xxxu_fileops { u8 init_reg_rxfltmap:1; u8 init_reg_pkt_life_time:1; u8 init_reg_hmtfr:1; + u8 supports_concurrent:1; u8 ampdu_max_time; u8 ustime_tsf_edca; u16 max_aggr_num; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 574a5fe95154..464216d007ce 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -1752,6 +1752,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .supports_ap = 1, .max_macid_num = 16, .max_sec_cam_num = 16, + .supports_concurrent = 1, .adda_1t_init = 0x03c00014, .adda_1t_path_on = 0x03c00014, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 911155843655..921d25e152cf 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7665,6 +7665,20 @@ static void rtl8xxxu_deinit_led(struct rtl8xxxu_priv *priv) led_classdev_unregister(led); } +struct ieee80211_iface_limit rtl8xxxu_limits[] = { + { .max = 2, .types = BIT(NL80211_IFTYPE_STATION), }, + { .max = 1, .types = BIT(NL80211_IFTYPE_AP), }, +}; + +struct ieee80211_iface_combination rtl8xxxu_combinations[] = { + { + .limits = rtl8xxxu_limits, + .n_limits = ARRAY_SIZE(rtl8xxxu_limits), + .max_interfaces = 2, + .num_different_channels = 1, + }, +}; + static int rtl8xxxu_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -7811,6 +7825,11 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); hw->queues = 4; + if (priv->fops->supports_concurrent) { + hw->wiphy->iface_combinations = rtl8xxxu_combinations; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtl8xxxu_combinations); + } + sband = &rtl8xxxu_supported_band; sband->ht_cap.ht_supported = true; sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; From 9475cc7ac31503521af95e38151e9d856e8ff30b Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sun, 31 Dec 2023 00:45:54 +0200 Subject: [PATCH 0052/2255] wifi: rtl8xxxu: Fix LED control code of RTL8192FU Some devices, like the Comfast CF-826F, use LED1, which already works. Others, like Asus USB-N13 C1, use LED0, which doesn't work correctly. Write the right values to the LED control registers to make LED0 work as well. This is unfortunately tested only with the Comfast CF-826F. Signed-off-by: Bitterblue Smith Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/7a2c3158-3a45-4466-b11e-fc09802b20e2@gmail.com --- .../realtek/rtl8xxxu/rtl8xxxu_8192f.c | 32 +++++++++++++------ .../wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 15 +++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c index 28e93835e05a..585b1a5eed69 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c @@ -2014,26 +2014,40 @@ static int rtl8192fu_led_brightness_set(struct led_classdev *led_cdev, struct rtl8xxxu_priv *priv = container_of(led_cdev, struct rtl8xxxu_priv, led_cdev); - u16 ledcfg; + u32 ledcfg; /* Values obtained by observing the USB traffic from the Windows driver. */ rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_0, 0x20080); rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_1, 0x1b0000); - ledcfg = rtl8xxxu_read16(priv, REG_LEDCFG0); + ledcfg = rtl8xxxu_read32(priv, REG_LEDCFG0); + + /* Comfast CF-826F uses LED1. Asus USB-N13 C1 uses LED0. Set both. */ + + u32p_replace_bits(&ledcfg, LED_GPIO_ENABLE, LEDCFG0_LED2EN); + u32p_replace_bits(&ledcfg, LED_IO_MODE_OUTPUT, LEDCFG0_LED0_IO_MODE); + u32p_replace_bits(&ledcfg, LED_IO_MODE_OUTPUT, LEDCFG0_LED1_IO_MODE); if (brightness == LED_OFF) { - /* Value obtained like above. */ - ledcfg = BIT(1) | BIT(7); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED0CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED0SV); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED1CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED1SV); } else if (brightness == LED_ON) { - /* Value obtained like above. */ - ledcfg = BIT(1) | BIT(7) | BIT(11); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED0CM); + u32p_replace_bits(&ledcfg, LED_SW_ON, LEDCFG0_LED0SV); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED1CM); + u32p_replace_bits(&ledcfg, LED_SW_ON, LEDCFG0_LED1SV); } else if (brightness == RTL8XXXU_HW_LED_CONTROL) { - /* Value obtained by brute force. */ - ledcfg = BIT(8) | BIT(9); + u32p_replace_bits(&ledcfg, LED_MODE_TX_OR_RX_EVENTS, + LEDCFG0_LED0CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED0SV); + u32p_replace_bits(&ledcfg, LED_MODE_TX_OR_RX_EVENTS, + LEDCFG0_LED1CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED1SV); } - rtl8xxxu_write16(priv, REG_LEDCFG0, ledcfg); + rtl8xxxu_write32(priv, REG_LEDCFG0, ledcfg); return 0; } diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 920ee50e2115..61c0c0ec07b3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -146,6 +146,21 @@ #define GPIO_INTM_EDGE_TRIG_IRQ BIT(9) #define REG_LEDCFG0 0x004c +#define LEDCFG0_LED0CM GENMASK(2, 0) +#define LEDCFG0_LED1CM GENMASK(10, 8) +#define LED_MODE_SW_CTRL 0x0 +#define LED_MODE_TX_OR_RX_EVENTS 0x3 +#define LEDCFG0_LED0SV BIT(3) +#define LEDCFG0_LED1SV BIT(11) +#define LED_SW_OFF 0x0 +#define LED_SW_ON 0x1 +#define LEDCFG0_LED0_IO_MODE BIT(7) +#define LEDCFG0_LED1_IO_MODE BIT(15) +#define LED_IO_MODE_OUTPUT 0x0 +#define LED_IO_MODE_INPUT 0x1 +#define LEDCFG0_LED2EN BIT(21) +#define LED_GPIO_DISABLE 0x0 +#define LED_GPIO_ENABLE 0x1 #define LEDCFG0_DPDT_SELECT BIT(23) #define REG_LEDCFG1 0x004d #define LEDCFG1_HW_LED_CONTROL BIT(1) From 80850ca041f2c7ee28fa5e47c5c1b106415f099f Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 2 Jan 2024 21:33:07 +0200 Subject: [PATCH 0053/2255] wifi: rtl8xxxu: Fix off by one initial RTS rate rtl8xxxu_set_basic_rates() sets the wrong initial RTS rate. It sets the next higher rate than the one it should set, e.g. 36M instead of 24M. The while loop was supposed to find the index of the most significant bit which is 1, but it was copied incorrectly from the vendor driver. Use __fls() instead. Signed-off-by: Bitterblue Smith Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/761e6836-6cd6-4930-91b6-0446834655c5@gmail.com --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 921d25e152cf..aac594093629 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4870,10 +4870,9 @@ static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__, rate_cfg); - while (rate_cfg) { - rate_cfg = (rate_cfg >> 1); - rate_idx++; - } + if (rate_cfg) + rate_idx = __fls(rate_cfg); + rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx); } From 9636951e4468f02c72cc75a82dc65d003077edbc Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:33 +0000 Subject: [PATCH 0054/2255] wifi: b43: Stop/wake correct queue in DMA Tx path when QoS is disabled When QoS is disabled, the queue priority value will not map to the correct ieee80211 queue since there is only one queue. Stop/wake queue 0 when QoS is disabled to prevent trying to stop/wake a non-existent queue and failing to stop/wake the actual queue instantiated. Log of issue before change (with kernel parameter qos=0): [ +5.112651] ------------[ cut here ]------------ [ +0.000005] WARNING: CPU: 7 PID: 25513 at net/mac80211/util.c:449 __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000067] Modules linked in: b43(O) snd_seq_dummy snd_hrtimer snd_seq snd_seq_device nft_chain_nat xt_MASQUERADE nf_nat xfrm_user xfrm_algo xt_addrtype overlay ccm af_packet amdgpu snd_hda_codec_cirrus snd_hda_codec_generic ledtrig_audio drm_exec amdxcp gpu_sched xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip6t_rpfilter ipt_rpfilter xt_pkttype xt_LOG nf_log_syslog xt_tcpudp nft_compat nf_tables nfnetlink sch_fq_codel btusb uinput iTCO_wdt ctr btrtl intel_pmc_bxt i915 intel_rapl_msr mei_hdcp mei_pxp joydev at24 watchdog btintel atkbd libps2 serio radeon btbcm vivaldi_fmap btmtk intel_rapl_common snd_hda_codec_hdmi bluetooth uvcvideo nls_iso8859_1 applesmc nls_cp437 x86_pkg_temp_thermal snd_hda_intel intel_powerclamp vfat videobuf2_vmalloc coretemp fat snd_intel_dspcfg crc32_pclmul uvc polyval_clmulni snd_intel_sdw_acpi loop videobuf2_memops snd_hda_codec tun drm_suballoc_helper polyval_generic drm_ttm_helper drm_buddy tap ecdh_generic videobuf2_v4l2 gf128mul macvlan ttm ghash_clmulni_intel ecc tg3 [ +0.000044] videodev bridge snd_hda_core rapl crc16 drm_display_helper cec mousedev snd_hwdep evdev intel_cstate bcm5974 hid_appleir videobuf2_common stp mac_hid libphy snd_pcm drm_kms_helper acpi_als mei_me intel_uncore llc mc snd_timer intel_gtt industrialio_triggered_buffer apple_mfi_fastcharge i2c_i801 mei snd lpc_ich agpgart ptp i2c_smbus thunderbolt apple_gmux i2c_algo_bit kfifo_buf video industrialio soundcore pps_core wmi tiny_power_button sbs sbshc button ac cordic bcma mac80211 cfg80211 ssb rfkill libarc4 kvm_intel kvm drm irqbypass fuse backlight firmware_class efi_pstore configfs efivarfs dmi_sysfs ip_tables x_tables autofs4 dm_crypt cbc encrypted_keys trusted asn1_encoder tee tpm rng_core input_leds hid_apple led_class hid_generic usbhid hid sd_mod t10_pi crc64_rocksoft crc64 crc_t10dif crct10dif_generic ahci libahci libata uhci_hcd ehci_pci ehci_hcd crct10dif_pclmul crct10dif_common sha512_ssse3 sha512_generic sha256_ssse3 sha1_ssse3 aesni_intel usbcore scsi_mod libaes crypto_simd cryptd scsi_common [ +0.000055] usb_common rtc_cmos btrfs blake2b_generic libcrc32c crc32c_generic crc32c_intel xor raid6_pq dm_snapshot dm_bufio dm_mod dax [last unloaded: b43(O)] [ +0.000009] CPU: 7 PID: 25513 Comm: irq/17-b43 Tainted: G W O 6.6.7 #1-NixOS [ +0.000003] Hardware name: Apple Inc. MacBookPro8,3/Mac-942459F5819B171B, BIOS 87.0.0.0.0 06/13/2019 [ +0.000001] RIP: 0010:__ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000046] Code: 00 45 85 e4 0f 85 9b 00 00 00 48 8d bd 40 09 00 00 f0 48 0f ba ad 48 09 00 00 00 72 0f 5b 5d 41 5c 41 5d 41 5e e9 cb 6d 3c d0 <0f> 0b 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8d b4 16 94 00 00 [ +0.000002] RSP: 0018:ffffc90003c77d60 EFLAGS: 00010097 [ +0.000001] RAX: 0000000000000001 RBX: 0000000000000002 RCX: 0000000000000000 [ +0.000001] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff88820b924900 [ +0.000002] RBP: ffff88820b924900 R08: ffffc90003c77d90 R09: 000000000003bfd0 [ +0.000001] R10: ffff88820b924900 R11: ffffc90003c77c68 R12: 0000000000000000 [ +0.000001] R13: 0000000000000000 R14: ffffc90003c77d90 R15: ffffffffc0fa6f40 [ +0.000001] FS: 0000000000000000(0000) GS:ffff88846fb80000(0000) knlGS:0000000000000000 [ +0.000001] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ +0.000001] CR2: 00007fafda7ae008 CR3: 000000046d220005 CR4: 00000000000606e0 [ +0.000002] Call Trace: [ +0.000003] [ +0.000001] ? __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000044] ? __warn+0x81/0x130 [ +0.000005] ? __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000045] ? report_bug+0x171/0x1a0 [ +0.000004] ? handle_bug+0x41/0x70 [ +0.000004] ? exc_invalid_op+0x17/0x70 [ +0.000003] ? asm_exc_invalid_op+0x1a/0x20 [ +0.000005] ? __ieee80211_wake_queue+0xd5/0x180 [mac80211] [ +0.000043] ieee80211_wake_queue+0x4a/0x80 [mac80211] [ +0.000044] b43_dma_handle_txstatus+0x29c/0x3a0 [b43] [ +0.000016] ? __pfx_irq_thread_fn+0x10/0x10 [ +0.000002] b43_handle_txstatus+0x61/0x80 [b43] [ +0.000012] b43_interrupt_thread_handler+0x3f9/0x6b0 [b43] [ +0.000011] irq_thread_fn+0x23/0x60 [ +0.000002] irq_thread+0xfe/0x1c0 [ +0.000002] ? __pfx_irq_thread_dtor+0x10/0x10 [ +0.000001] ? __pfx_irq_thread+0x10/0x10 [ +0.000001] kthread+0xe8/0x120 [ +0.000003] ? __pfx_kthread+0x10/0x10 [ +0.000003] ret_from_fork+0x34/0x50 [ +0.000002] ? __pfx_kthread+0x10/0x10 [ +0.000002] ret_from_fork_asm+0x1b/0x30 [ +0.000004] [ +0.000001] ---[ end trace 0000000000000000 ]--- [ +0.000065] ------------[ cut here ]------------ [ +0.000001] WARNING: CPU: 0 PID: 56077 at net/mac80211/util.c:514 __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000077] Modules linked in: b43(O) snd_seq_dummy snd_hrtimer snd_seq snd_seq_device nft_chain_nat xt_MASQUERADE nf_nat xfrm_user xfrm_algo xt_addrtype overlay ccm af_packet amdgpu snd_hda_codec_cirrus snd_hda_codec_generic ledtrig_audio drm_exec amdxcp gpu_sched xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip6t_rpfilter ipt_rpfilter xt_pkttype xt_LOG nf_log_syslog xt_tcpudp nft_compat nf_tables nfnetlink sch_fq_codel btusb uinput iTCO_wdt ctr btrtl intel_pmc_bxt i915 intel_rapl_msr mei_hdcp mei_pxp joydev at24 watchdog btintel atkbd libps2 serio radeon btbcm vivaldi_fmap btmtk intel_rapl_common snd_hda_codec_hdmi bluetooth uvcvideo nls_iso8859_1 applesmc nls_cp437 x86_pkg_temp_thermal snd_hda_intel intel_powerclamp vfat videobuf2_vmalloc coretemp fat snd_intel_dspcfg crc32_pclmul uvc polyval_clmulni snd_intel_sdw_acpi loop videobuf2_memops snd_hda_codec tun drm_suballoc_helper polyval_generic drm_ttm_helper drm_buddy tap ecdh_generic videobuf2_v4l2 gf128mul macvlan ttm ghash_clmulni_intel ecc tg3 [ +0.000073] videodev bridge snd_hda_core rapl crc16 drm_display_helper cec mousedev snd_hwdep evdev intel_cstate bcm5974 hid_appleir videobuf2_common stp mac_hid libphy snd_pcm drm_kms_helper acpi_als mei_me intel_uncore llc mc snd_timer intel_gtt industrialio_triggered_buffer apple_mfi_fastcharge i2c_i801 mei snd lpc_ich agpgart ptp i2c_smbus thunderbolt apple_gmux i2c_algo_bit kfifo_buf video industrialio soundcore pps_core wmi tiny_power_button sbs sbshc button ac cordic bcma mac80211 cfg80211 ssb rfkill libarc4 kvm_intel kvm drm irqbypass fuse backlight firmware_class efi_pstore configfs efivarfs dmi_sysfs ip_tables x_tables autofs4 dm_crypt cbc encrypted_keys trusted asn1_encoder tee tpm rng_core input_leds hid_apple led_class hid_generic usbhid hid sd_mod t10_pi crc64_rocksoft crc64 crc_t10dif crct10dif_generic ahci libahci libata uhci_hcd ehci_pci ehci_hcd crct10dif_pclmul crct10dif_common sha512_ssse3 sha512_generic sha256_ssse3 sha1_ssse3 aesni_intel usbcore scsi_mod libaes crypto_simd cryptd scsi_common [ +0.000084] usb_common rtc_cmos btrfs blake2b_generic libcrc32c crc32c_generic crc32c_intel xor raid6_pq dm_snapshot dm_bufio dm_mod dax [last unloaded: b43] [ +0.000012] CPU: 0 PID: 56077 Comm: kworker/u16:17 Tainted: G W O 6.6.7 #1-NixOS [ +0.000003] Hardware name: Apple Inc. MacBookPro8,3/Mac-942459F5819B171B, BIOS 87.0.0.0.0 06/13/2019 [ +0.000001] Workqueue: phy7 b43_tx_work [b43] [ +0.000019] RIP: 0010:__ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000076] Code: 74 11 48 8b 78 08 0f b7 d6 89 e9 4c 89 e6 e8 ab f4 00 00 65 ff 0d 9c b7 34 3f 0f 85 55 ff ff ff 0f 1f 44 00 00 e9 4b ff ff ff <0f> 0b 5b 5d 41 5c 41 5d c3 cc cc cc cc 0f 1f 80 00 00 00 00 90 90 [ +0.000002] RSP: 0000:ffffc90004157d50 EFLAGS: 00010097 [ +0.000002] RAX: 0000000000000001 RBX: 0000000000000002 RCX: 0000000000000000 [ +0.000002] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff8882d65d0900 [ +0.000002] RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000001 [ +0.000001] R10: 00000000000000ff R11: ffff88814d0155a0 R12: ffff8882d65d0900 [ +0.000002] R13: 0000000000000000 R14: ffff8881002d2800 R15: 00000000000000d0 [ +0.000002] FS: 0000000000000000(0000) GS:ffff88846f800000(0000) knlGS:0000000000000000 [ +0.000003] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ +0.000002] CR2: 00007f2e8c10c880 CR3: 0000000385b66005 CR4: 00000000000606f0 [ +0.000002] Call Trace: [ +0.000001] [ +0.000001] ? __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000075] ? __warn+0x81/0x130 [ +0.000004] ? __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000075] ? report_bug+0x171/0x1a0 [ +0.000005] ? handle_bug+0x41/0x70 [ +0.000003] ? exc_invalid_op+0x17/0x70 [ +0.000004] ? asm_exc_invalid_op+0x1a/0x20 [ +0.000004] ? __ieee80211_stop_queue+0xcc/0xe0 [mac80211] [ +0.000076] ieee80211_stop_queue+0x36/0x50 [mac80211] [ +0.000077] b43_dma_tx+0x550/0x780 [b43] [ +0.000023] b43_tx_work+0x90/0x130 [b43] [ +0.000018] process_one_work+0x174/0x340 [ +0.000003] worker_thread+0x27b/0x3a0 [ +0.000004] ? __pfx_worker_thread+0x10/0x10 [ +0.000002] kthread+0xe8/0x120 [ +0.000003] ? __pfx_kthread+0x10/0x10 [ +0.000004] ret_from_fork+0x34/0x50 [ +0.000002] ? __pfx_kthread+0x10/0x10 [ +0.000003] ret_from_fork_asm+0x1b/0x30 [ +0.000006] [ +0.000001] ---[ end trace 0000000000000000 ]--- Fixes: e6f5b934fba8 ("b43: Add QOS support") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-2-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/b43.h | 16 ++++++++++++++++ drivers/net/wireless/broadcom/b43/dma.c | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h index 67b4bac048e5..c0d8fc0b22fb 100644 --- a/drivers/net/wireless/broadcom/b43/b43.h +++ b/drivers/net/wireless/broadcom/b43/b43.h @@ -1082,6 +1082,22 @@ static inline bool b43_using_pio_transfers(struct b43_wldev *dev) return dev->__using_pio_transfers; } +static inline void b43_wake_queue(struct b43_wldev *dev, int queue_prio) +{ + if (dev->qos_enabled) + ieee80211_wake_queue(dev->wl->hw, queue_prio); + else + ieee80211_wake_queue(dev->wl->hw, 0); +} + +static inline void b43_stop_queue(struct b43_wldev *dev, int queue_prio) +{ + if (dev->qos_enabled) + ieee80211_stop_queue(dev->wl->hw, queue_prio); + else + ieee80211_stop_queue(dev->wl->hw, 0); +} + /* Message printing */ __printf(2, 3) void b43info(struct b43_wl *wl, const char *fmt, ...); __printf(2, 3) void b43err(struct b43_wl *wl, const char *fmt, ...); diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 760d1a28edc6..6ac7dcebfff9 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1399,7 +1399,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) should_inject_overflow(ring)) { /* This TX ring is full. */ unsigned int skb_mapping = skb_get_queue_mapping(skb); - ieee80211_stop_queue(dev->wl->hw, skb_mapping); + b43_stop_queue(dev, skb_mapping); dev->wl->tx_queue_stopped[skb_mapping] = true; ring->stopped = true; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { @@ -1570,7 +1570,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } else { /* If the driver queue is running wake the corresponding * mac80211 queue. */ - ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); + b43_wake_queue(dev, ring->queue_prio); if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } From 77135a38f6c2f950d2306ac3d37cbb407e6243f2 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:45 +0000 Subject: [PATCH 0055/2255] wifi: b43: Stop/wake correct queue in PIO Tx path when QoS is disabled When QoS is disabled, the queue priority value will not map to the correct ieee80211 queue since there is only one queue. Stop/wake queue 0 when QoS is disabled to prevent trying to stop/wake a non-existent queue and failing to stop/wake the actual queue instantiated. Fixes: 5100d5ac81b9 ("b43: Add PIO support for PCMCIA devices") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-3-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/pio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/pio.c b/drivers/net/wireless/broadcom/b43/pio.c index 0cf70fdb60a6..e41f2f5b4c26 100644 --- a/drivers/net/wireless/broadcom/b43/pio.c +++ b/drivers/net/wireless/broadcom/b43/pio.c @@ -525,7 +525,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + b43_stop_queue(dev, skb_get_queue_mapping(skb)); q->stopped = true; goto out; } @@ -552,7 +552,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + b43_stop_queue(dev, skb_get_queue_mapping(skb)); q->stopped = true; } @@ -587,7 +587,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, list_add(&pack->list, &q->packets_list); if (q->stopped) { - ieee80211_wake_queue(dev->wl->hw, q->queue_prio); + b43_wake_queue(dev, q->queue_prio); q->stopped = false; } } From 581c8967d66c4961076dbbee356834e9c6777184 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:51 +0000 Subject: [PATCH 0056/2255] wifi: b43: Stop correct queue in DMA worker when QoS is disabled When QoS is disabled, the queue priority value will not map to the correct ieee80211 queue since there is only one queue. Stop queue 0 when QoS is disabled to prevent trying to stop a non-existent queue and failing to stop the actual queue instantiated. Fixes: bad691946966 ("b43: avoid packet losses in the dma worker code.") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-4-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 92ca0b2ca286..97d8bdeaa06c 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -3603,7 +3603,7 @@ static void b43_tx_work(struct work_struct *work) err = b43_dma_tx(dev, skb); if (err == -ENOSPC) { wl->tx_queue_stopped[queue_num] = true; - ieee80211_stop_queue(wl->hw, queue_num); + b43_stop_queue(dev, queue_num); skb_queue_head(&wl->tx_queue[queue_num], skb); break; } @@ -3627,6 +3627,7 @@ static void b43_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); + u16 skb_queue_mapping; if (unlikely(skb->len < 2 + 2 + 6)) { /* Too short, this can't be a valid frame. */ @@ -3635,12 +3636,12 @@ static void b43_op_tx(struct ieee80211_hw *hw, } B43_WARN_ON(skb_shinfo(skb)->nr_frags); - skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb); - if (!wl->tx_queue_stopped[skb->queue_mapping]) { + skb_queue_mapping = skb_get_queue_mapping(skb); + skb_queue_tail(&wl->tx_queue[skb_queue_mapping], skb); + if (!wl->tx_queue_stopped[skb_queue_mapping]) ieee80211_queue_work(wl->hw, &wl->tx_work); - } else { - ieee80211_stop_queue(wl->hw, skb->queue_mapping); - } + else + b43_stop_queue(wl->current_dev, skb_queue_mapping); } static void b43_qos_params_upload(struct b43_wldev *dev, From 09795bded2e725443fe4a4803cae2079cdaf7b26 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 31 Dec 2023 05:03:58 +0000 Subject: [PATCH 0057/2255] wifi: b43: Disable QoS for bcm4331 bcm4331 seems to not function correctly with QoS support. This may be due to issues with currently available firmware or potentially a device specific issue. When queues that are not of the default "best effort" priority are selected, traffic appears to not transmit out of the hardware while no errors are returned. This behavior is present among all the other priority queues: video, voice, and background. While this can be worked around by setting a kernel parameter, the default behavior is problematic for most users and may be difficult to debug. This patch offers a working out-of-box experience for bcm4331 users. Log of the issue (using ssh low-priority traffic as an example): ssh -T -vvvv git@github.com OpenSSH_9.6p1, OpenSSL 3.0.12 24 Oct 2023 debug1: Reading configuration data /etc/ssh/ssh_config debug2: checking match for 'host * exec "/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash -c '/nix/store/c015armnkhr6v18za0rypm7sh1i8js8w-gnupg-2.4.1/bin/gpg-connect-agent --quiet updatestartuptty /bye >/dev/null 2>&1'"' host github.com originally github.com debug3: /etc/ssh/ssh_config line 5: matched 'host "github.com"' debug1: Executing command: '/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash -c '/nix/store/c015armnkhr6v18za0rypm7sh1i8js8w-gnupg-2.4.1/bin/gpg-connect-agent --quiet updatestartuptty /bye >/dev/null 2>&1'' debug3: command returned status 0 debug3: /etc/ssh/ssh_config line 5: matched 'exec "/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash -c '/nix/store/c015armnkhr6v18za0r"' debug2: match found debug1: /etc/ssh/ssh_config line 9: Applying options for * debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> '/home/binary-eater/.ssh/known_hosts' debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> '/home/binary-eater/.ssh/known_hosts2' debug2: resolving "github.com" port 22 debug3: resolve_host: lookup github.com:22 debug3: channel_clear_timeouts: clearing debug3: ssh_connect_direct: entering debug1: Connecting to github.com [192.30.255.113] port 22. debug3: set_sock_tos: set socket 3 IP_TOS 0x48 Fixes: e6f5b934fba8 ("b43: Add QOS support") Signed-off-by: Rahul Rameshbabu Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo Link: https://msgid.link/20231231050300.122806-5-sergeantsagara@protonmail.com --- drivers/net/wireless/broadcom/b43/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 97d8bdeaa06c..effb6c23f825 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -2587,7 +2587,8 @@ static void b43_request_firmware(struct work_struct *work) start_ieee80211: wl->hw->queues = B43_QOS_QUEUE_NUM; - if (!modparam_qos || dev->fw.opensource) + if (!modparam_qos || dev->fw.opensource || + dev->dev->chip_id == BCMA_CHIP_ID_BCM4331) wl->hw->queues = 1; err = ieee80211_register_hw(wl->hw); From aaf244141ed7195a9a56e03c2367f4a9d0b727a8 Mon Sep 17 00:00:00 2001 From: Zhenghao Gu Date: Wed, 20 Dec 2023 20:33:08 +0200 Subject: [PATCH 0058/2255] wifi: ath11k: fix IOMMU errors on buffer rings virt_to_phys() doesn't work on systems with IOMMU enabled, which have non-identity physical-to-IOVA mappings. It leads to IO_PAGE_FAULTs like this: [IO_PAGE_FAULT domain=0x0023 address=0x1cce00000 flags=0x0020] And no association to the AP can be established. This patch changes that to dma_map_single(), which works correctly. Even virt_to_phys() documentation says device drivers should not use it: This function does not give bus mappings for DMA transfers. In almost all conceivable cases a device driver should not be using this function Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Zhenghao Gu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231212031914.47339-1-imguzh@gmail.com --- drivers/net/wireless/ath/ath11k/dp.c | 20 +++++++++++++++++--- drivers/net/wireless/ath/ath11k/hal.c | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 8975dc57ad77..1a62407e5a9f 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -104,11 +104,14 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring) if (!ring->vaddr_unaligned) return; - if (ring->cached) + if (ring->cached) { + dma_unmap_single(ab->dev, ring->paddr_unaligned, ring->size, + DMA_FROM_DEVICE); kfree(ring->vaddr_unaligned); - else + } else { dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, ring->paddr_unaligned); + } ring->vaddr_unaligned = NULL; } @@ -249,7 +252,18 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, if (cached) { ring->vaddr_unaligned = kzalloc(ring->size, GFP_KERNEL); - ring->paddr_unaligned = virt_to_phys(ring->vaddr_unaligned); + if (!ring->vaddr_unaligned) + return -ENOMEM; + + ring->paddr_unaligned = dma_map_single(ab->dev, + ring->vaddr_unaligned, + ring->size, + DMA_FROM_DEVICE); + if (dma_mapping_error(ab->dev, ring->paddr_unaligned)) { + kfree(ring->vaddr_unaligned); + ring->vaddr_unaligned = NULL; + return -ENOMEM; + } } } diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index c060c4b5c0cc..f3d04568c221 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -626,15 +626,30 @@ u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng) return NULL; } +static u32 *ath11k_hal_srng_dst_peek_with_dma(struct ath11k_base *ab, + struct hal_srng *srng, dma_addr_t *paddr) +{ + lockdep_assert_held(&srng->lock); + + if (srng->u.dst_ring.tp != srng->u.dst_ring.cached_hp) { + *paddr = srng->ring_base_paddr + + sizeof(*srng->ring_base_vaddr) * srng->u.dst_ring.tp; + return srng->ring_base_vaddr + srng->u.dst_ring.tp; + } + + return NULL; +} + static void ath11k_hal_srng_prefetch_desc(struct ath11k_base *ab, struct hal_srng *srng) { + dma_addr_t desc_paddr; u32 *desc; /* prefetch only if desc is available */ - desc = ath11k_hal_srng_dst_peek(ab, srng); + desc = ath11k_hal_srng_dst_peek_with_dma(ab, srng, &desc_paddr); if (likely(desc)) { - dma_sync_single_for_cpu(ab->dev, virt_to_phys(desc), + dma_sync_single_for_cpu(ab->dev, desc_paddr, (srng->entry_size * sizeof(u32)), DMA_FROM_DEVICE); prefetch(desc); From fba97a777dcb90896ab1dc32e796d85bb7bbcd69 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 19 Dec 2023 12:10:18 +0300 Subject: [PATCH 0059/2255] wifi: ath12k: refactor ath12k_wmi_tlv_parse_alloc() Since 'ath12k_wmi_tlv_parse_alloc()' always operates on 'skb->data, skb->len' tuple, it may be simplified to pass the only 'skb' argument instead (which implies refactoring of 'ath12k_pull_bcn_tx_status_ev()', 'ath12k_pull_chan_info_ev()' and 'ath12k_pull_pdev_temp_ev()' in the same way). This is an ath12k counterpart of the recently submitted ath11k patch and compile tested only as well. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://msgid.link/20231219091022.70861-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath12k/wmi.c | 69 +++++++++++++-------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 11cc3005c0f9..553d2566b3f7 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -359,8 +359,8 @@ static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb, } static const void ** -ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr, - size_t len, gfp_t gfp) +ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, + struct sk_buff *skb, gfp_t gfp) { const void **tb; int ret; @@ -369,7 +369,7 @@ ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr, if (!tb) return ERR_PTR(-ENOMEM); - ret = ath12k_wmi_tlv_parse(ab, tb, ptr, len); + ret = ath12k_wmi_tlv_parse(ab, tb, skb->data, skb->len); if (ret) { kfree(tb); return ERR_PTR(ret); @@ -4374,7 +4374,7 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf const struct wmi_vdev_start_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4452,7 +4452,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n"); - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4738,7 +4738,7 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff * const struct wmi_peer_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4770,7 +4770,7 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, const struct wmi_vdev_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4790,15 +4790,15 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, return 0; } -static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, void *evt_buf, - u32 len, u32 *vdev_id, - u32 *tx_status) +static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, + struct sk_buff *skb, + u32 *vdev_id, u32 *tx_status) { const void **tb; const struct wmi_bcn_tx_status_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4826,7 +4826,7 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_ const struct wmi_vdev_stopped_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4970,7 +4970,7 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, const struct wmi_mgmt_tx_compl_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5141,7 +5141,7 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_scan_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5174,7 +5174,7 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf const struct wmi_peer_sta_kickout_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5201,7 +5201,7 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_roam_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5245,14 +5245,14 @@ 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); From 535733e90e5d8912ebeccebb05b354a2d06ff459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Fri, 5 Jan 2024 08:57:32 +0100 Subject: [PATCH 0060/2255] wifi: wilc1000: fix declarations ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder parameters declaration in wilc_parse_join_bss_param to enforce reverse christmas tree Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240105075733.36331-2-alexis.lothore@bootlin.com --- drivers/net/wireless/microchip/wilc1000/hif.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index 839f142663e8..6f1218a51061 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -377,13 +377,13 @@ struct wilc_join_bss_param * wilc_parse_join_bss_param(struct cfg80211_bss *bss, struct cfg80211_crypto_settings *crypto) { - struct wilc_join_bss_param *param; - struct ieee80211_p2p_noa_attr noa_attr; - u8 rates_len = 0; + const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; + struct ieee80211_p2p_noa_attr noa_attr; + struct wilc_join_bss_param *param; + u8 rates_len = 0; int ret; - const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) From 205c50306acf58a335eb19fa84e40140f4fe814f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Fri, 5 Jan 2024 08:57:33 +0100 Subject: [PATCH 0061/2255] wifi: wilc1000: fix RCU usage in connect path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With lockdep enabled, calls to the connect function from cfg802.11 layer lead to the following warning: ============================= WARNING: suspicious RCU usage 6.7.0-rc1-wt+ #333 Not tainted ----------------------------- drivers/net/wireless/microchip/wilc1000/hif.c:386 suspicious rcu_dereference_check() usage! [...] stack backtrace: CPU: 0 PID: 100 Comm: wpa_supplicant Not tainted 6.7.0-rc1-wt+ #333 Hardware name: Atmel SAMA5 unwind_backtrace from show_stack+0x18/0x1c show_stack from dump_stack_lvl+0x34/0x48 dump_stack_lvl from wilc_parse_join_bss_param+0x7dc/0x7f4 wilc_parse_join_bss_param from connect+0x2c4/0x648 connect from cfg80211_connect+0x30c/0xb74 cfg80211_connect from nl80211_connect+0x860/0xa94 nl80211_connect from genl_rcv_msg+0x3fc/0x59c genl_rcv_msg from netlink_rcv_skb+0xd0/0x1f8 netlink_rcv_skb from genl_rcv+0x2c/0x3c genl_rcv from netlink_unicast+0x3b0/0x550 netlink_unicast from netlink_sendmsg+0x368/0x688 netlink_sendmsg from ____sys_sendmsg+0x190/0x430 ____sys_sendmsg from ___sys_sendmsg+0x110/0x158 ___sys_sendmsg from sys_sendmsg+0xe8/0x150 sys_sendmsg from ret_fast_syscall+0x0/0x1c This warning is emitted because in the connect path, when trying to parse target BSS parameters, we dereference a RCU pointer whithout being in RCU critical section. Fix RCU dereference usage by moving it to a RCU read critical section. To avoid wrapping the whole wilc_parse_join_bss_param under the critical section, just use the critical section to copy ies data Fixes: c460495ee072 ("staging: wilc1000: fix incorrent type in initializer") Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240105075733.36331-3-alexis.lothore@bootlin.com --- drivers/net/wireless/microchip/wilc1000/hif.c | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index 6f1218a51061..d2b8c2630819 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -377,38 +377,49 @@ struct wilc_join_bss_param * wilc_parse_join_bss_param(struct cfg80211_bss *bss, struct cfg80211_crypto_settings *crypto) { - const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); - const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; + const u8 *ies_data, *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; struct ieee80211_p2p_noa_attr noa_attr; + const struct cfg80211_bss_ies *ies; struct wilc_join_bss_param *param; - u8 rates_len = 0; + u8 rates_len = 0, ies_len; int ret; param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) return NULL; + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + ies_data = kmemdup(ies->data, ies->len, GFP_ATOMIC); + if (!ies_data) { + rcu_read_unlock(); + kfree(param); + return NULL; + } + ies_len = ies->len; + rcu_read_unlock(); + param->beacon_period = cpu_to_le16(bss->beacon_interval); param->cap_info = cpu_to_le16(bss->capability); param->bss_type = WILC_FW_BSS_TYPE_INFRA; param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); ether_addr_copy(param->bssid, bss->bssid); - ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies_data, ies_len); if (ssid_elm) { if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); } - tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies_data, ies_len); if (tim_elm && tim_elm[1] >= 2) param->dtim_period = tim_elm[3]; memset(param->p_suites, 0xFF, 3); memset(param->akm_suites, 0xFF, 3); - rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); + rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies_data, ies_len); if (rates_ie) { rates_len = rates_ie[1]; if (rates_len > WILC_MAX_RATES_SUPPORTED) @@ -419,7 +430,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, if (rates_len < WILC_MAX_RATES_SUPPORTED) { supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, - ies->data, ies->len); + ies_data, ies_len); if (supp_rates_ie) { u8 ext_rates = supp_rates_ie[1]; @@ -434,11 +445,11 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, } } - ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); + ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies_data, ies_len); if (ht_ie) param->ht_capable = true; - ret = cfg80211_get_p2p_attr(ies->data, ies->len, + ret = cfg80211_get_p2p_attr(ies_data, ies_len, IEEE80211_P2P_ATTR_ABSENCE_NOTICE, (u8 *)&noa_attr, sizeof(noa_attr)); if (ret > 0) { @@ -462,7 +473,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, } wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, - ies->data, ies->len); + ies_data, ies_len); if (wmm_ie) { struct ieee80211_wmm_param_ie *ie; @@ -477,13 +488,13 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, - ies->data, ies->len); + ies_data, ies_len); if (wpa_ie) { param->mode_802_11i = 1; param->rsn_found = true; } - rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); + rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies_data, ies_len); if (rsn_ie) { int rsn_ie_len = sizeof(struct element) + rsn_ie[1]; int offset = 8; @@ -517,6 +528,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; } + kfree(ies_data); return (void *)param; } From 6f066439f9dc9584543aac3d60cfecba10c4a579 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:11:25 +0800 Subject: [PATCH 0062/2255] wifi: rtw89: add firmware H2C command of BA CAM V1 BA CAM is used to generate BA frame for received AMPDU packets. To support WiFi 7, change format from V0 to have more fields and enlarge entry number for new need. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091134.67007-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 74 +++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 20 +++++++ 2 files changed, 94 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 09684cea9731..4cda96f15ecc 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1609,6 +1609,80 @@ void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev) } } +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_h2c_ba_cam_v1 *h2c; + u8 macid = rtwsta->mac_id; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u8 entry_idx; + u8 bmap_size; + int ret; + + ret = valid ? + rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) : + rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx); + if (ret) { + /* it still works even if we don't have static BA CAM, because + * hardware can create dynamic BA CAM automatically. + */ + rtw89_debug(rtwdev, RTW89_DBG_TXRX, + "failed to %s entry tid=%d for h2c ba cam\n", + valid ? "alloc" : "free", params->tid); + return 0; + } + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam_v1 *)skb->data; + + if (params->buf_size > 512) + bmap_size = 10; + else if (params->buf_size > 256) + bmap_size = 8; + else if (params->buf_size > 64) + bmap_size = 4; + else + bmap_size = 0; + + h2c->w0 = le32_encode_bits(valid, RTW89_H2C_BA_CAM_V1_W0_VALID) | + le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W0_INIT_REQ) | + le32_encode_bits(macid, RTW89_H2C_BA_CAM_V1_W0_MACID_MASK) | + le32_encode_bits(params->tid, RTW89_H2C_BA_CAM_V1_W0_TID_MASK) | + le32_encode_bits(bmap_size, RTW89_H2C_BA_CAM_V1_W0_BMAP_SIZE_MASK) | + le32_encode_bits(params->ssn, RTW89_H2C_BA_CAM_V1_W0_SSN_MASK); + + entry_idx += chip->bacam_dynamic_num; /* std entry right after dynamic ones */ + h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK) | + le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN) | + le32_encode_bits(!!rtwvif->mac_idx, RTW89_H2C_BA_CAM_V1_W1_BAND_SEL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_BA_CAM, + H2C_FUNC_MAC_BA_CAM_V1, 0, 1, + 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_LOG_CFG_LEN 12 int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 01016588b1fc..b7f564d30378 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1796,6 +1796,23 @@ static inline void SET_BA_CAM_ENTRY_IDX_V1(void *h2c, u32 val) le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 28)); } +struct rtw89_h2c_ba_cam_v1 { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_BA_CAM_V1_W0_VALID BIT(0) +#define RTW89_H2C_BA_CAM_V1_W0_INIT_REQ BIT(1) +#define RTW89_H2C_BA_CAM_V1_W0_TID_MASK GENMASK(7, 4) +#define RTW89_H2C_BA_CAM_V1_W0_MACID_MASK GENMASK(15, 8) +#define RTW89_H2C_BA_CAM_V1_W0_BMAP_SIZE_MASK GENMASK(19, 16) +#define RTW89_H2C_BA_CAM_V1_W0_SSN_MASK GENMASK(31, 20) +#define RTW89_H2C_BA_CAM_V1_W1_UID_VALUE_MASK GENMASK(7, 0) +#define RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN BIT(8) +#define RTW89_H2C_BA_CAM_V1_W1_BAND_SEL BIT(9) +#define RTW89_H2C_BA_CAM_V1_W1_MLD_EN BIT(10) +#define RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK GENMASK(31, 24) + static inline void SET_LPS_PARM_MACID(void *h2c, u32 val) { le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); @@ -3690,6 +3707,7 @@ enum rtw89_fw_ofld_h2c_func { /* CLASS 12 - BA CAM */ #define H2C_CL_BA_CAM 0xc #define H2C_FUNC_MAC_BA_CAM 0x0 +#define H2C_FUNC_MAC_BA_CAM_V1 0x1 /* CLASS 14 - MCC */ #define H2C_CL_MCC 0xe @@ -3898,6 +3916,8 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw); int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params); +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params); void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, From 3b96833a5727135a206001f941b43288f6d61099 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:11:26 +0800 Subject: [PATCH 0063/2255] wifi: rtw89: mac: add feature_init to initialize BA CAM V1 Add a call of feature_init() when bringing interface up. For now, the feature is to reset BA CAM V1 that is only used by upcoming 8922A. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091134.67007-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 39 ++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 11 +++++++ drivers/net/wireless/realtek/rtw89/mac.c | 26 ++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4cda96f15ecc..28bf8108a177 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1683,6 +1683,45 @@ fail: return ret; } +int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, + u8 offset, u8 mac_idx) +{ + struct rtw89_h2c_ba_cam_init *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 ba cam init\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam_init *)skb->data; + + h2c->w0 = le32_encode_bits(users, RTW89_H2C_BA_CAM_INIT_USERS_MASK) | + le32_encode_bits(offset, RTW89_H2C_BA_CAM_INIT_OFFSET_MASK) | + le32_encode_bits(mac_idx, RTW89_H2C_BA_CAM_INIT_BAND_SEL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_BA_CAM, + H2C_FUNC_MAC_BA_CAM_INIT, 0, 1, + 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_LOG_CFG_LEN 12 int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b7f564d30378..687623fb7e1d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1813,6 +1813,14 @@ struct rtw89_h2c_ba_cam_v1 { #define RTW89_H2C_BA_CAM_V1_W1_MLD_EN BIT(10) #define RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK GENMASK(31, 24) +struct rtw89_h2c_ba_cam_init { + __le32 w0; +} __packed; + +#define RTW89_H2C_BA_CAM_INIT_USERS_MASK GENMASK(7, 0) +#define RTW89_H2C_BA_CAM_INIT_OFFSET_MASK GENMASK(19, 12) +#define RTW89_H2C_BA_CAM_INIT_BAND_SEL BIT(24) + static inline void SET_LPS_PARM_MACID(void *h2c, u32 val) { le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); @@ -3708,6 +3716,7 @@ enum rtw89_fw_ofld_h2c_func { #define H2C_CL_BA_CAM 0xc #define H2C_FUNC_MAC_BA_CAM 0x0 #define H2C_FUNC_MAC_BA_CAM_V1 0x1 +#define H2C_FUNC_MAC_BA_CAM_INIT 0x2 /* CLASS 14 - MCC */ #define H2C_CL_MCC 0xe @@ -3919,6 +3928,8 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params); void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, + u8 offset, u8 mac_idx); int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index c485ef2cc3d3..0d5f91d4adee 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -3676,6 +3676,28 @@ static int trx_init_ax(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mac_feat_init(struct rtw89_dev *rtwdev) +{ +#define BACAM_1024BMP_OCC_ENTRY 4 +#define BACAM_MAX_RU_SUPPORT_B0_STA 1 +#define BACAM_MAX_RU_SUPPORT_B1_STA 1 + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 users, offset; + + if (chip->bacam_ver != RTW89_BACAM_V1) + return 0; + + offset = 0; + users = BACAM_MAX_RU_SUPPORT_B0_STA; + rtw89_fw_h2c_init_ba_cam_users(rtwdev, users, offset, RTW89_MAC_0); + + offset += users * BACAM_1024BMP_OCC_ENTRY; + users = BACAM_MAX_RU_SUPPORT_B1_STA; + rtw89_fw_h2c_init_ba_cam_users(rtwdev, users, offset, RTW89_MAC_1); + + return 0; +} + static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -3910,6 +3932,10 @@ int rtw89_mac_init(struct rtw89_dev *rtwdev) if (ret) goto fail; + ret = rtw89_mac_feat_init(rtwdev); + if (ret) + goto fail; + if (rtwdev->hci.ops->mac_post_init) { ret = rtwdev->hci.ops->mac_post_init(rtwdev); if (ret) From 5d461dba16fa0887ad434b66298b3f8dd2d13235 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:11:27 +0800 Subject: [PATCH 0064/2255] wifi: rtw89: add chip_ops::h2c_ba_cam() to configure BA CAM Since chips could use different version of BA CAM H2C command, add a chip_ops to abstract the operation. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091134.67007-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 ++ drivers/net/wireless/realtek/rtw89/fw.c | 2 ++ drivers/net/wireless/realtek/rtw89/fw.h | 9 +++++++++ drivers/net/wireless/realtek/rtw89/mac80211.c | 4 ++-- 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 + 9 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 662425ba395b..151b000adcaa 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3197,6 +3197,8 @@ struct rtw89_chip_ops { int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); + int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params); void (*btc_set_rfe)(struct rtw89_dev *rtwdev); void (*btc_init_cfg)(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 28bf8108a177..b1215200f5a1 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1556,6 +1556,7 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_ba_cam); static int rtw89_fw_h2c_init_ba_cam_v0_ext(struct rtw89_dev *rtwdev, u8 entry_idx, u8 uid) @@ -1682,6 +1683,7 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_ba_cam_v1); int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, u8 offset, u8 mac_idx) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 687623fb7e1d..6c51ee9a5fa8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3996,6 +3996,15 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(rtwdev); } +static inline +int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_ba_cam(rtwdev, rtwsta, valid, params); +} + /* must consider compatibility; don't insert new in the mid */ struct rtw89_fw_txpwr_byrate_entry { u8 band; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 93889d2fface..915bd82586fc 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -673,12 +673,12 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_RX_START: mutex_lock(&rtwdev->mutex); - rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, true, params); + rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, true, params); mutex_unlock(&rtwdev->mutex); break; case IEEE80211_AMPDU_RX_STOP: mutex_lock(&rtwdev->mutex); - rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, false, params); + rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, false, params); mutex_unlock(&rtwdev->mutex); break; default: diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index b5cf093146cb..73700c4ccf57 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2334,6 +2334,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8851b_btc_set_rfe, .btc_init_cfg = rtw8851b_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0c76c52ce22c..481c1f59fda0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2078,6 +2078,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852a_btc_set_rfe, .btc_init_cfg = rtw8852a_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index ab60cc11a385..86663659fa71 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2503,6 +2503,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852b_btc_set_rfe, .btc_init_cfg = rtw8852b_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 9a9b7103caeb..6727c9f73053 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2848,6 +2848,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx_v1, .resume_sch_tx = rtw89_mac_resume_sch_tx_v1, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v1, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852c_btc_set_rfe, .btc_init_cfg = rtw8852c_btc_init_cfg, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 070d0c716659..2c8cefbe2e41 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -822,6 +822,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .read_phycap = rtw8922a_read_phycap, .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, }; const struct rtw89_chip_info rtw8922a_chip_info = { From 2d623151bf26c81e6af4847907a01935f0a5285e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:11:28 +0800 Subject: [PATCH 0065/2255] wifi: rtw89: 8922a: update BA CAM number to 24 The total BA CAM number of 8922a is 32 instead of 16, and initial 8 entries are dynamic, so update the entry number to 24. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091134.67007-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 151b000adcaa..63f1f0e2c30f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -2876,7 +2876,7 @@ struct rtw89_ba_cam_entry { #define RTW89_MAX_ADDR_CAM_NUM 128 #define RTW89_MAX_BSSID_CAM_NUM 20 #define RTW89_MAX_SEC_CAM_NUM 128 -#define RTW89_MAX_BA_CAM_NUM 8 +#define RTW89_MAX_BA_CAM_NUM 24 #define RTW89_SEC_CAM_IN_ADDR_CAM 7 struct rtw89_addr_cam_entry { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 2c8cefbe2e41..752f48821028 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -875,7 +875,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .acam_num = 128, .bcam_num = 20, .scam_num = 32, - .bacam_num = 8, + .bacam_num = 24, .bacam_dynamic_num = 8, .bacam_ver = RTW89_BACAM_V1, .ppdu_max_usr = 16, From cdd368ce1ca4a6d70dc08da4175309a93ed88062 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:12:45 +0800 Subject: [PATCH 0066/2255] wifi: rtw89: fw: use struct to fill BA CAM H2C commands The WiFi 6 chips use these commands to create BA CAM entry when RX BA session is established, this BA CAM can record whether packets are received or not, then reply BA for current status. This patch doesn't change logic. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091245.67220-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 52 ++++++++++--------- drivers/net/wireless/realtek/rtw89/fw.h | 68 ++++++------------------- 2 files changed, 44 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index b1215200f5a1..61ae8e584a3b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1485,13 +1485,14 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1); -#define H2C_BA_CAM_LEN 8 int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_h2c_ba_cam *h2c; u8 macid = rtwsta->mac_id; + u32 len = sizeof(*h2c); struct sk_buff *skb; u8 entry_idx; int ret; @@ -1509,32 +1510,34 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, return 0; } - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n"); return -ENOMEM; } - skb_put(skb, H2C_BA_CAM_LEN); - SET_BA_CAM_MACID(skb->data, macid); + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam *)skb->data; + + h2c->w0 = le32_encode_bits(macid, RTW89_H2C_BA_CAM_W0_MACID); if (chip->bacam_ver == RTW89_BACAM_V0_EXT) - SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx); + h2c->w1 |= le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1); else - SET_BA_CAM_ENTRY_IDX(skb->data, entry_idx); + h2c->w0 |= le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W0_ENTRY_IDX); if (!valid) goto end; - SET_BA_CAM_VALID(skb->data, valid); - SET_BA_CAM_TID(skb->data, params->tid); + h2c->w0 |= le32_encode_bits(valid, RTW89_H2C_BA_CAM_W0_VALID) | + le32_encode_bits(params->tid, RTW89_H2C_BA_CAM_W0_TID); if (params->buf_size > 64) - SET_BA_CAM_BMAP_SIZE(skb->data, 4); + h2c->w0 |= le32_encode_bits(4, RTW89_H2C_BA_CAM_W0_BMAP_SIZE); else - SET_BA_CAM_BMAP_SIZE(skb->data, 0); + h2c->w0 |= le32_encode_bits(0, RTW89_H2C_BA_CAM_W0_BMAP_SIZE); /* If init req is set, hw will set the ssn */ - SET_BA_CAM_INIT_REQ(skb->data, 1); - SET_BA_CAM_SSN(skb->data, params->ssn); + h2c->w0 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W0_INIT_REQ) | + le32_encode_bits(params->ssn, RTW89_H2C_BA_CAM_W0_SSN); if (chip->bacam_ver == RTW89_BACAM_V0_EXT) { - SET_BA_CAM_STD_EN(skb->data, 1); - SET_BA_CAM_BAND(skb->data, rtwvif->mac_idx); + h2c->w1 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W1_STD_EN) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BA_CAM_W1_BAND); } end: @@ -1542,7 +1545,7 @@ end: H2C_CAT_MAC, H2C_CL_BA_CAM, H2C_FUNC_MAC_BA_CAM, 0, 1, - H2C_BA_CAM_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -1561,27 +1564,30 @@ EXPORT_SYMBOL(rtw89_fw_h2c_ba_cam); static int rtw89_fw_h2c_init_ba_cam_v0_ext(struct rtw89_dev *rtwdev, u8 entry_idx, u8 uid) { + struct rtw89_h2c_ba_cam *h2c; + u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for dynamic h2c ba cam\n"); return -ENOMEM; } - skb_put(skb, H2C_BA_CAM_LEN); + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam *)skb->data; - SET_BA_CAM_VALID(skb->data, 1); - SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx); - SET_BA_CAM_UID(skb->data, uid); - SET_BA_CAM_BAND(skb->data, 0); - SET_BA_CAM_STD_EN(skb->data, 0); + h2c->w0 = le32_encode_bits(1, RTW89_H2C_BA_CAM_W0_VALID); + h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1) | + le32_encode_bits(uid, RTW89_H2C_BA_CAM_W1_UID) | + le32_encode_bits(0, RTW89_H2C_BA_CAM_W1_BAND) | + le32_encode_bits(0, RTW89_H2C_BA_CAM_W1_STD_EN); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_BA_CAM, H2C_FUNC_MAC_BA_CAM, 0, 1, - H2C_BA_CAM_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 6c51ee9a5fa8..ec90cc9b0b53 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1741,60 +1741,22 @@ static inline void SET_LOG_CFG_COMP_EXT(void *h2c, u32 val) le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 0)); } -static inline void SET_BA_CAM_VALID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(0)); -} +struct rtw89_h2c_ba_cam { + __le32 w0; + __le32 w1; +} __packed; -static inline void SET_BA_CAM_INIT_REQ(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(1)); -} - -static inline void SET_BA_CAM_ENTRY_IDX(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(3, 2)); -} - -static inline void SET_BA_CAM_TID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 4)); -} - -static inline void SET_BA_CAM_MACID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); -} - -static inline void SET_BA_CAM_BMAP_SIZE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(19, 16)); -} - -static inline void SET_BA_CAM_SSN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 20)); -} - -static inline void SET_BA_CAM_UID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(7, 0)); -} - -static inline void SET_BA_CAM_STD_EN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, BIT(8)); -} - -static inline void SET_BA_CAM_BAND(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, BIT(9)); -} - -static inline void SET_BA_CAM_ENTRY_IDX_V1(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 28)); -} +#define RTW89_H2C_BA_CAM_W0_VALID BIT(0) +#define RTW89_H2C_BA_CAM_W0_INIT_REQ BIT(1) +#define RTW89_H2C_BA_CAM_W0_ENTRY_IDX GENMASK(3, 2) +#define RTW89_H2C_BA_CAM_W0_TID GENMASK(7, 4) +#define RTW89_H2C_BA_CAM_W0_MACID GENMASK(15, 8) +#define RTW89_H2C_BA_CAM_W0_BMAP_SIZE GENMASK(19, 16) +#define RTW89_H2C_BA_CAM_W0_SSN GENMASK(31, 20) +#define RTW89_H2C_BA_CAM_W1_UID GENMASK(7, 0) +#define RTW89_H2C_BA_CAM_W1_STD_EN BIT(8) +#define RTW89_H2C_BA_CAM_W1_BAND BIT(9) +#define RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1 GENMASK(31, 28) struct rtw89_h2c_ba_cam_v1 { __le32 w0; From e3552b37dacea361a2ae488cc10c3d2e243ee514 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:13:07 +0800 Subject: [PATCH 0067/2255] wifi: rtw89: refine H2C command that pause transmitting by MAC ID To reuse this function to support extended H2C command that is used by newer chip, change to use a pointer to fill pause ID and mask. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091307.67296-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 61ae8e584a3b..991c42c4e509 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2489,20 +2489,23 @@ fail: int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, bool pause) { - struct rtw89_fw_macid_pause_grp h2c = {{0}}; - u8 len = sizeof(struct rtw89_fw_macid_pause_grp); + struct rtw89_fw_macid_pause_grp *h2c; + __le32 set = cpu_to_le32(BIT(sh)); + u8 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); + rtw89_err(rtwdev, "failed to alloc skb for h2c macid pause\n"); return -ENOMEM; } - h2c.mask_grp[grp] = cpu_to_le32(BIT(sh)); + skb_put(skb, len); + h2c = (struct rtw89_fw_macid_pause_grp *)skb->data; + + h2c->mask_grp[grp] = set; if (pause) - h2c.pause_grp[grp] = cpu_to_le32(BIT(sh)); - skb_put_data(skb, &h2c, len); + h2c->pause_grp[grp] = set; rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, From c313c31ff40d6fe65570eaf237c8ba4428aeace6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:13:15 +0800 Subject: [PATCH 0068/2255] wifi: rtw89: add new H2C command to pause/sleep transmitting by MAC ID New H2C command is introduced to pause/sleep transmitting. That extends more bits to support more MAC ID, and currently we still configure 256 MAC ID at most. This new command is always used by coming WiFi 7 chips, and existing chips can use old or new command because firmware still preserves the old one. Add a firmware feature flag to determine which command is adopted according to firmware version. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091315.67358-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 35 +++++++++++++++++++---- drivers/net/wireless/realtek/rtw89/fw.h | 10 +++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 63f1f0e2c30f..0c6d83c4c047 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3900,6 +3900,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_NO_DEEP_PS, RTW89_FW_FEATURE_NO_LPS_PG, RTW89_FW_FEATURE_BEACON_FILTER, + RTW89_FW_FEATURE_MACID_PAUSE_SLEEP, }; struct rtw89_fw_suit { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 991c42c4e509..9d6748f65ba3 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -458,6 +458,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), __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), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -2489,27 +2490,49 @@ fail: int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, bool pause) { + struct rtw89_fw_macid_pause_sleep_grp *h2c_new; struct rtw89_fw_macid_pause_grp *h2c; __le32 set = cpu_to_le32(BIT(sh)); - u8 len = sizeof(*h2c); + u8 h2c_macid_pause_id; struct sk_buff *skb; + u32 len; int ret; + if (RTW89_CHK_FW_FEATURE(MACID_PAUSE_SLEEP, &rtwdev->fw)) { + h2c_macid_pause_id = H2C_FUNC_MAC_MACID_PAUSE_SLEEP; + len = sizeof(*h2c_new); + } else { + h2c_macid_pause_id = H2C_FUNC_MAC_MACID_PAUSE; + len = sizeof(*h2c); + } + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c macid pause\n"); return -ENOMEM; } skb_put(skb, len); - h2c = (struct rtw89_fw_macid_pause_grp *)skb->data; - h2c->mask_grp[grp] = set; - if (pause) - h2c->pause_grp[grp] = set; + if (h2c_macid_pause_id == H2C_FUNC_MAC_MACID_PAUSE_SLEEP) { + h2c_new = (struct rtw89_fw_macid_pause_sleep_grp *)skb->data; + + h2c_new->n[0].pause_mask_grp[grp] = set; + h2c_new->n[0].sleep_mask_grp[grp] = set; + if (pause) { + h2c_new->n[0].pause_grp[grp] = set; + h2c_new->n[0].sleep_grp[grp] = set; + } + } else { + h2c = (struct rtw89_fw_macid_pause_grp *)skb->data; + + h2c->mask_grp[grp] = set; + if (pause) + h2c->pause_grp[grp] = set; + } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, - H2C_FUNC_MAC_MACID_PAUSE, 1, 0, + h2c_macid_pause_id, 1, 0, len); ret = rtw89_h2c_tx(rtwdev, skb, false); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index ec90cc9b0b53..0365cd7b8da0 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -231,6 +231,15 @@ struct rtw89_fw_macid_pause_grp { __le32 mask_grp[4]; } __packed; +struct rtw89_fw_macid_pause_sleep_grp { + struct { + __le32 pause_grp[4]; + __le32 pause_mask_grp[4]; + __le32 sleep_grp[4]; + __le32 sleep_mask_grp[4]; + } __packed n[4]; +} __packed; + #define RTW89_H2C_MAX_SIZE 2048 #define RTW89_CHANNEL_TIME 45 #define RTW89_CHANNEL_TIME_6G 20 @@ -3659,6 +3668,7 @@ enum rtw89_fw_ofld_h2c_func { H2C_FUNC_CFG_BCNFLTR = 0x1e, H2C_FUNC_OFLD_RSSI = 0x1f, H2C_FUNC_OFLD_TP = 0x20, + H2C_FUNC_MAC_MACID_PAUSE_SLEEP = 0x28, NUM_OF_RTW89_FW_OFLD_H2C_FUNC, }; From 69466b979a72008022ee7c054b6123488eb00472 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:13:25 +0800 Subject: [PATCH 0069/2255] wifi: rtw89: use struct to fill H2C command to download beacon frame Download beacon frame via H2C command for AP mode, and then firmware can issues beacon periodically. Originally TIM offset minus fixed 24 bytes of frame header implicitly in macro, and this patch explicitly uses ieee80211_hdrlen() to get header length, but expected to change nothing at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091325.67424-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 34 ++++--- drivers/net/wireless/realtek/rtw89/fw.h | 123 +++++------------------- 2 files changed, 45 insertions(+), 112 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 9d6748f65ba3..89eda20c20cb 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2277,18 +2277,20 @@ fail: return ret; } -#define H2C_BCN_BASE_LEN 12 int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx); - struct sk_buff *skb; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_h2c_bcn_upd *h2c; struct sk_buff *skb_beacon; - u16 tim_offset; + struct ieee80211_hdr *hdr; + u32 len = sizeof(*h2c); + struct sk_buff *skb; int bcn_total_len; u16 beacon_rate; + u16 tim_offset; void *noa_data; u8 noa_len; int ret; @@ -2314,23 +2316,27 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, skb_put_data(skb_beacon, noa_data, noa_len); } - bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len; + hdr = (struct ieee80211_hdr *)skb_beacon; + tim_offset -= ieee80211_hdrlen(hdr->frame_control); + + bcn_total_len = len + skb_beacon->len; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); dev_kfree_skb_any(skb_beacon); return -ENOMEM; } - skb_put(skb, H2C_BCN_BASE_LEN); + skb_put(skb, len); + h2c = (struct rtw89_h2c_bcn_upd *)skb->data; - SET_BCN_UPD_PORT(skb->data, rtwvif->port); - SET_BCN_UPD_MBSSID(skb->data, 0); - SET_BCN_UPD_BAND(skb->data, rtwvif->mac_idx); - SET_BCN_UPD_GRP_IE_OFST(skb->data, tim_offset); - SET_BCN_UPD_MACID(skb->data, rtwvif->mac_id); - SET_BCN_UPD_SSN_SEL(skb->data, RTW89_MGMT_HW_SSN_SEL); - SET_BCN_UPD_SSN_MODE(skb->data, RTW89_MGMT_HW_SEQ_MODE); - SET_BCN_UPD_RATE(skb->data, beacon_rate); + h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_W0_PORT) | + le32_encode_bits(0, RTW89_H2C_BCN_UPD_W0_MBSSID) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) | + le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST); + h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) | + le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_W1_SSN_SEL) | + le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_W1_SSN_MODE) | + le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_W1_RATE); skb_put_data(skb, skb_beacon->data, skb_beacon->len); dev_kfree_skb_any(skb_beacon); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 0365cd7b8da0..9424b4add222 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1509,105 +1509,32 @@ static inline void SET_DCTL_SEC_ENT6_V1(void *table, u32 val) GENMASK(31, 24)); } -static inline void SET_BCN_UPD_PORT(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); -} +struct rtw89_h2c_bcn_upd { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; -static inline void SET_BCN_UPD_MBSSID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); -} - -static inline void SET_BCN_UPD_BAND(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); -} - -static inline void SET_BCN_UPD_GRP_IE_OFST(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, (val - 24) | BIT(7), GENMASK(31, 24)); -} - -static inline void SET_BCN_UPD_MACID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(7, 0)); -} - -static inline void SET_BCN_UPD_SSN_SEL(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(9, 8)); -} - -static inline void SET_BCN_UPD_SSN_MODE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(11, 10)); -} - -static inline void SET_BCN_UPD_RATE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(20, 12)); -} - -static inline void SET_BCN_UPD_TXPWR(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(23, 21)); -} - -static inline void SET_BCN_UPD_TXINFO_CTRL_EN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(0)); -} - -static inline void SET_BCN_UPD_NTX_PATH_EN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(4, 1)); -} - -static inline void SET_BCN_UPD_PATH_MAP_A(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(6, 5)); -} - -static inline void SET_BCN_UPD_PATH_MAP_B(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(8, 7)); -} - -static inline void SET_BCN_UPD_PATH_MAP_C(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(10, 9)); -} - -static inline void SET_BCN_UPD_PATH_MAP_D(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(12, 11)); -} - -static inline void SET_BCN_UPD_PATH_ANTSEL_A(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(13)); -} - -static inline void SET_BCN_UPD_PATH_ANTSEL_B(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(14)); -} - -static inline void SET_BCN_UPD_PATH_ANTSEL_C(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(15)); -} - -static inline void SET_BCN_UPD_PATH_ANTSEL_D(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(16)); -} - -static inline void SET_BCN_UPD_CSA_OFST(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 17)); -} +#define RTW89_H2C_BCN_UPD_W0_PORT GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_W0_MBSSID GENMASK(15, 8) +#define RTW89_H2C_BCN_UPD_W0_BAND GENMASK(23, 16) +#define RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST GENMASK(31, 24) +#define RTW89_H2C_BCN_UPD_W1_MACID GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_W1_SSN_SEL GENMASK(9, 8) +#define RTW89_H2C_BCN_UPD_W1_SSN_MODE GENMASK(11, 10) +#define RTW89_H2C_BCN_UPD_W1_RATE GENMASK(20, 12) +#define RTW89_H2C_BCN_UPD_W1_TXPWR GENMASK(23, 21) +#define RTW89_H2C_BCN_UPD_W2_TXINFO_CTRL_EN BIT(0) +#define RTW89_H2C_BCN_UPD_W2_NTX_PATH_EN GENMASK(4, 1) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_A GENMASK(6, 5) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_B GENMASK(8, 7) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_C GENMASK(10, 9) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_D GENMASK(12, 11) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_A BIT(13) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_B BIT(14) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_C BIT(15) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_D BIT(16) +#define RTW89_H2C_BCN_UPD_W2_CSA_OFST GENMASK(31, 17) static inline void SET_FWROLE_MAINTAIN_MACID(void *h2c, u32 val) { From a880b9283009b312a7a5e8f03e068712f8750651 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:13:33 +0800 Subject: [PATCH 0070/2255] wifi: rtw89: add H2C command to download beacon frame for WiFi 7 chips The firmware of coming WiFi 7 chips can support more AP functions, like virtual AP, so extend format of download beacon frame to configure them. Currently rtw89 only enables AP mode as old chips, so leave new fields zeros. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091333.67484-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 82 +++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 51 +++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 89eda20c20cb..42214af0e15a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2356,6 +2356,88 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, return 0; } +int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_h2c_bcn_upd_be *h2c; + struct sk_buff *skb_beacon; + struct ieee80211_hdr *hdr; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int bcn_total_len; + u16 beacon_rate; + u16 tim_offset; + void *noa_data; + u8 noa_len; + int ret; + + if (vif->p2p) + beacon_rate = RTW89_HW_RATE_OFDM6; + else if (chan->band_type == RTW89_BAND_2G) + beacon_rate = RTW89_HW_RATE_CCK1; + else + beacon_rate = RTW89_HW_RATE_OFDM6; + + skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, + NULL, 0); + if (!skb_beacon) { + rtw89_err(rtwdev, "failed to get beacon skb\n"); + return -ENOMEM; + } + + noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data); + if (noa_len && + (noa_len <= skb_tailroom(skb_beacon) || + pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) { + skb_put_data(skb_beacon, noa_data, noa_len); + } + + hdr = (struct ieee80211_hdr *)skb_beacon; + tim_offset -= ieee80211_hdrlen(hdr->frame_control); + + bcn_total_len = len + skb_beacon->len; + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); + dev_kfree_skb_any(skb_beacon); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_bcn_upd_be *)skb->data; + + h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) | + le32_encode_bits(0, RTW89_H2C_BCN_UPD_BE_W0_MBSSID) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) | + le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST); + h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) | + le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL) | + le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE) | + le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_BE_W1_RATE); + + skb_put_data(skb, skb_beacon->data, skb_beacon->len); + dev_kfree_skb_any(skb_beacon); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_BCN_UPD_BE, 0, 1, + bcn_total_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_ROLE_MAINTAIN_LEN 4 int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 9424b4add222..dc1c805f1500 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1536,6 +1536,54 @@ struct rtw89_h2c_bcn_upd { #define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_D BIT(16) #define RTW89_H2C_BCN_UPD_W2_CSA_OFST GENMASK(31, 17) +struct rtw89_h2c_bcn_upd_be { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; +} __packed; + +#define RTW89_H2C_BCN_UPD_BE_W0_PORT GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_BE_W0_MBSSID GENMASK(15, 8) +#define RTW89_H2C_BCN_UPD_BE_W0_BAND GENMASK(23, 16) +#define RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST GENMASK(31, 24) +#define RTW89_H2C_BCN_UPD_BE_W1_MACID GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL GENMASK(9, 8) +#define RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE GENMASK(11, 10) +#define RTW89_H2C_BCN_UPD_BE_W1_RATE GENMASK(20, 12) +#define RTW89_H2C_BCN_UPD_BE_W1_TXPWR GENMASK(23, 21) +#define RTW89_H2C_BCN_UPD_BE_W1_MACID_EXT GENMASK(31, 24) +#define RTW89_H2C_BCN_UPD_BE_W2_TXINFO_CTRL_EN BIT(0) +#define RTW89_H2C_BCN_UPD_BE_W2_NTX_PATH_EN GENMASK(4, 1) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_A GENMASK(6, 5) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_B GENMASK(8, 7) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_C GENMASK(10, 9) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_D GENMASK(12, 11) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_A BIT(13) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_B BIT(14) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_C BIT(15) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_D BIT(16) +#define RTW89_H2C_BCN_UPD_BE_W2_CSA_OFST GENMASK(31, 17) +#define RTW89_H2C_BCN_UPD_BE_W3_MLIE_CSA_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W3_CRITICAL_UPD_FLAG_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W4_VAP1_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W4_VAP2_DTIM_CNT_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W5_VAP3_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W5_VAP4_DTIM_CNT_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W6_VAP5_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W6_VAP6_DTIM_CNT_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W7_VAP7_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W7_ECSA_OFST GENMASK(30, 16) +#define RTW89_H2C_BCN_UPD_BE_W7_PROTECTION_KEY_ID BIT(31) + static inline void SET_FWROLE_MAINTAIN_MACID(void *h2c, u32 val) { le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); @@ -3570,6 +3618,7 @@ struct rtw89_fw_h2c_rf_reg_info { #define H2C_FUNC_MAC_BCN_UPD 0x5 #define H2C_FUNC_MAC_DCTLINFO_UD_V1 0x9 #define H2C_FUNC_MAC_CCTLINFO_UD_V1 0xa +#define H2C_FUNC_MAC_BCN_UPD_BE 0xd /* CLASS 6 - Address CAM */ #define H2C_CL_MAC_ADDR_CAM_UPDATE 0x6 @@ -3766,6 +3815,8 @@ int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif); int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, struct rtw89_sta *rtwsta, const u8 *scan_mac_addr); int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, From bcd1ae78448ea15d5d93ac5e07070e46e5d082da Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 8 Jan 2024 17:13:59 +0800 Subject: [PATCH 0071/2255] wifi: rtw89: add chip_ops::update_beacon to abstract update beacon operation Since coming WiFi 7 and existing chips use different update_beacon() format, add to abstract selection of H2C command. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240108091359.67636-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 2 +- drivers/net/wireless/realtek/rtw89/core.c | 2 +- drivers/net/wireless/realtek/rtw89/core.h | 2 ++ drivers/net/wireless/realtek/rtw89/fw.c | 2 ++ drivers/net/wireless/realtek/rtw89/fw.h | 8 ++++++++ drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +- 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 + 11 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index cbf6821af6b8..21449cb9b069 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1494,7 +1494,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) if (!rtwvif_go->chanctx_assigned) return; - rtw89_fw_h2c_update_beacon(rtwdev, rtwvif_go); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_go); } static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index fd527a249996..ac7ae19429f9 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3879,7 +3879,7 @@ void rtw89_core_update_beacon_work(struct work_struct *work) rtwdev = rtwvif->rtwdev; mutex_lock(&rtwdev->mutex); - rtw89_fw_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); mutex_unlock(&rtwdev->mutex); } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 0c6d83c4c047..73694aca1108 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3197,6 +3197,8 @@ struct rtw89_chip_ops { int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); + int (*h2c_update_beacon)(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif); int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 42214af0e15a..55a9f4eb47be 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2355,6 +2355,7 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, return 0; } +EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) @@ -2437,6 +2438,7 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be); #define H2C_ROLE_MAINTAIN_LEN 4 int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index dc1c805f1500..7fa7cd11c495 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3946,6 +3946,14 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(rtwdev); } +static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_update_beacon(rtwdev, rtwvif); +} + static inline int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 915bd82586fc..c023c182be6a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -452,7 +452,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON) - rtw89_fw_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); if (changed & BSS_CHANGED_ERP_SLOT) rtw89_conf_tx(rtwdev, rtwvif); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 73700c4ccf57..558ab6c2c24a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2334,6 +2334,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8851b_btc_set_rfe, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 481c1f59fda0..3349397e3af1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2078,6 +2078,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852a_btc_set_rfe, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 86663659fa71..43e803cb06f2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2503,6 +2503,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852b_btc_set_rfe, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 6727c9f73053..e2393e621755 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2848,6 +2848,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx_v1, .resume_sch_tx = rtw89_mac_resume_sch_tx_v1, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v1, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852c_btc_set_rfe, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 752f48821028..7f6dde384223 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -822,6 +822,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .read_phycap = rtw8922a_read_phycap, .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, }; From 0ac008b6357f3f5f0b3751ee952c827e87c09458 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 9 Jan 2024 13:47:32 +0300 Subject: [PATCH 0072/2255] wifi: rtlwifi: cleanup few rtlxxx_tx_fill_desc() routines Remove unreachable branches in 'rtl92ce_tx_fill_desc()', 'rtl92cu_tx_fill_desc()' and 'rtl8723e_tx_fill_desc()'. Compile tested only. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://msgid.link/20240109104735.140550-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c | 4 ---- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c | 3 --- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c | 6 +----- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c index 50e139186a93..ed151754fc6e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c @@ -350,7 +350,6 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - bool defaultadapter = true; __le32 *pdesc = (__le32 *)pdesc8; u16 seq_number; __le16 fc = hdr->frame_control; @@ -503,9 +502,6 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { set_tx_desc_hwseq_en(pdesc, 1); set_tx_desc_pkt_id(pdesc, 8); - - if (!defaultadapter) - set_tx_desc_qos(pdesc, 1); } set_tx_desc_more_frag(pdesc, (lastseg ? 0 : 1)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index 2f44c8aa6066..e5c81c1c63c0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -475,7 +475,6 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - bool defaultadapter = true; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; @@ -587,8 +586,6 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, ppsc->fwctrl_lps) { set_tx_desc_hwseq_en(txdesc, 1); set_tx_desc_pkt_id(txdesc, 8); - if (!defaultadapter) - set_tx_desc_qos(txdesc, 1); } if (ieee80211_has_morefrags(fc)) set_tx_desc_more_frag(txdesc, 1); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c index d9823ddab7be..65bfc14702f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c @@ -349,7 +349,6 @@ void rtl8723e_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - bool b_defaultadapter = true; /* bool b_trigger_ac = false; */ u8 *pdesc8 = (u8 *)pdesc_tx; __le32 *pdesc = (__le32 *)pdesc8; @@ -503,10 +502,7 @@ void rtl8723e_tx_fill_desc(struct ieee80211_hw *hw, set_tx_desc_hwseq_en_8723(pdesc, 1); /* set_tx_desc_hwseq_en(pdesc, 1); */ /* set_tx_desc_pkt_id(pdesc, 8); */ - - if (!b_defaultadapter) - set_tx_desc_hwseq_sel_8723(pdesc, 1); - /* set_tx_desc_qos(pdesc, 1); */ + /* set_tx_desc_qos(pdesc, 1); */ } set_tx_desc_more_frag(pdesc, (lastseg ? 0 : 1)); From 178cc55d5129556e290cc05e152138037930419f Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Thu, 11 Jan 2024 16:56:39 +0200 Subject: [PATCH 0073/2255] wifi: rtlwifi: rtl_usb: Use sync register writes Currently rtl_usb performs register writes using the async usb_submit_urb() function. This appears to work fine for the RTL8192CU, but the RTL8192DU (soon to be supported by rtlwifi) has a problem: it transmits everything at the 1M rate in the 2.4 GHz band. (The 5 GHz band is still untested.) With this patch, rtl_usb performs the register writes using the synchronous usb_control_msg() function, and the RTL8192DU works normally. The RTL8192CU still works. The vendor drivers use the async writes in only one function, rtl8192du_trigger_gpio_0 / rtl8192cu_trigger_gpio_0, which probably doesn't even run in real life. They use sync writes everywhere else. Also, remove "sync" and "async" from the names of the members of struct rtl_io to avoid confusion: write{8,16,32}_async -> write{8,16,32} read{8,16,32}_sync -> read{8,16,32} Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/fb71bae6-8b19-4b6e-b4a6-0d260f2139e1@gmail.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 12 +- drivers/net/wireless/realtek/rtlwifi/usb.c | 163 ++++++-------------- drivers/net/wireless/realtek/rtlwifi/wifi.h | 30 ++-- 3 files changed, 66 insertions(+), 139 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 96ce05bcf0b3..d059cfe5a2a9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -378,13 +378,13 @@ static void _rtl_pci_io_handler_init(struct device *dev, rtlpriv->io.dev = dev; - rtlpriv->io.write8_async = pci_write8_async; - rtlpriv->io.write16_async = pci_write16_async; - rtlpriv->io.write32_async = pci_write32_async; + rtlpriv->io.write8 = pci_write8_async; + rtlpriv->io.write16 = pci_write16_async; + rtlpriv->io.write32 = pci_write32_async; - rtlpriv->io.read8_sync = pci_read8_sync; - rtlpriv->io.read16_sync = pci_read16_sync; - rtlpriv->io.read32_sync = pci_read32_sync; + rtlpriv->io.read8 = pci_read8_sync; + rtlpriv->io.read16 = pci_read16_sync; + rtlpriv->io.read32 = pci_read32_sync; } static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 30bf2775a335..07a7e6fa46af 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -23,86 +23,23 @@ MODULE_DESCRIPTION("USB basic driver for rtlwifi"); #define MAX_USBCTRL_VENDORREQ_TIMES 10 -static void usbctrl_async_callback(struct urb *urb) -{ - if (urb) { - /* free dr */ - kfree(urb->setup_packet); - /* free databuf */ - kfree(urb->transfer_buffer); - } -} - -static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, - u16 value, u16 index, void *pdata, - u16 len) -{ - int rc; - unsigned int pipe; - u8 reqtype; - struct usb_ctrlrequest *dr; - struct urb *urb; - const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE; - u8 *databuf; - - if (WARN_ON_ONCE(len > databuf_maxlen)) - len = databuf_maxlen; - - pipe = usb_sndctrlpipe(udev, 0); /* write_out */ - reqtype = REALTEK_USB_VENQT_WRITE; - - dr = kzalloc(sizeof(*dr), GFP_ATOMIC); - if (!dr) - return -ENOMEM; - - databuf = kzalloc(databuf_maxlen, GFP_ATOMIC); - if (!databuf) { - kfree(dr); - return -ENOMEM; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(databuf); - kfree(dr); - return -ENOMEM; - } - - dr->bRequestType = reqtype; - dr->bRequest = request; - dr->wValue = cpu_to_le16(value); - dr->wIndex = cpu_to_le16(index); - dr->wLength = cpu_to_le16(len); - /* data are already in little-endian order */ - memcpy(databuf, pdata, len); - usb_fill_control_urb(urb, udev, pipe, - (unsigned char *)dr, databuf, len, - usbctrl_async_callback, NULL); - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) { - kfree(databuf); - kfree(dr); - } - usb_free_urb(urb); - return rc; -} - -static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, - u16 value, u16 index, void *pdata, - u16 len) +static void _usbctrl_vendorreq_sync(struct usb_device *udev, u8 reqtype, + u16 value, void *pdata, u16 len) { unsigned int pipe; int status; - u8 reqtype; int vendorreq_times = 0; static int count; - pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ - reqtype = REALTEK_USB_VENQT_READ; + if (reqtype == REALTEK_USB_VENQT_READ) + pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ + else + pipe = usb_sndctrlpipe(udev, 0); /* write_out */ do { - status = usb_control_msg(udev, pipe, request, reqtype, value, - index, pdata, len, 1000); + status = usb_control_msg(udev, pipe, REALTEK_USB_VENQT_CMD_REQ, + reqtype, value, REALTEK_USB_VENQT_CMD_IDX, + pdata, len, 1000); if (status < 0) { /* firmware download is checksumed, don't retry */ if ((value >= FW_8192C_START_ADDRESS && @@ -114,18 +51,15 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, } while (++vendorreq_times < MAX_USBCTRL_VENDORREQ_TIMES); if (status < 0 && count++ < 4) - pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", - value, status, *(u32 *)pdata); - return status; + dev_err(&udev->dev, "reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x reqtype=0x%x\n", + value, status, *(u32 *)pdata, reqtype); } static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) { struct device *dev = rtlpriv->io.dev; struct usb_device *udev = to_usb_device(dev); - u8 request; u16 wvalue; - u16 index; __le32 *data; unsigned long flags; @@ -134,14 +68,33 @@ static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) rtlpriv->usb_data_index = 0; data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); - request = REALTEK_USB_VENQT_CMD_REQ; - index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ wvalue = (u16)addr; - _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); + _usbctrl_vendorreq_sync(udev, REALTEK_USB_VENQT_READ, wvalue, data, len); return le32_to_cpu(*data); } + +static void _usb_write_sync(struct rtl_priv *rtlpriv, u32 addr, u32 val, u16 len) +{ + struct device *dev = rtlpriv->io.dev; + struct usb_device *udev = to_usb_device(dev); + unsigned long flags; + __le32 *data; + u16 wvalue; + + spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags); + if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) + rtlpriv->usb_data_index = 0; + data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); + + wvalue = (u16)(addr & 0x0000ffff); + *data = cpu_to_le32(val); + + _usbctrl_vendorreq_sync(udev, REALTEK_USB_VENQT_WRITE, wvalue, data, len); +} + static u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr) { return (u8)_usb_read_sync(rtlpriv, addr, 1); @@ -157,45 +110,19 @@ static u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr) return _usb_read_sync(rtlpriv, addr, 4); } -static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, - u16 len) +static void _usb_write8_sync(struct rtl_priv *rtlpriv, u32 addr, u8 val) { - u8 request; - u16 wvalue; - u16 index; - __le32 data; - int ret; - - request = REALTEK_USB_VENQT_CMD_REQ; - index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ - wvalue = (u16)(addr&0x0000ffff); - data = cpu_to_le32(val); - - ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, - index, &data, len); - if (ret < 0) - dev_err(&udev->dev, "error %d writing at 0x%x\n", ret, addr); + _usb_write_sync(rtlpriv, addr, val, 1); } -static void _usb_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) +static void _usb_write16_sync(struct rtl_priv *rtlpriv, u32 addr, u16 val) { - struct device *dev = rtlpriv->io.dev; - - _usb_write_async(to_usb_device(dev), addr, val, 1); + _usb_write_sync(rtlpriv, addr, val, 2); } -static void _usb_write16_async(struct rtl_priv *rtlpriv, u32 addr, u16 val) +static void _usb_write32_sync(struct rtl_priv *rtlpriv, u32 addr, u32 val) { - struct device *dev = rtlpriv->io.dev; - - _usb_write_async(to_usb_device(dev), addr, val, 2); -} - -static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) -{ - struct device *dev = rtlpriv->io.dev; - - _usb_write_async(to_usb_device(dev), addr, val, 4); + _usb_write_sync(rtlpriv, addr, val, 4); } static void _rtl_usb_io_handler_init(struct device *dev, @@ -205,12 +132,12 @@ static void _rtl_usb_io_handler_init(struct device *dev, rtlpriv->io.dev = dev; mutex_init(&rtlpriv->io.bb_mutex); - rtlpriv->io.write8_async = _usb_write8_async; - rtlpriv->io.write16_async = _usb_write16_async; - rtlpriv->io.write32_async = _usb_write32_async; - rtlpriv->io.read8_sync = _usb_read8_sync; - rtlpriv->io.read16_sync = _usb_read16_sync; - rtlpriv->io.read32_sync = _usb_read32_sync; + rtlpriv->io.write8 = _usb_write8_sync; + rtlpriv->io.write16 = _usb_write16_sync; + rtlpriv->io.write32 = _usb_write32_sync; + rtlpriv->io.read8 = _usb_read8_sync; + rtlpriv->io.read16 = _usb_read16_sync; + rtlpriv->io.read32 = _usb_read32_sync; } static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index d87cd2252eac..53af324f3807 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1447,13 +1447,13 @@ struct rtl_io { /*PCI IO map */ unsigned long pci_base_addr; /*device I/O address */ - void (*write8_async)(struct rtl_priv *rtlpriv, u32 addr, u8 val); - void (*write16_async)(struct rtl_priv *rtlpriv, u32 addr, u16 val); - void (*write32_async)(struct rtl_priv *rtlpriv, u32 addr, u32 val); + void (*write8)(struct rtl_priv *rtlpriv, u32 addr, u8 val); + void (*write16)(struct rtl_priv *rtlpriv, u32 addr, u16 val); + void (*write32)(struct rtl_priv *rtlpriv, u32 addr, u32 val); - u8 (*read8_sync)(struct rtl_priv *rtlpriv, u32 addr); - u16 (*read16_sync)(struct rtl_priv *rtlpriv, u32 addr); - u32 (*read32_sync)(struct rtl_priv *rtlpriv, u32 addr); + u8 (*read8)(struct rtl_priv *rtlpriv, u32 addr); + u16 (*read16)(struct rtl_priv *rtlpriv, u32 addr); + u32 (*read32)(struct rtl_priv *rtlpriv, u32 addr); }; @@ -2916,25 +2916,25 @@ extern u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M]; static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) { - return rtlpriv->io.read8_sync(rtlpriv, addr); + return rtlpriv->io.read8(rtlpriv, addr); } static inline u16 rtl_read_word(struct rtl_priv *rtlpriv, u32 addr) { - return rtlpriv->io.read16_sync(rtlpriv, addr); + return rtlpriv->io.read16(rtlpriv, addr); } static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) { - return rtlpriv->io.read32_sync(rtlpriv, addr); + return rtlpriv->io.read32(rtlpriv, addr); } static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) { - rtlpriv->io.write8_async(rtlpriv, addr, val8); + rtlpriv->io.write8(rtlpriv, addr, val8); if (rtlpriv->cfg->write_readback) - rtlpriv->io.read8_sync(rtlpriv, addr); + rtlpriv->io.read8(rtlpriv, addr); } static inline void rtl_write_byte_with_val32(struct ieee80211_hw *hw, @@ -2947,19 +2947,19 @@ static inline void rtl_write_byte_with_val32(struct ieee80211_hw *hw, static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) { - rtlpriv->io.write16_async(rtlpriv, addr, val16); + rtlpriv->io.write16(rtlpriv, addr, val16); if (rtlpriv->cfg->write_readback) - rtlpriv->io.read16_sync(rtlpriv, addr); + rtlpriv->io.read16(rtlpriv, addr); } static inline void rtl_write_dword(struct rtl_priv *rtlpriv, u32 addr, u32 val32) { - rtlpriv->io.write32_async(rtlpriv, addr, val32); + rtlpriv->io.write32(rtlpriv, addr, val32); if (rtlpriv->cfg->write_readback) - rtlpriv->io.read32_sync(rtlpriv, addr); + rtlpriv->io.read32(rtlpriv, addr); } static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, From e3d373ec4f02bf41379d91707e3e3f2a46464cd7 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 0074/2255] wifi: ath11k: add support to select 6 GHz regulatory type There are 3 types of regulatory rules for AP mode and 6 type for station mode. Add wmi_vdev_type and ieee80211_ap_reg_power to select the exact reg rules. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 70 +++++++++++++++++++++------ drivers/net/wireless/ath/ath11k/reg.h | 6 ++- drivers/net/wireless/ath/ath11k/wmi.c | 3 +- 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index b4fd4d2107c7..78b99ab10c63 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -618,25 +618,68 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, *rule_idx = i; } +enum wmi_reg_6ghz_ap_type +ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type) +{ + switch (power_type) { + case IEEE80211_REG_LPI_AP: + return WMI_REG_INDOOR_AP; + case IEEE80211_REG_SP_AP: + return WMI_REG_STANDARD_POWER_AP; + case IEEE80211_REG_VLP_AP: + return WMI_REG_VERY_LOW_POWER_AP; + default: + return WMI_REG_MAX_AP_TYPE; + } +} + struct ieee80211_regdomain * ath11k_reg_build_regd(struct ath11k_base *ab, - struct cur_regulatory_info *reg_info, bool intersect) + struct cur_regulatory_info *reg_info, bool intersect, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type) { struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL; - struct cur_reg_rule *reg_rule; + struct cur_reg_rule *reg_rule, *reg_rule_6ghz; u8 i = 0, j = 0, k = 0; u8 num_rules; u16 max_bw; - u32 flags; + u32 flags, reg_6ghz_number, max_bw_6ghz; char alpha2[3]; num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules; - /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list. - * This can be updated after complete 6 GHz regulatory support is added. - */ - if (reg_info->is_ext_reg_event) - num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; + if (reg_info->is_ext_reg_event) { + if (vdev_type == WMI_VDEV_TYPE_STA) { + enum wmi_reg_6ghz_ap_type ap_type; + + ap_type = ath11k_reg_ap_pwr_convert(power_type); + + if (ap_type == WMI_REG_MAX_AP_TYPE) + ap_type = WMI_REG_INDOOR_AP; + + reg_6ghz_number = reg_info->num_6ghz_rules_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + + if (reg_6ghz_number == 0) { + ap_type = WMI_REG_INDOOR_AP; + reg_6ghz_number = reg_info->num_6ghz_rules_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + } + + reg_rule_6ghz = reg_info->reg_rules_6ghz_client_ptr + [ap_type][WMI_REG_DEFAULT_CLIENT]; + max_bw_6ghz = reg_info->max_bw_6ghz_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + } else { + reg_6ghz_number = reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; + reg_rule_6ghz = + reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP]; + max_bw_6ghz = reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]; + } + + num_rules += reg_6ghz_number; + } if (!num_rules) goto ret; @@ -683,13 +726,10 @@ ath11k_reg_build_regd(struct ath11k_base *ab, * per other BW rule flags we pass from here */ flags = NL80211_RRF_AUTO_BW; - } else if (reg_info->is_ext_reg_event && - reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] && - (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) { - reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] + - k++; - max_bw = min_t(u16, reg_rule->max_bw, - reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]); + } else if (reg_info->is_ext_reg_event && reg_6ghz_number && + k < reg_6ghz_number) { + reg_rule = reg_rule_6ghz + k++; + max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); flags = NL80211_RRF_AUTO_BW; } else { break; diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index f28902f85e41..989b27b16bea 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -34,7 +34,11 @@ void ath11k_reg_free(struct ath11k_base *ab); void ath11k_regd_update_work(struct work_struct *work); struct ieee80211_regdomain * ath11k_reg_build_regd(struct ath11k_base *ab, - struct cur_regulatory_info *reg_info, bool intersect); + struct cur_regulatory_info *reg_info, bool intersect, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type); int ath11k_regd_update(struct ath11k *ar); int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait); +enum wmi_reg_6ghz_ap_type +ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); #endif diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 89514899fcd5..58882829351e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -7151,7 +7151,8 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) intersect = true; - regd = ath11k_reg_build_regd(ab, reg_info, intersect); + regd = ath11k_reg_build_regd(ab, reg_info, intersect, + WMI_VDEV_TYPE_AP, IEEE80211_REG_LPI_AP); if (!regd) { ath11k_warn(ab, "failed to build regd from reg_info\n"); goto fallback; From 7004bdceef605e5c1c5ab4aaf282002ad7523ddd Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 0075/2255] wifi: ath11k: store cur_regulatory_info for each radio The regulatory info of WMI_REG_CHAN_LIST_CC_EXT_EVENTID is not saved in ath11k now, the info should be saved in ath11k. Save the info for each radio and support switch regulatory rules dynamically. As mac.c will also call ath11k_reg_handle_chan_list() in next patches move the function to reg.c. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/reg.c | 179 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/reg.h | 5 + drivers/net/wireless/ath/ath11k/wmi.c | 148 +++----------------- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 5 files changed, 207 insertions(+), 127 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 7e3b6779f4e9..cc91f7d3ca8e 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -922,6 +922,7 @@ struct ath11k_base { * This may or may not be used during the runtime */ struct ieee80211_regdomain *new_regd[MAX_RADIOS]; + struct cur_regulatory_info *reg_info_store; /* Current DFS Regulatory */ enum ath11k_dfs_region dfs_region; diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 78b99ab10c63..adcd9063a59c 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -798,6 +798,159 @@ 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"); + ath11k_warn(ab, "failed to extract regulatory info\n"); goto mem_free; } - pdev_idx = reg_info->phy_id; - - /* Avoid default reg rule updates sent during FW recovery if - * it is already available - */ - spin_lock(&ab->base_lock); - if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && - ab->default_regd[pdev_idx]) { - spin_unlock(&ab->base_lock); + ret = ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP); + if (ret) { + ath11k_warn(ab, "failed to process regulatory info %d\n", ret); goto mem_free; } - spin_unlock(&ab->base_lock); - if (pdev_idx >= ab->num_radios) { - /* Process the event for phy0 only if single_pdev_only - * is true. If pdev_idx is valid but not 0, discard the - * event. Otherwise, it goes to fallback. - */ - if (ab->hw_params.single_pdev_only && - pdev_idx < ab->hw_params.num_rxmda_per_pdev) - goto mem_free; - else - goto fallback; - } + kfree(reg_info); + return 0; - /* Avoid multiple overwrites to default regd, during core - * stop-start after mac registration. - */ - if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && - !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, - (char *)reg_info->alpha2, 2)) - goto mem_free; - - /* Intersect new rules with default regd if a new country setting was - * requested, i.e a default regd was already set during initialization - * and the regd coming from this event has a valid country info. - */ - if (ab->default_regd[pdev_idx] && - !ath11k_reg_is_world_alpha((char *) - ab->default_regd[pdev_idx]->alpha2) && - !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) - intersect = true; - - regd = ath11k_reg_build_regd(ab, reg_info, intersect, - WMI_VDEV_TYPE_AP, IEEE80211_REG_LPI_AP); - if (!regd) { - ath11k_warn(ab, "failed to build regd from reg_info\n"); - goto fallback; - } - - spin_lock(&ab->base_lock); - if (ab->default_regd[pdev_idx]) { - /* The initial rules from FW after WMI Init is to build - * the default regd. From then on, any rules updated for - * the pdev could be due to user reg changes. - * Free previously built regd before assigning the newly - * generated regd to ar. NULL pointer handling will be - * taken care by kfree itself. - */ - ar = ab->pdevs[pdev_idx].ar; - kfree(ab->new_regd[pdev_idx]); - ab->new_regd[pdev_idx] = regd; - queue_work(ab->workqueue, &ar->regd_update_work); - } else { - /* This regd would be applied during mac registration and is - * held constant throughout for regd intersection purpose - */ - ab->default_regd[pdev_idx] = regd; - } - ab->dfs_region = reg_info->dfs_region; - spin_unlock(&ab->base_lock); - - goto mem_free; - -fallback: - /* Fallback to older reg (by sending previous country setting - * again if fw has succeeded and we failed to process here. - * The Regdomain should be uniform across driver and fw. Since the - * FW has processed the command and sent a success status, we expect - * this function to succeed as well. If it doesn't, CTRY needs to be - * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. - */ - /* TODO: This is rare, but still should also be handled */ - WARN_ON(1); mem_free: - if (reg_info) { - kfree(reg_info->reg_rules_2ghz_ptr); - kfree(reg_info->reg_rules_5ghz_ptr); - if (reg_info->is_ext_reg_event) { - for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) - kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); - - for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) - for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) - kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]); - } - kfree(reg_info); - } + ath11k_reg_reset_info(reg_info); + kfree(reg_info); return ret; } diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index b1b4ee804b7b..a466d2bb4bb8 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4951,6 +4951,7 @@ struct ath11k_targ_cap { }; enum wmi_vdev_type { + WMI_VDEV_TYPE_UNSPEC = 0, WMI_VDEV_TYPE_AP = 1, WMI_VDEV_TYPE_STA = 2, WMI_VDEV_TYPE_IBSS = 3, From cf2df0080bd59cb97a1519ddefaf59788febdaa5 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 0076/2255] wifi: ath11k: fix a possible dead lock caused by ab->base_lock spin_lock()/spin_unlock() are used in ath11k_reg_chan_list_event() to acquire/release ab->base_lock. For now this is safe because that function is only called in soft IRQ context. But ath11k_reg_chan_list_event() will be called from process context in an upcoming patch, and this can result in a deadlock if ab->base_lock is acquired in process context and then soft IRQ occurs on the same CPU and tries to acquire that lock. Fix it by using spin_lock_bh() and spin_unlock_bh() instead. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 69a0fcf8a9f2 ("ath11k: Avoid reg rules update during firmware recovery") Signed-off-by: Baochen Qiang Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index adcd9063a59c..d4fd3509e608 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -852,13 +852,13 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, /* Avoid default reg rule updates sent during FW recovery if * it is already available */ - spin_lock(&ab->base_lock); + spin_lock_bh(&ab->base_lock); if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && ab->default_regd[pdev_idx]) { - spin_unlock(&ab->base_lock); + spin_unlock_bh(&ab->base_lock); goto retfail; } - spin_unlock(&ab->base_lock); + spin_unlock_bh(&ab->base_lock); if (pdev_idx >= ab->num_radios) { /* Process the event for phy0 only if single_pdev_only @@ -911,7 +911,7 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, ab->reg_info_store[pdev_idx] = *reg_info; } - spin_lock(&ab->base_lock); + spin_lock_bh(&ab->base_lock); if (ab->default_regd[pdev_idx]) { /* The initial rules from FW after WMI Init is to build * the default regd. From then on, any rules updated for @@ -931,7 +931,7 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, ab->default_regd[pdev_idx] = regd; } ab->dfs_region = reg_info->dfs_region; - spin_unlock(&ab->base_lock); + spin_unlock_bh(&ab->base_lock); return 0; From 17144d32e90708cd5532055f3d9894ced9ac45a2 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 0077/2255] wifi: ath11k: update regulatory rules when interface added There are two power types for 6 GHz regulatory, one is AP, another is client. When firmware boots up, WMI_REG_CHAN_LIST_CC_EXT_EVENTID is sent from firmware at an early stage, the interface mode is not decided at this point, then ath11k select reg rules of AP type as default. After interface is created, it is exactly decided the interface type such as AP/mesh point/station. Then ath11k need to update reg rules to the exact power type matched to the interface type. The client power type is used for station interface, and AP power type is used for AP/mesh point interface. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 8 ++++++++ drivers/net/wireless/ath/ath11k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath11k/wmi.h | 1 + 3 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index db241589424d..3f52428433d1 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6949,6 +6949,14 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, ret); } + if (ath11k_wmi_supports_6ghz_cc_ext(ar)) { + struct cur_regulatory_info *reg_info; + + reg_info = &ab->reg_info_store[ar->pdev_idx]; + ath11k_dbg(ab, ATH11K_DBG_MAC, "interface added to change reg rules\n"); + ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_LPI_AP); + } + mutex_unlock(&ar->conf_mutex); return 0; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 7e604d4b9a77..5c6f3bdcb4af 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -9687,3 +9687,9 @@ int ath11k_wmi_sta_keepalive(struct ath11k *ar, return ath11k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID); } + +bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar) +{ + return test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, + ar->ab->wmi_ab.svc_map) && ar->supports_6ghz; +} diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index a466d2bb4bb8..528756198a7a 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -6480,5 +6480,6 @@ int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_va int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar); int ath11k_wmi_sta_keepalive(struct ath11k *ar, const struct wmi_sta_keepalive_arg *arg); +bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar); #endif From 1329beb56297021042788223e666f6ccd2e11a0a Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 0078/2255] wifi: ath11k: update regulatory rules when connect to AP on 6 GHz band for station When station connect to AP on 6 GHz band, it needs switch the regulatory rules according to the regulatory info sub field in HE operation element. Switch to the power type which AP used for station interface. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-6-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 3f52428433d1..0b2b79ca5b1d 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7619,6 +7619,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); int ret; struct peer_create_params param; + struct cur_regulatory_info *reg_info; + enum ieee80211_ap_reg_power power_type; mutex_lock(&ar->conf_mutex); @@ -7626,6 +7628,22 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, "chanctx assign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); + if (ath11k_wmi_supports_6ghz_cc_ext(ar) && + ctx->def.chan->band == NL80211_BAND_6GHZ && + arvif->vdev_type == WMI_VDEV_TYPE_STA) { + reg_info = &ab->reg_info_store[ar->pdev_idx]; + power_type = vif->bss_conf.power_type; + + ath11k_dbg(ab, ATH11K_DBG_MAC, "chanctx power type %d\n", power_type); + + if (power_type == IEEE80211_REG_UNSET_AP) { + ret = -EINVAL; + goto out; + } + + ath11k_reg_handle_chan_list(ab, reg_info, power_type); + } + /* for QCA6390 bss peer must be created before vdev_start */ if (ab->hw_params.vdev_start_delay && arvif->vdev_type != WMI_VDEV_TYPE_AP && From 28f64d368b21c551d5faf33687e7228531256d10 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 0079/2255] wifi: ath11k: save power spectral density(PSD) of regulatory rule Save the power spectral density (PSD) report from firmware to struct ieee80211_reg_rule. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-7-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index d4fd3509e608..737fcd450d4b 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -425,6 +425,11 @@ static void ath11k_reg_intersect_rules(struct ieee80211_reg_rule *rule1, /* Use the flags of both the rules */ new_rule->flags = rule1->flags | rule2->flags; + if ((rule1->flags & NL80211_RRF_PSD) && (rule2->flags & NL80211_RRF_PSD)) + new_rule->psd = min_t(s8, rule1->psd, rule2->psd); + else + new_rule->flags &= ~NL80211_RRF_PSD; + /* To be safe, lts use the max cac timeout of both rules */ new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms, rule2->dfs_cac_ms); @@ -527,13 +532,14 @@ ath11k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw) static void ath11k_reg_update_rule(struct ieee80211_reg_rule *reg_rule, u32 start_freq, u32 end_freq, u32 bw, u32 ant_gain, u32 reg_pwr, - u32 reg_flags) + s8 psd, u32 reg_flags) { reg_rule->freq_range.start_freq_khz = MHZ_TO_KHZ(start_freq); reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(end_freq); reg_rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw); reg_rule->power_rule.max_antenna_gain = DBI_TO_MBI(ant_gain); reg_rule->power_rule.max_eirp = DBM_TO_MBM(reg_pwr); + reg_rule->psd = psd; reg_rule->flags = reg_flags; } @@ -563,7 +569,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, reg_rule->start_freq, ETSI_WEATHER_RADAR_BAND_LOW, bw, reg_rule->ant_gain, reg_rule->reg_power, - flags); + reg_rule->psd_eirp, flags); ath11k_dbg(ab, ATH11K_DBG_REG, "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", @@ -584,7 +590,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, ath11k_reg_update_rule(regd->reg_rules + i, start_freq, end_freq, bw, reg_rule->ant_gain, - reg_rule->reg_power, flags); + reg_rule->reg_power, reg_rule->psd_eirp, flags); regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT; @@ -605,7 +611,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, ETSI_WEATHER_RADAR_BAND_HIGH, reg_rule->end_freq, bw, reg_rule->ant_gain, reg_rule->reg_power, - flags); + reg_rule->psd_eirp, flags); ath11k_dbg(ab, ATH11K_DBG_REG, "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", @@ -731,6 +737,8 @@ ath11k_reg_build_regd(struct ath11k_base *ab, reg_rule = reg_rule_6ghz + k++; max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); flags = NL80211_RRF_AUTO_BW; + if (reg_rule->psd_flag) + flags |= NL80211_RRF_PSD; } else { break; } @@ -742,7 +750,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab, reg_rule->start_freq, reg_rule->end_freq, max_bw, reg_rule->ant_gain, reg_rule->reg_power, - flags); + reg_rule->psd_eirp, flags); /* Update dfs cac timeout if the dfs domain is ETSI and the * new rule covers weather radar band. From 6f4e235be6550f67791616d88682fb99f4e670e4 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 0080/2255] wifi: ath11k: add parse of transmit power envelope element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The transmit power envelope element has some fields for power, ath11k should parse it according to IEEE Std 802.11ax™‐2021. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-8-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.h | 39 +++++ drivers/net/wireless/ath/ath11k/mac.c | 188 +++++++++++++++++++++++++ 2 files changed, 227 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index cc91f7d3ca8e..9a398de5dc44 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -314,6 +314,43 @@ struct ath11k_rekey_data { bool enable_offload; }; +/** + * struct ath11k_chan_power_info - TPE containing power info per channel chunk + * @chan_cfreq: channel center freq (MHz) + * e.g. + * channel 37/20 MHz, it is 6135 + * channel 37/40 MHz, it is 6125 + * channel 37/80 MHz, it is 6145 + * channel 37/160 MHz, it is 6185 + * @tx_power: transmit power (dBm) + */ +struct ath11k_chan_power_info { + u16 chan_cfreq; + s8 tx_power; +}; + +/** + * struct ath11k_reg_tpc_power_info - regulatory TPC power info + * @is_psd_power: is PSD power or not + * @eirp_power: Maximum EIRP power (dBm), valid only if power is PSD + * @ap_power_type: type of power (SP/LPI/VLP) + * @num_pwr_levels: number of power levels + * @reg_max: Array of maximum TX power (dBm) per PSD value + * @ap_constraint_power: AP constraint power (dBm) + * @tpe: TPE values processed from TPE IE + * @chan_power_info: power info to send to firmware + */ +struct ath11k_reg_tpc_power_info { + bool is_psd_power; + u8 eirp_power; + enum wmi_reg_6ghz_ap_type ap_power_type; + u8 num_pwr_levels; + u8 reg_max[IEEE80211_MAX_NUM_PWR_LEVEL]; + u8 ap_constraint_power; + s8 tpe[IEEE80211_MAX_NUM_PWR_LEVEL]; + struct ath11k_chan_power_info chan_power_info[IEEE80211_MAX_NUM_PWR_LEVEL]; +}; + struct ath11k_vif { u32 vdev_id; enum wmi_vdev_type vdev_type; @@ -369,6 +406,8 @@ struct ath11k_vif { struct ath11k_arp_ns_offload arp_ns_offload; struct ath11k_rekey_data rekey_data; + struct ath11k_reg_tpc_power_info reg_tpc_info; + #ifdef CONFIG_ATH11K_DEBUGFS struct dentry *debugfs_twt; #endif /* CONFIG_ATH11K_DEBUGFS */ diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 0b2b79ca5b1d..4be5b2a35ec9 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7608,6 +7608,192 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, return 0; } +static u8 ath11k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt) +{ + switch (txpwr_intrprt) { + /* Refer "Table 9-276-Meaning of Maximum Transmit Power Count subfield + * if the Maximum Transmit Power Interpretation subfield is 0 or 2" of + * "IEEE Std 802.11ax 2021". + */ + case IEEE80211_TPE_LOCAL_EIRP: + case IEEE80211_TPE_REG_CLIENT_EIRP: + txpwr_cnt = txpwr_cnt <= 3 ? txpwr_cnt : 3; + txpwr_cnt = txpwr_cnt + 1; + break; + /* Refer "Table 9-277-Meaning of Maximum Transmit Power Count subfield + * if Maximum Transmit Power Interpretation subfield is 1 or 3" of + * "IEEE Std 802.11ax 2021". + */ + case IEEE80211_TPE_LOCAL_EIRP_PSD: + case IEEE80211_TPE_REG_CLIENT_EIRP_PSD: + txpwr_cnt = txpwr_cnt <= 4 ? txpwr_cnt : 4; + txpwr_cnt = txpwr_cnt ? (BIT(txpwr_cnt - 1)) : 1; + break; + } + + return txpwr_cnt; +} + +static u8 ath11k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def) +{ + if (chan_def->chan->flags & IEEE80211_CHAN_PSD) { + switch (chan_def->width) { + case NL80211_CHAN_WIDTH_20: + return 1; + case NL80211_CHAN_WIDTH_40: + return 2; + case NL80211_CHAN_WIDTH_80: + return 4; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + return 8; + default: + return 1; + } + } else { + switch (chan_def->width) { + case NL80211_CHAN_WIDTH_20: + return 1; + case NL80211_CHAN_WIDTH_40: + return 2; + case NL80211_CHAN_WIDTH_80: + return 3; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + return 4; + default: + return 1; + } + } +} + +static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_tx_pwr_env *single_tpe; + enum wmi_reg_6ghz_client_type client_type; + struct cur_regulatory_info *reg_info; + int i; + u8 pwr_count, pwr_interpret, pwr_category; + u8 psd_index = 0, non_psd_index = 0, local_tpe_count = 0, reg_tpe_count = 0; + bool use_local_tpe, non_psd_set = false, psd_set = false; + + reg_info = &ab->reg_info_store[ar->pdev_idx]; + client_type = reg_info->client_type; + + for (i = 0; i < bss_conf->tx_pwr_env_num; i++) { + single_tpe = &bss_conf->tx_pwr_env[i]; + pwr_category = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_CATEGORY); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + + if (pwr_category == client_type) { + if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP || + pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) + local_tpe_count++; + else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP || + pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) + reg_tpe_count++; + } + } + + if (!reg_tpe_count && !local_tpe_count) { + ath11k_warn(ab, + "no transmit power envelope match client power type %d\n", + client_type); + return; + } else if (!reg_tpe_count) { + use_local_tpe = true; + } else { + use_local_tpe = false; + } + + for (i = 0; i < bss_conf->tx_pwr_env_num; i++) { + single_tpe = &bss_conf->tx_pwr_env[i]; + pwr_category = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_CATEGORY); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + + if (pwr_category != client_type) + continue; + + /* get local transmit power envelope */ + if (use_local_tpe) { + if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP) { + non_psd_index = i; + non_psd_set = true; + } else if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) { + psd_index = i; + psd_set = true; + } + /* get regulatory transmit power envelope */ + } else { + if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP) { + non_psd_index = i; + non_psd_set = true; + } else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) { + psd_index = i; + psd_set = true; + } + } + } + + if (non_psd_set && !psd_set) { + single_tpe = &bss_conf->tx_pwr_env[non_psd_index]; + pwr_count = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_COUNT); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + arvif->reg_tpc_info.is_psd_power = false; + arvif->reg_tpc_info.eirp_power = 0; + + arvif->reg_tpc_info.num_pwr_levels = + ath11k_mac_get_tpe_count(pwr_interpret, pwr_count); + + for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) { + ath11k_dbg(ab, ATH11K_DBG_MAC, + "non PSD power[%d] : %d\n", + i, single_tpe->tx_power[i]); + arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2; + } + } + + if (psd_set) { + single_tpe = &bss_conf->tx_pwr_env[psd_index]; + pwr_count = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_COUNT); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + arvif->reg_tpc_info.is_psd_power = true; + + if (pwr_count == 0) { + ath11k_dbg(ab, ATH11K_DBG_MAC, + "TPE PSD power : %d\n", single_tpe->tx_power[0]); + arvif->reg_tpc_info.num_pwr_levels = + ath11k_mac_get_num_pwr_levels(&ctx->def); + + for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) + arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[0] / 2; + } else { + arvif->reg_tpc_info.num_pwr_levels = + ath11k_mac_get_tpe_count(pwr_interpret, pwr_count); + + for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) { + ath11k_dbg(ab, ATH11K_DBG_MAC, + "TPE PSD power[%d] : %d\n", + i, single_tpe->tx_power[i]); + arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2; + } + } + } +} + static int ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -7642,6 +7828,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, } ath11k_reg_handle_chan_list(ab, reg_info, power_type); + + ath11k_mac_parse_tx_pwr_env(ar, vif, ctx); } /* for QCA6390 bss peer must be created before vdev_start */ From 46f20de2c4f8faadea12679a3edb2082f35dcf1e Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 0081/2255] wifi: ath11k: save max transmit power in vdev start response event from firmware Save the max transmit power received in the vdev start response event from firmware. A subsequent patch will use this to calculate the final power value for WMI_VDEV_SET_TPC_POWER_CMDID. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-9-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/wmi.c | 3 ++- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 9a398de5dc44..12fa5b28520f 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -778,6 +778,7 @@ struct ath11k { /* protected by conf_mutex */ bool ps_state_enable; bool ps_timekeeper_enable; + s8 max_allowed_tx_power; }; struct ath11k_band_cap { diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 5c6f3bdcb4af..3a3a2b697119 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -5036,6 +5036,7 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf vdev_rsp->mac_id = ev->mac_id; vdev_rsp->cfgd_tx_streams = ev->cfgd_tx_streams; vdev_rsp->cfgd_rx_streams = ev->cfgd_rx_streams; + vdev_rsp->max_allowed_tx_power = ev->max_allowed_tx_power; kfree(tb); return 0; @@ -7257,7 +7258,7 @@ static void ath11k_vdev_start_resp_event(struct ath11k_base *ab, struct sk_buff } ar->last_wmi_vdev_start_status = 0; - + ar->max_allowed_tx_power = vdev_start_resp.max_allowed_tx_power; status = vdev_start_resp.status; if (WARN_ON_ONCE(status)) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 528756198a7a..7f6287f22cf5 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4119,6 +4119,7 @@ struct wmi_vdev_start_resp_event { }; u32 cfgd_tx_streams; u32 cfgd_rx_streams; + s32 max_allowed_tx_power; } __packed; /* VDEV start response status codes */ From 92425f788feede9bf152ecf3fb7a264942ee7719 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 0082/2255] wifi: ath11k: fill parameters for vdev set tpc power WMI command Prepare the parameters which are needed for WMI command WMI_VDEV_SET_TPC_POWER_CMDID. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-10-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 284 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/mac.h | 5 +- 2 files changed, 288 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 4be5b2a35ec9..f812a6f44b82 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7667,6 +7667,290 @@ static u8 ath11k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def) } } +static u16 ath11k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def) +{ + u16 diff_seq; + + /* It is to get the lowest channel number's center frequency of the chan. + * For example, + * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1 + * with center frequency 5955, its diff is 5965 - 5955 = 10. + * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1 + * with center frequency 5955, its diff is 5985 - 5955 = 30. + * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1 + * with center frequency 5955, its diff is 6025 - 5955 = 70. + */ + switch (chan_def->width) { + case NL80211_CHAN_WIDTH_160: + diff_seq = 70; + break; + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + diff_seq = 30; + break; + case NL80211_CHAN_WIDTH_40: + diff_seq = 10; + break; + default: + diff_seq = 0; + } + + return chan_def->center_freq1 - diff_seq; +} + +static u16 ath11k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def, + u16 start_seq, u8 seq) +{ + u16 seg_seq; + + /* It is to get the center frequency of the specific bandwidth. + * start_seq means the lowest channel number's center frequency. + * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz&80P80. + * For example, + * lowest channel is 1, its center frequency 5955, + * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0. + * lowest channel is 1, its center frequency 5955, + * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10. + * lowest channel is 1, its center frequency 5955, + * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30. + * lowest channel is 1, its center frequency 5955, + * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70. + */ + if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3) + return chan_def->center_freq2; + + seg_seq = 10 * (BIT(seq) - 1); + return seg_seq + start_seq; +} + +static void ath11k_mac_get_psd_channel(struct ath11k *ar, + u16 step_freq, + u16 *start_freq, + u16 *center_freq, + u8 i, + struct ieee80211_channel **temp_chan, + s8 *tx_power) +{ + /* It is to get the center frequency for each 20 MHz. + * For example, if the chan is 160 MHz and center frequency is 6025, + * then it include 8 channels, they are 1/5/9/13/17/21/25/29, + * channel number 1's center frequency is 5955, it is parameter start_freq. + * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels. + * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7, + * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095, + * the gap is 20 for each channel, parameter step_freq means the gap. + * after get the center frequency of each channel, it is easy to find the + * struct ieee80211_channel of it and get the max_reg_power. + */ + *center_freq = *start_freq + i * step_freq; + *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq); + *tx_power = (*temp_chan)->max_reg_power; +} + +static void ath11k_mac_get_eirp_power(struct ath11k *ar, + u16 *start_freq, + u16 *center_freq, + u8 i, + struct ieee80211_channel **temp_chan, + struct cfg80211_chan_def *def, + s8 *tx_power) +{ + /* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/ + * 160 MHz&80P80 bandwidth, and then plus 10 to the center frequency, + * it is the center frequency of a channel number. + * For example, when configured channel number is 1. + * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975, + * then it is channel number 5. + * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995, + * then it is channel number 9. + * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035, + * then it is channel number 17. + * after get the center frequency of each channel, it is easy to find the + * struct ieee80211_channel of it and get the max_reg_power. + */ + *center_freq = ath11k_mac_get_seg_freq(def, *start_freq, i); + + /* For the 20 MHz, its center frequency is same with same channel */ + if (i != 0) + *center_freq += 10; + + *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq); + *tx_power = (*temp_chan)->max_reg_power; +} + +void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath11k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info; + struct ieee80211_channel *chan, *temp_chan; + u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction; + bool is_psd_power = false, is_tpe_present = false; + s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL], + psd_power, tx_power, eirp_power; + u16 start_freq, center_freq; + + chan = ctx->def.chan; + start_freq = ath11k_mac_get_6ghz_start_frequency(&ctx->def); + pwr_reduction = bss_conf->pwr_reduction; + + if (arvif->reg_tpc_info.num_pwr_levels) { + is_tpe_present = true; + num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels; + } else { + num_pwr_levels = ath11k_mac_get_num_pwr_levels(&ctx->def); + } + + for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) { + /* STA received TPE IE*/ + if (is_tpe_present) { + /* local power is PSD power*/ + if (chan->flags & IEEE80211_CHAN_PSD) { + /* Connecting AP is psd power */ + if (reg_tpc_info->is_psd_power) { + is_psd_power = true; + ath11k_mac_get_psd_channel(ar, 20, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &tx_power); + psd_power = temp_chan->psd; + eirp_power = tx_power; + max_tx_power[pwr_lvl_idx] = + min_t(s8, + psd_power, + reg_tpc_info->tpe[pwr_lvl_idx]); + /* Connecting AP is not psd power */ + } else { + ath11k_mac_get_eirp_power(ar, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &ctx->def, + &tx_power); + psd_power = temp_chan->psd; + /* convert psd power to EIRP power based + * on channel width + */ + tx_power = + min_t(s8, tx_power, + psd_power + 13 + pwr_lvl_idx * 3); + max_tx_power[pwr_lvl_idx] = + min_t(s8, + tx_power, + reg_tpc_info->tpe[pwr_lvl_idx]); + } + /* local power is not PSD power */ + } else { + /* Connecting AP is psd power */ + if (reg_tpc_info->is_psd_power) { + is_psd_power = true; + ath11k_mac_get_psd_channel(ar, 20, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &tx_power); + eirp_power = tx_power; + max_tx_power[pwr_lvl_idx] = + reg_tpc_info->tpe[pwr_lvl_idx]; + /* Connecting AP is not psd power */ + } else { + ath11k_mac_get_eirp_power(ar, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &ctx->def, + &tx_power); + max_tx_power[pwr_lvl_idx] = + min_t(s8, + tx_power, + reg_tpc_info->tpe[pwr_lvl_idx]); + } + } + /* STA not received TPE IE */ + } else { + /* local power is PSD power*/ + if (chan->flags & IEEE80211_CHAN_PSD) { + is_psd_power = true; + ath11k_mac_get_psd_channel(ar, 20, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &tx_power); + psd_power = temp_chan->psd; + eirp_power = tx_power; + max_tx_power[pwr_lvl_idx] = psd_power; + } else { + ath11k_mac_get_eirp_power(ar, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &ctx->def, + &tx_power); + max_tx_power[pwr_lvl_idx] = tx_power; + } + } + + if (is_psd_power) { + /* If AP local power constraint is present */ + if (pwr_reduction) + eirp_power = eirp_power - pwr_reduction; + + /* If firmware updated max tx power is non zero, then take + * the min of firmware updated ap tx power + * and max power derived from above mentioned parameters. + */ + ath11k_dbg(ab, ATH11K_DBG_MAC, + "eirp power : %d firmware report power : %d\n", + eirp_power, ar->max_allowed_tx_power); + /* Firmware reports lower max_allowed_tx_power during vdev + * start response. In case of 6 GHz, firmware is not aware + * of EIRP power unless driver sets EIRP power through WMI + * TPC command. So radio which does not support idle power + * save can set maximum calculated EIRP power directly to + * firmware through TPC command without min comparison with + * vdev start response's max_allowed_tx_power. + */ + if (ar->max_allowed_tx_power && ab->hw_params.idle_ps) + eirp_power = min_t(s8, + eirp_power, + ar->max_allowed_tx_power); + } else { + /* If AP local power constraint is present */ + if (pwr_reduction) + max_tx_power[pwr_lvl_idx] = + max_tx_power[pwr_lvl_idx] - pwr_reduction; + /* If firmware updated max tx power is non zero, then take + * the min of firmware updated ap tx power + * and max power derived from above mentioned parameters. + */ + if (ar->max_allowed_tx_power && ab->hw_params.idle_ps) + max_tx_power[pwr_lvl_idx] = + min_t(s8, + max_tx_power[pwr_lvl_idx], + ar->max_allowed_tx_power); + } + reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq; + reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power = + max_tx_power[pwr_lvl_idx]; + } + + reg_tpc_info->num_pwr_levels = num_pwr_levels; + reg_tpc_info->is_psd_power = is_psd_power; + reg_tpc_info->eirp_power = eirp_power; + reg_tpc_info->ap_power_type = + ath11k_reg_ap_pwr_convert(vif->bss_conf.power_type); +} + static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx) diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 0dfdeed5177b..f5800fbecff8 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_MAC_H @@ -176,4 +176,7 @@ int ath11k_mac_wait_tx_complete(struct ath11k *ar); int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval); +void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx); #endif From f8a573bd5f3b1c272c431831add259deabfd9948 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 0083/2255] wifi: ath11k: add WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT service bit Firmware advertises support for SERVICE_EXT_TPC_REG via a WMI service bit. Add the definition of this service bit so that a subsequent patch can check whether or not firmware supports this service. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-11-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 7f6287f22cf5..9ed802194a5b 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2114,6 +2114,7 @@ enum wmi_tlv_service { /* The second 128 bits */ WMI_MAX_EXT_SERVICE = 256, WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL = 265, + WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280, WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281, WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326, WMI_TLV_SERVICE_SUPPORT_11D_FOR_HOST_SCAN = 357, From ed0a61dcb2d3936cf15dfc04341c4d0fc297919f Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:59 +0200 Subject: [PATCH 0084/2255] wifi: ath11k: add handler for WMI_VDEV_SET_TPC_POWER_CMDID Add the handler for WMI_VDEV_SET_TPC_POWER_CMDID, it is for 6 GHz band. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-12-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.c | 64 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 57 ++++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 3a3a2b697119..688ee20528a0 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2379,6 +2379,70 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, + u32 vdev_id, + struct ath11k_reg_tpc_power_info *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_vdev_set_tpc_power_cmd *cmd; + struct wmi_vdev_ch_power_info *ch; + struct sk_buff *skb; + struct wmi_tlv *tlv; + u8 *ptr; + int i, ret, len, array_len; + + array_len = sizeof(*ch) * param->num_pwr_levels; + len = sizeof(*cmd) + TLV_HDR_SIZE + array_len; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + ptr = skb->data; + + cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_SET_TPC_POWER_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->psd_power = param->is_psd_power; + cmd->eirp_power = param->eirp_power; + cmd->power_type_6ghz = param->ap_power_type; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "tpc vdev id %d is psd power %d eirp power %d 6 ghz power type %d\n", + vdev_id, param->is_psd_power, param->eirp_power, param->ap_power_type); + + ptr += sizeof(*cmd); + tlv = (struct wmi_tlv *)ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, array_len); + + ptr += TLV_HDR_SIZE; + ch = (struct wmi_vdev_ch_power_info *)ptr; + + for (i = 0; i < param->num_pwr_levels; i++, ch++) { + ch->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_VDEV_CH_POWER_INFO) | + FIELD_PREP(WMI_TLV_LEN, + sizeof(*ch) - TLV_HDR_SIZE); + + ch->chan_cfreq = param->chan_power_info[i].chan_cfreq; + ch->tx_power = param->chan_power_info[i].tx_power; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tpc chan freq %d TX power %d\n", + ch->chan_cfreq, ch->tx_power); + } + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_SET_TPC_POWER_CMDID); + if (ret) { + ath11k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n"); + dev_kfree_skb(skb); + return ret; + } + + return 0; +} + int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar, struct scan_cancel_param *param) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 9ed802194a5b..6dcd14700570 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -15,6 +15,7 @@ struct ath11k; struct ath11k_fw_stats; struct ath11k_fw_dbglog; struct ath11k_vif; +struct ath11k_reg_tpc_power_info; #define PSOC_HOST_MAX_NUM_SS (8) @@ -327,6 +328,22 @@ enum wmi_tlv_cmd_id { WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID, WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID, WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID, + WMI_VDEV_SET_ARP_STAT_CMDID, + WMI_VDEV_GET_ARP_STAT_CMDID, + WMI_VDEV_GET_TX_POWER_CMDID, + WMI_VDEV_LIMIT_OFFCHAN_CMDID, + WMI_VDEV_SET_CUSTOM_SW_RETRY_TH_CMDID, + WMI_VDEV_CHAINMASK_CONFIG_CMDID, + WMI_VDEV_GET_BCN_RECEPTION_STATS_CMDID, + WMI_VDEV_GET_MWS_COEX_INFO_CMDID, + WMI_VDEV_DELETE_ALL_PEER_CMDID, + WMI_VDEV_BSS_MAX_IDLE_TIME_CMDID, + WMI_VDEV_AUDIO_SYNC_TRIGGER_CMDID, + WMI_VDEV_AUDIO_SYNC_QTIMER_CMDID, + WMI_VDEV_SET_PCL_CMDID, + WMI_VDEV_GET_BIG_DATA_CMDID, + WMI_VDEV_GET_BIG_DATA_P2_CMDID, + WMI_VDEV_SET_TPC_POWER_CMDID, WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER), WMI_PEER_DELETE_CMDID, WMI_PEER_FLUSH_TIDS_CMDID, @@ -1880,6 +1897,8 @@ enum wmi_tlv_tag { WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD, WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9, WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT, + WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5, + WMI_TAG_VDEV_CH_POWER_INFO, WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8, WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD, WMI_TAG_MAX @@ -3169,6 +3188,41 @@ struct wlan_ssid { u8 ssid[WLAN_SSID_MAX_LEN]; }; +struct wmi_vdev_ch_power_info { + u32 tlv_header; + + /* Channel center frequency (MHz) */ + u32 chan_cfreq; + + /* Unit: dBm, either PSD/EIRP power for this frequency or + * incremental for non-PSD BW + */ + u32 tx_power; +} __packed; + +struct wmi_vdev_set_tpc_power_cmd { + u32 tlv_header; + u32 vdev_id; + + /* Value: 0 or 1, is PSD power or not */ + u32 psd_power; + + /* Maximum EIRP power (dBm units), valid only if power is PSD */ + u32 eirp_power; + + /* Type: WMI_6GHZ_REG_TYPE, used for halphy CTL lookup */ + u32 power_type_6ghz; + + /* This fixed_param TLV is followed by the below TLVs: + * num_pwr_levels of wmi_vdev_ch_power_info + * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks). + * For non-PSD power, the power values are for 20, 40, and till + * BSS BW power levels. + * The num_pwr_levels will be checked by sw how many elements present + * in the variable-length array. + */ +} __packed; + #define WMI_IE_BITMAP_SIZE 8 /* prefix used by scan requestor ids on the host */ @@ -6483,5 +6537,8 @@ int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar); int ath11k_wmi_sta_keepalive(struct ath11k *ar, const struct wmi_sta_keepalive_arg *arg); bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar); +int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, + u32 vdev_id, + struct ath11k_reg_tpc_power_info *param); #endif From 74ef2d05ede63fd6416aa635aa8972dff901325f Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:59 +0200 Subject: [PATCH 0085/2255] wifi: ath11k: use WMI_VDEV_SET_TPC_POWER_CMDID when EXT_TPC_REG_SUPPORT for 6 GHz When station is connected to a 6 GHz AP, it has 2 ways to configure the power limit to firmware. The first way is to send 2 WMI commands WMI_PDEV_PARAM_TXPOWER_LIMIT2G/WMI_PDEV_PARAM_TXPOWER_LIMIT5G to firmware, the second way is to send WMI_VDEV_SET_TPC_POWER_CMDID to firmware which include more parameters for power control. When firmware supports SERVICE_EXT_TPC_REG, it means firmware supports WMI_VDEV_SET_TPC_POWER_CMDID, then ath11k selects the second way. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-13-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f812a6f44b82..bf4a97967177 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3397,6 +3397,18 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar, return 0; } +static bool ath11k_mac_supports_station_tpc(struct ath11k *ar, + struct ath11k_vif *arvif, + const struct cfg80211_chan_def *chandef) +{ + return ath11k_wmi_supports_6ghz_cc_ext(ar) && + test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map) && + arvif->vdev_type == WMI_VDEV_TYPE_STA && + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE && + chandef->chan && + chandef->chan->band == NL80211_BAND_6GHZ; +} + static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -3596,7 +3608,6 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_TXPOWER) { ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev_id %i txpower %d\n", arvif->vdev_id, info->txpower); - arvif->txpower = info->txpower; ath11k_mac_txpower_recalc(ar); } @@ -7285,6 +7296,15 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, return ret; } + /* TODO: For now we only set TPC power here. However when + * channel changes, say CSA, it should be updated again. + */ + if (ath11k_mac_supports_station_tpc(ar, arvif, chandef)) { + ath11k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx); + ath11k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id, + &arvif->reg_tpc_info); + } + if (!restart) ar->num_started_vdevs++; @@ -8112,7 +8132,7 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, } ath11k_reg_handle_chan_list(ab, reg_info, power_type); - + arvif->chanctx = *ctx; ath11k_mac_parse_tx_pwr_env(ar, vif, ctx); } From 59cf57ab3deea979ffc0a6f7c22f4331e59d32f0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:30 -0800 Subject: [PATCH 0086/2255] wifi: ath12k: Remove unnecessary struct qmi_txn initializers Currently most of the ath12k QMI messaging functions define their struct qmi_txn variables with a {} initializer. However, all of these functions subsequently call qmi_txn_init(), and the very first thing that function does is zero the struct. Hence, the initializers are unnecessary. Since these consume code space and cpu cycles, remove them. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-qmi-cleanup-v2-1-53343af953d5@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 536856234f3b..180e86c2a10c 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1921,7 +1921,7 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) { struct qmi_wlanfw_host_cap_req_msg_v01 req; struct qmi_wlanfw_host_cap_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0; memset(&req, 0, sizeof(req)); @@ -2069,7 +2069,7 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) { struct qmi_wlanfw_respond_mem_req_msg_v01 *req; struct qmi_wlanfw_respond_mem_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0, i; bool delayed; @@ -2210,7 +2210,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) { struct qmi_wlanfw_cap_req_msg_v01 req; struct qmi_wlanfw_cap_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; unsigned int board_id = ATH12K_BOARD_ID_DEFAULT; int ret = 0; int r; @@ -2311,7 +2311,7 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab, { struct qmi_wlanfw_bdf_download_req_msg_v01 *req; struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; const u8 *temp = data; int ret; u32 remaining = len; @@ -2547,7 +2547,7 @@ static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; struct qmi_wlanfw_m3_info_req_msg_v01 req; struct qmi_wlanfw_m3_info_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0; memset(&req, 0, sizeof(req)); @@ -2598,7 +2598,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, { struct qmi_wlanfw_wlan_mode_req_msg_v01 req; struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0; memset(&req, 0, sizeof(req)); @@ -2651,7 +2651,7 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp; struct ce_pipe_config *ce_cfg; struct service_to_pipe *svc_cfg; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0, pipe_num; ce_cfg = (struct ce_pipe_config *)ab->qmi.ce_cfg.tgt_ce; From 2e82b5f09a97f1b98b885470c81c1248bec103af Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:31 -0800 Subject: [PATCH 0087/2255] wifi: ath12k: Add missing qmi_txn_cancel() calls Per the QMI documentation "A client calling qmi_txn_init() must call either qmi_txn_wait() or qmi_txn_cancel() to free up the allocated resources." Unfortunately, in most of the ath12k messaging functions, when qmi_send_request() fails, the function returns without performing the necessary cleanup. So update those functions to call qmi_txn_cancel() when qmi_send_request() fails. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-qmi-cleanup-v2-2-53343af953d5@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 180e86c2a10c..1f2df2e3fbce 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1977,6 +1977,7 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_host_cap_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "Failed to send host capability request,err = %d\n", ret); goto out; } @@ -2040,6 +2041,7 @@ static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab) QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_ind_register_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "Failed to send indication register request, err = %d\n", ret); goto out; @@ -2114,6 +2116,7 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_respond_mem_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to respond memory request, err = %d\n", ret); goto out; @@ -2229,6 +2232,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_cap_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send target cap request, err = %d\n", ret); goto out; @@ -2572,6 +2576,7 @@ static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN, qmi_wlanfw_m3_info_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send M3 information request, err = %d\n", ret); goto out; @@ -2618,6 +2623,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send mode request, mode: %d, err = %d\n", mode, ret); goto out; @@ -2709,6 +2715,7 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send wlan config request, err = %d\n", ret); goto out; From 6d2b0a066941c5d9c56c79d95c91dcec2fd7a7fa Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:32 -0800 Subject: [PATCH 0088/2255] wifi: ath12k: Use initializers for QMI message buffers Currently most of the QMI messaging functions use memset() to zero out the QMI message buffers. Prefer to use a {} initializer to allow the compiler to generate optimized code and avoid the function call overhead. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-qmi-cleanup-v2-3-53343af953d5@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 40 ++++++++------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 1f2df2e3fbce..c4c7f31a91cd 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1919,14 +1919,11 @@ static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *re static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) { - struct qmi_wlanfw_host_cap_req_msg_v01 req; - struct qmi_wlanfw_host_cap_resp_msg_v01 resp; + struct qmi_wlanfw_host_cap_req_msg_v01 req = {}; + struct qmi_wlanfw_host_cap_resp_msg_v01 resp = {}; struct qmi_txn txn; int ret = 0; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - req.num_clients_valid = 1; req.num_clients = 1; req.mem_cfg_mode = ab->qmi.target_mem_mode; @@ -2070,7 +2067,7 @@ 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)); From 1213acb478a7181cd73eeaf00db430f1e45b1361 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Thu, 11 Jan 2024 17:36:27 +0100 Subject: [PATCH 0089/2255] wifi: rtl8xxxu: add cancel_work_sync() for c2hcmd_work The workqueue might still be running, when the driver is stopped. To avoid a use-after-free, call cancel_work_sync() in rtl8xxxu_stop(). Fixes: e542e66b7c2e ("rtl8xxxu: add bluetooth co-existence support for single antenna") Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240111163628.320697-2-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index aac594093629..757ebd46452e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7480,6 +7480,7 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) if (priv->usb_interrupts) rtl8xxxu_write32(priv, REG_USB_HIMR, 0); + cancel_work_sync(&priv->c2hcmd_work); cancel_delayed_work_sync(&priv->ra_watchdog); rtl8xxxu_free_rx_resources(priv); From ece90a8622320bf5a24d3326da1f8e109891573c Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Thu, 11 Jan 2024 17:36:28 +0100 Subject: [PATCH 0090/2255] wifi: rtl8xxxu: enable channel switch support The CSA countdown in the beacon frames, which are sent out by firmware, needs to get updated by the driver. To achieve this, convert update_beacon_work to delayed_work and schedule it with the beacon interval in case CSA is active and the countdown is not complete. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240111163628.320697-3-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 +- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 803c76b3209c..03307da67c2c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1900,7 +1900,7 @@ struct rtl8xxxu_priv { struct delayed_work ra_watchdog; struct work_struct c2hcmd_work; struct sk_buff_head c2hcmd_queue; - struct work_struct update_beacon_work; + struct delayed_work update_beacon_work; struct rtl8xxxu_btcoex bt_coex; struct rtl8xxxu_ra_report ra_report; struct rtl8xxxu_cfo_tracking cfo_tracking; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 757ebd46452e..521faa48803c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4605,7 +4605,7 @@ static int rtl8xxxu_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, { struct rtl8xxxu_priv *priv = hw->priv; - schedule_work(&priv->update_beacon_work); + schedule_delayed_work(&priv->update_beacon_work, 0); return 0; } @@ -5107,7 +5107,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changed & BSS_CHANGED_BEACON) - schedule_work(&priv->update_beacon_work); + schedule_delayed_work(&priv->update_beacon_work, 0); error: return; @@ -5726,7 +5726,7 @@ static void rtl8xxxu_send_beacon_frame(struct ieee80211_hw *hw, static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) { struct rtl8xxxu_priv *priv = - container_of(work, struct rtl8xxxu_priv, update_beacon_work); + container_of(work, struct rtl8xxxu_priv, update_beacon_work.work); struct ieee80211_hw *hw = priv->hw; struct ieee80211_vif *vif = priv->vifs[0]; @@ -5735,6 +5735,14 @@ static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) return; } + if (vif->bss_conf.csa_active) { + if (ieee80211_beacon_cntdwn_is_complete(vif)) { + ieee80211_csa_finish(vif); + return; + } + schedule_delayed_work(&priv->update_beacon_work, + msecs_to_jiffies(vif->bss_conf.beacon_int)); + } rtl8xxxu_send_beacon_frame(hw, vif); } @@ -7482,6 +7490,7 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) cancel_work_sync(&priv->c2hcmd_work); cancel_delayed_work_sync(&priv->ra_watchdog); + cancel_delayed_work_sync(&priv->update_beacon_work); rtl8xxxu_free_rx_resources(priv); rtl8xxxu_free_tx_resources(priv); @@ -7764,7 +7773,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, spin_lock_init(&priv->rx_urb_lock); INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback); - INIT_WORK(&priv->update_beacon_work, rtl8xxxu_update_beacon_work_callback); + INIT_DELAYED_WORK(&priv->update_beacon_work, rtl8xxxu_update_beacon_work_callback); skb_queue_head_init(&priv->c2hcmd_queue); usb_set_intfdata(interface, hw); @@ -7825,6 +7834,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); hw->queues = 4; + hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + if (priv->fops->supports_concurrent) { hw->wiphy->iface_combinations = rtl8xxxu_combinations; hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtl8xxxu_combinations); From eaf9f17b861b665a0bc8dff120ae3c9028642e6d Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:38 +0200 Subject: [PATCH 0091/2255] wifi: ath12k: relocate ath12k_dp_pdev_pre_alloc() call Currently, the data path pdev pre alloc and mac allocate are called separately from the core start procedure. The data path pdev pre alloc can be called from the mac allocate procedure itself since initialization related to pdev happens in the mac allocate procedure. So move the caller of DP pdev pre alloc from the core start procedure to the mac allocate procedure. This change helps in the future to easily decouple the mac allocate procedure from core start handling in order to support MLO in multi chip. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 2 -- drivers/net/wireless/ath/ath12k/mac.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index d73e2d33a41e..ababe7f01b5b 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -714,8 +714,6 @@ static int ath12k_core_start(struct ath12k_base *ab, ath12k_dp_cc_config(ab); - ath12k_dp_pdev_pre_alloc(ab); - ret = ath12k_dp_rx_pdev_reo_setup(ab); if (ret) { ath12k_err(ab, "failed to initialize reo destination rings: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 88cec54c6c2e..49d56f5d8896 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7667,6 +7667,8 @@ int ath12k_mac_allocate(struct ath12k_base *ab) clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); } + ath12k_dp_pdev_pre_alloc(ab); + return 0; err_free_mac: From 8a742a79f90e3d3f0378b030110eccac8d28b655 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:38 +0200 Subject: [PATCH 0092/2255] wifi: ath12k: refactor ath12k_mac_allocate() and ath12k_mac_destroy() Currently, the MAC allocation and destroy helper functions are tightly coupled with the link/radio (ar) structure. In the future, to support single/Multi link operations, need to refactor these helper functions across the core and mac sub modules, so that it can be easy to scale these functions to support single/Multi link operations. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 150 +++++++++++++++----------- 1 file changed, 88 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 49d56f5d8896..09a1a2edf842 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7607,77 +7607,47 @@ err_cleanup: return ret; } -int ath12k_mac_allocate(struct ath12k_base *ab) +static void ath12k_mac_setup(struct ath12k *ar) { - struct ieee80211_hw *hw; - struct ath12k *ar; - struct ath12k_pdev *pdev; - int ret; - int i; + struct ath12k_base *ab = ar->ab; + struct ath12k_pdev *pdev = ar->pdev; + u8 pdev_idx = ar->pdev_idx; - if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) - return 0; + ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, pdev_idx); - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); - if (!hw) { - ath12k_warn(ab, "failed to allocate mac80211 hw device\n"); - ret = -ENOMEM; - goto err_free_mac; - } + ar->wmi = &ab->wmi_ab.wmi[pdev_idx]; + /* FIXME: wmi[0] is already initialized during attach, + * Should we do this again? + */ + ath12k_wmi_pdev_attach(ab, pdev_idx); - ar = hw->priv; - ar->hw = hw; - ar->ab = ab; - ar->pdev = pdev; - ar->pdev_idx = i; - ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, i); + ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask; + ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; + ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); + ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); - ar->wmi = &ab->wmi_ab.wmi[i]; - /* FIXME: wmi[0] is already initialized during attach, - * Should we do this again? - */ - ath12k_wmi_pdev_attach(ab, i); + spin_lock_init(&ar->data_lock); + INIT_LIST_HEAD(&ar->arvifs); + INIT_LIST_HEAD(&ar->ppdu_stats_info); + mutex_init(&ar->conf_mutex); + init_completion(&ar->vdev_setup_done); + init_completion(&ar->vdev_delete_done); + init_completion(&ar->peer_assoc_done); + init_completion(&ar->peer_delete_done); + init_completion(&ar->install_key_done); + init_completion(&ar->bss_survey_done); + init_completion(&ar->scan.started); + init_completion(&ar->scan.completed); - ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask; - ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; - ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); - ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); + INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); + INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); - pdev->ar = ar; - spin_lock_init(&ar->data_lock); - INIT_LIST_HEAD(&ar->arvifs); - INIT_LIST_HEAD(&ar->ppdu_stats_info); - mutex_init(&ar->conf_mutex); - init_completion(&ar->vdev_setup_done); - init_completion(&ar->vdev_delete_done); - init_completion(&ar->peer_assoc_done); - init_completion(&ar->peer_delete_done); - init_completion(&ar->install_key_done); - init_completion(&ar->bss_survey_done); - init_completion(&ar->scan.started); - init_completion(&ar->scan.completed); - - INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); - INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); - - INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); - skb_queue_head_init(&ar->wmi_mgmt_tx_queue); - clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); - } - - ath12k_dp_pdev_pre_alloc(ab); - - return 0; - -err_free_mac: - ath12k_mac_destroy(ab); - - return ret; + INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); } -void ath12k_mac_destroy(struct ath12k_base *ab) +static void ath12k_mac_hw_destroy(struct ath12k_base *ab) { struct ath12k *ar; struct ath12k_pdev *pdev; @@ -7693,3 +7663,59 @@ void ath12k_mac_destroy(struct ath12k_base *ab) pdev->ar = NULL; } } + +static int ath12k_mac_hw_allocate(struct ath12k_base *ab) +{ + struct ieee80211_hw *hw; + struct ath12k *ar; + struct ath12k_pdev *pdev; + int ret; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); + if (!hw) { + ath12k_warn(ab, "failed to allocate mac80211 hw device\n"); + ret = -ENOMEM; + goto err_free_mac; + } + + ar = hw->priv; + ar->hw = hw; + ar->ab = ab; + ar->pdev = pdev; + ar->pdev_idx = i; + pdev->ar = ar; + + ath12k_mac_setup(ar); + } + + return 0; + +err_free_mac: + ath12k_mac_hw_destroy(ab); + + return ret; +} + +void ath12k_mac_destroy(struct ath12k_base *ab) +{ + ath12k_mac_hw_destroy(ab); +} + +int ath12k_mac_allocate(struct ath12k_base *ab) +{ + int ret; + + if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + + ret = ath12k_mac_hw_allocate(ab); + if (ret) + return ret; + + ath12k_dp_pdev_pre_alloc(ab); + + return 0; +} From d2b7a6e5fa1c92deabe77aa57ef16f599f3b4247 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:39 +0200 Subject: [PATCH 0093/2255] wifi: ath12k: refactor ath12k_mac_setup_channels_rates() Currently, the MAC setup helper function is accessing the mac80211 hw data. In the future, to support single/multi link operation, need to decouple the mac80211 hw data from this helper function so that it can be easy to scale these functions to support single/multi link operations. So remove the mac80211 hw access from the ath12k_mac_setup_channels_rates() helper function. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 09a1a2edf842..33e03208479d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7158,9 +7158,9 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) } static int ath12k_mac_setup_channels_rates(struct ath12k *ar, - u32 supported_bands) + u32 supported_bands, + struct ieee80211_supported_band *bands[]) { - struct ieee80211_hw *hw = ar->hw; struct ieee80211_supported_band *band; struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap; void *channels; @@ -7186,7 +7186,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_g_rates_size; band->bitrates = ath12k_g_rates; - hw->wiphy->bands[NL80211_BAND_2GHZ] = band; + bands[NL80211_BAND_2GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); @@ -7213,7 +7213,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - hw->wiphy->bands[NL80211_BAND_6GHZ] = band; + bands[NL80211_BAND_6GHZ] = band; ath12k_mac_update_ch_list(ar, band, reg_cap->low_5ghz_chan, reg_cap->high_5ghz_chan); @@ -7235,7 +7235,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + bands[NL80211_BAND_5GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); @@ -7414,7 +7414,8 @@ static int __ath12k_mac_register(struct ath12k *ar) SET_IEEE80211_DEV(hw, ab->dev); ret = ath12k_mac_setup_channels_rates(ar, - cap->supported_bands); + cap->supported_bands, + hw->wiphy->bands); if (ret) goto err; From d786c9f5fe3472ac102160c113a7bba8ec79a6c6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:39 +0200 Subject: [PATCH 0094/2255] wifi: ath12k: refactor ath12k_mac_register() and ath12k_mac_unregister() Currently, the mac80211 hw registration procedure is tightly coupled with the handling of link/radio (ar). Define a new helper function to separate the link/radio handling from the mac80211 hw registration procedure for improved code readability. Also, it can be easy to scale these functionality to support single/multi link operation in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-5-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 183 ++++++++++++++------------ 1 file changed, 102 insertions(+), 81 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 33e03208479d..4fc338bace8d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7349,7 +7349,17 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { }, }; -static void __ath12k_mac_unregister(struct ath12k *ar) +static void ath12k_mac_cleanup_unregister(struct ath12k *ar) +{ + idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); + idr_destroy(&ar->txmgmt_idr); + + kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); + kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); + kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); +} + +static void ath12k_mac_hw_unregister(struct ath12k *ar) { struct ieee80211_hw *hw = ar->hw; struct wiphy *wiphy = hw->wiphy; @@ -7358,12 +7368,7 @@ static void __ath12k_mac_unregister(struct ath12k *ar) ieee80211_unregister_hw(hw); - idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); - idr_destroy(&ar->txmgmt_idr); - - kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); + ath12k_mac_cleanup_unregister(ar); kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); @@ -7371,28 +7376,41 @@ static void __ath12k_mac_unregister(struct ath12k *ar) SET_IEEE80211_DEV(hw, NULL); } -void ath12k_mac_unregister(struct ath12k_base *ab) +static int ath12k_mac_setup_register(struct ath12k *ar, + u32 *ht_cap, + struct ieee80211_supported_band *bands[]) { - struct ath12k *ar; - struct ath12k_pdev *pdev; - int i; + struct ath12k_pdev_cap *cap = &ar->pdev->cap; + int ret; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar) - continue; + init_waitqueue_head(&ar->txmgmt_empty_waitq); + idr_init(&ar->txmgmt_idr); + spin_lock_init(&ar->txmgmt_idr_lock); - __ath12k_mac_unregister(ar); - } + ath12k_pdev_caps_update(ar); + + ret = ath12k_mac_setup_channels_rates(ar, + cap->supported_bands, + bands); + if (ret) + return ret; + + ath12k_mac_setup_ht_vht_cap(ar, cap, ht_cap); + ath12k_mac_setup_sband_iftype_data(ar, cap); + + ar->max_num_stations = TARGET_NUM_STATIONS; + ar->max_num_peers = TARGET_NUM_PEERS_PDEV; + + return 0; } -static int __ath12k_mac_register(struct ath12k *ar) +static int ath12k_mac_hw_register(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ar->hw; struct wiphy *wiphy = hw->wiphy; - struct ath12k_pdev_cap *cap = &ar->pdev->cap; + struct ath12k_pdev *pdev = ar->pdev; + struct ath12k_pdev_cap *cap = &pdev->cap; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, @@ -7407,25 +7425,24 @@ static int __ath12k_mac_register(struct ath12k *ar) int ret; u32 ht_cap = 0; - ath12k_pdev_caps_update(ar); + if (ab->pdevs_macaddr_valid) { + ether_addr_copy(ar->mac_addr, pdev->mac_addr); + } else { + ether_addr_copy(ar->mac_addr, ab->mac_addr); + ar->mac_addr[4] += ar->pdev_idx; + } + + ret = ath12k_mac_setup_register(ar, &ht_cap, hw->wiphy->bands); + if (ret) + goto out; SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); - SET_IEEE80211_DEV(hw, ab->dev); - ret = ath12k_mac_setup_channels_rates(ar, - cap->supported_bands, - hw->wiphy->bands); - if (ret) - goto err; - - ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); - ath12k_mac_setup_sband_iftype_data(ar, cap); - ret = ath12k_mac_setup_iface_combinations(ar); if (ret) { ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret); - goto err_free_channels; + goto err_setup_unregister; } wiphy->available_antennas_rx = cap->rx_chain_mask; @@ -7484,9 +7501,6 @@ static int __ath12k_mac_register(struct ath12k *ar) wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; - ar->max_num_stations = TARGET_NUM_STATIONS; - ar->max_num_peers = TARGET_NUM_PEERS_PDEV; - wiphy->max_ap_assoc_sta = ar->max_num_stations; hw->queues = ATH12K_HW_MAX_QUEUES; @@ -7553,58 +7567,14 @@ 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; From 3e141f0034d573f133fc3e73508949ba64461a4a Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 0095/2255] wifi: ath12k: refactor ath12k_mac_op_config() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback config(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4fc338bace8d..06ecbb382b63 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1083,9 +1083,9 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) return ret; } -static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) +static int ath12k_mac_config(struct ath12k *ar, u32 changed) { - struct ath12k *ar = hw->priv; + struct ieee80211_hw *hw = ar->hw; struct ieee80211_conf *conf = &hw->conf; int ret = 0; @@ -1122,6 +1122,19 @@ 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; From ce20a10fdff41afbbc119e91cf3e2378d81e2eb0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 0096/2255] wifi: ath12k: refactor ath12k_bss_assoc() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback bss_info_change(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 43 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 06ecbb382b63..58bd850bb86e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2279,12 +2279,11 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, ath12k_smps_map[smps]); } -static void ath12k_bss_assoc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, +static void ath12k_bss_assoc(struct ath12k *ar, + struct ath12k_vif *arvif, struct ieee80211_bss_conf *bss_conf) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = arvif->vif; struct ath12k_wmi_peer_assoc_arg peer_arg; struct ieee80211_sta *ap_sta; struct ath12k_peer *peer; @@ -2374,11 +2373,9 @@ static void ath12k_bss_assoc(struct ieee80211_hw *hw, arvif->vdev_id, ret); } -static void ath12k_bss_disassoc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void ath12k_bss_disassoc(struct ath12k *ar, + struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2504,13 +2501,12 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, return ret; } -static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u64 changed) +static void ath12k_mac_bss_info_changed(struct ath12k *ar, + struct ath12k_vif *arvif, + struct ieee80211_bss_conf *info, + u64 changed) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = arvif->vif; struct cfg80211_chan_def def; u32 param_id, param_value; enum nl80211_band band; @@ -2523,7 +2519,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, u8 rateidx; u32 rate; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); if (changed & BSS_CHANGED_BEACON_INT) { arvif->beacon_interval = info->beacon_int; @@ -2679,9 +2675,9 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (vif->cfg.assoc) - ath12k_bss_assoc(hw, vif, info); + ath12k_bss_assoc(ar, arvif, info); else - ath12k_bss_disassoc(hw, vif); + ath12k_bss_disassoc(ar, arvif); } if (changed & BSS_CHANGED_TXPOWER) { @@ -2783,6 +2779,19 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_EHT_PUNCTURING) arvif->punct_bitmap = info->eht_puncturing; +} + +static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u64 changed) +{ + struct ath12k *ar = hw->priv; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + mutex_lock(&ar->conf_mutex); + + ath12k_mac_bss_info_changed(ar, arvif, info, changed); mutex_unlock(&ar->conf_mutex); } From 00c9b1a6d21d03b8fb74f1029c370dccce294dd5 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 0097/2255] wifi: ath12k: refactor ath12k_mac_op_conf_tx() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback conf_tx(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 41 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 58bd850bb86e..37ae22d27ccb 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3986,10 +3986,10 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, ieee80211_queue_work(hw, &arsta->update_wk); } -static int ath12k_conf_tx_uapsd(struct ath12k *ar, struct ieee80211_vif *vif, +static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, u16 ac, bool enable) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar = arvif->ar; u32 value; int ret; @@ -4043,17 +4043,16 @@ 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; } From e1e275a699061fba965b5653a8f03d550bb5fe6e Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 0098/2255] wifi: ath12k: refactor ath12k_mac_op_start() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback start(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-5-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 31 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 37ae22d27ccb..d48161b43a4a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5081,14 +5081,12 @@ static void ath12k_mac_wait_reconfigure(struct ath12k_base *ab) ATH12K_RECONFIGURE_TIMEOUT_HZ); } -static int ath12k_mac_op_start(struct ieee80211_hw *hw) +static int ath12k_mac_start(struct ath12k *ar) { - struct ath12k *ar = hw->priv; struct ath12k_base *ab = ar->ab; struct ath12k_pdev *pdev = ar->pdev; int ret; - ath12k_mac_drain_tx(ar); mutex_lock(&ar->conf_mutex); switch (ar->state) { @@ -5111,14 +5109,14 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret); + ath12k_err(ab, "failed to enable PMF QOS: (%d\n", ret); goto err; } ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret); + ath12k_err(ab, "failed to enable dynamic bw: %d\n", ret); goto err; } @@ -5148,7 +5146,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret); + ath12k_err(ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret); goto err; } @@ -5174,7 +5172,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) } if (ret == -ENOTSUPP) - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + ath12k_dbg(ab, ATH12K_DBG_MAC, "monitor status config is not yet supported"); /* Configure the hash seed for hash based reo dest ring selection */ @@ -5196,7 +5194,6 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) &ab->pdevs[ar->pdev_idx]); return 0; - err: ar->state = ATH12K_STATE_OFF; mutex_unlock(&ar->conf_mutex); @@ -5204,6 +5201,24 @@ 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; From 3bbc9c7429ff9e9c79c36add3742f7292d135b98 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 0099/2255] wifi: ath12k: refactor ath12k_mac_op_stop() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback stop(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-6-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d48161b43a4a..b6ee5527f350 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5276,14 +5276,11 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable) return 0; } -static void ath12k_mac_op_stop(struct ieee80211_hw *hw) +static void ath12k_mac_stop(struct ath12k *ar) { - struct ath12k *ar = hw->priv; struct htt_ppdu_stats_info *ppdu_stats, *tmp; int ret; - ath12k_mac_drain_tx(ar); - mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); if (ret && (ret != -ENOTSUPP)) @@ -5312,6 +5309,15 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw) atomic_set(&ar->num_pending_mgmt_tx, 0); } +static void ath12k_mac_op_stop(struct ieee80211_hw *hw) +{ + struct ath12k *ar = hw->priv; + + ath12k_mac_drain_tx(ar); + + ath12k_mac_stop(ar); +} + static u8 ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) { From 92b30bb397869f94724b59d85f16e8de00fa9bc4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 0100/2255] wifi: ath12k: refactor ath12k_mac_op_update_vif_offload() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback update_vif_offload(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-7-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b6ee5527f350..bc6746abebf0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5434,12 +5434,11 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, return ret; } -static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; + struct ieee80211_vif *vif = arvif->vif; + struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); u32 param_id, param_value; int ret; @@ -5481,6 +5480,14 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, } } +static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + ath12k_mac_update_vif_offload(arvif); +} + static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -5584,7 +5591,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, list_add(&arvif->list, &ar->arvifs); spin_unlock_bh(&ar->data_lock); - ath12k_mac_op_update_vif_offload(hw, vif); + ath12k_mac_update_vif_offload(arvif); nss = hweight32(ar->cfg_tx_chainmask) ? : 1; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, From d629b0c149c913d633ada52357069b8ac7fc81c6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 0101/2255] wifi: ath12k: refactor ath12k_mac_op_configure_filter() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback configure_filter(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-8-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 28 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index bc6746abebf0..ef9e3558f5eb 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5831,19 +5831,15 @@ 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); } From 5b1b5dbfd6a6590606d7dbb99b0708be100a4acb Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 0102/2255] wifi: ath12k: refactor ath12k_mac_op_ampdu_action() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback ampdu_action(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-9-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ef9e3558f5eb..895bf9d19457 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5901,14 +5901,13 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx return ret; } -static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) +static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif, + struct ieee80211_ampdu_params *params) { - struct ath12k *ar = hw->priv; + struct ath12k *ar = arvif->ar; int ret = -EINVAL; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); switch (params->action) { case IEEE80211_AMPDU_RX_START: @@ -5929,8 +5928,25 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, break; } + return ret; +} + +static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + struct ath12k *ar = hw->priv; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + int ret = -EINVAL; + + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_ampdu_action(arvif, params); mutex_unlock(&ar->conf_mutex); + if (ret) + ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n", + ar->pdev_idx, params->action, ret); + return ret; } From b33dcbe8d53d1e57cfc9bc035f43a27af5b6a973 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 0103/2255] wifi: ath12k: refactor ath12k_mac_op_flush() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback flush(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-10-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 895bf9d19457..ce916bf2dcc9 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6644,15 +6644,10 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) return -EOPNOTSUPP; } -static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) +static void ath12k_mac_flush(struct ath12k *ar) { - struct ath12k *ar = hw->priv; long time_left; - if (drop) - return; - time_left = wait_event_timeout(ar->dp.tx_empty_waitq, (atomic_read(&ar->dp.num_tx_pending) == 0), ATH12K_FLUSH_TIMEOUT); @@ -6667,6 +6662,17 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v time_left); } +static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct ath12k *ar = hw->priv; + + if (drop) + return; + + ath12k_mac_flush(ar); +} + static int ath12k_mac_bitrate_mask_num_ht_rates(struct ath12k *ar, enum nl80211_band band, From 5bdfb8c9db223009d15a2379b87d16cc800d439a Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 0104/2255] wifi: ath12k: ath12k_start_vdev_delay(): convert to use ar To support single wiphy abstraction, remove the mac80211 hw data dependency from the start vdev delay function. This way, this function can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-11-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ce916bf2dcc9..a90c0309230a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -241,8 +241,8 @@ static const u32 ath12k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; -static int ath12k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); +static int ath12k_start_vdev_delay(struct ath12k *ar, + struct ath12k_vif *arvif); static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) { @@ -3718,7 +3718,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, if (ab->hw_params->vdev_start_delay && !arvif->is_started && arvif->vdev_type != WMI_VDEV_TYPE_AP) { - ret = ath12k_start_vdev_delay(ar->hw, vif); + ret = ath12k_start_vdev_delay(ar, arvif); if (ret) { ath12k_warn(ab, "failed to delay vdev start: %d\n", ret); goto free_peer; @@ -6411,12 +6411,11 @@ 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)) From 9666ad011992b51da2a4623d20084a363a3a095e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 14 Jan 2024 17:02:42 +0200 Subject: [PATCH 0105/2255] wifi: ath11k: document HAL_RX_BUF_RBM_SW4_BM Commit 7636c9a6e7d7 ("wifi: ath11k: Add multi TX ring support for WCN6750") added HAL_RX_BUF_RBM_SW4_BM to enum hal_rx_buf_return_buf_manager. However, as flagged by the kernel-doc script, the documentation was not updated: drivers/net/wireless/ath/ath11k/hal.h:689: warning: Enum value 'HAL_RX_BUF_RBM_SW4_BM' not described in enum 'hal_rx_buf_return_buf_manager' So update the documentation. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-document-hal_rx_buf_rbm_sw4_bm-v1-1-ad277e8ab3cc@quicinc.com --- drivers/net/wireless/ath/ath11k/hal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 80447f488954..65e8f244ebb9 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HAL_H @@ -674,6 +674,7 @@ struct hal_srng_config { * @HAL_RX_BUF_RBM_SW1_BM: For Tx completion -- returned to host * @HAL_RX_BUF_RBM_SW2_BM: For Tx completion -- returned to host * @HAL_RX_BUF_RBM_SW3_BM: For Rx release -- returned to host + * @HAL_RX_BUF_RBM_SW4_BM: For Tx completion -- returned to host */ enum hal_rx_buf_return_buf_manager { From 76fece36f17a535c75ebc83d026bacad1263fd37 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 16 Jan 2024 14:33:07 +0200 Subject: [PATCH 0106/2255] wifi: ath12k: refactor QMI MLO host capability helper function Currently, QMI MLO host capability parameters are specific to the WCN7850 platform. To make use of this helper function across all the platforms, move the platform specific MLO capability parameter to the HW param configuration. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240113001659.1022465-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 9 +++++++ drivers/net/wireless/ath/ath12k/hw.h | 3 +++ drivers/net/wireless/ath/ath12k/qmi.c | 34 +++++++++++++++++++-------- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index de60d988d860..cbb6e2b6d826 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -914,6 +914,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 0, .rddm_size = 0, + + .def_num_link = 0, + .max_mlo_peer = 256, }, { .name = "wcn7850 hw2.0", @@ -978,6 +981,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 1, .rddm_size = 0x780000, + + .def_num_link = 2, + .max_mlo_peer = 32, }, { .name = "qcn9274 hw2.0", @@ -1040,6 +1046,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 0, .rddm_size = 0, + + .def_num_link = 0, + .max_mlo_peer = 256, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index fa8230def22b..0c3b416ae150 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -192,6 +192,9 @@ struct ath12k_hw_params { u32 rfkill_on_level; u32 rddm_size; + + u8 def_num_link; + u16 max_mlo_peer; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index c4c7f31a91cd..916dec626702 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1893,8 +1893,16 @@ static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { }, }; -static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *req) +static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, + struct qmi_wlanfw_host_cap_req_msg_v01 *req) { + struct wlfw_host_mlo_chip_info_s_v01 *info; + u8 hw_link_id = 0; + int i; + + if (!ab->hw_params->def_num_link) + return; + req->mlo_capable_valid = 1; req->mlo_capable = 1; req->mlo_chip_id_valid = 1; @@ -1905,16 +1913,22 @@ static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *re /* Max peer number generally won't change for the same device * but needs to be synced with host driver. */ - req->max_mlo_peer = 32; + req->max_mlo_peer = ab->hw_params->max_mlo_peer; req->mlo_num_chips_valid = 1; req->mlo_num_chips = 1; + + info = &req->mlo_chip_info[0]; + info->chip_id = 0; + info->num_local_links = ab->hw_params->def_num_link; + + for (i = 0; i < info->num_local_links; i++) { + info->hw_link_id[i] = hw_link_id; + info->valid_mlo_link_id[i] = 1; + + hw_link_id++; + } + req->mlo_chip_info_valid = 1; - req->mlo_chip_info[0].chip_id = 0; - req->mlo_chip_info[0].num_local_links = 2; - req->mlo_chip_info[0].hw_link_id[0] = 0; - req->mlo_chip_info[0].hw_link_id[1] = 1; - req->mlo_chip_info[0].valid_mlo_link_id[0] = 1; - req->mlo_chip_info[0].valid_mlo_link_id[1] = 1; } static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) @@ -1960,10 +1974,10 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) */ req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT; req.nm_modem |= PLATFORM_CAP_PCIE_GLOBAL_RESET; - - ath12k_host_cap_parse_mlo(&req); } + ath12k_host_cap_parse_mlo(ab, &req); + ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp); if (ret < 0) From 53a65445c144f99a6769788d0c04b64cdbb497d4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 16 Jan 2024 14:33:07 +0200 Subject: [PATCH 0107/2255] wifi: ath12k: add QMI PHY capability learn support Currently, the number of PHY is learned from the firmware service ready event message. However, on the QCN9274 platform, number of PHY is a variable parameter. To enable MLO capability in the QMI host capability request message, the driver needs the PHY count information earlier than the firmware service ready event. Therefore, a new QMI message, "PHY capability message", is introduced to retrieve this information. This message allows the driver to fill in the MLO parameter in the QMI host capability request message. If the new QMI PHY capability message fails, the default configuration in the HW params will be used. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240113001659.1022465-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/qmi.c | 124 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/qmi.h | 17 ++++ 3 files changed, 140 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index ababe7f01b5b..6cab747ff858 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1174,6 +1174,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, ab->dev = dev; ab->hif.bus = bus; + ab->qmi.num_radios = U8_MAX; return ab; diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 916dec626702..d20d08023c81 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -528,6 +528,67 @@ static const struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { }, }; +static const struct qmi_elem_info qmi_wlanfw_phy_cap_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_phy_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + num_phy_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + num_phy), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + board_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + board_id), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + static const struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, @@ -1900,8 +1961,12 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, u8 hw_link_id = 0; int i; - if (!ab->hw_params->def_num_link) + if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) { + ath12k_dbg(ab, ATH12K_DBG_QMI, + "skip QMI MLO cap due to invalid num_radio %d\n", + ab->qmi.num_radios); return; + } req->mlo_capable_valid = 1; req->mlo_capable = 1; @@ -1919,7 +1984,7 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, info = &req->mlo_chip_info[0]; info->chip_id = 0; - info->num_local_links = ab->hw_params->def_num_link; + info->num_local_links = ab->qmi.num_radios; for (i = 0; i < info->num_local_links; i++) { info->hw_link_id[i] = hw_link_id; @@ -2008,6 +2073,59 @@ 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 From 49b88e5f3fa114ed187f876082aa5bc4349f5bc7 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:29 +0530 Subject: [PATCH 0108/2255] wifi: ath12k: replace ENOTSUPP with EOPNOTSUPP ENOTSUPP is not a standard error code, don't use it. Replace with EOPNOTSUPP instead. No functional changes, compile tested only. Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117080431.2907471-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_tx.c | 6 +++--- drivers/net/wireless/ath/ath12k/hal_rx.c | 4 ++-- drivers/net/wireless/ath/ath12k/mac.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 62f9cdbb811c..05d5f14cdfa1 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -151,7 +151,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && !ieee80211_is_data(hdr->frame_control)) - return -ENOTSUPP; + return -EOPNOTSUPP; pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1); @@ -837,7 +837,7 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) { ath12k_err(ab, "unsupported htt major version %d supported version is %d\n", dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR); - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 4f25eb9f7745..4fc08d4f85b5 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" @@ -247,7 +247,7 @@ int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng, case HAL_REO_CMD_UNBLOCK_CACHE: case HAL_REO_CMD_FLUSH_TIMEOUT_LIST: ath12k_warn(ab, "Unsupported reo command %d\n", type); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; break; default: ath12k_warn(ab, "Unknown reo command %d\n", type); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a90c0309230a..d453e4165228 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5055,7 +5055,7 @@ void ath12k_mac_drain_tx(struct ath12k *ar) static int ath12k_mac_config_mon_status_default(struct ath12k *ar, bool enable) { - return -ENOTSUPP; + return -EOPNOTSUPP; /* TODO: Need to support new monitor mode */ } @@ -5165,13 +5165,13 @@ static int ath12k_mac_start(struct ath12k *ar) * such as rssi, rx_duration. */ ret = ath12k_mac_config_mon_status_default(ar, true); - if (ret && (ret != -ENOTSUPP)) { + if (ret && (ret != -EOPNOTSUPP)) { ath12k_err(ab, "failed to configure monitor status ring with default rx_filter: (%d)\n", ret); goto err; } - if (ret == -ENOTSUPP) + if (ret == -EOPNOTSUPP) ath12k_dbg(ab, ATH12K_DBG_MAC, "monitor status config is not yet supported"); @@ -5283,7 +5283,7 @@ static void ath12k_mac_stop(struct ath12k *ar) mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); - if (ret && (ret != -ENOTSUPP)) + if (ret && (ret != -EOPNOTSUPP)) ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n", ret); From 3422402bacd0322875be2e2a97a98e67d30c1b14 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:30 +0530 Subject: [PATCH 0109/2255] wifi: ath11k: replace ENOTSUPP with EOPNOTSUPP ENOTSUPP is not a standard error code, don't use it. Replace with EOPNOTSUPP instead. No functional changes, compile tested only. Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117080431.2907471-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath11k/dp_tx.c | 6 +++--- drivers/net/wireless/ath/ath11k/hal_rx.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index c1072e66e3e8..272b1c35f98d 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -103,7 +103,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && !ieee80211_is_data(hdr->frame_control))) - return -ENOTSUPP; + return -EOPNOTSUPP; pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); @@ -1018,7 +1018,7 @@ int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab) if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) { ath11k_err(ab, "unsupported htt major version %d supported version is %d\n", dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR); - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index e758ee8e17c9..8f7dd43dc1bd 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" @@ -246,7 +246,7 @@ int ath11k_hal_reo_cmd_send(struct ath11k_base *ab, struct hal_srng *srng, case HAL_REO_CMD_UNBLOCK_CACHE: case HAL_REO_CMD_FLUSH_TIMEOUT_LIST: ath11k_warn(ab, "Unsupported reo command %d\n", type); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; break; default: ath11k_warn(ab, "Unknown reo command %d\n", type); From bc2ef64931c263104532723e9d8d923cfb357ab6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:31 +0530 Subject: [PATCH 0110/2255] wifi: ath10k: replace ENOTSUPP with EOPNOTSUPP ENOTSUPP is not a standard error code, don't use it. Replace with EOPNOTSUPP instead. No functional changes, compile tested only. Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117080431.2907471-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath10k/core.c | 4 ++-- drivers/net/wireless/ath/ath10k/htt.c | 3 ++- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- drivers/net/wireless/ath/ath10k/pci.c | 10 +++++----- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 7 ++++--- drivers/net/wireless/ath/ath10k/wmi.c | 12 ++++++------ 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 0032f8aa892f..9ce6f49ab261 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -3613,7 +3613,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, default: ath10k_err(ar, "unsupported core hardware revision %d\n", hw_rev); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; goto err_free_mac; } diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 907e1e13871a..dbaf262cd7c1 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -381,7 +382,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt) htt->target_version_major != 3) { ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n", htt->target_version_major); - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 090bcf148d0c..fc503db2fd8e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "mac.h" @@ -4056,7 +4056,7 @@ static int ath10k_mac_tx(struct ath10k *ar, !(skb_cb->flags & ATH10K_SKB_F_RAW_TX)) { WARN_ON_ONCE(1); ieee80211_free_txskb(hw, skb); - return -ENOTSUPP; + return -EOPNOTSUPP; } } @@ -7065,7 +7065,7 @@ static int ath10k_mac_set_tid_config(struct ath10k *ar, struct ieee80211_sta *st if (sta) { if (!sta->wme) - return -ENOTSUPP; + return -EOPNOTSUPP; arsta = (struct ath10k_sta *)sta->drv_priv; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 3de2de6d44bc..5c34b156b4ff 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -889,7 +889,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (WARN_ON_ONCE(!ar_pci->targ_cpu_to_ce_addr)) - return -ENOTSUPP; + return -EOPNOTSUPP; return ar_pci->targ_cpu_to_ce_addr(ar, addr); } @@ -2668,7 +2668,7 @@ static int ath10k_pci_safe_chip_reset(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (!ar_pci->pci_soft_reset) - return -ENOTSUPP; + return -EOPNOTSUPP; return ar_pci->pci_soft_reset(ar); } @@ -2808,7 +2808,7 @@ static int ath10k_pci_chip_reset(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (WARN_ON(!ar_pci->pci_hard_reset)) - return -ENOTSUPP; + return -EOPNOTSUPP; return ar_pci->pci_hard_reset(ar); } @@ -3594,7 +3594,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, break; default: WARN_ON(1); - return -ENOTSUPP; + return -EOPNOTSUPP; } ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 0ce08e9a0a3d..aed97fd121ba 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" #include "debug.h" @@ -1351,7 +1352,7 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 || __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 || __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) { - return -ENOTSUPP; + return -EOPNOTSUPP; } arg->min_tx_power = ev->hw_min_tx_power; @@ -2123,9 +2124,9 @@ static int ath10k_wmi_tlv_op_get_vdev_subtype(struct ath10k *ar, case WMI_VDEV_SUBTYPE_MESH_11S: return WMI_TLV_VDEV_SUBTYPE_MESH_11S; case WMI_VDEV_SUBTYPE_MESH_NON_11S: - return -ENOTSUPP; + return -EOPNOTSUPP; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static struct sk_buff * diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0cfd9484c45e..9e2f0a50aaea 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -8733,9 +8733,9 @@ int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, return WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA; case WMI_VDEV_SUBTYPE_MESH_11S: case WMI_VDEV_SUBTYPE_MESH_NON_11S: - return -ENOTSUPP; + return -EOPNOTSUPP; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar, @@ -8755,9 +8755,9 @@ static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar, case WMI_VDEV_SUBTYPE_MESH_11S: return WMI_VDEV_SUBTYPE_10_2_4_MESH_11S; case WMI_VDEV_SUBTYPE_MESH_NON_11S: - return -ENOTSUPP; + return -EOPNOTSUPP; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar, @@ -8779,7 +8779,7 @@ static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar, case WMI_VDEV_SUBTYPE_MESH_NON_11S: return WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static struct sk_buff * From 60b9376583217c8726be0a57d9ff71d52e9ce261 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 29 Nov 2023 10:04:12 +0800 Subject: [PATCH 0111/2255] wifi: ath12k: fix wrong definitions of hal_reo_update_rx_queue Some fields of hal_reo_update_rx_queue structure are wrongly defined, so fix it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231129020414.56425-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/hal_desc.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 6c17adc6d60b..ec204939e50c 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -2500,13 +2500,13 @@ struct hal_rx_reo_queue { #define HAL_REO_UPD_RX_QUEUE_INFO1_PN_HANDLE_ENABLE BIT(30) #define HAL_REO_UPD_RX_QUEUE_INFO1_IGNORE_AMPDU_FLG BIT(31) -#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE GENMASK(7, 0) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE GENMASK(9, 8) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD BIT(10) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN GENMASK(22, 11) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR BIT(23) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR BIT(24) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID BIT(25) +#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE GENMASK(9, 0) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE GENMASK(11, 10) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD BIT(12) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN GENMASK(24, 13) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR BIT(25) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR BIT(26) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID BIT(27) struct hal_reo_update_rx_queue { struct hal_reo_cmd_hdr cmd; From b0970f50839ecbb71d43914fe88ea7eeb3416a21 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 17 Jan 2024 14:05:30 +0200 Subject: [PATCH 0112/2255] wifi: ath12k: add support for BA1024 Currently the maximum block ACK window size supported is 256. This results in that, when connected to an AP which supports larger BA sizes like BA512 or BA1024, only BA256 is established, leading to a lower peak throughput. So add support for BA1024, this is done by allocating a larger REO queue and advertising IEEE80211_MAX_AMPDU_BUF_EHT support to MAC80211. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231129020414.56425-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.h | 2 +- drivers/net/wireless/ath/ath12k/hal_desc.h | 6 ++++++ drivers/net/wireless/ath/ath12k/hal_rx.c | 11 ++++++++--- drivers/net/wireless/ath/ath12k/mac.c | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 1df3cdd46140..f8fc72a178ef 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -150,7 +150,7 @@ struct ath12k_pdev_dp { #define DP_RX_HASH_ENABLE 1 /* Enable hash based Rx steering */ -#define DP_BA_WIN_SZ_MAX 256 +#define DP_BA_WIN_SZ_MAX 1024 #define DP_TCL_NUM_RING_MAX 4 diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index ec204939e50c..63340256d3f6 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -2517,6 +2517,12 @@ struct hal_reo_update_rx_queue { __le32 pn[4]; } __packed; +struct hal_rx_reo_queue_1k { + struct hal_desc_header desc_hdr; + __le32 rx_bitmap_1023_288[23]; + __le32 reserved[8]; +} __packed; + #define HAL_REO_UNBLOCK_CACHE_INFO0_UNBLK_CACHE BIT(0) #define HAL_REO_UNBLOCK_CACHE_INFO0_RESOURCE_IDX GENMASK(2, 1) diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 4fc08d4f85b5..f7c1aaa3b5d4 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -688,23 +688,28 @@ void ath12k_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab, u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid) { - u32 num_ext_desc; + u32 num_ext_desc, num_1k_desc = 0; if (ba_window_size <= 1) { if (tid != HAL_DESC_REO_NON_QOS_TID) num_ext_desc = 1; else num_ext_desc = 0; + } else if (ba_window_size <= 105) { num_ext_desc = 1; } else if (ba_window_size <= 210) { num_ext_desc = 2; - } else { + } else if (ba_window_size <= 256) { num_ext_desc = 3; + } else { + num_ext_desc = 10; + num_1k_desc = 1; } return sizeof(struct hal_rx_reo_queue) + - (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext)); + (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext)) + + (num_1k_desc * sizeof(struct hal_rx_reo_queue_1k)); } void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d453e4165228..408f1fada337 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7602,7 +7602,7 @@ static int ath12k_mac_hw_register(struct ath12k *ar) hw->queues = ATH12K_HW_MAX_QUEUES; wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; - hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT; hw->vif_data_size = sizeof(struct ath12k_vif); hw->sta_data_size = sizeof(struct ath12k_sta); From 955df16f2a4c3023753680925e71e099818c2329 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 17 Jan 2024 14:05:39 +0200 Subject: [PATCH 0113/2255] wifi: ath12k: change MAC buffer ring size to 2048 For WCN7850, there is a SRNG named MAC buffer ring, i.e., dp->rx_mac_buf_ring. During initialization, it is setup by host and then under control of firmware. During RX process, firmware fetches buffers from dp->rx_refill_buf_ring to fill that MAC buffer ring, and those buffers are taken by RXDMA to carry real WLAN frames received from air. Currently a low RX throughput is observed. Checking firmware log, lots of errors are reported by MAC buffer ring, complaining that it is running out of buffers, which further indicates that RXDMA is suffering from starvation. Currently the size of dp->rx_mac_buf_ring is configured as 1024. After changing it to 2048, those error messages are reduced, and a 6.4% increase is seen in peak throughput. Note that 2048 is an empirical value. It is chosen here because the RX throughput meets our expectation after the change. This change only applies to WCN7850 since other chips don't have a MAC buffer ring. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231129020414.56425-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.h | 1 + drivers/net/wireless/ath/ath12k/dp_rx.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index f8fc72a178ef..0a10cd362356 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -170,6 +170,7 @@ struct ath12k_pdev_dp { #define DP_REO_CMD_RING_SIZE 128 #define DP_REO_STATUS_RING_SIZE 2048 #define DP_RXDMA_BUF_RING_SIZE 4096 +#define DP_RX_MAC_BUF_RING_SIZE 2048 #define DP_RXDMA_REFILL_RING_SIZE 2048 #define DP_RXDMA_ERR_DST_RING_SIZE 1024 #define DP_RXDMA_MON_STATUS_RING_SIZE 1024 diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 1ee83f765929..07430289023f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -4086,7 +4086,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->rx_mac_buf_ring[i], HAL_RXDMA_BUF, 1, - i, 1024); + i, DP_RX_MAC_BUF_RING_SIZE); if (ret) { ath12k_warn(ab, "failed to setup rx_mac_buf_ring %d\n", i); From 23b8330156e55aa80027d2e962146ada78a693ce Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 10 Jan 2024 16:29:28 +0300 Subject: [PATCH 0114/2255] wifi: rtw88: use kstrtoX_from_user() in debugfs handlers When 'sscanf()' is not needed to scan an input, prefer common 'kstrtoX_from_user()' over 'rtw_debugfs_copy_from_user()' with following 'kstrtoX()'. Minor adjustments, compile tested only. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240110132930.438828-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtw88/debug.c | 44 ++++------------------ 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 1b2ad81838be..5b2036798159 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -316,23 +316,13 @@ static ssize_t rtw_debugfs_set_single_input(struct file *filp, { struct seq_file *seqpriv = (struct seq_file *)filp->private_data; struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; - struct rtw_dev *rtwdev = debugfs_priv->rtwdev; - char tmp[32 + 1]; u32 input; - int num; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtou32_from_user(buffer, count, 0, &input); if (ret) return ret; - num = kstrtoint(tmp, 0, &input); - - if (num) { - rtw_warn(rtwdev, "kstrtoint failed\n"); - return num; - } - debugfs_priv->cb_data = input; return count; @@ -485,19 +475,12 @@ static ssize_t rtw_debugfs_set_fix_rate(struct file *filp, struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 fix_rate; - char tmp[32 + 1]; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtou8_from_user(buffer, count, 0, &fix_rate); if (ret) return ret; - ret = kstrtou8(tmp, 0, &fix_rate); - if (ret) { - rtw_warn(rtwdev, "invalid args, [rate]\n"); - return ret; - } - dm_info->fix_rate = fix_rate; return count; @@ -879,20 +862,13 @@ static ssize_t rtw_debugfs_set_coex_enable(struct file *filp, struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_coex *coex = &rtwdev->coex; - char tmp[32 + 1]; bool enable; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtobool_from_user(buffer, count, &enable); if (ret) return ret; - ret = kstrtobool(tmp, &enable); - if (ret) { - rtw_warn(rtwdev, "invalid arguments\n"); - return ret; - } - mutex_lock(&rtwdev->mutex); coex->manual_control = !enable; mutex_unlock(&rtwdev->mutex); @@ -951,18 +927,13 @@ static ssize_t rtw_debugfs_set_fw_crash(struct file *filp, struct seq_file *seqpriv = (struct seq_file *)filp->private_data; struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; - char tmp[32 + 1]; bool input; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtobool_from_user(buffer, count, &input); if (ret) return ret; - ret = kstrtobool(tmp, &input); - if (ret) - return -EINVAL; - if (!input) return -EINVAL; @@ -1030,11 +1001,12 @@ static ssize_t rtw_debugfs_set_dm_cap(struct file *filp, struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_dm_info *dm_info = &rtwdev->dm_info; - int bit; + int ret, bit; bool en; - if (kstrtoint_from_user(buffer, count, 10, &bit)) - return -EINVAL; + ret = kstrtoint_from_user(buffer, count, 10, &bit); + if (ret) + return ret; en = bit > 0; bit = abs(bit); From c19443700370d77f400625246df9a825f4ff85f4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 Jan 2024 14:26:37 +0800 Subject: [PATCH 0115/2255] wifi: rtw89: adjust init_he_cap() to add EHT cap into iftype_data EHT capabilities are also stored in struct ieee80211_sband_iftype_data, so adjust allocation of iftype_data as common part named init_he_eht_cap(), and then init_eht_cap() can be added later. Don't change logic at all by this patch. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240112062640.36922-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 216 +++++++++++----------- 1 file changed, 113 insertions(+), 103 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index ac7ae19429f9..1e722215034e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3649,25 +3649,21 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, vht_cap->vht_mcs.tx_highest = highest[hal->tx_nss - 1]; } -#define RTW89_SBAND_IFTYPES_NR 2 - static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, enum nl80211_band band, - struct ieee80211_supported_band *sband) + enum nl80211_iftype iftype, + struct ieee80211_sband_iftype_data *iftype_data) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_hal *hal = &rtwdev->hal; - struct ieee80211_sband_iftype_data *iftype_data; bool no_ng16 = (chip->chip_id == RTL8852A && hal->cv == CHIP_CBV) || (chip->chip_id == RTL8852B && hal->cv == CHIP_CAV); + struct ieee80211_sta_he_cap *he_cap; + int nss = hal->rx_nss; + u8 *mac_cap_info; + u8 *phy_cap_info; u16 mcs_map = 0; int i; - int nss = hal->rx_nss; - int idx = 0; - - iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL); - if (!iftype_data) - return; for (i = 0; i < 8; i++) { if (i < nss) @@ -3676,12 +3672,109 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, mcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); } - for (i = 0; i < NUM_NL80211_IFTYPES; i++) { - struct ieee80211_sta_he_cap *he_cap; - u8 *mac_cap_info; - u8 *phy_cap_info; + he_cap = &iftype_data->he_cap; + mac_cap_info = he_cap->he_cap_elem.mac_cap_info; + phy_cap_info = he_cap->he_cap_elem.phy_cap_info; - switch (i) { + he_cap->has_he = true; + mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; + if (iftype == NL80211_IFTYPE_STATION) + mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; + mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK | + IEEE80211_HE_MAC_CAP2_BSR; + mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2; + if (iftype == NL80211_IFTYPE_AP) + mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL; + mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS | + IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; + if (iftype == NL80211_IFTYPE_STATION) + mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; + if (band == NL80211_BAND_2GHZ) { + phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + } else { + phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + if (chip->support_bw160) + phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + } + phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; + phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_DOPPLER_TX; + phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM; + if (iftype == NL80211_IFTYPE_STATION) + phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2; + if (iftype == NL80211_IFTYPE_AP) + phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU; + phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; + if (chip->support_bw160) + phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; + phy_cap_info[5] = no_ng16 ? 0 : + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; + phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE; + phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP7_MAX_NC_1; + phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996; + if (chip->support_bw160) + phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; + phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, + IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); + if (iftype == NL80211_IFTYPE_STATION) + phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map); + he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map); + if (chip->support_bw160) { + he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map); + he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map); + } + + if (band == NL80211_BAND_6GHZ) { + __le16 capa; + + capa = le16_encode_bits(IEEE80211_HT_MPDU_DENSITY_NONE, + IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | + le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, + IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | + le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); + iftype_data->he_6ghz_capa.capa = capa; + } +} + +#define RTW89_SBAND_IFTYPES_NR 2 + +static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev, + enum nl80211_band band, + struct ieee80211_supported_band *sband) +{ + struct ieee80211_sband_iftype_data *iftype_data; + enum nl80211_iftype iftype; + int idx = 0; + + iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL); + if (!iftype_data) + return; + + for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { + switch (iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP: break; @@ -3694,92 +3787,9 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, break; } - iftype_data[idx].types_mask = BIT(i); - he_cap = &iftype_data[idx].he_cap; - mac_cap_info = he_cap->he_cap_elem.mac_cap_info; - phy_cap_info = he_cap->he_cap_elem.phy_cap_info; + iftype_data[idx].types_mask = BIT(iftype); - he_cap->has_he = true; - mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; - if (i == NL80211_IFTYPE_STATION) - mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; - mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK | - IEEE80211_HE_MAC_CAP2_BSR; - mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2; - if (i == NL80211_IFTYPE_AP) - mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL; - mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS | - IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; - if (i == NL80211_IFTYPE_STATION) - mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; - if (band == NL80211_BAND_2GHZ) { - phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; - } else { - phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; - if (chip->support_bw160) - phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; - } - phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | - IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | - IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; - phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | - IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_DOPPLER_TX; - phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM; - if (i == NL80211_IFTYPE_STATION) - phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM | - IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2; - if (i == NL80211_IFTYPE_AP) - phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU; - phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; - if (chip->support_bw160) - phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; - phy_cap_info[5] = no_ng16 ? 0 : - IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | - IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; - phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | - IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | - IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | - IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE; - phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_1; - phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996; - if (chip->support_bw160) - phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; - phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | - IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | - u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, - IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); - if (i == NL80211_IFTYPE_STATION) - phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; - he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map); - he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map); - if (chip->support_bw160) { - he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map); - he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map); - } - - if (band == NL80211_BAND_6GHZ) { - __le16 capa; - - capa = le16_encode_bits(IEEE80211_HT_MPDU_DENSITY_NONE, - IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | - le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, - IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | - le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, - IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); - iftype_data[idx].he_6ghz_capa.capa = capa; - } + rtw89_init_he_cap(rtwdev, band, iftype, &iftype_data[idx]); idx++; } @@ -3800,7 +3810,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev) if (!sband_2ghz) goto err; rtw89_init_ht_cap(rtwdev, &sband_2ghz->ht_cap); - rtw89_init_he_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz); + rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz); hw->wiphy->bands[NL80211_BAND_2GHZ] = sband_2ghz; } @@ -3810,7 +3820,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev) goto err; rtw89_init_ht_cap(rtwdev, &sband_5ghz->ht_cap); rtw89_init_vht_cap(rtwdev, &sband_5ghz->vht_cap); - rtw89_init_he_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz); + rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz); hw->wiphy->bands[NL80211_BAND_5GHZ] = sband_5ghz; } @@ -3818,7 +3828,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev) sband_6ghz = kmemdup(&rtw89_sband_6ghz, size, GFP_KERNEL); if (!sband_6ghz) goto err; - rtw89_init_he_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz); + rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz); hw->wiphy->bands[NL80211_BAND_6GHZ] = sband_6ghz; } From c5bdcddaa32c602a8864a3a1df3a10429f0ed8a9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 Jan 2024 14:26:38 +0800 Subject: [PATCH 0116/2255] wifi: rtw89: change supported bandwidths of chip_info to bit mask Basically, all chips can support 20/40/80MHz bandwidth, and 8952C can support 160MHz bandwidth, which is why we introduced support_bw160 before. The coming WiFi 7 chips will support 320MHz optionally, so change it to bit mask instead of adding another support_bw320. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240112062640.36922-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 13 +++++++------ drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 +++- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 4 +++- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 +++- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 5 ++++- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 4 ++++ 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 1e722215034e..3d93649d5893 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3611,7 +3611,8 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, cpu_to_le16(867), cpu_to_le16(1733), cpu_to_le16(2600), cpu_to_le16(3467), }; const struct rtw89_chip_info *chip = rtwdev->chip; - const __le16 *highest = chip->support_bw160 ? highest_bw160 : highest_bw80; + const __le16 *highest = chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160) ? + highest_bw160 : highest_bw80; struct rtw89_hal *hal = &rtwdev->hal; u16 tx_mcs_map = 0, rx_mcs_map = 0; u8 sts_cap = 3; @@ -3640,7 +3641,7 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; vht_cap->cap |= sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; - if (chip->support_bw160) + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHT_CAP_SHORT_GI_160; vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rx_mcs_map); @@ -3695,7 +3696,7 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, } else { phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; - if (chip->support_bw160) + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; } phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | @@ -3713,7 +3714,7 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU; phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; - if (chip->support_bw160) + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; phy_cap_info[5] = no_ng16 ? 0 : IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | @@ -3728,7 +3729,7 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996; - if (chip->support_bw160) + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | @@ -3741,7 +3742,7 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map); he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map); - if (chip->support_bw160) { + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) { he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map); he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map); } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 73694aca1108..d45ddb9320b1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3718,7 +3718,7 @@ struct rtw89_chip_info { u32 rf_base_addr[2]; u8 support_chanctx_num; u8 support_bands; - bool support_bw160; + u16 support_bandwidths; bool support_unii4; bool ul_tb_waveform_ctrl; bool ul_tb_pwr_diff; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 558ab6c2c24a..6cbdbf26cfd6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2396,7 +2396,9 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .support_chanctx_num = 0, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), - .support_bw160 = false, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), .support_unii4 = true, .ul_tb_waveform_ctrl = true, .ul_tb_pwr_diff = false, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 3349397e3af1..c8a9fe8e359a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2132,7 +2132,9 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .support_chanctx_num = 1, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), - .support_bw160 = false, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), .support_unii4 = false, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = false, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 43e803cb06f2..9bcbbb2d2c6f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2566,7 +2566,9 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .support_chanctx_num = 0, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), - .support_bw160 = false, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), .support_unii4 = true, .ul_tb_waveform_ctrl = true, .ul_tb_pwr_diff = false, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index e2393e621755..637656879da4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2904,7 +2904,10 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | BIT(NL80211_BAND_6GHZ), - .support_bw160 = true, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), .support_unii4 = true, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = true, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 7f6dde384223..067d34b4d32e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -866,6 +866,10 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | BIT(NL80211_BAND_6GHZ), + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), .support_unii4 = true, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = false, From 9156181f62744ddea2f2b7a5d7180c08f143a056 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 Jan 2024 14:26:39 +0800 Subject: [PATCH 0117/2255] wifi: rtw89: add EHT capabilities for WiFi 7 chips The coming WiFi 7 chip 8922A will support EHT, so declare EHT along with hardware capabilities. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240112062640.36922-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 90 +++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 3d93649d5893..693261e21c98 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3760,6 +3760,95 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, } } +static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, + enum nl80211_band band, + enum nl80211_iftype iftype, + struct ieee80211_sband_iftype_data *iftype_data) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct ieee80211_eht_cap_elem_fixed *eht_cap_elem; + struct ieee80211_eht_mcs_nss_supp *eht_nss; + struct ieee80211_sta_eht_cap *eht_cap; + struct rtw89_hal *hal = &rtwdev->hal; + bool support_320mhz = false; + int sts = 3; + u8 val; + + if (chip->chip_gen == RTW89_CHIP_AX) + return; + + if (band == NL80211_BAND_6GHZ && + chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_320)) + support_320mhz = true; + + eht_cap = &iftype_data->eht_cap; + eht_cap_elem = &eht_cap->eht_cap_elem; + eht_nss = &eht_cap->eht_mcs_nss_supp; + + eht_cap->has_eht = true; + + eht_cap_elem->mac_cap_info[0] = + u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991, + IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); + eht_cap_elem->mac_cap_info[1] = 0; + + eht_cap_elem->phy_cap_info[0] = + IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + if (support_320mhz) + eht_cap_elem->phy_cap_info[0] |= + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + + eht_cap_elem->phy_cap_info[0] |= + u8_encode_bits(u8_get_bits(sts - 1, BIT(0)), + IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK); + eht_cap_elem->phy_cap_info[1] = + u8_encode_bits(u8_get_bits(sts - 1, GENMASK(2, 1)), + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) | + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK); + if (support_320mhz) + eht_cap_elem->phy_cap_info[1] |= + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK); + + eht_cap_elem->phy_cap_info[2] = 0; + + eht_cap_elem->phy_cap_info[3] = + IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | + IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | + IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | + IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK; + + eht_cap_elem->phy_cap_info[4] = + IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | + u8_encode_bits(1, IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK); + + eht_cap_elem->phy_cap_info[5] = + IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | + u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US, + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); + + eht_cap_elem->phy_cap_info[6] = 0; + eht_cap_elem->phy_cap_info[7] = 0; + eht_cap_elem->phy_cap_info[8] = 0; + + val = u8_encode_bits(hal->rx_nss, IEEE80211_EHT_MCS_NSS_RX) | + u8_encode_bits(hal->tx_nss, IEEE80211_EHT_MCS_NSS_TX); + eht_nss->bw._80.rx_tx_mcs9_max_nss = val; + eht_nss->bw._80.rx_tx_mcs11_max_nss = val; + eht_nss->bw._80.rx_tx_mcs13_max_nss = val; + eht_nss->bw._160.rx_tx_mcs9_max_nss = val; + eht_nss->bw._160.rx_tx_mcs11_max_nss = val; + eht_nss->bw._160.rx_tx_mcs13_max_nss = val; + if (support_320mhz) { + eht_nss->bw._320.rx_tx_mcs9_max_nss = val; + eht_nss->bw._320.rx_tx_mcs11_max_nss = val; + eht_nss->bw._320.rx_tx_mcs13_max_nss = val; + } +} + #define RTW89_SBAND_IFTYPES_NR 2 static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev, @@ -3791,6 +3880,7 @@ static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev, iftype_data[idx].types_mask = BIT(iftype); rtw89_init_he_cap(rtwdev, band, iftype, &iftype_data[idx]); + rtw89_init_eht_cap(rtwdev, band, iftype, &iftype_data[idx]); idx++; } From 4f47e0cf1a84debed285b2b6a4a567a2cfec7e9b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 Jan 2024 14:26:40 +0800 Subject: [PATCH 0118/2255] wifi: rtw89: declare EXT NSS BW of VHT capability According to IEEE Std. 802.11, it defines: Indicates whether the STA is capable of interpreting the Extended NSS BW Support subfield of the VHT Capabilities Information field. Some AP such as TP-LINK BE19000 would check it for bandwidth settings, so causes 80MHz rate when associating on 160 MHz bandwidth. Declare this capability to yield expected result. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240112062640.36922-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 693261e21c98..4f33e0a6ff9f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3648,6 +3648,10 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(tx_mcs_map); vht_cap->vht_mcs.rx_highest = highest[hal->rx_nss - 1]; vht_cap->vht_mcs.tx_highest = highest[hal->tx_nss - 1]; + + if (ieee80211_hw_check(rtwdev->hw, SUPPORTS_VHT_EXT_NSS_BW)) + vht_cap->vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); } static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, @@ -4391,6 +4395,7 @@ EXPORT_SYMBOL(rtw89_chip_info_setup); static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_hal *hal = &rtwdev->hal; @@ -4428,6 +4433,9 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) /* 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); + if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) ieee80211_hw_set(hw, CONNECTION_MONITOR); From 8d666e57545525e160af96f52ba5027c5f3430de Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:35 +0800 Subject: [PATCH 0119/2255] wifi: rtw89: fw: add H2C command to update security CAM v2 To have secure connection, set key information into security CAM including key index, entry index and valid map. This new introduced H2C command can support MLO, but currently not implement yet. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/cam.c | 61 ++++++++++++ drivers/net/wireless/realtek/rtw89/cam.h | 96 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.c | 39 ++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 4 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 + 5 files changed, 201 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index 914c94988b2f..11fbdd142162 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -777,3 +777,64 @@ void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, SET_DCTL_SEC_ENT5_V1(cmd, addr_cam->sec_ent[5]); SET_DCTL_SEC_ENT6_V1(cmd, addr_cam->sec_ent[6]); } + +void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, + struct rtw89_h2c_dctlinfo_ud_v2 *h2c) +{ + struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + + h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id, + DCTLINFO_V2_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V2_C0_OP); + + h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0], + DCTLINFO_V2_W4_SEC_ENT0_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[1], + DCTLINFO_V2_W4_SEC_ENT1_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[2], + DCTLINFO_V2_W4_SEC_ENT2_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[3], + DCTLINFO_V2_W4_SEC_ENT3_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[4], + DCTLINFO_V2_W4_SEC_ENT4_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[5], + DCTLINFO_V2_W4_SEC_ENT5_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[6], + DCTLINFO_V2_W4_SEC_ENT6_KEYID); + h2c->m4 = cpu_to_le32(DCTLINFO_V2_W4_SEC_ENT0_KEYID | + DCTLINFO_V2_W4_SEC_ENT1_KEYID | + DCTLINFO_V2_W4_SEC_ENT2_KEYID | + DCTLINFO_V2_W4_SEC_ENT3_KEYID | + DCTLINFO_V2_W4_SEC_ENT4_KEYID | + DCTLINFO_V2_W4_SEC_ENT5_KEYID | + DCTLINFO_V2_W4_SEC_ENT6_KEYID); + + h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0], + DCTLINFO_V2_W5_SEC_ENT_VALID_V1) | + le32_encode_bits(addr_cam->sec_ent[0], + DCTLINFO_V2_W5_SEC_ENT0_V1); + h2c->m5 = cpu_to_le32(DCTLINFO_V2_W5_SEC_ENT_VALID_V1 | + DCTLINFO_V2_W5_SEC_ENT0_V1); + + h2c->w6 = le32_encode_bits(addr_cam->sec_ent[1], + DCTLINFO_V2_W6_SEC_ENT1_V1) | + le32_encode_bits(addr_cam->sec_ent[2], + DCTLINFO_V2_W6_SEC_ENT2_V1) | + le32_encode_bits(addr_cam->sec_ent[3], + DCTLINFO_V2_W6_SEC_ENT3_V1) | + le32_encode_bits(addr_cam->sec_ent[4], + DCTLINFO_V2_W6_SEC_ENT4_V1); + h2c->m6 = cpu_to_le32(DCTLINFO_V2_W6_SEC_ENT1_V1 | + DCTLINFO_V2_W6_SEC_ENT2_V1 | + DCTLINFO_V2_W6_SEC_ENT3_V1 | + DCTLINFO_V2_W6_SEC_ENT4_V1); + + h2c->w7 = le32_encode_bits(addr_cam->sec_ent[5], + DCTLINFO_V2_W7_SEC_ENT5_V1) | + le32_encode_bits(addr_cam->sec_ent[6], + DCTLINFO_V2_W7_SEC_ENT6_V1); + h2c->m7 = cpu_to_le32(DCTLINFO_V2_W7_SEC_ENT5_V1 | + DCTLINFO_V2_W7_SEC_ENT6_V1); +} diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index 83c160a614e6..9a2dd5999edb 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -352,6 +352,98 @@ static inline void FWCMD_SET_ADDR_BSSID_BSSID5(void *cmd, u32 value) le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(31, 24)); } +struct rtw89_h2c_dctlinfo_ud_v2 { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define DCTLINFO_V2_C0_MACID GENMASK(6, 0) +#define DCTLINFO_V2_C0_OP BIT(7) + +#define DCTLINFO_V2_W0_QOS_FIELD_H GENMASK(7, 0) +#define DCTLINFO_V2_W0_HW_EXSEQ_MACID GENMASK(14, 8) +#define DCTLINFO_V2_W0_QOS_DATA BIT(15) +#define DCTLINFO_V2_W0_AES_IV_L GENMASK(31, 16) +#define DCTLINFO_V2_W1_AES_IV_H GENMASK(31, 0) +#define DCTLINFO_V2_W2_SEQ0 GENMASK(11, 0) +#define DCTLINFO_V2_W2_SEQ1 GENMASK(23, 12) +#define DCTLINFO_V2_W2_AMSDU_MAX_LEN GENMASK(26, 24) +#define DCTLINFO_V2_W2_STA_AMSDU_EN BIT(27) +#define DCTLINFO_V2_W2_CHKSUM_OFLD_EN BIT(28) +#define DCTLINFO_V2_W2_WITH_LLC BIT(29) +#define DCTLINFO_V2_W2_NAT25_EN BIT(30) +#define DCTLINFO_V2_W2_IS_MLD BIT(31) +#define DCTLINFO_V2_W3_SEQ2 GENMASK(11, 0) +#define DCTLINFO_V2_W3_SEQ3 GENMASK(23, 12) +#define DCTLINFO_V2_W3_TGT_IND GENMASK(27, 24) +#define DCTLINFO_V2_W3_TGT_IND_EN BIT(28) +#define DCTLINFO_V2_W3_HTC_LB GENMASK(31, 29) +#define DCTLINFO_V2_W4_VLAN_TAG_SEL GENMASK(7, 5) +#define DCTLINFO_V2_W4_HTC_ORDER BIT(8) +#define DCTLINFO_V2_W4_SEC_KEY_ID GENMASK(10, 9) +#define DCTLINFO_V2_W4_VLAN_RX_DYNAMIC_PCP_EN BIT(11) +#define DCTLINFO_V2_W4_VLAN_RX_PKT_DROP BIT(12) +#define DCTLINFO_V2_W4_VLAN_RX_VALID BIT(13) +#define DCTLINFO_V2_W4_VLAN_TX_VALID BIT(14) +#define DCTLINFO_V2_W4_WAPI BIT(15) +#define DCTLINFO_V2_W4_SEC_ENT_MODE GENMASK(17, 16) +#define DCTLINFO_V2_W4_SEC_ENT0_KEYID GENMASK(19, 18) +#define DCTLINFO_V2_W4_SEC_ENT1_KEYID GENMASK(21, 20) +#define DCTLINFO_V2_W4_SEC_ENT2_KEYID GENMASK(23, 22) +#define DCTLINFO_V2_W4_SEC_ENT3_KEYID GENMASK(25, 24) +#define DCTLINFO_V2_W4_SEC_ENT4_KEYID GENMASK(27, 26) +#define DCTLINFO_V2_W4_SEC_ENT5_KEYID GENMASK(29, 28) +#define DCTLINFO_V2_W4_SEC_ENT6_KEYID GENMASK(31, 30) +#define DCTLINFO_V2_W5_SEC_ENT7_KEYID GENMASK(1, 0) +#define DCTLINFO_V2_W5_SEC_ENT8_KEYID GENMASK(3, 2) +#define DCTLINFO_V2_W5_SEC_ENT_VALID_V1 GENMASK(23, 8) +#define DCTLINFO_V2_W5_SEC_ENT0_V1 GENMASK(31, 24) +#define DCTLINFO_V2_W6_SEC_ENT1_V1 GENMASK(7, 0) +#define DCTLINFO_V2_W6_SEC_ENT2_V1 GENMASK(15, 8) +#define DCTLINFO_V2_W6_SEC_ENT3_V1 GENMASK(23, 16) +#define DCTLINFO_V2_W6_SEC_ENT4_V1 GENMASK(31, 24) +#define DCTLINFO_V2_W7_SEC_ENT5_V1 GENMASK(7, 0) +#define DCTLINFO_V2_W7_SEC_ENT6_V1 GENMASK(15, 8) +#define DCTLINFO_V2_W7_SEC_ENT7 GENMASK(23, 16) +#define DCTLINFO_V2_W7_SEC_ENT8 GENMASK(31, 24) +#define DCTLINFO_V2_W8_MLD_SMA_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W9_MLD_SMA_H_V1 GENMASK(15, 0) +#define DCTLINFO_V2_W9_MLD_TMA_L_V1 GENMASK(31, 16) +#define DCTLINFO_V2_W10_MLD_TMA_H_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W11_MLD_TA_BSSID_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W12_MLD_TA_BSSID_H_V1 GENMASK(15, 0) + int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, @@ -373,6 +465,10 @@ void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, u8 *cmd); +void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, + struct rtw89_h2c_dctlinfo_ud_v2 *h2c); int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, u8 *cmd); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 55a9f4eb47be..bc4c09939160 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1486,6 +1486,45 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1); +int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + struct rtw89_h2c_dctlinfo_ud_v2 *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 dctl sec cam\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data; + + rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif, rtwsta, h2c); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V2, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2); + int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7fa7cd11c495..7ff04472fbdc 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3618,6 +3618,7 @@ struct rtw89_fw_h2c_rf_reg_info { #define H2C_FUNC_MAC_BCN_UPD 0x5 #define H2C_FUNC_MAC_DCTLINFO_UD_V1 0x9 #define H2C_FUNC_MAC_CCTLINFO_UD_V1 0xa +#define H2C_FUNC_MAC_DCTLINFO_UD_V2 0xc #define H2C_FUNC_MAC_BCN_UPD_BE 0xd /* CLASS 6 - Address CAM */ @@ -3822,6 +3823,9 @@ int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); +int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct work_struct *work); int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 067d34b4d32e..64f8013a1300 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -822,6 +822,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .read_phycap = rtw8922a_read_phycap, .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, + .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, }; From 7992619306562fa70fc2ed9ee859daf5408b0c1f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:36 +0800 Subject: [PATCH 0120/2255] wifi: rtw89: fw: fill CMAC table to associated station for WiFi 7 chips When a station get connected, fill hardware CMAC table via H2C command to tell hardware arguments related to transmit, such as the lowest rate, packet padding and so on. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/fw.c | 175 +++++++++++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 136 ++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 + 4 files changed, 309 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index d45ddb9320b1..1acf55f343b7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -879,7 +879,7 @@ enum rtw89_ps_mode { #define RTW89_5G_BW_NUM (RTW89_CHANNEL_WIDTH_160 + 1) #define RTW89_6G_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1) #define RTW89_BYR_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1) -#define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_160 + 1) +#define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1) enum rtw89_ru_bandwidth { RTW89_RU26 = 0, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index bc4c09939160..7c33b10a39be 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2111,9 +2111,6 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, u16 ppe; int i; - if (!sta->deflink.he_cap.has_he) - return; - ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]); if (!ppe_th) { @@ -2172,7 +2169,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, int ret; memset(pads, 0, sizeof(pads)); - if (sta) + if (sta && sta->deflink.he_cap.has_he) __get_sta_he_pkt_padding(rtwdev, sta, pads); if (vif->p2p) @@ -2235,6 +2232,176 @@ fail: return ret; } +static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta, u8 *pads) +{ + u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; + u16 ppe_thres_hdr; + u8 ppe16, ppe8; + u8 n, idx, sh; + u8 ru_bitmap; + bool ppe_th; + u16 ppe; + int i; + + ppe_th = !!u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT); + if (!ppe_th) { + u8 pad; + + pad = u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); + + for (i = 0; i < RTW89_PPE_BW_NUM; i++) + pads[i] = pad; + + return; + } + + ppe_thres_hdr = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres); + ru_bitmap = u16_get_bits(ppe_thres_hdr, + IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); + n = hweight8(ru_bitmap); + n = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE + + (n * IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2) * nss; + + for (i = 0; i < RTW89_PPE_BW_NUM; i++) { + if (!(ru_bitmap & BIT(i))) { + pads[i] = 1; + continue; + } + + idx = n >> 3; + sh = n & 7; + n += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; + + ppe = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres + idx); + ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; + sh += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE; + ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; + + if (ppe16 != 7 && ppe8 == 7) + pads[i] = 2; + else if (ppe8 != 7) + pads[i] = 1; + else + pads[i] = 0; + } +} + +int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u8 pads[RTW89_PPE_BW_NUM]; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 lowest_rate; + int ret; + + memset(pads, 0, sizeof(pads)); + if (sta) { + if (sta->deflink.eht_cap.has_eht) + __get_sta_eht_pkt_padding(rtwdev, sta, pads); + else if (sta->deflink.he_cap.has_he) + __get_sta_he_pkt_padding(rtwdev, sta, pads); + } + + if (vif->p2p) + lowest_rate = RTW89_HW_RATE_OFDM6; + else if (chan->band_type == RTW89_BAND_2G) + lowest_rate = RTW89_HW_RATE_CCK1; + else + lowest_rate = RTW89_HW_RATE_OFDM6; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w0 = le32_encode_bits(1, CCTLINFO_G7_W0_DISRTSFB) | + le32_encode_bits(1, CCTLINFO_G7_W0_DISDATAFB); + h2c->m0 = cpu_to_le32(CCTLINFO_G7_W0_DISRTSFB | + CCTLINFO_G7_W0_DISDATAFB); + + h2c->w1 = le32_encode_bits(lowest_rate, CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE); + + h2c->w2 = le32_encode_bits(0, CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL); + h2c->m2 = cpu_to_le32(CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL); + + h2c->w3 = le32_encode_bits(0, CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); + h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); + + h2c->w4 = le32_encode_bits(rtwvif->port, CCTLINFO_G7_W4_MULTI_PORT_ID); + h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_MULTI_PORT_ID); + + if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) { + h2c->w4 |= le32_encode_bits(0, CCTLINFO_G7_W4_DATA_DCM); + h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_DATA_DCM); + } + + if (vif->bss_conf.eht_support) { + h2c->w4 |= le32_encode_bits(~vif->bss_conf.eht_puncturing, + CCTLINFO_G7_W4_ACT_SUBCH_CBW); + h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW); + } + + h2c->w5 = le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_20], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_40], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_80], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_160], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_320], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4); + h2c->m5 = cpu_to_le32(CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4); + + h2c->w6 = le32_encode_bits(vif->type == NL80211_IFTYPE_STATION ? 1 : 0, + CCTLINFO_G7_W6_ULDL); + h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL); + + if (sta) { + h2c->w8 = le32_encode_bits(sta->deflink.he_cap.has_he, + CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); + h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + 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_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7ff04472fbdc..dad09e57b821 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1207,6 +1207,138 @@ static inline void SET_CMC_TBL_CSI_BW(void *table, u32 val) GENMASK(31, 30)); } +struct rtw89_h2c_cctlinfo_ud_g7 { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define CCTLINFO_G7_C0_MACID GENMASK(6, 0) +#define CCTLINFO_G7_C0_OP BIT(7) + +#define CCTLINFO_G7_W0_DATARATE GENMASK(11, 0) +#define CCTLINFO_G7_W0_DATA_GI_LTF GENMASK(14, 12) +#define CCTLINFO_G7_W0_TRYRATE BIT(15) +#define CCTLINFO_G7_W0_ARFR_CTRL GENMASK(17, 16) +#define CCTLINFO_G7_W0_DIS_HE1SS_STBC BIT(18) +#define CCTLINFO_G7_W0_ACQ_RPT_EN BIT(20) +#define CCTLINFO_G7_W0_MGQ_RPT_EN BIT(21) +#define CCTLINFO_G7_W0_ULQ_RPT_EN BIT(22) +#define CCTLINFO_G7_W0_TWTQ_RPT_EN BIT(23) +#define CCTLINFO_G7_W0_FORCE_TXOP BIT(24) +#define CCTLINFO_G7_W0_DISRTSFB BIT(25) +#define CCTLINFO_G7_W0_DISDATAFB BIT(26) +#define CCTLINFO_G7_W0_NSTR_EN BIT(27) +#define CCTLINFO_G7_W0_AMPDU_DENSITY GENMASK(31, 28) +#define CCTLINFO_G7_W1_DATA_RTY_LOWEST_RATE GENMASK(11, 0) +#define CCTLINFO_G7_W1_RTS_TXCNT_LMT GENMASK(15, 12) +#define CCTLINFO_G7_W1_RTSRATE GENMASK(27, 16) +#define CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE GENMASK(31, 28) +#define CCTLINFO_G7_W2_DATA_TX_CNT_LMT GENMASK(5, 0) +#define CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL BIT(6) +#define CCTLINFO_G7_W2_MAX_AGG_NUM_SEL BIT(7) +#define CCTLINFO_G7_W2_RTS_EN BIT(8) +#define CCTLINFO_G7_W2_CTS2SELF_EN BIT(9) +#define CCTLINFO_G7_W2_CCA_RTS GENMASK(11, 10) +#define CCTLINFO_G7_W2_HW_RTS_EN BIT(12) +#define CCTLINFO_G7_W2_RTS_DROP_DATA_MODE GENMASK(14, 13) +#define CCTLINFO_G7_W2_PRELD_EN BIT(15) +#define CCTLINFO_G7_W2_AMPDU_MAX_LEN GENMASK(26, 16) +#define CCTLINFO_G7_W2_UL_MU_DIS BIT(27) +#define CCTLINFO_G7_W2_AMPDU_MAX_TIME GENMASK(31, 28) +#define CCTLINFO_G7_W3_MAX_AGG_NUM GENMASK(7, 0) +#define CCTLINFO_G7_W3_DATA_BW GENMASK(10, 8) +#define CCTLINFO_G7_W3_DATA_BW_ER BIT(11) +#define CCTLINFO_G7_W3_BA_BMAP GENMASK(14, 12) +#define CCTLINFO_G7_W3_VCS_STBC BIT(15) +#define CCTLINFO_G7_W3_VO_LFTIME_SEL GENMASK(18, 16) +#define CCTLINFO_G7_W3_VI_LFTIME_SEL GENMASK(21, 19) +#define CCTLINFO_G7_W3_BE_LFTIME_SEL GENMASK(24, 22) +#define CCTLINFO_G7_W3_BK_LFTIME_SEL GENMASK(27, 25) +#define CCTLINFO_G7_W3_AMPDU_TIME_SEL BIT(28) +#define CCTLINFO_G7_W3_AMPDU_LEN_SEL BIT(29) +#define CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL BIT(30) +#define CCTLINFO_G7_W3_LSIG_TXOP_EN BIT(31) +#define CCTLINFO_G7_W4_MULTI_PORT_ID GENMASK(2, 0) +#define CCTLINFO_G7_W4_BYPASS_PUNC BIT(3) +#define CCTLINFO_G7_W4_MBSSID GENMASK(7, 4) +#define CCTLINFO_G7_W4_DATA_DCM BIT(8) +#define CCTLINFO_G7_W4_DATA_ER BIT(9) +#define CCTLINFO_G7_W4_DATA_LDPC BIT(10) +#define CCTLINFO_G7_W4_DATA_STBC BIT(11) +#define CCTLINFO_G7_W4_A_CTRL_BQR BIT(12) +#define CCTLINFO_G7_W4_A_CTRL_BSR BIT(14) +#define CCTLINFO_G7_W4_A_CTRL_CAS BIT(15) +#define CCTLINFO_G7_W4_ACT_SUBCH_CBW GENMASK(31, 16) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0 GENMASK(1, 0) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1 GENMASK(3, 2) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2 GENMASK(5, 4) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3 GENMASK(7, 6) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4 GENMASK(9, 8) +#define CCTLINFO_G7_W5_SR_RATE GENMASK(14, 10) +#define CCTLINFO_G7_W5_TID_DISABLE GENMASK(23, 16) +#define CCTLINFO_G7_W5_ADDR_CAM_INDEX GENMASK(31, 24) +#define CCTLINFO_G7_W6_AID12_PAID GENMASK(11, 0) +#define CCTLINFO_G7_W6_RESP_REF_RATE GENMASK(23, 12) +#define CCTLINFO_G7_W6_ULDL BIT(31) +#define CCTLINFO_G7_W7_NC GENMASK(2, 0) +#define CCTLINFO_G7_W7_NR GENMASK(5, 3) +#define CCTLINFO_G7_W7_NG GENMASK(7, 6) +#define CCTLINFO_G7_W7_CB GENMASK(9, 8) +#define CCTLINFO_G7_W7_CS GENMASK(11, 10) +#define CCTLINFO_G7_W7_CSI_STBC_EN BIT(13) +#define CCTLINFO_G7_W7_CSI_LDPC_EN BIT(14) +#define CCTLINFO_G7_W7_CSI_PARA_EN BIT(15) +#define CCTLINFO_G7_W7_CSI_FIX_RATE GENMASK(27, 16) +#define CCTLINFO_G7_W7_CSI_BW GENMASK(31, 29) +#define CCTLINFO_G7_W8_ALL_ACK_SUPPORT BIT(0) +#define CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT BIT(1) +#define CCTLINFO_G7_W8_BSR_OM_UPD_EN BIT(2) +#define CCTLINFO_G7_W8_MACID_FWD_IDC BIT(3) +#define CCTLINFO_G7_W8_AZ_SEC_EN BIT(4) +#define CCTLINFO_G7_W8_CSI_SEC_EN BIT(5) +#define CCTLINFO_G7_W8_FIX_UL_ADDRCAM_IDX BIT(6) +#define CCTLINFO_G7_W8_CTRL_CNT_VLD BIT(7) +#define CCTLINFO_G7_W8_CTRL_CNT GENMASK(11, 8) +#define CCTLINFO_G7_W8_RESP_SEC_TYPE GENMASK(15, 12) +/* W9~13 are reserved */ +#define CCTLINFO_G7_W14_VO_CURR_RATE GENMASK(11, 0) +#define CCTLINFO_G7_W14_VI_CURR_RATE GENMASK(23, 12) +#define CCTLINFO_G7_W14_BE_CURR_RATE_L GENMASK(31, 24) +#define CCTLINFO_G7_W15_BE_CURR_RATE_H GENMASK(3, 0) +#define CCTLINFO_G7_W15_BK_CURR_RATE GENMASK(15, 4) +#define CCTLINFO_G7_W15_MGNT_CURR_RATE GENMASK(27, 16) + static inline void SET_DCTL_MACID_V1(void *table, u32 val) { le32p_replace_bits((__le32 *)(table) + 0, val, GENMASK(6, 0)); @@ -3620,6 +3752,7 @@ struct rtw89_fw_h2c_rf_reg_info { #define H2C_FUNC_MAC_CCTLINFO_UD_V1 0xa #define H2C_FUNC_MAC_DCTLINFO_UD_V2 0xc #define H2C_FUNC_MAC_BCN_UPD_BE 0xd +#define H2C_FUNC_MAC_CCTLINFO_UD_G7 0x11 /* CLASS 6 - Address CAM */ #define H2C_CL_MAC_ADDR_CAM_UPDATE 0x6 @@ -3810,6 +3943,9 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 64f8013a1300..dac5fdbe65eb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -899,6 +899,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { BIT(RTW89_PS_MODE_CLK_GATED) | BIT(RTW89_PS_MODE_PWR_GATED), .low_power_hci_modes = 0, + .h2c_cctl_func_id = H2C_FUNC_MAC_CCTLINFO_UD_G7, .hci_func_en_addr = R_BE_HCI_FUNC_EN, .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v2), .txwd_body_size = sizeof(struct rtw89_txwd_body_v2), From 7e24cc86c9c9ac5102494e89289a4a276da9c224 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:37 +0800 Subject: [PATCH 0121/2255] wifi: rtw89: fw: add chip_ops to update CMAC table to associated station For WiFi 7 chips, we add H2C command with rich fields to support MLO, so add a chip_ops to generalize calling of update CMAC table. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 4 ++-- drivers/net/wireless/realtek/rtw89/core.h | 3 +++ drivers/net/wireless/realtek/rtw89/fw.c | 2 ++ drivers/net/wireless/realtek/rtw89/fw.h | 9 +++++++++ drivers/net/wireless/realtek/rtw89/mac80211.c | 4 ++-- 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/wow.c | 2 +- 11 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4f33e0a6ff9f..745aa3e52fd3 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3393,7 +3393,7 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true); } - ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; @@ -3442,7 +3442,7 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, } } - ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 1acf55f343b7..433557e89296 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3197,6 +3197,9 @@ struct rtw89_chip_ops { int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); + int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int (*h2c_update_beacon)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 7c33b10a39be..fc1295d5d8e8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2231,6 +2231,7 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl); static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, u8 *pads) @@ -2401,6 +2402,7 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index dad09e57b821..f1f119358b28 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4094,6 +4094,15 @@ static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev, return chip->ops->h2c_update_beacon(rtwdev, rtwvif); } +static inline int rtw89_chip_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_assoc_cmac_tbl(rtwdev, vif, sta); +} + static inline int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index c023c182be6a..71d5e6f7bb64 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -497,7 +497,7 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); rtw89_cam_bssid_changed(rtwdev, rtwvif); rtw89_mac_port_update(rtwdev, rtwvif); - rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE); rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); @@ -518,7 +518,7 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&rtwdev->mutex); rtw89_mac_stop_ap(rtwdev, rtwvif); - rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); mutex_unlock(&rtwdev->mutex); } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 6cbdbf26cfd6..0688b4c576f9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2334,6 +2334,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index c8a9fe8e359a..e15751f48fa3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2078,6 +2078,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 9bcbbb2d2c6f..817ba15bba20 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2503,6 +2503,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 637656879da4..892e3412a9e9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2848,6 +2848,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx_v1, .resume_sch_tx = rtw89_mac_resume_sch_tx_v1, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v1, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index dac5fdbe65eb..d0b11848dc93 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -823,6 +823,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v2, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, }; diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 5c7ca36c09b6..4c17936795b6 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -519,7 +519,7 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) return ret; } - ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); if (ret) { rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n"); return ret; From 999db6f48b28008d0045d29b739d0d670a9ab453 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:38 +0800 Subject: [PATCH 0122/2255] wifi: rtw89: fw: update TX AMPDU parameter to CMAC table The CMAC table is used to define how hardware TX a certain packet, and we can specify TX AMPDU size, so hardware can prepare proper retry window buffer. Otherwise, it can't transmit with expected aggregation number. Since each TID could have different aggregation number, the smallest number is adopted to prevent over peer's receiving buffer. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 4 ++ drivers/net/wireless/realtek/rtw89/fw.c | 66 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 15 +++++ drivers/net/wireless/realtek/rtw89/mac80211.c | 4 ++ 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 + 9 files changed, 94 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 433557e89296..b795a06d8d13 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -2933,6 +2933,7 @@ struct rtw89_sta { struct ewma_evm evm_min[RF_PATH_MAX]; struct ewma_evm evm_max[RF_PATH_MAX]; struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; + DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS); struct ieee80211_rx_status rx_status; u16 rx_hw_rate; __le32 htc_template; @@ -3200,6 +3201,9 @@ struct rtw89_chip_ops { int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); + int (*h2c_ampdu_cmac_tbl)(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int (*h2c_update_beacon)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index fc1295d5d8e8..3181cde5ab93 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2404,6 +2404,72 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7); +int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 agg_num = 0; + u8 ba_bmap = 0; + int ret; + u8 tid; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for ampdu cmac g7\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + for_each_set_bit(tid, rtwsta->ampdu_map, IEEE80211_NUM_TIDS) { + if (agg_num == 0) + agg_num = rtwsta->ampdu_params[tid].agg_num; + else + agg_num = min(agg_num, rtwsta->ampdu_params[tid].agg_num); + } + + if (agg_num <= 0x20) + ba_bmap = 3; + else if (agg_num > 0x20 && agg_num <= 0x40) + ba_bmap = 0; + else if (agg_num > 0x40 && agg_num <= 0x80) + ba_bmap = 1; + else if (agg_num > 0x80 && agg_num <= 0x100) + ba_bmap = 2; + else if (agg_num > 0x100 && agg_num <= 0x200) + ba_bmap = 4; + else if (agg_num > 0x200 && agg_num <= 0x400) + ba_bmap = 5; + + h2c->c0 = le32_encode_bits(rtwsta->mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w3 = le32_encode_bits(ba_bmap, CCTLINFO_G7_W3_BA_BMAP); + h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_BA_BMAP); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7); + int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index f1f119358b28..b9159278dd4b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3946,6 +3946,9 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, @@ -4103,6 +4106,18 @@ static inline int rtw89_chip_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, return chip->ops->h2c_assoc_cmac_tbl(rtwdev, vif, sta); } +static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->ops->h2c_ampdu_cmac_tbl) + return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + + return 0; +} + static inline int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 71d5e6f7bb64..21b42984fd8a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -660,6 +660,8 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mutex_lock(&rtwdev->mutex); clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); + clear_bit(tid, rtwsta->ampdu_map); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); mutex_unlock(&rtwdev->mutex); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -668,7 +670,9 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, set_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); rtwsta->ampdu_params[tid].agg_num = params->buf_size; rtwsta->ampdu_params[tid].amsdu = params->amsdu; + set_bit(tid, rtwsta->ampdu_map); rtw89_leave_ps_mode(rtwdev); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); mutex_unlock(&rtwdev->mutex); break; case IEEE80211_AMPDU_RX_START: diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 0688b4c576f9..63523ca3a0d7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2335,6 +2335,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index e15751f48fa3..3e8219974343 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2079,6 +2079,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 817ba15bba20..341adc067a96 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2504,6 +2504,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 892e3412a9e9..9c9800b2f299 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2849,6 +2849,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .resume_sch_tx = rtw89_mac_resume_sch_tx_v1, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v1, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index d0b11848dc93..acccd4be1528 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -824,6 +824,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .pwr_off_func = rtw8922a_pwr_off_func, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v2, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, + .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_g7, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, }; From 3d49ed071582c612815a20463e727a4b8b2875fd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:39 +0800 Subject: [PATCH 0123/2255] wifi: rtw89: fw: add H2C command to reset CMAC table for WiFi 7 Do reset on CMAC tables by mac_id, so we don't get random values when powering on. Therefore, add the same function for WiFi 7 chips. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 4 + drivers/net/wireless/realtek/rtw89/core.h | 3 + drivers/net/wireless/realtek/rtw89/fw.c | 90 ++++++++++++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 26 +++++- drivers/net/wireless/realtek/rtw89/mac.c | 2 +- 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 + 10 files changed, 126 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 745aa3e52fd3..cf819434a2a1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3345,6 +3345,10 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, return ret; } + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); + if (ret) + return ret; + rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index b795a06d8d13..27d314a1baed 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3198,6 +3198,9 @@ struct rtw89_chip_ops { int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); + int (*h2c_default_cmac_tbl)(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 3181cde5ab93..052dc3cc01eb 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2053,11 +2053,12 @@ static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev, #define H2C_CMC_TBL_LEN 68 int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) { const struct rtw89_chip_info *chip = rtwdev->chip; + u8 macid = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; struct sk_buff *skb; - u8 macid = rtwvif->mac_id; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); @@ -2098,6 +2099,91 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl); + +int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct rtw89_h2c_cctlinfo_ud_g7 *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 cmac g7\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w0 = le32_encode_bits(4, CCTLINFO_G7_W0_DATARATE); + h2c->m0 = cpu_to_le32(CCTLINFO_G7_W0_ALL); + + h2c->w1 = le32_encode_bits(4, CCTLINFO_G7_W1_DATA_RTY_LOWEST_RATE) | + le32_encode_bits(0xa, CCTLINFO_G7_W1_RTSRATE) | + le32_encode_bits(4, CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(CCTLINFO_G7_W1_ALL); + + h2c->m2 = cpu_to_le32(CCTLINFO_G7_W2_ALL); + + h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_ALL); + + h2c->w4 = le32_encode_bits(0xFFFF, CCTLINFO_G7_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_ALL); + + h2c->w5 = le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4); + h2c->m5 = cpu_to_le32(CCTLINFO_G7_W5_ALL); + + h2c->w6 = le32_encode_bits(0xb, CCTLINFO_G7_W6_RESP_REF_RATE); + h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ALL); + + h2c->w7 = le32_encode_bits(1, CCTLINFO_G7_W7_NC) | + le32_encode_bits(1, CCTLINFO_G7_W7_NR) | + le32_encode_bits(1, CCTLINFO_G7_W7_CB) | + le32_encode_bits(0x1, CCTLINFO_G7_W7_CSI_PARA_EN) | + le32_encode_bits(0xb, CCTLINFO_G7_W7_CSI_FIX_RATE); + h2c->m7 = cpu_to_le32(CCTLINFO_G7_W7_ALL); + + h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_ALL); + + h2c->w14 = le32_encode_bits(0, CCTLINFO_G7_W14_VO_CURR_RATE) | + le32_encode_bits(0, CCTLINFO_G7_W14_VI_CURR_RATE) | + le32_encode_bits(0, CCTLINFO_G7_W14_BE_CURR_RATE_L); + h2c->m14 = cpu_to_le32(CCTLINFO_G7_W14_ALL); + + h2c->w15 = le32_encode_bits(0, CCTLINFO_G7_W15_BE_CURR_RATE_H) | + le32_encode_bits(0, CCTLINFO_G7_W15_BK_CURR_RATE) | + le32_encode_bits(0, CCTLINFO_G7_W15_MGNT_CURR_RATE); + h2c->m15 = cpu_to_le32(CCTLINFO_G7_W15_ALL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7); static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, u8 *pads) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b9159278dd4b..b9e8fb693202 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1260,10 +1260,12 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W0_DISDATAFB BIT(26) #define CCTLINFO_G7_W0_NSTR_EN BIT(27) #define CCTLINFO_G7_W0_AMPDU_DENSITY GENMASK(31, 28) +#define CCTLINFO_G7_W0_ALL (GENMASK(31, 20) | GENMASK(18, 0)) #define CCTLINFO_G7_W1_DATA_RTY_LOWEST_RATE GENMASK(11, 0) #define CCTLINFO_G7_W1_RTS_TXCNT_LMT GENMASK(15, 12) #define CCTLINFO_G7_W1_RTSRATE GENMASK(27, 16) #define CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE GENMASK(31, 28) +#define CCTLINFO_G7_W1_ALL GENMASK(31, 0) #define CCTLINFO_G7_W2_DATA_TX_CNT_LMT GENMASK(5, 0) #define CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL BIT(6) #define CCTLINFO_G7_W2_MAX_AGG_NUM_SEL BIT(7) @@ -1276,6 +1278,7 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W2_AMPDU_MAX_LEN GENMASK(26, 16) #define CCTLINFO_G7_W2_UL_MU_DIS BIT(27) #define CCTLINFO_G7_W2_AMPDU_MAX_TIME GENMASK(31, 28) +#define CCTLINFO_G7_W2_ALL GENMASK(31, 0) #define CCTLINFO_G7_W3_MAX_AGG_NUM GENMASK(7, 0) #define CCTLINFO_G7_W3_DATA_BW GENMASK(10, 8) #define CCTLINFO_G7_W3_DATA_BW_ER BIT(11) @@ -1289,6 +1292,7 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W3_AMPDU_LEN_SEL BIT(29) #define CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL BIT(30) #define CCTLINFO_G7_W3_LSIG_TXOP_EN BIT(31) +#define CCTLINFO_G7_W3_ALL GENMASK(31, 0) #define CCTLINFO_G7_W4_MULTI_PORT_ID GENMASK(2, 0) #define CCTLINFO_G7_W4_BYPASS_PUNC BIT(3) #define CCTLINFO_G7_W4_MBSSID GENMASK(7, 4) @@ -1300,6 +1304,7 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W4_A_CTRL_BSR BIT(14) #define CCTLINFO_G7_W4_A_CTRL_CAS BIT(15) #define CCTLINFO_G7_W4_ACT_SUBCH_CBW GENMASK(31, 16) +#define CCTLINFO_G7_W4_ALL (GENMASK(31, 14) | GENMASK(12, 0)) #define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0 GENMASK(1, 0) #define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1 GENMASK(3, 2) #define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2 GENMASK(5, 4) @@ -1308,9 +1313,11 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W5_SR_RATE GENMASK(14, 10) #define CCTLINFO_G7_W5_TID_DISABLE GENMASK(23, 16) #define CCTLINFO_G7_W5_ADDR_CAM_INDEX GENMASK(31, 24) +#define CCTLINFO_G7_W5_ALL (GENMASK(31, 16) | GENMASK(14, 0)) #define CCTLINFO_G7_W6_AID12_PAID GENMASK(11, 0) #define CCTLINFO_G7_W6_RESP_REF_RATE GENMASK(23, 12) #define CCTLINFO_G7_W6_ULDL BIT(31) +#define CCTLINFO_G7_W6_ALL (BIT(31) | GENMASK(23, 0)) #define CCTLINFO_G7_W7_NC GENMASK(2, 0) #define CCTLINFO_G7_W7_NR GENMASK(5, 3) #define CCTLINFO_G7_W7_NG GENMASK(7, 6) @@ -1321,6 +1328,7 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W7_CSI_PARA_EN BIT(15) #define CCTLINFO_G7_W7_CSI_FIX_RATE GENMASK(27, 16) #define CCTLINFO_G7_W7_CSI_BW GENMASK(31, 29) +#define CCTLINFO_G7_W7_ALL (GENMASK(31, 29) | GENMASK(27, 13) | GENMASK(11, 0)) #define CCTLINFO_G7_W8_ALL_ACK_SUPPORT BIT(0) #define CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT BIT(1) #define CCTLINFO_G7_W8_BSR_OM_UPD_EN BIT(2) @@ -1331,13 +1339,16 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W8_CTRL_CNT_VLD BIT(7) #define CCTLINFO_G7_W8_CTRL_CNT GENMASK(11, 8) #define CCTLINFO_G7_W8_RESP_SEC_TYPE GENMASK(15, 12) +#define CCTLINFO_G7_W8_ALL GENMASK(15, 0) /* W9~13 are reserved */ #define CCTLINFO_G7_W14_VO_CURR_RATE GENMASK(11, 0) #define CCTLINFO_G7_W14_VI_CURR_RATE GENMASK(23, 12) #define CCTLINFO_G7_W14_BE_CURR_RATE_L GENMASK(31, 24) +#define CCTLINFO_G7_W14_ALL GENMASK(31, 0) #define CCTLINFO_G7_W15_BE_CURR_RATE_H GENMASK(3, 0) #define CCTLINFO_G7_W15_BK_CURR_RATE GENMASK(15, 4) #define CCTLINFO_G7_W15_MGNT_CURR_RATE GENMASK(27, 16) +#define CCTLINFO_G7_W15_ALL GENMASK(27, 0) static inline void SET_DCTL_MACID_V1(void *table, u32 val) { @@ -3939,7 +3950,11 @@ void rtw89_h2c_pkt_set_hdr(struct rtw89_dev *rtwdev, struct sk_buff *skb, u8 type, u8 cat, u8 class, u8 func, bool rack, bool dack, u32 len); int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); +int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); @@ -4089,6 +4104,15 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(rtwdev); } +static inline int rtw89_chip_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); +} + static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 0d5f91d4adee..cee1e512d264 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4497,7 +4497,7 @@ int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) if (ret) return ret; - ret = rtw89_fw_h2c_default_cmac_tbl(rtwdev, rtwvif); + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, NULL); if (ret) return ret; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 63523ca3a0d7..05750924d339 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2334,6 +2334,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 3e8219974343..e28ebefc6774 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2078,6 +2078,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 341adc067a96..8b8e7b54494a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2503,6 +2503,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 9c9800b2f299..9616167e3f6e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2848,6 +2848,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx_v1, .resume_sch_tx = rtw89_mac_resume_sch_tx_v1, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v1, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index acccd4be1528..46596f5583e2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -823,6 +823,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, .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, .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_g7, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, From 011e276865d32db280381a166ac9245451555459 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:40 +0800 Subject: [PATCH 0124/2255] wifi: rtw89: fw: add H2C command to reset DMAC table for WiFi 7 Reset DMAC table, so we get expected behavior instead of random values at early stage. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/cam.h | 13 +++++ drivers/net/wireless/realtek/rtw89/core.c | 4 ++ drivers/net/wireless/realtek/rtw89/core.h | 3 + drivers/net/wireless/realtek/rtw89/fw.c | 55 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 15 +++++ drivers/net/wireless/realtek/rtw89/mac.c | 4 ++ 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 + 11 files changed, 99 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index 9a2dd5999edb..fa09d11c345c 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -395,7 +395,9 @@ struct rtw89_h2c_dctlinfo_ud_v2 { #define DCTLINFO_V2_W0_HW_EXSEQ_MACID GENMASK(14, 8) #define DCTLINFO_V2_W0_QOS_DATA BIT(15) #define DCTLINFO_V2_W0_AES_IV_L GENMASK(31, 16) +#define DCTLINFO_V2_W0_ALL GENMASK(31, 0) #define DCTLINFO_V2_W1_AES_IV_H GENMASK(31, 0) +#define DCTLINFO_V2_W1_ALL GENMASK(31, 0) #define DCTLINFO_V2_W2_SEQ0 GENMASK(11, 0) #define DCTLINFO_V2_W2_SEQ1 GENMASK(23, 12) #define DCTLINFO_V2_W2_AMSDU_MAX_LEN GENMASK(26, 24) @@ -404,11 +406,13 @@ struct rtw89_h2c_dctlinfo_ud_v2 { #define DCTLINFO_V2_W2_WITH_LLC BIT(29) #define DCTLINFO_V2_W2_NAT25_EN BIT(30) #define DCTLINFO_V2_W2_IS_MLD BIT(31) +#define DCTLINFO_V2_W2_ALL GENMASK(31, 0) #define DCTLINFO_V2_W3_SEQ2 GENMASK(11, 0) #define DCTLINFO_V2_W3_SEQ3 GENMASK(23, 12) #define DCTLINFO_V2_W3_TGT_IND GENMASK(27, 24) #define DCTLINFO_V2_W3_TGT_IND_EN BIT(28) #define DCTLINFO_V2_W3_HTC_LB GENMASK(31, 29) +#define DCTLINFO_V2_W3_ALL GENMASK(31, 0) #define DCTLINFO_V2_W4_VLAN_TAG_SEL GENMASK(7, 5) #define DCTLINFO_V2_W4_HTC_ORDER BIT(8) #define DCTLINFO_V2_W4_SEC_KEY_ID GENMASK(10, 9) @@ -425,24 +429,33 @@ struct rtw89_h2c_dctlinfo_ud_v2 { #define DCTLINFO_V2_W4_SEC_ENT4_KEYID GENMASK(27, 26) #define DCTLINFO_V2_W4_SEC_ENT5_KEYID GENMASK(29, 28) #define DCTLINFO_V2_W4_SEC_ENT6_KEYID GENMASK(31, 30) +#define DCTLINFO_V2_W4_ALL GENMASK(31, 5) #define DCTLINFO_V2_W5_SEC_ENT7_KEYID GENMASK(1, 0) #define DCTLINFO_V2_W5_SEC_ENT8_KEYID GENMASK(3, 2) #define DCTLINFO_V2_W5_SEC_ENT_VALID_V1 GENMASK(23, 8) #define DCTLINFO_V2_W5_SEC_ENT0_V1 GENMASK(31, 24) +#define DCTLINFO_V2_W5_ALL (GENMASK(31, 8) | GENMASK(3, 0)) #define DCTLINFO_V2_W6_SEC_ENT1_V1 GENMASK(7, 0) #define DCTLINFO_V2_W6_SEC_ENT2_V1 GENMASK(15, 8) #define DCTLINFO_V2_W6_SEC_ENT3_V1 GENMASK(23, 16) #define DCTLINFO_V2_W6_SEC_ENT4_V1 GENMASK(31, 24) +#define DCTLINFO_V2_W6_ALL GENMASK(31, 0) #define DCTLINFO_V2_W7_SEC_ENT5_V1 GENMASK(7, 0) #define DCTLINFO_V2_W7_SEC_ENT6_V1 GENMASK(15, 8) #define DCTLINFO_V2_W7_SEC_ENT7 GENMASK(23, 16) #define DCTLINFO_V2_W7_SEC_ENT8 GENMASK(31, 24) +#define DCTLINFO_V2_W7_ALL GENMASK(31, 0) #define DCTLINFO_V2_W8_MLD_SMA_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W8_ALL GENMASK(31, 0) #define DCTLINFO_V2_W9_MLD_SMA_H_V1 GENMASK(15, 0) #define DCTLINFO_V2_W9_MLD_TMA_L_V1 GENMASK(31, 16) +#define DCTLINFO_V2_W9_ALL GENMASK(31, 0) #define DCTLINFO_V2_W10_MLD_TMA_H_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W10_ALL GENMASK(31, 0) #define DCTLINFO_V2_W11_MLD_TA_BSSID_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W11_ALL GENMASK(31, 0) #define DCTLINFO_V2_W12_MLD_TA_BSSID_H_V1 GENMASK(15, 0) +#define DCTLINFO_V2_W12_ALL GENMASK(15, 0) int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index cf819434a2a1..347703b68dfd 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3349,6 +3349,10 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, if (ret) return ret; + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + if (ret) + return ret; + rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 27d314a1baed..80f67f1b0679 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3207,6 +3207,9 @@ struct rtw89_chip_ops { int (*h2c_ampdu_cmac_tbl)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); + int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); int (*h2c_update_beacon)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 052dc3cc01eb..255be99b3630 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1525,6 +1525,61 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2); +int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct rtw89_h2c_dctlinfo_ud_v2 *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 dctl v2\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, DCTLINFO_V2_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V2_C0_OP); + + h2c->m0 = cpu_to_le32(DCTLINFO_V2_W0_ALL); + h2c->m1 = cpu_to_le32(DCTLINFO_V2_W1_ALL); + h2c->m2 = cpu_to_le32(DCTLINFO_V2_W2_ALL); + h2c->m3 = cpu_to_le32(DCTLINFO_V2_W3_ALL); + h2c->m4 = cpu_to_le32(DCTLINFO_V2_W4_ALL); + h2c->m5 = cpu_to_le32(DCTLINFO_V2_W5_ALL); + h2c->m6 = cpu_to_le32(DCTLINFO_V2_W6_ALL); + h2c->m7 = cpu_to_le32(DCTLINFO_V2_W7_ALL); + h2c->m8 = cpu_to_le32(DCTLINFO_V2_W8_ALL); + h2c->m9 = cpu_to_le32(DCTLINFO_V2_W9_ALL); + h2c->m10 = cpu_to_le32(DCTLINFO_V2_W10_ALL); + h2c->m11 = cpu_to_le32(DCTLINFO_V2_W11_ALL); + h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V2, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2); + int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b9e8fb693202..b5f724087954 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3955,6 +3955,9 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); +int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); @@ -4113,6 +4116,18 @@ static inline int rtw89_chip_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); } +static inline int rtw89_chip_h2c_default_dmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->ops->h2c_default_dmac_tbl) + return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + + return 0; +} + static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index cee1e512d264..16f21406fbd2 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4501,6 +4501,10 @@ int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) if (ret) return ret; + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, NULL); + if (ret) + return ret; + return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 05750924d339..40020d0ebbdf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2337,6 +2337,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index e28ebefc6774..726b08ca5897 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2081,6 +2081,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 8b8e7b54494a..b3ad84cfad95 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2506,6 +2506,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 9616167e3f6e..cbc896a29fb4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2851,6 +2851,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 46596f5583e2..7ded6f431309 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -826,6 +826,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl_g7, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_g7, + .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, }; From 85eacdcabd0f9293fd20e598424a1cf990542b73 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:41 +0800 Subject: [PATCH 0125/2255] wifi: rtw89: fw: use struct to fill JOIN H2C command The JOIN command is used to tell firmware an new station is joining, and create an entry for it. This patch is only to convert to set data via struct, and don't change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 37 ++++++------ drivers/net/wireless/realtek/rtw89/fw.h | 79 +++++-------------------- 2 files changed, 36 insertions(+), 80 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 255be99b3630..03825fe1d9c2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2904,7 +2904,6 @@ fail: return ret; } -#define H2C_JOIN_INFO_LEN 4 int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, bool dis_conn) { @@ -2912,6 +2911,8 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; u8 self_role = rtwvif->self_role; u8 net_type = rtwvif->net_type; + struct rtw89_h2c_join *h2c; + u32 len = sizeof(*h2c); int ret; if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) { @@ -2919,30 +2920,32 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type; } - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); return -ENOMEM; } - skb_put(skb, H2C_JOIN_INFO_LEN); - SET_JOININFO_MACID(skb->data, mac_id); - SET_JOININFO_OP(skb->data, dis_conn); - SET_JOININFO_BAND(skb->data, rtwvif->mac_idx); - SET_JOININFO_WMM(skb->data, rtwvif->wmm); - SET_JOININFO_TGR(skb->data, rtwvif->trigger); - SET_JOININFO_ISHESTA(skb->data, 0); - SET_JOININFO_DLBW(skb->data, 0); - SET_JOININFO_TF_MAC_PAD(skb->data, 0); - SET_JOININFO_DL_T_PE(skb->data, 0); - SET_JOININFO_PORT_ID(skb->data, rtwvif->port); - SET_JOININFO_NET_TYPE(skb->data, net_type); - SET_JOININFO_WIFI_ROLE(skb->data, rtwvif->wifi_role); - SET_JOININFO_SELF_ROLE(skb->data, self_role); + skb_put(skb, len); + h2c = (struct rtw89_h2c_join *)skb->data; + + h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_JOININFO_W0_MACID) | + le32_encode_bits(dis_conn, RTW89_H2C_JOININFO_W0_OP) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_JOININFO_W0_BAND) | + le32_encode_bits(rtwvif->wmm, RTW89_H2C_JOININFO_W0_WMM) | + le32_encode_bits(rtwvif->trigger, RTW89_H2C_JOININFO_W0_TGR) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_ISHESTA) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DLBW) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_TF_MAC_PAD) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DL_T_PE) | + le32_encode_bits(rtwvif->port, RTW89_H2C_JOININFO_W0_PORT_ID) | + le32_encode_bits(net_type, RTW89_H2C_JOININFO_W0_NET_TYPE) | + le32_encode_bits(rtwvif->wifi_role, RTW89_H2C_JOININFO_W0_WIFI_ROLE) | + le32_encode_bits(self_role, RTW89_H2C_JOININFO_W0_SELF_ROLE); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, H2C_FUNC_MAC_JOININFO, 0, 1, - H2C_JOIN_INFO_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b5f724087954..036fe4f983e6 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1747,70 +1747,23 @@ static inline void SET_FWROLE_MAINTAIN_WIFI_ROLE(void *h2c, u32 val) le32p_replace_bits((__le32 *)h2c, val, GENMASK(16, 13)); } -static inline void SET_JOININFO_MACID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); -} +struct rtw89_h2c_join { + __le32 w0; +} __packed; -static inline void SET_JOININFO_OP(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(8)); -} - -static inline void SET_JOININFO_BAND(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(9)); -} - -static inline void SET_JOININFO_WMM(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(11, 10)); -} - -static inline void SET_JOININFO_TGR(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(12)); -} - -static inline void SET_JOININFO_ISHESTA(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(13)); -} - -static inline void SET_JOININFO_DLBW(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 14)); -} - -static inline void SET_JOININFO_TF_MAC_PAD(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(17, 16)); -} - -static inline void SET_JOININFO_DL_T_PE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(20, 18)); -} - -static inline void SET_JOININFO_PORT_ID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 21)); -} - -static inline void SET_JOININFO_NET_TYPE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(25, 24)); -} - -static inline void SET_JOININFO_WIFI_ROLE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(29, 26)); -} - -static inline void SET_JOININFO_SELF_ROLE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 30)); -} +#define RTW89_H2C_JOININFO_W0_MACID GENMASK(7, 0) +#define RTW89_H2C_JOININFO_W0_OP BIT(8) +#define RTW89_H2C_JOININFO_W0_BAND BIT(9) +#define RTW89_H2C_JOININFO_W0_WMM GENMASK(11, 10) +#define RTW89_H2C_JOININFO_W0_TGR BIT(12) +#define RTW89_H2C_JOININFO_W0_ISHESTA BIT(13) +#define RTW89_H2C_JOININFO_W0_DLBW GENMASK(15, 14) +#define RTW89_H2C_JOININFO_W0_TF_MAC_PAD GENMASK(17, 16) +#define RTW89_H2C_JOININFO_W0_DL_T_PE GENMASK(20, 18) +#define RTW89_H2C_JOININFO_W0_PORT_ID GENMASK(23, 21) +#define RTW89_H2C_JOININFO_W0_NET_TYPE GENMASK(25, 24) +#define RTW89_H2C_JOININFO_W0_WIFI_ROLE GENMASK(29, 26) +#define RTW89_H2C_JOININFO_W0_SELF_ROLE GENMASK(31, 30) struct rtw89_h2c_notify_dbcc { __le32 w0; From 3832a9c40b356500c5b85a6fdf9577c590fcd637 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 15 Jan 2024 11:37:42 +0800 Subject: [PATCH 0126/2255] wifi: rtw89: fw: extend JOIN H2C command to support WiFi 7 chips WiFi 7 chips will support MLD, so there are more fields about that. But currently we don't support MLD yet, just define fields and bits by this patch ahead, and fill STA_TYPE only. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240115033742.16372-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 45 +++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 23 +++++++++++++ 2 files changed, 68 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 03825fe1d9c2..362ea2e228d2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2904,17 +2904,51 @@ fail: return ret; } +static enum rtw89_fw_sta_type +rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + + if (!sta) + goto by_vif; + + if (sta->deflink.eht_cap.has_eht) + return RTW89_FW_BE_STA; + else if (sta->deflink.he_cap.has_he) + return RTW89_FW_AX_STA; + else + return RTW89_FW_N_AC_STA; + +by_vif: + if (vif->bss_conf.eht_support) + return RTW89_FW_BE_STA; + else if (vif->bss_conf.he_support) + return RTW89_FW_AX_STA; + else + return RTW89_FW_N_AC_STA; +} + int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, bool dis_conn) { struct sk_buff *skb; u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; u8 self_role = rtwvif->self_role; + enum rtw89_fw_sta_type sta_type; u8 net_type = rtwvif->net_type; + struct rtw89_h2c_join_v1 *h2c_v1; struct rtw89_h2c_join *h2c; u32 len = sizeof(*h2c); + bool format_v1 = false; int ret; + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { + len = sizeof(*h2c_v1); + format_v1 = true; + } + if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) { self_role = RTW89_SELF_ROLE_AP_CLIENT; net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type; @@ -2942,6 +2976,17 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, le32_encode_bits(rtwvif->wifi_role, RTW89_H2C_JOININFO_W0_WIFI_ROLE) | le32_encode_bits(self_role, RTW89_H2C_JOININFO_W0_SELF_ROLE); + if (!format_v1) + goto done; + + h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data; + + sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif, rtwsta); + + h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE); + h2c_v1->w2 = 0; + +done: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, H2C_FUNC_MAC_JOININFO, 0, 1, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 036fe4f983e6..7a80f45ce27b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1747,10 +1747,22 @@ static inline void SET_FWROLE_MAINTAIN_WIFI_ROLE(void *h2c, u32 val) le32p_replace_bits((__le32 *)h2c, val, GENMASK(16, 13)); } +enum rtw89_fw_sta_type { /* value of RTW89_H2C_JOININFO_W1_STA_TYPE */ + RTW89_FW_N_AC_STA = 0, + RTW89_FW_AX_STA = 1, + RTW89_FW_BE_STA = 2, +}; + struct rtw89_h2c_join { __le32 w0; } __packed; +struct rtw89_h2c_join_v1 { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; + #define RTW89_H2C_JOININFO_W0_MACID GENMASK(7, 0) #define RTW89_H2C_JOININFO_W0_OP BIT(8) #define RTW89_H2C_JOININFO_W0_BAND BIT(9) @@ -1764,6 +1776,17 @@ struct rtw89_h2c_join { #define RTW89_H2C_JOININFO_W0_NET_TYPE GENMASK(25, 24) #define RTW89_H2C_JOININFO_W0_WIFI_ROLE GENMASK(29, 26) #define RTW89_H2C_JOININFO_W0_SELF_ROLE GENMASK(31, 30) +#define RTW89_H2C_JOININFO_W1_STA_TYPE GENMASK(2, 0) +#define RTW89_H2C_JOININFO_W1_IS_MLD BIT(3) +#define RTW89_H2C_JOININFO_W1_MAIN_MACID GENMASK(11, 4) +#define RTW89_H2C_JOININFO_W1_MLO_MODE BIT(12) +#define RTW89_H2C_JOININFO_W1_EMLSR_CAB BIT(13) +#define RTW89_H2C_JOININFO_W1_NSTR_EN BIT(14) +#define RTW89_H2C_JOININFO_W1_INIT_PWR_STATE BIT(15) +#define RTW89_H2C_JOININFO_W1_EMLSR_PADDING GENMASK(18, 16) +#define RTW89_H2C_JOININFO_W1_EMLSR_TRANS_DELAY GENMASK(21, 19) +#define RTW89_H2C_JOININFO_W2_MACID_EXT GENMASK(7, 0) +#define RTW89_H2C_JOININFO_W2_MAIN_MACID_EXT GENMASK(15, 8) struct rtw89_h2c_notify_dbcc { __le32 w0; From 0635d73d85c1264060a92cbe1c53b7f010b6dd4a Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 13 Jan 2024 01:42:29 +0200 Subject: [PATCH 0127/2255] wifi: rtlwifi: rtl8192de: Don't read register in _rtl92de_query_rxphystatus Instead of reading bit 9 of RFPGA0_XA_HSSIPARAMETER2 every time a frame is received, just use rtlphy->cck_high_power, which is initialised in _rtl92d_phy_bb_config(). That bit never changes anyway. With this change _rtl92de_query_rxphystatus() can be shared with the upcoming USB driver. The USB driver can't read registers in this function because register reading can sleep. Compile tested only. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/19a3e023-0eaa-4096-9f78-a2c8e909cb54@gmail.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c index 02ac69c08ed3..192982ec8152 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c @@ -42,6 +42,7 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, bool packet_beacon) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); struct phy_sts_cck_8192d *cck_buf; s8 rx_pwr_all, rx_pwr[4]; @@ -62,9 +63,7 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, u8 report, cck_highpwr; cck_buf = (struct phy_sts_cck_8192d *)p_drvinfo; if (ppsc->rfpwr_state == ERFON) - cck_highpwr = (u8) rtl_get_bbreg(hw, - RFPGA0_XA_HSSIPARAMETER2, - BIT(9)); + cck_highpwr = rtlphy->cck_high_power; else cck_highpwr = false; if (!cck_highpwr) { From 52284952cbf38c3026c2c61e8582ec01f8ee61c7 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Mon, 15 Jan 2024 15:56:31 +0100 Subject: [PATCH 0128/2255] wifi: wilc1000: fix driver_handler when committing initial configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During firmware initial configuration in wilc_init_fw_config, the special driver_handler 0 should be used instead of targeting a specific virtual interface (either 1 or 2) The issue does not seem to have real consequence (both virtual interfaces seems to answer correctly to a Add Block Ack request with the Immediate policy), but lets make everything homogeneous Signed-off-by: Ajay Singh Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240115-wilc_1000_fixes-v1-2-54d29463a738@bootlin.com --- drivers/net/wireless/microchip/wilc1000/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 91d71e0f7ef2..7ea538f2d623 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -416,7 +416,7 @@ static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) b = 1; if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1, - 1, 1)) + 1, 0)) goto fail; return 0; From 328efda22af81130c2ad981c110518cb29ff2f1d Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Mon, 15 Jan 2024 15:56:32 +0100 Subject: [PATCH 0129/2255] wifi: wilc1000: do not realloc workqueue everytime an interface is added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 09ed8bfc5215 ("wilc1000: Rename workqueue from "WILC_wq" to "NETDEV-wq"") moved workqueue creation in wilc_netdev_ifc_init in order to set the interface name in the workqueue name. However, while the driver needs only one workqueue, the wilc_netdev_ifc_init is called each time we add an interface over a phy, which in turns overwrite the workqueue with a new one. This can be observed with the following commands: for i in $(seq 0 10) do iw phy phy0 interface add wlan1 type managed iw dev wlan1 del done ps -eo pid,comm|grep wlan 39 kworker/R-wlan0 98 kworker/R-wlan1 102 kworker/R-wlan1 105 kworker/R-wlan1 108 kworker/R-wlan1 111 kworker/R-wlan1 114 kworker/R-wlan1 117 kworker/R-wlan1 120 kworker/R-wlan1 123 kworker/R-wlan1 126 kworker/R-wlan1 129 kworker/R-wlan1 Fix this leakage by putting back hif_workqueue allocation in wilc_cfg80211_init. Regarding the workqueue name, it is indeed relevant to set it lowercase, however it is not attached to a specific netdev, so enforcing netdev name in the name is not so relevant. Still, enrich the name with the wiphy name to make it clear which phy is using the workqueue. Fixes: 09ed8bfc5215 ("wilc1000: Rename workqueue from "WILC_wq" to "NETDEV-wq"") Signed-off-by: Ajay Singh Co-developed-by: Alexis Lothoré Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240115-wilc_1000_fixes-v1-3-54d29463a738@bootlin.com --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 11 ++++++++++- drivers/net/wireless/microchip/wilc1000/netdev.c | 10 +--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index ad2509d8c99a..2d0474e6404e 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1804,15 +1804,24 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, INIT_LIST_HEAD(&wl->rxq_head.list); INIT_LIST_HEAD(&wl->vif_list); + wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + wiphy_name(wl->wiphy)); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto free_cfg; + } vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE, NL80211_IFTYPE_STATION, false); if (IS_ERR(vif)) { ret = PTR_ERR(vif); - goto free_cfg; + goto free_hq; } return 0; +free_hq: + destroy_workqueue(wl->hif_workqueue); + free_cfg: wilc_wlan_cfg_deinit(wl); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 7ea538f2d623..3be3c1754770 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -989,13 +989,6 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, goto error; } - wl->hif_workqueue = alloc_ordered_workqueue("%s-wq", WQ_MEM_RECLAIM, - ndev->name); - if (!wl->hif_workqueue) { - ret = -ENOMEM; - goto unregister_netdev; - } - ndev->needs_free_netdev = true; vif->iftype = vif_type; vif->idx = wilc_get_available_idx(wl); @@ -1008,12 +1001,11 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, return vif; -unregister_netdev: +error: if (rtnl_locked) cfg80211_unregister_netdevice(ndev); else unregister_netdev(ndev); - error: free_netdev(ndev); return ERR_PTR(ret); } From a4f1a05b832e212f8e5b7adcb1b5e8c5c072ae88 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Mon, 15 Jan 2024 15:56:33 +0100 Subject: [PATCH 0130/2255] wifi: wilc1000: fix incorrect power down sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the correct register configuration when the WILC chip is down so the successive interface up operation is successful. The modified registers values during chip down helps to avoid the "FW not responding" debug message which sometimes occurs because of temporary bus communication failure during the next start. Also, make sure on first communication with the chip that it is indeed woken up. Reported-by: Michael Walle Closes: https://lore.kernel.org/linux-wireless/20221026085415.6jgwrhq4sunqaypm@0002.3ffe.de/ Signed-off-by: Ajay Singh Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240115-wilc_1000_fixes-v1-4-54d29463a738@bootlin.com --- .../net/wireless/microchip/wilc1000/wlan.c | 35 +++++++++++-------- .../net/wireless/microchip/wilc1000/wlan.h | 6 ++++ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 9eb115c79c90..6b2f2269ddf8 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -1198,6 +1198,24 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, ®); + if (ret) + goto release; + + reg &= ~WILC_GLOBAL_MODE_ENABLE_WIFI; + ret = wilc->hif_func->hif_write_reg(wilc, GLOBAL_MODE_CONTROL, reg); + if (ret) + goto release; + + ret = wilc->hif_func->hif_read_reg(wilc, PWR_SEQ_MISC_CTRL, ®); + if (ret) + goto release; + + reg &= ~WILC_PWR_SEQ_ENABLE_WIFI_SLEEP; + ret = wilc->hif_func->hif_write_reg(wilc, PWR_SEQ_MISC_CTRL, reg); + if (ret) + goto release; + ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); if (ret) { netdev_err(vif->ndev, "Error while reading reg\n"); @@ -1211,19 +1229,6 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) goto release; } - ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); - if (ret) { - netdev_err(vif->ndev, "Error while reading reg\n"); - goto release; - } - reg = BIT(0); - - ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg); - if (ret) { - netdev_err(vif->ndev, "Error while writing reg\n"); - goto release; - } - ret = 0; release: /* host comm is disabled - we can't issue sleep command anymore: */ @@ -1410,7 +1415,7 @@ static int init_chip(struct net_device *dev) struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); chipid = wilc_get_chipid(wilc, true); @@ -1440,7 +1445,7 @@ static int init_chip(struct net_device *dev) } release: - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); return ret; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index a72cd5cac81d..f02775f7e41f 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -156,6 +156,12 @@ #define WILC_GP_REG_0 0x149c #define WILC_GP_REG_1 0x14a0 +#define GLOBAL_MODE_CONTROL 0x1614 +#define PWR_SEQ_MISC_CTRL 0x3008 + +#define WILC_GLOBAL_MODE_ENABLE_WIFI BIT(0) +#define WILC_PWR_SEQ_ENABLE_WIFI_SLEEP BIT(28) + #define WILC_HAVE_SDIO_IRQ_GPIO BIT(0) #define WILC_HAVE_USE_PMU BIT(1) #define WILC_HAVE_SLEEP_CLK_SRC_RTC BIT(2) From 12cfc9c8d3faf887a202c89bc312202445fca7e8 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Mon, 15 Jan 2024 15:56:34 +0100 Subject: [PATCH 0131/2255] wifi: wilc1000: fix multi-vif management when deleting a vif MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding then removing a second vif currently makes the first vif not working anymore. This is visible for example when we have a first interface connected to some access point: - create a wpa_supplicant.conf with some AP credentials - wpa_supplicant -Dnl80211 -c /etc/wpa_supplicant.conf -i wlan0 - dhclient wlan0 - iw phy phy0 interface add wlan1 type managed - iw dev wlan1 del wlan0 does not manage properly traffic anymore (eg: ping not working) This is due to vif mode being incorrectly reconfigured with some default values in del_virtual_intf, affecting by default first vif. Prevent first vif from being affected on second vif removal by removing vif mode change command in del_virtual_intf Fixes: 9bc061e88054 ("staging: wilc1000: added support to dynamically add/remove interfaces") Signed-off-by: Ajay Singh Co-developed-by: Alexis Lothoré Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240115-wilc_1000_fixes-v1-5-54d29463a738@bootlin.com --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index 2d0474e6404e..f03fd15c0c97 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1609,7 +1609,6 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) cfg80211_unregister_netdevice(vif->ndev); vif->monitor_flag = 0; - wilc_set_operation_mode(vif, 0, 0, 0); mutex_lock(&wl->vif_mutex); list_del_rcu(&vif->list); wl->vif_num--; From 426e7b4773921d07ab4ab8ba16fbad396d6c9971 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 Jan 2024 16:09:44 +0800 Subject: [PATCH 0132/2255] wifi: rtl8xxxu: convert EN_DESC_ID of TX descriptor to le32 type Fields of TX descriptor are little-endian order, so correct EN_DESC_ID field to le32 type. Fixes: b837f78fbffa ("wifi: rtl8xxxu: add hw crypto support for AP mode") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401161318.YtXoCkjU-lkp@intel.com/ Cc: Martin Kaistra Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240116080945.20172-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 521faa48803c..98700f3ad6f9 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5619,7 +5619,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, break; } if (bmc && rtlvif->hw_key_idx != 0xff) { - tx_desc->txdw1 |= TXDESC_EN_DESC_ID; + tx_desc->txdw1 |= cpu_to_le32(TXDESC_EN_DESC_ID); macid = rtlvif->hw_key_idx; } } From 92c7428f942da7dfcdc629b05b5114f80822d7a4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 Jan 2024 16:09:45 +0800 Subject: [PATCH 0133/2255] wifi: rtl8xxxu: make instances of iface limit and combination to be static const rtl8xxxu_limits and rtl8xxxu_combinations can be static const, so add modifiers as desire. Otherwise, Sparse reports warnings rtl8xxxu_core.c:7677:30: warning: symbol 'rtl8xxxu_limits' was not declared. Should it be static? rtl8xxxu_core.c:7682:36: warning: symbol 'rtl8xxxu_combinations' was not declared. Should it be static? Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240116080945.20172-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 98700f3ad6f9..3b954c2fe448 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7674,12 +7674,12 @@ static void rtl8xxxu_deinit_led(struct rtl8xxxu_priv *priv) led_classdev_unregister(led); } -struct ieee80211_iface_limit rtl8xxxu_limits[] = { +static const struct ieee80211_iface_limit rtl8xxxu_limits[] = { { .max = 2, .types = BIT(NL80211_IFTYPE_STATION), }, { .max = 1, .types = BIT(NL80211_IFTYPE_AP), }, }; -struct ieee80211_iface_combination rtl8xxxu_combinations[] = { +static const struct ieee80211_iface_combination rtl8xxxu_combinations[] = { { .limits = rtl8xxxu_limits, .n_limits = ARRAY_SIZE(rtl8xxxu_limits), From 47f0e32ffe4ecfa038eadffad7f15831d0d843fb Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Mon, 14 Aug 2023 12:36:21 +0300 Subject: [PATCH 0134/2255] wifi: brcmsmac: phy: Remove unreachable code wlc_phy_txpwr_srom_read_nphy() in wlc_phy_attach_nphy() can not return false, so it's impossible to get true value in this if-statement. Also change those functions return types to void since no one using it. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Artem Chernyshev Reviewed-by: Jonas Gorski Signed-off-by: Kalle Valo Link: https://msgid.link/20230814093621.289754-1-artem.chernyshev@red-soft.ru --- .../broadcom/brcm80211/brcmsmac/phy/phy_cmn.c | 3 +-- .../broadcom/brcm80211/brcmsmac/phy/phy_int.h | 2 +- .../wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c | 11 +++-------- 3 files changed, 5 insertions(+), 11 deletions(-) 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 ccc621b8ed9f..07f83ff5a54a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -551,8 +551,7 @@ wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core, if (!pi->phycal_timer) goto err; - if (!wlc_phy_attach_nphy(pi)) - goto err; + wlc_phy_attach_nphy(pi); } else if (ISLCNPHY(pi)) { if (!wlc_phy_attach_lcnphy(pi)) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h index 8668fa5558a2..70a9ec050717 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h @@ -941,7 +941,7 @@ void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag); void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi); void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi); -bool wlc_phy_attach_nphy(struct brcms_phy *pi); +void wlc_phy_attach_nphy(struct brcms_phy *pi); bool wlc_phy_attach_lcnphy(struct brcms_phy *pi); void wlc_phy_detach_lcnphy(struct brcms_phy *pi); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index 8580a2754789..cd9b502a6a9f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -14546,7 +14546,7 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) wlc_phy_txpwr_apply_nphy(pi); } -static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) +static void wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) { struct ssb_sprom *sprom = &pi->d11core->bus->sprom; @@ -14595,11 +14595,9 @@ static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) pi->phycal_tempdelta = 0; wlc_phy_txpwr_srom_read_ppr_nphy(pi); - - return true; } -bool wlc_phy_attach_nphy(struct brcms_phy *pi) +void wlc_phy_attach_nphy(struct brcms_phy *pi) { uint i; @@ -14645,10 +14643,7 @@ bool wlc_phy_attach_nphy(struct brcms_phy *pi) pi->pi_fptr.chanset = wlc_phy_chanspec_set_nphy; pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_nphy; - if (!wlc_phy_txpwr_srom_read_nphy(pi)) - return false; - - return true; + wlc_phy_txpwr_srom_read_nphy(pi); } static s32 get_rf_pwr_offset(struct brcms_phy *pi, s16 pga_gn, s16 pad_gn) From 899c0e8a221983ce20e887932dfed7955662609c Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Mon, 14 Aug 2023 20:42:12 +0800 Subject: [PATCH 0135/2255] wifi: mwifiex: Use helpers to check multicast addresses Use is_multicast_ether_addr() and is_unicast_ether_addr() to check the addresses. Signed-off-by: Ruan Jinjie Signed-off-by: Kalle Valo Link: https://msgid.link/20230814124212.302738-3-ruanjinjie@huawei.com --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/marvell/mwifiex/wmm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 3604abcbcff9..b909a7665e9c 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3359,7 +3359,7 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, } if (!wowlan->patterns[i].pkt_offset) { - if (!(byte_seq[0] & 0x01) && + if (is_unicast_ether_addr(byte_seq) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; continue; diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 00a5679b5c51..8558995e8fc7 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -871,7 +871,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, } } else { memcpy(ra, skb->data, ETH_ALEN); - if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb)) + if (is_multicast_ether_addr(ra) || mwifiex_is_skb_mgmt_frame(skb)) eth_broadcast_addr(ra); ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); } From 50180c7f8e3de7c2d87f619131776598fcb1478d Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sun, 3 Sep 2023 11:02:15 +0800 Subject: [PATCH 0136/2255] wifi: mwifiex: debugfs: Drop unnecessary error check for debugfs_create_dir() debugfs_create_dir() returns ERR_PTR and never return NULL. As Russell suggested, this patch removes the error checking for debugfs_create_dir(). This is because the DebugFS kernel API is developed in a way that the caller can safely ignore the errors that occur during the creation of DebugFS nodes. The debugfs APIs have a IS_ERR() judge in start_creating() which can handle it gracefully. So these checks are unnecessary. Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") Signed-off-by: Jinjie Ruan Suggested-by: Russell King (Oracle) Signed-off-by: Kalle Valo Link: https://msgid.link/20230903030216.1509013-3-ruanjinjie@huawei.com --- drivers/net/wireless/marvell/mwifiex/debugfs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index f9c9fec7c792..d14a0f4c1b6d 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -970,9 +970,6 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, mwifiex_dfs_dir); - if (!priv->dfs_dev_dir) - return; - MWIFIEX_DFS_ADD_FILE(info); MWIFIEX_DFS_ADD_FILE(debug); MWIFIEX_DFS_ADD_FILE(getlog); From 173b0fb47c3dbd1e489cb449422c1037076a66d7 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 19 Oct 2023 10:06:09 +0300 Subject: [PATCH 0137/2255] wifi: rt2x00: simplify rt2x00crypto_rx_insert_iv() In 'rt2x00crypto_rx_insert_iv()', added alignment can't exceed 3 bytes and ICV size is either 4 or 8 bytes, so skb space adjustment may be simplified. Compile tested only. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://msgid.link/20231019070750.17911-1-dmantipov@yandex.ru --- drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c b/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c index ad95f9eba301..1000fbfb94b8 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c @@ -197,10 +197,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, transfer += header_length; } else { skb_push(skb, iv_len + align); - if (align < icv_len) - skb_put(skb, icv_len - align); - else if (align > icv_len) - skb_trim(skb, rxdesc->size + iv_len + icv_len); + skb_put(skb, icv_len - align); /* Move ieee80211 header */ memmove(skb->data + transfer, From 0f7352557a35ab7888bc7831411ec8a3cbe20d78 Mon Sep 17 00:00:00 2001 From: Zheng Wang Date: Sun, 7 Jan 2024 08:25:04 +0100 Subject: [PATCH 0138/2255] wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach This is the candidate patch of CVE-2023-47233 : https://nvd.nist.gov/vuln/detail/CVE-2023-47233 In brcm80211 driver,it starts with the following invoking chain to start init a timeout worker: ->brcmf_usb_probe ->brcmf_usb_probe_cb ->brcmf_attach ->brcmf_bus_started ->brcmf_cfg80211_attach ->wl_init_priv ->brcmf_init_escan ->INIT_WORK(&cfg->escan_timeout_work, brcmf_cfg80211_escan_timeout_worker); If we disconnect the USB by hotplug, it will call brcmf_usb_disconnect to make cleanup. The invoking chain is : brcmf_usb_disconnect ->brcmf_usb_disconnect_cb ->brcmf_detach ->brcmf_cfg80211_detach ->kfree(cfg); While the timeout woker may still be running. This will cause a use-after-free bug on cfg in brcmf_cfg80211_escan_timeout_worker. Fix it by deleting the timer and canceling the worker in brcmf_cfg80211_detach. Fixes: e756af5b30b0 ("brcmfmac: add e-scan support.") Signed-off-by: Zheng Wang Cc: stable@vger.kernel.org [arend.vanspriel@broadcom.com: keep timer delete as is and cancel work just before free] Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240107072504.392713-1-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 133c5ea6429c..52df03243c9f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1179,8 +1179,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, scan_request = cfg->scan_request; cfg->scan_request = NULL; - if (timer_pending(&cfg->escan_timeout)) - del_timer_sync(&cfg->escan_timeout); + timer_delete_sync(&cfg->escan_timeout); if (fw_abort) { /* Do a scan abort to stop the driver's scan engine */ @@ -8435,6 +8434,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); wl_deinit_priv(cfg); + cancel_work_sync(&cfg->escan_timeout_work); brcmf_free_wiphy(cfg->wiphy); kfree(cfg); } From 31343230abb1683e8afb254e6b13a7a7fd01fcac Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 3 Jan 2024 10:57:01 +0100 Subject: [PATCH 0139/2255] wifi: brcmfmac: export firmware interface functions With multi-vendor support the vendor-specific module may need to use the firmware interface functions so export them using the macro BRCMF_EXPORT_SYMBOL_GPL() which exports them to driver namespace. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-2-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 4 +- .../broadcom/brcm80211/brcmfmac/core.c | 2 +- .../broadcom/brcm80211/brcmfmac/feature.c | 2 +- .../broadcom/brcm80211/brcmfmac/fwil.c | 115 +--------------- .../broadcom/brcm80211/brcmfmac/fwil.h | 125 +++++++++++++++--- 5 files changed, 120 insertions(+), 128 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 52df03243c9f..21096cff0c72 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3080,7 +3080,7 @@ brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp, struct brcmf_scb_val_le scbval; struct brcmf_pktcnt_le pktcnt; s32 err; - u32 rate; + u32 rate = 0; u32 rssi; /* Get the current tx rate */ @@ -7268,7 +7268,7 @@ static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg) u32 nmode = 0; u32 vhtmode = 0; u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT }; - u32 rxchain; + u32 rxchain = 0; u32 nchain; int err; s32 i; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index f599d5f896e8..a92f78026cfd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -691,7 +691,7 @@ static int brcmf_net_mon_open(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; - u32 monitor; + u32 monitor = 0; int err; brcmf_dbg(TRACE, "Enter\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 6d10c9efbe93..7348f73680d6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -183,7 +183,7 @@ static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv) static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, enum brcmf_feat_id id, char *name) { - u32 data; + u32 data = 0; int err; /* we need to know firmware error */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index 72fe8bce6eaf..2aec7d2abd52 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -142,6 +142,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_set); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) @@ -160,36 +161,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) return err; } - - -s32 -brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) -{ - s32 err; - __le32 data_le = cpu_to_le32(data); - - mutex_lock(&ifp->drvr->proto_block); - brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); - err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); - mutex_unlock(&ifp->drvr->proto_block); - - return err; -} - -s32 -brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) -{ - s32 err; - __le32 data_le = cpu_to_le32(*data); - - mutex_lock(&ifp->drvr->proto_block); - err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); - mutex_unlock(&ifp->drvr->proto_block); - *data = le32_to_cpu(data_le); - brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); - - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_get); static u32 brcmf_create_iovar(const char *name, const char *data, u32 datalen, @@ -270,26 +242,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, mutex_unlock(&drvr->proto_block); return err; } - -s32 -brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); -} - -s32 -brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_get); static u32 brcmf_create_bsscfg(s32 bsscfgidx, const char *name, char *data, u32 datalen, @@ -364,6 +317,7 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_set); s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, @@ -394,28 +348,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, mutex_unlock(&drvr->proto_block); return err; } - -s32 -brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, - sizeof(data_le)); -} - -s32 -brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, - sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_get); static u32 brcmf_create_xtlv(const char *name, u16 id, char *data, u32 len, char *buf, u32 buflen) @@ -465,6 +398,7 @@ s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id, mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_set); s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len) @@ -494,39 +428,4 @@ s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, mutex_unlock(&drvr->proto_block); return err; } - -s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le, - sizeof(data_le)); -} - -s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} - -s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data) -{ - return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data)); -} - -s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data) -{ - __le16 data_le = cpu_to_le16(*data); - s32 err; - - err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); - if (err == 0) - *data = le16_to_cpu(data_le); - return err; -} - +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_get); \ No newline at end of file diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h index bc693157c4b1..a315a7fac6a0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h @@ -81,29 +81,122 @@ s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); -s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data); -s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data); +static inline +s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) +{ + s32 err; + __le32 data_le = cpu_to_le32(data); -s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data, - u32 len); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); + err = brcmf_fil_cmd_data_set(ifp, cmd, &data_le, sizeof(data_le)); + + return err; +} +static inline +s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) +{ + s32 err; + __le32 data_le = cpu_to_le32(*data); + + err = brcmf_fil_cmd_data_get(ifp, cmd, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); + + return err; +} + +s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, + const void *data, u32 len); s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, u32 len); -s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data); -s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data); +static inline +s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); +} +static inline +s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} + + +s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, + void *data, u32 len); +s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, + void *data, u32 len); +static inline +s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, + sizeof(data_le)); +} +static inline +s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, + sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} -s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, void *data, - u32 len); -s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, void *data, - u32 len); -s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data); -s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data); s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len); s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len); -s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data); -s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data); -s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data); -s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data); +static inline +s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, + u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le, + sizeof(data_le)); +} +static inline +s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, + u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} +static inline +s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, + u8 *data) +{ + return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data)); +} +static inline +s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, + u16 *data) +{ + __le16 data_le = cpu_to_le16(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le16_to_cpu(data_le); + return err; +} #endif /* _fwil_h_ */ From 14e1391b71027948cdbacdbea4bf8858c2068eb7 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 3 Jan 2024 10:57:02 +0100 Subject: [PATCH 0140/2255] wifi: brcmfmac: add per-vendor feature detection callback Adding a .feat_attach() callback allowing per-vendor overrides of the driver feature flags. In this patch the callback is only provided by BCA vendor to disable SAE feature as it has not been confirmed yet. BCA chips generally do not have the in-driver supplicant (idsup) feature so they rely on NL80211_CMD_EXTERNAL_AUTH to trigger user-space authentication. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-3-arend.vanspriel@broadcom.com --- .../wireless/broadcom/brcm80211/brcmfmac/bca/core.c | 8 ++++++++ .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 3 +++ .../net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h | 12 ++++++++++++ 3 files changed, 23 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c index ac3a36fa3640..a5d9ac5e6763 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "vops.h" @@ -21,7 +22,14 @@ static void brcmf_bca_detach(struct brcmf_pub *drvr) pr_err("%s: executing\n", __func__); } +static void brcmf_bca_feat_attach(struct brcmf_if *ifp) +{ + /* SAE support not confirmed so disabling for now */ + ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_SAE); +} + const struct brcmf_fwvid_ops brcmf_bca_ops = { .attach = brcmf_bca_attach, .detach = brcmf_bca_detach, + .feat_attach = brcmf_bca_feat_attach, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 7348f73680d6..7fef93ede0fb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -13,6 +13,7 @@ #include "debug.h" #include "fwil.h" #include "fwil_types.h" +#include "fwvid.h" #include "feature.h" #include "common.h" @@ -339,6 +340,8 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver"); + brcmf_fwvid_feat_attach(ifp); + if (drvr->settings->feature_disable) { brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", ifp->drvr->feat_flags, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index 43df58bb70ad..17fbdbb76f51 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -8,10 +8,12 @@ #include "firmware.h" struct brcmf_pub; +struct brcmf_if; struct brcmf_fwvid_ops { int (*attach)(struct brcmf_pub *drvr); void (*detach)(struct brcmf_pub *drvr); + void (*feat_attach)(struct brcmf_if *ifp); }; /* exported functions */ @@ -44,4 +46,14 @@ static inline void brcmf_fwvid_detach(struct brcmf_pub *drvr) brcmf_fwvid_detach_ops(drvr); } +static inline void brcmf_fwvid_feat_attach(struct brcmf_if *ifp) +{ + const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; + + if (!vops->feat_attach) + return; + + vops->feat_attach(ifp); +} + #endif /* FWVID_H_ */ From ba4d4726335c77bb0ac17840b2c5f764f3d40b99 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 3 Jan 2024 10:57:03 +0100 Subject: [PATCH 0141/2255] wifi: brcmfmac: move feature overrides before feature_disable The feature_disable option in brcmf_feat_attach() is a debugging or workaround option to disable features that cause driver issues. Hence they should be done as last step after all feature detection mechanisms have been completed. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-4-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 7fef93ede0fb..f23310a77a5d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -340,6 +340,9 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver"); + brcmf_feat_wlc_version_overrides(drvr); + brcmf_feat_firmware_overrides(drvr); + brcmf_fwvid_feat_attach(ifp); if (drvr->settings->feature_disable) { @@ -349,9 +352,6 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) ifp->drvr->feat_flags &= ~drvr->settings->feature_disable; } - brcmf_feat_wlc_version_overrides(drvr); - brcmf_feat_firmware_overrides(drvr); - /* set chip related quirks */ switch (drvr->bus_if->chip) { case BRCM_CC_43236_CHIP_ID: From 9f7861c56b51b84d30114e7fea9d744a9d5ba9b7 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 3 Jan 2024 10:57:04 +0100 Subject: [PATCH 0142/2255] wifi: brcmfmac: cfg80211: Use WSEC to set SAE password Using the WSEC command instead of sae_password seems to be the supported mechanism on newer firmware, and also how the brcmdhd driver does it. The existing firmware mechanism intended for (some) Cypress chips has been separated from the new firmware mechanism using the multi-vendor framework. Depending on the device it will select the appropriate firmware mechanism. This makes WPA3 work with iwd, or with wpa_supplicant pending a support patchset [2]. [1] https://rachelbythebay.com/w/2023/11/06/wpa3/ [2] http://lists.infradead.org/pipermail/hostap/2023-July/041653.html Signed-off-by: Hector Martin Reviewed-by: Neal Gompa [arend.vanspriel@broadcom.com: use multi-vendor framework] Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240103095704.135651-5-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 56 ++++++++----------- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 2 + .../broadcom/brcm80211/brcmfmac/cyw/core.c | 28 ++++++++++ .../broadcom/brcm80211/brcmfmac/fwil.c | 1 + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 2 +- .../broadcom/brcm80211/brcmfmac/fwvid.h | 13 +++++ .../broadcom/brcm80211/brcmfmac/wcc/core.c | 9 +++ 7 files changed, 76 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 21096cff0c72..736b2ada6f59 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -32,6 +32,7 @@ #include "vendor.h" #include "bus.h" #include "common.h" +#include "fwvid.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 @@ -1686,52 +1687,39 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) return reason; } -static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) +int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags) { struct brcmf_pub *drvr = ifp->drvr; struct brcmf_wsec_pmk_le pmk; int err; + if (key_len > sizeof(pmk.key)) { + bphy_err(drvr, "key must be less than %zu bytes\n", + sizeof(pmk.key)); + return -EINVAL; + } + memset(&pmk, 0, sizeof(pmk)); - /* pass pmk directly */ - pmk.key_len = cpu_to_le16(pmk_len); - pmk.flags = cpu_to_le16(0); - memcpy(pmk.key, pmk_data, pmk_len); + /* pass key material directly */ + pmk.key_len = cpu_to_le16(key_len); + pmk.flags = cpu_to_le16(flags); + memcpy(pmk.key, key, key_len); - /* store psk in firmware */ + /* store key material in firmware */ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, &pmk, sizeof(pmk)); if (err < 0) bphy_err(drvr, "failed to change PSK in firmware (len=%u)\n", - pmk_len); + key_len); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_set_wsec); -static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, - u16 pwd_len) +static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) { - struct brcmf_pub *drvr = ifp->drvr; - struct brcmf_wsec_sae_pwd_le sae_pwd; - int err; - - if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { - bphy_err(drvr, "sae_password must be less than %d\n", - BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); - return -EINVAL; - } - - sae_pwd.key_len = cpu_to_le16(pwd_len); - memcpy(sae_pwd.key, pwd_data, pwd_len); - - err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, - sizeof(sae_pwd)); - if (err < 0) - bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", - pwd_len); - - return err; + return brcmf_set_wsec(ifp, pmk_data, pmk_len, 0); } static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason, @@ -2502,8 +2490,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, bphy_err(drvr, "failed to clean up user-space RSNE\n"); goto done; } - err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, - sme->crypto.sae_pwd_len); + err = brcmf_fwvid_set_sae_password(ifp, &sme->crypto); if (!err && sme->crypto.psk) err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); @@ -5251,8 +5238,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, if (crypto->sae_pwd) { brcmf_dbg(INFO, "using SAE offload\n"); profile->use_fwauth |= BIT(BRCMF_PROFILE_FWAUTH_SAE); - err = brcmf_set_sae_password(ifp, crypto->sae_pwd, - crypto->sae_pwd_len); + err = brcmf_fwvid_set_sae_password(ifp, crypto); if (err < 0) goto exit; } @@ -5359,10 +5345,12 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, msleep(400); if (profile->use_fwauth != BIT(BRCMF_PROFILE_FWAUTH_NONE)) { + struct cfg80211_crypto_settings crypto = {}; + if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_PSK)) brcmf_set_pmk(ifp, NULL, 0); if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_SAE)) - brcmf_set_sae_password(ifp, NULL, 0); + brcmf_fwvid_set_sae_password(ifp, &crypto); profile->use_fwauth = BIT(BRCMF_PROFILE_FWAUTH_NONE); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 0e1fa3f0dea2..dc3a6a537507 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -468,4 +468,6 @@ void brcmf_set_mpc(struct brcmf_if *ndev, int mpc); void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_free_netdev(struct net_device *ndev); +int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags); + #endif /* BRCMFMAC_CFG80211_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index b75652ba9359..24670497f1a4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "vops.h" @@ -21,7 +22,34 @@ static void brcmf_cyw_detach(struct brcmf_pub *drvr) pr_err("%s: executing\n", __func__); } +static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) +{ + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_sae_pwd_le sae_pwd; + u16 pwd_len = crypto->sae_pwd_len; + int err; + + if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { + bphy_err(drvr, "sae_password must be less than %d\n", + BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); + return -EINVAL; + } + + sae_pwd.key_len = cpu_to_le16(pwd_len); + memcpy(sae_pwd.key, crypto->sae_pwd, pwd_len); + + err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, + sizeof(sae_pwd)); + if (err < 0) + bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", + pwd_len); + + return err; +} + const struct brcmf_fwvid_ops brcmf_cyw_ops = { .attach = brcmf_cyw_attach, .detach = brcmf_cyw_detach, + .set_sae_password = brcmf_cyw_set_sae_pwd, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index 2aec7d2abd52..bc1c6b5a6e31 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -211,6 +211,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *dat mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_set); s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 9d248ba1c0b2..e74a23e11830 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -584,7 +584,7 @@ struct brcmf_wsec_key_le { struct brcmf_wsec_pmk_le { __le16 key_len; __le16 flags; - u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; + u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN]; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index 17fbdbb76f51..d9fc76b46db9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -6,6 +6,7 @@ #define FWVID_H_ #include "firmware.h" +#include "cfg80211.h" struct brcmf_pub; struct brcmf_if; @@ -14,6 +15,7 @@ struct brcmf_fwvid_ops { int (*attach)(struct brcmf_pub *drvr); void (*detach)(struct brcmf_pub *drvr); void (*feat_attach)(struct brcmf_if *ifp); + int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); }; /* exported functions */ @@ -56,4 +58,15 @@ static inline void brcmf_fwvid_feat_attach(struct brcmf_if *ifp) vops->feat_attach(ifp); } +static inline int brcmf_fwvid_set_sae_password(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) +{ + const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; + + if (!vops || !vops->set_sae_password) + return -EOPNOTSUPP; + + return vops->set_sae_password(ifp, crypto); +} + #endif /* FWVID_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index 5573a47766ad..2d8f80bd7382 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "vops.h" @@ -21,7 +22,15 @@ static void brcmf_wcc_detach(struct brcmf_pub *drvr) pr_debug("%s: executing\n", __func__); } +static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) +{ + return brcmf_set_wsec(ifp, crypto->sae_pwd, crypto->sae_pwd_len, + BRCMF_WSEC_PASSPHRASE); +} + const struct brcmf_fwvid_ops brcmf_wcc_ops = { .attach = brcmf_wcc_attach, .detach = brcmf_wcc_detach, + .set_sae_password = brcmf_wcc_set_sae_pwd, }; From 85da8f71aaa7b83ea7ef0e89182e0cd47e16d465 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sat, 6 Jan 2024 11:38:33 +0100 Subject: [PATCH 0143/2255] wifi: brcmfmac: Demote vendor-specific attach/detach messages to info People are getting spooked by brcmfmac errors on their boot console. There's no reason for these messages to be errors. Cc: stable@vger.kernel.org # 6.2.x Fixes: d6a5c562214f ("wifi: brcmfmac: add support for vendor-specific firmware api") Signed-off-by: Hector Martin [arend.vanspriel@broadcom.com: remove attach/detach vendor callbacks] Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240106103835.269149-2-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/bca/core.c | 13 ---------- .../broadcom/brcm80211/brcmfmac/cyw/core.c | 13 ---------- .../broadcom/brcm80211/brcmfmac/fwvid.c | 7 +++-- .../broadcom/brcm80211/brcmfmac/fwvid.h | 26 ++----------------- .../broadcom/brcm80211/brcmfmac/wcc/core.c | 15 +---------- 5 files changed, 6 insertions(+), 68 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c index a5d9ac5e6763..a963c242975a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c @@ -11,17 +11,6 @@ #include "vops.h" -static int brcmf_bca_attach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); - return 0; -} - -static void brcmf_bca_detach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); -} - static void brcmf_bca_feat_attach(struct brcmf_if *ifp) { /* SAE support not confirmed so disabling for now */ @@ -29,7 +18,5 @@ static void brcmf_bca_feat_attach(struct brcmf_if *ifp) } const struct brcmf_fwvid_ops brcmf_bca_ops = { - .attach = brcmf_bca_attach, - .detach = brcmf_bca_detach, .feat_attach = brcmf_bca_feat_attach, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index 24670497f1a4..bec5748310b9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -11,17 +11,6 @@ #include "vops.h" -static int brcmf_cyw_attach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); - return 0; -} - -static void brcmf_cyw_detach(struct brcmf_pub *drvr) -{ - pr_err("%s: executing\n", __func__); -} - static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -49,7 +38,5 @@ static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, } const struct brcmf_fwvid_ops brcmf_cyw_ops = { - .attach = brcmf_cyw_attach, - .detach = brcmf_cyw_detach, .set_sae_password = brcmf_cyw_set_sae_pwd, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c index 86eafdb40541..f633e2bbd891 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c @@ -89,8 +89,7 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod, if (fwvid >= BRCMF_FWVENDOR_NUM) return -ERANGE; - if (WARN_ON(!vmod) || WARN_ON(!vops) || - WARN_ON(!vops->attach) || WARN_ON(!vops->detach)) + if (WARN_ON(!vmod) || WARN_ON(!vops)) return -EINVAL; if (WARN_ON(fwvid_list[fwvid].vmod)) @@ -150,7 +149,7 @@ static inline int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid) } #endif -int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr) +int brcmf_fwvid_attach(struct brcmf_pub *drvr) { enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid; int ret; @@ -175,7 +174,7 @@ int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr) return ret; } -void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr) +void brcmf_fwvid_detach(struct brcmf_pub *drvr) { enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index d9fc76b46db9..dac22534d033 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -12,8 +12,6 @@ struct brcmf_pub; struct brcmf_if; struct brcmf_fwvid_ops { - int (*attach)(struct brcmf_pub *drvr); - void (*detach)(struct brcmf_pub *drvr); void (*feat_attach)(struct brcmf_if *ifp); int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); }; @@ -24,30 +22,10 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *mod, int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod); /* core driver functions */ -int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr); -void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr); +int brcmf_fwvid_attach(struct brcmf_pub *drvr); +void brcmf_fwvid_detach(struct brcmf_pub *drvr); const char *brcmf_fwvid_vendor_name(struct brcmf_pub *drvr); -static inline int brcmf_fwvid_attach(struct brcmf_pub *drvr) -{ - int ret; - - ret = brcmf_fwvid_attach_ops(drvr); - if (ret) - return ret; - - return drvr->vops->attach(drvr); -} - -static inline void brcmf_fwvid_detach(struct brcmf_pub *drvr) -{ - if (!drvr->vops) - return; - - drvr->vops->detach(drvr); - brcmf_fwvid_detach_ops(drvr); -} - static inline void brcmf_fwvid_feat_attach(struct brcmf_if *ifp) { const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index 2d8f80bd7382..fd593b93ad40 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -7,21 +7,10 @@ #include #include #include -#include +#include #include "vops.h" -static int brcmf_wcc_attach(struct brcmf_pub *drvr) -{ - pr_debug("%s: executing\n", __func__); - return 0; -} - -static void brcmf_wcc_detach(struct brcmf_pub *drvr) -{ - pr_debug("%s: executing\n", __func__); -} - static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -30,7 +19,5 @@ static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, } const struct brcmf_fwvid_ops brcmf_wcc_ops = { - .attach = brcmf_wcc_attach, - .detach = brcmf_wcc_detach, .set_sae_password = brcmf_wcc_set_sae_pwd, }; From b822015a1f57268f5b2ff656736dc4004e7097da Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 6 Jan 2024 11:38:34 +0100 Subject: [PATCH 0144/2255] wifi: brcmfmac: avoid invalid list operation when vendor attach fails When the brcmf_fwvid_attach() fails the driver instance is not added to the vendor list. Hence we should not try to delete it from that list when the brcmf_fwvid_detach() function is called in cleanup path. Cc: stable@vger.kernel.org # 6.2.x Fixes: d6a5c562214f ("wifi: brcmfmac: add support for vendor-specific firmware api") Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240106103835.269149-3-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c index f633e2bbd891..b427782554b5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c @@ -186,9 +186,10 @@ void brcmf_fwvid_detach(struct brcmf_pub *drvr) mutex_lock(&fwvid_list_lock); - drvr->vops = NULL; - list_del(&drvr->bus_if->list); - + if (drvr->vops) { + drvr->vops = NULL; + list_del(&drvr->bus_if->list); + } mutex_unlock(&fwvid_list_lock); } From edec42821911a68317a611a2c2434a80c48bd3c0 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 6 Jan 2024 11:38:35 +0100 Subject: [PATCH 0145/2255] wifi: brcmfmac: allow per-vendor event handling The firmware interface also defines events generated by firmware on the device. As the get/set primitives the events are likely to diverge between the vendors so this commit adds support for per-vendor handling. The number of events may differ so we let the vendor-specific code allocate the struct brcmf_fweh_info which contains array of event handlers. The existing event enumeration will be used by the higher layers and thus are common definitions. The vendor-specific code can provide a mapping table for converting the common definition to the vendor-specific firmware event definition and vice-versa. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240106103835.269149-4-arend.vanspriel@broadcom.com --- .../broadcom/brcm80211/brcmfmac/bca/core.c | 17 ++ .../broadcom/brcm80211/brcmfmac/common.c | 18 +- .../broadcom/brcm80211/brcmfmac/core.c | 10 +- .../broadcom/brcm80211/brcmfmac/core.h | 2 +- .../broadcom/brcm80211/brcmfmac/cyw/core.c | 17 ++ .../broadcom/brcm80211/brcmfmac/fweh.c | 154 +++++++++++++----- .../broadcom/brcm80211/brcmfmac/fweh.h | 60 +++++-- .../broadcom/brcm80211/brcmfmac/fwvid.c | 3 +- .../broadcom/brcm80211/brcmfmac/fwvid.h | 9 + .../broadcom/brcm80211/brcmfmac/wcc/core.c | 17 ++ 10 files changed, 244 insertions(+), 63 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c index a963c242975a..f471c962104a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c @@ -11,12 +11,29 @@ #include "vops.h" +#define BRCMF_BCA_E_LAST 212 + static void brcmf_bca_feat_attach(struct brcmf_if *ifp) { /* SAE support not confirmed so disabling for now */ ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_SAE); } +static int brcmf_bca_alloc_fweh_info(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_BCA_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_BCA_E_LAST; + drvr->fweh = fweh; + return 0; +} + const struct brcmf_fwvid_ops brcmf_bca_ops = { .feat_attach = brcmf_bca_feat_attach, + .alloc_fweh_info = brcmf_bca_alloc_fweh_info, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index b6d458e022fa..b24faae35873 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -266,7 +266,7 @@ static int brcmf_c_process_cal_blob(struct brcmf_if *ifp) int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + struct brcmf_fweh_info *fweh = drvr->fweh; u8 buf[BRCMF_DCMD_SMLEN]; struct brcmf_bus *bus; struct brcmf_rev_info_le revinfo; @@ -413,15 +413,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) brcmf_c_set_joinpref_default(ifp); /* Setup event_msgs, enable E_IF */ - err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); + err = brcmf_fil_iovar_data_get(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) { bphy_err(drvr, "Get event_msgs error (%d)\n", err); goto done; } - setbit(eventmask, BRCMF_E_IF); - err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); + /* + * BRCMF_E_IF can safely be used to set the appropriate bit + * in the event_mask as the firmware event code is guaranteed + * to match the value of BRCMF_E_IF because it is old cruft + * that all vendors have. + */ + setbit(fweh->event_mask, BRCMF_E_IF); + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) { bphy_err(drvr, "Set event_msgs error (%d)\n", err); goto done; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index a92f78026cfd..bf91b1e1368f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -1348,13 +1348,17 @@ int brcmf_attach(struct device *dev) goto fail; } + /* attach firmware event handler */ + ret = brcmf_fweh_attach(drvr); + if (ret != 0) { + bphy_err(drvr, "brcmf_fweh_attach failed\n"); + goto fail; + } + /* Attach to events important for core code */ brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG, brcmf_psm_watchdog_notify); - /* attach firmware event handler */ - brcmf_fweh_attach(drvr); - ret = brcmf_bus_started(drvr, drvr->ops); if (ret != 0) { bphy_err(drvr, "dongle is not responding: err=%d\n", ret); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index e4f911dd414b..ea76b8d33401 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -122,7 +122,7 @@ struct brcmf_pub { struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; - struct brcmf_fweh_info fweh; + struct brcmf_fweh_info *fweh; struct brcmf_ampdu_rx_reorder *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index bec5748310b9..9a4837881486 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -11,6 +11,8 @@ #include "vops.h" +#define BRCMF_CYW_E_LAST 197 + static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -37,6 +39,21 @@ static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, return err; } +static int brcmf_cyw_alloc_fweh_info(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_CYW_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_CYW_E_LAST; + drvr->fweh = fweh; + return 0; +} + const struct brcmf_fwvid_ops brcmf_cyw_ops = { .set_sae_password = brcmf_cyw_set_sae_pwd, + .alloc_fweh_info = brcmf_cyw_alloc_fweh_info, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index 68960ae98987..0774f6c59226 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -14,7 +14,8 @@ #include "fweh.h" #include "fwil.h" #include "proto.h" - +#include "bus.h" +#include "fwvid.h" /** * struct brcmf_fweh_queue_item - event item on event queue. * @@ -28,7 +29,7 @@ */ struct brcmf_fweh_queue_item { struct list_head q; - enum brcmf_fweh_event_code code; + u32 code; u8 ifidx; u8 ifaddr[ETH_ALEN]; struct brcmf_event_msg_be emsg; @@ -94,7 +95,7 @@ static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh, static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, struct brcmf_if *ifp, - enum brcmf_fweh_event_code code, + u32 fwcode, struct brcmf_event_msg *emsg, void *data) { @@ -102,13 +103,13 @@ static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, int err = -EINVAL; if (ifp) { - fweh = &ifp->drvr->fweh; + fweh = ifp->drvr->fweh; /* handle the event if valid interface and handler */ - if (fweh->evt_handler[code]) - err = fweh->evt_handler[code](ifp, emsg, data); + if (fweh->evt_handler[fwcode]) + err = fweh->evt_handler[fwcode](ifp, emsg, data); else - bphy_err(drvr, "unhandled event %d ignored\n", code); + bphy_err(drvr, "unhandled fwevt %d ignored\n", fwcode); } else { bphy_err(drvr, "no interface object\n"); } @@ -142,7 +143,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) && (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT || ((ifevent->role == BRCMF_E_IF_ROLE_STA) && - (drvr->fweh.p2pdev_setup_ongoing)))); + (drvr->fweh->p2pdev_setup_ongoing)))); if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { brcmf_dbg(EVENT, "event can be ignored\n"); return; @@ -163,7 +164,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, return; if (!is_p2pdev) brcmf_proto_add_if(drvr, ifp); - if (!drvr->fweh.evt_handler[BRCMF_E_IF]) + if (!drvr->fweh->evt_handler[BRCMF_E_IF]) if (brcmf_net_attach(ifp, false) < 0) return; } @@ -183,6 +184,45 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, } } +static void brcmf_fweh_map_event_code(struct brcmf_fweh_info *fweh, + enum brcmf_fweh_event_code code, + u32 *fw_code) +{ + int i; + + if (WARN_ON(!fw_code)) + return; + + *fw_code = code; + if (fweh->event_map) { + for (i = 0; i < fweh->event_map->n_items; i++) { + if (fweh->event_map->items[i].code == code) { + *fw_code = fweh->event_map->items[i].fwevt_code; + break; + } + } + } +} + +static void brcmf_fweh_map_fwevt_code(struct brcmf_fweh_info *fweh, u32 fw_code, + enum brcmf_fweh_event_code *code) +{ + int i; + + if (WARN_ON(!code)) + return; + + *code = fw_code; + if (fweh->event_map) { + for (i = 0; i < fweh->event_map->n_items; i++) { + if (fweh->event_map->items[i].fwevt_code == fw_code) { + *code = fweh->event_map->items[i].code; + break; + } + } + } +} + /** * brcmf_fweh_dequeue_event() - get event from the queue. * @@ -221,15 +261,19 @@ static void brcmf_fweh_event_worker(struct work_struct *work) struct brcmf_event_msg emsg; fweh = container_of(work, struct brcmf_fweh_info, event_work); - drvr = container_of(fweh, struct brcmf_pub, fweh); + drvr = fweh->drvr; while ((event = brcmf_fweh_dequeue_event(fweh))) { - brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", - brcmf_fweh_event_name(event->code), event->code, + enum brcmf_fweh_event_code code; + + brcmf_fweh_map_fwevt_code(fweh, event->code, &code); + brcmf_dbg(EVENT, "event %s (%u:%u) ifidx %u bsscfg %u addr %pM\n", + brcmf_fweh_event_name(code), code, event->code, event->emsg.ifidx, event->emsg.bsscfgidx, event->emsg.addr); if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) { - bphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx); + bphy_err(drvr, "invalid bsscfg index: %u\n", + event->emsg.bsscfgidx); goto event_free; } @@ -237,7 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) emsg_be = &event->emsg; emsg.version = be16_to_cpu(emsg_be->version); emsg.flags = be16_to_cpu(emsg_be->flags); - emsg.event_code = event->code; + emsg.event_code = code; emsg.status = be32_to_cpu(emsg_be->status); emsg.reason = be32_to_cpu(emsg_be->reason); emsg.auth_type = be32_to_cpu(emsg_be->auth_type); @@ -283,7 +327,7 @@ event_free: */ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) { - ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing; + ifp->drvr->fweh->p2pdev_setup_ongoing = ongoing; } /** @@ -291,12 +335,27 @@ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) * * @drvr: driver information object. */ -void brcmf_fweh_attach(struct brcmf_pub *drvr) +int brcmf_fweh_attach(struct brcmf_pub *drvr) { - struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_info *fweh; + int err; + + err = brcmf_fwvid_alloc_fweh_info(drvr); + if (err < 0) + return err; + + fweh = drvr->fweh; + fweh->drvr = drvr; + + fweh->event_mask_len = DIV_ROUND_UP(fweh->num_event_codes, 8); + fweh->event_mask = kzalloc(fweh->event_mask_len, GFP_KERNEL); + if (!fweh->event_mask) + return -ENOMEM; + INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker); spin_lock_init(&fweh->evt_q_lock); INIT_LIST_HEAD(&fweh->event_q); + return 0; } /** @@ -306,14 +365,19 @@ void brcmf_fweh_attach(struct brcmf_pub *drvr) */ void brcmf_fweh_detach(struct brcmf_pub *drvr) { - struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_info *fweh = drvr->fweh; + + if (!fweh) + return; /* cancel the worker if initialized */ if (fweh->event_work.func) { cancel_work_sync(&fweh->event_work); WARN_ON(!list_empty(&fweh->event_q)); - memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler)); } + drvr->fweh = NULL; + kfree(fweh->event_mask); + kfree(fweh); } /** @@ -326,11 +390,17 @@ void brcmf_fweh_detach(struct brcmf_pub *drvr) int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, brcmf_fweh_handler_t handler) { - if (drvr->fweh.evt_handler[code]) { + struct brcmf_fweh_info *fweh = drvr->fweh; + u32 evt_handler_idx; + + brcmf_fweh_map_event_code(fweh, code, &evt_handler_idx); + + if (fweh->evt_handler[evt_handler_idx]) { bphy_err(drvr, "event code %d already registered\n", code); return -ENOSPC; } - drvr->fweh.evt_handler[code] = handler; + + fweh->evt_handler[evt_handler_idx] = handler; brcmf_dbg(TRACE, "event handler registered for %s\n", brcmf_fweh_event_name(code)); return 0; @@ -345,9 +415,12 @@ int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, void brcmf_fweh_unregister(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code) { + u32 evt_handler_idx; + brcmf_dbg(TRACE, "event handler cleared for %s\n", brcmf_fweh_event_name(code)); - drvr->fweh.evt_handler[code] = NULL; + brcmf_fweh_map_event_code(drvr->fweh, code, &evt_handler_idx); + drvr->fweh->evt_handler[evt_handler_idx] = NULL; } /** @@ -357,27 +430,28 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr, */ int brcmf_fweh_activate_events(struct brcmf_if *ifp) { - struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_fweh_info *fweh = ifp->drvr->fweh; + enum brcmf_fweh_event_code code; int i, err; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - memset(eventmask, 0, sizeof(eventmask)); - for (i = 0; i < BRCMF_E_LAST; i++) { - if (ifp->drvr->fweh.evt_handler[i]) { + memset(fweh->event_mask, 0, fweh->event_mask_len); + for (i = 0; i < fweh->num_event_codes; i++) { + if (fweh->evt_handler[i]) { + brcmf_fweh_map_fwevt_code(fweh, i, &code); brcmf_dbg(EVENT, "enable event %s\n", - brcmf_fweh_event_name(i)); - setbit(eventmask, i); + brcmf_fweh_event_name(code)); + setbit(fweh->event_mask, i); } } /* want to handle IF event as well */ brcmf_dbg(EVENT, "enable event IF\n"); - setbit(eventmask, BRCMF_E_IF); + setbit(fweh->event_mask, BRCMF_E_IF); - err = brcmf_fil_iovar_data_set(ifp, "event_msgs", - eventmask, BRCMF_EVENTING_MASK_LEN); + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) - bphy_err(drvr, "Set event_msgs error (%d)\n", err); + bphy_err(fweh->drvr, "Set event_msgs error (%d)\n", err); return err; } @@ -397,21 +471,21 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, struct brcmf_event *event_packet, u32 packet_len, gfp_t gfp) { - enum brcmf_fweh_event_code code; - struct brcmf_fweh_info *fweh = &drvr->fweh; + u32 fwevt_idx; + struct brcmf_fweh_info *fweh = drvr->fweh; struct brcmf_fweh_queue_item *event; void *data; u32 datalen; /* get event info */ - code = get_unaligned_be32(&event_packet->msg.event_type); + fwevt_idx = get_unaligned_be32(&event_packet->msg.event_type); datalen = get_unaligned_be32(&event_packet->msg.datalen); data = &event_packet[1]; - if (code >= BRCMF_E_LAST) + if (fwevt_idx >= fweh->num_event_codes) return; - if (code != BRCMF_E_IF && !fweh->evt_handler[code]) + if (fwevt_idx != BRCMF_E_IF && !fweh->evt_handler[fwevt_idx]) return; if (datalen > BRCMF_DCMD_MAXLEN || @@ -422,13 +496,13 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, if (!event) return; - event->datalen = datalen; - event->code = code; + event->code = fwevt_idx; event->ifidx = event_packet->msg.ifidx; /* use memcpy to get aligned event message */ memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); memcpy(event->data, data, datalen); + event->datalen = datalen; memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); brcmf_fweh_queue_event(fweh, event); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 48414e8b9389..9ca1b2aadcb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -17,6 +17,10 @@ struct brcmf_pub; struct brcmf_if; struct brcmf_cfg80211_info; +#define BRCMF_ABSTRACT_EVENT_BIT BIT(31) +#define BRCMF_ABSTRACT_ENUM_DEF(_id, _val) \ + BRCMF_ENUM_DEF(_id, (BRCMF_ABSTRACT_EVENT_BIT | (_val))) + /* list of firmware events */ #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ BRCMF_ENUM_DEF(SET_SSID, 0) \ @@ -98,16 +102,9 @@ struct brcmf_cfg80211_info; /* firmware event codes sent by the dongle */ enum brcmf_fweh_event_code { BRCMF_FWEH_EVENT_ENUM_DEFLIST - /* this determines event mask length which must match - * minimum length check in device firmware so it is - * hard-coded here. - */ - BRCMF_E_LAST = 139 }; #undef BRCMF_ENUM_DEF -#define BRCMF_EVENTING_MASK_LEN DIV_ROUND_UP(BRCMF_E_LAST, 8) - /* flags field values in struct brcmf_event_msg */ #define BRCMF_EVENT_MSG_LINK 0x01 #define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 @@ -287,6 +284,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, const struct brcmf_event_msg *evtmsg, void *data); +/** + * struct brcmf_fweh_event_map_item - fweh event and firmware event pair. + * + * @code: fweh event code as used by higher layers. + * @fwevt_code: firmware event code as used by firmware. + * + * This mapping is needed when a functionally identical event has a + * different numerical definition between vendors. When such mapping + * is needed the higher layer event code should not collide with the + * firmware event. + */ +struct brcmf_fweh_event_map_item { + enum brcmf_fweh_event_code code; + u32 fwevt_code; +}; + +/** + * struct brcmf_fweh_event_map - mapping between firmware event and fweh event. + * + * @n_items: number of mapping items. + * @items: array of fweh event and firmware event pairs. + */ +struct brcmf_fweh_event_map { + u32 n_items; + const struct brcmf_fweh_event_map_item items[] __counted_by(n_items); +}; + /** * struct brcmf_fweh_info - firmware event handling information. * @@ -294,21 +318,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, * @event_work: event worker. * @evt_q_lock: lock for event queue protection. * @event_q: event queue. - * @evt_handler: registered event handlers. + * @event_mask_len: length of @event_mask used to enable firmware events. + * @event_mask: byte array used in 'event_msgs' iovar command. + * @event_map: mapping between fweh event and firmware event which + * may be provided by vendor-specific module for events that need + * mapping. + * @num_event_codes: number of firmware events supported by firmware which + * does a minimum length check for the @event_mask. This value is to + * be provided by vendor-specific module determining @event_mask_len + * and consequently the allocation size for @event_mask. + * @evt_handler: event handler registry indexed by firmware event code. */ struct brcmf_fweh_info { + struct brcmf_pub *drvr; bool p2pdev_setup_ongoing; struct work_struct event_work; spinlock_t evt_q_lock; struct list_head event_q; - int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp, - const struct brcmf_event_msg *evtmsg, - void *data); + uint event_mask_len; + u8 *event_mask; + struct brcmf_fweh_event_map *event_map; + uint num_event_codes; + brcmf_fweh_handler_t evt_handler[] __counted_by(num_event_codes); }; const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code); -void brcmf_fweh_attach(struct brcmf_pub *drvr); +int brcmf_fweh_attach(struct brcmf_pub *drvr); void brcmf_fweh_detach(struct brcmf_pub *drvr); int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, int (*handler)(struct brcmf_if *ifp, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c index b427782554b5..41eafcda77f7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c @@ -89,7 +89,8 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod, if (fwvid >= BRCMF_FWVENDOR_NUM) return -ERANGE; - if (WARN_ON(!vmod) || WARN_ON(!vops)) + if (WARN_ON(!vmod) || WARN_ON(!vops) || + WARN_ON(!vops->alloc_fweh_info)) return -EINVAL; if (WARN_ON(fwvid_list[fwvid].vmod)) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index dac22534d033..e6ac9fc341bc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -14,6 +14,7 @@ struct brcmf_if; struct brcmf_fwvid_ops { void (*feat_attach)(struct brcmf_if *ifp); int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); + int (*alloc_fweh_info)(struct brcmf_pub *drvr); }; /* exported functions */ @@ -47,4 +48,12 @@ static inline int brcmf_fwvid_set_sae_password(struct brcmf_if *ifp, return vops->set_sae_password(ifp, crypto); } +static inline int brcmf_fwvid_alloc_fweh_info(struct brcmf_pub *drvr) +{ + if (!drvr->vops) + return -EIO; + + return drvr->vops->alloc_fweh_info(drvr); +} + #endif /* FWVID_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index fd593b93ad40..05d7c2a4fba5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -11,6 +11,8 @@ #include "vops.h" +#define BRCMF_WCC_E_LAST 213 + static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto) { @@ -18,6 +20,21 @@ static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, BRCMF_WSEC_PASSPHRASE); } +static int brcmf_wcc_alloc_fweh_info(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_WCC_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_WCC_E_LAST; + drvr->fweh = fweh; + return 0; +} + const struct brcmf_fwvid_ops brcmf_wcc_ops = { .set_sae_password = brcmf_wcc_set_sae_pwd, + .alloc_fweh_info = brcmf_wcc_alloc_fweh_info, }; From 563d5025cf3b51c7bf20e6966af433ed5f838875 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Tue, 16 Jan 2024 10:50:01 +0100 Subject: [PATCH 0146/2255] wifi: rtl8xxxu: add missing number of sec cam entries for all variants Commit b837f78fbffa ("wifi: rtl8xxxu: add hw crypto support for AP mode") introduced max_sec_cam_num as a member of rtl8xxxu_fileops. It was missed to set this number for all variants except 8188f, which caused rtl8xxxu_get_free_sec_cam() to always return 0 and therefore breaking encrypted traffic. Fix it by adding the numbers for all variants. The values are taken from the vendor drivers and rtlwifi. Link: https://lore.kernel.org/linux-wireless/20240111163603.2325-1-zenmchen@gmail.com/ Fixes: b837f78fbffa ("wifi: rtl8xxxu: add hw crypto support for AP mode") Signed-off-by: Martin Kaistra Signed-off-by: Kalle Valo Link: https://msgid.link/20240116095001.399500-1-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 1 + 7 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c index cbeac9386ae5..afe9cc1b49dc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c @@ -1882,6 +1882,7 @@ struct rtl8xxxu_fileops rtl8188eu_fops = { .has_tx_report = 1, .init_reg_pkt_life_time = 1, .gen2_thermal_meter = 1, + .max_sec_cam_num = 32, .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, /* diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c index b30a9a513cb8..3ee7d8f87da6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c @@ -613,6 +613,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = { .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), + .max_sec_cam_num = 32, .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, .adda_2t_path_on_a = 0x04db25a4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index 47bcaec6f2db..63b73ace27ec 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -1769,6 +1769,7 @@ struct rtl8xxxu_fileops rtl8192eu_fops = { .needs_full_init = 1, .supports_ap = 1, .max_macid_num = 128, + .max_sec_cam_num = 64, .adda_1t_init = 0x0fc01616, .adda_1t_path_on = 0x0fc01616, .adda_2t_path_on_a = 0x0fc01616, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c index 585b1a5eed69..21e4204769d0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c @@ -2095,6 +2095,7 @@ struct rtl8xxxu_fileops rtl8192fu_fops = { .max_aggr_num = 0x1f1f, .supports_ap = 1, .max_macid_num = 128, + .max_sec_cam_num = 64, .trxff_boundary = 0x3f3f, .pbp_rx = PBP_PAGE_SIZE_256, .pbp_tx = PBP_PAGE_SIZE_256, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c index 871b8cca8a18..46d57510e9fc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c @@ -1877,6 +1877,7 @@ struct rtl8xxxu_fileops rtl8710bu_fops = { .max_aggr_num = 0x0c14, .supports_ap = 1, .max_macid_num = 16, + .max_sec_cam_num = 32, .adda_1t_init = 0x03c00016, .adda_1t_path_on = 0x03c00016, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c index 15a30e496221..ad1bb9377ca2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c @@ -510,6 +510,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = { .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), + .max_sec_cam_num = 32, .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, .adda_2t_path_on_a = 0x04db25a4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index 954369ed6226..9640c841d20a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1744,6 +1744,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .max_aggr_num = 0x0c14, .supports_ap = 1, .max_macid_num = 128, + .max_sec_cam_num = 64, .adda_1t_init = 0x01c00014, .adda_1t_path_on = 0x01c00014, .adda_2t_path_on_a = 0x01c00014, From b06439c6687443e6b99dbcf746042067ff0e9ba9 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Wed, 17 Jan 2024 22:11:48 +0200 Subject: [PATCH 0147/2255] wifi: rtlwifi: Speed up firmware loading for USB Currently it takes almost 6 seconds to upload the firmware for RTL8192CU (and 11 seconds for RTL8192DU). That's because the firmware is uploaded one byte at a time. Also, after plugging the device, the firmware gets uploaded three times before a connection to the AP is established. Maybe this is fine for most users, but when testing changes to the driver it's really annoying to wait so long. Speed up the firmware upload by writing chunks of 64 bytes at a time. This way it takes about 110 ms for RTL8192CU (and about 210 ms for RTL8192DU). PCI devices could upload it in chunks of 4 bytes, but I don't have any to test and commit 89d32c9071aa ("rtlwifi: Download firmware as bytes rather than as dwords") decided otherwise anyway. Allocate memory for the firmware image with kmalloc instead of vzalloc because this memory is passed directly to usb_control_msg(), which can't take memory allocated by vmalloc. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/d9bd4949-6e92-4f35-8b60-3b45f9ad74ab@gmail.com --- drivers/net/wireless/realtek/rtlwifi/efuse.c | 36 ++++++++++++++++--- drivers/net/wireless/realtek/rtlwifi/efuse.h | 4 +-- .../wireless/realtek/rtlwifi/rtl8192cu/sw.c | 6 ++-- drivers/net/wireless/realtek/rtlwifi/usb.c | 9 +++++ drivers/net/wireless/realtek/rtlwifi/wifi.h | 8 +++++ 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 2e945554ed6d..c1fbc29d5ca1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -1287,18 +1287,44 @@ int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, } EXPORT_SYMBOL_GPL(rtl_get_hwinfo); -void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size) +static void _rtl_fw_block_write_usb(struct ieee80211_hw *hw, u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 start = START_ADDRESS; + u32 n; + + while (size > 0) { + if (size >= 64) + n = 64; + else if (size >= 8) + n = 8; + else + n = 1; + + rtl_write_chunk(rtlpriv, start, n, buffer); + + start += n; + buffer += n; + size -= n; + } +} + +void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size) { struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 *pu4byteptr = (u8 *)buffer; u32 i; - for (i = 0; i < size; i++) - rtl_write_byte(rtlpriv, (START_ADDRESS + i), *(pu4byteptr + i)); + if (rtlpriv->rtlhal.interface == INTF_PCI) { + for (i = 0; i < size; i++) + rtl_write_byte(rtlpriv, (START_ADDRESS + i), + *(buffer + i)); + } else if (rtlpriv->rtlhal.interface == INTF_USB) { + _rtl_fw_block_write_usb(hw, buffer, size); + } } EXPORT_SYMBOL_GPL(rtl_fw_block_write); -void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, +void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer, u32 size) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.h b/drivers/net/wireless/realtek/rtlwifi/efuse.h index 1ec59f439382..4821625ad1e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.h +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.h @@ -91,8 +91,8 @@ void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate); int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, int max_size, u8 *hwinfo, int *params); void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen); -void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, +void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer, u32 size); -void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size); +void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size); void rtl_efuse_ops_init(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index 20b4aac69642..9f4cf09090d6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -40,7 +40,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.thermalvalue = 0; /* for firmware buf */ - rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); + rtlpriv->rtlhal.pfirmware = kmalloc(0x4000, GFP_KERNEL); if (!rtlpriv->rtlhal.pfirmware) { pr_err("Can't alloc buffer for fw\n"); return 1; @@ -61,7 +61,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { - vfree(rtlpriv->rtlhal.pfirmware); + kfree(rtlpriv->rtlhal.pfirmware); rtlpriv->rtlhal.pfirmware = NULL; } return err; @@ -72,7 +72,7 @@ static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); if (rtlpriv->rtlhal.pfirmware) { - vfree(rtlpriv->rtlhal.pfirmware); + kfree(rtlpriv->rtlhal.pfirmware); rtlpriv->rtlhal.pfirmware = NULL; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 07a7e6fa46af..1fc480fe18ad 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -125,6 +125,14 @@ static void _usb_write32_sync(struct rtl_priv *rtlpriv, u32 addr, u32 val) _usb_write_sync(rtlpriv, addr, val, 4); } +static void _usb_write_chunk_sync(struct rtl_priv *rtlpriv, u32 addr, + u32 length, u8 *data) +{ + struct usb_device *udev = to_usb_device(rtlpriv->io.dev); + + _usbctrl_vendorreq_sync(udev, REALTEK_USB_VENQT_WRITE, addr, data, length); +} + static void _rtl_usb_io_handler_init(struct device *dev, struct ieee80211_hw *hw) { @@ -135,6 +143,7 @@ static void _rtl_usb_io_handler_init(struct device *dev, rtlpriv->io.write8 = _usb_write8_sync; rtlpriv->io.write16 = _usb_write16_sync; rtlpriv->io.write32 = _usb_write32_sync; + rtlpriv->io.write_chunk = _usb_write_chunk_sync; rtlpriv->io.read8 = _usb_read8_sync; rtlpriv->io.read16 = _usb_read16_sync; rtlpriv->io.read32 = _usb_read32_sync; diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 53af324f3807..3821f6e31447 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1450,6 +1450,8 @@ struct rtl_io { void (*write8)(struct rtl_priv *rtlpriv, u32 addr, u8 val); void (*write16)(struct rtl_priv *rtlpriv, u32 addr, u16 val); void (*write32)(struct rtl_priv *rtlpriv, u32 addr, u32 val); + void (*write_chunk)(struct rtl_priv *rtlpriv, u32 addr, u32 length, + u8 *data); u8 (*read8)(struct rtl_priv *rtlpriv, u32 addr); u16 (*read16)(struct rtl_priv *rtlpriv, u32 addr); @@ -2962,6 +2964,12 @@ static inline void rtl_write_dword(struct rtl_priv *rtlpriv, rtlpriv->io.read32(rtlpriv, addr); } +static inline void rtl_write_chunk(struct rtl_priv *rtlpriv, + u32 addr, u32 length, u8 *data) +{ + rtlpriv->io.write_chunk(rtlpriv, addr, length, data); +} + static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) { From b856f023b40fa7735ca19de433fc1307d69c36d0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 18 Jan 2024 06:33:19 +0530 Subject: [PATCH 0148/2255] wifi: ath12k: Refactor the mac80211 hw access from link/radio Currently, mac80211 hardware accesses link/radio structure directly in multiple locations. Introduce helper function to avoid this direct access, as this change will facilitate refactoring for Multi-link operation support. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20240118010320.3918136-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 10 +++-- drivers/net/wireless/ath/ath12k/core.h | 6 ++- drivers/net/wireless/ath/ath12k/dp_mon.c | 4 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 6 +-- drivers/net/wireless/ath/ath12k/dp_tx.c | 4 +- drivers/net/wireless/ath/ath12k/mac.c | 51 ++++++++++++++---------- drivers/net/wireless/ath/ath12k/reg.c | 6 +-- drivers/net/wireless/ath/ath12k/wmi.c | 17 ++++---- 8 files changed, 60 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 6cab747ff858..d21618ca70b9 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -879,6 +879,7 @@ static void ath12k_rfkill_work(struct work_struct *work) { struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work); struct ath12k *ar; + struct ieee80211_hw *hw; bool rfkill_radio_on; int i; @@ -891,8 +892,9 @@ static void ath12k_rfkill_work(struct work_struct *work) if (!ar) continue; + hw = ath12k_ar_to_hw(ar); ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); - wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on); + wiphy_rfkill_set_hw_state(hw->wiphy, !rfkill_radio_on); } } @@ -936,7 +938,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) if (!ar || ar->state == ATH12K_STATE_OFF) continue; - ieee80211_stop_queues(ar->hw); + ieee80211_stop_queues(ath12k_ar_to_hw(ar)); ath12k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); @@ -976,7 +978,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) case ATH12K_STATE_ON: ar->state = ATH12K_STATE_RESTARTING; ath12k_core_halt(ar); - ieee80211_restart_hw(ar->hw); + ieee80211_restart_hw(ath12k_ar_to_hw(ar)); break; case ATH12K_STATE_OFF: ath12k_warn(ab, diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index ba0a30f1ea29..10a292b28d4d 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CORE_H @@ -896,4 +896,8 @@ static inline const char *ath12k_bus_str(enum ath12k_bus bus) return "unknown"; } +static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) +{ + return ar->hw; +} #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index be4b39f5fa80..2432ab605c85 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "dp_mon.h" @@ -1130,7 +1130,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) rx_status->flag |= RX_FLAG_8023; - ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi); } static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 07430289023f..a31c24b54851 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2458,7 +2458,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) rx_status->flag |= RX_FLAG_8023; - ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi); } static int ath12k_dp_rx_process_msdu(struct ath12k *ar, @@ -2844,7 +2844,7 @@ 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(); From 6db6e70a17f6fb3f2cfae31bb212a2179d0f6e6b Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 18 Jan 2024 07:58:56 +0200 Subject: [PATCH 0149/2255] wifi: ath12k: Introduce the container for mac80211 hw To support multi link operation, we need to combine all the link/pdev under a single wiphy. This avoids the overhead of synchronization across multiple hardware instances in both the cfg80211 and mac80211 layers. Currently, each link/pdev is registered as separate wiphy, tightly coupled with link/pdev/radio (ar) structure. To enable single wiphy registration within the chip, we decouple the wiphy data entity from the link/pdev/radio (ar) structure and move it under the chip (ab) structure with a new data container (ath12k_hw) structure. This approach improves scalability for future multi link operation support. mac80211 hw private data structure diagram ------------------------------------------ Now After +---------------------+ +---------------------+ |mac80211 hw priv data| |mac80211 hw priv data| | | | | | | | | | | | | | | | ath12k_hw (ah) | | | | | | | +-------------------> | | | ath12k (ar) | | +-------------+ | | | | | | | | | | | ath12k (ar) | | | | | | | | | | | | | | | | | +-------------+ | | | | | | | | | +---------------------+ +---------------------+ Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20240118010320.3918136-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 10 +- drivers/net/wireless/ath/ath12k/core.h | 37 ++- drivers/net/wireless/ath/ath12k/mac.c | 421 +++++++++++++++++-------- drivers/net/wireless/ath/ath12k/mac.h | 4 +- drivers/net/wireless/ath/ath12k/reg.c | 3 +- 5 files changed, 337 insertions(+), 138 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index d21618ca70b9..1baad3302157 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -923,6 +923,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) { struct ath12k *ar; struct ath12k_pdev *pdev; + struct ath12k_hw *ah; int i; spin_lock_bh(&ab->base_lock); @@ -932,13 +933,20 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) if (ab->is_reset) set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags); + for (i = 0; i < ab->num_hw; i++) { + if (!ab->ah[i]) + continue; + + ah = ab->ah[i]; + ieee80211_stop_queues(ah->hw); + } + for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; if (!ar || ar->state == ATH12K_STATE_OFF) continue; - ieee80211_stop_queues(ath12k_ar_to_hw(ar)); ath12k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 10a292b28d4d..a56fc74366b4 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -473,7 +473,7 @@ struct ath12k_per_peer_tx_stats { struct ath12k { struct ath12k_base *ab; struct ath12k_pdev *pdev; - struct ieee80211_hw *hw; + struct ath12k_hw *ah; struct ath12k_wmi_pdev *wmi; struct ath12k_pdev_dp dp; u8 mac_addr[ETH_ALEN]; @@ -537,6 +537,7 @@ struct ath12k { /* pdev_idx starts from 0 whereas pdev->pdev_id starts with 1 */ u8 pdev_idx; u8 lmac_id; + u8 hw_link_id; struct completion peer_assoc_done; struct completion peer_delete_done; @@ -596,6 +597,13 @@ struct ath12k { int monitor_vdev_id; }; +struct ath12k_hw { + struct ieee80211_hw *hw; + + u8 num_radio; + struct ath12k radio[] __aligned(sizeof(void *)); +}; + struct ath12k_band_cap { u32 phy_id; u32 max_bw_supported; @@ -729,6 +737,16 @@ struct ath12k_base { u8 fw_pdev_count; struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS]; + + /* Holds information of wiphy (hw) registration. + * + * In Multi/Single Link Operation case, all pdevs are registered as + * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is + * registered as separate wiphys. + */ + struct ath12k_hw *ah[MAX_RADIOS]; + u8 num_hw; + struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS]; unsigned long long free_vdev_map; unsigned long long free_vdev_stats_id_map; @@ -810,6 +828,11 @@ struct ath12k_base { u8 drv_priv[] __aligned(sizeof(void *)); }; +struct ath12k_pdev_map { + struct ath12k_base *ab; + u8 pdev_idx; +}; + int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab); int ath12k_core_pre_init(struct ath12k_base *ab); int ath12k_core_init(struct ath12k_base *ath12k); @@ -896,8 +919,18 @@ static inline const char *ath12k_bus_str(enum ath12k_bus bus) return "unknown"; } +static inline struct ath12k_hw *ath12k_hw_to_ah(struct ieee80211_hw *hw) +{ + return hw->priv; +} + +static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah) +{ + return ah->radio; +} + static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) { - return ar->hw; + return ar->ah->hw; } #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 27c5337a764e..fe600dbef875 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1124,9 +1124,12 @@ 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; - SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); - SET_IEEE80211_DEV(hw, ab->dev); + wiphy->max_ap_assoc_sta = ar->max_num_stations; - ret = ath12k_mac_setup_iface_combinations(ar); - if (ret) { - ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret); - goto err_setup_unregister; - } + cap = &pdev->cap; wiphy->available_antennas_rx = cap->rx_chain_mask; wiphy->available_antennas_tx = cap->tx_chain_mask; - wiphy->interface_modes = ab->hw_params->interface_modes; + SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); + SET_IEEE80211_DEV(hw, ab->dev); + + ret = ath12k_mac_setup_iface_combinations(ah); + if (ret) { + ath12k_err(ab, "failed to setup interface combinations: %d\n", ret); + goto err_cleanup_unregister; + } + + wiphy->interface_modes = ath12k_mac_get_ifmodes(ah); if (wiphy->bands[NL80211_BAND_2GHZ] && wiphy->bands[NL80211_BAND_5GHZ] && @@ -7604,8 +7727,6 @@ static int ath12k_mac_hw_register(struct ath12k *ar) wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; - wiphy->max_ap_assoc_sta = ar->max_num_stations; - hw->queues = ATH12K_HW_MAX_QUEUES; wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; @@ -7642,7 +7763,7 @@ static int ath12k_mac_hw_register(struct ath12k *ar) ret = ieee80211_register_hw(hw); if (ret) { - ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret); + ath12k_err(ab, "ieee80211 registration failed: %d\n", ret); goto err_free_if_combs; } @@ -7670,14 +7791,12 @@ 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); - - SET_IEEE80211_DEV(hw, NULL); +err_cleanup_unregister: + ath12k_mac_cleanup_unregister(ar); out: + SET_IEEE80211_DEV(hw, NULL); + return ret; } @@ -7723,8 +7842,7 @@ static void ath12k_mac_setup(struct ath12k *ar) int ath12k_mac_register(struct ath12k_base *ab) { - struct ath12k *ar; - struct ath12k_pdev *pdev; + struct ath12k_hw *ah; int i; int ret; @@ -7735,22 +7853,23 @@ int ath12k_mac_register(struct ath12k_base *ab) ab->cc_freq_hz = 320000; ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; - ret = ath12k_mac_hw_register(ar); + ret = ath12k_mac_hw_register(ah); if (ret) - goto err_cleanup; + goto err; } return 0; -err_cleanup: +err: for (i = i - 1; i >= 0; i--) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - ath12k_mac_hw_unregister(ar); + ah = ab->ah[i]; + if (!ah) + continue; + + ath12k_mac_hw_unregister(ah); } return ret; @@ -7758,89 +7877,125 @@ 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; - ar = hw->priv; - ar->hw = hw; + ah = ath12k_hw_to_ah(hw); + ah->hw = hw; + ah->num_radio = num_pdev_map; + + for (i = 0; i < num_pdev_map; i++) { + ab = pdev_map[i].ab; + pdev_idx = pdev_map[i].pdev_idx; + pdev = &ab->pdevs[pdev_idx]; + + ar = ath12k_ah_to_ar(ah); + ar->ah = ah; ar->ab = ab; + ar->hw_link_id = i; ar->pdev = pdev; - ar->pdev_idx = i; + ar->pdev_idx = pdev_idx; pdev->ar = ar; ath12k_mac_setup(ar); } - return 0; - -err_free_mac: - ath12k_mac_hw_destroy(ab); - - return ret; + return ah; } void ath12k_mac_destroy(struct ath12k_base *ab) { - ath12k_mac_hw_destroy(ab); + struct ath12k_pdev *pdev; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + if (!pdev->ar) + continue; + + pdev->ar = NULL; + } + + for (i = 0; i < ab->num_hw; i++) { + if (!ab->ah[i]) + continue; + + ath12k_mac_hw_destroy(ab->ah[i]); + ab->ah[i] = NULL; + } } int ath12k_mac_allocate(struct ath12k_base *ab) { - int ret; + struct ath12k_hw *ah; + struct ath12k_pdev_map pdev_map[MAX_RADIOS]; + int ret, i, j; + u8 radio_per_hw; if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) return 0; - ret = ath12k_mac_hw_allocate(ab); - if (ret) - return ret; + ab->num_hw = ab->num_radios; + radio_per_hw = 1; + + for (i = 0; i < ab->num_hw; i++) { + for (j = 0; j < radio_per_hw; j++) { + pdev_map[j].ab = ab; + pdev_map[j].pdev_idx = (i * radio_per_hw) + j; + } + + ah = ath12k_mac_hw_allocate(ab, pdev_map, radio_per_hw); + if (!ah) { + ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n", + i); + goto err; + } + + ab->ah[i] = ah; + } ath12k_dp_pdev_pre_alloc(ab); return 0; + +err: + for (i = i - 1; i >= 0; i--) { + if (!ab->ah[i]) + continue; + + ath12k_mac_hw_destroy(ab->ah[i]); + ab->ah[i] = NULL; + } + + return ret; } diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 7c63bb628adc..3f5e1be0dff9 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_MAC_H @@ -12,6 +12,8 @@ struct ath12k; struct ath12k_base; +struct ath12k_hw; +struct ath12k_pdev_map; struct ath12k_generic_iter { struct ath12k *ar; diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 88e71d171355..a164f15d1e2b 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -48,7 +48,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath12k_wmi_init_country_arg arg; - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); int ret; ath12k_dbg(ar->ab, ATH12K_DBG_REG, From 9f9df1a2535f6c890242b80d8538bd90ae540647 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 18 Jan 2024 07:53:48 +0200 Subject: [PATCH 0150/2255] wifi: ath12k: add support for collecting firmware log Currently there is no way to collect firmware log because firmware does not send it to host. Also host does not handle WMI_DIAG_EVENTID which is used by firmware to upload firmware log. So add support for it by firstly enabling firmware log upload via a QMI message, and secondly processing WMI DIAG event to expose it to userspace via trace event. This change applies to both WCN7850 and QCN9274. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240115023726.2866-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 93 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/qmi.h | 17 ++++- drivers/net/wireless/ath/ath12k/trace.h | 29 +++++++- drivers/net/wireless/ath/ath12k/wmi.c | 9 +++ 4 files changed, 146 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index d20d08023c81..69f56400367c 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1954,6 +1954,50 @@ static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { }, }; +static const struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, + enable_fwlog_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, + enable_fwlog), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_wlan_ini_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, struct qmi_wlanfw_host_cap_req_msg_v01 *req) { @@ -2853,6 +2897,49 @@ 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); From 1779487e72e0390d240df271be0005397d0110f3 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:53 -0800 Subject: [PATCH 0151/2255] wifi: ath10k: add missing wmi_10_4_feature_mask documentation Currently kernel-doc reports the following issues: drivers/net/wireless/ath/ath10k/wmi.h:3033: warning: Enum value 'WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT' not described in enum 'wmi_10_4_feature_mask' drivers/net/wireless/ath/ath10k/wmi.h:3033: warning: Enum value 'WMI_10_4_REPORT_AIRTIME' not described in enum 'wmi_10_4_feature_mask' Update the kernel-doc for enum wmi_10_4_feature_mask to add the missing documentation. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-1-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b64b6e214bae..2379501225a4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_H_ @@ -3008,8 +3008,11 @@ enum wmi_coex_version { * @WMI_10_4_TDLS_UAPSD_SLEEP_STA: TDLS sleep sta support enable/disable * @WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE: TDLS connection tracker in host * enable/disable - * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY:Explicit TDLS mode enable/disable + * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY: Explicit TDLS mode enable/disable * @WMI_10_4_TX_DATA_ACK_RSSI: Enable DATA ACK RSSI if firmware is capable + * @WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT: Firmware supports Extended Peer + * TID configuration for QoS related settings + * @WMI_10_4_REPORT_AIRTIME: Firmware supports transmit airtime reporting */ enum wmi_10_4_feature_mask { WMI_10_4_LTEU_SUPPORT = BIT(0), From 5f813b0447feef3a4883b66e600c7317a4d7d76b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:54 -0800 Subject: [PATCH 0152/2255] wifi: ath10k: correctly document enum wmi_tlv_tx_pause_id Currently kernel-doc reports the issue: drivers/net/wireless/ath/ath10k/wmi-tlv.h:2363: warning: cannot understand function prototype: 'enum wmi_tlv_tx_pause_id ' Update the enum wmi_tlv_tx_pause_id documentation to fix this issue. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-2-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi-tlv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 83a8f07a687f..8a2f87d0a3a3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_TLV_H #define _WMI_TLV_H @@ -2343,7 +2343,7 @@ struct wmi_tlv_adaptive_qcs { } __packed; /** - * wmi_tlv_tx_pause_id - firmware tx queue pause reason types + * enum wmi_tlv_tx_pause_id - firmware tx queue pause reason types * * @WMI_TLV_TX_PAUSE_ID_MCC: used for by multi-channel firmware scheduler. * Only vdev_map is valid. From 75dd17fdef110d99a2613d1284d2863cfc7cf6e9 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:55 -0800 Subject: [PATCH 0153/2255] wifi: ath10k: fix htt_q_state_conf & htt_q_state kernel-doc Currently kernel-doc reports: drivers/net/wireless/ath/ath10k/htt.h:1488: warning: cannot understand function prototype: 'struct htt_q_state_conf ' drivers/net/wireless/ath/ath10k/htt.h:1542: warning: cannot understand function prototype: 'struct htt_q_state ' Update the kernel-doc for these two structs to resolve the warnings. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-3-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/htt.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 4a9270e2a4c8..eb0ce2f49315 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021, 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HTT_H_ @@ -1474,15 +1474,19 @@ enum htt_q_depth_type { #define HTT_TX_Q_STATE_ENTRY_MULTIPLIER 0 /** - * htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config + * struct htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config * * Defines host q state format and behavior. See htt_q_state. * + * @paddr: Queue physical address + * @num_peers: Number of supported peers + * @num_tids: Number of supported TIDs * @record_size: Defines the size of each host q entry in bytes. In practice * however firmware (at least 10.4.3-00191) ignores this host * configuration value and uses hardcoded value of 1. * @record_multiplier: This is valid only when q depth type is MSDUs. It * defines the exponent for the power of 2 multiplication. + * @pad: struct padding for 32-bit alignment */ struct htt_q_state_conf { __le32 paddr; @@ -1518,7 +1522,7 @@ struct htt_frag_desc_bank_cfg64 { #define HTT_TX_Q_STATE_ENTRY_EXP_LSB 6 /** - * htt_q_state - shared between host and firmware via DMA + * struct htt_q_state - shared between host and firmware via DMA * * This structure is used for the host to expose it's software queue state to * firmware so that its rate control can schedule fetch requests for optimized From c80cc5cfefbaca35e019a26f31faa11031c13665 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:56 -0800 Subject: [PATCH 0154/2255] wifi: ath10k: Fix htt_data_tx_completion kernel-doc warning Currently kernel-doc reports: drivers/net/wireless/ath/ath10k/htt.h:911: warning: Cannot understand * @brief target -> host TX completion indication message definition on line 911 - I thought it was a doc line This is because even though struct htt_data_tx_completion uses the kernel-doc marker "/**", it doesn't actual use kernel-doc syntax for the documentation. Rather than try to update this legacy driver documentation to use kernel-doc style, just replace the comment marker. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-4-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/htt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index eb0ce2f49315..603f6de62b0a 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -906,7 +906,7 @@ struct htt_data_tx_completion_ext { __le16 msdus_rssi[]; } __packed; -/** +/* * @brief target -> host TX completion indication message definition * * @details From f020c30299323c206b9041dd478ac040dd828ec0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:57 -0800 Subject: [PATCH 0155/2255] wifi: ath10k: Fix enum ath10k_fw_crash_dump_type kernel-doc The kernel-doc script currently reports: drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_REGISTERS' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_CE_DATA' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_RAM_DATA' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_MAX' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Excess enum value 'ATH10K_FW_CRASH_DUMP_REGDUMP' description in 'ath10k_fw_crash_dump_type' Fix these issues with the enum ath10k_fw_crash_dump_type kernel-doc. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-5-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/coredump.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index e5ef0352e319..8d274e0f374b 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _COREDUMP_H_ @@ -13,7 +13,11 @@ /** * enum ath10k_fw_crash_dump_type - types of data in the dump file - * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format + * @ATH10K_FW_CRASH_DUMP_REGISTERS: Register crash dump in binary format + * @ATH10K_FW_CRASH_DUMP_CE_DATA: Copy Engine crash dump data + * @ATH10K_FW_CRASH_DUMP_RAM_DATA: RAM crash dump data, contains multiple + * struct ath10k_dump_ram_data_hdr + * @ATH10K_FW_CRASH_DUMP_MAX: Maximum enumeration */ enum ath10k_fw_crash_dump_type { ATH10K_FW_CRASH_DUMP_REGISTERS = 0, From aacb84adf1a2e9eae06920e2fc471b1272132510 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 Jan 2024 08:38:26 +0800 Subject: [PATCH 0156/2255] wifi: rtw89: add mlo_dbcc_mode for WiFi 7 chips WiFi 7 chips can operate in various MLO applications, such as 1 link (2SS) and 2 links (1SS + 1SS), and we should configure different PHY mode for each of them. For example, - MLO_2_PLUS_0_1RF is 1 link with 2SS rate, and enable one RF component. - MLO_1_PLUS_1_1RF is 2 links with 1SS rate for each, and enable one RF component that can support two paths. By default, we set the mode to legacy MLO_DBCC_NOT_SUPPORT (don't support MLO and DBCC yet), and later we will introduce logic to change the mode. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240120003831.7014-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 2 ++ drivers/net/wireless/realtek/rtw89/core.h | 27 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 347703b68dfd..b1fcd284a6b8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4191,6 +4191,8 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) rtw89_traffic_stats_init(rtwdev, &rtwdev->stats); rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR; + rtwdev->dbcc_en = false; + rtwdev->mlo_dbcc_mode = MLO_DBCC_NOT_SUPPORT; 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 80f67f1b0679..34e52f7c3bba 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3243,6 +3243,20 @@ enum rtw89_dma_ch { RTW89_DMA_CH_NUM = 13 }; +#define MLO_MODE_FOR_BB0_BB1_RF(bb0, bb1, rf) ((rf) << 12 | (bb1) << 4 | (bb0)) + +enum rtw89_mlo_dbcc_mode { + MLO_DBCC_NOT_SUPPORT = 1, + MLO_0_PLUS_2_1RF = MLO_MODE_FOR_BB0_BB1_RF(0, 2, 1), + MLO_0_PLUS_2_2RF = MLO_MODE_FOR_BB0_BB1_RF(0, 2, 2), + MLO_1_PLUS_1_1RF = MLO_MODE_FOR_BB0_BB1_RF(1, 1, 1), + MLO_1_PLUS_1_2RF = MLO_MODE_FOR_BB0_BB1_RF(1, 1, 2), + MLO_2_PLUS_0_1RF = MLO_MODE_FOR_BB0_BB1_RF(2, 0, 1), + MLO_2_PLUS_0_2RF = MLO_MODE_FOR_BB0_BB1_RF(2, 0, 2), + MLO_2_PLUS_2_2RF = MLO_MODE_FOR_BB0_BB1_RF(2, 2, 2), + DBCC_LEGACY = 0xffffffff, +}; + enum rtw89_qta_mode { RTW89_QTA_SCC, RTW89_QTA_DLFW, @@ -4839,6 +4853,7 @@ struct rtw89_dev { const struct ieee80211_ops *ops; bool dbcc_en; + enum rtw89_mlo_dbcc_mode mlo_dbcc_mode; struct rtw89_hw_scan_info scan_info; const struct rtw89_chip_info *chip; const struct rtw89_pci_info *pci_info; @@ -5835,6 +5850,18 @@ out: rcu_read_unlock(); } +static inline bool rtw89_is_mlo_1_1(struct rtw89_dev *rtwdev) +{ + switch (rtwdev->mlo_dbcc_mode) { + case MLO_1_PLUS_1_1RF: + case MLO_1_PLUS_1_2RF: + case DBCC_LEGACY: + return true; + default: + return false; + } +} + int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel); int rtw89_h2c_tx(struct rtw89_dev *rtwdev, From 5c682bcb2cedc4188102fa7fe04e116f5bd3ddea Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 Jan 2024 08:38:27 +0800 Subject: [PATCH 0157/2255] wifi: rtw89: 8922a: add chip_ops::{enable,disable}_bb_rf When we are going to up interface to make connection, turn on BB and RF hardware power by enable_bb_rf ops. Oppositely, using disable_bb_rf to turn them off. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240120003831.7014-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 36 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 19 ++++++++++ 2 files changed, 55 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index b411bf726849..c4a9ddeb38e0 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4488,6 +4488,42 @@ #define B_BE_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) #define B_BE_SER_L0_COUNTER_MASK GENMASK(8, 0) +#define R_BE_DMAC_SYS_CR32B 0x842C +#define B_BE_DMAC_BB_PHY1_MASK GENMASK(31, 16) +#define B_BE_DMAC_BB_PHY0_MASK GENMASK(15, 0) +#define B_BE_DMAC_BB_CTRL_39 BIT(31) +#define B_BE_DMAC_BB_CTRL_38 BIT(30) +#define B_BE_DMAC_BB_CTRL_37 BIT(29) +#define B_BE_DMAC_BB_CTRL_36 BIT(28) +#define B_BE_DMAC_BB_CTRL_35 BIT(27) +#define B_BE_DMAC_BB_CTRL_34 BIT(26) +#define B_BE_DMAC_BB_CTRL_33 BIT(25) +#define B_BE_DMAC_BB_CTRL_32 BIT(24) +#define B_BE_DMAC_BB_CTRL_31 BIT(23) +#define B_BE_DMAC_BB_CTRL_30 BIT(22) +#define B_BE_DMAC_BB_CTRL_29 BIT(21) +#define B_BE_DMAC_BB_CTRL_28 BIT(20) +#define B_BE_DMAC_BB_CTRL_27 BIT(19) +#define B_BE_DMAC_BB_CTRL_26 BIT(18) +#define B_BE_DMAC_BB_CTRL_25 BIT(17) +#define B_BE_DMAC_BB_CTRL_24 BIT(16) +#define B_BE_DMAC_BB_CTRL_23 BIT(15) +#define B_BE_DMAC_BB_CTRL_22 BIT(14) +#define B_BE_DMAC_BB_CTRL_21 BIT(13) +#define B_BE_DMAC_BB_CTRL_20 BIT(12) +#define B_BE_DMAC_BB_CTRL_19 BIT(11) +#define B_BE_DMAC_BB_CTRL_18 BIT(10) +#define B_BE_DMAC_BB_CTRL_17 BIT(9) +#define B_BE_DMAC_BB_CTRL_16 BIT(8) +#define B_BE_DMAC_BB_CTRL_15 BIT(7) +#define B_BE_DMAC_BB_CTRL_14 BIT(6) +#define B_BE_DMAC_BB_CTRL_13 BIT(5) +#define B_BE_DMAC_BB_CTRL_12 BIT(4) +#define B_BE_DMAC_BB_CTRL_11 BIT(3) +#define B_BE_DMAC_BB_CTRL_10 BIT(2) +#define B_BE_DMAC_BB_CTRL_9 BIT(1) +#define B_BE_DMAC_BB_CTRL_8 BIT(0) + #define R_BE_DLE_EMPTY0 0x8430 #define B_BE_PLE_EMPTY_QTA_DMAC_H2D BIT(27) #define B_BE_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 7ded6f431309..1ccaea3af4ae 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -807,6 +807,23 @@ static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, rtw8922a_set_channel_bb(rtwdev, chan, phy_idx); } +static int rtw8922a_mac_enable_bb_rf(struct rtw89_dev *rtwdev) +{ + rtw89_write8_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_FEN_BBPLAT_RSTB | B_BE_FEN_BB_IP_RSTN); + rtw89_write32(rtwdev, R_BE_DMAC_SYS_CR32B, 0x7FF97FF9); + + return 0; +} + +static int rtw8922a_mac_disable_bb_rf(struct rtw89_dev *rtwdev) +{ + rtw89_write8_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_FEN_BBPLAT_RSTB | B_BE_FEN_BB_IP_RSTN); + + return 0; +} + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -817,6 +834,8 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { #endif static const struct rtw89_chip_ops rtw8922a_chip_ops = { + .enable_bb_rf = rtw8922a_mac_enable_bb_rf, + .disable_bb_rf = rtw8922a_mac_disable_bb_rf, .set_channel = rtw8922a_set_channel, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, From 10af16279a9a4aab4e6e5767c88cac9828d7ce48 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 Jan 2024 08:38:28 +0800 Subject: [PATCH 0158/2255] wifi: rtw89: 8922a: add chip_ops related to BB init The chip_ops::bb_preinit and ::bb_postinit are called before and after loading BB parameters from tables of firmware file. The ::bb_reset is used to reset hardware state, and currently it is not needed by 8922AE so leave it as empty. The ::bb_sethw is to implement conditional parameters. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240120003831.7014-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 1 + drivers/net/wireless/realtek/rtw89/core.h | 15 ++ drivers/net/wireless/realtek/rtw89/phy.c | 1 + drivers/net/wireless/realtek/rtw89/phy.h | 10 + drivers/net/wireless/realtek/rtw89/reg.h | 73 +++++++ 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 | 194 ++++++++++++++++++ 10 files changed, 298 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index b1fcd284a6b8..aefb5a078d1a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4074,6 +4074,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) return ret; rtw89_phy_init_bb_reg(rtwdev); + rtw89_chip_bb_postinit(rtwdev); rtw89_phy_init_rf_reg(rtwdev, false); rtw89_btc_ntfy_init(rtwdev, BTC_MODE_NORMAL); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 34e52f7c3bba..f56a5d423eb0 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3133,6 +3133,7 @@ struct rtw89_chip_ops { int (*enable_bb_rf)(struct rtw89_dev *rtwdev); int (*disable_bb_rf)(struct rtw89_dev *rtwdev); void (*bb_preinit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); + void (*bb_postinit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void (*bb_reset)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void (*bb_sethw)(struct rtw89_dev *rtwdev); @@ -5546,6 +5547,20 @@ void rtw89_chip_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) chip->ops->bb_preinit(rtwdev, phy_idx); } +static inline +void rtw89_chip_bb_postinit(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!chip->ops->bb_postinit) + return; + + chip->ops->bb_postinit(rtwdev, RTW89_PHY_0); + + if (rtwdev->dbcc_en) + chip->ops->bb_postinit(rtwdev, RTW89_PHY_1); +} + static inline void rtw89_chip_bb_sethw(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 926a4459ea4f..7880fbaee092 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1570,6 +1570,7 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1); } +EXPORT_SYMBOL(rtw89_phy_set_phy_regs); void rtw89_phy_write_reg3_tbl(struct rtw89_dev *rtwdev, const struct rtw89_phy_reg3_tbl *tbl) diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index a16bff77661f..c05f724a84ce 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -7,6 +7,7 @@ #include "core.h" +#define RTW89_BBMCU_ADDR_OFFSET 0x30000 #define RTW89_RF_ADDR_ADSEL_MASK BIT(16) #define get_phy_headline(addr) FIELD_GET(GENMASK(31, 28), addr) @@ -611,6 +612,15 @@ static inline u32 rtw89_phy_read32_mask(struct rtw89_dev *rtwdev, return rtw89_read32_mask(rtwdev, addr + phy->cr_base, mask); } +static inline void rtw89_bbmcu_write32(struct rtw89_dev *rtwdev, + u32 addr, u32 data, enum rtw89_phy_idx phy_idx) +{ + if (phy_idx && addr < 0x10000) + addr += 0x20000; + + rtw89_write32(rtwdev, addr + RTW89_BBMCU_ADDR_OFFSET, data); +} + static inline enum rtw89_gain_offset rtw89_subband_to_gain_offset_band_of_ofdm(enum rtw89_subband subband) { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index c4a9ddeb38e0..c4c886fd1941 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4033,6 +4033,30 @@ #define B_BE_SYSON_DIS_PMCR_BE_WRMSK BIT(2) #define B_BE_SYSON_R_BE_ARB_MASK GENMASK(1, 0) +#define R_BE_MEM_PWR_CTRL 0x00D0 +#define B_BE_DMEM5_WLMCU_DS BIT(31) +#define B_BE_DMEM4_WLMCU_DS BIT(30) +#define B_BE_DMEM3_WLMCU_DS BIT(29) +#define B_BE_DMEM2_WLMCU_DS BIT(28) +#define B_BE_DMEM1_WLMCU_DS BIT(27) +#define B_BE_DMEM0_WLMCU_DS BIT(26) +#define B_BE_IMEM5_WLMCU_DS BIT(25) +#define B_BE_IMEM4_WLMCU_DS BIT(24) +#define B_BE_IMEM3_WLMCU_DS BIT(23) +#define B_BE_IMEM2_WLMCU_DS BIT(22) +#define B_BE_IMEM1_WLMCU_DS BIT(21) +#define B_BE_IMEM0_WLMCU_DS BIT(20) +#define B_BE_MEM_BBMCU1_DS BIT(19) +#define B_BE_MEM_BBMCU0_DS_V1 BIT(17) +#define B_BE_MEM_BT_DS BIT(10) +#define B_BE_MEM_SDIO_LS BIT(9) +#define B_BE_MEM_SDIO_DS BIT(8) +#define B_BE_MEM_USB_LS BIT(7) +#define B_BE_MEM_USB_DS BIT(6) +#define B_BE_MEM_PCI_LS BIT(5) +#define B_BE_MEM_PCI_DS BIT(4) +#define B_BE_MEM_WLMAC_LS BIT(3) + #define R_BE_PCIE_MIO_INTF 0x00E4 #define B_BE_AON_MIO_EPHY_1K_SEL_MASK GENMASK(29, 24) #define B_BE_PCIE_MIO_ADDR_PAGE_V1_MASK GENMASK(20, 16) @@ -7542,10 +7566,14 @@ #define RR_RFC_CKEN BIT(1) #define R_UPD_P0 0x0000 +#define R_BBCLK 0x0000 +#define B_CLK_640M BIT(2) #define R_RSTB_WATCH_DOG 0x000C #define B_P0_RSTB_WATCH_DOG BIT(0) #define B_P1_RSTB_WATCH_DOG BIT(1) #define B_UPD_P0_EN BIT(31) +#define R_EMLSR 0x0044 +#define B_EMLSR_PARM GENMASK(27, 12) #define R_SPOOF_CG 0x00B4 #define B_SPOOF_CG_EN BIT(17) #define R_CHINFO_SEG 0x00B4 @@ -7585,6 +7613,9 @@ #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_EN_SND_WO_NDP 0x047c +#define R_EN_SND_WO_NDP_C1 0x147c +#define B_EN_SND_WO_NDP BIT(1) #define R_UPD_CLK_ADC 0x0700 #define B_UPD_CLK_ADC_VAL GENMASK(26, 25) #define B_UPD_CLK_ADC_ON BIT(24) @@ -7696,6 +7727,8 @@ #define B_SNDCCA_A1_EN GENMASK(19, 12) #define R_SNDCCA_A2 0x0CA0 #define B_SNDCCA_A2_VAL GENMASK(19, 12) +#define R_UDP_COEEF 0x0CBC +#define B_UDP_COEEF BIT(19) #define R_TX_COLLISION_T2R_ST_BE 0x0CC8 #define B_TX_COLLISION_T2R_ST_BE_M GENMASK(13, 8) #define R_RXHT_MCS_LIMIT 0x0D18 @@ -7868,6 +7901,10 @@ #define B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0 BIT(13) #define R_DBCC_80P80_SEL_EVM_RPT2 0x2A10 #define B_DBCC_80P80_SEL_EVM_RPT2_EN BIT(0) +#define R_AFEDAC0 0x2A5C +#define B_AFEDAC0 GENMASK(31, 27) +#define R_AFEDAC1 0x2A60 +#define B_AFEDAC1 GENMASK(2, 0) #define R_IQKDPK_HC 0x2AB8 #define B_IQKDPK_HC BIT(28) #define R_P1_EN_SOUND_WO_NDP 0x2D7C @@ -8350,12 +8387,48 @@ #define B_DCFO_WEIGHT_MSK_V1 GENMASK(31, 28) #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_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_SLOPE 0x6B6C +#define B_EHT_RATE_TH GENMASK(31, 28) +#define B_SLOPE_B GENMASK(27, 14) +#define B_SLOPE_A GENMASK(13, 0) +#define R_SC_CORNER 0x6B70 +#define B_SC_CORNER GENMASK(10, 0) +#define R_MAG_A 0x6BF4 +#define B_MGA_AEND GENMASK(31, 24) +#define R_MAG_AB 0x6BF8 +#define B_BY_SLOPE GENMASK(31, 24) +#define B_MAG_AB GENMASK(23, 0) +#define R_BEDGE 0x6BFC +#define B_EHT_MCS14 BIT(31) +#define B_HE_RATE_TH GENMASK(30, 27) +#define R_BEDGE2 0x6C00 +#define B_EHT_MCS15 BIT(31) +#define B_HT_VHT_TH GENMASK(11, 0) +#define R_BEDGE3 0x6C04 +#define B_TB_EN BIT(23) +#define B_HEMU_EN BIT(21) +#define B_HEERSU_EN BIT(19) +#define B_EHTTB_EN BIT(15) +#define B_BEDGE_CFG GENMASK(1, 0) +#define R_SU_PUNC 0x6C08 +#define B_SU_PUNC_EN BIT(1) +#define R_BEDGE5 0x6C10 +#define B_HWGEN_EN BIT(25) +#define B_PWROFST_COMP BIT(20) #define R_RPL_BIAS_COMP1 0x6DF0 #define B_RPL_BIAS_COMP1_MASK GENMASK(7, 0) +#define R_DBCC_FA 0x703C +#define B_DBCC_FA BIT(12) #define R_P1_TSSI_ALIM1 0x7630 #define B_P1_TSSI_ALIM1 GENMASK(29, 0) #define B_P1_TSSI_ALIM11 GENMASK(29, 20) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 40020d0ebbdf..09b23c56aa8e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2299,6 +2299,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .enable_bb_rf = rtw8851b_mac_enable_bb_rf, .disable_bb_rf = rtw8851b_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8851b_bb_reset, .bb_sethw = rtw8851b_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 726b08ca5897..c28f05bbdccf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2043,6 +2043,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .enable_bb_rf = rtw89_mac_enable_bb_rf, .disable_bb_rf = rtw89_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8852a_bb_reset, .bb_sethw = rtw8852a_bb_sethw, .read_rf = rtw89_phy_read_rf, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index b3ad84cfad95..18ed372ed5cd 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2468,6 +2468,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .enable_bb_rf = rtw8852b_mac_enable_bb_rf, .disable_bb_rf = rtw8852b_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8852b_bb_reset, .bb_sethw = rtw8852b_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index cbc896a29fb4..431acfaba89b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2813,6 +2813,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .enable_bb_rf = rtw8852c_mac_enable_bb_rf, .disable_bb_rf = rtw8852c_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8852c_bb_reset, .bb_sethw = rtw8852c_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 1ccaea3af4ae..1a070d6e1c16 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -792,6 +792,196 @@ static void rtw8922a_ctrl_ch(struct rtw89_dev *rtwdev, rtw8922a_set_gain(rtwdev, chan, RF_PATH_B, phy_idx); } +static void rtw8922a_ctrl_afe_dac(struct rtw89_dev *rtwdev, enum rtw89_bandwidth bw, + enum rtw89_rf_path path) +{ + u32 cr_ofst = 0x0; + + if (path == RF_PATH_B) + cr_ofst = 0x100; + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + case RTW89_CHANNEL_WIDTH_10: + case RTW89_CHANNEL_WIDTH_20: + case RTW89_CHANNEL_WIDTH_40: + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, R_AFEDAC0 + cr_ofst, B_AFEDAC0, 0xE); + rtw89_phy_write32_mask(rtwdev, R_AFEDAC1 + cr_ofst, B_AFEDAC1, 0x7); + break; + case RTW89_CHANNEL_WIDTH_160: + rtw89_phy_write32_mask(rtwdev, R_AFEDAC0 + cr_ofst, B_AFEDAC0, 0xD); + rtw89_phy_write32_mask(rtwdev, R_AFEDAC1 + cr_ofst, B_AFEDAC1, 0x6); + break; + default: + break; + } +} + +static const struct rtw89_reg2_def bb_mcu0_init_reg[] = { + {0x6990, 0x00000000}, + {0x6994, 0x00000000}, + {0x6998, 0x00000000}, + {0x6820, 0xFFFFFFFE}, + {0x6800, 0xC0000FFE}, + {0x6808, 0x76543210}, + {0x6814, 0xBFBFB000}, + {0x6818, 0x0478C009}, + {0x6800, 0xC0000FFF}, + {0x6820, 0xFFFFFFFF}, +}; + +static const struct rtw89_reg2_def bb_mcu1_init_reg[] = { + {0x6990, 0x00000000}, + {0x6994, 0x00000000}, + {0x6998, 0x00000000}, + {0x6820, 0xFFFFFFFE}, + {0x6800, 0xC0000FFE}, + {0x6808, 0x76543210}, + {0x6814, 0xBFBFB000}, + {0x6818, 0x0478C009}, + {0x6800, 0xC0000FFF}, + {0x6820, 0xFFFFFFFF}, +}; + +static void rtw8922a_bbmcu_cr_init(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_reg2_def *reg; + int size; + int i; + + if (phy_idx == RTW89_PHY_0) { + reg = bb_mcu0_init_reg; + size = ARRAY_SIZE(bb_mcu0_init_reg); + } else { + reg = bb_mcu1_init_reg; + size = ARRAY_SIZE(bb_mcu1_init_reg); + } + + for (i = 0; i < size; i++, reg++) + rtw89_bbmcu_write32(rtwdev, reg->addr, reg->data, phy_idx); +} + +static const u32 dmac_sys_mask[2] = {B_BE_DMAC_BB_PHY0_MASK, B_BE_DMAC_BB_PHY1_MASK}; +static const u32 bbrst_mask[2] = {B_BE_FEN_BBPLAT_RSTB, B_BE_FEN_BB1PLAT_RSTB}; +static const u32 glbrst_mask[2] = {B_BE_FEN_BB_IP_RSTN, B_BE_FEN_BB1_IP_RSTN}; +static const u32 mcu_bootrdy_mask[2] = {B_BE_BOOT_RDY0, B_BE_BOOT_RDY1}; + +static void rtw8922a_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u32 rdy = 0; + + if (phy_idx == RTW89_PHY_1) + rdy = 1; + + rtw89_write32_mask(rtwdev, R_BE_DMAC_SYS_CR32B, dmac_sys_mask[phy_idx], 0x7FF9); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x0); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x0); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x1); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, mcu_bootrdy_mask[phy_idx], rdy); + rtw89_write32_mask(rtwdev, R_BE_MEM_PWR_CTRL, B_BE_MEM_BBMCU0_DS_V1, 0); + + fsleep(1); + rtw8922a_bbmcu_cr_init(rtwdev, phy_idx); +} + +static void rtw8922a_bb_postinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + if (phy_idx == RTW89_PHY_0) + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, mcu_bootrdy_mask[phy_idx]); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx]); + + rtw89_phy_write32_set(rtwdev, R_BBCLK, B_CLK_640M); + rtw89_phy_write32_clr(rtwdev, R_TXSCALE, B_TXFCTR_EN); + rtw89_phy_set_phy_regs(rtwdev, R_TXFCTR, B_TXFCTR_THD, 0x200); + rtw89_phy_set_phy_regs(rtwdev, R_SLOPE, B_EHT_RATE_TH, 0xA); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE, B_HE_RATE_TH, 0xA); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE2, B_HT_VHT_TH, 0xAAA); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE, B_EHT_MCS14, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE2, B_EHT_MCS15, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_EHTTB_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_HEERSU_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_HEMU_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_TB_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_SU_PUNC, B_SU_PUNC_EN, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE5, B_HWGEN_EN, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE5, B_PWROFST_COMP, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_MAG_AB, B_BY_SLOPE, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_MAG_A, B_MGA_AEND, 0xe0); + rtw89_phy_set_phy_regs(rtwdev, R_MAG_AB, B_MAG_AB, 0xe0c000); + rtw89_phy_set_phy_regs(rtwdev, R_SLOPE, B_SLOPE_A, 0x3FE0); + rtw89_phy_set_phy_regs(rtwdev, R_SLOPE, B_SLOPE_B, 0x3FE0); + rtw89_phy_set_phy_regs(rtwdev, R_SC_CORNER, B_SC_CORNER, 0x200); + rtw89_phy_write32_idx(rtwdev, R_UDP_COEEF, B_UDP_COEEF, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_UDP_COEEF, B_UDP_COEEF, 0x1, phy_idx); +} + +static void rtw8922a_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ +} + +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); + + if (mode == MLO_1_PLUS_1_1RF || mode == DBCC_LEGACY) { + rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DBCC_FA, B_DBCC_FA, 0x0); + } else if (mode == MLO_2_PLUS_0_1RF || mode == MLO_0_PLUS_2_1RF || + mode == MLO_DBCC_NOT_SUPPORT) { + rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DBCC_FA, B_DBCC_FA, 0x1); + } else { + return -EOPNOTSUPP; + } + + if (mode == MLO_2_PLUS_0_1RF) { + rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_A); + rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_B); + } else { + rtw89_warn(rtwdev, "unsupported MLO mode %d\n", mode); + } + + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x6180); + + if (mode == MLO_2_PLUS_0_1RF) { + 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 if (mode == MLO_0_PLUS_2_1RF) { + 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); + } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) { + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x7BAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x3BAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x3AAB); + } else { + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x180); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x0); + } + + return 0; +} + +static void rtw8922a_bb_sethw(struct rtw89_dev *rtwdev) +{ + u32 reg; + + rtw89_phy_write32_clr(rtwdev, R_EN_SND_WO_NDP, B_EN_SND_WO_NDP); + rtw89_phy_write32_clr(rtwdev, R_EN_SND_WO_NDP_C1, B_EN_SND_WO_NDP); + + rtw89_write32_mask(rtwdev, R_BE_PWR_BOOST, B_BE_PWR_CTRL_SEL, 0); + if (rtwdev->dbcc_en) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_MAC_1); + rtw89_write32_mask(rtwdev, reg, B_BE_PWR_CTRL_SEL, 0); + } + + rtw8922a_ctrl_mlo(rtwdev, rtwdev->mlo_dbcc_mode); +} + static void rtw8922a_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) @@ -836,6 +1026,10 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { static const struct rtw89_chip_ops rtw8922a_chip_ops = { .enable_bb_rf = rtw8922a_mac_enable_bb_rf, .disable_bb_rf = rtw8922a_mac_disable_bb_rf, + .bb_preinit = rtw8922a_bb_preinit, + .bb_postinit = rtw8922a_bb_postinit, + .bb_reset = rtw8922a_bb_reset, + .bb_sethw = rtw8922a_bb_sethw, .set_channel = rtw8922a_set_channel, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, From d2ff221579e5b281376e84ea9669115723b753b9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 Jan 2024 08:38:29 +0800 Subject: [PATCH 0159/2255] wifi: rtw89: 8922a: add register definitions of H2C, C2H, page, RRSR and EDCCA Firmware H2C commands and C2H events can go via registers, so define them accordingly. The page registers are to arrange local buffer of WiFi chip. RRSR is to define rate selection to transmit BA or ACK. EDCCA is to set threshold of engine detection mechanism by BB hardware. Like other chips, define these registers and we can share the same flow. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240120003831.7014-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 22 ++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 55 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index c4c886fd1941..741e2b0329a4 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4425,6 +4425,19 @@ #define R_BE_LTR_LATENCY_IDX2_V1 0x361C #define R_BE_LTR_LATENCY_IDX3_V1 0x3620 +#define R_BE_H2CREG_DATA0 0x7140 +#define R_BE_H2CREG_DATA1 0x7144 +#define R_BE_H2CREG_DATA2 0x7148 +#define R_BE_H2CREG_DATA3 0x714C +#define R_BE_C2HREG_DATA0 0x7150 +#define R_BE_C2HREG_DATA1 0x7154 +#define R_BE_C2HREG_DATA2 0x7158 +#define R_BE_C2HREG_DATA3 0x715C +#define R_BE_H2CREG_CTRL 0x7160 +#define B_BE_H2CREG_TRIGGER BIT(0) +#define R_BE_C2HREG_CTRL 0x7164 +#define B_BE_C2HREG_TRIGGER BIT(0) + #define R_BE_HCI_FUNC_EN 0x7880 #define B_BE_HCI_CR_PROTECT BIT(31) #define B_BE_HCI_TRXBUF_EN BIT(2) @@ -5837,6 +5850,15 @@ #define B_BE_PREC_PAGE_CH12_V1_MASK GENMASK(21, 16) #define B_BE_PREC_PAGE_CH011_V1_MASK GENMASK(5, 0) +#define R_BE_CH0_PAGE_CTRL 0xB718 +#define B_BE_CH0_GRP BIT(31) +#define B_BE_CH0_MAX_PG_MASK GENMASK(28, 16) +#define B_BE_CH0_MIN_PG_MASK GENMASK(12, 0) + +#define R_BE_CH0_PAGE_INFO 0xB750 +#define B_BE_CH0_AVAL_PG_MASK GENMASK(28, 16) +#define B_BE_CH0_USE_PG_MASK GENMASK(12, 0) + #define R_BE_PUB_PAGE_INFO3 0xB78C #define B_BE_G1_AVAL_PG_MASK GENMASK(28, 16) #define B_BE_G0_AVAL_PG_MASK GENMASK(12, 0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 1a070d6e1c16..568e6ac69202 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -63,6 +63,31 @@ static const struct rtw89_dle_mem rtw8922a_dle_mem_pcie[] = { NULL}, }; +static const u32 rtw8922a_h2c_regs[RTW89_H2CREG_MAX] = { + R_BE_H2CREG_DATA0, R_BE_H2CREG_DATA1, R_BE_H2CREG_DATA2, + R_BE_H2CREG_DATA3 +}; + +static const u32 rtw8922a_c2h_regs[RTW89_H2CREG_MAX] = { + R_BE_C2HREG_DATA0, R_BE_C2HREG_DATA1, R_BE_C2HREG_DATA2, + R_BE_C2HREG_DATA3 +}; + +static const struct rtw89_page_regs rtw8922a_page_regs = { + .hci_fc_ctrl = R_BE_HCI_FC_CTRL, + .ch_page_ctrl = R_BE_CH_PAGE_CTRL, + .ach_page_ctrl = R_BE_CH0_PAGE_CTRL, + .ach_page_info = R_BE_CH0_PAGE_INFO, + .pub_page_info3 = R_BE_PUB_PAGE_INFO3, + .pub_page_ctrl1 = R_BE_PUB_PAGE_CTRL1, + .pub_page_ctrl2 = R_BE_PUB_PAGE_CTRL2, + .pub_page_info1 = R_BE_PUB_PAGE_INFO1, + .pub_page_info2 = R_BE_PUB_PAGE_INFO2, + .wp_page_ctrl1 = R_BE_WP_PAGE_CTRL1, + .wp_page_ctrl2 = R_BE_WP_PAGE_CTRL2, + .wp_page_info1 = R_BE_WP_PAGE_INFO1, +}; + static const struct rtw89_reg_imr rtw8922a_imr_dmac_regs[] = { {R_BE_DISP_HOST_IMR, B_BE_DISP_HOST_IMR_CLR, B_BE_DISP_HOST_IMR_SET}, {R_BE_DISP_CPU_IMR, B_BE_DISP_CPU_IMR_CLR, B_BE_DISP_CPU_IMR_SET}, @@ -119,6 +144,11 @@ static const struct rtw89_imr_table rtw8922a_imr_cmac_table = { .n_regs = ARRAY_SIZE(rtw8922a_imr_cmac_regs), }; +static const struct rtw89_rrsr_cfgs rtw8922a_rrsr_cfgs = { + .ref_rate = {R_BE_TRXPTCL_RESP_1, B_BE_WMAC_RESP_REF_RATE_SEL, 0}, + .rsc = {R_BE_PTCL_RRSR1, B_BE_RSC_MASK, 2}, +}; + static const struct rtw89_dig_regs rtw8922a_dig_regs = { .seg0_pd_reg = R_SEG0R_PD_V2, .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK, @@ -143,6 +173,22 @@ static const struct rtw89_dig_regs rtw8922a_dig_regs = { B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, }; +static const struct rtw89_edcca_regs rtw8922a_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL_BE, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_PPDU_LVL_BE, + .ppdu_mask = B_EDCCA_LVL_MSK1, + .rpt_a = R_EDCCA_RPT_A_BE, + .rpt_b = R_EDCCA_RPT_B_BE, + .rpt_sel = R_EDCCA_RPT_SEL_BE, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .rpt_sel_be = R_EDCCA_RPTREG_SEL_BE, + .rpt_sel_be_mask = B_EDCCA_RPTREG_SEL_BE_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST_BE, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_BE_M, +}; + static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, @@ -1121,6 +1167,13 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v2), .txwd_body_size = sizeof(struct rtw89_txwd_body_v2), .txwd_info_size = sizeof(struct rtw89_txwd_info_v2), + .h2c_ctrl_reg = R_BE_H2CREG_CTRL, + .h2c_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_H2C_DEQ_CNT_MASK >> 8}, + .h2c_regs = rtw8922a_h2c_regs, + .c2h_ctrl_reg = R_BE_C2HREG_CTRL, + .c2h_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, + .c2h_regs = rtw8922a_c2h_regs, + .page_regs = &rtw8922a_page_regs, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = NULL, @@ -1128,9 +1181,11 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .imr_info = NULL, .imr_dmac_table = &rtw8922a_imr_dmac_table, .imr_cmac_table = &rtw8922a_imr_cmac_table, + .rrsr_cfgs = &rtw8922a_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2}, .bss_clr_map_reg = R_BSS_CLR_MAP_V2, .dma_ch_mask = 0, + .edcca_regs = &rtw8922a_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8922a, #endif From 295304040d9f6f350b68652acd99650c7e16d0a8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 Jan 2024 08:38:30 +0800 Subject: [PATCH 0160/2255] wifi: rtw89: 8922a: add TX power related ops The ::power_trim is to write bias value programmed in efuse to normalize TX power, and then using ::set_txpwr_ctrl to set reference TX power value. The ::set_txpwr is to set final TX power according to regulation of current country. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240120003831.7014-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 18 ++- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 120 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 741e2b0329a4..1cdf8a656a5b 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7454,8 +7454,12 @@ #define RR_TXAC 0x5f #define RR_TXAC_IQG GENMASK(3, 0) #define RR_BIASA 0x60 -#define RR_BIASA_TXG GENMASK(15, 12) #define RR_BIASA_TXA GENMASK(19, 16) +#define RR_BIASA_TXG GENMASK(15, 12) +#define RR_BIASD_TXA_V1 GENMASK(15, 12) +#define RR_BIASA_TXA_V1 GENMASK(11, 8) +#define RR_BIASD_TXG_V1 GENMASK(7, 4) +#define RR_BIASA_TXG_V1 GENMASK(3, 0) #define RR_BIASA_A GENMASK(2, 0) #define RR_BIASA2 0x63 #define RR_BIASA2_LB GENMASK(4, 2) @@ -8836,6 +8840,18 @@ #define R_IQK_DPK_PRST 0xE4AC #define R_IQK_DPK_PRST_C1 0xE5AC #define B_IQK_DPK_PRST BIT(27) +#define R_TSSI_MAP_OFST_P0 0xE620 +#define R_TSSI_MAP_OFST_P1 0xE720 +#define B_TSSI_MAP_OFST_OFDM GENMASK(17, 9) +#define B_TSSI_MAP_OFST_CCK GENMASK(26, 18) +#define R_TXAGC_REF0_P0 0xE628 +#define R_TXAGC_REF0_P1 0xE728 +#define B_TXAGC_REF0_OFDM_DBM GENMASK(8, 0) +#define B_TXAGC_REF0_CCK_DBM GENMASK(17, 9) +#define B_TXAGC_REF0_OFDM_CW GENMASK(26, 18) +#define R_TXAGC_REF1_P0 0xE62C +#define R_TXAGC_REF1_P1 0xE72C +#define B_TXAGC_REF1_CCK_CW GENMASK(8, 0) /* 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 568e6ac69202..a3a35661b851 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -644,6 +644,32 @@ static void rtw8922a_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, } } +static void rtw8922a_pa_bias_trim(struct rtw89_dev *rtwdev) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 pabias_2g, pabias_5g; + u8 i; + + if (!info->pg_pa_bias_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] no PG, do nothing\n"); + + return; + } + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]); + pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", + i, pabias_2g, pabias_5g); + + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG_V1, pabias_2g); + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA_V1, pabias_5g); + } +} + static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev, u8 *phycap_map) { @@ -661,6 +687,31 @@ static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev, } } +static void rtw8922a_pad_bias_trim(struct rtw89_dev *rtwdev) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 pad_bias_2g, pad_bias_5g; + u8 i; + + if (!info->pg_pa_bias_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PAD_BIAS][TRIM] no PG, do nothing\n"); + return; + } + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + pad_bias_2g = u8_get_bits(info->pad_bias_trim[i], GENMASK(3, 0)); + pad_bias_5g = u8_get_bits(info->pad_bias_trim[i], GENMASK(7, 4)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PAD_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", + i, pad_bias_2g, pad_bias_5g); + + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXG_V1, pad_bias_2g); + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXA_V1, pad_bias_5g); + } +} + static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) { rtw8922a_phycap_parsing_thermal_trim(rtwdev, phycap_map); @@ -670,6 +721,12 @@ static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) return 0; } +static void rtw8922a_power_trim(struct rtw89_dev *rtwdev) +{ + rtw8922a_pa_bias_trim(rtwdev); + rtw8922a_pad_bias_trim(rtwdev); +} + struct rtw8922a_bb_gain { u32 gain_g[BB_PATH_NUM_8922A]; u32 gain_a[BB_PATH_NUM_8922A]; @@ -1043,6 +1100,64 @@ static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, rtw8922a_set_channel_bb(rtwdev, chan, phy_idx); } +static void rtw8922a_set_txpwr_ref(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + s16 ref_ofdm = 0; + s16 ref_cck = 0; + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n"); + + rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL, + B_BE_PWR_REF_CTRL_OFDM, ref_ofdm); + rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL, + B_BE_PWR_REF_CTRL_CCK, ref_cck); +} + +static void rtw8922a_bb_tx_triangular(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + u8 ctrl = en ? 0x1 : 0x0; + + rtw89_phy_write32_idx(rtwdev, R_BEDGE3, B_BEDGE_CFG, ctrl, phy_idx); +} + +static void rtw8922a_set_tx_shape(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms; + const struct rtw89_tx_shape *tx_shape = &rfe_parms->tx_shape; + u8 tx_shape_idx; + u8 band, regd; + + band = chan->band_type; + regd = rtw89_regd_get(rtwdev, band); + tx_shape_idx = (*tx_shape->lmt)[band][RTW89_RS_OFDM][regd]; + + if (tx_shape_idx == 0) + rtw8922a_bb_tx_triangular(rtwdev, false, phy_idx); + else + rtw8922a_bb_tx_triangular(rtwdev, true, phy_idx); +} + +static void rtw8922a_set_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); + rtw8922a_set_tx_shape(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); +} + +static void rtw8922a_set_txpwr_ctrl(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_txpwr_ref(rtwdev, phy_idx); +} + static int rtw8922a_mac_enable_bb_rf(struct rtw89_dev *rtwdev) { rtw89_write8_set(rtwdev, R_BE_FEN_RST_ENABLE, @@ -1079,6 +1194,11 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .set_channel = rtw8922a_set_channel, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, + .power_trim = rtw8922a_power_trim, + .set_txpwr = rtw8922a_set_txpwr, + .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, + .init_txpwr_unit = NULL, + .set_txpwr_ul_tb_offset = NULL, .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v2, From a4374cbd6b2e15340488e66983c7535d5dd6a5a9 Mon Sep 17 00:00:00 2001 From: Chung-Hsuan Hung Date: Sat, 20 Jan 2024 08:38:31 +0800 Subject: [PATCH 0161/2255] wifi: rtw89: 8922a: add BTG functions to assist BT coexistence to control TX/RX These functions are to control baseband AGC while BT coexists with WiFi. Among these functions, ctrl_btg_bt_rx is used to control AGC related settings, which is affected by BT RX, while BT shares the same path with WiFi; ctrl_nbtg_bt_tx is used to control AGC settings under non-shared path condition, which is affected by BT TX. Signed-off-by: Chung-Hsuan Hung Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240120003831.7014-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 50 ++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 94 +++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 1cdf8a656a5b..acc96d30d085 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7968,8 +7968,28 @@ #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 B_OP1DB_A GENMASK(31, 24) +#define R_OP1DB1_A 0x40BC +#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_BACKOFF_LNA_A GENMASK(29, 24) +#define B_BACKOFF_IBADC_A GENMASK(23, 18) +#define R_RXBY_WBADC_A 0x40F4 +#define B_RXBY_WBADC_A GENMASK(14, 10) #define R_MUIC 0x40F8 #define B_MUIC_EN BIT(0) +#define R_BT_RXBY_WBADC_A 0x4160 +#define B_BT_RXBY_WBADC_A BIT(31) +#define R_BT_SHARE_A 0x4164 +#define B_BT_SHARE_A BIT(0) +#define B_BT_TRK_OFF_A BIT(1) +#define B_BTG_PATH_A BIT(4) +#define R_FORCE_FIR_A 0x418C +#define B_FORCE_FIR_A GENMASK(1, 0) #define R_DCFO 0x4264 #define B_DCFO GENMASK(7, 0) #define R_SEG0CSI 0x42AC @@ -8008,8 +8028,28 @@ #define R_DPD_BF 0x44a0 #define B_DPD_BF_OFDM GENMASK(16, 12) #define B_DPD_BF_SCA GENMASK(6, 0) +#define R_LNA_OP 0x44B0 +#define B_LNA6 GENMASK(31, 24) +#define R_LNA_TIA 0x44BC +#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_BACKOFF_LNA_B GENMASK(29, 24) +#define B_BACKOFF_IBADC_B GENMASK(23, 18) +#define R_RXBY_WBADC_B 0x44F4 +#define B_RXBY_WBADC_B GENMASK(14, 10) +#define R_BT_RXBY_WBADC_B 0x4560 +#define B_BT_RXBY_WBADC_B BIT(31) +#define R_BT_SHARE_B 0x4564 +#define B_BT_SHARE_B BIT(0) +#define B_BT_TRK_OFF_B BIT(1) +#define B_BTG_PATH_B BIT(4) #define R_TXPATH_SEL 0x458C #define B_TXPATH_SEL_MSK GENMASK(31, 28) +#define R_FORCE_FIR_B 0x458C +#define B_FORCE_FIR_B GENMASK(1, 0) #define R_TXPWR 0x4594 #define B_TXPWR_MSK GENMASK(30, 22) #define R_TXNSS_MAP 0x45B4 @@ -8423,6 +8463,16 @@ #define B_SEGSND_EN BIT(31) #define R_DBCC 0x6B48 #define B_DBCC_EN BIT(0) +#define R_FC0INV_SBW 0x6B50 +#define B_SMALLBW GENMASK(31, 30) +#define B_RX_BT_SG0 GENMASK(25, 22) +#define B_RX_1RCCA GENMASK(17, 14) +#define B_FC0_INV GENMASK(6, 0) +#define R_ANT_CHBW 0x6B54 +#define B_ANT_BT_SHARE BIT(16) +#define B_CHBW_BW GENMASK(14, 12) +#define B_CHBW_PRICH GENMASK(11, 8) +#define B_ANT_RX_SG0 GENMASK(3, 0) #define R_SLOPE 0x6B6C #define B_EHT_RATE_TH GENMASK(31, 28) #define B_SLOPE_B GENMASK(27, 14) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index a3a35661b851..f34e2a8bff07 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -200,6 +200,36 @@ static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10}, }; +static void rtw8922a_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + if (en) { + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_SHARE_A, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BTG_PATH_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_SHARE_B, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BTG_PATH_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_PMAC_GNT, B_PMAC_GNT_P1, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_BT_SHARE, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_RX_BT_SG0, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, + 0x1, phy_idx); + } else { + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_SHARE_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BTG_PATH_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_SHARE_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BTG_PATH_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_OP, B_LNA6, 0x1a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA0_B, 0x2a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0xc, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_BT_SHARE, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_RX_BT_SG0, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, + 0x0, phy_idx); + } +} + static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; @@ -1158,6 +1188,68 @@ static void rtw8922a_set_txpwr_ctrl(struct rtw89_dev *rtwdev, rtw8922a_set_txpwr_ref(rtwdev, phy_idx); } +static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + if (en) { + rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x3, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A, + 0xf, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A, + 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_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, + 0xf, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B, + 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_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); + rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A, + 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A, + 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_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, + 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B, + 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_BKOFF_B, B_BKOFF_IBADC_B, 0x26, phy_idx); + } +} + static int rtw8922a_mac_enable_bb_rf(struct rtw89_dev *rtwdev) { rtw89_write8_set(rtwdev, R_BE_FEN_RST_ENABLE, @@ -1198,6 +1290,8 @@ 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, + .ctrl_btg_bt_rx = rtw8922a_ctrl_btg_bt_rx, + .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, From 49d158557474a0c173e313ba1b7d0bd9d1f815a2 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 19 Jan 2024 16:14:54 +0800 Subject: [PATCH 0162/2255] wifi: rtw89: refine add_chan H2C command to encode_bits Use struct filling style instead of pointer casting. This does not change the original behavior. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 69 +++++----- drivers/net/wireless/realtek/rtw89/fw.h | 169 ++++++------------------ 2 files changed, 78 insertions(+), 160 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 362ea2e228d2..d967120a8813 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3996,55 +3996,60 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, return 0; } -#define H2C_LEN_SCAN_LIST_OFFLOAD 4 -int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len, +int rtw89_fw_h2c_scan_list_offload(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 *elem; struct rtw89_mac_chinfo *ch_info; + struct rtw89_h2c_chinfo *h2c; struct sk_buff *skb; - int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE; unsigned int cond; - u8 *cmd; + 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, H2C_LEN_SCAN_LIST_OFFLOAD); - cmd = skb->data; + skb_put(skb, sizeof(*h2c)); + h2c = (struct rtw89_h2c_chinfo *)skb->data; - RTW89_SET_FWCMD_SCANOFLD_CH_NUM(cmd, len); - /* in unit of 4 bytes */ - RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(cmd, RTW89_MAC_CHINFO_SIZE / 4); + h2c->ch_num = ch_num; + h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */ list_for_each_entry(ch_info, chan_list, list) { - cmd = skb_put(skb, RTW89_MAC_CHINFO_SIZE); + elem = (struct rtw89_h2c_chinfo_elem *)skb_put(skb, sizeof(*elem)); - RTW89_SET_FWCMD_CHINFO_PERIOD(cmd, ch_info->period); - RTW89_SET_FWCMD_CHINFO_DWELL(cmd, ch_info->dwell_time); - RTW89_SET_FWCMD_CHINFO_CENTER_CH(cmd, ch_info->central_ch); - RTW89_SET_FWCMD_CHINFO_PRI_CH(cmd, ch_info->pri_ch); - RTW89_SET_FWCMD_CHINFO_BW(cmd, ch_info->bw); - RTW89_SET_FWCMD_CHINFO_ACTION(cmd, ch_info->notify_action); - RTW89_SET_FWCMD_CHINFO_NUM_PKT(cmd, ch_info->num_pkt); - RTW89_SET_FWCMD_CHINFO_TX(cmd, ch_info->tx_pkt); - RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(cmd, ch_info->pause_data); - RTW89_SET_FWCMD_CHINFO_BAND(cmd, ch_info->ch_band); - RTW89_SET_FWCMD_CHINFO_PKT_ID(cmd, ch_info->probe_id); - RTW89_SET_FWCMD_CHINFO_DFS(cmd, ch_info->dfs_ch); - RTW89_SET_FWCMD_CHINFO_TX_NULL(cmd, ch_info->tx_null); - RTW89_SET_FWCMD_CHINFO_RANDOM(cmd, ch_info->rand_seq_num); - RTW89_SET_FWCMD_CHINFO_PKT0(cmd, ch_info->pkt_id[0]); - RTW89_SET_FWCMD_CHINFO_PKT1(cmd, ch_info->pkt_id[1]); - RTW89_SET_FWCMD_CHINFO_PKT2(cmd, ch_info->pkt_id[2]); - RTW89_SET_FWCMD_CHINFO_PKT3(cmd, ch_info->pkt_id[3]); - RTW89_SET_FWCMD_CHINFO_PKT4(cmd, ch_info->pkt_id[4]); - RTW89_SET_FWCMD_CHINFO_PKT5(cmd, ch_info->pkt_id[5]); - RTW89_SET_FWCMD_CHINFO_PKT6(cmd, ch_info->pkt_id[6]); - RTW89_SET_FWCMD_CHINFO_PKT7(cmd, ch_info->pkt_id[7]); + elem->w0 = le32_encode_bits(ch_info->period, RTW89_H2C_CHINFO_W0_PERIOD) | + le32_encode_bits(ch_info->dwell_time, RTW89_H2C_CHINFO_W0_DWELL) | + le32_encode_bits(ch_info->central_ch, RTW89_H2C_CHINFO_W0_CENTER_CH) | + le32_encode_bits(ch_info->pri_ch, RTW89_H2C_CHINFO_W0_PRI_CH); + + elem->w1 = le32_encode_bits(ch_info->bw, RTW89_H2C_CHINFO_W1_BW) | + le32_encode_bits(ch_info->notify_action, RTW89_H2C_CHINFO_W1_ACTION) | + le32_encode_bits(ch_info->num_pkt, RTW89_H2C_CHINFO_W1_NUM_PKT) | + le32_encode_bits(ch_info->tx_pkt, RTW89_H2C_CHINFO_W1_TX) | + le32_encode_bits(ch_info->pause_data, RTW89_H2C_CHINFO_W1_PAUSE_DATA) | + le32_encode_bits(ch_info->ch_band, RTW89_H2C_CHINFO_W1_BAND) | + le32_encode_bits(ch_info->probe_id, RTW89_H2C_CHINFO_W1_PKT_ID) | + le32_encode_bits(ch_info->dfs_ch, RTW89_H2C_CHINFO_W1_DFS) | + le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_W1_TX_NULL) | + le32_encode_bits(ch_info->rand_seq_num, RTW89_H2C_CHINFO_W1_RANDOM); + + elem->w2 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_W2_PKT0) | + le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_W2_PKT1) | + le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_W2_PKT2) | + le32_encode_bits(ch_info->pkt_id[3], RTW89_H2C_CHINFO_W2_PKT3); + + elem->w3 = le32_encode_bits(ch_info->pkt_id[4], RTW89_H2C_CHINFO_W3_PKT4) | + le32_encode_bits(ch_info->pkt_id[5], RTW89_H2C_CHINFO_W3_PKT5) | + le32_encode_bits(ch_info->pkt_id[6], RTW89_H2C_CHINFO_W3_PKT6) | + le32_encode_bits(ch_info->pkt_id[7], RTW89_H2C_CHINFO_W3_PKT7); } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7a80f45ce27b..c5f1fdff9fe0 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2659,135 +2659,48 @@ static inline void RTW89_SET_FWCMD_PACKET_OFLD_PKT_LENGTH(void *cmd, u32 val) le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(31, 16)); } -static inline void RTW89_SET_FWCMD_SCANOFLD_CH_NUM(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0)); -} +struct rtw89_h2c_chinfo_elem { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; +} __packed; -static inline void RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(15, 8)); -} +#define RTW89_H2C_CHINFO_W0_PERIOD GENMASK(7, 0) +#define RTW89_H2C_CHINFO_W0_DWELL GENMASK(15, 8) +#define RTW89_H2C_CHINFO_W0_CENTER_CH GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W0_PRI_CH GENMASK(31, 24) +#define RTW89_H2C_CHINFO_W1_BW GENMASK(2, 0) +#define RTW89_H2C_CHINFO_W1_ACTION GENMASK(7, 3) +#define RTW89_H2C_CHINFO_W1_NUM_PKT GENMASK(11, 8) +#define RTW89_H2C_CHINFO_W1_TX BIT(12) +#define RTW89_H2C_CHINFO_W1_PAUSE_DATA BIT(13) +#define RTW89_H2C_CHINFO_W1_BAND GENMASK(15, 14) +#define RTW89_H2C_CHINFO_W1_PKT_ID GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W1_DFS BIT(24) +#define RTW89_H2C_CHINFO_W1_TX_NULL BIT(25) +#define RTW89_H2C_CHINFO_W1_RANDOM BIT(26) +#define RTW89_H2C_CHINFO_W1_CFG_TX BIT(27) +#define RTW89_H2C_CHINFO_W2_PKT0 GENMASK(7, 0) +#define RTW89_H2C_CHINFO_W2_PKT1 GENMASK(15, 8) +#define RTW89_H2C_CHINFO_W2_PKT2 GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W2_PKT3 GENMASK(31, 24) +#define RTW89_H2C_CHINFO_W3_PKT4 GENMASK(7, 0) +#define RTW89_H2C_CHINFO_W3_PKT5 GENMASK(15, 8) +#define RTW89_H2C_CHINFO_W3_PKT6 GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W3_PKT7 GENMASK(31, 24) +#define RTW89_H2C_CHINFO_W4_POWER_IDX GENMASK(15, 0) -static inline void RTW89_SET_FWCMD_CHINFO_PERIOD(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_DWELL(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(15, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_CENTER_CH(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PRI_CH(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(31, 24)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_BW(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(2, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_ACTION(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(7, 3)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_NUM_PKT(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(11, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_TX(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(12)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(13)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_BAND(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(15, 14)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT_ID(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_DFS(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(24)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_TX_NULL(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(25)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_RANDOM(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(26)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_CFG_TX(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(27)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT0(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(7, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT1(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(15, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT2(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT3(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(31, 24)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT4(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(7, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT5(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(15, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT6(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT7(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(31, 24)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_POWER_IDX(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 16), val, GENMASK(15, 0)); -} +struct rtw89_h2c_chinfo { + u8 ch_num; + u8 elem_size; + u8 rsvd0; + u8 rsvd1; + struct rtw89_h2c_chinfo_elem elem[] __counted_by(ch_num); +} __packed; struct rtw89_h2c_scanofld { __le32 w0; @@ -3990,7 +3903,7 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id); 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 len, +int rtw89_fw_h2c_scan_list_offload(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, From b9979843febfad8e346b25da1d4999d755663ef2 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 19 Jan 2024 16:14:55 +0800 Subject: [PATCH 0163/2255] wifi: rtw89: refine hardware scan C2H events Define struct for scan offload C2H events and update each elements' bitfield. This patch does not change original behavior, just style conversion and naming changes. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.h | 36 +++++++++++++++--------- drivers/net/wireless/realtek/rtw89/mac.c | 16 ++++++----- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index c5f1fdff9fe0..f64fba138834 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -169,6 +169,10 @@ enum rtw89_scanofld_notify_reason { RTW89_SCAN_ENTER_CH_NOTIFY, RTW89_SCAN_LEAVE_CH_NOTIFY, RTW89_SCAN_END_SCAN_NOTIFY, + RTW89_SCAN_REPORT_NOTIFY, + RTW89_SCAN_CHKPT_NOTIFY, + RTW89_SCAN_ENTER_OP_NOTIFY, + RTW89_SCAN_LEAVE_OP_NOTIFY, }; enum rtw89_chan_type { @@ -3278,20 +3282,24 @@ struct rtw89_c2h_ra_rpt { #define RTW89_GET_MAC_C2H_PKTOFLD_LEN(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 16)) -#define RTW89_GET_MAC_C2H_SCANOFLD_PRI_CH(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 0)) -#define RTW89_GET_MAC_C2H_SCANOFLD_RSP(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(19, 16)) -#define RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 20)) -#define RTW89_GET_MAC_C2H_ACTUAL_PERIOD(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 24)) -#define RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(3, 0)) -#define RTW89_GET_MAC_C2H_SCANOFLD_AIR_DENSITY(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(7, 4)) -#define RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(25, 24)) +struct rtw89_c2h_scanofld { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; +} __packed; + +#define RTW89_C2H_SCANOFLD_W2_PRI_CH GENMASK(7, 0) +#define RTW89_C2H_SCANOFLD_W2_RSN GENMASK(19, 16) +#define RTW89_C2H_SCANOFLD_W2_STATUS GENMASK(23, 20) +#define RTW89_C2H_SCANOFLD_W2_PERIOD GENMASK(31, 24) +#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_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 16f21406fbd2..d472906bd073 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4671,9 +4671,11 @@ static bool rtw89_is_op_chan(struct rtw89_dev *rtwdev, u8 band, u8 channel) } static void -rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, +rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len) { + const struct rtw89_c2h_scanofld *c2h = + (const struct rtw89_c2h_scanofld *)skb->data; struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct rtw89_chan new; @@ -4685,12 +4687,12 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, if (!rtwvif) return; - tx_fail = RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h->data); - status = RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h->data); - chan = RTW89_GET_MAC_C2H_SCANOFLD_PRI_CH(c2h->data); - reason = RTW89_GET_MAC_C2H_SCANOFLD_RSP(c2h->data); - band = RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h->data); - actual_period = RTW89_GET_MAC_C2H_ACTUAL_PERIOD(c2h->data); + tx_fail = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_TX_FAIL); + status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); + chan = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_PRI_CH); + 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); if (!(rtwdev->chip->support_bands & BIT(NL80211_BAND_6GHZ))) band = chan > 14 ? RTW89_BAND_5G : RTW89_BAND_2G; From 7cf6b6764b2f665d317ba0f91c247437019a2f4c Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 19 Jan 2024 16:14:56 +0800 Subject: [PATCH 0164/2255] wifi: rtw89: Set default CQM config if not present When wpa_supplicant is initiated by users and not by NetworkManager, the CQM configuration might not be set. Without this setting, ICs with connection monitor handled by driver won't detect connection loss. To fix this we prepare a default setting upon associated at first, then update again if any is given later. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 2 ++ drivers/net/wireless/realtek/rtw89/fw.c | 11 +++++++++-- drivers/net/wireless/realtek/rtw89/fw.h | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index aefb5a078d1a..29df1ea0c826 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3493,6 +3493,8 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, rtw89_warn(rtwdev, "failed to send h2c general packet\n"); return ret; } + + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); } return ret; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d967120a8813..ed0ac3726336 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3216,6 +3216,8 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, { struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct ieee80211_bss_conf *bss_conf = vif ? &vif->bss_conf : NULL; + s32 thold = RTW89_DEFAULT_CQM_THOLD; + u32 hyst = RTW89_DEFAULT_CQM_HYST; struct rtw89_h2c_bcnfltr *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -3236,14 +3238,19 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcnfltr *)skb->data; + if (bss_conf->cqm_rssi_hyst) + hyst = bss_conf->cqm_rssi_hyst; + if (bss_conf->cqm_rssi_thold) + thold = bss_conf->cqm_rssi_thold; + h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) | le32_encode_bits(RTW89_BCN_FLTR_OFFLOAD_MODE_DEFAULT, RTW89_H2C_BCNFLTR_W0_MODE) | le32_encode_bits(RTW89_BCN_LOSS_CNT, RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT) | - le32_encode_bits(bss_conf->cqm_rssi_hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) | - le32_encode_bits(bss_conf->cqm_rssi_thold + MAX_RSSI, + le32_encode_bits(hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) | + le32_encode_bits(thold + MAX_RSSI, RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) | le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index f64fba138834..5d51611d5f6d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -188,6 +188,9 @@ enum rtw89_p2pps_action { RTW89_P2P_ACT_TERMINATE = 3, }; +#define RTW89_DEFAULT_CQM_HYST 4 +#define RTW89_DEFAULT_CQM_THOLD -70 + enum rtw89_bcn_fltr_offload_mode { RTW89_BCN_FLTR_OFFLOAD_MODE_0 = 0, RTW89_BCN_FLTR_OFFLOAD_MODE_1, From dab2b8c41db2e1756ec9d52d211beb58a00e1400 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 19 Jan 2024 16:14:57 +0800 Subject: [PATCH 0165/2255] wifi: rtw89: disable RTS when broadcast/multicast RTS switch should not be enabled for broadcast and multicast. This could cause incorrect behavior during AP mode, so we fix it. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 29df1ea0c826..260da86bf04a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1176,7 +1176,8 @@ static __le32 rtw89_build_txwd_info2_v1(struct rtw89_tx_desc_info *desc_info) static __le32 rtw89_build_txwd_info4(struct rtw89_tx_desc_info *desc_info) { - u32 dword = FIELD_PREP(RTW89_TXWD_INFO4_RTS_EN, 1) | + bool rts_en = !desc_info->is_bmc; + u32 dword = FIELD_PREP(RTW89_TXWD_INFO4_RTS_EN, rts_en) | FIELD_PREP(RTW89_TXWD_INFO4_HW_RTS_EN, 1); return cpu_to_le32(dword); @@ -1329,7 +1330,8 @@ static __le32 rtw89_build_txwd_info2_v2(struct rtw89_tx_desc_info *desc_info) static __le32 rtw89_build_txwd_info4_v2(struct rtw89_tx_desc_info *desc_info) { - u32 dword = FIELD_PREP(BE_TXD_INFO4_RTS_EN, 1) | + bool rts_en = !desc_info->is_bmc; + u32 dword = FIELD_PREP(BE_TXD_INFO4_RTS_EN, rts_en) | FIELD_PREP(BE_TXD_INFO4_HW_RTS_EN, 1); return cpu_to_le32(dword); From 7e11a2966f51695c0af0b1f976a32d64dee243b2 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 19 Jan 2024 16:14:58 +0800 Subject: [PATCH 0166/2255] wifi: rtw89: fix null pointer access when abort scan During cancel scan we might use vif that weren't scanning. Fix this by using the actual scanning vif. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 21b42984fd8a..b61c5be8cae3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -441,7 +441,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, * when disconnected by peer */ if (rtwdev->scanning) - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); } } @@ -994,7 +994,7 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, } if (rtwdev->scanning) - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); if (type == IEEE80211_ROC_TYPE_MGMT_TX) roc->state = RTW89_ROC_MGMT; From bcbefbd032df6bfe925e6afeca82eb9d2cc0cb23 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 19 Jan 2024 16:14:59 +0800 Subject: [PATCH 0167/2255] wifi: rtw89: add wait/completion for abort scan When aborting scan, wait until FW is done to keep both states aligned. This prevents driver modifying channel then gets overwritten by FW. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 21 ++++++++++++---- drivers/net/wireless/realtek/rtw89/fw.h | 11 +++++++++ drivers/net/wireless/realtek/rtw89/mac.c | 29 ++++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/mac.h | 3 ++- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index f56a5d423eb0..c86b46e7964f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4623,6 +4623,7 @@ struct rtw89_hw_scan_info { struct ieee80211_vif *scanning_vif; struct list_head pkt_list[NUM_NL80211_BANDS]; struct rtw89_chan op_chan; + bool abort; u32 last_chan_idx; }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index ed0ac3726336..231dd884645a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4063,7 +4063,7 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len); - cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH); + cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH; ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { @@ -4122,7 +4122,10 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, H2C_FUNC_SCANOFLD, 1, 1, len); - cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD); + if (option->enable) + cond = RTW89_SCANOFLD_WAIT_COND_START; + else + cond = RTW89_SCANOFLD_WAIT_COND_STOP; ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { @@ -4312,7 +4315,7 @@ static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev, default: return false; case RTW89_C2H_CAT_MAC: - return rtw89_mac_c2h_chk_atomic(rtwdev, class, func); + return rtw89_mac_c2h_chk_atomic(rtwdev, c2h, class, func); case RTW89_C2H_CAT_OUTSRC: return rtw89_phy_c2h_chk_atomic(rtwdev, class, func); } @@ -4866,6 +4869,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtw89_get_channel(rtwdev, rtwvif, &rtwdev->scan_info.op_chan); rtwdev->scan_info.scanning_vif = vif; rtwdev->scan_info.last_chan_idx = 0; + rtwdev->scan_info.abort = false; rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; ieee80211_stop_queues(rtwdev->hw); @@ -4917,14 +4921,21 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtwvif->scan_ies = NULL; scan_info->last_chan_idx = 0; scan_info->scanning_vif = NULL; + scan_info->abort = false; rtw89_chanctx_proceed(rtwdev); } void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) { - rtw89_hw_scan_offload(rtwdev, vif, false); - rtw89_hw_scan_complete(rtwdev, vif, true); + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + int ret; + + scan_info->abort = true; + + ret = rtw89_hw_scan_offload(rtwdev, vif, false); + if (ret) + rtw89_hw_scan_complete(rtwdev, vif, true); } static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 5d51611d5f6d..a3df701bdc6e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -175,6 +175,12 @@ enum rtw89_scanofld_notify_reason { RTW89_SCAN_LEAVE_OP_NOTIFY, }; +enum rtw89_scanofld_status { + RTW89_SCAN_STATUS_NOTIFY, + RTW89_SCAN_STATUS_SUCCESS, + RTW89_SCAN_STATUS_FAIL, +}; + enum rtw89_chan_type { RTW89_CHAN_OPERATE = 0, RTW89_CHAN_ACTIVE, @@ -3701,6 +3707,11 @@ enum rtw89_fw_ofld_h2c_func { RTW89_FW_OFLD_WAIT_COND(RTW89_PKT_OFLD_WAIT_TAG(pkt_id, pkt_op), \ H2C_FUNC_PACKET_OFLD) +#define RTW89_SCANOFLD_WAIT_COND_ADD_CH RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH) + +#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) + /* CLASS 10 - Security CAM */ #define H2C_CL_MAC_SEC_CAM 0xa #define H2C_FUNC_MAC_SEC_UPD 0x1 diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index d472906bd073..03553b63a4a8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4717,7 +4717,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, rtw89_warn(rtwdev, "HW scan failed: %d\n", ret); } } else { - rtw89_hw_scan_complete(rtwdev, vif, false); + rtw89_hw_scan_complete(rtwdev, vif, rtwdev->scan_info.abort); } break; case RTW89_SCAN_ENTER_CH_NOTIFY: @@ -4839,8 +4839,10 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le default: return; case H2C_FUNC_ADD_SCANOFLD_CH: + cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH; + break; case H2C_FUNC_SCANOFLD: - cond = RTW89_FW_OFLD_WAIT_COND(0, h2c_func); + cond = RTW89_SCANOFLD_WAIT_COND_START; break; } @@ -5084,7 +5086,25 @@ void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt, }; -bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) +static void rtw89_mac_c2h_scanofld_rsp_atomic(struct rtw89_dev *rtwdev, + struct sk_buff *skb) +{ + const struct rtw89_c2h_scanofld *c2h = + (const struct rtw89_c2h_scanofld *)skb->data; + struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_completion_data data = {}; + 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); +} + +bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h, + u8 class, u8 func) { switch (class) { default: @@ -5101,6 +5121,9 @@ bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) switch (func) { default: return false; + case RTW89_MAC_C2H_FUNC_SCANOFLD_RSP: + rtw89_mac_c2h_scanofld_rsp_atomic(rtwdev, c2h); + return false; case RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP: return true; } diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index ed98b49809a4..54ce16a2c475 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1127,7 +1127,8 @@ static inline int rtw89_chip_reset_bb_rf(struct rtw89_dev *rtwdev) u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev); int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err); -bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func); +bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h, + u8 class, u8 func); void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func); int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev); From f59a98c82534e986b06615ba94e060aa3129b08b Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Fri, 19 Jan 2024 16:15:00 +0800 Subject: [PATCH 0168/2255] wifi: rtw89: fix HW scan timeout due to TSF sync issue When STA connects to an AP and doesn't receive any beacon yet, the hardware scan is triggered. This scan begins with the default TSF value. Once STA receives a beacon when switches back to the operating channel, its TSF synchronizes with the AP. However, if there is a significant difference in TSF values between the default value and the synchronized value, it will cause firmware fail to trigger interrupt, and the C2H won't be sent out. As a result, the scan continues until a timeout occurs. To fix this issue, we disable TSF synchronization during scanning to prevent drastic TSF changes, and enable TSF synchronization after scan. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 5 +++-- drivers/net/wireless/realtek/rtw89/mac.c | 17 ++++++++++++----- drivers/net/wireless/realtek/rtw89/mac.h | 2 ++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 231dd884645a..e49360e29faf 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4873,6 +4873,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; ieee80211_stop_queues(rtwdev->hw); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, false); if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) get_random_mask_addr(mac_addr, req->mac_addr, @@ -4897,10 +4898,10 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct cfg80211_scan_info info = { .aborted = aborted, }; - struct rtw89_vif *rtwvif; if (!vif) return; @@ -4913,10 +4914,10 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtw89_core_scan_complete(rtwdev, vif, true); ieee80211_scan_completed(rtwdev->hw, &info); ieee80211_wake_queues(rtwdev->hw); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, true); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); rtw89_release_pkt_list(rtwdev); - rtwvif = (struct rtw89_vif *)vif->drv_priv; rtwvif->scan_req = NULL; rtwvif->scan_ies = NULL; scan_info->last_chan_idx = 0; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 03553b63a4a8..b224d06e5f3c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4185,13 +4185,11 @@ static void rtw89_mac_port_cfg_rx_sw(struct rtw89_dev *rtwdev, rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bit); } -static void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) +void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; if (en) rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); @@ -4199,6 +4197,15 @@ static void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); } +static void rtw89_mac_port_cfg_rx_sync_by_nettype(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || + rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, en); +} + static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, bool en) { @@ -4538,7 +4545,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_mac_port_cfg_net_type(rtwdev, rtwvif); rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif); rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif); - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif); + rtw89_mac_port_cfg_rx_sync_by_nettype(rtwdev, rtwvif); rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif); rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif); rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 54ce16a2c475..181d03d1f78a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1086,6 +1086,8 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, u16 offset_tu); int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u64 *tsf); +void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool en); void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); From 5ba45ba77616637e554d66a57ef0334e5cc2efe4 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Fri, 19 Jan 2024 16:15:01 +0800 Subject: [PATCH 0169/2255] wifi: rtw89: fix disabling concurrent mode TX hang issue When disabling concurrent mode and switching to a single interface, the TX might stuck. The reason is TBTT prohibit area circuit still enable to block TX. To disable tbtt prohibit area circuit need to delay 2ms to make it effective. However, we only delay 2us in original code. So we fix it. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240119081501.25223-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b224d06e5f3c..eb94e832e154 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4072,7 +4072,7 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvi rtw89_write32_clr(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port)); rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN); - fsleep(2); + fsleep(2000); } #define BCN_INTERVAL 100 From acf868ff60b1cd1f2e597f0b15aee2ff43f9fcd3 Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Fri, 19 Jan 2024 18:16:55 +0100 Subject: [PATCH 0170/2255] wifi: iwlegacy: Use kcalloc() instead of kzalloc() As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. So, use the purpose specific kcalloc() function instead of the argument size * count in the kzalloc() function. Also, it is preferred to use sizeof(*pointer) instead of sizeof(type) due to the type of the variable can change and one needs not change the former (unlike the latter). Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [1] Link: https://github.com/KSPP/linux/issues/162 Signed-off-by: Erick Archer Reviewed-by: Gustavo A. R. Silva Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://msgid.link/20240119171655.7740-1-erick.archer@gmx.com --- drivers/net/wireless/intel/iwlegacy/common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 17570d62c896..9d33a66a49b5 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -3438,9 +3438,7 @@ il_init_geos(struct il_priv *il) if (!channels) return -ENOMEM; - rates = - kzalloc((sizeof(struct ieee80211_rate) * RATE_COUNT_LEGACY), - GFP_KERNEL); + rates = kcalloc(RATE_COUNT_LEGACY, sizeof(*rates), GFP_KERNEL); if (!rates) { kfree(channels); return -ENOMEM; From efd402537673f9951992aea4ef0f5ff51d858f4b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:25:55 +0000 Subject: [PATCH 0171/2255] sock_diag: annotate data-races around sock_diag_handlers[family] __sock_diag_cmd() and sock_diag_bind() read sock_diag_handlers[family] without a lock held. Use READ_ONCE()/WRITE_ONCE() annotations to avoid potential issues. Fixes: 8ef874bfc729 ("sock_diag: Move the sock_ code to net/core/") Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- net/core/sock_diag.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index b1e29e18d1d6..c53b731f2d67 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -193,7 +193,7 @@ int sock_diag_register(const struct sock_diag_handler *hndl) if (sock_diag_handlers[hndl->family]) err = -EBUSY; else - sock_diag_handlers[hndl->family] = hndl; + WRITE_ONCE(sock_diag_handlers[hndl->family], hndl); mutex_unlock(&sock_diag_table_mutex); return err; @@ -209,7 +209,7 @@ void sock_diag_unregister(const struct sock_diag_handler *hnld) mutex_lock(&sock_diag_table_mutex); BUG_ON(sock_diag_handlers[family] != hnld); - sock_diag_handlers[family] = NULL; + WRITE_ONCE(sock_diag_handlers[family], NULL); mutex_unlock(&sock_diag_table_mutex); } EXPORT_SYMBOL_GPL(sock_diag_unregister); @@ -227,7 +227,7 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) return -EINVAL; req->sdiag_family = array_index_nospec(req->sdiag_family, AF_MAX); - if (sock_diag_handlers[req->sdiag_family] == NULL) + if (READ_ONCE(sock_diag_handlers[req->sdiag_family]) == NULL) sock_load_diag_module(req->sdiag_family, 0); mutex_lock(&sock_diag_table_mutex); @@ -286,12 +286,12 @@ static int sock_diag_bind(struct net *net, int group) switch (group) { case SKNLGRP_INET_TCP_DESTROY: case SKNLGRP_INET_UDP_DESTROY: - if (!sock_diag_handlers[AF_INET]) + if (!READ_ONCE(sock_diag_handlers[AF_INET])) sock_load_diag_module(AF_INET, 0); break; case SKNLGRP_INET6_TCP_DESTROY: case SKNLGRP_INET6_UDP_DESTROY: - if (!sock_diag_handlers[AF_INET6]) + if (!READ_ONCE(sock_diag_handlers[AF_INET6])) sock_load_diag_module(AF_INET6, 0); break; } From e50e10ae5d81ddb41547114bfdc5edc04422f082 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:25:56 +0000 Subject: [PATCH 0172/2255] inet_diag: annotate data-races around inet_diag_table[] inet_diag_lock_handler() reads inet_diag_table[proto] locklessly. Use READ_ONCE()/WRITE_ONCE() annotations to avoid potential issues. Fixes: d523a328fb02 ("[INET]: Fix inet_diag dead-lock regression") Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- net/ipv4/inet_diag.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 8e6b6aa0579e..9804e9608a5a 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -57,7 +57,7 @@ static const struct inet_diag_handler *inet_diag_lock_handler(int proto) return ERR_PTR(-ENOENT); } - if (!inet_diag_table[proto]) + if (!READ_ONCE(inet_diag_table[proto])) sock_load_diag_module(AF_INET, proto); mutex_lock(&inet_diag_table_mutex); @@ -1503,7 +1503,7 @@ int inet_diag_register(const struct inet_diag_handler *h) mutex_lock(&inet_diag_table_mutex); err = -EEXIST; if (!inet_diag_table[type]) { - inet_diag_table[type] = h; + WRITE_ONCE(inet_diag_table[type], h); err = 0; } mutex_unlock(&inet_diag_table_mutex); @@ -1520,7 +1520,7 @@ void inet_diag_unregister(const struct inet_diag_handler *h) return; mutex_lock(&inet_diag_table_mutex); - inet_diag_table[type] = NULL; + WRITE_ONCE(inet_diag_table[type], NULL); mutex_unlock(&inet_diag_table_mutex); } EXPORT_SYMBOL_GPL(inet_diag_unregister); From db5914695a84a7b128ec2e4e9272e6e8091753e1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:25:57 +0000 Subject: [PATCH 0173/2255] inet_diag: add module pointer to "struct inet_diag_handler" Following patch is going to use RCU instead of inet_diag_table_mutex acquisition. This patch is a preparation, no change of behavior yet. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- include/linux/inet_diag.h | 1 + net/dccp/diag.c | 1 + net/ipv4/raw_diag.c | 1 + net/ipv4/tcp_diag.c | 1 + net/ipv4/udp_diag.c | 2 ++ net/mptcp/mptcp_diag.c | 1 + net/sctp/diag.c | 1 + 7 files changed, 8 insertions(+) diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 84abb30a3fbb..a9033696b0aa 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -8,6 +8,7 @@ struct inet_hashinfo; struct inet_diag_handler { + struct module *owner; void (*dump)(struct sk_buff *skb, struct netlink_callback *cb, const struct inet_diag_req_v2 *r); diff --git a/net/dccp/diag.c b/net/dccp/diag.c index 8a82c5a2c5a8..f5019d95c3ae 100644 --- a/net/dccp/diag.c +++ b/net/dccp/diag.c @@ -58,6 +58,7 @@ static int dccp_diag_dump_one(struct netlink_callback *cb, } static const struct inet_diag_handler dccp_diag_handler = { + .owner = THIS_MODULE, .dump = dccp_diag_dump, .dump_one = dccp_diag_dump_one, .idiag_get_info = dccp_diag_get_info, diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index fe2140c8375c..cc793bd8de25 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c @@ -213,6 +213,7 @@ static int raw_diag_destroy(struct sk_buff *in_skb, #endif static const struct inet_diag_handler raw_diag_handler = { + .owner = THIS_MODULE, .dump = raw_diag_dump, .dump_one = raw_diag_dump_one, .idiag_get_info = raw_diag_get_info, diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 4cbe4b44425a..f428ecf9120f 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -222,6 +222,7 @@ static int tcp_diag_destroy(struct sk_buff *in_skb, #endif static const struct inet_diag_handler tcp_diag_handler = { + .owner = THIS_MODULE, .dump = tcp_diag_dump, .dump_one = tcp_diag_dump_one, .idiag_get_info = tcp_diag_get_info, diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index dc41a22ee80e..38cb3a28e4ed 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -237,6 +237,7 @@ static int udplite_diag_destroy(struct sk_buff *in_skb, #endif static const struct inet_diag_handler udp_diag_handler = { + .owner = THIS_MODULE, .dump = udp_diag_dump, .dump_one = udp_diag_dump_one, .idiag_get_info = udp_diag_get_info, @@ -260,6 +261,7 @@ static int udplite_diag_dump_one(struct netlink_callback *cb, } static const struct inet_diag_handler udplite_diag_handler = { + .owner = THIS_MODULE, .dump = udplite_diag_dump, .dump_one = udplite_diag_dump_one, .idiag_get_info = udp_diag_get_info, diff --git a/net/mptcp/mptcp_diag.c b/net/mptcp/mptcp_diag.c index 5409c2ea3f57..bd8ff5950c8d 100644 --- a/net/mptcp/mptcp_diag.c +++ b/net/mptcp/mptcp_diag.c @@ -225,6 +225,7 @@ static void mptcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, } static const struct inet_diag_handler mptcp_diag_handler = { + .owner = THIS_MODULE, .dump = mptcp_diag_dump, .dump_one = mptcp_diag_dump_one, .idiag_get_info = mptcp_diag_get_info, diff --git a/net/sctp/diag.c b/net/sctp/diag.c index eb05131ff1dd..23359e522273 100644 --- a/net/sctp/diag.c +++ b/net/sctp/diag.c @@ -507,6 +507,7 @@ done: } static const struct inet_diag_handler sctp_diag_handler = { + .owner = THIS_MODULE, .dump = sctp_diag_dump, .dump_one = sctp_diag_dump_one, .idiag_get_info = sctp_diag_get_info, From 223f55196bbdb182a9b8de6108a0834b5e5e832e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:25:58 +0000 Subject: [PATCH 0174/2255] inet_diag: allow concurrent operations inet_diag_lock_handler() current implementation uses a mutex to protect inet_diag_table[] array against concurrent changes. This makes inet_diag dump serialized, thus less scalable than legacy /proc files. It is time to switch to full RCU protection. As a bonus, if a target is statically linked instead of being modular, inet_diag_lock_handler() & inet_diag_unlock_handler() reduce to reads only. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- net/ipv4/inet_diag.c | 80 ++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 9804e9608a5a..abf7dc982796 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -32,7 +32,7 @@ #include #include -static const struct inet_diag_handler **inet_diag_table; +static const struct inet_diag_handler __rcu **inet_diag_table; struct inet_diag_entry { const __be32 *saddr; @@ -48,28 +48,28 @@ struct inet_diag_entry { #endif }; -static DEFINE_MUTEX(inet_diag_table_mutex); - static const struct inet_diag_handler *inet_diag_lock_handler(int proto) { - if (proto < 0 || proto >= IPPROTO_MAX) { - mutex_lock(&inet_diag_table_mutex); - return ERR_PTR(-ENOENT); - } + const struct inet_diag_handler *handler; + + if (proto < 0 || proto >= IPPROTO_MAX) + return NULL; if (!READ_ONCE(inet_diag_table[proto])) sock_load_diag_module(AF_INET, proto); - mutex_lock(&inet_diag_table_mutex); - if (!inet_diag_table[proto]) - return ERR_PTR(-ENOENT); + rcu_read_lock(); + handler = rcu_dereference(inet_diag_table[proto]); + if (handler && !try_module_get(handler->owner)) + handler = NULL; + rcu_read_unlock(); - return inet_diag_table[proto]; + return handler; } static void inet_diag_unlock_handler(const struct inet_diag_handler *handler) { - mutex_unlock(&inet_diag_table_mutex); + module_put(handler->owner); } void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk) @@ -104,9 +104,12 @@ static size_t inet_sk_attr_size(struct sock *sk, const struct inet_diag_handler *handler; size_t aux = 0; - handler = inet_diag_table[req->sdiag_protocol]; + rcu_read_lock(); + handler = rcu_dereference(inet_diag_table[req->sdiag_protocol]); + DEBUG_NET_WARN_ON_ONCE(!handler); if (handler && handler->idiag_get_aux_size) aux = handler->idiag_get_aux_size(sk, net_admin); + rcu_read_unlock(); return nla_total_size(sizeof(struct tcp_info)) + nla_total_size(sizeof(struct inet_diag_msg)) @@ -244,10 +247,16 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, struct nlmsghdr *nlh; struct nlattr *attr; void *info = NULL; + int protocol; cb_data = cb->data; - handler = inet_diag_table[inet_diag_get_protocol(req, cb_data)]; - BUG_ON(!handler); + protocol = inet_diag_get_protocol(req, cb_data); + + /* inet_diag_lock_handler() made sure inet_diag_table[] is stable. */ + handler = rcu_dereference_protected(inet_diag_table[protocol], 1); + DEBUG_NET_WARN_ON_ONCE(!handler); + if (!handler) + return -ENXIO; nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); @@ -605,9 +614,10 @@ static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb, protocol = inet_diag_get_protocol(req, &dump_data); handler = inet_diag_lock_handler(protocol); - if (IS_ERR(handler)) { - err = PTR_ERR(handler); - } else if (cmd == SOCK_DIAG_BY_FAMILY) { + if (!handler) + return -ENOENT; + + if (cmd == SOCK_DIAG_BY_FAMILY) { struct netlink_callback cb = { .nlh = nlh, .skb = in_skb, @@ -1259,12 +1269,12 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, again: prev_min_dump_alloc = cb->min_dump_alloc; handler = inet_diag_lock_handler(protocol); - if (!IS_ERR(handler)) + if (handler) { handler->dump(skb, cb, r); - else - err = PTR_ERR(handler); - inet_diag_unlock_handler(handler); - + inet_diag_unlock_handler(handler); + } else { + err = -ENOENT; + } /* The skb is not large enough to fit one sk info and * inet_sk_diag_fill() has requested for a larger skb. */ @@ -1457,10 +1467,9 @@ int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk) } handler = inet_diag_lock_handler(sk->sk_protocol); - if (IS_ERR(handler)) { - inet_diag_unlock_handler(handler); + if (!handler) { nlmsg_cancel(skb, nlh); - return PTR_ERR(handler); + return -ENOENT; } attr = handler->idiag_info_size @@ -1495,20 +1504,12 @@ static const struct sock_diag_handler inet6_diag_handler = { int inet_diag_register(const struct inet_diag_handler *h) { const __u16 type = h->idiag_type; - int err = -EINVAL; if (type >= IPPROTO_MAX) - goto out; + return -EINVAL; - mutex_lock(&inet_diag_table_mutex); - err = -EEXIST; - if (!inet_diag_table[type]) { - WRITE_ONCE(inet_diag_table[type], h); - err = 0; - } - mutex_unlock(&inet_diag_table_mutex); -out: - return err; + return !cmpxchg((const struct inet_diag_handler **)&inet_diag_table[type], + NULL, h) ? 0 : -EEXIST; } EXPORT_SYMBOL_GPL(inet_diag_register); @@ -1519,9 +1520,8 @@ void inet_diag_unregister(const struct inet_diag_handler *h) if (type >= IPPROTO_MAX) return; - mutex_lock(&inet_diag_table_mutex); - WRITE_ONCE(inet_diag_table[type], NULL); - mutex_unlock(&inet_diag_table_mutex); + xchg((const struct inet_diag_handler **)&inet_diag_table[type], + NULL); } EXPORT_SYMBOL_GPL(inet_diag_unregister); From 114b4bb1cc19239b272d52ebbe156053483fe2f8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:25:59 +0000 Subject: [PATCH 0175/2255] sock_diag: add module pointer to "struct sock_diag_handler" Following patch is going to use RCU instead of sock_diag_table_mutex acquisition. This patch is a preparation, no change of behavior yet. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- include/linux/sock_diag.h | 1 + net/ipv4/inet_diag.c | 2 ++ net/netlink/diag.c | 1 + net/packet/diag.c | 1 + net/smc/smc_diag.c | 1 + net/tipc/diag.c | 1 + net/unix/diag.c | 1 + net/vmw_vsock/diag.c | 1 + net/xdp/xsk_diag.c | 1 + 9 files changed, 10 insertions(+) diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index 0b9ecd8cf979..7c07754d711b 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -13,6 +13,7 @@ struct nlmsghdr; struct sock; struct sock_diag_handler { + struct module *owner; __u8 family; int (*dump)(struct sk_buff *skb, struct nlmsghdr *nlh); int (*get_info)(struct sk_buff *skb, struct sock *sk); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index abf7dc982796..52ce20691e4e 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -1488,6 +1488,7 @@ int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk) } static const struct sock_diag_handler inet_diag_handler = { + .owner = THIS_MODULE, .family = AF_INET, .dump = inet_diag_handler_cmd, .get_info = inet_diag_handler_get_info, @@ -1495,6 +1496,7 @@ static const struct sock_diag_handler inet_diag_handler = { }; static const struct sock_diag_handler inet6_diag_handler = { + .owner = THIS_MODULE, .family = AF_INET6, .dump = inet_diag_handler_cmd, .get_info = inet_diag_handler_get_info, diff --git a/net/netlink/diag.c b/net/netlink/diag.c index 1eeff9422856..e12c90d5f6ad 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c @@ -241,6 +241,7 @@ static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler netlink_diag_handler = { + .owner = THIS_MODULE, .family = AF_NETLINK, .dump = netlink_diag_handler_dump, }; diff --git a/net/packet/diag.c b/net/packet/diag.c index 9a7980e3309d..b3bd2f6c2bf7 100644 --- a/net/packet/diag.c +++ b/net/packet/diag.c @@ -245,6 +245,7 @@ static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler packet_diag_handler = { + .owner = THIS_MODULE, .family = AF_PACKET, .dump = packet_diag_handler_dump, }; diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c index 52f7c4f1e767..32bad267fa3e 100644 --- a/net/smc/smc_diag.c +++ b/net/smc/smc_diag.c @@ -255,6 +255,7 @@ static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler smc_diag_handler = { + .owner = THIS_MODULE, .family = AF_SMC, .dump = smc_diag_handler_dump, }; diff --git a/net/tipc/diag.c b/net/tipc/diag.c index 18733451c9e0..54dde8c4e4d4 100644 --- a/net/tipc/diag.c +++ b/net/tipc/diag.c @@ -95,6 +95,7 @@ static int tipc_sock_diag_handler_dump(struct sk_buff *skb, } static const struct sock_diag_handler tipc_sock_diag_handler = { + .owner = THIS_MODULE, .family = AF_TIPC, .dump = tipc_sock_diag_handler_dump, }; diff --git a/net/unix/diag.c b/net/unix/diag.c index bec09a3a1d44..c3648b706509 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -322,6 +322,7 @@ static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler unix_diag_handler = { + .owner = THIS_MODULE, .family = AF_UNIX, .dump = unix_diag_handler_dump, }; diff --git a/net/vmw_vsock/diag.c b/net/vmw_vsock/diag.c index 2e29994f92ff..ab87ef66c1e8 100644 --- a/net/vmw_vsock/diag.c +++ b/net/vmw_vsock/diag.c @@ -157,6 +157,7 @@ static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler vsock_diag_handler = { + .owner = THIS_MODULE, .family = AF_VSOCK, .dump = vsock_diag_handler_dump, }; diff --git a/net/xdp/xsk_diag.c b/net/xdp/xsk_diag.c index 9f8955367275..09dcea0cbbed 100644 --- a/net/xdp/xsk_diag.c +++ b/net/xdp/xsk_diag.c @@ -194,6 +194,7 @@ static int xsk_diag_handler_dump(struct sk_buff *nlskb, struct nlmsghdr *hdr) } static const struct sock_diag_handler xsk_diag_handler = { + .owner = THIS_MODULE, .family = AF_XDP, .dump = xsk_diag_handler_dump, }; From 1d55a6974756cf3979efd2cc68bcece611a44053 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:26:00 +0000 Subject: [PATCH 0176/2255] sock_diag: allow concurrent operations sock_diag_broadcast_destroy_work() and __sock_diag_cmd() are currently using sock_diag_table_mutex to protect against concurrent sock_diag_handlers[] changes. This makes inet_diag dump serialized, thus less scalable than legacy /proc files. It is time to switch to full RCU protection. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- net/core/sock_diag.c | 73 +++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index c53b731f2d67..72009e1f4380 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -16,7 +16,7 @@ #include #include -static const struct sock_diag_handler *sock_diag_handlers[AF_MAX]; +static const struct sock_diag_handler __rcu *sock_diag_handlers[AF_MAX]; static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); static DEFINE_MUTEX(sock_diag_table_mutex); static struct workqueue_struct *broadcast_wq; @@ -122,6 +122,24 @@ static size_t sock_diag_nlmsg_size(void) + nla_total_size_64bit(sizeof(struct tcp_info))); /* INET_DIAG_INFO */ } +static const struct sock_diag_handler *sock_diag_lock_handler(int family) +{ + const struct sock_diag_handler *handler; + + rcu_read_lock(); + handler = rcu_dereference(sock_diag_handlers[family]); + if (handler && !try_module_get(handler->owner)) + handler = NULL; + rcu_read_unlock(); + + return handler; +} + +static void sock_diag_unlock_handler(const struct sock_diag_handler *handler) +{ + module_put(handler->owner); +} + static void sock_diag_broadcast_destroy_work(struct work_struct *work) { struct broadcast_sk *bsk = @@ -138,12 +156,12 @@ static void sock_diag_broadcast_destroy_work(struct work_struct *work) if (!skb) goto out; - mutex_lock(&sock_diag_table_mutex); - hndl = sock_diag_handlers[sk->sk_family]; - if (hndl && hndl->get_info) - err = hndl->get_info(skb, sk); - mutex_unlock(&sock_diag_table_mutex); - + hndl = sock_diag_lock_handler(sk->sk_family); + if (hndl) { + if (hndl->get_info) + err = hndl->get_info(skb, sk); + sock_diag_unlock_handler(hndl); + } if (!err) nlmsg_multicast(sock_net(sk)->diag_nlsk, skb, 0, group, GFP_KERNEL); @@ -184,33 +202,26 @@ EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat); int sock_diag_register(const struct sock_diag_handler *hndl) { - int err = 0; + int family = hndl->family; - if (hndl->family >= AF_MAX) + if (family >= AF_MAX) return -EINVAL; - mutex_lock(&sock_diag_table_mutex); - if (sock_diag_handlers[hndl->family]) - err = -EBUSY; - else - WRITE_ONCE(sock_diag_handlers[hndl->family], hndl); - mutex_unlock(&sock_diag_table_mutex); - - return err; + return !cmpxchg((const struct sock_diag_handler **) + &sock_diag_handlers[family], + NULL, hndl) ? 0 : -EBUSY; } EXPORT_SYMBOL_GPL(sock_diag_register); -void sock_diag_unregister(const struct sock_diag_handler *hnld) +void sock_diag_unregister(const struct sock_diag_handler *hndl) { - int family = hnld->family; + int family = hndl->family; if (family >= AF_MAX) return; - mutex_lock(&sock_diag_table_mutex); - BUG_ON(sock_diag_handlers[family] != hnld); - WRITE_ONCE(sock_diag_handlers[family], NULL); - mutex_unlock(&sock_diag_table_mutex); + xchg((const struct sock_diag_handler **)&sock_diag_handlers[family], + NULL); } EXPORT_SYMBOL_GPL(sock_diag_unregister); @@ -227,20 +238,20 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) return -EINVAL; req->sdiag_family = array_index_nospec(req->sdiag_family, AF_MAX); - if (READ_ONCE(sock_diag_handlers[req->sdiag_family]) == NULL) + if (!rcu_access_pointer(sock_diag_handlers[req->sdiag_family])) sock_load_diag_module(req->sdiag_family, 0); - mutex_lock(&sock_diag_table_mutex); - hndl = sock_diag_handlers[req->sdiag_family]; + hndl = sock_diag_lock_handler(req->sdiag_family); if (hndl == NULL) - err = -ENOENT; - else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY) + return -ENOENT; + + if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY) err = hndl->dump(skb, nlh); else if (nlh->nlmsg_type == SOCK_DESTROY && hndl->destroy) err = hndl->destroy(skb, nlh); else err = -EOPNOTSUPP; - mutex_unlock(&sock_diag_table_mutex); + sock_diag_unlock_handler(hndl); return err; } @@ -286,12 +297,12 @@ static int sock_diag_bind(struct net *net, int group) switch (group) { case SKNLGRP_INET_TCP_DESTROY: case SKNLGRP_INET_UDP_DESTROY: - if (!READ_ONCE(sock_diag_handlers[AF_INET])) + if (!rcu_access_pointer(sock_diag_handlers[AF_INET])) sock_load_diag_module(AF_INET, 0); break; case SKNLGRP_INET6_TCP_DESTROY: case SKNLGRP_INET6_UDP_DESTROY: - if (!READ_ONCE(sock_diag_handlers[AF_INET6])) + if (!rcu_access_pointer(sock_diag_handlers[AF_INET6])) sock_load_diag_module(AF_INET6, 0); break; } From 86e8921df05c6e9423ab74ab8d41022775d8b83a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:26:01 +0000 Subject: [PATCH 0177/2255] sock_diag: allow concurrent operation in sock_diag_rcv_msg() TCPDIAG_GETSOCK and DCCPDIAG_GETSOCK diag are serialized on sock_diag_table_mutex. This is to make sure inet_diag module is not unloaded while diag was ongoing. It is time to get rid of this mutex and use RCU protection, allowing full parallelism. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- include/linux/sock_diag.h | 9 ++++++-- net/core/sock_diag.c | 43 +++++++++++++++++++++++---------------- net/ipv4/inet_diag.c | 9 ++++++-- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index 7c07754d711b..110978dc9af1 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -23,8 +23,13 @@ struct sock_diag_handler { int sock_diag_register(const struct sock_diag_handler *h); void sock_diag_unregister(const struct sock_diag_handler *h); -void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)); -void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)); +struct sock_diag_inet_compat { + struct module *owner; + int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh); +}; + +void sock_diag_register_inet_compat(const struct sock_diag_inet_compat *ptr); +void sock_diag_unregister_inet_compat(const struct sock_diag_inet_compat *ptr); u64 __sock_gen_cookie(struct sock *sk); diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index 72009e1f4380..5c3666431df4 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -17,8 +17,9 @@ #include static const struct sock_diag_handler __rcu *sock_diag_handlers[AF_MAX]; -static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); -static DEFINE_MUTEX(sock_diag_table_mutex); + +static struct sock_diag_inet_compat __rcu *inet_rcv_compat; + static struct workqueue_struct *broadcast_wq; DEFINE_COOKIE(sock_cookie); @@ -184,19 +185,20 @@ void sock_diag_broadcast_destroy(struct sock *sk) queue_work(broadcast_wq, &bsk->work); } -void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) +void sock_diag_register_inet_compat(const struct sock_diag_inet_compat *ptr) { - mutex_lock(&sock_diag_table_mutex); - inet_rcv_compat = fn; - mutex_unlock(&sock_diag_table_mutex); + xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat, + ptr); } EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat); -void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) +void sock_diag_unregister_inet_compat(const struct sock_diag_inet_compat *ptr) { - mutex_lock(&sock_diag_table_mutex); - inet_rcv_compat = NULL; - mutex_unlock(&sock_diag_table_mutex); + const struct sock_diag_inet_compat *old; + + old = xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat, + NULL); + WARN_ON_ONCE(old != ptr); } EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat); @@ -259,20 +261,27 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { + const struct sock_diag_inet_compat *ptr; int ret; switch (nlh->nlmsg_type) { case TCPDIAG_GETSOCK: case DCCPDIAG_GETSOCK: - if (inet_rcv_compat == NULL) + + if (!rcu_access_pointer(inet_rcv_compat)) sock_load_diag_module(AF_INET, 0); - mutex_lock(&sock_diag_table_mutex); - if (inet_rcv_compat != NULL) - ret = inet_rcv_compat(skb, nlh); - else - ret = -EOPNOTSUPP; - mutex_unlock(&sock_diag_table_mutex); + rcu_read_lock(); + ptr = rcu_dereference(inet_rcv_compat); + if (ptr && !try_module_get(ptr->owner)) + ptr = NULL; + rcu_read_unlock(); + + ret = -EOPNOTSUPP; + if (ptr) { + ret = ptr->fn(skb, nlh); + module_put(ptr->owner); + } return ret; case SOCK_DIAG_BY_FAMILY: diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 52ce20691e4e..2c2d8b9dd8e9 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -1527,6 +1527,11 @@ void inet_diag_unregister(const struct inet_diag_handler *h) } EXPORT_SYMBOL_GPL(inet_diag_unregister); +static const struct sock_diag_inet_compat inet_diag_compat = { + .owner = THIS_MODULE, + .fn = inet_diag_rcv_msg_compat, +}; + static int __init inet_diag_init(void) { const int inet_diag_table_size = (IPPROTO_MAX * @@ -1545,7 +1550,7 @@ static int __init inet_diag_init(void) if (err) goto out_free_inet; - sock_diag_register_inet_compat(inet_diag_rcv_msg_compat); + sock_diag_register_inet_compat(&inet_diag_compat); out: return err; @@ -1560,7 +1565,7 @@ static void __exit inet_diag_exit(void) { sock_diag_unregister(&inet6_diag_handler); sock_diag_unregister(&inet_diag_handler); - sock_diag_unregister_inet_compat(inet_diag_rcv_msg_compat); + sock_diag_unregister_inet_compat(&inet_diag_compat); kfree(inet_diag_table); } From f44e64990beb41167bd7c313d90bcf7e290c3582 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:26:02 +0000 Subject: [PATCH 0178/2255] sock_diag: remove sock_diag_mutex sock_diag_rcv() is still serializing its operations using a mutex, for no good reason. This came with commit 0a9c73014415 ("[INET_DIAG]: Fix oops in netlink_rcv_skb"), but the root cause has been fixed with commit cd40b7d3983c ("[NET]: make netlink user -> kernel interface synchronious") Remove this mutex to let multiple threads run concurrently. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- net/core/sock_diag.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index 5c3666431df4..654122838025 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -292,13 +292,9 @@ static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, } } -static DEFINE_MUTEX(sock_diag_mutex); - static void sock_diag_rcv(struct sk_buff *skb) { - mutex_lock(&sock_diag_mutex); netlink_rcv_skb(skb, &sock_diag_rcv_msg); - mutex_unlock(&sock_diag_mutex); } static int sock_diag_bind(struct net *net, int group) From 622a08e8de9f9ad576fd56e3a2e97a84370a8100 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:26:03 +0000 Subject: [PATCH 0179/2255] inet_diag: skip over empty buckets After the removal of inet_diag_table_mutex, sock_diag_table_mutex and sock_diag_mutex, I was able so see spinlock contention from inet_diag_dump_icsk() when running 100 parallel invocations. It is time to skip over empty buckets. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni --- net/ipv4/inet_diag.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 2c2d8b9dd8e9..7adace541fe2 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -1045,6 +1045,10 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, num = 0; ilb = &hashinfo->lhash2[i]; + if (hlist_nulls_empty(&ilb->nulls_head)) { + s_num = 0; + continue; + } spin_lock(&ilb->lock); sk_nulls_for_each(sk, node, &ilb->nulls_head) { struct inet_sock *inet = inet_sk(sk); @@ -1109,6 +1113,10 @@ resume_bind_walk: accum = 0; ibb = &hashinfo->bhash2[i]; + if (hlist_empty(&ibb->chain)) { + s_num = 0; + continue; + } spin_lock_bh(&ibb->lock); inet_bind_bucket_for_each(tb2, &ibb->chain) { if (!net_eq(ib2_net(tb2), net)) From 7c05e7f3e74e7e550534d524e04d7e6f78d6fa24 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 5 Jan 2024 18:48:17 +0800 Subject: [PATCH 0180/2255] bpf: Support inlining bpf_kptr_xchg() helper The motivation of inlining bpf_kptr_xchg() comes from the performance profiling of bpf memory allocator benchmark. The benchmark uses bpf_kptr_xchg() to stash the allocated objects and to pop the stashed objects for free. After inling bpf_kptr_xchg(), the performance for object free on 8-CPUs VM increases about 2%~10%. The inline also has downside: both the kasan and kcsan checks on the pointer will be unavailable. bpf_kptr_xchg() can be inlined by converting the calling of bpf_kptr_xchg() into an atomic_xchg() instruction. But the conversion depends on two conditions: 1) JIT backend supports atomic_xchg() on pointer-sized word 2) For the specific arch, the implementation of xchg is the same as atomic_xchg() on pointer-sized words. It seems most 64-bit JIT backends satisfies these two conditions. But as a precaution, defining a weak function bpf_jit_supports_ptr_xchg() to state whether such conversion is safe and only supporting inline for 64-bit host. For x86-64, it supports BPF_XCHG atomic operation and both xchg() and atomic_xchg() use arch_xchg() to implement the exchange, so enabling the inline of bpf_kptr_xchg() on x86-64 first. Reviewed-by: Eduard Zingerman Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20240105104819.3916743-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- arch/x86/net/bpf_jit_comp.c | 5 +++++ include/linux/filter.h | 1 + kernel/bpf/core.c | 10 ++++++++++ kernel/bpf/helpers.c | 1 + kernel/bpf/verifier.c | 17 +++++++++++++++++ 5 files changed, 34 insertions(+) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 919f647c740f..e1390d1e331b 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -3242,3 +3242,8 @@ void bpf_arch_poke_desc_update(struct bpf_jit_poke_descriptor *poke, BUG_ON(ret < 0); } } + +bool bpf_jit_supports_ptr_xchg(void) +{ + return true; +} diff --git a/include/linux/filter.h b/include/linux/filter.h index 68fb6c8142fe..35f067fd3840 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -955,6 +955,7 @@ bool bpf_jit_supports_subprog_tailcalls(void); bool bpf_jit_supports_kfunc_call(void); bool bpf_jit_supports_far_kfunc_call(void); bool bpf_jit_supports_exceptions(void); +bool bpf_jit_supports_ptr_xchg(void); void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie); bool bpf_helper_changes_pkt_data(void *func); diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index ea6843be2616..fbb1d95a9b44 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2925,6 +2925,16 @@ bool __weak bpf_jit_supports_far_kfunc_call(void) return false; } +/* Return TRUE if the JIT backend satisfies the following two conditions: + * 1) JIT backend supports atomic_xchg() on pointer-sized words. + * 2) Under the specific arch, the implementation of xchg() is the same + * as atomic_xchg() on pointer-sized words. + */ +bool __weak bpf_jit_supports_ptr_xchg(void) +{ + return false; +} + /* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call * skb_copy_bits(), so provide a weak definition of it for NET-less config. */ diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index be72824f32b2..e04ca1af8927 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1414,6 +1414,7 @@ BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr) { unsigned long *kptr = map_value; + /* This helper may be inlined by verifier. */ return xchg(kptr, (unsigned long)ptr); } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 65f598694d55..5b33d65eef7b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -19809,6 +19809,23 @@ patch_map_ops_generic: continue; } + /* Implement bpf_kptr_xchg inline */ + if (prog->jit_requested && BITS_PER_LONG == 64 && + insn->imm == BPF_FUNC_kptr_xchg && + bpf_jit_supports_ptr_xchg()) { + insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_2); + insn_buf[1] = BPF_ATOMIC_OP(BPF_DW, BPF_XCHG, BPF_REG_1, BPF_REG_0, 0); + cnt = 2; + + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); + if (!new_prog) + return -ENOMEM; + + delta += cnt - 1; + env->prog = prog = new_prog; + insn = new_prog->insnsi + i + delta; + continue; + } patch_call_imm: fn = env->ops->get_func_proto(insn->imm, env->prog); /* all functions that have prototype and verifier allowed From b4b7a4099b8ccea224577003fcf9d321bf0817b7 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 5 Jan 2024 18:48:18 +0800 Subject: [PATCH 0181/2255] selftests/bpf: Factor out get_xlated_program() helper Both test_verifier and test_progs use get_xlated_program(), so moving the helper into testing_helpers.h to reuse it. Acked-by: Eduard Zingerman Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20240105104819.3916743-3-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/ctx_rewrite.c | 44 ----------------- tools/testing/selftests/bpf/test_verifier.c | 47 +------------------ tools/testing/selftests/bpf/testing_helpers.c | 42 +++++++++++++++++ tools/testing/selftests/bpf/testing_helpers.h | 6 +++ 4 files changed, 50 insertions(+), 89 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c b/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c index 4951aa978f33..3b7c57fe55a5 100644 --- a/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c +++ b/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c @@ -626,50 +626,6 @@ err: return false; } -/* Request BPF program instructions after all rewrites are applied, - * e.g. verifier.c:convert_ctx_access() is done. - */ -static int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt) -{ - struct bpf_prog_info info = {}; - __u32 info_len = sizeof(info); - __u32 xlated_prog_len; - __u32 buf_element_size = sizeof(struct bpf_insn); - - if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { - perror("bpf_prog_get_info_by_fd failed"); - return -1; - } - - xlated_prog_len = info.xlated_prog_len; - if (xlated_prog_len % buf_element_size) { - printf("Program length %d is not multiple of %d\n", - xlated_prog_len, buf_element_size); - return -1; - } - - *cnt = xlated_prog_len / buf_element_size; - *buf = calloc(*cnt, buf_element_size); - if (!buf) { - perror("can't allocate xlated program buffer"); - return -ENOMEM; - } - - bzero(&info, sizeof(info)); - info.xlated_prog_len = xlated_prog_len; - info.xlated_prog_insns = (__u64)(unsigned long)*buf; - if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { - perror("second bpf_prog_get_info_by_fd failed"); - goto out_free_buf; - } - - return 0; - -out_free_buf: - free(*buf); - return -1; -} - static void print_insn(void *private_data, const char *fmt, ...) { va_list args; diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index f36e41435be7..87519d7fe4c6 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1341,48 +1341,6 @@ static bool cmp_str_seq(const char *log, const char *exp) return true; } -static struct bpf_insn *get_xlated_program(int fd_prog, int *cnt) -{ - __u32 buf_element_size = sizeof(struct bpf_insn); - struct bpf_prog_info info = {}; - __u32 info_len = sizeof(info); - __u32 xlated_prog_len; - struct bpf_insn *buf; - - if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { - perror("bpf_prog_get_info_by_fd failed"); - return NULL; - } - - xlated_prog_len = info.xlated_prog_len; - if (xlated_prog_len % buf_element_size) { - printf("Program length %d is not multiple of %d\n", - xlated_prog_len, buf_element_size); - return NULL; - } - - *cnt = xlated_prog_len / buf_element_size; - buf = calloc(*cnt, buf_element_size); - if (!buf) { - perror("can't allocate xlated program buffer"); - return NULL; - } - - bzero(&info, sizeof(info)); - info.xlated_prog_len = xlated_prog_len; - info.xlated_prog_insns = (__u64)(unsigned long)buf; - if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { - perror("second bpf_prog_get_info_by_fd failed"); - goto out_free_buf; - } - - return buf; - -out_free_buf: - free(buf); - return NULL; -} - static bool is_null_insn(struct bpf_insn *insn) { struct bpf_insn null_insn = {}; @@ -1505,7 +1463,7 @@ static void print_insn(struct bpf_insn *buf, int cnt) static bool check_xlated_program(struct bpf_test *test, int fd_prog) { struct bpf_insn *buf; - int cnt; + unsigned int cnt; bool result = true; bool check_expected = !is_null_insn(test->expected_insns); bool check_unexpected = !is_null_insn(test->unexpected_insns); @@ -1513,8 +1471,7 @@ static bool check_xlated_program(struct bpf_test *test, int fd_prog) if (!check_expected && !check_unexpected) goto out; - buf = get_xlated_program(fd_prog, &cnt); - if (!buf) { + if (get_xlated_program(fd_prog, &buf, &cnt)) { printf("FAIL: can't get xlated program\n"); result = false; goto out; diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index d2458c1b1671..53c40f62fdcb 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -387,3 +387,45 @@ int kern_sync_rcu(void) { return syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0, 0); } + +int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt) +{ + __u32 buf_element_size = sizeof(struct bpf_insn); + struct bpf_prog_info info = {}; + __u32 info_len = sizeof(info); + __u32 xlated_prog_len; + + if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { + perror("bpf_prog_get_info_by_fd failed"); + return -1; + } + + xlated_prog_len = info.xlated_prog_len; + if (xlated_prog_len % buf_element_size) { + printf("Program length %u is not multiple of %u\n", + xlated_prog_len, buf_element_size); + return -1; + } + + *cnt = xlated_prog_len / buf_element_size; + *buf = calloc(*cnt, buf_element_size); + if (!buf) { + perror("can't allocate xlated program buffer"); + return -ENOMEM; + } + + bzero(&info, sizeof(info)); + info.xlated_prog_len = xlated_prog_len; + info.xlated_prog_insns = (__u64)(unsigned long)*buf; + if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { + perror("second bpf_prog_get_info_by_fd failed"); + goto out_free_buf; + } + + return 0; + +out_free_buf: + free(*buf); + *buf = NULL; + return -1; +} diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index 35284faff4f2..1ed5b9200d66 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -46,4 +46,10 @@ static inline __u64 get_time_ns(void) return (u64)t.tv_sec * 1000000000 + t.tv_nsec; } +struct bpf_insn; +/* Request BPF program instructions after all rewrites are applied, + * e.g. verifier.c:convert_ctx_access() is done. + */ +int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt); + #endif /* __TESTING_HELPERS_H */ From 17bda53e43bc41d881ca6a02b3c6f5376c55b3d3 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 5 Jan 2024 18:48:19 +0800 Subject: [PATCH 0182/2255] selftests/bpf: Test the inlining of bpf_kptr_xchg() The test uses bpf_prog_get_info_by_fd() to obtain the xlated instructions of the program first. Since these instructions have already been rewritten by the verifier, the tests then checks whether the rewritten instructions are as expected. And to ensure LLVM generates code exactly as expected, use inline assembly and a naked function. Suggested-by: Eduard Zingerman Signed-off-by: Hou Tao Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240105104819.3916743-4-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/kptr_xchg_inline.c | 51 +++++++++++++++++++ .../selftests/bpf/progs/kptr_xchg_inline.c | 48 +++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c create mode 100644 tools/testing/selftests/bpf/progs/kptr_xchg_inline.c diff --git a/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c b/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c new file mode 100644 index 000000000000..5a4bee1cf970 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#include + +#include "linux/filter.h" +#include "kptr_xchg_inline.skel.h" + +void test_kptr_xchg_inline(void) +{ + struct kptr_xchg_inline *skel; + struct bpf_insn *insn = NULL; + struct bpf_insn exp; + unsigned int cnt; + int err; + +#if !defined(__x86_64__) + test__skip(); + return; +#endif + + skel = kptr_xchg_inline__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_load")) + return; + + err = get_xlated_program(bpf_program__fd(skel->progs.kptr_xchg_inline), &insn, &cnt); + if (!ASSERT_OK(err, "prog insn")) + goto out; + + /* The original instructions are: + * r1 = map[id:xxx][0]+0 + * r2 = 0 + * call bpf_kptr_xchg#yyy + * + * call bpf_kptr_xchg#yyy will be inlined as: + * r0 = r2 + * r0 = atomic64_xchg((u64 *)(r1 +0), r0) + */ + if (!ASSERT_GT(cnt, 5, "insn cnt")) + goto out; + + exp = BPF_MOV64_REG(BPF_REG_0, BPF_REG_2); + if (!ASSERT_OK(memcmp(&insn[3], &exp, sizeof(exp)), "mov")) + goto out; + + exp = BPF_ATOMIC_OP(BPF_DW, BPF_XCHG, BPF_REG_1, BPF_REG_0, 0); + if (!ASSERT_OK(memcmp(&insn[4], &exp, sizeof(exp)), "xchg")) + goto out; +out: + free(insn); + kptr_xchg_inline__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/kptr_xchg_inline.c b/tools/testing/selftests/bpf/progs/kptr_xchg_inline.c new file mode 100644 index 000000000000..2414ac20b6d5 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kptr_xchg_inline.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#include +#include + +#include "bpf_experimental.h" +#include "bpf_misc.h" + +char _license[] SEC("license") = "GPL"; + +struct bin_data { + char blob[32]; +}; + +#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8))) +private(kptr) struct bin_data __kptr * ptr; + +SEC("tc") +__naked int kptr_xchg_inline(void) +{ + asm volatile ( + "r1 = %[ptr] ll;" + "r2 = 0;" + "call %[bpf_kptr_xchg];" + "if r0 == 0 goto 1f;" + "r1 = r0;" + "r2 = 0;" + "call %[bpf_obj_drop_impl];" + "1:" + "r0 = 0;" + "exit;" + : + : __imm_addr(ptr), + __imm(bpf_kptr_xchg), + __imm(bpf_obj_drop_impl) + : __clobber_all + ); +} + +/* BTF FUNC records are not generated for kfuncs referenced + * from inline assembly. These records are necessary for + * libbpf to link the program. The function below is a hack + * to ensure that BTF FUNC records are generated. + */ +void __btf_root(void) +{ + bpf_obj_drop(NULL); +} From e31f98c1af810a13395ee9ab57402d82272445af Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 Jan 2024 16:09:02 -0800 Subject: [PATCH 0183/2255] selftests/bpf: fix test_loader check message Seeing: process_subtest:PASS:Can't alloc specs array 0 nsec ... in verbose successful test log is very confusing. Use smaller identifier-like test tag to denote that we are asserting specs array allocation success. Now it's much less distracting: process_subtest:PASS:specs_alloc 0 nsec Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240105000909.2818934-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c index f01391021218..72906d27babf 100644 --- a/tools/testing/selftests/bpf/test_loader.c +++ b/tools/testing/selftests/bpf/test_loader.c @@ -688,7 +688,7 @@ static void process_subtest(struct test_loader *tester, ++nr_progs; specs = calloc(nr_progs, sizeof(struct test_spec)); - if (!ASSERT_OK_PTR(specs, "Can't alloc specs array")) + if (!ASSERT_OK_PTR(specs, "specs_alloc")) return; i = 0; From 18810ad3929ff6b5d8e67e3adc40d690bd780fd6 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 Jan 2024 16:09:03 -0800 Subject: [PATCH 0184/2255] bpf: make sure scalar args don't accept __arg_nonnull tag Move scalar arg processing in btf_prepare_func_args() after all pointer arg processing is done. This makes it easier to do validation. One example of unintended behavior right now is ability to specify __arg_nonnull for integer/enum arguments. This patch fixes this. Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240105000909.2818934-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 596471189176..dbe7a590f565 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -7058,10 +7058,6 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); - if (btf_type_is_int(t) || btf_is_any_enum(t)) { - sub->args[i].arg_type = ARG_ANYTHING; - continue; - } if (btf_type_is_ptr(t) && btf_get_prog_ctx_type(log, btf, t, prog_type, i)) { sub->args[i].arg_type = ARG_PTR_TO_CTX; continue; @@ -7091,6 +7087,10 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) bpf_log(log, "arg#%d marked as non-null, but is not a pointer type\n", i); return -EINVAL; } + if (btf_type_is_int(t) || btf_is_any_enum(t)) { + sub->args[i].arg_type = ARG_ANYTHING; + continue; + } bpf_log(log, "Arg#%d type %s in %s() is not supported yet.\n", i, btf_type_str(t), tname); return -EINVAL; From 54c11ec4935a61af32bb03fc52e7172c97bd7203 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 Jan 2024 16:09:04 -0800 Subject: [PATCH 0185/2255] bpf: prepare btf_prepare_func_args() for multiple tags per argument Add btf_arg_tag flags enum to be able to record multiple tags per argument. Also streamline pointer argument processing some more. Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240105000909.2818934-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 53 ++++++++++++++++++++++++++++++------------- kernel/bpf/verifier.c | 1 - 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index dbe7a590f565..1636b574a63d 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6946,6 +6946,11 @@ static bool btf_is_dynptr_ptr(const struct btf *btf, const struct btf_type *t) return false; } +enum btf_arg_tag { + ARG_TAG_CTX = 0x1, + ARG_TAG_NONNULL = 0x2, +}; + /* Process BTF of a function to produce high-level expectation of function * arguments (like ARG_PTR_TO_CTX, or ARG_PTR_TO_MEM, etc). This information * is cached in subprog info for reuse. @@ -7027,10 +7032,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) * Only PTR_TO_CTX and SCALAR are supported atm. */ for (i = 0; i < nargs; i++) { - bool is_nonnull = false; const char *tag; - - t = btf_type_by_id(btf, args[i].type); + u32 tags = 0; tag = btf_find_decl_tag_value(btf, fn_t, i, "arg:"); if (IS_ERR(tag) && PTR_ERR(tag) == -ENOENT) { @@ -7048,43 +7051,61 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) bpf_log(log, "arg#%d type tag is not supported in static functions\n", i); return -EOPNOTSUPP; } + if (strcmp(tag, "ctx") == 0) { - sub->args[i].arg_type = ARG_PTR_TO_CTX; - continue; + tags |= ARG_TAG_CTX; + } else if (strcmp(tag, "nonnull") == 0) { + tags |= ARG_TAG_NONNULL; + } else { + bpf_log(log, "arg#%d has unsupported set of tags\n", i); + return -EOPNOTSUPP; } - if (strcmp(tag, "nonnull") == 0) - is_nonnull = true; } + t = btf_type_by_id(btf, args[i].type); while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); - if (btf_type_is_ptr(t) && btf_get_prog_ctx_type(log, btf, t, prog_type, i)) { + if (!btf_type_is_ptr(t)) + goto skip_pointer; + + if ((tags & ARG_TAG_CTX) || btf_get_prog_ctx_type(log, btf, t, prog_type, i)) { + if (tags & ~ARG_TAG_CTX) { + bpf_log(log, "arg#%d has invalid combination of tags\n", i); + return -EINVAL; + } sub->args[i].arg_type = ARG_PTR_TO_CTX; continue; } - if (btf_type_is_ptr(t) && btf_is_dynptr_ptr(btf, t)) { + if (btf_is_dynptr_ptr(btf, t)) { + if (tags) { + bpf_log(log, "arg#%d has invalid combination of tags\n", i); + return -EINVAL; + } sub->args[i].arg_type = ARG_PTR_TO_DYNPTR | MEM_RDONLY; continue; } - if (is_global && btf_type_is_ptr(t)) { + if (is_global) { /* generic user data pointer */ u32 mem_size; t = btf_type_skip_modifiers(btf, t->type, NULL); ref_t = btf_resolve_size(btf, t, &mem_size); if (IS_ERR(ref_t)) { - bpf_log(log, - "arg#%d reference type('%s %s') size cannot be determined: %ld\n", - i, btf_type_str(t), btf_name_by_offset(btf, t->name_off), + bpf_log(log, "arg#%d reference type('%s %s') size cannot be determined: %ld\n", + i, btf_type_str(t), btf_name_by_offset(btf, t->name_off), PTR_ERR(ref_t)); return -EINVAL; } - sub->args[i].arg_type = is_nonnull ? ARG_PTR_TO_MEM : ARG_PTR_TO_MEM_OR_NULL; + sub->args[i].arg_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL; + if (tags & ARG_TAG_NONNULL) + sub->args[i].arg_type &= ~PTR_MAYBE_NULL; sub->args[i].mem_size = mem_size; continue; } - if (is_nonnull) { - bpf_log(log, "arg#%d marked as non-null, but is not a pointer type\n", i); + +skip_pointer: + if (tags) { + bpf_log(log, "arg#%d has pointer tag, but is not a pointer type\n", i); return -EINVAL; } if (btf_type_is_int(t) || btf_is_any_enum(t)) { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5b33d65eef7b..27ad463b3bdd 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20058,7 +20058,6 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog) state->first_insn_idx = env->subprog_info[subprog].start; state->last_insn_idx = -1; - regs = state->frame[state->curframe]->regs; if (subprog || env->prog->type == BPF_PROG_TYPE_EXT) { const char *sub_name = subprog_name(env, subprog); From 522bb2c1f82b12eb7befaae815d1d959b8e6bba2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 Jan 2024 16:09:05 -0800 Subject: [PATCH 0186/2255] bpf: support multiple tags per argument Add ability to iterate multiple decl_tag types pointed to the same function argument. Use this to support multiple __arg_xxx tags per global subprog argument. We leave btf_find_decl_tag_value() intact, but change its implementation to use a new btf_find_next_decl_tag() which can be straightforwardly used to find next BTF type ID of a matching btf_decl_tag type. btf_prepare_func_args() is switched from btf_find_decl_tag_value() to btf_find_next_decl_tag() to gain multiple tags per argument support. Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240105000909.2818934-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 2 ++ kernel/bpf/btf.c | 72 ++++++++++++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index e30100597d0a..377857b232c6 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2472,6 +2472,8 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr struct btf *btf, const struct btf_type *t); const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt, int comp_idx, const char *tag_key); +int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, + int comp_idx, const char *tag_key, int last_id); struct bpf_prog *bpf_prog_by_id(u32 id); struct bpf_link *bpf_link_by_id(u32 id); diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 1636b574a63d..4f532b303a27 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -3310,30 +3310,48 @@ static int btf_find_kptr(const struct btf *btf, const struct btf_type *t, return BTF_FIELD_FOUND; } +int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, + int comp_idx, const char *tag_key, int last_id) +{ + int len = strlen(tag_key); + int i, n; + + for (i = last_id + 1, n = btf_nr_types(btf); i < n; i++) { + const struct btf_type *t = btf_type_by_id(btf, i); + + if (!btf_type_is_decl_tag(t)) + continue; + if (pt != btf_type_by_id(btf, t->type)) + continue; + if (btf_type_decl_tag(t)->component_idx != comp_idx) + continue; + if (strncmp(__btf_name_by_offset(btf, t->name_off), tag_key, len)) + continue; + return i; + } + return -ENOENT; +} + const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt, int comp_idx, const char *tag_key) { const char *value = NULL; - int i; + const struct btf_type *t; + int len, id; - for (i = 1; i < btf_nr_types(btf); i++) { - const struct btf_type *t = btf_type_by_id(btf, i); - int len = strlen(tag_key); + id = btf_find_next_decl_tag(btf, pt, comp_idx, tag_key, 0); + if (id < 0) + return ERR_PTR(id); + + t = btf_type_by_id(btf, id); + len = strlen(tag_key); + value = __btf_name_by_offset(btf, t->name_off) + len; + + /* Prevent duplicate entries for same type */ + id = btf_find_next_decl_tag(btf, pt, comp_idx, tag_key, id); + if (id >= 0) + return ERR_PTR(-EEXIST); - if (!btf_type_is_decl_tag(t)) - continue; - if (pt != btf_type_by_id(btf, t->type) || - btf_type_decl_tag(t)->component_idx != comp_idx) - continue; - if (strncmp(__btf_name_by_offset(btf, t->name_off), tag_key, len)) - continue; - /* Prevent duplicate entries for same type */ - if (value) - return ERR_PTR(-EEXIST); - value = __btf_name_by_offset(btf, t->name_off) + len; - } - if (!value) - return ERR_PTR(-ENOENT); return value; } @@ -7032,20 +7050,16 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) * Only PTR_TO_CTX and SCALAR are supported atm. */ for (i = 0; i < nargs; i++) { - const char *tag; u32 tags = 0; + int id = 0; - tag = btf_find_decl_tag_value(btf, fn_t, i, "arg:"); - if (IS_ERR(tag) && PTR_ERR(tag) == -ENOENT) { - tag = NULL; - } else if (IS_ERR(tag)) { - bpf_log(log, "arg#%d type's tag fetching failure: %ld\n", i, PTR_ERR(tag)); - return PTR_ERR(tag); - } /* 'arg:' decl_tag takes precedence over derivation of * register type from BTF type itself */ - if (tag) { + while ((id = btf_find_next_decl_tag(btf, fn_t, i, "arg:", id)) > 0) { + const struct btf_type *tag_t = btf_type_by_id(btf, id); + const char *tag = __btf_name_by_offset(btf, tag_t->name_off) + 4; + /* disallow arg tags in static subprogs */ if (!is_global) { bpf_log(log, "arg#%d type tag is not supported in static functions\n", i); @@ -7061,6 +7075,10 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) return -EOPNOTSUPP; } } + if (id != -ENOENT) { + bpf_log(log, "arg#%d type tag fetching failure: %d\n", i, id); + return id; + } t = btf_type_by_id(btf, args[i].type); while (btf_type_is_modifier(t)) From 15b8b0be985592fd19ee4e661d13d291877b09c7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 5 Jan 2024 22:55:45 -0800 Subject: [PATCH 0187/2255] net: filter: fix spelling mistakes Fix spelling errors as reported by codespell. Signed-off-by: Randy Dunlap Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Andrii Nakryiko Cc: bpf@vger.kernel.org Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240106065545.16855-1-rdunlap@infradead.org Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 24061f29c9dd..8c9f67c81e22 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -777,7 +777,7 @@ jmp_rest: BPF_EMIT_JMP; break; - /* ldxb 4 * ([14] & 0xf) is remaped into 6 insns. */ + /* ldxb 4 * ([14] & 0xf) is remapped into 6 insns. */ case BPF_LDX | BPF_MSH | BPF_B: { struct sock_filter tmp = { .code = BPF_LD | BPF_ABS | BPF_B, @@ -803,7 +803,7 @@ jmp_rest: *insn = BPF_MOV64_REG(BPF_REG_A, BPF_REG_TMP); break; } - /* RET_K is remaped into 2 insns. RET_A case doesn't need an + /* RET_K is remapped into 2 insns. RET_A case doesn't need an * extra mov as BPF_REG_0 is already mapped into BPF_REG_A. */ case BPF_RET | BPF_A: @@ -2967,7 +2967,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, * * Then if B is non-zero AND there is no space allocate space and * compact A, B regions into page. If there is space shift ring to - * the rigth free'ing the next element in ring to place B, leaving + * the right free'ing the next element in ring to place B, leaving * A untouched except to reduce length. */ if (start != offset) { @@ -8226,7 +8226,7 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) #if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES) /* The nf_conn___init type is used in the NF_CONNTRACK kfuncs. The * kfuncs are defined in two different modules, and we want to be able - * to use them interchangably with the same BTF type ID. Because modules + * to use them interchangeably with the same BTF type ID. Because modules * can't de-duplicate BTF IDs between each other, we need the type to be * referenced in the vmlinux BTF or the verifier will get confused about * the different types. So we add this dummy type reference which will From 81777efbf59305fa145bede97dd4abdc35540578 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Mon, 8 Jan 2024 13:42:31 -0800 Subject: [PATCH 0188/2255] Introduce concept of conformance groups The discussion of what the actual conformance groups should be is still in progress, so this is just part 1 which only uses "legacy" for deprecated instructions and "basic" for everything else. Subsequent patches will add more groups as discussion continues. Signed-off-by: Dave Thaler Acked-by: David Vernet Link: https://lore.kernel.org/r/20240108214231.5280-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/standardization/instruction-set.rst | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index 245b6defc298..eb0f234a8001 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -97,6 +97,28 @@ Definitions A: 10000110 B: 11111111 10000110 +Conformance groups +------------------ + +An implementation does not need to support all instructions specified in this +document (e.g., deprecated instructions). Instead, a number of conformance +groups are specified. An implementation must support the "basic" conformance +group and may support additional conformance groups, where supporting a +conformance group means it must support all instructions in that conformance +group. + +The use of named conformance groups enables interoperability between a runtime +that executes instructions, and tools as such compilers that generate +instructions for the runtime. Thus, capability discovery in terms of +conformance groups might be done manually by users or automatically by tools. + +Each conformance group has a short ASCII label (e.g., "basic") that +corresponds to a set of instructions that are mandatory. That is, each +instruction has one or more conformance groups of which it is a member. + +The "basic" conformance group includes all instructions defined in this +specification unless otherwise noted. + Instruction encoding ==================== @@ -610,4 +632,6 @@ Legacy BPF Packet access instructions BPF previously introduced special instructions for access to packet data that were carried over from classic BPF. However, these instructions are -deprecated and should no longer be used. +deprecated and should no longer be used. All legacy packet access +instructions belong to the "legacy" conformance group instead of the "basic" +conformance group. From 56d3e44af80c6b4c7cb89a73061ee35d4a7aee18 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 9 Jan 2024 15:17:38 -0800 Subject: [PATCH 0189/2255] selftests/bpf: detect testing prog flags support Various tests specify extra testing prog_flags when loading BPF programs, like BPF_F_TEST_RND_HI32, and more recently also BPF_F_TEST_REG_INVARIANTS. While BPF_F_TEST_RND_HI32 is old enough to not cause much problem on older kernels, BPF_F_TEST_REG_INVARIANTS is very fresh and unconditionally specifying it causes selftests to fail on even slightly outdated kernels. This breaks libbpf CI test against 4.9 and 5.15 kernels, it can break some local development (done outside of VM), etc. To prevent this, and guard against similar problems in the future, do runtime detection of supported "testing flags", and only provide those that host kernel recognizes. Acked-by: Song Liu Acked-by: Jiri Olsa Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240109231738.575844-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/bpf_verif_scale.c | 2 +- .../selftests/bpf/prog_tests/reg_bounds.c | 2 +- tools/testing/selftests/bpf/test_loader.c | 2 +- tools/testing/selftests/bpf/test_sock_addr.c | 3 +- tools/testing/selftests/bpf/test_verifier.c | 2 +- tools/testing/selftests/bpf/testing_helpers.c | 32 +++++++++++++++++-- tools/testing/selftests/bpf/testing_helpers.h | 1 + 7 files changed, 37 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c index e770912fc1d2..4c6ada5b270b 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c @@ -35,7 +35,7 @@ static int check_load(const char *file, enum bpf_prog_type type) } bpf_program__set_type(prog, type); - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); + bpf_program__set_flags(prog, testing_prog_flags()); bpf_program__set_log_level(prog, 4 | extra_prog_load_log_flags); err = bpf_object__load(obj); diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c index 820d0bcfc474..eb74363f9f70 100644 --- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -840,7 +840,7 @@ static int load_range_cmp_prog(struct range x, struct range y, enum op op, .log_level = 2, .log_buf = log_buf, .log_size = log_sz, - .prog_flags = BPF_F_TEST_REG_INVARIANTS, + .prog_flags = testing_prog_flags(), ); /* ; skip exit block below diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c index 72906d27babf..ba57601c2a4d 100644 --- a/tools/testing/selftests/bpf/test_loader.c +++ b/tools/testing/selftests/bpf/test_loader.c @@ -181,7 +181,7 @@ static int parse_test_spec(struct test_loader *tester, memset(spec, 0, sizeof(*spec)); spec->prog_name = bpf_program__name(prog); - spec->prog_flags = BPF_F_TEST_REG_INVARIANTS; /* by default be strict */ + spec->prog_flags = testing_prog_flags(); btf = bpf_object__btf(obj); if (!btf) { diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index b0068a9d2cfe..80c42583f597 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -19,6 +19,7 @@ #include #include "cgroup_helpers.h" +#include "testing_helpers.h" #include "bpf_util.h" #ifndef ENOTSUPP @@ -679,7 +680,7 @@ static int load_path(const struct sock_addr_test *test, const char *path) bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR); bpf_program__set_expected_attach_type(prog, test->expected_attach_type); - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); + bpf_program__set_flags(prog, testing_prog_flags()); err = bpf_object__load(obj); if (err) { diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 87519d7fe4c6..1a09fc34d093 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1545,7 +1545,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, if (fixup_skips != skips) return; - pflags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; + pflags = testing_prog_flags(); if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT) pflags |= BPF_F_STRICT_ALIGNMENT; if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 53c40f62fdcb..106ef05586b8 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -252,6 +252,34 @@ __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info) int extra_prog_load_log_flags = 0; +int testing_prog_flags(void) +{ + static int cached_flags = -1; + static int prog_flags[] = { BPF_F_TEST_RND_HI32, BPF_F_TEST_REG_INVARIANTS }; + static struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int insn_cnt = ARRAY_SIZE(insns), i, fd, flags = 0; + LIBBPF_OPTS(bpf_prog_load_opts, opts); + + if (cached_flags >= 0) + return cached_flags; + + for (i = 0; i < ARRAY_SIZE(prog_flags); i++) { + opts.prog_flags = prog_flags[i]; + fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "flag-test", "GPL", + insns, insn_cnt, &opts); + if (fd >= 0) { + flags |= prog_flags[i]; + close(fd); + } + } + + cached_flags = flags; + return cached_flags; +} + int bpf_prog_test_load(const char *file, enum bpf_prog_type type, struct bpf_object **pobj, int *prog_fd) { @@ -276,7 +304,7 @@ int bpf_prog_test_load(const char *file, enum bpf_prog_type type, if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) bpf_program__set_type(prog, type); - flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; + flags = bpf_program__flags(prog) | testing_prog_flags(); bpf_program__set_flags(prog, flags); err = bpf_object__load(obj); @@ -299,7 +327,7 @@ int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, { LIBBPF_OPTS(bpf_prog_load_opts, opts, .kern_version = kern_version, - .prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS, + .prog_flags = testing_prog_flags(), .log_level = extra_prog_load_log_flags, .log_buf = log_buf, .log_size = log_buf_sz, diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index 1ed5b9200d66..e099aa4da611 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -51,5 +51,6 @@ struct bpf_insn; * e.g. verifier.c:convert_ctx_access() is done. */ int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt); +int testing_prog_flags(void); #endif /* __TESTING_HELPERS_H */ From f067074bafd5060428211ee7bb8a3f86ff6bc58d Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 11 Jan 2024 13:16:48 -0700 Subject: [PATCH 0190/2255] selftests/bpf: Update LLVM Phabricator links reviews.llvm.org was LLVM's Phabricator instances for code review. It has been abandoned in favor of GitHub pull requests. While the majority of links in the kernel sources still work because of the work Fangrui has done turning the dynamic Phabricator instance into a static archive, there are some issues with that work, so preemptively convert all the links in the kernel sources to point to the commit on GitHub. Most of the commits have the corresponding differential review link in the commit message itself so there should not be any loss of fidelity in the relevant information. Additionally, fix a typo in the xdpwall.c print ("LLMV" -> "LLVM") while in the area. Link: https://discourse.llvm.org/t/update-on-github-pull-requests/71540/172 Acked-by: Yonghong Song Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20240111-bpf-update-llvm-phabricator-links-v2-1-9a7ae976bd64@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/README.rst | 32 +++++++++---------- .../selftests/bpf/prog_tests/xdpwall.c | 2 +- .../bpf/progs/test_core_reloc_type_id.c | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/bpf/README.rst b/tools/testing/selftests/bpf/README.rst index 9af79c7a9b58..9b974e425af3 100644 --- a/tools/testing/selftests/bpf/README.rst +++ b/tools/testing/selftests/bpf/README.rst @@ -115,7 +115,7 @@ the insn 20 undoes map_value addition. It is currently impossible for the verifier to understand such speculative pointer arithmetic. Hence `this patch`__ addresses it on the compiler side. It was committed on llvm 12. -__ https://reviews.llvm.org/D85570 +__ https://github.com/llvm/llvm-project/commit/ddf1864ace484035e3cde5e83b3a31ac81e059c6 The corresponding C code @@ -165,7 +165,7 @@ This is due to a llvm BPF backend bug. `The fix`__ has been pushed to llvm 10.x release branch and will be available in 10.0.1. The patch is available in llvm 11.0.0 trunk. -__ https://reviews.llvm.org/D78466 +__ https://github.com/llvm/llvm-project/commit/3cb7e7bf959dcd3b8080986c62e10a75c7af43f0 bpf_verif_scale/loop6.bpf.o test failure with Clang 12 ====================================================== @@ -204,7 +204,7 @@ r5(w5) is eventually saved on stack at insn #24 for later use. This cause later verifier failure. The bug has been `fixed`__ in Clang 13. -__ https://reviews.llvm.org/D97479 +__ https://github.com/llvm/llvm-project/commit/1959ead525b8830cc8a345f45e1c3ef9902d3229 BPF CO-RE-based tests and Clang version ======================================= @@ -221,11 +221,11 @@ failures: - __builtin_btf_type_id() [0_, 1_, 2_]; - __builtin_preserve_type_info(), __builtin_preserve_enum_value() [3_, 4_]. -.. _0: https://reviews.llvm.org/D74572 -.. _1: https://reviews.llvm.org/D74668 -.. _2: https://reviews.llvm.org/D85174 -.. _3: https://reviews.llvm.org/D83878 -.. _4: https://reviews.llvm.org/D83242 +.. _0: https://github.com/llvm/llvm-project/commit/6b01b465388b204d543da3cf49efd6080db094a9 +.. _1: https://github.com/llvm/llvm-project/commit/072cde03aaa13a2c57acf62d79876bf79aa1919f +.. _2: https://github.com/llvm/llvm-project/commit/00602ee7ef0bf6c68d690a2bd729c12b95c95c99 +.. _3: https://github.com/llvm/llvm-project/commit/6d218b4adb093ff2e9764febbbc89f429412006c +.. _4: https://github.com/llvm/llvm-project/commit/6d6750696400e7ce988d66a1a00e1d0cb32815f8 Floating-point tests and Clang version ====================================== @@ -234,7 +234,7 @@ Certain selftests, e.g. core_reloc, require support for the floating-point types, which was introduced in `Clang 13`__. The older Clang versions will either crash when compiling these tests, or generate an incorrect BTF. -__ https://reviews.llvm.org/D83289 +__ https://github.com/llvm/llvm-project/commit/a7137b238a07d9399d3ae96c0b461571bd5aa8b2 Kernel function call test and Clang version =========================================== @@ -248,7 +248,7 @@ Without it, the error from compiling bpf selftests looks like: libbpf: failed to find BTF for extern 'tcp_slow_start' [25] section: -2 -__ https://reviews.llvm.org/D93563 +__ https://github.com/llvm/llvm-project/commit/886f9ff53155075bd5f1e994f17b85d1e1b7470c btf_tag test and Clang version ============================== @@ -264,8 +264,8 @@ Without them, the btf_tag selftest will be skipped and you will observe: # btf_tag:SKIP -.. _0: https://reviews.llvm.org/D111588 -.. _1: https://reviews.llvm.org/D111199 +.. _0: https://github.com/llvm/llvm-project/commit/a162b67c98066218d0d00aa13b99afb95d9bb5e6 +.. _1: https://github.com/llvm/llvm-project/commit/3466e00716e12e32fdb100e3fcfca5c2b3e8d784 Clang dependencies for static linking tests =========================================== @@ -274,7 +274,7 @@ linked_vars, linked_maps, and linked_funcs tests depend on `Clang fix`__ to generate valid BTF information for weak variables. Please make sure you use Clang that contains the fix. -__ https://reviews.llvm.org/D100362 +__ https://github.com/llvm/llvm-project/commit/968292cb93198442138128d850fd54dc7edc0035 Clang relocation changes ======================== @@ -292,7 +292,7 @@ Here, ``type 2`` refers to new relocation type ``R_BPF_64_ABS64``. To fix this issue, user newer libbpf. .. Links -.. _clang reloc patch: https://reviews.llvm.org/D102712 +.. _clang reloc patch: https://github.com/llvm/llvm-project/commit/6a2ea84600ba4bd3b2733bd8f08f5115eb32164b .. _kernel llvm reloc: /Documentation/bpf/llvm_reloc.rst Clang dependencies for the u32 spill test (xdpwall) @@ -304,6 +304,6 @@ from running test_progs will look like: .. code-block:: console - test_xdpwall:FAIL:Does LLVM have https://reviews.llvm.org/D109073? unexpected error: -4007 + test_xdpwall:FAIL:Does LLVM have https://github.com/llvm/llvm-project/commit/ea72b0319d7b0f0c2fcf41d121afa5d031b319d5? unexpected error: -4007 -__ https://reviews.llvm.org/D109073 +__ https://github.com/llvm/llvm-project/commit/ea72b0319d7b0f0c2fcf41d121afa5d031b319d5 diff --git a/tools/testing/selftests/bpf/prog_tests/xdpwall.c b/tools/testing/selftests/bpf/prog_tests/xdpwall.c index f3927829a55a..4599154c8e9b 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdpwall.c +++ b/tools/testing/selftests/bpf/prog_tests/xdpwall.c @@ -9,7 +9,7 @@ void test_xdpwall(void) struct xdpwall *skel; skel = xdpwall__open_and_load(); - ASSERT_OK_PTR(skel, "Does LLMV have https://reviews.llvm.org/D109073?"); + ASSERT_OK_PTR(skel, "Does LLVM have https://github.com/llvm/llvm-project/commit/ea72b0319d7b0f0c2fcf41d121afa5d031b319d5?"); xdpwall__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_type_id.c b/tools/testing/selftests/bpf/progs/test_core_reloc_type_id.c index 22aba3f6e344..6fc8b9d66e34 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_type_id.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_type_id.c @@ -80,7 +80,7 @@ int test_core_type_id(void *ctx) * to detect whether this test has to be executed, however strange * that might look like. * - * [0] https://reviews.llvm.org/D85174 + * [0] https://github.com/llvm/llvm-project/commit/00602ee7ef0bf6c68d690a2bd729c12b95c95c99 */ #if __has_builtin(__builtin_preserve_type_info) struct core_reloc_type_id_output *out = (void *)&data.out; From 242d18514149d86b431b6f5db5a33579ea79ebad Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Mon, 8 Jan 2024 22:51:55 +0200 Subject: [PATCH 0191/2255] selftests/bpf: Fix the u64_offset_to_skb_data test The u64_offset_to_skb_data test is supposed to make a 64-bit fill, but instead makes a 16-bit one. Fix the test according to its intention and update the comments accordingly (umax is no longer 0xffff). The 16-bit fill is covered by u16_offset_to_skb_data. Signed-off-by: Maxim Mikityanskiy Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-2-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/verifier_spill_fill.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 39fe3372e0e0..848f2930f599 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -243,7 +243,7 @@ l0_%=: r0 = 0; \ SEC("tc") __description("Spill u32 const scalars. Refill as u64. Offset to skb->data") -__failure __msg("invalid access to packet") +__failure __msg("math between pkt pointer and register with unbounded min value is not allowed") __naked void u64_offset_to_skb_data(void) { asm volatile (" \ @@ -253,13 +253,11 @@ __naked void u64_offset_to_skb_data(void) w7 = 20; \ *(u32*)(r10 - 4) = r6; \ *(u32*)(r10 - 8) = r7; \ - r4 = *(u16*)(r10 - 8); \ + r4 = *(u64*)(r10 - 8); \ r0 = r2; \ - /* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=umax=65535 */\ + /* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4= */ \ r0 += r4; \ - /* if (r0 > r3) R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=umax=65535 */\ if r0 > r3 goto l0_%=; \ - /* r0 = *(u32 *)r2 R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=20 */\ r0 = *(u32*)(r2 + 0); \ l0_%=: r0 = 0; \ exit; \ From d5b892fd607abec2a1e49b6a2afc278c329a0ee2 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Mon, 8 Jan 2024 22:51:56 +0200 Subject: [PATCH 0192/2255] bpf: make infinite loop detection in is_state_visited() exact Current infinite loops detection mechanism is speculative: - first, states_maybe_looping() check is done which simply does memcmp for R1-R10 in current frame; - second, states_equal(..., exact=false) is called. With exact=false states_equal() would compare scalars for equality only if in old state scalar has precision mark. Such logic might be problematic if compiler makes some unlucky stack spill/fill decisions. An artificial example of a false positive looks as follows: r0 = ... unknown scalar ... r0 &= 0xff; *(u64 *)(r10 - 8) = r0; r0 = 0; loop: r0 = *(u64 *)(r10 - 8); if r0 > 10 goto exit_; r0 += 1; *(u64 *)(r10 - 8) = r0; r0 = 0; goto loop; This commit updates call to states_equal to use exact=true, forcing all scalar comparisons to be exact. Signed-off-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-3-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 27ad463b3bdd..7ae4fa0a2c0c 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17027,7 +17027,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) } /* attempt to detect infinite loop to avoid unnecessary doomed work */ if (states_maybe_looping(&sl->state, cur) && - states_equal(env, &sl->state, cur, false) && + states_equal(env, &sl->state, cur, true) && !iter_active_depths_differ(&sl->state, cur) && sl->state.callback_unroll_depth == cur->callback_unroll_depth) { verbose_linfo(env, insn_idx, "; "); From c035b3e555b5642f786fb2d089a6ddf7b00eb374 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Mon, 8 Jan 2024 22:51:57 +0200 Subject: [PATCH 0193/2255] selftests/bpf: check if imprecise stack spills confuse infinite loop detection Verify that infinite loop detection logic separates states with identical register states but different imprecise scalars spilled to stack. Signed-off-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-4-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_loops1.c | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_loops1.c b/tools/testing/selftests/bpf/progs/verifier_loops1.c index 71735dbf33d4..e07b43b78fd2 100644 --- a/tools/testing/selftests/bpf/progs/verifier_loops1.c +++ b/tools/testing/selftests/bpf/progs/verifier_loops1.c @@ -259,4 +259,28 @@ l0_%=: r2 += r1; \ " ::: __clobber_all); } +SEC("xdp") +__success +__naked void not_an_inifinite_loop(void) +{ + asm volatile (" \ + call %[bpf_get_prandom_u32]; \ + r0 &= 0xff; \ + *(u64 *)(r10 - 8) = r0; \ + r0 = 0; \ +loop_%=: \ + r0 = *(u64 *)(r10 - 8); \ + if r0 > 10 goto exit_%=; \ + r0 += 1; \ + *(u64 *)(r10 - 8) = r0; \ + r0 = 0; \ + goto loop_%=; \ +exit_%=: \ + r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; From 32f55dd4add4df1a5bc8febc1fafd3086290dbf6 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Mon, 8 Jan 2024 22:51:58 +0200 Subject: [PATCH 0194/2255] bpf: Make bpf_for_each_spilled_reg consider narrow spills Adjust the check in bpf_get_spilled_reg to take into account spilled registers narrower than 64 bits. That allows find_equal_scalars to properly adjust the range of all spilled registers that have the same ID. Before this change, it was possible for a register and a spilled register to have the same IDs but different ranges if the spill was narrower than 64 bits and a range check was performed on the register. Signed-off-by: Maxim Mikityanskiy Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-5-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index d07d857ca67f..e11baecbde68 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -453,7 +453,7 @@ struct bpf_verifier_state { #define bpf_get_spilled_reg(slot, frame, mask) \ (((slot < frame->allocated_stack / BPF_REG_SIZE) && \ - ((1 << frame->stack[slot].slot_type[0]) & (mask))) \ + ((1 << frame->stack[slot].slot_type[BPF_REG_SIZE - 1]) & (mask))) \ ? &frame->stack[slot].spilled_ptr : NULL) /* Iterate over 'frame', setting 'reg' to either NULL or a spilled register. */ From b827eee4c4d83ad92094b38d49cfec6844fb5863 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Mon, 8 Jan 2024 22:51:59 +0200 Subject: [PATCH 0195/2255] selftests/bpf: Add a test case for 32-bit spill tracking When a range check is performed on a register that was 32-bit spilled to the stack, the IDs of the two instances of the register are the same, so the range should also be the same. Signed-off-by: Maxim Mikityanskiy Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-6-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_spill_fill.c | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 848f2930f599..f303ac19cf41 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -735,4 +735,35 @@ __naked void stack_load_preserves_const_precision_subreg(void) : __clobber_common); } +SEC("xdp") +__description("32-bit spilled reg range should be tracked") +__success __retval(0) +__naked void spill_32bit_range_track(void) +{ + asm volatile(" \ + call %[bpf_ktime_get_ns]; \ + /* Make r0 bounded. */ \ + r0 &= 65535; \ + /* Assign an ID to r0. */ \ + r1 = r0; \ + /* 32-bit spill r0 to stack. */ \ + *(u32*)(r10 - 8) = r0; \ + /* Boundary check on r0. */ \ + if r0 < 1 goto l0_%=; \ + /* 32-bit fill r1 from stack. */ \ + r1 = *(u32*)(r10 - 8); \ + /* r1 == r0 => r1 >= 1 always. */ \ + if r1 >= 1 goto l0_%=; \ + /* Dead branch: the verifier should prune it. \ + * Do an invalid memory access if the verifier \ + * follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; From 8e0e074aafb8fec227363ed905ddd2ac7e4575e4 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Mon, 8 Jan 2024 22:52:00 +0200 Subject: [PATCH 0196/2255] bpf: Add the assign_scalar_id_before_mov function Extract the common code that generates a register ID for src_reg before MOV if needed into a new function. This function will also be used in a following commit. Signed-off-by: Maxim Mikityanskiy Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-7-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7ae4fa0a2c0c..8c4204f8fcc1 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4403,6 +4403,18 @@ static bool __is_pointer_value(bool allow_ptr_leaks, return reg->type != SCALAR_VALUE; } +static void assign_scalar_id_before_mov(struct bpf_verifier_env *env, + struct bpf_reg_state *src_reg) +{ + if (src_reg->type == SCALAR_VALUE && !src_reg->id && + !tnum_is_const(src_reg->var_off)) + /* Ensure that src_reg has a valid ID that will be copied to + * dst_reg and then will be used by find_equal_scalars() to + * propagate min/max range. + */ + src_reg->id = ++env->id_gen; +} + /* Copy src state preserving dst->parent and dst->live fields */ static void copy_register_state(struct bpf_reg_state *dst, const struct bpf_reg_state *src) { @@ -13905,20 +13917,13 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) if (BPF_SRC(insn->code) == BPF_X) { struct bpf_reg_state *src_reg = regs + insn->src_reg; struct bpf_reg_state *dst_reg = regs + insn->dst_reg; - bool need_id = src_reg->type == SCALAR_VALUE && !src_reg->id && - !tnum_is_const(src_reg->var_off); if (BPF_CLASS(insn->code) == BPF_ALU64) { if (insn->off == 0) { /* case: R1 = R2 * copy register state to dest reg */ - if (need_id) - /* Assign src and dst registers the same ID - * that will be used by find_equal_scalars() - * to propagate min/max range. - */ - src_reg->id = ++env->id_gen; + assign_scalar_id_before_mov(env, src_reg); copy_register_state(dst_reg, src_reg); dst_reg->live |= REG_LIVE_WRITTEN; dst_reg->subreg_def = DEF_NOT_SUBREG; @@ -13933,8 +13938,8 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) bool no_sext; no_sext = src_reg->umax_value < (1ULL << (insn->off - 1)); - if (no_sext && need_id) - src_reg->id = ++env->id_gen; + if (no_sext) + assign_scalar_id_before_mov(env, src_reg); copy_register_state(dst_reg, src_reg); if (!no_sext) dst_reg->id = 0; @@ -13956,8 +13961,8 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) if (insn->off == 0) { bool is_src_reg_u32 = src_reg->umax_value <= U32_MAX; - if (is_src_reg_u32 && need_id) - src_reg->id = ++env->id_gen; + if (is_src_reg_u32) + assign_scalar_id_before_mov(env, src_reg); copy_register_state(dst_reg, src_reg); /* Make sure ID is cleared if src_reg is not in u32 * range otherwise dst_reg min/max could be incorrectly @@ -13971,8 +13976,8 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) /* case: W1 = (s8, s16)W2 */ bool no_sext = src_reg->umax_value < (1ULL << (insn->off - 1)); - if (no_sext && need_id) - src_reg->id = ++env->id_gen; + if (no_sext) + assign_scalar_id_before_mov(env, src_reg); copy_register_state(dst_reg, src_reg); if (!no_sext) dst_reg->id = 0; From 87e51ac6cb19c5d33d70d4cae9e26d2a3a5fcba0 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Mon, 8 Jan 2024 22:52:01 +0200 Subject: [PATCH 0197/2255] bpf: Add the get_reg_width function Put calculation of the register value width into a dedicated function. This function will also be used in a following commit. Signed-off-by: Maxim Mikityanskiy Link: https://lore.kernel.org/r/20240108205209.838365-8-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8c4204f8fcc1..dfcbe011aff1 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4450,6 +4450,11 @@ static bool is_bpf_st_mem(struct bpf_insn *insn) return BPF_CLASS(insn->code) == BPF_ST && BPF_MODE(insn->code) == BPF_MEM; } +static int get_reg_width(struct bpf_reg_state *reg) +{ + return fls64(reg->umax_value); +} + /* check_stack_{read,write}_fixed_off functions track spill/fill of registers, * stack boundary and alignment are checked in check_mem_access() */ @@ -4502,7 +4507,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && env->bpf_capable) { save_register_state(env, state, spi, reg, size); /* Break the relation on a narrowing spill. */ - if (fls64(reg->umax_value) > BITS_PER_BYTE * size) + if (get_reg_width(reg) > BITS_PER_BYTE * size) state->stack[spi].spilled_ptr.id = 0; } else if (!reg && !(off % BPF_REG_SIZE) && is_bpf_st_mem(insn) && insn->imm != 0 && env->bpf_capable) { @@ -13959,7 +13964,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) return -EACCES; } else if (src_reg->type == SCALAR_VALUE) { if (insn->off == 0) { - bool is_src_reg_u32 = src_reg->umax_value <= U32_MAX; + bool is_src_reg_u32 = get_reg_width(src_reg) <= 32; if (is_src_reg_u32) assign_scalar_id_before_mov(env, src_reg); From 8ecfc371d829bfed75e0ef2cab45b2290b982f64 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Mon, 8 Jan 2024 22:52:02 +0200 Subject: [PATCH 0198/2255] bpf: Assign ID to scalars on spill Currently, when a scalar bounded register is spilled to the stack, its ID is preserved, but only if was already assigned, i.e. if this register was MOVed before. Assign an ID on spill if none is set, so that equal scalars could be tracked if a register is spilled to the stack and filled into another register. One test is adjusted to reflect the change in register IDs. Signed-off-by: Maxim Mikityanskiy Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-9-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 8 +++++++- .../selftests/bpf/progs/verifier_direct_packet_access.c | 2 +- tools/testing/selftests/bpf/verifier/precise.c | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index dfcbe011aff1..744fc9b778fe 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4505,9 +4505,15 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, mark_stack_slot_scratched(env, spi); if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && env->bpf_capable) { + bool reg_value_fits; + + reg_value_fits = get_reg_width(reg) <= BITS_PER_BYTE * size; + /* Make sure that reg had an ID to build a relation on spill. */ + if (reg_value_fits) + assign_scalar_id_before_mov(env, reg); save_register_state(env, state, spi, reg, size); /* Break the relation on a narrowing spill. */ - if (get_reg_width(reg) > BITS_PER_BYTE * size) + if (!reg_value_fits) state->stack[spi].spilled_ptr.id = 0; } else if (!reg && !(off % BPF_REG_SIZE) && is_bpf_st_mem(insn) && insn->imm != 0 && env->bpf_capable) { diff --git a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c index be95570ab382..28b602ac9cbe 100644 --- a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c +++ b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c @@ -568,7 +568,7 @@ l0_%=: r0 = 0; \ SEC("tc") __description("direct packet access: test23 (x += pkt_ptr, 4)") -__failure __msg("invalid access to packet, off=0 size=8, R5(id=2,off=0,r=0)") +__failure __msg("invalid access to packet, off=0 size=8, R5(id=3,off=0,r=0)") __flag(BPF_F_ANY_ALIGNMENT) __naked void test23_x_pkt_ptr_4(void) { diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 8a2ff81d8350..0a9293a57211 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -183,10 +183,10 @@ .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, .errstr = "mark_precise: frame0: last_idx 7 first_idx 7\ - mark_precise: frame0: parent state regs=r4 stack=:\ + mark_precise: frame0: parent state regs=r4 stack=-8:\ mark_precise: frame0: last_idx 6 first_idx 4\ - mark_precise: frame0: regs=r4 stack= before 6: (b7) r0 = -1\ - mark_precise: frame0: regs=r4 stack= before 5: (79) r4 = *(u64 *)(r10 -8)\ + mark_precise: frame0: regs=r4 stack=-8 before 6: (b7) r0 = -1\ + mark_precise: frame0: regs=r4 stack=-8 before 5: (79) r4 = *(u64 *)(r10 -8)\ mark_precise: frame0: regs= stack=-8 before 4: (7b) *(u64 *)(r3 -8) = r0\ mark_precise: frame0: parent state regs=r0 stack=:\ mark_precise: frame0: last_idx 3 first_idx 3\ From 3893f0b6a0698aeeb3d27cb22baef7c4ca1a07f1 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Mon, 8 Jan 2024 22:52:03 +0200 Subject: [PATCH 0199/2255] selftests/bpf: Test assigning ID to scalars on spill The previous commit implemented assigning IDs to registers holding scalars before spill. Add the test cases to check the new functionality. Signed-off-by: Maxim Mikityanskiy Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240108205209.838365-10-maxtram95@gmail.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_spill_fill.c | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index f303ac19cf41..b05aab925ee5 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -766,4 +766,137 @@ l0_%=: r0 = 0; \ : __clobber_all); } +SEC("xdp") +__description("64-bit spill of 64-bit reg should assign ID") +__success __retval(0) +__naked void spill_64bit_of_64bit_ok(void) +{ + asm volatile (" \ + /* Roll one bit to make the register inexact. */\ + call %[bpf_get_prandom_u32]; \ + r0 &= 0x80000000; \ + r0 <<= 32; \ + /* 64-bit spill r0 to stack - should assign an ID. */\ + *(u64*)(r10 - 8) = r0; \ + /* 64-bit fill r1 from stack - should preserve the ID. */\ + r1 = *(u64*)(r10 - 8); \ + /* Compare r1 with another register to trigger find_equal_scalars.\ + * Having one random bit is important here, otherwise the verifier cuts\ + * the corners. \ + */ \ + r2 = 0; \ + if r1 != r2 goto l0_%=; \ + /* The result of this comparison is predefined. */\ + if r0 == r2 goto l0_%=; \ + /* Dead branch: the verifier should prune it. Do an invalid memory\ + * access if the verifier follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ + exit; \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +SEC("xdp") +__description("32-bit spill of 32-bit reg should assign ID") +__success __retval(0) +__naked void spill_32bit_of_32bit_ok(void) +{ + asm volatile (" \ + /* Roll one bit to make the register inexact. */\ + call %[bpf_get_prandom_u32]; \ + w0 &= 0x80000000; \ + /* 32-bit spill r0 to stack - should assign an ID. */\ + *(u32*)(r10 - 8) = r0; \ + /* 32-bit fill r1 from stack - should preserve the ID. */\ + r1 = *(u32*)(r10 - 8); \ + /* Compare r1 with another register to trigger find_equal_scalars.\ + * Having one random bit is important here, otherwise the verifier cuts\ + * the corners. \ + */ \ + r2 = 0; \ + if r1 != r2 goto l0_%=; \ + /* The result of this comparison is predefined. */\ + if r0 == r2 goto l0_%=; \ + /* Dead branch: the verifier should prune it. Do an invalid memory\ + * access if the verifier follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ + exit; \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +SEC("xdp") +__description("16-bit spill of 16-bit reg should assign ID") +__success __retval(0) +__naked void spill_16bit_of_16bit_ok(void) +{ + asm volatile (" \ + /* Roll one bit to make the register inexact. */\ + call %[bpf_get_prandom_u32]; \ + r0 &= 0x8000; \ + /* 16-bit spill r0 to stack - should assign an ID. */\ + *(u16*)(r10 - 8) = r0; \ + /* 16-bit fill r1 from stack - should preserve the ID. */\ + r1 = *(u16*)(r10 - 8); \ + /* Compare r1 with another register to trigger find_equal_scalars.\ + * Having one random bit is important here, otherwise the verifier cuts\ + * the corners. \ + */ \ + r2 = 0; \ + if r1 != r2 goto l0_%=; \ + /* The result of this comparison is predefined. */\ + if r0 == r2 goto l0_%=; \ + /* Dead branch: the verifier should prune it. Do an invalid memory\ + * access if the verifier follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ + exit; \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +SEC("xdp") +__description("8-bit spill of 8-bit reg should assign ID") +__success __retval(0) +__naked void spill_8bit_of_8bit_ok(void) +{ + asm volatile (" \ + /* Roll one bit to make the register inexact. */\ + call %[bpf_get_prandom_u32]; \ + r0 &= 0x80; \ + /* 8-bit spill r0 to stack - should assign an ID. */\ + *(u8*)(r10 - 8) = r0; \ + /* 8-bit fill r1 from stack - should preserve the ID. */\ + r1 = *(u8*)(r10 - 8); \ + /* Compare r1 with another register to trigger find_equal_scalars.\ + * Having one random bit is important here, otherwise the verifier cuts\ + * the corners. \ + */ \ + r2 = 0; \ + if r1 != r2 goto l0_%=; \ + /* The result of this comparison is predefined. */\ + if r0 == r2 goto l0_%=; \ + /* Dead branch: the verifier should prune it. Do an invalid memory\ + * access if the verifier follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ + exit; \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; From 9a4c57f52b5e0de3a6b1f40c5b656730ce33ee01 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 9 Jan 2024 21:13:48 -0800 Subject: [PATCH 0200/2255] bpf: Track aligned st store as imprecise spilled registers With patch set [1], precision backtracing supports register spill/fill to/from the stack. The patch [2] allows initial imprecise register spill with content 0. This is a common case for cpuv3 and lower for initializing the stack variables with pattern r1 = 0 *(u64 *)(r10 - 8) = r1 and the [2] has demonstrated good verification improvement. For cpuv4, the initialization could be *(u64 *)(r10 - 8) = 0 The current verifier marks the r10-8 contents with STACK_ZERO. Similar to [2], let us permit the above insn to behave like imprecise register spill which can reduce number of verified states. The change is in function check_stack_write_fixed_off(). Before this patch, spilled zero will be marked as STACK_ZERO which can provide precise values. In check_stack_write_var_off(), STACK_ZERO will be maintained if writing a const zero so later it can provide precise values if needed. The above handling of '*(u64 *)(r10 - 8) = 0' as a spill will have issues in check_stack_write_var_off() as the spill will be converted to STACK_MISC and the precise value 0 is lost. To fix this issue, if the spill slots with const zero and the BPF_ST write also with const zero, the spill slots are preserved, which can later provide precise values if needed. Without the change in check_stack_write_var_off(), the test_verifier subtest 'BPF_ST_MEM stack imm zero, variable offset' will fail. I checked cpuv3 and cpuv4 with and without this patch with veristat. There is no state change for cpuv3 since '*(u64 *)(r10 - 8) = 0' is only generated with cpuv4. For cpuv4: $ ../veristat -C old.cpuv4.csv new.cpuv4.csv -e file,prog,insns,states -f 'insns_diff!=0' File Program Insns (A) Insns (B) Insns (DIFF) States (A) States (B) States (DIFF) ------------------------------------------ ------------------- --------- --------- --------------- ---------- ---------- ------------- local_storage_bench.bpf.linked3.o get_local 228 168 -60 (-26.32%) 17 14 -3 (-17.65%) pyperf600_bpf_loop.bpf.linked3.o on_event 6066 4889 -1177 (-19.40%) 403 321 -82 (-20.35%) test_cls_redirect.bpf.linked3.o cls_redirect 35483 35387 -96 (-0.27%) 2179 2177 -2 (-0.09%) test_l4lb_noinline.bpf.linked3.o balancer_ingress 4494 4522 +28 (+0.62%) 217 219 +2 (+0.92%) test_l4lb_noinline_dynptr.bpf.linked3.o balancer_ingress 1432 1455 +23 (+1.61%) 92 94 +2 (+2.17%) test_xdp_noinline.bpf.linked3.o balancer_ingress_v6 3462 3458 -4 (-0.12%) 216 216 +0 (+0.00%) verifier_iterating_callbacks.bpf.linked3.o widening 52 41 -11 (-21.15%) 4 3 -1 (-25.00%) xdp_synproxy_kern.bpf.linked3.o syncookie_tc 12412 11719 -693 (-5.58%) 345 330 -15 (-4.35%) xdp_synproxy_kern.bpf.linked3.o syncookie_xdp 12478 11794 -684 (-5.48%) 346 331 -15 (-4.34%) test_l4lb_noinline and test_l4lb_noinline_dynptr has minor regression, but pyperf600_bpf_loop and local_storage_bench gets pretty good improvement. [1] https://lore.kernel.org/all/20231205184248.1502704-1-andrii@kernel.org/ [2] https://lore.kernel.org/all/20231205184248.1502704-9-andrii@kernel.org/ Cc: Kuniyuki Iwashima Cc: Martin KaFai Lau Signed-off-by: Yonghong Song Tested-by: Kuniyuki Iwashima Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240110051348.2737007-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 17 +++++++++++++++-- .../selftests/bpf/progs/verifier_spill_fill.c | 16 ++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 744fc9b778fe..bd1da0d3ebce 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4516,7 +4516,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, if (!reg_value_fits) state->stack[spi].spilled_ptr.id = 0; } else if (!reg && !(off % BPF_REG_SIZE) && is_bpf_st_mem(insn) && - insn->imm != 0 && env->bpf_capable) { + env->bpf_capable) { struct bpf_reg_state fake_reg = {}; __mark_reg_known(&fake_reg, insn->imm); @@ -4663,7 +4663,20 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env, return -EINVAL; } - /* Erase all spilled pointers. */ + /* If writing_zero and the spi slot contains a spill of value 0, + * maintain the spill type. + */ + if (writing_zero && *stype == STACK_SPILL && + is_spilled_scalar_reg(&state->stack[spi])) { + struct bpf_reg_state *spill_reg = &state->stack[spi].spilled_ptr; + + if (tnum_is_const(spill_reg->var_off) && spill_reg->var_off.value == 0) { + zero_used = true; + continue; + } + } + + /* Erase all other spilled pointers. */ state->stack[spi].spilled_ptr.type = NOT_INIT; /* Update the slot type. */ diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index b05aab925ee5..e38f29e73be7 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -493,14 +493,14 @@ char single_byte_buf[1] SEC(".data.single_byte_buf"); SEC("raw_tp") __log_level(2) __success -/* make sure fp-8 is all STACK_ZERO */ -__msg("2: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8_w=00000000") +/* fp-8 is spilled IMPRECISE value zero (represented by a zero value fake reg) */ +__msg("2: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8_w=0") /* but fp-16 is spilled IMPRECISE zero const reg */ __msg("4: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=0 R10=fp0 fp-16_w=0") -/* validate that assigning R2 from STACK_ZERO doesn't mark register +/* validate that assigning R2 from STACK_SPILL with zero value doesn't mark register * precise immediately; if necessary, it will be marked precise later */ -__msg("6: (71) r2 = *(u8 *)(r10 -1) ; R2_w=0 R10=fp0 fp-8_w=00000000") +__msg("6: (71) r2 = *(u8 *)(r10 -1) ; R2_w=0 R10=fp0 fp-8_w=0") /* similarly, when R2 is assigned from spilled register, it is initially * imprecise, but will be marked precise later once it is used in precise context */ @@ -518,14 +518,14 @@ __msg("mark_precise: frame0: regs=r0 stack= before 3: (b7) r0 = 0") __naked void partial_stack_load_preserves_zeros(void) { asm volatile ( - /* fp-8 is all STACK_ZERO */ + /* fp-8 is value zero (represented by a zero value fake reg) */ ".8byte %[fp8_st_zero];" /* LLVM-18+: *(u64 *)(r10 -8) = 0; */ /* fp-16 is const zero register */ "r0 = 0;" "*(u64 *)(r10 -16) = r0;" - /* load single U8 from non-aligned STACK_ZERO slot */ + /* load single U8 from non-aligned spilled value zero slot */ "r1 = %[single_byte_buf];" "r2 = *(u8 *)(r10 -1);" "r1 += r2;" @@ -537,7 +537,7 @@ __naked void partial_stack_load_preserves_zeros(void) "r1 += r2;" "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ - /* load single U16 from non-aligned STACK_ZERO slot */ + /* load single U16 from non-aligned spilled value zero slot */ "r1 = %[single_byte_buf];" "r2 = *(u16 *)(r10 -2);" "r1 += r2;" @@ -549,7 +549,7 @@ __naked void partial_stack_load_preserves_zeros(void) "r1 += r2;" "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ - /* load single U32 from non-aligned STACK_ZERO slot */ + /* load single U32 from non-aligned spilled value zero slot */ "r1 = %[single_byte_buf];" "r2 = *(u32 *)(r10 -4);" "r1 += r2;" From 6ae99ac8b7da30c9fdb15e380624dbc41f8200c8 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 9 Jan 2024 21:13:55 -0800 Subject: [PATCH 0201/2255] selftests/bpf: Add a selftest with not-8-byte aligned BPF_ST Add a selftest with a 4 bytes BPF_ST of 0 where the store is not 8-byte aligned. The goal is to ensure that STACK_ZERO is properly marked in stack slots and the STACK_ZERO value can propagate properly during the load. Acked-by: Andrii Nakryiko Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20240110051355.2737232-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/verifier_spill_fill.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index e38f29e73be7..7013a9694163 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -581,6 +581,47 @@ __naked void partial_stack_load_preserves_zeros(void) : __clobber_common); } +SEC("raw_tp") +__log_level(2) +__success +/* fp-4 is STACK_ZERO */ +__msg("2: (62) *(u32 *)(r10 -4) = 0 ; R10=fp0 fp-8=0000????") +__msg("4: (71) r2 = *(u8 *)(r10 -1) ; R2_w=0 R10=fp0 fp-8=0000????") +__msg("5: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 4: (71) r2 = *(u8 *)(r10 -1)") +__naked void partial_stack_load_preserves_partial_zeros(void) +{ + asm volatile ( + /* fp-4 is value zero */ + ".8byte %[fp4_st_zero];" /* LLVM-18+: *(u32 *)(r10 -4) = 0; */ + + /* load single U8 from non-aligned stack zero slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u8 *)(r10 -1);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U16 from non-aligned stack zero slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u16 *)(r10 -2);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U32 from non-aligned stack zero slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u32 *)(r10 -4);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + "r0 = 0;" + "exit;" + : + : __imm_ptr(single_byte_buf), + __imm_insn(fp4_st_zero, BPF_ST_MEM(BPF_W, BPF_REG_FP, -4, 0)) + : __clobber_common); +} + char two_byte_buf[2] SEC(".data.two_byte_buf"); SEC("raw_tp") From 88031b929c01fe3686d34a848c413c2e51e6a7c8 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 10 Jan 2024 21:21:36 -0800 Subject: [PATCH 0202/2255] docs/bpf: Fix an incorrect statement in verifier.rst In verifier.rst, I found an incorrect statement (maybe a typo) in section 'Liveness marks tracking'. Basically, the wrong register is attributed to have a read mark. This may confuse the user. Signed-off-by: Yonghong Song Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240111052136.3440417-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov --- Documentation/bpf/verifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/bpf/verifier.rst b/Documentation/bpf/verifier.rst index f0ec19db301c..356894399fbf 100644 --- a/Documentation/bpf/verifier.rst +++ b/Documentation/bpf/verifier.rst @@ -562,7 +562,7 @@ works:: * ``checkpoint[0].r1`` is marked as read; * At instruction #5 exit is reached and ``checkpoint[0]`` can now be processed - by ``clean_live_states()``. After this processing ``checkpoint[0].r0`` has a + by ``clean_live_states()``. After this processing ``checkpoint[0].r1`` has a read mark and all other registers and stack slots are marked as ``NOT_INIT`` or ``STACK_INVALID`` From 49c06547d5218b54fbcc6011864b8c8e3aa0b565 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Fri, 12 Jan 2024 14:01:34 -0800 Subject: [PATCH 0203/2255] bpf: Minor improvements for bpf_cmp. Few minor improvements for bpf_cmp() macro: . reduce number of args in __bpf_cmp() . rename NOFLIP to UNLIKELY . add a comment about 64-bit truncation in "i" constraint . use "ri" constraint for sizeof(rhs) <= 4 . improve error message for bpf_cmp_likely() Before: progs/iters_task_vma.c:31:7: error: variable 'ret' is uninitialized when used here [-Werror,-Wuninitialized] 31 | if (bpf_cmp_likely(seen, <==, 1000)) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../bpf/bpf_experimental.h:325:3: note: expanded from macro 'bpf_cmp_likely' 325 | ret; | ^~~ progs/iters_task_vma.c:31:7: note: variable 'ret' is declared here ../bpf/bpf_experimental.h:310:3: note: expanded from macro 'bpf_cmp_likely' 310 | bool ret; | ^ After: progs/iters_task_vma.c:31:7: error: invalid operand for instruction 31 | if (bpf_cmp_likely(seen, <==, 1000)) | ^ ../bpf/bpf_experimental.h:324:17: note: expanded from macro 'bpf_cmp_likely' 324 | asm volatile("r0 " #OP " invalid compare"); | ^ :1:5: note: instantiated into assembly here 1 | r0 <== invalid compare | ^ Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240112220134.71209-1-alexei.starovoitov@gmail.com Signed-off-by: Alexei Starovoitov --- .../testing/selftests/bpf/bpf_experimental.h | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h index f44875f8b367..0d749006d107 100644 --- a/tools/testing/selftests/bpf/bpf_experimental.h +++ b/tools/testing/selftests/bpf/bpf_experimental.h @@ -260,11 +260,11 @@ extern void bpf_throw(u64 cookie) __ksym; #define __is_signed_type(type) (((type)(-1)) < (type)1) -#define __bpf_cmp(LHS, OP, SIGN, PRED, RHS, DEFAULT) \ +#define __bpf_cmp(LHS, OP, PRED, RHS, DEFAULT) \ ({ \ __label__ l_true; \ bool ret = DEFAULT; \ - asm volatile goto("if %[lhs] " SIGN #OP " %[rhs] goto %l[l_true]" \ + asm volatile goto("if %[lhs] " OP " %[rhs] goto %l[l_true]" \ :: [lhs] "r"((short)LHS), [rhs] PRED (RHS) :: l_true); \ ret = !DEFAULT; \ l_true: \ @@ -276,7 +276,7 @@ l_true: \ * __lhs OP __rhs below will catch the mistake. * Be aware that we check only __lhs to figure out the sign of compare. */ -#define _bpf_cmp(LHS, OP, RHS, NOFLIP) \ +#define _bpf_cmp(LHS, OP, RHS, UNLIKELY) \ ({ \ typeof(LHS) __lhs = (LHS); \ typeof(RHS) __rhs = (RHS); \ @@ -285,14 +285,17 @@ l_true: \ (void)(__lhs OP __rhs); \ if (__cmp_cannot_be_signed(OP) || !__is_signed_type(typeof(__lhs))) { \ if (sizeof(__rhs) == 8) \ - ret = __bpf_cmp(__lhs, OP, "", "r", __rhs, NOFLIP); \ + /* "i" will truncate 64-bit constant into s32, \ + * so we have to use extra register via "r". \ + */ \ + ret = __bpf_cmp(__lhs, #OP, "r", __rhs, UNLIKELY); \ else \ - ret = __bpf_cmp(__lhs, OP, "", "i", __rhs, NOFLIP); \ + ret = __bpf_cmp(__lhs, #OP, "ri", __rhs, UNLIKELY); \ } else { \ if (sizeof(__rhs) == 8) \ - ret = __bpf_cmp(__lhs, OP, "s", "r", __rhs, NOFLIP); \ + ret = __bpf_cmp(__lhs, "s"#OP, "r", __rhs, UNLIKELY); \ else \ - ret = __bpf_cmp(__lhs, OP, "s", "i", __rhs, NOFLIP); \ + ret = __bpf_cmp(__lhs, "s"#OP, "ri", __rhs, UNLIKELY); \ } \ ret; \ }) @@ -304,7 +307,7 @@ l_true: \ #ifndef bpf_cmp_likely #define bpf_cmp_likely(LHS, OP, RHS) \ ({ \ - bool ret; \ + bool ret = 0; \ if (__builtin_strcmp(#OP, "==") == 0) \ ret = _bpf_cmp(LHS, !=, RHS, false); \ else if (__builtin_strcmp(#OP, "!=") == 0) \ @@ -318,7 +321,7 @@ l_true: \ else if (__builtin_strcmp(#OP, ">=") == 0) \ ret = _bpf_cmp(LHS, <, RHS, false); \ else \ - (void) "bug"; \ + asm volatile("r0 " #OP " invalid compare"); \ ret; \ }) #endif From b18afb6f42292a9154102fed7265ae747bbfbc57 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 15 Jan 2024 12:55:09 -0800 Subject: [PATCH 0204/2255] tcp: Move tcp_ns_to_ts() to tcp.h We will support arbitrary SYN Cookie with BPF. When BPF prog validates ACK and kfunc allocates a reqsk, we need to call tcp_ns_to_ts() to calculate an offset of TSval for later use: time t0 : Send SYN+ACK -> tsval = Initial TSval (Random Number) t1 : Recv ACK of 3WHS -> tsoff = TSecr - tcp_ns_to_ts(usec_ts_ok, tcp_clock_ns()) = Initial TSval - t1 t2 : Send ACK -> tsval = t2 + tsoff = Initial TSval + (t2 - t1) = Initial TSval + Time Delta (x) (x) Note that the time delta does not include the initial RTT from t0 to t1. Let's move tcp_ns_to_ts() to tcp.h. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20240115205514.68364-2-kuniyu@amazon.com Signed-off-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- include/net/tcp.h | 9 +++++++++ net/ipv4/syncookies.c | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index dd78a1181031..114000e71a46 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -577,6 +577,15 @@ static inline u32 tcp_cookie_time(void) return val; } +/* Convert one nsec 64bit timestamp to ts (ms or usec resolution) */ +static inline u64 tcp_ns_to_ts(bool usec_ts, u64 val) +{ + if (usec_ts) + return div_u64(val, NSEC_PER_USEC); + + return div_u64(val, NSEC_PER_MSEC); +} + u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, u16 *mssp); __u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 61f1c96cfe63..981944c22820 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -51,15 +51,6 @@ static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, count, &syncookie_secret[c]); } -/* Convert one nsec 64bit timestamp to ts (ms or usec resolution) */ -static u64 tcp_ns_to_ts(bool usec_ts, u64 val) -{ - if (usec_ts) - return div_u64(val, NSEC_PER_USEC); - - return div_u64(val, NSEC_PER_MSEC); -} - /* * when syncookies are in effect and tcp timestamps are enabled we encode * tcp options in the lower bits of the timestamp value that will be From f5f30386c78105cba520e443a6a9ee945ec1d066 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 16 Jan 2024 14:19:20 +0800 Subject: [PATCH 0205/2255] bpftool: Silence build warning about calloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There exists the following warning when building bpftool: CC prog.o prog.c: In function ‘profile_open_perf_events’: prog.c:2301:24: warning: ‘calloc’ sizes specified with ‘sizeof’ in the earlier argument and not in the later argument [-Wcalloc-transposed-args] 2301 | sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); | ^~~ prog.c:2301:24: note: earlier argument should specify number of elements, later size of each element Tested with the latest upstream GCC which contains a new warning option -Wcalloc-transposed-args. The first argument to calloc is documented to be number of elements in array, while the second argument is size of each element, just switch the first and second arguments of calloc() to silence the build warning, compile tested only. Fixes: 47c09d6a9f67 ("bpftool: Introduce "prog profile" command") Signed-off-by: Tiezhu Yang Signed-off-by: Daniel Borkmann Reviewed-by: Quentin Monnet Link: https://lore.kernel.org/bpf/20240116061920.31172-1-yangtiezhu@loongson.cn Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/prog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index feb8e305804f..9cb42a3366c0 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -2298,7 +2298,7 @@ static int profile_open_perf_events(struct profiler_bpf *obj) int map_fd; profile_perf_events = calloc( - sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); + obj->rodata->num_cpu * obj->rodata->num_metric, sizeof(int)); if (!profile_perf_events) { p_err("failed to allocate memory for perf_event array: %s", strerror(errno)); From 95e752b5299fa8c90099f7bc2aa1ee3e2e2c95ab Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 15 Jan 2024 12:55:10 -0800 Subject: [PATCH 0206/2255] tcp: Move skb_steal_sock() to request_sock.h We will support arbitrary SYN Cookie with BPF. If BPF prog validates ACK and kfunc allocates a reqsk, it will be carried to TCP stack as skb->sk with req->syncookie 1. In skb_steal_sock(), we need to check inet_reqsk(sk)->syncookie to see if the reqsk is created by kfunc. However, inet_reqsk() is not available in sock.h. Let's move skb_steal_sock() to request_sock.h. While at it, we refactor skb_steal_sock() so it returns early if skb->sk is NULL to minimise the following patch. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20240115205514.68364-3-kuniyu@amazon.com Signed-off-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- include/net/request_sock.h | 28 ++++++++++++++++++++++++++++ include/net/sock.h | 25 ------------------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 144c39db9898..26c630c40abb 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -83,6 +83,34 @@ static inline struct sock *req_to_sk(struct request_sock *req) return (struct sock *)req; } +/** + * skb_steal_sock - steal a socket from an sk_buff + * @skb: sk_buff to steal the socket from + * @refcounted: is set to true if the socket is reference-counted + * @prefetched: is set to true if the socket was assigned from bpf + */ +static inline struct sock *skb_steal_sock(struct sk_buff *skb, + bool *refcounted, bool *prefetched) +{ + struct sock *sk = skb->sk; + + if (!sk) { + *prefetched = false; + *refcounted = false; + return NULL; + } + + *prefetched = skb_sk_is_prefetched(skb); + if (*prefetched) + *refcounted = sk_is_refcounted(sk); + else + *refcounted = true; + + skb->destructor = NULL; + skb->sk = NULL; + return sk; +} + static inline struct request_sock * reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener, bool attach_listener) diff --git a/include/net/sock.h b/include/net/sock.h index a7f815c7cfdf..32a399fdcbb5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2814,31 +2814,6 @@ sk_is_refcounted(struct sock *sk) return !sk_fullsock(sk) || !sock_flag(sk, SOCK_RCU_FREE); } -/** - * skb_steal_sock - steal a socket from an sk_buff - * @skb: sk_buff to steal the socket from - * @refcounted: is set to true if the socket is reference-counted - * @prefetched: is set to true if the socket was assigned from bpf - */ -static inline struct sock * -skb_steal_sock(struct sk_buff *skb, bool *refcounted, bool *prefetched) -{ - if (skb->sk) { - struct sock *sk = skb->sk; - - *refcounted = true; - *prefetched = skb_sk_is_prefetched(skb); - if (*prefetched) - *refcounted = sk_is_refcounted(sk); - skb->destructor = NULL; - skb->sk = NULL; - return sk; - } - *prefetched = false; - *refcounted = false; - return NULL; -} - /* Checks if this SKB belongs to an HW offloaded socket * and whether any SW fallbacks are required based on dev. * Check decrypted mark in case skb_orphan() cleared socket. From d177c1be06ce28aa8c8710ac55be1b5ad3f314c6 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Wed, 10 Jan 2024 09:57:37 +0100 Subject: [PATCH 0207/2255] selftests/bpf: Fix potential premature unload in bpf_testmod It is possible for bpf_kfunc_call_test_release() to be called from bpf_map_free_deferred() when bpf_testmod is already unloaded and perf_test_stuct.cnt which it tries to decrease is no longer in memory. This patch tries to fix the issue by waiting for all references to be dropped in bpf_testmod_exit(). The issue can be triggered by running 'test_progs -t map_kptr' in 6.5, but is obscured in 6.6 by d119357d07435 ("rcu-tasks: Treat only synchronous grace periods urgently"). Fixes: 65eb006d85a2 ("bpf: Move kernel test kfuncs to bpf_testmod") Signed-off-by: Artem Savkov Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Cc: Jiri Olsa Link: https://lore.kernel.org/bpf/82f55c0e-0ec8-4fe1-8d8c-b1de07558ad9@linux.dev Link: https://lore.kernel.org/bpf/20240110085737.8895-1-asavkov@redhat.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 91907b321f91..e7c9e1c7fde0 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -2,6 +2,7 @@ /* Copyright (c) 2020 Facebook */ #include #include +#include #include #include #include @@ -544,6 +545,14 @@ static int bpf_testmod_init(void) static void bpf_testmod_exit(void) { + /* Need to wait for all references to be dropped because + * bpf_kfunc_call_test_release() which currently resides in kernel can + * be called after bpf_testmod is unloaded. Once release function is + * moved into the module this wait can be removed. + */ + while (refcount_read(&prog_test_struct.cnt) > 1) + msleep(20); + return sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file); } From 8b5ac68fb5ee416537c1214cbacf0ddc4293cce9 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 15 Jan 2024 12:55:11 -0800 Subject: [PATCH 0208/2255] bpf: tcp: Handle BPF SYN Cookie in skb_steal_sock(). We will support arbitrary SYN Cookie with BPF. If BPF prog validates ACK and kfunc allocates a reqsk, it will be carried to TCP stack as skb->sk with req->syncookie 1. Also, the reqsk has its listener as req->rsk_listener with no refcnt taken. When the TCP stack looks up a socket from the skb, we steal inet_reqsk(skb->sk)->rsk_listener in skb_steal_sock() so that the skb will be processed in cookie_v[46]_check() with the listener. Note that we do not clear skb->sk and skb->destructor so that we can carry the reqsk to cookie_v[46]_check(). Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240115205514.68364-4-kuniyu@amazon.com Signed-off-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- include/net/request_sock.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 26c630c40abb..8839133d6f6b 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -101,10 +101,21 @@ static inline struct sock *skb_steal_sock(struct sk_buff *skb, } *prefetched = skb_sk_is_prefetched(skb); - if (*prefetched) + if (*prefetched) { +#if IS_ENABLED(CONFIG_SYN_COOKIES) + if (sk->sk_state == TCP_NEW_SYN_RECV && inet_reqsk(sk)->syncookie) { + struct request_sock *req = inet_reqsk(sk); + + *refcounted = false; + sk = req->rsk_listener; + req->rsk_listener = NULL; + return sk; + } +#endif *refcounted = sk_is_refcounted(sk); - else + } else { *refcounted = true; + } skb->destructor = NULL; skb->sk = NULL; From 695751e31a63efd2bbe6779873adf1e4deb00cd5 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 15 Jan 2024 12:55:12 -0800 Subject: [PATCH 0209/2255] bpf: tcp: Handle BPF SYN Cookie in cookie_v[46]_check(). We will support arbitrary SYN Cookie with BPF in the following patch. If BPF prog validates ACK and kfunc allocates a reqsk, it will be carried to cookie_[46]_check() as skb->sk. If skb->sk is not NULL, we call cookie_bpf_check(). Then, we clear skb->sk and skb->destructor, which are needed not to hold refcnt for reqsk and the listener. See the following patch for details. After that, we finish initialisation for the remaining fields with cookie_tcp_reqsk_init(). Note that the server side WScale is set only for non-BPF SYN Cookie. Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240115205514.68364-5-kuniyu@amazon.com Signed-off-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- include/net/tcp.h | 20 ++++++++++++++++++++ net/ipv4/syncookies.c | 31 +++++++++++++++++++++++++++---- net/ipv6/syncookies.c | 13 +++++++++---- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 114000e71a46..dfe99a084a71 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -599,6 +599,26 @@ static inline bool cookie_ecn_ok(const struct net *net, const struct dst_entry * dst_feature(dst, RTAX_FEATURE_ECN); } +#if IS_ENABLED(CONFIG_BPF) +static inline bool cookie_bpf_ok(struct sk_buff *skb) +{ + return skb->sk; +} + +struct request_sock *cookie_bpf_check(struct sock *sk, struct sk_buff *skb); +#else +static inline bool cookie_bpf_ok(struct sk_buff *skb) +{ + return false; +} + +static inline struct request_sock *cookie_bpf_check(struct net *net, struct sock *sk, + struct sk_buff *skb) +{ + return NULL; +} +#endif + /* From net/ipv6/syncookies.c */ int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th); struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 981944c22820..be88bf586ff9 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -295,6 +295,24 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb, return 0; } +#if IS_ENABLED(CONFIG_BPF) +struct request_sock *cookie_bpf_check(struct sock *sk, struct sk_buff *skb) +{ + struct request_sock *req = inet_reqsk(skb->sk); + + skb->sk = NULL; + skb->destructor = NULL; + + if (cookie_tcp_reqsk_init(sk, skb, req)) { + reqsk_free(req); + req = NULL; + } + + return req; +} +EXPORT_SYMBOL_GPL(cookie_bpf_check); +#endif + struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk, struct sk_buff *skb, struct tcp_options_received *tcp_opt, @@ -395,9 +413,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) !th->ack || th->rst) goto out; - req = cookie_tcp_check(net, sk, skb); - if (IS_ERR(req)) - goto out; + if (cookie_bpf_ok(skb)) { + req = cookie_bpf_check(sk, skb); + } else { + req = cookie_tcp_check(net, sk, skb); + if (IS_ERR(req)) + goto out; + } if (!req) goto out_drop; @@ -445,7 +467,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->wscale_ok, &rcv_wscale, dst_metric(&rt->dst, RTAX_INITRWND)); - ireq->rcv_wscale = rcv_wscale; + if (!req->syncookie) + ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok &= cookie_ecn_ok(net, &rt->dst); ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst); diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index c8d2ca27220c..6b9c69278819 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -182,9 +182,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) !th->ack || th->rst) goto out; - req = cookie_tcp_check(net, sk, skb); - if (IS_ERR(req)) - goto out; + if (cookie_bpf_ok(skb)) { + req = cookie_bpf_check(sk, skb); + } else { + req = cookie_tcp_check(net, sk, skb); + if (IS_ERR(req)) + goto out; + } if (!req) goto out_drop; @@ -247,7 +251,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq->wscale_ok, &rcv_wscale, dst_metric(dst, RTAX_INITRWND)); - ireq->rcv_wscale = rcv_wscale; + if (!req->syncookie) + ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok &= cookie_ecn_ok(net, dst); ret = tcp_get_cookie_sock(sk, skb, req, dst); From e472f88891abbc535a5e16a68a104073985f6061 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 15 Jan 2024 12:55:13 -0800 Subject: [PATCH 0210/2255] bpf: tcp: Support arbitrary SYN Cookie. This patch adds a new kfunc available at TC hook to support arbitrary SYN Cookie. The basic usage is as follows: struct bpf_tcp_req_attrs attrs = { .mss = mss, .wscale_ok = wscale_ok, .rcv_wscale = rcv_wscale, /* Server's WScale < 15 */ .snd_wscale = snd_wscale, /* Client's WScale < 15 */ .tstamp_ok = tstamp_ok, .rcv_tsval = tsval, .rcv_tsecr = tsecr, /* Server's Initial TSval */ .usec_ts_ok = usec_ts_ok, .sack_ok = sack_ok, .ecn_ok = ecn_ok, } skc = bpf_skc_lookup_tcp(...); sk = (struct sock *)bpf_skc_to_tcp_sock(skc); bpf_sk_assign_tcp_reqsk(skb, sk, attrs, sizeof(attrs)); bpf_sk_release(skc); bpf_sk_assign_tcp_reqsk() takes skb, a listener sk, and struct bpf_tcp_req_attrs and allocates reqsk and configures it. Then, bpf_sk_assign_tcp_reqsk() links reqsk with skb and the listener. The notable thing here is that we do not hold refcnt for both reqsk and listener. To differentiate that, we mark reqsk->syncookie, which is only used in TX for now. So, if reqsk->syncookie is 1 in RX, it means that the reqsk is allocated by kfunc. When skb is freed, sock_pfree() checks if reqsk->syncookie is 1, and in that case, we set NULL to reqsk->rsk_listener before calling reqsk_free() as reqsk does not hold a refcnt of the listener. When the TCP stack looks up a socket from the skb, we steal the listener from the reqsk in skb_steal_sock() and create a full sk in cookie_v[46]_check(). The refcnt of reqsk will finally be set to 1 in tcp_get_cookie_sock() after creating a full sk. Note that we can extend struct bpf_tcp_req_attrs in the future when we add a new attribute that is determined in 3WHS. Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240115205514.68364-6-kuniyu@amazon.com Signed-off-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- include/net/tcp.h | 14 ++++++ net/core/filter.c | 111 +++++++++++++++++++++++++++++++++++++++++++++- net/core/sock.c | 14 +++++- 3 files changed, 135 insertions(+), 4 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index dfe99a084a71..451dc1373970 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -600,6 +600,20 @@ static inline bool cookie_ecn_ok(const struct net *net, const struct dst_entry * } #if IS_ENABLED(CONFIG_BPF) +struct bpf_tcp_req_attrs { + u32 rcv_tsval; + u32 rcv_tsecr; + u16 mss; + u8 rcv_wscale; + u8 snd_wscale; + u8 ecn_ok; + u8 wscale_ok; + u8 sack_ok; + u8 tstamp_ok; + u8 usec_ts_ok; + u8 reserved[3]; +}; + static inline bool cookie_bpf_ok(struct sk_buff *skb) { return skb->sk; diff --git a/net/core/filter.c b/net/core/filter.c index 8c9f67c81e22..6a7abbaa50b8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -11837,6 +11837,103 @@ __bpf_kfunc int bpf_sock_addr_set_sun_path(struct bpf_sock_addr_kern *sa_kern, return 0; } + +__bpf_kfunc int bpf_sk_assign_tcp_reqsk(struct sk_buff *skb, struct sock *sk, + struct bpf_tcp_req_attrs *attrs, int attrs__sz) +{ +#if IS_ENABLED(CONFIG_SYN_COOKIES) + const struct request_sock_ops *ops; + struct inet_request_sock *ireq; + struct tcp_request_sock *treq; + struct request_sock *req; + struct net *net; + __u16 min_mss; + u32 tsoff = 0; + + if (attrs__sz != sizeof(*attrs) || + attrs->reserved[0] || attrs->reserved[1] || attrs->reserved[2]) + return -EINVAL; + + if (!skb_at_tc_ingress(skb)) + return -EINVAL; + + net = dev_net(skb->dev); + if (net != sock_net(sk)) + return -ENETUNREACH; + + switch (skb->protocol) { + case htons(ETH_P_IP): + ops = &tcp_request_sock_ops; + min_mss = 536; + break; +#if IS_BUILTIN(CONFIG_IPV6) + case htons(ETH_P_IPV6): + ops = &tcp6_request_sock_ops; + min_mss = IPV6_MIN_MTU - 60; + break; +#endif + default: + return -EINVAL; + } + + if (sk->sk_type != SOCK_STREAM || sk->sk_state != TCP_LISTEN || + sk_is_mptcp(sk)) + return -EINVAL; + + if (attrs->mss < min_mss) + return -EINVAL; + + if (attrs->wscale_ok) { + if (!READ_ONCE(net->ipv4.sysctl_tcp_window_scaling)) + return -EINVAL; + + if (attrs->snd_wscale > TCP_MAX_WSCALE || + attrs->rcv_wscale > TCP_MAX_WSCALE) + return -EINVAL; + } + + if (attrs->sack_ok && !READ_ONCE(net->ipv4.sysctl_tcp_sack)) + return -EINVAL; + + if (attrs->tstamp_ok) { + if (!READ_ONCE(net->ipv4.sysctl_tcp_timestamps)) + return -EINVAL; + + tsoff = attrs->rcv_tsecr - tcp_ns_to_ts(attrs->usec_ts_ok, tcp_clock_ns()); + } + + req = inet_reqsk_alloc(ops, sk, false); + if (!req) + return -ENOMEM; + + ireq = inet_rsk(req); + treq = tcp_rsk(req); + + req->rsk_listener = sk; + req->syncookie = 1; + req->mss = attrs->mss; + req->ts_recent = attrs->rcv_tsval; + + ireq->snd_wscale = attrs->snd_wscale; + ireq->rcv_wscale = attrs->rcv_wscale; + ireq->tstamp_ok = !!attrs->tstamp_ok; + ireq->sack_ok = !!attrs->sack_ok; + ireq->wscale_ok = !!attrs->wscale_ok; + ireq->ecn_ok = !!attrs->ecn_ok; + + treq->req_usec_ts = !!attrs->usec_ts_ok; + treq->ts_off = tsoff; + + skb_orphan(skb); + skb->sk = req_to_sk(req); + skb->destructor = sock_pfree; + + return 0; +#else + return -EOPNOTSUPP; +#endif +} + __bpf_kfunc_end_defs(); int bpf_dynptr_from_skb_rdonly(struct sk_buff *skb, u64 flags, @@ -11865,6 +11962,10 @@ BTF_SET8_START(bpf_kfunc_check_set_sock_addr) BTF_ID_FLAGS(func, bpf_sock_addr_set_sun_path) BTF_SET8_END(bpf_kfunc_check_set_sock_addr) +BTF_SET8_START(bpf_kfunc_check_set_tcp_reqsk) +BTF_ID_FLAGS(func, bpf_sk_assign_tcp_reqsk, KF_TRUSTED_ARGS) +BTF_SET8_END(bpf_kfunc_check_set_tcp_reqsk) + static const struct btf_kfunc_id_set bpf_kfunc_set_skb = { .owner = THIS_MODULE, .set = &bpf_kfunc_check_set_skb, @@ -11880,6 +11981,11 @@ static const struct btf_kfunc_id_set bpf_kfunc_set_sock_addr = { .set = &bpf_kfunc_check_set_sock_addr, }; +static const struct btf_kfunc_id_set bpf_kfunc_set_tcp_reqsk = { + .owner = THIS_MODULE, + .set = &bpf_kfunc_check_set_tcp_reqsk, +}; + static int __init bpf_kfunc_init(void) { int ret; @@ -11895,8 +12001,9 @@ static int __init bpf_kfunc_init(void) ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_LWT_SEG6LOCAL, &bpf_kfunc_set_skb); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_NETFILTER, &bpf_kfunc_set_skb); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &bpf_kfunc_set_xdp); - return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, - &bpf_kfunc_set_sock_addr); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + &bpf_kfunc_set_sock_addr); + return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_kfunc_set_tcp_reqsk); } late_initcall(bpf_kfunc_init); diff --git a/net/core/sock.c b/net/core/sock.c index 158dbdebce6a..147fb2656e6b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2582,8 +2582,18 @@ EXPORT_SYMBOL(sock_efree); #ifdef CONFIG_INET void sock_pfree(struct sk_buff *skb) { - if (sk_is_refcounted(skb->sk)) - sock_gen_put(skb->sk); + struct sock *sk = skb->sk; + + if (!sk_is_refcounted(sk)) + return; + + if (sk->sk_state == TCP_NEW_SYN_RECV && inet_reqsk(sk)->syncookie) { + inet_reqsk(sk)->rsk_listener = NULL; + reqsk_free(inet_reqsk(sk)); + return; + } + + sock_gen_put(sk); } EXPORT_SYMBOL(sock_pfree); #endif /* CONFIG_INET */ From a74712241b4675175cd8e3310fa206d8756ad5a1 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 15 Jan 2024 12:55:14 -0800 Subject: [PATCH 0211/2255] selftest: bpf: Test bpf_sk_assign_tcp_reqsk(). This commit adds a sample selftest to demonstrate how we can use bpf_sk_assign_tcp_reqsk() as the backend of SYN Proxy. The test creates IPv4/IPv6 x TCP connections and transfer messages over them on lo with BPF tc prog attached. The tc prog will process SYN and returns SYN+ACK with the following ISN and TS. In a real use case, this part will be done by other hosts. MSB LSB ISN: | 31 ... 8 | 7 6 | 5 | 4 | 3 2 1 0 | | Hash_1 | MSS | ECN | SACK | WScale | TS: | 31 ... 8 | 7 ... 0 | | Random | Hash_2 | WScale in SYN is reused in SYN+ACK. The client returns ACK, and tc prog will recalculate ISN and TS from ACK and validate SYN Cookie. If it's valid, the prog calls kfunc to allocate a reqsk for skb and configure the reqsk based on the argument created from SYN Cookie. Later, the reqsk will be processed in cookie_v[46]_check() to create a connection. Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240115205514.68364-7-kuniyu@amazon.com Signed-off-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_kfuncs.h | 10 + tools/testing/selftests/bpf/config | 1 + .../bpf/prog_tests/tcp_custom_syncookie.c | 150 +++++ .../selftests/bpf/progs/bpf_tracing_net.h | 16 + .../selftests/bpf/progs/test_siphash.h | 64 ++ .../bpf/progs/test_tcp_custom_syncookie.c | 572 ++++++++++++++++++ .../bpf/progs/test_tcp_custom_syncookie.h | 140 +++++ 7 files changed, 953 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c create mode 100644 tools/testing/selftests/bpf/progs/test_siphash.h create mode 100644 tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c create mode 100644 tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.h diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index b4e78c1eb37b..23c24f852f4f 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -51,6 +51,16 @@ extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clo extern int bpf_sock_addr_set_sun_path(struct bpf_sock_addr_kern *sa_kern, const __u8 *sun_path, __u32 sun_path__sz) __ksym; +/* Description + * Allocate and configure a reqsk and link it with a listener and skb. + * Returns + * Error code + */ +struct sock; +struct bpf_tcp_req_attrs; +extern int bpf_sk_assign_tcp_reqsk(struct __sk_buff *skb, struct sock *sk, + struct bpf_tcp_req_attrs *attrs, int attrs__sz) __ksym; + void *bpf_cast_to_kern_ctx(void *) __ksym; void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym; diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index c125c441abc7..01f241ea2c67 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -81,6 +81,7 @@ CONFIG_NF_NAT=y CONFIG_RC_CORE=y CONFIG_SECURITY=y CONFIG_SECURITYFS=y +CONFIG_SYN_COOKIES=y CONFIG_TEST_BPF=m CONFIG_USERFAULTFD=y CONFIG_VSOCKETS=y diff --git a/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c b/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c new file mode 100644 index 000000000000..eaf441dc7e79 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright Amazon.com Inc. or its affiliates. */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "test_progs.h" +#include "cgroup_helpers.h" +#include "network_helpers.h" +#include "test_tcp_custom_syncookie.skel.h" + +static struct test_tcp_custom_syncookie_case { + int family, type; + char addr[16]; + char name[10]; +} test_cases[] = { + { + .name = "IPv4 TCP", + .family = AF_INET, + .type = SOCK_STREAM, + .addr = "127.0.0.1", + }, + { + .name = "IPv6 TCP", + .family = AF_INET6, + .type = SOCK_STREAM, + .addr = "::1", + }, +}; + +static int setup_netns(void) +{ + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) + return -1; + + if (!ASSERT_OK(system("ip link set dev lo up"), "ip")) + goto err; + + if (!ASSERT_OK(write_sysctl("/proc/sys/net/ipv4/tcp_ecn", "1"), + "write_sysctl")) + goto err; + + return 0; +err: + return -1; +} + +static int setup_tc(struct test_tcp_custom_syncookie *skel) +{ + LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point = BPF_TC_INGRESS); + LIBBPF_OPTS(bpf_tc_opts, tc_attach, + .prog_fd = bpf_program__fd(skel->progs.tcp_custom_syncookie)); + + qdisc_lo.ifindex = if_nametoindex("lo"); + if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact")) + goto err; + + if (!ASSERT_OK(bpf_tc_attach(&qdisc_lo, &tc_attach), + "filter add dev lo ingress")) + goto err; + + return 0; +err: + return -1; +} + +#define msg "Hello World" +#define msglen 11 + +static void transfer_message(int sender, int receiver) +{ + char buf[msglen]; + int ret; + + ret = send(sender, msg, msglen, 0); + if (!ASSERT_EQ(ret, msglen, "send")) + return; + + memset(buf, 0, sizeof(buf)); + + ret = recv(receiver, buf, msglen, 0); + if (!ASSERT_EQ(ret, msglen, "recv")) + return; + + ret = strncmp(buf, msg, msglen); + if (!ASSERT_EQ(ret, 0, "strncmp")) + return; +} + +static void create_connection(struct test_tcp_custom_syncookie_case *test_case) +{ + int server, client, child; + + server = start_server(test_case->family, test_case->type, test_case->addr, 0, 0); + if (!ASSERT_NEQ(server, -1, "start_server")) + return; + + client = connect_to_fd(server, 0); + if (!ASSERT_NEQ(client, -1, "connect_to_fd")) + goto close_server; + + child = accept(server, NULL, 0); + if (!ASSERT_NEQ(child, -1, "accept")) + goto close_client; + + transfer_message(client, child); + transfer_message(child, client); + + close(child); +close_client: + close(client); +close_server: + close(server); +} + +void test_tcp_custom_syncookie(void) +{ + struct test_tcp_custom_syncookie *skel; + int i; + + if (setup_netns()) + return; + + skel = test_tcp_custom_syncookie__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + + if (setup_tc(skel)) + goto destroy_skel; + + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { + if (!test__start_subtest(test_cases[i].name)) + continue; + + skel->bss->handled_syn = false; + skel->bss->handled_ack = false; + + create_connection(&test_cases[i]); + + ASSERT_EQ(skel->bss->handled_syn, true, "SYN is not handled at tc."); + ASSERT_EQ(skel->bss->handled_ack, true, "ACK is not handled at tc"); + } + +destroy_skel: + system("tc qdisc del dev lo clsact"); + + test_tcp_custom_syncookie__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h index e8bd4b7b5ef7..7001965d1cc3 100644 --- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h +++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h @@ -51,9 +51,25 @@ #define ICSK_TIME_LOSS_PROBE 5 #define ICSK_TIME_REO_TIMEOUT 6 +#define ETH_ALEN 6 #define ETH_HLEN 14 +#define ETH_P_IP 0x0800 #define ETH_P_IPV6 0x86DD +#define NEXTHDR_TCP 6 + +#define TCPOPT_NOP 1 +#define TCPOPT_EOL 0 +#define TCPOPT_MSS 2 +#define TCPOPT_WINDOW 3 +#define TCPOPT_TIMESTAMP 8 +#define TCPOPT_SACK_PERM 4 + +#define TCPOLEN_MSS 4 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_SACK_PERM 2 + #define CHECKSUM_NONE 0 #define CHECKSUM_PARTIAL 3 diff --git a/tools/testing/selftests/bpf/progs/test_siphash.h b/tools/testing/selftests/bpf/progs/test_siphash.h new file mode 100644 index 000000000000..5d3a7ec36780 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_siphash.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright Amazon.com Inc. or its affiliates. */ + +#ifndef _TEST_SIPHASH_H +#define _TEST_SIPHASH_H + +/* include/linux/bitops.h */ +static inline u64 rol64(u64 word, unsigned int shift) +{ + return (word << (shift & 63)) | (word >> ((-shift) & 63)); +} + +/* include/linux/siphash.h */ +#define SIPHASH_PERMUTATION(a, b, c, d) ( \ + (a) += (b), (b) = rol64((b), 13), (b) ^= (a), (a) = rol64((a), 32), \ + (c) += (d), (d) = rol64((d), 16), (d) ^= (c), \ + (a) += (d), (d) = rol64((d), 21), (d) ^= (a), \ + (c) += (b), (b) = rol64((b), 17), (b) ^= (c), (c) = rol64((c), 32)) + +#define SIPHASH_CONST_0 0x736f6d6570736575ULL +#define SIPHASH_CONST_1 0x646f72616e646f6dULL +#define SIPHASH_CONST_2 0x6c7967656e657261ULL +#define SIPHASH_CONST_3 0x7465646279746573ULL + +/* lib/siphash.c */ +#define SIPROUND SIPHASH_PERMUTATION(v0, v1, v2, v3) + +#define PREAMBLE(len) \ + u64 v0 = SIPHASH_CONST_0; \ + u64 v1 = SIPHASH_CONST_1; \ + u64 v2 = SIPHASH_CONST_2; \ + u64 v3 = SIPHASH_CONST_3; \ + u64 b = ((u64)(len)) << 56; \ + v3 ^= key->key[1]; \ + v2 ^= key->key[0]; \ + v1 ^= key->key[1]; \ + v0 ^= key->key[0]; + +#define POSTAMBLE \ + v3 ^= b; \ + SIPROUND; \ + SIPROUND; \ + v0 ^= b; \ + v2 ^= 0xff; \ + SIPROUND; \ + SIPROUND; \ + SIPROUND; \ + SIPROUND; \ + return (v0 ^ v1) ^ (v2 ^ v3); + +static inline u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key) +{ + PREAMBLE(16) + v3 ^= first; + SIPROUND; + SIPROUND; + v0 ^= first; + v3 ^= second; + SIPROUND; + SIPROUND; + v0 ^= second; + POSTAMBLE +} +#endif diff --git a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c new file mode 100644 index 000000000000..a5501b29979a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright Amazon.com Inc. or its affiliates. */ + +#include "vmlinux.h" + +#include +#include +#include "bpf_tracing_net.h" +#include "bpf_kfuncs.h" +#include "test_siphash.h" +#include "test_tcp_custom_syncookie.h" + +/* Hash is calculated for each client and split into ISN and TS. + * + * MSB LSB + * ISN: | 31 ... 8 | 7 6 | 5 | 4 | 3 2 1 0 | + * | Hash_1 | MSS | ECN | SACK | WScale | + * + * TS: | 31 ... 8 | 7 ... 0 | + * | Random | Hash_2 | + */ +#define COOKIE_BITS 8 +#define COOKIE_MASK (((__u32)1 << COOKIE_BITS) - 1) + +enum { + /* 0xf is invalid thus means that SYN did not have WScale. */ + BPF_SYNCOOKIE_WSCALE_MASK = (1 << 4) - 1, + BPF_SYNCOOKIE_SACK = (1 << 4), + BPF_SYNCOOKIE_ECN = (1 << 5), +}; + +#define MSS_LOCAL_IPV4 65495 +#define MSS_LOCAL_IPV6 65476 + +const __u16 msstab4[] = { + 536, + 1300, + 1460, + MSS_LOCAL_IPV4, +}; + +const __u16 msstab6[] = { + 1280 - 60, /* IPV6_MIN_MTU - 60 */ + 1480 - 60, + 9000 - 60, + MSS_LOCAL_IPV6, +}; + +static siphash_key_t test_key_siphash = { + { 0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL } +}; + +struct tcp_syncookie { + struct __sk_buff *skb; + void *data_end; + struct ethhdr *eth; + struct iphdr *ipv4; + struct ipv6hdr *ipv6; + struct tcphdr *tcp; + union { + char *ptr; + __be32 *ptr32; + }; + struct bpf_tcp_req_attrs attrs; + u32 cookie; + u64 first; +}; + +bool handled_syn, handled_ack; + +static int tcp_load_headers(struct tcp_syncookie *ctx) +{ + ctx->data_end = (void *)(long)ctx->skb->data_end; + ctx->eth = (struct ethhdr *)(long)ctx->skb->data; + + if (ctx->eth + 1 > ctx->data_end) + goto err; + + switch (bpf_ntohs(ctx->eth->h_proto)) { + case ETH_P_IP: + ctx->ipv4 = (struct iphdr *)(ctx->eth + 1); + + if (ctx->ipv4 + 1 > ctx->data_end) + goto err; + + if (ctx->ipv4->ihl != sizeof(*ctx->ipv4) / 4) + goto err; + + if (ctx->ipv4->version != 4) + goto err; + + if (ctx->ipv4->protocol != IPPROTO_TCP) + goto err; + + ctx->tcp = (struct tcphdr *)(ctx->ipv4 + 1); + break; + case ETH_P_IPV6: + ctx->ipv6 = (struct ipv6hdr *)(ctx->eth + 1); + + if (ctx->ipv6 + 1 > ctx->data_end) + goto err; + + if (ctx->ipv6->version != 6) + goto err; + + if (ctx->ipv6->nexthdr != NEXTHDR_TCP) + goto err; + + ctx->tcp = (struct tcphdr *)(ctx->ipv6 + 1); + break; + default: + goto err; + } + + if (ctx->tcp + 1 > ctx->data_end) + goto err; + + return 0; +err: + return -1; +} + +static int tcp_reload_headers(struct tcp_syncookie *ctx) +{ + /* Without volatile, + * R3 32-bit pointer arithmetic prohibited + */ + volatile u64 data_len = ctx->skb->data_end - ctx->skb->data; + + if (ctx->tcp->doff < sizeof(*ctx->tcp) / 4) + goto err; + + /* Needed to calculate csum and parse TCP options. */ + if (bpf_skb_change_tail(ctx->skb, data_len + 60 - ctx->tcp->doff * 4, 0)) + goto err; + + ctx->data_end = (void *)(long)ctx->skb->data_end; + ctx->eth = (struct ethhdr *)(long)ctx->skb->data; + if (ctx->ipv4) { + ctx->ipv4 = (struct iphdr *)(ctx->eth + 1); + ctx->ipv6 = NULL; + ctx->tcp = (struct tcphdr *)(ctx->ipv4 + 1); + } else { + ctx->ipv4 = NULL; + ctx->ipv6 = (struct ipv6hdr *)(ctx->eth + 1); + ctx->tcp = (struct tcphdr *)(ctx->ipv6 + 1); + } + + if ((void *)ctx->tcp + 60 > ctx->data_end) + goto err; + + return 0; +err: + return -1; +} + +static __sum16 tcp_v4_csum(struct tcp_syncookie *ctx, __wsum csum) +{ + return csum_tcpudp_magic(ctx->ipv4->saddr, ctx->ipv4->daddr, + ctx->tcp->doff * 4, IPPROTO_TCP, csum); +} + +static __sum16 tcp_v6_csum(struct tcp_syncookie *ctx, __wsum csum) +{ + return csum_ipv6_magic(&ctx->ipv6->saddr, &ctx->ipv6->daddr, + ctx->tcp->doff * 4, IPPROTO_TCP, csum); +} + +static int tcp_validate_header(struct tcp_syncookie *ctx) +{ + s64 csum; + + if (tcp_reload_headers(ctx)) + goto err; + + csum = bpf_csum_diff(0, 0, (void *)ctx->tcp, ctx->tcp->doff * 4, 0); + if (csum < 0) + goto err; + + if (ctx->ipv4) { + /* check tcp_v4_csum(csum) is 0 if not on lo. */ + + csum = bpf_csum_diff(0, 0, (void *)ctx->ipv4, ctx->ipv4->ihl * 4, 0); + if (csum < 0) + goto err; + + if (csum_fold(csum) != 0) + goto err; + } else if (ctx->ipv6) { + /* check tcp_v6_csum(csum) is 0 if not on lo. */ + } + + return 0; +err: + return -1; +} + +static int tcp_parse_option(__u32 index, struct tcp_syncookie *ctx) +{ + char opcode, opsize; + + if (ctx->ptr + 1 > ctx->data_end) + goto stop; + + opcode = *ctx->ptr++; + + if (opcode == TCPOPT_EOL) + goto stop; + + if (opcode == TCPOPT_NOP) + goto next; + + if (ctx->ptr + 1 > ctx->data_end) + goto stop; + + opsize = *ctx->ptr++; + + if (opsize < 2) + goto stop; + + switch (opcode) { + case TCPOPT_MSS: + if (opsize == TCPOLEN_MSS && ctx->tcp->syn && + ctx->ptr + (TCPOLEN_MSS - 2) < ctx->data_end) + ctx->attrs.mss = get_unaligned_be16(ctx->ptr); + break; + case TCPOPT_WINDOW: + if (opsize == TCPOLEN_WINDOW && ctx->tcp->syn && + ctx->ptr + (TCPOLEN_WINDOW - 2) < ctx->data_end) { + ctx->attrs.wscale_ok = 1; + ctx->attrs.snd_wscale = *ctx->ptr; + } + break; + case TCPOPT_TIMESTAMP: + if (opsize == TCPOLEN_TIMESTAMP && + ctx->ptr + (TCPOLEN_TIMESTAMP - 2) < ctx->data_end) { + ctx->attrs.rcv_tsval = get_unaligned_be32(ctx->ptr); + ctx->attrs.rcv_tsecr = get_unaligned_be32(ctx->ptr + 4); + + if (ctx->tcp->syn && ctx->attrs.rcv_tsecr) + ctx->attrs.tstamp_ok = 0; + else + ctx->attrs.tstamp_ok = 1; + } + break; + case TCPOPT_SACK_PERM: + if (opsize == TCPOLEN_SACK_PERM && ctx->tcp->syn && + ctx->ptr + (TCPOLEN_SACK_PERM - 2) < ctx->data_end) + ctx->attrs.sack_ok = 1; + break; + } + + ctx->ptr += opsize - 2; +next: + return 0; +stop: + return 1; +} + +static void tcp_parse_options(struct tcp_syncookie *ctx) +{ + ctx->ptr = (char *)(ctx->tcp + 1); + + bpf_loop(40, tcp_parse_option, ctx, 0); +} + +static int tcp_validate_sysctl(struct tcp_syncookie *ctx) +{ + if ((ctx->ipv4 && ctx->attrs.mss != MSS_LOCAL_IPV4) || + (ctx->ipv6 && ctx->attrs.mss != MSS_LOCAL_IPV6)) + goto err; + + if (!ctx->attrs.wscale_ok || ctx->attrs.snd_wscale != 7) + goto err; + + if (!ctx->attrs.tstamp_ok) + goto err; + + if (!ctx->attrs.sack_ok) + goto err; + + if (!ctx->tcp->ece || !ctx->tcp->cwr) + goto err; + + return 0; +err: + return -1; +} + +static void tcp_prepare_cookie(struct tcp_syncookie *ctx) +{ + u32 seq = bpf_ntohl(ctx->tcp->seq); + u64 first = 0, second; + int mssind = 0; + u32 hash; + + if (ctx->ipv4) { + for (mssind = ARRAY_SIZE(msstab4) - 1; mssind; mssind--) + if (ctx->attrs.mss >= msstab4[mssind]) + break; + + ctx->attrs.mss = msstab4[mssind]; + + first = (u64)ctx->ipv4->saddr << 32 | ctx->ipv4->daddr; + } else if (ctx->ipv6) { + for (mssind = ARRAY_SIZE(msstab6) - 1; mssind; mssind--) + if (ctx->attrs.mss >= msstab6[mssind]) + break; + + ctx->attrs.mss = msstab6[mssind]; + + first = (u64)ctx->ipv6->saddr.in6_u.u6_addr8[0] << 32 | + ctx->ipv6->daddr.in6_u.u6_addr32[0]; + } + + second = (u64)seq << 32 | ctx->tcp->source << 16 | ctx->tcp->dest; + hash = siphash_2u64(first, second, &test_key_siphash); + + if (ctx->attrs.tstamp_ok) { + ctx->attrs.rcv_tsecr = bpf_get_prandom_u32(); + ctx->attrs.rcv_tsecr &= ~COOKIE_MASK; + ctx->attrs.rcv_tsecr |= hash & COOKIE_MASK; + } + + hash &= ~COOKIE_MASK; + hash |= mssind << 6; + + if (ctx->attrs.wscale_ok) + hash |= ctx->attrs.snd_wscale & BPF_SYNCOOKIE_WSCALE_MASK; + + if (ctx->attrs.sack_ok) + hash |= BPF_SYNCOOKIE_SACK; + + if (ctx->attrs.tstamp_ok && ctx->tcp->ece && ctx->tcp->cwr) + hash |= BPF_SYNCOOKIE_ECN; + + ctx->cookie = hash; +} + +static void tcp_write_options(struct tcp_syncookie *ctx) +{ + ctx->ptr32 = (__be32 *)(ctx->tcp + 1); + + *ctx->ptr32++ = bpf_htonl(TCPOPT_MSS << 24 | TCPOLEN_MSS << 16 | + ctx->attrs.mss); + + if (ctx->attrs.wscale_ok) + *ctx->ptr32++ = bpf_htonl(TCPOPT_NOP << 24 | + TCPOPT_WINDOW << 16 | + TCPOLEN_WINDOW << 8 | + ctx->attrs.snd_wscale); + + if (ctx->attrs.tstamp_ok) { + if (ctx->attrs.sack_ok) + *ctx->ptr32++ = bpf_htonl(TCPOPT_SACK_PERM << 24 | + TCPOLEN_SACK_PERM << 16 | + TCPOPT_TIMESTAMP << 8 | + TCPOLEN_TIMESTAMP); + else + *ctx->ptr32++ = bpf_htonl(TCPOPT_NOP << 24 | + TCPOPT_NOP << 16 | + TCPOPT_TIMESTAMP << 8 | + TCPOLEN_TIMESTAMP); + + *ctx->ptr32++ = bpf_htonl(ctx->attrs.rcv_tsecr); + *ctx->ptr32++ = bpf_htonl(ctx->attrs.rcv_tsval); + } else if (ctx->attrs.sack_ok) { + *ctx->ptr32++ = bpf_htonl(TCPOPT_NOP << 24 | + TCPOPT_NOP << 16 | + TCPOPT_SACK_PERM << 8 | + TCPOLEN_SACK_PERM); + } +} + +static int tcp_handle_syn(struct tcp_syncookie *ctx) +{ + s64 csum; + + if (tcp_validate_header(ctx)) + goto err; + + tcp_parse_options(ctx); + + if (tcp_validate_sysctl(ctx)) + goto err; + + tcp_prepare_cookie(ctx); + tcp_write_options(ctx); + + swap(ctx->tcp->source, ctx->tcp->dest); + ctx->tcp->check = 0; + ctx->tcp->ack_seq = bpf_htonl(bpf_ntohl(ctx->tcp->seq) + 1); + ctx->tcp->seq = bpf_htonl(ctx->cookie); + ctx->tcp->doff = ((long)ctx->ptr32 - (long)ctx->tcp) >> 2; + ctx->tcp->ack = 1; + if (!ctx->attrs.tstamp_ok || !ctx->tcp->ece || !ctx->tcp->cwr) + ctx->tcp->ece = 0; + ctx->tcp->cwr = 0; + + csum = bpf_csum_diff(0, 0, (void *)ctx->tcp, ctx->tcp->doff * 4, 0); + if (csum < 0) + goto err; + + if (ctx->ipv4) { + swap(ctx->ipv4->saddr, ctx->ipv4->daddr); + ctx->tcp->check = tcp_v4_csum(ctx, csum); + + ctx->ipv4->check = 0; + ctx->ipv4->tos = 0; + ctx->ipv4->tot_len = bpf_htons((long)ctx->ptr32 - (long)ctx->ipv4); + ctx->ipv4->id = 0; + ctx->ipv4->ttl = 64; + + csum = bpf_csum_diff(0, 0, (void *)ctx->ipv4, sizeof(*ctx->ipv4), 0); + if (csum < 0) + goto err; + + ctx->ipv4->check = csum_fold(csum); + } else if (ctx->ipv6) { + swap(ctx->ipv6->saddr, ctx->ipv6->daddr); + ctx->tcp->check = tcp_v6_csum(ctx, csum); + + *(__be32 *)ctx->ipv6 = bpf_htonl(0x60000000); + ctx->ipv6->payload_len = bpf_htons((long)ctx->ptr32 - (long)ctx->tcp); + ctx->ipv6->hop_limit = 64; + } + + swap_array(ctx->eth->h_source, ctx->eth->h_dest); + + if (bpf_skb_change_tail(ctx->skb, (long)ctx->ptr32 - (long)ctx->eth, 0)) + goto err; + + return bpf_redirect(ctx->skb->ifindex, 0); +err: + return TC_ACT_SHOT; +} + +static int tcp_validate_cookie(struct tcp_syncookie *ctx) +{ + u32 cookie = bpf_ntohl(ctx->tcp->ack_seq) - 1; + u32 seq = bpf_ntohl(ctx->tcp->seq) - 1; + u64 first = 0, second; + int mssind; + u32 hash; + + if (ctx->ipv4) + first = (u64)ctx->ipv4->saddr << 32 | ctx->ipv4->daddr; + else if (ctx->ipv6) + first = (u64)ctx->ipv6->saddr.in6_u.u6_addr8[0] << 32 | + ctx->ipv6->daddr.in6_u.u6_addr32[0]; + + second = (u64)seq << 32 | ctx->tcp->source << 16 | ctx->tcp->dest; + hash = siphash_2u64(first, second, &test_key_siphash); + + if (ctx->attrs.tstamp_ok) + hash -= ctx->attrs.rcv_tsecr & COOKIE_MASK; + else + hash &= ~COOKIE_MASK; + + hash -= cookie & ~COOKIE_MASK; + if (hash) + goto err; + + mssind = (cookie & (3 << 6)) >> 6; + if (ctx->ipv4) { + if (mssind > ARRAY_SIZE(msstab4)) + goto err; + + ctx->attrs.mss = msstab4[mssind]; + } else { + if (mssind > ARRAY_SIZE(msstab6)) + goto err; + + ctx->attrs.mss = msstab6[mssind]; + } + + ctx->attrs.snd_wscale = cookie & BPF_SYNCOOKIE_WSCALE_MASK; + ctx->attrs.rcv_wscale = ctx->attrs.snd_wscale; + ctx->attrs.wscale_ok = ctx->attrs.snd_wscale == BPF_SYNCOOKIE_WSCALE_MASK; + ctx->attrs.sack_ok = cookie & BPF_SYNCOOKIE_SACK; + ctx->attrs.ecn_ok = cookie & BPF_SYNCOOKIE_ECN; + + return 0; +err: + return -1; +} + +static int tcp_handle_ack(struct tcp_syncookie *ctx) +{ + struct bpf_sock_tuple tuple; + struct bpf_sock *skc; + int ret = TC_ACT_OK; + struct sock *sk; + u32 tuple_size; + + if (ctx->ipv4) { + tuple.ipv4.saddr = ctx->ipv4->saddr; + tuple.ipv4.daddr = ctx->ipv4->daddr; + tuple.ipv4.sport = ctx->tcp->source; + tuple.ipv4.dport = ctx->tcp->dest; + tuple_size = sizeof(tuple.ipv4); + } else if (ctx->ipv6) { + __builtin_memcpy(tuple.ipv6.saddr, &ctx->ipv6->saddr, sizeof(tuple.ipv6.saddr)); + __builtin_memcpy(tuple.ipv6.daddr, &ctx->ipv6->daddr, sizeof(tuple.ipv6.daddr)); + tuple.ipv6.sport = ctx->tcp->source; + tuple.ipv6.dport = ctx->tcp->dest; + tuple_size = sizeof(tuple.ipv6); + } else { + goto out; + } + + skc = bpf_skc_lookup_tcp(ctx->skb, &tuple, tuple_size, -1, 0); + if (!skc) + goto out; + + if (skc->state != TCP_LISTEN) + goto release; + + sk = (struct sock *)bpf_skc_to_tcp_sock(skc); + if (!sk) + goto err; + + if (tcp_validate_header(ctx)) + goto err; + + tcp_parse_options(ctx); + + if (tcp_validate_cookie(ctx)) + goto err; + + ret = bpf_sk_assign_tcp_reqsk(ctx->skb, sk, &ctx->attrs, sizeof(ctx->attrs)); + if (ret < 0) + goto err; + +release: + bpf_sk_release(skc); +out: + return ret; + +err: + ret = TC_ACT_SHOT; + goto release; +} + +SEC("tc") +int tcp_custom_syncookie(struct __sk_buff *skb) +{ + struct tcp_syncookie ctx = { + .skb = skb, + }; + + if (tcp_load_headers(&ctx)) + return TC_ACT_OK; + + if (ctx.tcp->rst) + return TC_ACT_OK; + + if (ctx.tcp->syn) { + if (ctx.tcp->ack) + return TC_ACT_OK; + + handled_syn = true; + + return tcp_handle_syn(&ctx); + } + + handled_ack = true; + + return tcp_handle_ack(&ctx); +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.h b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.h new file mode 100644 index 000000000000..29a6a53cf229 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.h @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright Amazon.com Inc. or its affiliates. */ + +#ifndef _TEST_TCP_SYNCOOKIE_H +#define _TEST_TCP_SYNCOOKIE_H + +#define __packed __attribute__((__packed__)) +#define __force + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define swap(a, b) \ + do { \ + typeof(a) __tmp = (a); \ + (a) = (b); \ + (b) = __tmp; \ + } while (0) + +#define swap_array(a, b) \ + do { \ + typeof(a) __tmp[sizeof(a)]; \ + __builtin_memcpy(__tmp, a, sizeof(a)); \ + __builtin_memcpy(a, b, sizeof(a)); \ + __builtin_memcpy(b, __tmp, sizeof(a)); \ + } while (0) + +/* asm-generic/unaligned.h */ +#define __get_unaligned_t(type, ptr) ({ \ + const struct { type x; } __packed * __pptr = (typeof(__pptr))(ptr); \ + __pptr->x; \ +}) + +#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr)) + +static inline u16 get_unaligned_be16(const void *p) +{ + return bpf_ntohs(__get_unaligned_t(__be16, p)); +} + +static inline u32 get_unaligned_be32(const void *p) +{ + return bpf_ntohl(__get_unaligned_t(__be32, p)); +} + +/* lib/checksum.c */ +static inline u32 from64to32(u64 x) +{ + /* add up 32-bit and 32-bit for 32+c bit */ + x = (x & 0xffffffff) + (x >> 32); + /* add up carry.. */ + x = (x & 0xffffffff) + (x >> 32); + return (u32)x; +} + +static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, + __u32 len, __u8 proto, __wsum sum) +{ + unsigned long long s = (__force u32)sum; + + s += (__force u32)saddr; + s += (__force u32)daddr; +#ifdef __BIG_ENDIAN + s += proto + len; +#else + s += (proto + len) << 8; +#endif + return (__force __wsum)from64to32(s); +} + +/* asm-generic/checksum.h */ +static inline __sum16 csum_fold(__wsum csum) +{ + u32 sum = (__force u32)csum; + + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + return (__force __sum16)~sum; +} + +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, + __u8 proto, __wsum sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); +} + +/* net/ipv6/ip6_checksum.c */ +static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, __wsum csum) +{ + int carry; + __u32 ulen; + __u32 uproto; + __u32 sum = (__force u32)csum; + + sum += (__force u32)saddr->in6_u.u6_addr32[0]; + carry = (sum < (__force u32)saddr->in6_u.u6_addr32[0]); + sum += carry; + + sum += (__force u32)saddr->in6_u.u6_addr32[1]; + carry = (sum < (__force u32)saddr->in6_u.u6_addr32[1]); + sum += carry; + + sum += (__force u32)saddr->in6_u.u6_addr32[2]; + carry = (sum < (__force u32)saddr->in6_u.u6_addr32[2]); + sum += carry; + + sum += (__force u32)saddr->in6_u.u6_addr32[3]; + carry = (sum < (__force u32)saddr->in6_u.u6_addr32[3]); + sum += carry; + + sum += (__force u32)daddr->in6_u.u6_addr32[0]; + carry = (sum < (__force u32)daddr->in6_u.u6_addr32[0]); + sum += carry; + + sum += (__force u32)daddr->in6_u.u6_addr32[1]; + carry = (sum < (__force u32)daddr->in6_u.u6_addr32[1]); + sum += carry; + + sum += (__force u32)daddr->in6_u.u6_addr32[2]; + carry = (sum < (__force u32)daddr->in6_u.u6_addr32[2]); + sum += carry; + + sum += (__force u32)daddr->in6_u.u6_addr32[3]; + carry = (sum < (__force u32)daddr->in6_u.u6_addr32[3]); + sum += carry; + + ulen = (__force u32)bpf_htonl((__u32)len); + sum += ulen; + carry = (sum < ulen); + sum += carry; + + uproto = (__force u32)bpf_htonl(proto); + sum += uproto; + carry = (sum < uproto); + sum += carry; + + return csum_fold((__force __wsum)sum); +} +#endif From f98df79bf7f772597313adca2720cb38770490dd Mon Sep 17 00:00:00 2001 From: Victor Stewart Date: Tue, 16 Jan 2024 20:29:52 +0000 Subject: [PATCH 0212/2255] bpf, docs: Fix bpf_redirect_peer header doc Amend the bpf_redirect_peer() header documentation to also mention support for the netkit device type. Signed-off-by: Victor Stewart Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20240116202952.241009-1-v@nametag.social Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 754e68ca8744..a00f8a5623e1 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -4839,9 +4839,9 @@ union bpf_attr { * going through the CPU's backlog queue. * * The *flags* argument is reserved and must be 0. The helper is - * currently only supported for tc BPF program types at the ingress - * hook and for veth device types. The peer device must reside in a - * different network namespace. + * currently only supported for tc BPF program types at the + * ingress hook and for veth and netkit target device types. The + * peer device must reside in a different network namespace. * Return * The helper returns **TC_ACT_REDIRECT** on success or * **TC_ACT_SHOT** on error. From 091f2bf60d52ac205c48dffcb8646ed9299078c9 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 17 Jan 2024 10:16:11 +0100 Subject: [PATCH 0213/2255] bpf: Sync uapi bpf.h header for the tooling infra Both commit 91051f003948 ("tcp: Dump bound-only sockets in inet_diag.") and commit 985b8ea9ec7e ("bpf, docs: Fix bpf_redirect_peer header doc") missed the tooling header sync. Fix it. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- tools/include/uapi/linux/bpf.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 7f24d898efbb..a00f8a5623e1 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -4839,9 +4839,9 @@ union bpf_attr { * going through the CPU's backlog queue. * * The *flags* argument is reserved and must be 0. The helper is - * currently only supported for tc BPF program types at the ingress - * hook and for veth device types. The peer device must reside in a - * different network namespace. + * currently only supported for tc BPF program types at the + * ingress hook and for veth and netkit target device types. The + * peer device must reside in a different network namespace. * Return * The helper returns **TC_ACT_REDIRECT** on success or * **TC_ACT_SHOT** on error. @@ -6904,6 +6904,7 @@ enum { BPF_TCP_LISTEN, BPF_TCP_CLOSING, /* Now a valid state */ BPF_TCP_NEW_SYN_RECV, + BPF_TCP_BOUND_INACTIVE, BPF_TCP_MAX_STATES /* Leave at the end! */ }; From f04deb90e516e8e48bf8693397529bc942a9e80b Mon Sep 17 00:00:00 2001 From: Andrey Grafin Date: Wed, 17 Jan 2024 16:06:18 +0300 Subject: [PATCH 0214/2255] libbpf: Apply map_set_def_max_entries() for inner_maps on creation This patch allows to auto create BPF_MAP_TYPE_ARRAY_OF_MAPS and BPF_MAP_TYPE_HASH_OF_MAPS with values of BPF_MAP_TYPE_PERF_EVENT_ARRAY by bpf_object__load(). Previous behaviour created a zero filled btf_map_def for inner maps and tried to use it for a map creation but the linux kernel forbids to create a BPF_MAP_TYPE_PERF_EVENT_ARRAY map with max_entries=0. Fixes: 646f02ffdd49 ("libbpf: Add BTF-defined map-in-map support") Signed-off-by: Andrey Grafin Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Acked-by: Hou Tao Link: https://lore.kernel.org/bpf/20240117130619.9403-1-conquistador@yandex-team.ru Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index afd09571c482..b8b00da62907 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -70,6 +70,7 @@ static struct bpf_map *bpf_object__add_map(struct bpf_object *obj); static bool prog_is_subprog(const struct bpf_object *obj, const struct bpf_program *prog); +static int map_set_def_max_entries(struct bpf_map *map); static const char * const attach_type_name[] = { [BPF_CGROUP_INET_INGRESS] = "cgroup_inet_ingress", @@ -5172,6 +5173,9 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b if (bpf_map_type__is_map_in_map(def->type)) { if (map->inner_map) { + err = map_set_def_max_entries(map->inner_map); + if (err) + return err; err = bpf_object__create_map(obj, map->inner_map, true); if (err) { pr_warn("map '%s': failed to create inner map: %d\n", From 40628f9fff73adecac77a9aa390f8016724cad99 Mon Sep 17 00:00:00 2001 From: Andrey Grafin Date: Wed, 17 Jan 2024 16:06:19 +0300 Subject: [PATCH 0215/2255] selftest/bpf: Add map_in_maps with BPF_MAP_TYPE_PERF_EVENT_ARRAY values Check that bpf_object__load() successfully creates map_in_maps with BPF_MAP_TYPE_PERF_EVENT_ARRAY values. These changes cover fix in the previous patch "libbpf: Apply map_set_def_max_entries() for inner_maps on creation". A command line output is: - w/o fix $ sudo ./test_maps libbpf: map 'mim_array_pe': failed to create inner map: -22 libbpf: map 'mim_array_pe': failed to create: Invalid argument(-22) libbpf: failed to load object './test_map_in_map.bpf.o' Failed to load test prog - with fix $ sudo ./test_maps ... test_maps: OK, 0 SKIPPED Fixes: 646f02ffdd49 ("libbpf: Add BTF-defined map-in-map support") Signed-off-by: Andrey Grafin Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Acked-by: Hou Tao Link: https://lore.kernel.org/bpf/20240117130619.9403-2-conquistador@yandex-team.ru Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/progs/test_map_in_map.c | 26 +++++++++++++++++++ tools/testing/selftests/bpf/test_maps.c | 6 ++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/progs/test_map_in_map.c b/tools/testing/selftests/bpf/progs/test_map_in_map.c index f416032ba858..b295f9b721bf 100644 --- a/tools/testing/selftests/bpf/progs/test_map_in_map.c +++ b/tools/testing/selftests/bpf/progs/test_map_in_map.c @@ -21,6 +21,32 @@ struct { __type(value, __u32); } mim_hash SEC(".maps"); +/* The following three maps are used to test + * perf_event_array map can be an inner + * map of hash/array_of_maps. + */ +struct perf_event_array { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __type(key, __u32); + __type(value, __u32); +} inner_map0 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, 1); + __type(key, __u32); + __array(values, struct perf_event_array); +} mim_array_pe SEC(".maps") = { + .values = {&inner_map0}}; + +struct { + __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); + __uint(max_entries, 1); + __type(key, __u32); + __array(values, struct perf_event_array); +} mim_hash_pe SEC(".maps") = { + .values = {&inner_map0}}; + SEC("xdp") int xdp_mimtest0(struct xdp_md *ctx) { diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 767e0693df10..dfbab214f4d1 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -1190,7 +1190,11 @@ static void test_map_in_map(void) goto out_map_in_map; } - bpf_object__load(obj); + err = bpf_object__load(obj); + if (err) { + printf("Failed to load test prog\n"); + goto out_map_in_map; + } map = bpf_object__find_map_by_name(obj, "mim_array"); if (!map) { From 2ce793ebe207328b1210bb53effd702740987148 Mon Sep 17 00:00:00 2001 From: Hao Sun Date: Wed, 17 Jan 2024 10:40:12 +0100 Subject: [PATCH 0216/2255] bpf: Refactor ptr alu checking rules to allow alu explicitly Current checking rules are structured to disallow alu on particular ptr types explicitly, so default cases are allowed implicitly. This may lead to newly added ptr types being allowed unexpectedly. So restruture it to allow alu explicitly. The tradeoff is mainly a bit more cases added in the switch. The following table from Eduard summarizes the rules: | Pointer type | Arithmetics allowed | |---------------------+---------------------| | PTR_TO_CTX | yes | | CONST_PTR_TO_MAP | conditionally | | PTR_TO_MAP_VALUE | yes | | PTR_TO_MAP_KEY | yes | | PTR_TO_STACK | yes | | PTR_TO_PACKET_META | yes | | PTR_TO_PACKET | yes | | PTR_TO_PACKET_END | no | | PTR_TO_FLOW_KEYS | conditionally | | PTR_TO_SOCKET | no | | PTR_TO_SOCK_COMMON | no | | PTR_TO_TCP_SOCK | no | | PTR_TO_TP_BUFFER | yes | | PTR_TO_XDP_SOCK | no | | PTR_TO_BTF_ID | yes | | PTR_TO_MEM | yes | | PTR_TO_BUF | yes | | PTR_TO_FUNC | yes | | CONST_PTR_TO_DYNPTR | yes | The refactored rules are equivalent to the original one. Note that PTR_TO_FUNC and CONST_PTR_TO_DYNPTR are not reject here because: (1) check_mem_access() rejects load/store on those ptrs, and those ptrs with offset passing to calls are rejected check_func_arg_reg_off(); (2) someone may rely on the verifier not rejecting programs earily. Signed-off-by: Hao Sun Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240117094012.36798-1-sunhao.th@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index bd1da0d3ebce..9e9cc132dd02 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -12862,6 +12862,19 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, } switch (base_type(ptr_reg->type)) { + case PTR_TO_CTX: + case PTR_TO_MAP_VALUE: + case PTR_TO_MAP_KEY: + case PTR_TO_STACK: + case PTR_TO_PACKET_META: + case PTR_TO_PACKET: + case PTR_TO_TP_BUFFER: + case PTR_TO_BTF_ID: + case PTR_TO_MEM: + case PTR_TO_BUF: + case PTR_TO_FUNC: + case CONST_PTR_TO_DYNPTR: + break; case PTR_TO_FLOW_KEYS: if (known) break; @@ -12871,16 +12884,10 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, if (known && smin_val == 0 && opcode == BPF_ADD) break; fallthrough; - case PTR_TO_PACKET_END: - case PTR_TO_SOCKET: - case PTR_TO_SOCK_COMMON: - case PTR_TO_TCP_SOCK: - case PTR_TO_XDP_SOCK: + default: verbose(env, "R%d pointer arithmetic on %s prohibited\n", dst, reg_type_str(env, ptr_reg->type)); return -EACCES; - default: - break; } /* In case of 'scalar += pointer', dst_reg inherits pointer type and id. From b3f086a7a136d721d112f35fe4cd7272e93cf06b Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 18 Jan 2024 13:17:51 -0800 Subject: [PATCH 0217/2255] bpf: Define struct bpf_tcp_req_attrs when CONFIG_SYN_COOKIES=n. kernel test robot reported the warning below: >> net/core/filter.c:11842:13: warning: declaration of 'struct bpf_tcp_req_attrs' will not be visible outside of this function [-Wvisibility] 11842 | struct bpf_tcp_req_attrs *attrs, int attrs__sz) | ^ 1 warning generated. struct bpf_tcp_req_attrs is defined under CONFIG_SYN_COOKIES but used in kfunc without the config. Let's move struct bpf_tcp_req_attrs definition outside of CONFIG_SYN_COOKIES guard. Fixes: e472f88891ab ("bpf: tcp: Support arbitrary SYN Cookie.") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401180418.CUVc0hxF-lkp@intel.com/ Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240118211751.25790-1-kuniyu@amazon.com Signed-off-by: Alexei Starovoitov --- include/net/tcp.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 451dc1373970..58e65af74ad1 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -498,6 +498,22 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, struct tcp_options_received *tcp_opt, int mss, u32 tsoff); +#if IS_ENABLED(CONFIG_BPF) +struct bpf_tcp_req_attrs { + u32 rcv_tsval; + u32 rcv_tsecr; + u16 mss; + u8 rcv_wscale; + u8 snd_wscale; + u8 ecn_ok; + u8 wscale_ok; + u8 sack_ok; + u8 tstamp_ok; + u8 usec_ts_ok; + u8 reserved[3]; +}; +#endif + #ifdef CONFIG_SYN_COOKIES /* Syncookies use a monotonic timer which increments every 60 seconds. @@ -600,20 +616,6 @@ static inline bool cookie_ecn_ok(const struct net *net, const struct dst_entry * } #if IS_ENABLED(CONFIG_BPF) -struct bpf_tcp_req_attrs { - u32 rcv_tsval; - u32 rcv_tsecr; - u16 mss; - u8 rcv_wscale; - u8 snd_wscale; - u8 ecn_ok; - u8 wscale_ok; - u8 sack_ok; - u8 tstamp_ok; - u8 usec_ts_ok; - u8 reserved[3]; -}; - static inline bool cookie_bpf_ok(struct sk_buff *skb) { return skb->sk; From 20e109ea9842158a153b24ef42ec5cc3d44e9485 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 18 Jan 2024 15:29:54 -0800 Subject: [PATCH 0218/2255] bpf, docs: Clarify that MOVSX is only for BPF_X not BPF_K Per discussion on the mailing list at https://mailarchive.ietf.org/arch/msg/bpf/uQiqhURdtxV_ZQOTgjCdm-seh74/ the MOVSX operation is only defined to support register extension. The document didn't previously state this and incorrectly implied that one could use an immediate value. Signed-off-by: Dave Thaler Acked-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240118232954.27206-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov --- Documentation/bpf/standardization/instruction-set.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index eb0f234a8001..d17a96c6254f 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -317,7 +317,8 @@ The ``BPF_MOVSX`` instruction does a move operation with sign extension. ``BPF_ALU | BPF_MOVSX`` :term:`sign extends` 8-bit and 16-bit operands into 32 bit operands, and zeroes the remaining upper 32 bits. ``BPF_ALU64 | BPF_MOVSX`` :term:`sign extends` 8-bit, 16-bit, and 32-bit -operands into 64 bit operands. +operands into 64 bit operands. Unlike other arithmetic instructions, +``BPF_MOVSX`` is only defined for register source operands (``BPF_X``). Shift operations use a mask of 0x3F (63) for 64-bit operations and 0x1F (31) for 32-bit operations. From 18a45f12d746c06b7361b0cce59cf8e8b9e38da6 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 19 Jan 2024 18:25:28 +0800 Subject: [PATCH 0219/2255] bpf, arm64: Enable the inline of bpf_kptr_xchg() ARM64 bpf jit satisfies the following two conditions: 1) support BPF_XCHG() on pointer-sized word. 2) the implementation of xchg is the same as atomic_xchg() on pointer-sized words. Both of these two functions use arch_xchg() to implement the exchange. So enable the inline of bpf_kptr_xchg() for arm64 bpf jit. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20240119102529.99581-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- arch/arm64/net/bpf_jit_comp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 8955da5c47cf..cfd5434de483 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -2305,3 +2305,8 @@ out: return ret; } + +bool bpf_jit_supports_ptr_xchg(void) +{ + return true; +} From 29f868887a7dd3efc6faecc6fc91b28fc25cf5b0 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 19 Jan 2024 18:25:29 +0800 Subject: [PATCH 0220/2255] selftests/bpf: Enable kptr_xchg_inline test for arm64 Now arm64 bpf jit has enable bpf_jit_supports_ptr_xchg(), so enable the test for arm64 as well. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20240119102529.99581-3-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c b/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c index 5a4bee1cf970..15144943e88b 100644 --- a/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c +++ b/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c @@ -13,7 +13,7 @@ void test_kptr_xchg_inline(void) unsigned int cnt; int err; -#if !defined(__x86_64__) +#if !(defined(__x86_64__) || defined(__aarch64__)) test__skip(); return; #endif From bc308d011ab8cc61bf1be15a2920bcd7d7b9b9d3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 19 Jan 2024 13:02:01 -0800 Subject: [PATCH 0221/2255] libbpf: call dup2() syscall directly We've ran into issues with using dup2() API in production setting, where libbpf is linked into large production environment and ends up calling unintended custom implementations of dup2(). These custom implementations don't provide atomic FD replacement guarantees of dup2() syscall, leading to subtle and hard to debug issues. To prevent this in the future and guarantee that no libc implementation will do their own custom non-atomic dup2() implementation, call dup2() syscall directly with syscall(SYS_dup2). Note that some architectures don't seem to provide dup2 and have dup3 instead. Try to detect and pick best syscall. Signed-off-by: Andrii Nakryiko Acked-by: Song Liu Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240119210201.1295511-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf_internal.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 27e4e320e1a6..58c547d473e0 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "relo_core.h" @@ -555,6 +556,15 @@ static inline int ensure_good_fd(int fd) return fd; } +static inline int sys_dup2(int oldfd, int newfd) +{ +#ifdef __NR_dup2 + return syscall(__NR_dup2, oldfd, newfd); +#else + return syscall(__NR_dup3, oldfd, newfd, 0); +#endif +} + /* Point *fixed_fd* to the same file that *tmp_fd* points to. * Regardless of success, *tmp_fd* is closed. * Whatever *fixed_fd* pointed to is closed silently. @@ -563,7 +573,7 @@ static inline int reuse_fd(int fixed_fd, int tmp_fd) { int err; - err = dup2(tmp_fd, fixed_fd); + err = sys_dup2(tmp_fd, fixed_fd); err = err < 0 ? -errno : 0; close(tmp_fd); /* clean up temporary FD */ return err; From edb799035dd7d41c3e81e1bef83e2a2120b08abb Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Tue, 23 Jan 2024 21:17:29 +0100 Subject: [PATCH 0222/2255] bpf: avoid VLAs in progs/test_xdp_dynptr.c VLAs are not supported by either the BPF port of clang nor GCC. The selftest test_xdp_dynptr.c contains the following code: const size_t tcphdr_sz = sizeof(struct tcphdr); const size_t udphdr_sz = sizeof(struct udphdr); const size_t ethhdr_sz = sizeof(struct ethhdr); const size_t iphdr_sz = sizeof(struct iphdr); const size_t ipv6hdr_sz = sizeof(struct ipv6hdr); [...] static __always_inline int handle_ipv4(struct xdp_md *xdp, struct bpf_dynptr *xdp_ptr) { __u8 eth_buffer[ethhdr_sz + iphdr_sz + ethhdr_sz]; __u8 iph_buffer_tcp[iphdr_sz + tcphdr_sz]; __u8 iph_buffer_udp[iphdr_sz + udphdr_sz]; [...] } The eth_buffer, iph_buffer_tcp and other automatics are fixed size only if the compiler optimizes away the constant global variables. clang does this, but GCC does not, turning these automatics into variable length arrays. This patch removes the global variables and turns these values into preprocessor constants. This makes the selftest to build properly with GCC. Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Cc: Yonghong Song Cc: Eduard Zingerman Cc: david.faust@oracle.com Cc: cupertino.miranda@oracle.com Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240123201729.16173-1-jose.marchesi@oracle.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/test_xdp_dynptr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c b/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c index 78c368e71797..67a77944ef29 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c @@ -18,11 +18,11 @@ #include "test_iptunnel_common.h" #include "bpf_kfuncs.h" -const size_t tcphdr_sz = sizeof(struct tcphdr); -const size_t udphdr_sz = sizeof(struct udphdr); -const size_t ethhdr_sz = sizeof(struct ethhdr); -const size_t iphdr_sz = sizeof(struct iphdr); -const size_t ipv6hdr_sz = sizeof(struct ipv6hdr); +#define tcphdr_sz sizeof(struct tcphdr) +#define udphdr_sz sizeof(struct udphdr) +#define ethhdr_sz sizeof(struct ethhdr) +#define iphdr_sz sizeof(struct iphdr) +#define ipv6hdr_sz sizeof(struct ipv6hdr) struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); From 756e34da5380e4c0ed2cfbe5259e1b015567a099 Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Tue, 23 Jan 2024 21:56:24 +0100 Subject: [PATCH 0223/2255] bpf: fix constraint in test_tcpbpf_kern.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC emits a warning: progs/test_tcpbpf_kern.c:60:9: error: ‘op’ is used uninitialized [-Werror=uninitialized] when an uninialized op is used with a "+r" constraint. The + modifier means a read-write operand, but that operand in the selftest is just written to. This patch changes the selftest to use a "=r" constraint. This pacifies GCC. Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Cc: Yonghong Song Cc: Eduard Zingerman Cc: david.faust@oracle.com Cc: cupertino.miranda@oracle.com Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240123205624.14746-1-jose.marchesi@oracle.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c index cf7ed8cbb1fe..a3f3f43fc195 100644 --- a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c +++ b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c @@ -59,7 +59,7 @@ int bpf_testcb(struct bpf_sock_ops *skops) asm volatile ( "%[op] = *(u32 *)(%[skops] +96)" - : [op] "+r"(op) + : [op] "=r"(op) : [skops] "r"(skops) :); From bbc094b3052647c188d6f155f5c09cb9492ce106 Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Tue, 23 Jan 2024 19:13:09 +0100 Subject: [PATCH 0224/2255] bpf: Use r constraint instead of p constraint in selftests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the BPF selftests use the "p" constraint in inline assembly snippets, for input operands for MOV (rN = rM) instructions. This is mainly done via the __imm_ptr macro defined in tools/testing/selftests/bpf/progs/bpf_misc.h: #define __imm_ptr(name) [name]"p"(&name) Example: int consume_first_item_only(void *ctx) { struct bpf_iter_num iter; asm volatile ( /* create iterator */ "r1 = %[iter];" [...] : : __imm_ptr(iter) : CLOBBERS); [...] } The "p" constraint is a tricky one. It is documented in the GCC manual section "Simple Constraints": An operand that is a valid memory address is allowed. This is for ``load address'' and ``push address'' instructions. p in the constraint must be accompanied by address_operand as the predicate in the match_operand. This predicate interprets the mode specified in the match_operand as the mode of the memory reference for which the address would be valid. There are two problems: 1. It is questionable whether that constraint was ever intended to be used in inline assembly templates, because its behavior really depends on compiler internals. A "memory address" is not the same than a "memory operand" or a "memory reference" (constraint "m"), and in fact its usage in the template above results in an error in both x86_64-linux-gnu and bpf-unkonwn-none: foo.c: In function ‘bar’: foo.c:6:3: error: invalid 'asm': invalid expression as operand 6 | asm volatile ("r1 = %[jorl]" : : [jorl]"p"(&jorl)); | ^~~ I would assume the same happens with aarch64, riscv, and most/all other targets in GCC, that do not accept operands of the form A + B that are not wrapped either in a const or in a memory reference. To avoid that error, the usage of the "p" constraint in internal GCC instruction templates is supposed to be complemented by the 'a' modifier, like in: asm volatile ("r1 = %a[jorl]" : : [jorl]"p"(&jorl)); Internally documented (in GCC's final.cc) as: %aN means expect operand N to be a memory address (not a memory reference!) and print a reference to that address. That works because when the modifier 'a' is found, GCC prints an "operand address", which is not the same than an "operand". But... 2. Even if we used the internal 'a' modifier (we shouldn't) the 'rN = rM' instruction really requires a register argument. In cases involving automatics, like in the examples above, we easily end with: bar: #APP r1 = r10-4 #NO_APP In other cases we could conceibly also end with a 64-bit label that may overflow the 32-bit immediate operand of `rN = imm32' instructions: r1 = foo All of which is clearly wrong. clang happens to do "the right thing" in the current usage of __imm_ptr in the BPF tests, because even with -O2 it seems to "reload" the fp-relative address of the automatic to a register like in: bar: r1 = r10 r1 += -4 #APP r1 = r1 #NO_APP Which is what GCC would generate with -O0. Whether this is by chance or by design, the compiler shouln't be expected to do that reload driven by the "p" constraint. This patch changes the usage of the "p" constraint in the BPF selftests macros to use the "r" constraint instead. If a register is what is required, we should let the compiler know. Previous discussion in bpf@vger: https://lore.kernel.org/bpf/87h6p5ebpb.fsf@oracle.com/T/#ef0df83d6975c34dff20bf0dd52e078f5b8ca2767 Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Cc: Yonghong Song Cc: Eduard Zingerman Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240123181309.19853-1-jose.marchesi@oracle.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/bpf_misc.h | 2 +- tools/testing/selftests/bpf/progs/iters.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h index 2fd59970c43a..fb2f5513e29e 100644 --- a/tools/testing/selftests/bpf/progs/bpf_misc.h +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h @@ -80,7 +80,7 @@ #define __imm(name) [name]"i"(name) #define __imm_const(name, expr) [name]"i"(expr) #define __imm_addr(name) [name]"i"(&name) -#define __imm_ptr(name) [name]"p"(&name) +#define __imm_ptr(name) [name]"r"(&name) #define __imm_insn(name, expr) [name]"i"(*(long *)&(expr)) /* Magic constants used with __retval() */ diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c index fe971992e635..225f02dd66d0 100644 --- a/tools/testing/selftests/bpf/progs/iters.c +++ b/tools/testing/selftests/bpf/progs/iters.c @@ -78,8 +78,8 @@ int iter_err_unsafe_asm_loop(const void *ctx) "*(u32 *)(r1 + 0) = r6;" /* invalid */ : : [it]"r"(&it), - [small_arr]"p"(small_arr), - [zero]"p"(zero), + [small_arr]"r"(small_arr), + [zero]"r"(zero), __imm(bpf_iter_num_new), __imm(bpf_iter_num_next), __imm(bpf_iter_num_destroy) From d5c16492c66fbfca85f36e42363d32212df5927b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:04:58 +0100 Subject: [PATCH 0225/2255] bpf: Add cookie to perf_event bpf_link_info records At the moment we don't store cookie for perf_event probes, while we do that for the rest of the probes. Adding cookie fields to struct bpf_link_info perf event probe records: perf_event.uprobe perf_event.kprobe perf_event.tracepoint perf_event.perf_event And the code to store that in bpf_link_info struct. Signed-off-by: Jiri Olsa Acked-by: Song Liu Acked-by: Yafang Shao Link: https://lore.kernel.org/r/20240119110505.400573-2-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 6 ++++++ kernel/bpf/syscall.c | 4 ++++ tools/include/uapi/linux/bpf.h | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index a00f8a5623e1..181e74433272 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6582,6 +6582,7 @@ struct bpf_link_info { __aligned_u64 file_name; /* in/out */ __u32 name_len; __u32 offset; /* offset from file_name */ + __u64 cookie; } uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */ struct { __aligned_u64 func_name; /* in/out */ @@ -6589,14 +6590,19 @@ struct bpf_link_info { __u32 offset; /* offset from func_name */ __u64 addr; __u64 missed; + __u64 cookie; } kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */ struct { __aligned_u64 tp_name; /* in/out */ __u32 name_len; + __u32 :32; + __u64 cookie; } tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */ struct { __u64 config; __u32 type; + __u32 :32; + __u64 cookie; } event; /* BPF_PERF_EVENT_EVENT */ }; } perf_event; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index a1f18681721c..13193aaafb64 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -3501,6 +3501,7 @@ static int bpf_perf_link_fill_kprobe(const struct perf_event *event, if (!kallsyms_show_value(current_cred())) addr = 0; info->perf_event.kprobe.addr = addr; + info->perf_event.kprobe.cookie = event->bpf_cookie; return 0; } #endif @@ -3526,6 +3527,7 @@ static int bpf_perf_link_fill_uprobe(const struct perf_event *event, else info->perf_event.type = BPF_PERF_EVENT_UPROBE; info->perf_event.uprobe.offset = offset; + info->perf_event.uprobe.cookie = event->bpf_cookie; return 0; } #endif @@ -3553,6 +3555,7 @@ static int bpf_perf_link_fill_tracepoint(const struct perf_event *event, uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name); ulen = info->perf_event.tracepoint.name_len; info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT; + info->perf_event.tracepoint.cookie = event->bpf_cookie; return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL); } @@ -3561,6 +3564,7 @@ static int bpf_perf_link_fill_perf_event(const struct perf_event *event, { info->perf_event.event.type = event->attr.type; info->perf_event.event.config = event->attr.config; + info->perf_event.event.cookie = event->bpf_cookie; info->perf_event.type = BPF_PERF_EVENT_EVENT; return 0; } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index a00f8a5623e1..181e74433272 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -6582,6 +6582,7 @@ struct bpf_link_info { __aligned_u64 file_name; /* in/out */ __u32 name_len; __u32 offset; /* offset from file_name */ + __u64 cookie; } uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */ struct { __aligned_u64 func_name; /* in/out */ @@ -6589,14 +6590,19 @@ struct bpf_link_info { __u32 offset; /* offset from func_name */ __u64 addr; __u64 missed; + __u64 cookie; } kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */ struct { __aligned_u64 tp_name; /* in/out */ __u32 name_len; + __u32 :32; + __u64 cookie; } tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */ struct { __u64 config; __u32 type; + __u32 :32; + __u64 cookie; } event; /* BPF_PERF_EVENT_EVENT */ }; } perf_event; From 9fd112b1f82b587ffb12fb67dd032f551fdb571a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:04:59 +0100 Subject: [PATCH 0226/2255] bpf: Store cookies in kprobe_multi bpf_link_info data Storing cookies in kprobe_multi bpf_link_info data. The cookies field is optional and if provided it needs to be an array of __u64 with kprobe_multi.count length. Acked-by: Yafang Shao Signed-off-by: Jiri Olsa Acked-by: Song Liu Link: https://lore.kernel.org/r/20240119110505.400573-3-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 1 + kernel/trace/bpf_trace.c | 15 +++++++++++++++ tools/include/uapi/linux/bpf.h | 1 + 3 files changed, 17 insertions(+) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 181e74433272..287d05732668 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6563,6 +6563,7 @@ struct bpf_link_info { __u32 count; /* in/out: kprobe_multi function count */ __u32 flags; __u64 missed; + __aligned_u64 cookies; } kprobe_multi; struct { __aligned_u64 path; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 7ac6c52b25eb..c98c20abaf99 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -2679,6 +2679,7 @@ static void bpf_kprobe_multi_link_dealloc(struct bpf_link *link) static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link, struct bpf_link_info *info) { + u64 __user *ucookies = u64_to_user_ptr(info->kprobe_multi.cookies); u64 __user *uaddrs = u64_to_user_ptr(info->kprobe_multi.addrs); struct bpf_kprobe_multi_link *kmulti_link; u32 ucount = info->kprobe_multi.count; @@ -2686,6 +2687,8 @@ static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link, if (!uaddrs ^ !ucount) return -EINVAL; + if (ucookies && !ucount) + return -EINVAL; kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); info->kprobe_multi.count = kmulti_link->cnt; @@ -2699,6 +2702,18 @@ static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link, else ucount = kmulti_link->cnt; + if (ucookies) { + if (kmulti_link->cookies) { + if (copy_to_user(ucookies, kmulti_link->cookies, ucount * sizeof(u64))) + return -EFAULT; + } else { + for (i = 0; i < ucount; i++) { + if (put_user(0, ucookies + i)) + return -EFAULT; + } + } + } + if (kallsyms_show_value(current_cred())) { if (copy_to_user(uaddrs, kmulti_link->addrs, ucount * sizeof(u64))) return -EFAULT; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 181e74433272..287d05732668 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -6563,6 +6563,7 @@ struct bpf_link_info { __u32 count; /* in/out: kprobe_multi function count */ __u32 flags; __u64 missed; + __aligned_u64 cookies; } kprobe_multi; struct { __aligned_u64 path; From 2adb2e0fcdf3c6d8e28a5a9c33e458e1037ae5ad Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:05:00 +0100 Subject: [PATCH 0227/2255] bpftool: Fix wrong free call in do_show_link The error path frees wrong array, it should be ref_ctr_offsets. Acked-by: Yafang Shao Reviewed-by: Quentin Monnet Fixes: a7795698f8b6 ("bpftool: Add support to display uprobe_multi links") Signed-off-by: Jiri Olsa Acked-by: Song Liu Link: https://lore.kernel.org/r/20240119110505.400573-4-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index cb46667a6b2e..35b6859dd7c3 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -977,7 +977,7 @@ again: cookies = calloc(count, sizeof(__u64)); if (!cookies) { p_err("mem alloc failed"); - free(cookies); + free(ref_ctr_offsets); free(offsets); close(fd); return -ENOMEM; From 59a89706c40c153a74a3a9570b4d696cf9eebb0b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:05:01 +0100 Subject: [PATCH 0228/2255] selftests/bpf: Add cookies check for kprobe_multi fill_link_info test Adding cookies check for kprobe_multi fill_link_info test, plus tests for invalid values related to cookies. Signed-off-by: Jiri Olsa Acked-by: Song Liu Link: https://lore.kernel.org/r/20240119110505.400573-5-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/fill_link_info.c | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c index d4b1901f7879..2c2a02010c0b 100644 --- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c +++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c @@ -19,6 +19,7 @@ static const char *kmulti_syms[] = { }; #define KMULTI_CNT ARRAY_SIZE(kmulti_syms) static __u64 kmulti_addrs[KMULTI_CNT]; +static __u64 kmulti_cookies[] = { 3, 1, 2 }; #define KPROBE_FUNC "bpf_fentry_test1" static __u64 kprobe_addr; @@ -195,11 +196,11 @@ static void test_uprobe_fill_link_info(struct test_fill_link_info *skel, bpf_link__destroy(link); } -static int verify_kmulti_link_info(int fd, bool retprobe) +static int verify_kmulti_link_info(int fd, bool retprobe, bool has_cookies) { + __u64 addrs[KMULTI_CNT], cookies[KMULTI_CNT]; struct bpf_link_info info; __u32 len = sizeof(info); - __u64 addrs[KMULTI_CNT]; int flags, i, err; memset(&info, 0, sizeof(info)); @@ -221,18 +222,22 @@ again: if (!info.kprobe_multi.addrs) { info.kprobe_multi.addrs = ptr_to_u64(addrs); + info.kprobe_multi.cookies = ptr_to_u64(cookies); goto again; } - for (i = 0; i < KMULTI_CNT; i++) + for (i = 0; i < KMULTI_CNT; i++) { ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs"); + ASSERT_EQ(cookies[i], has_cookies ? kmulti_cookies[i] : 0, + "kmulti_cookies_value"); + } return 0; } static void verify_kmulti_invalid_user_buffer(int fd) { + __u64 addrs[KMULTI_CNT], cookies[KMULTI_CNT]; struct bpf_link_info info; __u32 len = sizeof(info); - __u64 addrs[KMULTI_CNT]; int err, i; memset(&info, 0, sizeof(info)); @@ -266,7 +271,20 @@ static void verify_kmulti_invalid_user_buffer(int fd) info.kprobe_multi.count = KMULTI_CNT; info.kprobe_multi.addrs = 0x1; /* invalid addr */ err = bpf_link_get_info_by_fd(fd, &info, &len); - ASSERT_EQ(err, -EFAULT, "invalid_buff"); + ASSERT_EQ(err, -EFAULT, "invalid_buff_addrs"); + + info.kprobe_multi.count = KMULTI_CNT; + info.kprobe_multi.addrs = ptr_to_u64(addrs); + info.kprobe_multi.cookies = 0x1; /* invalid addr */ + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EFAULT, "invalid_buff_cookies"); + + /* cookies && !count */ + info.kprobe_multi.count = 0; + info.kprobe_multi.addrs = ptr_to_u64(NULL); + info.kprobe_multi.cookies = ptr_to_u64(cookies); + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EINVAL, "invalid_cookies_count"); } static int symbols_cmp_r(const void *a, const void *b) @@ -278,13 +296,15 @@ static int symbols_cmp_r(const void *a, const void *b) } static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel, - bool retprobe, bool invalid) + bool retprobe, bool cookies, + bool invalid) { LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); struct bpf_link *link; int link_fd, err; opts.syms = kmulti_syms; + opts.cookies = cookies ? kmulti_cookies : NULL; opts.cnt = KMULTI_CNT; opts.retprobe = retprobe; link = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, NULL, &opts); @@ -293,7 +313,7 @@ static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel, link_fd = bpf_link__fd(link); if (!invalid) { - err = verify_kmulti_link_info(link_fd, retprobe); + err = verify_kmulti_link_info(link_fd, retprobe, cookies); ASSERT_OK(err, "verify_kmulti_link_info"); } else { verify_kmulti_invalid_user_buffer(link_fd); @@ -523,12 +543,16 @@ void test_fill_link_info(void) qsort(kmulti_syms, KMULTI_CNT, sizeof(kmulti_syms[0]), symbols_cmp_r); for (i = 0; i < KMULTI_CNT; i++) kmulti_addrs[i] = ksym_get_addr(kmulti_syms[i]); - if (test__start_subtest("kprobe_multi_link_info")) - test_kprobe_multi_fill_link_info(skel, false, false); - if (test__start_subtest("kretprobe_multi_link_info")) - test_kprobe_multi_fill_link_info(skel, true, false); + if (test__start_subtest("kprobe_multi_link_info")) { + test_kprobe_multi_fill_link_info(skel, false, false, false); + test_kprobe_multi_fill_link_info(skel, false, true, false); + } + if (test__start_subtest("kretprobe_multi_link_info")) { + test_kprobe_multi_fill_link_info(skel, true, false, false); + test_kprobe_multi_fill_link_info(skel, true, true, false); + } if (test__start_subtest("kprobe_multi_invalid_ubuff")) - test_kprobe_multi_fill_link_info(skel, true, true); + test_kprobe_multi_fill_link_info(skel, true, true, true); if (test__start_subtest("uprobe_multi_link_info")) test_uprobe_multi_fill_link_info(skel, false, false); From d74179708473c649c653f1db280e29875a532e99 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:05:02 +0100 Subject: [PATCH 0229/2255] selftests/bpf: Add cookies check for perf_event fill_link_info test Now that we get cookies for perf_event probes, adding tests for cookie for kprobe/uprobe/tracepoint. The perf_event test needs to be added completely and is coming in following change. Signed-off-by: Jiri Olsa Acked-by: Song Liu Link: https://lore.kernel.org/r/20240119110505.400573-6-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/fill_link_info.c | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c index 2c2a02010c0b..20e105001bc3 100644 --- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c +++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c @@ -32,6 +32,8 @@ static noinline void uprobe_func(void) asm volatile (""); } +#define PERF_EVENT_COOKIE 0xdeadbeef + static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long addr, ssize_t offset, ssize_t entry_offset) { @@ -63,6 +65,8 @@ again: ASSERT_EQ(info.perf_event.kprobe.addr, addr + entry_offset, "kprobe_addr"); + ASSERT_EQ(info.perf_event.kprobe.cookie, PERF_EVENT_COOKIE, "kprobe_cookie"); + if (!info.perf_event.kprobe.func_name) { ASSERT_EQ(info.perf_event.kprobe.name_len, 0, "name_len"); info.perf_event.kprobe.func_name = ptr_to_u64(&buf); @@ -82,6 +86,8 @@ again: goto again; } + ASSERT_EQ(info.perf_event.tracepoint.cookie, PERF_EVENT_COOKIE, "tracepoint_cookie"); + err = strncmp(u64_to_ptr(info.perf_event.tracepoint.tp_name), TP_NAME, strlen(TP_NAME)); ASSERT_EQ(err, 0, "cmp_tp_name"); @@ -97,6 +103,8 @@ again: goto again; } + ASSERT_EQ(info.perf_event.uprobe.cookie, PERF_EVENT_COOKIE, "uprobe_cookie"); + err = strncmp(u64_to_ptr(info.perf_event.uprobe.file_name), UPROBE_FILE, strlen(UPROBE_FILE)); ASSERT_EQ(err, 0, "cmp_file_name"); @@ -140,6 +148,7 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts, .attach_mode = PROBE_ATTACH_MODE_LINK, .retprobe = type == BPF_PERF_EVENT_KRETPROBE, + .bpf_cookie = PERF_EVENT_COOKIE, ); ssize_t entry_offset = 0; struct bpf_link *link; @@ -164,10 +173,13 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, static void test_tp_fill_link_info(struct test_fill_link_info *skel) { + DECLARE_LIBBPF_OPTS(bpf_tracepoint_opts, opts, + .bpf_cookie = PERF_EVENT_COOKIE, + ); struct bpf_link *link; int link_fd, err; - link = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME); + link = bpf_program__attach_tracepoint_opts(skel->progs.tp_run, TP_CAT, TP_NAME, &opts); if (!ASSERT_OK_PTR(link, "attach_tp")) return; @@ -180,13 +192,17 @@ static void test_tp_fill_link_info(struct test_fill_link_info *skel) static void test_uprobe_fill_link_info(struct test_fill_link_info *skel, enum bpf_perf_event_type type) { + DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, opts, + .retprobe = type == BPF_PERF_EVENT_URETPROBE, + .bpf_cookie = PERF_EVENT_COOKIE, + ); struct bpf_link *link; int link_fd, err; - link = bpf_program__attach_uprobe(skel->progs.uprobe_run, - type == BPF_PERF_EVENT_URETPROBE, - 0, /* self pid */ - UPROBE_FILE, uprobe_offset); + link = bpf_program__attach_uprobe_opts(skel->progs.uprobe_run, + 0, /* self pid */ + UPROBE_FILE, uprobe_offset, + &opts); if (!ASSERT_OK_PTR(link, "attach_uprobe")) return; From b7896486688af36e3bc5e27a6d5369cc5dcbcf69 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:05:03 +0100 Subject: [PATCH 0230/2255] selftests/bpf: Add fill_link_info test for perf event Adding fill_link_info test for perf event and testing we get its values back through the bpf_link_info interface. Signed-off-by: Jiri Olsa Acked-by: Song Liu Link: https://lore.kernel.org/r/20240119110505.400573-7-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/fill_link_info.c | 40 +++++++++++++++++++ .../selftests/bpf/progs/test_fill_link_info.c | 6 +++ 2 files changed, 46 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c index 20e105001bc3..f3932941bbaa 100644 --- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c +++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c @@ -109,6 +109,11 @@ again: strlen(UPROBE_FILE)); ASSERT_EQ(err, 0, "cmp_file_name"); break; + case BPF_PERF_EVENT_EVENT: + ASSERT_EQ(info.perf_event.event.type, PERF_TYPE_SOFTWARE, "event_type"); + ASSERT_EQ(info.perf_event.event.config, PERF_COUNT_SW_PAGE_FAULTS, "event_config"); + ASSERT_EQ(info.perf_event.event.cookie, PERF_EVENT_COOKIE, "event_cookie"); + break; default: err = -1; break; @@ -189,6 +194,39 @@ static void test_tp_fill_link_info(struct test_fill_link_info *skel) bpf_link__destroy(link); } +static void test_event_fill_link_info(struct test_fill_link_info *skel) +{ + DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, opts, + .bpf_cookie = PERF_EVENT_COOKIE, + ); + struct bpf_link *link; + int link_fd, err, pfd; + struct perf_event_attr attr = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_PAGE_FAULTS, + .freq = 1, + .sample_freq = 1, + .size = sizeof(struct perf_event_attr), + }; + + pfd = syscall(__NR_perf_event_open, &attr, -1 /* pid */, 0 /* cpu 0 */, + -1 /* group id */, 0 /* flags */); + if (!ASSERT_GE(pfd, 0, "perf_event_open")) + return; + + link = bpf_program__attach_perf_event_opts(skel->progs.event_run, pfd, &opts); + if (!ASSERT_OK_PTR(link, "attach_event")) + goto error; + + link_fd = bpf_link__fd(link); + err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_EVENT, 0, 0, 0); + ASSERT_OK(err, "verify_perf_link_info"); + bpf_link__destroy(link); + +error: + close(pfd); +} + static void test_uprobe_fill_link_info(struct test_fill_link_info *skel, enum bpf_perf_event_type type) { @@ -549,6 +587,8 @@ void test_fill_link_info(void) test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, true); if (test__start_subtest("tracepoint_link_info")) test_tp_fill_link_info(skel); + if (test__start_subtest("event_link_info")) + test_event_fill_link_info(skel); uprobe_offset = get_uprobe_offset(&uprobe_func); if (test__start_subtest("uprobe_link_info")) diff --git a/tools/testing/selftests/bpf/progs/test_fill_link_info.c b/tools/testing/selftests/bpf/progs/test_fill_link_info.c index 69509f8bb680..6afa834756e9 100644 --- a/tools/testing/selftests/bpf/progs/test_fill_link_info.c +++ b/tools/testing/selftests/bpf/progs/test_fill_link_info.c @@ -33,6 +33,12 @@ int BPF_PROG(tp_run) return 0; } +SEC("perf_event") +int event_run(void *ctx) +{ + return 0; +} + SEC("kprobe.multi") int BPF_PROG(kmulti_run) { From 54258324b934aa8552c239c443272ec7aea55285 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:05:04 +0100 Subject: [PATCH 0231/2255] bpftool: Display cookie for perf event link probes Displaying cookie for perf event link probes, in plain mode: # bpftool link 17: perf_event prog 90 kprobe ffffffff82b1c2b0 bpf_fentry_test1 cookie 3735928559 18: perf_event prog 90 kretprobe ffffffff82b1c2b0 bpf_fentry_test1 cookie 3735928559 20: perf_event prog 92 tracepoint sched_switch cookie 3735928559 21: perf_event prog 93 event software:page-faults cookie 3735928559 22: perf_event prog 91 uprobe /proc/self/exe+0xd703c cookie 3735928559 And in json mode: # bpftool link -j | jq { "id": 30, "type": "perf_event", "prog_id": 160, "retprobe": false, "addr": 18446744071607272112, "func": "bpf_fentry_test1", "offset": 0, "missed": 0, "cookie": 3735928559 } { "id": 33, "type": "perf_event", "prog_id": 162, "tracepoint": "sched_switch", "cookie": 3735928559 } { "id": 34, "type": "perf_event", "prog_id": 163, "event_type": "software", "event_config": "page-faults", "cookie": 3735928559 } { "id": 35, "type": "perf_event", "prog_id": 161, "retprobe": false, "file": "/proc/self/exe", "offset": 880700, "cookie": 3735928559 } Reviewed-by: Quentin Monnet Signed-off-by: Jiri Olsa Acked-by: Song Liu Link: https://lore.kernel.org/r/20240119110505.400573-8-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/link.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index 35b6859dd7c3..b66a1598b87c 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -334,6 +334,7 @@ show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) u64_to_ptr(info->perf_event.kprobe.func_name)); jsonw_uint_field(wtr, "offset", info->perf_event.kprobe.offset); jsonw_uint_field(wtr, "missed", info->perf_event.kprobe.missed); + jsonw_uint_field(wtr, "cookie", info->perf_event.kprobe.cookie); } static void @@ -343,6 +344,7 @@ show_perf_event_uprobe_json(struct bpf_link_info *info, json_writer_t *wtr) jsonw_string_field(wtr, "file", u64_to_ptr(info->perf_event.uprobe.file_name)); jsonw_uint_field(wtr, "offset", info->perf_event.uprobe.offset); + jsonw_uint_field(wtr, "cookie", info->perf_event.uprobe.cookie); } static void @@ -350,6 +352,7 @@ show_perf_event_tracepoint_json(struct bpf_link_info *info, json_writer_t *wtr) { jsonw_string_field(wtr, "tracepoint", u64_to_ptr(info->perf_event.tracepoint.tp_name)); + jsonw_uint_field(wtr, "cookie", info->perf_event.tracepoint.cookie); } static char *perf_config_hw_cache_str(__u64 config) @@ -426,6 +429,8 @@ show_perf_event_event_json(struct bpf_link_info *info, json_writer_t *wtr) else jsonw_uint_field(wtr, "event_config", config); + jsonw_uint_field(wtr, "cookie", info->perf_event.event.cookie); + if (type == PERF_TYPE_HW_CACHE && perf_config) free((void *)perf_config); } @@ -754,6 +759,8 @@ static void show_perf_event_kprobe_plain(struct bpf_link_info *info) printf("+%#x", info->perf_event.kprobe.offset); if (info->perf_event.kprobe.missed) printf(" missed %llu", info->perf_event.kprobe.missed); + if (info->perf_event.kprobe.cookie) + printf(" cookie %llu", info->perf_event.kprobe.cookie); printf(" "); } @@ -770,6 +777,8 @@ static void show_perf_event_uprobe_plain(struct bpf_link_info *info) else printf("\n\tuprobe "); printf("%s+%#x ", buf, info->perf_event.uprobe.offset); + if (info->perf_event.uprobe.cookie) + printf("cookie %llu ", info->perf_event.uprobe.cookie); } static void show_perf_event_tracepoint_plain(struct bpf_link_info *info) @@ -781,6 +790,8 @@ static void show_perf_event_tracepoint_plain(struct bpf_link_info *info) return; printf("\n\ttracepoint %s ", buf); + if (info->perf_event.tracepoint.cookie) + printf("cookie %llu ", info->perf_event.tracepoint.cookie); } static void show_perf_event_event_plain(struct bpf_link_info *info) @@ -802,6 +813,9 @@ static void show_perf_event_event_plain(struct bpf_link_info *info) else printf("%llu ", config); + if (info->perf_event.event.cookie) + printf("cookie %llu ", info->perf_event.event.cookie); + if (type == PERF_TYPE_HW_CACHE && perf_config) free((void *)perf_config); } From b0dc037399b19a777d569dbd9e2e9bbd62f3b3b1 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 19 Jan 2024 12:05:05 +0100 Subject: [PATCH 0232/2255] bpftool: Display cookie for kprobe multi link Displaying cookies for kprobe multi link, in plain mode: # bpftool link ... 1397: kprobe_multi prog 47532 kretprobe.multi func_cnt 3 addr cookie func [module] ffffffff82b370c0 3 bpf_fentry_test1 ffffffff82b39780 1 bpf_fentry_test2 ffffffff82b397a0 2 bpf_fentry_test3 And in json mode: # bpftool link -j | jq ... { "id": 1397, "type": "kprobe_multi", "prog_id": 47532, "retprobe": true, "func_cnt": 3, "missed": 0, "funcs": [ { "addr": 18446744071607382208, "func": "bpf_fentry_test1", "module": null, "cookie": 3 }, { "addr": 18446744071607392128, "func": "bpf_fentry_test2", "module": null, "cookie": 1 }, { "addr": 18446744071607392160, "func": "bpf_fentry_test3", "module": null, "cookie": 2 } ] } Cookie is attached to specific address, and because we sort addresses before printing, we need to sort cookies the same way, hence adding the struct addr_cookie to keep and sort them together. Also adding missing dd.sym_count check to show_kprobe_multi_json. Signed-off-by: Jiri Olsa Acked-by: Song Liu Link: https://lore.kernel.org/r/20240119110505.400573-9-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/link.c | 80 ++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index b66a1598b87c..afde9d0c2ea1 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -249,18 +249,44 @@ static int get_prog_info(int prog_id, struct bpf_prog_info *info) return err; } -static int cmp_u64(const void *A, const void *B) -{ - const __u64 *a = A, *b = B; +struct addr_cookie { + __u64 addr; + __u64 cookie; +}; - return *a - *b; +static int cmp_addr_cookie(const void *A, const void *B) +{ + const struct addr_cookie *a = A, *b = B; + + if (a->addr == b->addr) + return 0; + return a->addr < b->addr ? -1 : 1; +} + +static struct addr_cookie * +get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count) +{ + struct addr_cookie *data; + __u32 i; + + data = calloc(count, sizeof(data[0])); + if (!data) { + p_err("mem alloc failed"); + return NULL; + } + for (i = 0; i < count; i++) { + data[i].addr = addrs[i]; + data[i].cookie = cookies[i]; + } + qsort(data, count, sizeof(data[0]), cmp_addr_cookie); + return data; } static void show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) { + struct addr_cookie *data; __u32 i, j = 0; - __u64 *addrs; jsonw_bool_field(json_wtr, "retprobe", info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN); @@ -268,14 +294,20 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) jsonw_uint_field(json_wtr, "missed", info->kprobe_multi.missed); jsonw_name(json_wtr, "funcs"); jsonw_start_array(json_wtr); - addrs = u64_to_ptr(info->kprobe_multi.addrs); - qsort(addrs, info->kprobe_multi.count, sizeof(addrs[0]), cmp_u64); + data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs), + u64_to_ptr(info->kprobe_multi.cookies), + info->kprobe_multi.count); + if (!data) + return; /* Load it once for all. */ if (!dd.sym_count) kernel_syms_load(&dd); + if (!dd.sym_count) + goto error; + for (i = 0; i < dd.sym_count; i++) { - if (dd.sym_mapping[i].address != addrs[j]) + if (dd.sym_mapping[i].address != data[j].addr) continue; jsonw_start_object(json_wtr); jsonw_uint_field(json_wtr, "addr", dd.sym_mapping[i].address); @@ -287,11 +319,14 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) } else { jsonw_string_field(json_wtr, "module", dd.sym_mapping[i].module); } + jsonw_uint_field(json_wtr, "cookie", data[j].cookie); jsonw_end_object(json_wtr); if (j++ == info->kprobe_multi.count) break; } jsonw_end_array(json_wtr); +error: + free(data); } static __u64 *u64_to_arr(__u64 val) @@ -675,8 +710,8 @@ void netfilter_dump_plain(const struct bpf_link_info *info) static void show_kprobe_multi_plain(struct bpf_link_info *info) { + struct addr_cookie *data; __u32 i, j = 0; - __u64 *addrs; if (!info->kprobe_multi.count) return; @@ -688,21 +723,24 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) printf("func_cnt %u ", info->kprobe_multi.count); if (info->kprobe_multi.missed) printf("missed %llu ", info->kprobe_multi.missed); - addrs = (__u64 *)u64_to_ptr(info->kprobe_multi.addrs); - qsort(addrs, info->kprobe_multi.count, sizeof(__u64), cmp_u64); + data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs), + u64_to_ptr(info->kprobe_multi.cookies), + info->kprobe_multi.count); + if (!data) + return; /* Load it once for all. */ if (!dd.sym_count) kernel_syms_load(&dd); if (!dd.sym_count) - return; + goto error; - printf("\n\t%-16s %s", "addr", "func [module]"); + printf("\n\t%-16s %-16s %s", "addr", "cookie", "func [module]"); for (i = 0; i < dd.sym_count; i++) { - if (dd.sym_mapping[i].address != addrs[j]) + if (dd.sym_mapping[i].address != data[j].addr) continue; - printf("\n\t%016lx %s", - dd.sym_mapping[i].address, dd.sym_mapping[i].name); + printf("\n\t%016lx %-16llx %s", + dd.sym_mapping[i].address, data[j].cookie, dd.sym_mapping[i].name); if (dd.sym_mapping[i].module[0] != '\0') printf(" [%s] ", dd.sym_mapping[i].module); else @@ -711,6 +749,8 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) if (j++ == info->kprobe_multi.count) break; } +error: + free(data); } static void show_uprobe_multi_plain(struct bpf_link_info *info) @@ -966,6 +1006,14 @@ again: return -ENOMEM; } info.kprobe_multi.addrs = ptr_to_u64(addrs); + cookies = calloc(count, sizeof(__u64)); + if (!cookies) { + p_err("mem alloc failed"); + free(addrs); + close(fd); + return -ENOMEM; + } + info.kprobe_multi.cookies = ptr_to_u64(cookies); goto again; } } From 3b1f89e747cd4b24244f2798a35d28815b744303 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:52 -0800 Subject: [PATCH 0233/2255] bpf: refactory struct_ops type initialization to a function. Move the majority of the code to bpf_struct_ops_init_one(), which can then be utilized for the initialization of newly registered dynamically allocated struct_ops types in the following patches. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-2-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/btf.h | 1 + kernel/bpf/bpf_struct_ops.c | 163 +++++++++++++++++++----------------- kernel/bpf/btf.c | 5 ++ 3 files changed, 92 insertions(+), 77 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index cf5c6ff48981..932af1680bb5 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -137,6 +137,7 @@ struct btf_struct_metas { extern const struct file_operations btf_fops; +const char *btf_get_name(const struct btf *btf); void btf_get(struct btf *btf); void btf_put(struct btf *btf); int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_sz); diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 02068bd0e4d9..96cba76f4ac3 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -110,15 +110,95 @@ const struct bpf_prog_ops bpf_struct_ops_prog_ops = { static const struct btf_type *module_type; -void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) +static void bpf_struct_ops_init_one(struct bpf_struct_ops *st_ops, + struct btf *btf, + struct bpf_verifier_log *log) { - s32 type_id, value_id, module_id; const struct btf_member *member; - struct bpf_struct_ops *st_ops; const struct btf_type *t; + s32 type_id, value_id; char value_name[128]; const char *mname; - u32 i, j; + int i; + + if (strlen(st_ops->name) + VALUE_PREFIX_LEN >= + sizeof(value_name)) { + pr_warn("struct_ops name %s is too long\n", + st_ops->name); + return; + } + sprintf(value_name, "%s%s", VALUE_PREFIX, st_ops->name); + + value_id = btf_find_by_name_kind(btf, value_name, + BTF_KIND_STRUCT); + if (value_id < 0) { + pr_warn("Cannot find struct %s in %s\n", + value_name, btf_get_name(btf)); + return; + } + + type_id = btf_find_by_name_kind(btf, st_ops->name, + BTF_KIND_STRUCT); + if (type_id < 0) { + pr_warn("Cannot find struct %s in %s\n", + st_ops->name, btf_get_name(btf)); + return; + } + t = btf_type_by_id(btf, type_id); + if (btf_type_vlen(t) > BPF_STRUCT_OPS_MAX_NR_MEMBERS) { + pr_warn("Cannot support #%u members in struct %s\n", + btf_type_vlen(t), st_ops->name); + return; + } + + for_each_member(i, t, member) { + const struct btf_type *func_proto; + + mname = btf_name_by_offset(btf, member->name_off); + if (!*mname) { + pr_warn("anon member in struct %s is not supported\n", + st_ops->name); + break; + } + + if (__btf_member_bitfield_size(t, member)) { + pr_warn("bit field member %s in struct %s is not supported\n", + mname, st_ops->name); + break; + } + + func_proto = btf_type_resolve_func_ptr(btf, + member->type, + NULL); + if (func_proto && + btf_distill_func_proto(log, btf, + func_proto, mname, + &st_ops->func_models[i])) { + pr_warn("Error in parsing func ptr %s in struct %s\n", + mname, st_ops->name); + break; + } + } + + if (i == btf_type_vlen(t)) { + if (st_ops->init(btf)) { + pr_warn("Error in init bpf_struct_ops %s\n", + st_ops->name); + } else { + st_ops->type_id = type_id; + st_ops->type = t; + st_ops->value_id = value_id; + st_ops->value_type = btf_type_by_id(btf, + value_id); + } + } +} + +void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) +{ + struct bpf_struct_ops *st_ops; + s32 module_id; + u32 i; /* Ensure BTF type is emitted for "struct bpf_struct_ops_##_name" */ #define BPF_STRUCT_OPS_TYPE(_name) BTF_TYPE_EMIT(struct bpf_struct_ops_##_name); @@ -127,85 +207,14 @@ void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) module_id = btf_find_by_name_kind(btf, "module", BTF_KIND_STRUCT); if (module_id < 0) { - pr_warn("Cannot find struct module in btf_vmlinux\n"); + pr_warn("Cannot find struct module in %s\n", btf_get_name(btf)); return; } module_type = btf_type_by_id(btf, module_id); for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { st_ops = bpf_struct_ops[i]; - - if (strlen(st_ops->name) + VALUE_PREFIX_LEN >= - sizeof(value_name)) { - pr_warn("struct_ops name %s is too long\n", - st_ops->name); - continue; - } - sprintf(value_name, "%s%s", VALUE_PREFIX, st_ops->name); - - value_id = btf_find_by_name_kind(btf, value_name, - BTF_KIND_STRUCT); - if (value_id < 0) { - pr_warn("Cannot find struct %s in btf_vmlinux\n", - value_name); - continue; - } - - type_id = btf_find_by_name_kind(btf, st_ops->name, - BTF_KIND_STRUCT); - if (type_id < 0) { - pr_warn("Cannot find struct %s in btf_vmlinux\n", - st_ops->name); - continue; - } - t = btf_type_by_id(btf, type_id); - if (btf_type_vlen(t) > BPF_STRUCT_OPS_MAX_NR_MEMBERS) { - pr_warn("Cannot support #%u members in struct %s\n", - btf_type_vlen(t), st_ops->name); - continue; - } - - for_each_member(j, t, member) { - const struct btf_type *func_proto; - - mname = btf_name_by_offset(btf, member->name_off); - if (!*mname) { - pr_warn("anon member in struct %s is not supported\n", - st_ops->name); - break; - } - - if (__btf_member_bitfield_size(t, member)) { - pr_warn("bit field member %s in struct %s is not supported\n", - mname, st_ops->name); - break; - } - - func_proto = btf_type_resolve_func_ptr(btf, - member->type, - NULL); - if (func_proto && - btf_distill_func_proto(log, btf, - func_proto, mname, - &st_ops->func_models[j])) { - pr_warn("Error in parsing func ptr %s in struct %s\n", - mname, st_ops->name); - break; - } - } - - if (j == btf_type_vlen(t)) { - if (st_ops->init(btf)) { - pr_warn("Error in init bpf_struct_ops %s\n", - st_ops->name); - } else { - st_ops->type_id = type_id; - st_ops->type = t; - st_ops->value_id = value_id; - st_ops->value_type = btf_type_by_id(btf, - value_id); - } - } + bpf_struct_ops_init_one(st_ops, btf, log); } } diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 4f532b303a27..f8735a2ec5d4 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -1707,6 +1707,11 @@ static void btf_free_rcu(struct rcu_head *rcu) btf_free(btf); } +const char *btf_get_name(const struct btf *btf) +{ + return btf->name; +} + void btf_get(struct btf *btf) { refcount_inc(&btf->refcnt); From 95678395386d45fa0a075d2e7a6866326a469d76 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:53 -0800 Subject: [PATCH 0234/2255] bpf: get type information with BTF_ID_LIST Get ready to remove bpf_struct_ops_init() in the future. By using BTF_ID_LIST, it is possible to gather type information while building instead of runtime. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-3-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/bpf_struct_ops.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 96cba76f4ac3..5b3ebcb435d0 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -108,7 +108,12 @@ const struct bpf_prog_ops bpf_struct_ops_prog_ops = { #endif }; -static const struct btf_type *module_type; +BTF_ID_LIST(st_ops_ids) +BTF_ID(struct, module) + +enum { + IDX_MODULE_ID, +}; static void bpf_struct_ops_init_one(struct bpf_struct_ops *st_ops, struct btf *btf, @@ -197,7 +202,6 @@ static void bpf_struct_ops_init_one(struct bpf_struct_ops *st_ops, void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) { struct bpf_struct_ops *st_ops; - s32 module_id; u32 i; /* Ensure BTF type is emitted for "struct bpf_struct_ops_##_name" */ @@ -205,13 +209,6 @@ void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) #include "bpf_struct_ops_types.h" #undef BPF_STRUCT_OPS_TYPE - module_id = btf_find_by_name_kind(btf, "module", BTF_KIND_STRUCT); - if (module_id < 0) { - pr_warn("Cannot find struct module in %s\n", btf_get_name(btf)); - return; - } - module_type = btf_type_by_id(btf, module_id); - for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { st_ops = bpf_struct_ops[i]; bpf_struct_ops_init_one(st_ops, btf, log); @@ -387,6 +384,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; const struct bpf_struct_ops *st_ops = st_map->st_ops; struct bpf_struct_ops_value *uvalue, *kvalue; + const struct btf_type *module_type; const struct btf_member *member; const struct btf_type *t = st_ops->type; struct bpf_tramp_links *tlinks; @@ -434,6 +432,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, image = st_map->image; image_end = st_map->image + PAGE_SIZE; + module_type = btf_type_by_id(btf_vmlinux, st_ops_ids[IDX_MODULE_ID]); for_each_member(i, t, member) { const struct btf_type *mtype, *ptype; struct bpf_prog *prog; From 4c5763ed996a61b51d721d0968d0df957826ea49 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:54 -0800 Subject: [PATCH 0235/2255] bpf, net: introduce bpf_struct_ops_desc. Move some of members of bpf_struct_ops to bpf_struct_ops_desc. type_id is unavailabe in bpf_struct_ops anymore. Modules should get it from the btf received by kmod's init function. Cc: netdev@vger.kernel.org Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-4-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 15 ++++--- kernel/bpf/bpf_struct_ops.c | 80 +++++++++++++++++----------------- kernel/bpf/verifier.c | 8 ++-- net/bpf/bpf_dummy_struct_ops.c | 11 ++++- net/ipv4/bpf_tcp_ca.c | 8 +++- 5 files changed, 73 insertions(+), 49 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 377857b232c6..7fc95e7babab 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1673,18 +1673,23 @@ struct bpf_struct_ops { void (*unreg)(void *kdata); int (*update)(void *kdata, void *old_kdata); int (*validate)(void *kdata); - const struct btf_type *type; - const struct btf_type *value_type; + void *cfi_stubs; const char *name; struct btf_func_model func_models[BPF_STRUCT_OPS_MAX_NR_MEMBERS]; +}; + +struct bpf_struct_ops_desc { + struct bpf_struct_ops *st_ops; + + const struct btf_type *type; + const struct btf_type *value_type; u32 type_id; u32 value_id; - void *cfi_stubs; }; #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL) #define BPF_MODULE_OWNER ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA)) -const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id); +const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id); void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log); bool bpf_struct_ops_get(const void *kdata); void bpf_struct_ops_put(const void *kdata); @@ -1728,7 +1733,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, union bpf_attr __user *uattr); #endif #else -static inline const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id) +static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id) { return NULL; } diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 5b3ebcb435d0..9774f7824e8b 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -32,7 +32,7 @@ struct bpf_struct_ops_value { struct bpf_struct_ops_map { struct bpf_map map; struct rcu_head rcu; - const struct bpf_struct_ops *st_ops; + const struct bpf_struct_ops_desc *st_ops_desc; /* protect map_update */ struct mutex lock; /* link has all the bpf_links that is populated @@ -92,9 +92,9 @@ enum { __NR_BPF_STRUCT_OPS_TYPE, }; -static struct bpf_struct_ops * const bpf_struct_ops[] = { +static struct bpf_struct_ops_desc bpf_struct_ops[] = { #define BPF_STRUCT_OPS_TYPE(_name) \ - [BPF_STRUCT_OPS_TYPE_##_name] = &bpf_##_name, + [BPF_STRUCT_OPS_TYPE_##_name] = { .st_ops = &bpf_##_name }, #include "bpf_struct_ops_types.h" #undef BPF_STRUCT_OPS_TYPE }; @@ -115,10 +115,11 @@ enum { IDX_MODULE_ID, }; -static void bpf_struct_ops_init_one(struct bpf_struct_ops *st_ops, - struct btf *btf, - struct bpf_verifier_log *log) +static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, + struct btf *btf, + struct bpf_verifier_log *log) { + struct bpf_struct_ops *st_ops = st_ops_desc->st_ops; const struct btf_member *member; const struct btf_type *t; s32 type_id, value_id; @@ -190,18 +191,18 @@ static void bpf_struct_ops_init_one(struct bpf_struct_ops *st_ops, pr_warn("Error in init bpf_struct_ops %s\n", st_ops->name); } else { - st_ops->type_id = type_id; - st_ops->type = t; - st_ops->value_id = value_id; - st_ops->value_type = btf_type_by_id(btf, - value_id); + st_ops_desc->type_id = type_id; + st_ops_desc->type = t; + st_ops_desc->value_id = value_id; + st_ops_desc->value_type = btf_type_by_id(btf, + value_id); } } } void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) { - struct bpf_struct_ops *st_ops; + struct bpf_struct_ops_desc *st_ops_desc; u32 i; /* Ensure BTF type is emitted for "struct bpf_struct_ops_##_name" */ @@ -210,14 +211,14 @@ void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) #undef BPF_STRUCT_OPS_TYPE for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { - st_ops = bpf_struct_ops[i]; - bpf_struct_ops_init_one(st_ops, btf, log); + st_ops_desc = &bpf_struct_ops[i]; + bpf_struct_ops_desc_init(st_ops_desc, btf, log); } } extern struct btf *btf_vmlinux; -static const struct bpf_struct_ops * +static const struct bpf_struct_ops_desc * bpf_struct_ops_find_value(u32 value_id) { unsigned int i; @@ -226,14 +227,14 @@ bpf_struct_ops_find_value(u32 value_id) return NULL; for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { - if (bpf_struct_ops[i]->value_id == value_id) - return bpf_struct_ops[i]; + if (bpf_struct_ops[i].value_id == value_id) + return &bpf_struct_ops[i]; } return NULL; } -const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id) +const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id) { unsigned int i; @@ -241,8 +242,8 @@ const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id) return NULL; for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { - if (bpf_struct_ops[i]->type_id == type_id) - return bpf_struct_ops[i]; + if (bpf_struct_ops[i].type_id == type_id) + return &bpf_struct_ops[i]; } return NULL; @@ -302,7 +303,7 @@ static void *bpf_struct_ops_map_lookup_elem(struct bpf_map *map, void *key) static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map) { - const struct btf_type *t = st_map->st_ops->type; + const struct btf_type *t = st_map->st_ops_desc->type; u32 i; for (i = 0; i < btf_type_vlen(t); i++) { @@ -382,11 +383,12 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, void *value, u64 flags) { struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; - const struct bpf_struct_ops *st_ops = st_map->st_ops; + const struct bpf_struct_ops_desc *st_ops_desc = st_map->st_ops_desc; + const struct bpf_struct_ops *st_ops = st_ops_desc->st_ops; struct bpf_struct_ops_value *uvalue, *kvalue; const struct btf_type *module_type; const struct btf_member *member; - const struct btf_type *t = st_ops->type; + const struct btf_type *t = st_ops_desc->type; struct bpf_tramp_links *tlinks; void *udata, *kdata; int prog_fd, err; @@ -399,7 +401,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, if (*(u32 *)key != 0) return -E2BIG; - err = check_zero_holes(st_ops->value_type, value); + err = check_zero_holes(st_ops_desc->value_type, value); if (err) return err; @@ -492,7 +494,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, } if (prog->type != BPF_PROG_TYPE_STRUCT_OPS || - prog->aux->attach_btf_id != st_ops->type_id || + prog->aux->attach_btf_id != st_ops_desc->type_id || prog->expected_attach_type != i) { bpf_prog_put(prog); err = -EINVAL; @@ -588,7 +590,7 @@ static long bpf_struct_ops_map_delete_elem(struct bpf_map *map, void *key) BPF_STRUCT_OPS_STATE_TOBEFREE); switch (prev_state) { case BPF_STRUCT_OPS_STATE_INUSE: - st_map->st_ops->unreg(&st_map->kvalue.data); + st_map->st_ops_desc->st_ops->unreg(&st_map->kvalue.data); bpf_map_put(map); return 0; case BPF_STRUCT_OPS_STATE_TOBEFREE: @@ -669,22 +671,22 @@ static int bpf_struct_ops_map_alloc_check(union bpf_attr *attr) static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) { - const struct bpf_struct_ops *st_ops; + const struct bpf_struct_ops_desc *st_ops_desc; size_t st_map_size; struct bpf_struct_ops_map *st_map; const struct btf_type *t, *vt; struct bpf_map *map; int ret; - st_ops = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id); - if (!st_ops) + st_ops_desc = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id); + if (!st_ops_desc) return ERR_PTR(-ENOTSUPP); - vt = st_ops->value_type; + vt = st_ops_desc->value_type; if (attr->value_size != vt->size) return ERR_PTR(-EINVAL); - t = st_ops->type; + t = st_ops_desc->type; st_map_size = sizeof(*st_map) + /* kvalue stores the @@ -696,7 +698,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) if (!st_map) return ERR_PTR(-ENOMEM); - st_map->st_ops = st_ops; + st_map->st_ops_desc = st_ops_desc; map = &st_map->map; ret = bpf_jit_charge_modmem(PAGE_SIZE); @@ -733,8 +735,8 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) static u64 bpf_struct_ops_map_mem_usage(const struct bpf_map *map) { struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; - const struct bpf_struct_ops *st_ops = st_map->st_ops; - const struct btf_type *vt = st_ops->value_type; + const struct bpf_struct_ops_desc *st_ops_desc = st_map->st_ops_desc; + const struct btf_type *vt = st_ops_desc->value_type; u64 usage; usage = sizeof(*st_map) + @@ -808,7 +810,7 @@ static void bpf_struct_ops_map_link_dealloc(struct bpf_link *link) /* st_link->map can be NULL if * bpf_struct_ops_link_create() fails to register. */ - st_map->st_ops->unreg(&st_map->kvalue.data); + st_map->st_ops_desc->st_ops->unreg(&st_map->kvalue.data); bpf_map_put(&st_map->map); } kfree(st_link); @@ -855,7 +857,7 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map if (!bpf_struct_ops_valid_to_reg(new_map)) return -EINVAL; - if (!st_map->st_ops->update) + if (!st_map->st_ops_desc->st_ops->update) return -EOPNOTSUPP; mutex_lock(&update_mutex); @@ -868,12 +870,12 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map old_st_map = container_of(old_map, struct bpf_struct_ops_map, map); /* The new and old struct_ops must be the same type. */ - if (st_map->st_ops != old_st_map->st_ops) { + if (st_map->st_ops_desc != old_st_map->st_ops_desc) { err = -EINVAL; goto err_out; } - err = st_map->st_ops->update(st_map->kvalue.data, old_st_map->kvalue.data); + err = st_map->st_ops_desc->st_ops->update(st_map->kvalue.data, old_st_map->kvalue.data); if (err) goto err_out; @@ -924,7 +926,7 @@ int bpf_struct_ops_link_create(union bpf_attr *attr) if (err) goto err_out; - err = st_map->st_ops->reg(st_map->kvalue.data); + err = st_map->st_ops_desc->st_ops->reg(st_map->kvalue.data); if (err) { bpf_link_cleanup(&link_primer); link = NULL; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9e9cc132dd02..e279491118b7 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20285,6 +20285,7 @@ static void print_verification_stats(struct bpf_verifier_env *env) static int check_struct_ops_btf_id(struct bpf_verifier_env *env) { const struct btf_type *t, *func_proto; + const struct bpf_struct_ops_desc *st_ops_desc; const struct bpf_struct_ops *st_ops; const struct btf_member *member; struct bpf_prog *prog = env->prog; @@ -20297,14 +20298,15 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) } btf_id = prog->aux->attach_btf_id; - st_ops = bpf_struct_ops_find(btf_id); - if (!st_ops) { + st_ops_desc = bpf_struct_ops_find(btf_id); + if (!st_ops_desc) { verbose(env, "attach_btf_id %u is not a supported struct\n", btf_id); return -ENOTSUPP; } + st_ops = st_ops_desc->st_ops; - t = st_ops->type; + t = st_ops_desc->type; member_idx = prog->expected_attach_type; if (member_idx >= btf_type_vlen(t)) { verbose(env, "attach to invalid member idx %u of struct %s\n", diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c index 8906f7bdf4a9..ba2c58dba2da 100644 --- a/net/bpf/bpf_dummy_struct_ops.c +++ b/net/bpf/bpf_dummy_struct_ops.c @@ -22,6 +22,8 @@ struct bpf_dummy_ops_test_args { struct bpf_dummy_ops_state state; }; +static struct btf *bpf_dummy_ops_btf; + static struct bpf_dummy_ops_test_args * dummy_ops_init_args(const union bpf_attr *kattr, unsigned int nr) { @@ -90,9 +92,15 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, void *image = NULL; unsigned int op_idx; int prog_ret; + s32 type_id; int err; - if (prog->aux->attach_btf_id != st_ops->type_id) + type_id = btf_find_by_name_kind(bpf_dummy_ops_btf, + bpf_bpf_dummy_ops.name, + BTF_KIND_STRUCT); + if (type_id < 0) + return -EINVAL; + if (prog->aux->attach_btf_id != type_id) return -EOPNOTSUPP; func_proto = prog->aux->attach_func_proto; @@ -148,6 +156,7 @@ out: static int bpf_dummy_init(struct btf *btf) { + bpf_dummy_ops_btf = btf; return 0; } diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c index ae8b15e6896f..dffd8828079b 100644 --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c @@ -20,6 +20,7 @@ static u32 unsupported_ops[] = { static const struct btf_type *tcp_sock_type; static u32 tcp_sock_id, sock_id; +static const struct btf_type *tcp_congestion_ops_type; static int bpf_tcp_ca_init(struct btf *btf) { @@ -36,6 +37,11 @@ static int bpf_tcp_ca_init(struct btf *btf) tcp_sock_id = type_id; tcp_sock_type = btf_type_by_id(btf, tcp_sock_id); + type_id = btf_find_by_name_kind(btf, "tcp_congestion_ops", BTF_KIND_STRUCT); + if (type_id < 0) + return -EINVAL; + tcp_congestion_ops_type = btf_type_by_id(btf, type_id); + return 0; } @@ -149,7 +155,7 @@ static u32 prog_ops_moff(const struct bpf_prog *prog) u32 midx; midx = prog->expected_attach_type; - t = bpf_tcp_congestion_ops.type; + t = tcp_congestion_ops_type; m = &btf_type_member(t)[midx]; return __btf_member_bit_offset(t, m) / 8; From e61995111a76633376419d1bccede8696e94e6e5 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:55 -0800 Subject: [PATCH 0236/2255] bpf: add struct_ops_tab to btf. Maintain a registry of registered struct_ops types in the per-btf (module) struct_ops_tab. This registry allows for easy lookup of struct_ops types that are registered by a specific module. It is a preparation work for supporting kernel module struct_ops in a latter patch. Each struct_ops will be registered under its own kernel module btf and will be stored in the newly added btf->struct_ops_tab. The bpf verifier and bpf syscall (e.g. prog and map cmd) can find the struct_ops and its btf type/size/id... information from btf->struct_ops_tab. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-5-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/btf.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index f8735a2ec5d4..2e5e6ec5d965 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -241,6 +241,12 @@ struct btf_id_dtor_kfunc_tab { struct btf_id_dtor_kfunc dtors[]; }; +struct btf_struct_ops_tab { + u32 cnt; + u32 capacity; + struct bpf_struct_ops_desc ops[]; +}; + struct btf { void *data; struct btf_type **types; @@ -258,6 +264,7 @@ struct btf { struct btf_kfunc_set_tab *kfunc_set_tab; struct btf_id_dtor_kfunc_tab *dtor_kfunc_tab; struct btf_struct_metas *struct_meta_tab; + struct btf_struct_ops_tab *struct_ops_tab; /* split BTF support */ struct btf *base_btf; @@ -1688,11 +1695,20 @@ static void btf_free_struct_meta_tab(struct btf *btf) btf->struct_meta_tab = NULL; } +static void btf_free_struct_ops_tab(struct btf *btf) +{ + struct btf_struct_ops_tab *tab = btf->struct_ops_tab; + + kfree(tab); + btf->struct_ops_tab = NULL; +} + static void btf_free(struct btf *btf) { btf_free_struct_meta_tab(btf); btf_free_dtor_kfunc_tab(btf); btf_free_kfunc_set_tab(btf); + btf_free_struct_ops_tab(btf); kvfree(btf->types); kvfree(btf->resolved_sizes); kvfree(btf->resolved_ids); @@ -8689,3 +8705,42 @@ bool btf_type_ids_nocast_alias(struct bpf_verifier_log *log, return !strncmp(reg_name, arg_name, cmp_len); } + +static int +btf_add_struct_ops(struct btf *btf, struct bpf_struct_ops *st_ops) +{ + struct btf_struct_ops_tab *tab, *new_tab; + int i; + + tab = btf->struct_ops_tab; + if (!tab) { + tab = kzalloc(offsetof(struct btf_struct_ops_tab, ops[4]), + GFP_KERNEL); + if (!tab) + return -ENOMEM; + tab->capacity = 4; + btf->struct_ops_tab = tab; + } + + for (i = 0; i < tab->cnt; i++) + if (tab->ops[i].st_ops == st_ops) + return -EEXIST; + + if (tab->cnt == tab->capacity) { + new_tab = krealloc(tab, + offsetof(struct btf_struct_ops_tab, + ops[tab->capacity * 2]), + GFP_KERNEL); + if (!new_tab) + return -ENOMEM; + tab = new_tab; + tab->capacity *= 2; + btf->struct_ops_tab = tab; + } + + tab->ops[btf->struct_ops_tab->cnt].st_ops = st_ops; + + btf->struct_ops_tab->cnt++; + + return 0; +} From 47f4f657acd5d04c78c5c5ac7022cba9ce3b4a7d Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:56 -0800 Subject: [PATCH 0237/2255] bpf: make struct_ops_map support btfs other than btf_vmlinux. Once new struct_ops can be registered from modules, btf_vmlinux is no longer the only btf that struct_ops_map would face. st_map should remember what btf it should use to get type information. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-6-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/bpf_struct_ops.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 9774f7824e8b..5ddcca4c4fba 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -46,6 +46,8 @@ struct bpf_struct_ops_map { * "links[]". */ void *image; + /* The owner moduler's btf. */ + struct btf *btf; /* uvalue->data stores the kernel struct * (e.g. tcp_congestion_ops) that is more useful * to userspace than the kvalue. For example, @@ -314,7 +316,7 @@ static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map) } } -static int check_zero_holes(const struct btf_type *t, void *data) +static int check_zero_holes(const struct btf *btf, const struct btf_type *t, void *data) { const struct btf_member *member; u32 i, moff, msize, prev_mend = 0; @@ -326,8 +328,8 @@ static int check_zero_holes(const struct btf_type *t, void *data) memchr_inv(data + prev_mend, 0, moff - prev_mend)) return -EINVAL; - mtype = btf_type_by_id(btf_vmlinux, member->type); - mtype = btf_resolve_size(btf_vmlinux, mtype, &msize); + mtype = btf_type_by_id(btf, member->type); + mtype = btf_resolve_size(btf, mtype, &msize); if (IS_ERR(mtype)) return PTR_ERR(mtype); prev_mend = moff + msize; @@ -401,12 +403,12 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, if (*(u32 *)key != 0) return -E2BIG; - err = check_zero_holes(st_ops_desc->value_type, value); + err = check_zero_holes(st_map->btf, st_ops_desc->value_type, value); if (err) return err; uvalue = value; - err = check_zero_holes(t, uvalue->data); + err = check_zero_holes(st_map->btf, t, uvalue->data); if (err) return err; @@ -442,7 +444,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, u32 moff; moff = __btf_member_bit_offset(t, member) / 8; - ptype = btf_type_resolve_ptr(btf_vmlinux, member->type, NULL); + ptype = btf_type_resolve_ptr(st_map->btf, member->type, NULL); if (ptype == module_type) { if (*(void **)(udata + moff)) goto reset_unlock; @@ -467,8 +469,8 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, if (!ptype || !btf_type_is_func_proto(ptype)) { u32 msize; - mtype = btf_type_by_id(btf_vmlinux, member->type); - mtype = btf_resolve_size(btf_vmlinux, mtype, &msize); + mtype = btf_type_by_id(st_map->btf, member->type); + mtype = btf_resolve_size(st_map->btf, mtype, &msize); if (IS_ERR(mtype)) { err = PTR_ERR(mtype); goto reset_unlock; @@ -607,6 +609,7 @@ static long bpf_struct_ops_map_delete_elem(struct bpf_map *map, void *key) static void bpf_struct_ops_map_seq_show_elem(struct bpf_map *map, void *key, struct seq_file *m) { + struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; void *value; int err; @@ -616,7 +619,8 @@ static void bpf_struct_ops_map_seq_show_elem(struct bpf_map *map, void *key, err = bpf_struct_ops_map_sys_lookup_elem(map, key, value); if (!err) { - btf_type_seq_show(btf_vmlinux, map->btf_vmlinux_value_type_id, + btf_type_seq_show(st_map->btf, + map->btf_vmlinux_value_type_id, value, m); seq_puts(m, "\n"); } @@ -726,6 +730,8 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) return ERR_PTR(-ENOMEM); } + st_map->btf = btf_vmlinux; + mutex_init(&st_map->lock); bpf_map_init_from_attr(map, attr); From 1338b93346587a2a6ac79bbcf55ef5b357745573 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:57 -0800 Subject: [PATCH 0238/2255] bpf: pass btf object id in bpf_map_info. Include btf object id (btf_obj_id) in bpf_map_info so that tools (ex: bpftools struct_ops dump) know the correct btf from the kernel to look up type information of struct_ops types. Since struct_ops types can be defined and registered in a module. The type information of a struct_ops type are defined in the btf of the module defining it. The userspace tools need to know which btf is for the module defining a struct_ops type. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-7-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 4 ++++ include/uapi/linux/bpf.h | 2 +- kernel/bpf/bpf_struct_ops.c | 7 +++++++ kernel/bpf/syscall.c | 2 ++ tools/include/uapi/linux/bpf.h | 2 +- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7fc95e7babab..29fcae9fa8ed 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1732,6 +1732,7 @@ struct bpf_dummy_ops { int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, union bpf_attr __user *uattr); #endif +void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map); #else static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id) { @@ -1759,6 +1760,9 @@ static inline int bpf_struct_ops_link_create(union bpf_attr *attr) { return -EOPNOTSUPP; } +static inline void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map) +{ +} #endif diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 287d05732668..a380047c86af 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6487,7 +6487,7 @@ struct bpf_map_info { __u32 btf_id; __u32 btf_key_type_id; __u32 btf_value_type_id; - __u32 :32; /* alignment pad */ + __u32 btf_vmlinux_id; __u64 map_extra; } __attribute__((aligned(8))); diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 5ddcca4c4fba..5e98af4fc2e2 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -947,3 +947,10 @@ err_out: kfree(link); return err; } + +void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map) +{ + struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; + + info->btf_vmlinux_id = btf_obj_id(st_map->btf); +} diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 13193aaafb64..55b458429705 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4691,6 +4691,8 @@ static int bpf_map_get_info_by_fd(struct file *file, info.btf_value_type_id = map->btf_value_type_id; } info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; + if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) + bpf_map_struct_ops_info_fill(&info, map); if (bpf_map_is_offloaded(map)) { err = bpf_map_offload_info_fill(&info, map); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 287d05732668..a380047c86af 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -6487,7 +6487,7 @@ struct bpf_map_info { __u32 btf_id; __u32 btf_key_type_id; __u32 btf_value_type_id; - __u32 :32; /* alignment pad */ + __u32 btf_vmlinux_id; __u64 map_extra; } __attribute__((aligned(8))); From 689423db3bda2244c24db8a64de4cdb37be1de41 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:58 -0800 Subject: [PATCH 0239/2255] bpf: lookup struct_ops types from a given module BTF. This is a preparation for searching for struct_ops types from a specified module. BTF is always btf_vmlinux now. This patch passes a pointer of BTF to bpf_struct_ops_find_value() and bpf_struct_ops_find(). Once the new registration API of struct_ops types is used, other BTFs besides btf_vmlinux can also be passed to them. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-8-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 4 ++-- kernel/bpf/bpf_struct_ops.c | 11 ++++++----- kernel/bpf/verifier.c | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 29fcae9fa8ed..86ff8911d7ee 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1689,7 +1689,7 @@ struct bpf_struct_ops_desc { #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL) #define BPF_MODULE_OWNER ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA)) -const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id); +const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id); void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log); bool bpf_struct_ops_get(const void *kdata); void bpf_struct_ops_put(const void *kdata); @@ -1734,7 +1734,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, #endif void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map); #else -static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id) +static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id) { return NULL; } diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 5e98af4fc2e2..7505f515aac3 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -221,11 +221,11 @@ void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) extern struct btf *btf_vmlinux; static const struct bpf_struct_ops_desc * -bpf_struct_ops_find_value(u32 value_id) +bpf_struct_ops_find_value(struct btf *btf, u32 value_id) { unsigned int i; - if (!value_id || !btf_vmlinux) + if (!value_id || !btf) return NULL; for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { @@ -236,11 +236,12 @@ bpf_struct_ops_find_value(u32 value_id) return NULL; } -const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id) +const struct bpf_struct_ops_desc * +bpf_struct_ops_find(struct btf *btf, u32 type_id) { unsigned int i; - if (!type_id || !btf_vmlinux) + if (!type_id || !btf) return NULL; for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { @@ -682,7 +683,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) struct bpf_map *map; int ret; - st_ops_desc = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id); + st_ops_desc = bpf_struct_ops_find_value(btf_vmlinux, attr->btf_vmlinux_value_type_id); if (!st_ops_desc) return ERR_PTR(-ENOTSUPP); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e279491118b7..2a0fd2ccdb11 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20298,7 +20298,7 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) } btf_id = prog->aux->attach_btf_id; - st_ops_desc = bpf_struct_ops_find(btf_id); + st_ops_desc = bpf_struct_ops_find(btf_vmlinux, btf_id); if (!st_ops_desc) { verbose(env, "attach_btf_id %u is not a supported struct\n", btf_id); From fcc2c1fb0651477c8ed78a3a293c175ccd70697a Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:49:59 -0800 Subject: [PATCH 0240/2255] bpf: pass attached BTF to the bpf_struct_ops subsystem Pass the fd of a btf from the userspace to the bpf() syscall, and then convert the fd into a btf. The btf is generated from the module that defines the target BPF struct_ops type. In order to inform the kernel about the module that defines the target struct_ops type, the userspace program needs to provide a btf fd for the respective module's btf. This btf contains essential information on the types defined within the module, including the target struct_ops type. A btf fd must be provided to the kernel for struct_ops maps and for the bpf programs attached to those maps. In the case of the bpf programs, the attach_btf_obj_fd parameter is passed as part of the bpf_attr and is converted into a btf. This btf is then stored in the prog->aux->attach_btf field. Here, it just let the verifier access attach_btf directly. In the case of struct_ops maps, a btf fd is passed as value_type_btf_obj_fd of bpf_attr. The bpf_struct_ops_map_alloc() function converts the fd to a btf and stores it as st_map->btf. A flag BPF_F_VTYPE_BTF_OBJ_FD is added for map_flags to indicate that the value of value_type_btf_obj_fd is set. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-9-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/uapi/linux/bpf.h | 8 +++++ kernel/bpf/bpf_struct_ops.c | 65 ++++++++++++++++++++++++---------- kernel/bpf/syscall.c | 2 +- kernel/bpf/verifier.c | 9 +++-- tools/include/uapi/linux/bpf.h | 8 +++++ 5 files changed, 70 insertions(+), 22 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index a380047c86af..1fef6d5a1330 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1330,6 +1330,9 @@ enum { /* Get path from provided FD in BPF_OBJ_PIN/BPF_OBJ_GET commands */ BPF_F_PATH_FD = (1U << 14), + +/* Flag for value_type_btf_obj_fd, the fd is available */ + BPF_F_VTYPE_BTF_OBJ_FD = (1U << 15), }; /* Flags for BPF_PROG_QUERY. */ @@ -1403,6 +1406,11 @@ union bpf_attr { * to using 5 hash functions). */ __u64 map_extra; + + __s32 value_type_btf_obj_fd; /* fd pointing to a BTF + * type data for + * btf_vmlinux_value_type_id. + */ }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 7505f515aac3..3b8d689ece5d 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -641,6 +641,7 @@ static void __bpf_struct_ops_map_free(struct bpf_map *map) bpf_jit_uncharge_modmem(PAGE_SIZE); } bpf_map_area_free(st_map->uvalue); + btf_put(st_map->btf); bpf_map_area_free(st_map); } @@ -669,7 +670,8 @@ static void bpf_struct_ops_map_free(struct bpf_map *map) static int bpf_struct_ops_map_alloc_check(union bpf_attr *attr) { if (attr->key_size != sizeof(unsigned int) || attr->max_entries != 1 || - (attr->map_flags & ~BPF_F_LINK) || !attr->btf_vmlinux_value_type_id) + (attr->map_flags & ~(BPF_F_LINK | BPF_F_VTYPE_BTF_OBJ_FD)) || + !attr->btf_vmlinux_value_type_id) return -EINVAL; return 0; } @@ -681,15 +683,36 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) struct bpf_struct_ops_map *st_map; const struct btf_type *t, *vt; struct bpf_map *map; + struct btf *btf; int ret; - st_ops_desc = bpf_struct_ops_find_value(btf_vmlinux, attr->btf_vmlinux_value_type_id); - if (!st_ops_desc) - return ERR_PTR(-ENOTSUPP); + if (attr->map_flags & BPF_F_VTYPE_BTF_OBJ_FD) { + /* The map holds btf for its whole life time. */ + btf = btf_get_by_fd(attr->value_type_btf_obj_fd); + if (IS_ERR(btf)) + return ERR_CAST(btf); + if (!btf_is_module(btf)) { + btf_put(btf); + return ERR_PTR(-EINVAL); + } + } else { + btf = bpf_get_btf_vmlinux(); + if (IS_ERR(btf)) + return ERR_CAST(btf); + btf_get(btf); + } + + st_ops_desc = bpf_struct_ops_find_value(btf, attr->btf_vmlinux_value_type_id); + if (!st_ops_desc) { + ret = -ENOTSUPP; + goto errout; + } vt = st_ops_desc->value_type; - if (attr->value_size != vt->size) - return ERR_PTR(-EINVAL); + if (attr->value_size != vt->size) { + ret = -EINVAL; + goto errout; + } t = st_ops_desc->type; @@ -700,17 +723,17 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) (vt->size - sizeof(struct bpf_struct_ops_value)); st_map = bpf_map_area_alloc(st_map_size, NUMA_NO_NODE); - if (!st_map) - return ERR_PTR(-ENOMEM); + if (!st_map) { + ret = -ENOMEM; + goto errout; + } st_map->st_ops_desc = st_ops_desc; map = &st_map->map; ret = bpf_jit_charge_modmem(PAGE_SIZE); - if (ret) { - __bpf_struct_ops_map_free(map); - return ERR_PTR(ret); - } + if (ret) + goto errout_free; st_map->image = arch_alloc_bpf_trampoline(PAGE_SIZE); if (!st_map->image) { @@ -719,24 +742,30 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) * here. */ bpf_jit_uncharge_modmem(PAGE_SIZE); - __bpf_struct_ops_map_free(map); - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto errout_free; } st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE); st_map->links = bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_links *), NUMA_NO_NODE); if (!st_map->uvalue || !st_map->links) { - __bpf_struct_ops_map_free(map); - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto errout_free; } - - st_map->btf = btf_vmlinux; + st_map->btf = btf; mutex_init(&st_map->lock); bpf_map_init_from_attr(map, attr); return map; + +errout_free: + __bpf_struct_ops_map_free(map); +errout: + btf_put(btf); + + return ERR_PTR(ret); } static u64 bpf_struct_ops_map_mem_usage(const struct bpf_map *map) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 55b458429705..f8124b3229e2 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1123,7 +1123,7 @@ free_map_tab: return ret; } -#define BPF_MAP_CREATE_LAST_FIELD map_extra +#define BPF_MAP_CREATE_LAST_FIELD value_type_btf_obj_fd /* called via syscall */ static int map_create(union bpf_attr *attr) { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 2a0fd2ccdb11..6081512deb79 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20290,6 +20290,7 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) const struct btf_member *member; struct bpf_prog *prog = env->prog; u32 btf_id, member_idx; + struct btf *btf; const char *mname; if (!prog->gpl_compatible) { @@ -20297,8 +20298,10 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) return -EINVAL; } + btf = prog->aux->attach_btf ?: bpf_get_btf_vmlinux(); + btf_id = prog->aux->attach_btf_id; - st_ops_desc = bpf_struct_ops_find(btf_vmlinux, btf_id); + st_ops_desc = bpf_struct_ops_find(btf, btf_id); if (!st_ops_desc) { verbose(env, "attach_btf_id %u is not a supported struct\n", btf_id); @@ -20315,8 +20318,8 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) } member = &btf_type_member(t)[member_idx]; - mname = btf_name_by_offset(btf_vmlinux, member->name_off); - func_proto = btf_type_resolve_func_ptr(btf_vmlinux, member->type, + mname = btf_name_by_offset(btf, member->name_off); + func_proto = btf_type_resolve_func_ptr(btf, member->type, NULL); if (!func_proto) { verbose(env, "attach to invalid member %s(@idx %u) of struct %s\n", diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index a380047c86af..1fef6d5a1330 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1330,6 +1330,9 @@ enum { /* Get path from provided FD in BPF_OBJ_PIN/BPF_OBJ_GET commands */ BPF_F_PATH_FD = (1U << 14), + +/* Flag for value_type_btf_obj_fd, the fd is available */ + BPF_F_VTYPE_BTF_OBJ_FD = (1U << 15), }; /* Flags for BPF_PROG_QUERY. */ @@ -1403,6 +1406,11 @@ union bpf_attr { * to using 5 hash functions). */ __u64 map_extra; + + __s32 value_type_btf_obj_fd; /* fd pointing to a BTF + * type data for + * btf_vmlinux_value_type_id. + */ }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ From e3f87fdfed7b770dd7066b02262b12747881e76d Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:50:00 -0800 Subject: [PATCH 0241/2255] bpf: hold module refcnt in bpf_struct_ops map creation and prog verification. To ensure that a module remains accessible whenever a struct_ops object of a struct_ops type provided by the module is still in use. struct bpf_struct_ops_map doesn't hold a refcnt to btf anymore since a module will hold a refcnt to it's btf already. But, struct_ops programs are different. They hold their associated btf, not the module since they need only btf to assure their types (signatures). However, verifier holds the refcnt of the associated module of a struct_ops type temporarily when verify a struct_ops prog. Verifier needs the help from the verifier operators (struct bpf_verifier_ops) provided by the owner module to verify data access of a prog, provide information, and generate code. This patch also add a count of links (links_cnt) to bpf_struct_ops_map. It avoids bpf_struct_ops_map_put_progs() from accessing btf after calling module_put() in bpf_struct_ops_map_free(). Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-10-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 1 + include/linux/bpf_verifier.h | 1 + kernel/bpf/bpf_struct_ops.c | 29 +++++++++++++++++++++++------ kernel/bpf/verifier.c | 11 +++++++++++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 86ff8911d7ee..a5b425893d38 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1674,6 +1674,7 @@ struct bpf_struct_ops { int (*update)(void *kdata, void *old_kdata); int (*validate)(void *kdata); void *cfi_stubs; + struct module *owner; const char *name; struct btf_func_model func_models[BPF_STRUCT_OPS_MAX_NR_MEMBERS]; }; diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index e11baecbde68..7f5816482a10 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -662,6 +662,7 @@ struct bpf_verifier_env { u32 prev_insn_idx; struct bpf_prog *prog; /* eBPF program being verified */ const struct bpf_verifier_ops *ops; + struct module *attach_btf_mod; /* The owner module of prog->aux->attach_btf */ struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */ int stack_size; /* number of states to be processed */ bool strict_alignment; /* perform strict pointer alignment checks */ diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 3b8d689ece5d..02216a8d9265 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -40,6 +40,7 @@ struct bpf_struct_ops_map { * (in kvalue.data). */ struct bpf_link **links; + u32 links_cnt; /* image is a page that has all the trampolines * that stores the func args before calling the bpf_prog. * A PAGE_SIZE "image" is enough to store all trampoline for @@ -306,10 +307,9 @@ static void *bpf_struct_ops_map_lookup_elem(struct bpf_map *map, void *key) static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map) { - const struct btf_type *t = st_map->st_ops_desc->type; u32 i; - for (i = 0; i < btf_type_vlen(t); i++) { + for (i = 0; i < st_map->links_cnt; i++) { if (st_map->links[i]) { bpf_link_put(st_map->links[i]); st_map->links[i] = NULL; @@ -641,12 +641,20 @@ static void __bpf_struct_ops_map_free(struct bpf_map *map) bpf_jit_uncharge_modmem(PAGE_SIZE); } bpf_map_area_free(st_map->uvalue); - btf_put(st_map->btf); bpf_map_area_free(st_map); } static void bpf_struct_ops_map_free(struct bpf_map *map) { + struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; + + /* st_ops->owner was acquired during map_alloc to implicitly holds + * the btf's refcnt. The acquire was only done when btf_is_module() + * st_map->btf cannot be NULL here. + */ + if (btf_is_module(st_map->btf)) + module_put(st_map->st_ops_desc->st_ops->owner); + /* The struct_ops's function may switch to another struct_ops. * * For example, bpf_tcp_cc_x->init() may switch to @@ -682,6 +690,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) size_t st_map_size; struct bpf_struct_ops_map *st_map; const struct btf_type *t, *vt; + struct module *mod = NULL; struct bpf_map *map; struct btf *btf; int ret; @@ -695,11 +704,18 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) btf_put(btf); return ERR_PTR(-EINVAL); } + + mod = btf_try_get_module(btf); + /* mod holds a refcnt to btf. We don't need an extra refcnt + * here. + */ + btf_put(btf); + if (!mod) + return ERR_PTR(-EINVAL); } else { btf = bpf_get_btf_vmlinux(); if (IS_ERR(btf)) return ERR_CAST(btf); - btf_get(btf); } st_ops_desc = bpf_struct_ops_find_value(btf, attr->btf_vmlinux_value_type_id); @@ -746,8 +762,9 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) goto errout_free; } st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE); + st_map->links_cnt = btf_type_vlen(t); st_map->links = - bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_links *), + bpf_map_area_alloc(st_map->links_cnt * sizeof(struct bpf_links *), NUMA_NO_NODE); if (!st_map->uvalue || !st_map->links) { ret = -ENOMEM; @@ -763,7 +780,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) errout_free: __bpf_struct_ops_map_free(map); errout: - btf_put(btf); + module_put(mod); return ERR_PTR(ret); } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 6081512deb79..f31868ba0c2d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20299,6 +20299,15 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) } btf = prog->aux->attach_btf ?: bpf_get_btf_vmlinux(); + if (btf_is_module(btf)) { + /* Make sure st_ops is valid through the lifetime of env */ + env->attach_btf_mod = btf_try_get_module(btf); + if (!env->attach_btf_mod) { + verbose(env, "struct_ops module %s is not found\n", + btf_get_name(btf)); + return -ENOTSUPP; + } + } btf_id = prog->aux->attach_btf_id; st_ops_desc = bpf_struct_ops_find(btf, btf_id); @@ -21024,6 +21033,8 @@ err_release_maps: env->prog->expected_attach_type = 0; *prog = env->prog; + + module_put(env->attach_btf_mod); err_unlock: if (!is_priv) mutex_unlock(&bpf_verifier_lock); From 612d087d4ba54cef47946e22e5dabad762dd7ed5 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:50:01 -0800 Subject: [PATCH 0242/2255] bpf: validate value_type A value_type should consist of three components: refcnt, state, and data. refcnt and state has been move to struct bpf_struct_ops_common_value to make it easier to check the value type. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-11-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 12 +++++ kernel/bpf/bpf_struct_ops.c | 93 ++++++++++++++++++++++++------------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index a5b425893d38..7c178170f93f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1688,6 +1688,18 @@ struct bpf_struct_ops_desc { u32 value_id; }; +enum bpf_struct_ops_state { + BPF_STRUCT_OPS_STATE_INIT, + BPF_STRUCT_OPS_STATE_INUSE, + BPF_STRUCT_OPS_STATE_TOBEFREE, + BPF_STRUCT_OPS_STATE_READY, +}; + +struct bpf_struct_ops_common_value { + refcount_t refcnt; + enum bpf_struct_ops_state state; +}; + #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL) #define BPF_MODULE_OWNER ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA)) const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id); diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 02216a8d9265..30ab34fab0f8 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -13,19 +13,8 @@ #include #include -enum bpf_struct_ops_state { - BPF_STRUCT_OPS_STATE_INIT, - BPF_STRUCT_OPS_STATE_INUSE, - BPF_STRUCT_OPS_STATE_TOBEFREE, - BPF_STRUCT_OPS_STATE_READY, -}; - -#define BPF_STRUCT_OPS_COMMON_VALUE \ - refcount_t refcnt; \ - enum bpf_struct_ops_state state - struct bpf_struct_ops_value { - BPF_STRUCT_OPS_COMMON_VALUE; + struct bpf_struct_ops_common_value common; char data[] ____cacheline_aligned_in_smp; }; @@ -81,8 +70,8 @@ static DEFINE_MUTEX(update_mutex); #define BPF_STRUCT_OPS_TYPE(_name) \ extern struct bpf_struct_ops bpf_##_name; \ \ -struct bpf_struct_ops_##_name { \ - BPF_STRUCT_OPS_COMMON_VALUE; \ +struct bpf_struct_ops_##_name { \ + struct bpf_struct_ops_common_value common; \ struct _name data ____cacheline_aligned_in_smp; \ }; #include "bpf_struct_ops_types.h" @@ -113,11 +102,49 @@ const struct bpf_prog_ops bpf_struct_ops_prog_ops = { BTF_ID_LIST(st_ops_ids) BTF_ID(struct, module) +BTF_ID(struct, bpf_struct_ops_common_value) enum { IDX_MODULE_ID, + IDX_ST_OPS_COMMON_VALUE_ID, }; +extern struct btf *btf_vmlinux; + +static bool is_valid_value_type(struct btf *btf, s32 value_id, + const struct btf_type *type, + const char *value_name) +{ + const struct btf_type *common_value_type; + const struct btf_member *member; + const struct btf_type *vt, *mt; + + vt = btf_type_by_id(btf, value_id); + if (btf_vlen(vt) != 2) { + pr_warn("The number of %s's members should be 2, but we get %d\n", + value_name, btf_vlen(vt)); + return false; + } + member = btf_type_member(vt); + mt = btf_type_by_id(btf, member->type); + common_value_type = btf_type_by_id(btf_vmlinux, + st_ops_ids[IDX_ST_OPS_COMMON_VALUE_ID]); + if (mt != common_value_type) { + pr_warn("The first member of %s should be bpf_struct_ops_common_value\n", + value_name); + return false; + } + member++; + mt = btf_type_by_id(btf, member->type); + if (mt != type) { + pr_warn("The second member of %s should be %s\n", + value_name, btf_name_by_offset(btf, type->name_off)); + return false; + } + + return true; +} + static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, struct btf *btf, struct bpf_verifier_log *log) @@ -138,14 +165,6 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, } sprintf(value_name, "%s%s", VALUE_PREFIX, st_ops->name); - value_id = btf_find_by_name_kind(btf, value_name, - BTF_KIND_STRUCT); - if (value_id < 0) { - pr_warn("Cannot find struct %s in %s\n", - value_name, btf_get_name(btf)); - return; - } - type_id = btf_find_by_name_kind(btf, st_ops->name, BTF_KIND_STRUCT); if (type_id < 0) { @@ -160,6 +179,16 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, return; } + value_id = btf_find_by_name_kind(btf, value_name, + BTF_KIND_STRUCT); + if (value_id < 0) { + pr_warn("Cannot find struct %s in %s\n", + value_name, btf_get_name(btf)); + return; + } + if (!is_valid_value_type(btf, value_id, t, value_name)) + return; + for_each_member(i, t, member) { const struct btf_type *func_proto; @@ -219,8 +248,6 @@ void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) } } -extern struct btf *btf_vmlinux; - static const struct bpf_struct_ops_desc * bpf_struct_ops_find_value(struct btf *btf, u32 value_id) { @@ -276,7 +303,7 @@ int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key, kvalue = &st_map->kvalue; /* Pair with smp_store_release() during map_update */ - state = smp_load_acquire(&kvalue->state); + state = smp_load_acquire(&kvalue->common.state); if (state == BPF_STRUCT_OPS_STATE_INIT) { memset(value, 0, map->value_size); return 0; @@ -287,7 +314,7 @@ int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key, */ uvalue = value; memcpy(uvalue, st_map->uvalue, map->value_size); - uvalue->state = state; + uvalue->common.state = state; /* This value offers the user space a general estimate of how * many sockets are still utilizing this struct_ops for TCP @@ -295,7 +322,7 @@ int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key, * should sufficiently meet our present goals. */ refcnt = atomic64_read(&map->refcnt) - atomic64_read(&map->usercnt); - refcount_set(&uvalue->refcnt, max_t(s64, refcnt, 0)); + refcount_set(&uvalue->common.refcnt, max_t(s64, refcnt, 0)); return 0; } @@ -413,7 +440,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, if (err) return err; - if (uvalue->state || refcount_read(&uvalue->refcnt)) + if (uvalue->common.state || refcount_read(&uvalue->common.refcnt)) return -EINVAL; tlinks = kcalloc(BPF_TRAMP_MAX, sizeof(*tlinks), GFP_KERNEL); @@ -425,7 +452,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, mutex_lock(&st_map->lock); - if (kvalue->state != BPF_STRUCT_OPS_STATE_INIT) { + if (kvalue->common.state != BPF_STRUCT_OPS_STATE_INIT) { err = -EBUSY; goto unlock; } @@ -540,7 +567,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, * * Pair with smp_load_acquire() during lookup_elem(). */ - smp_store_release(&kvalue->state, BPF_STRUCT_OPS_STATE_READY); + smp_store_release(&kvalue->common.state, BPF_STRUCT_OPS_STATE_READY); goto unlock; } @@ -558,7 +585,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, * It ensures the above udata updates (e.g. prog->aux->id) * can be seen once BPF_STRUCT_OPS_STATE_INUSE is set. */ - smp_store_release(&kvalue->state, BPF_STRUCT_OPS_STATE_INUSE); + smp_store_release(&kvalue->common.state, BPF_STRUCT_OPS_STATE_INUSE); goto unlock; } @@ -588,7 +615,7 @@ static long bpf_struct_ops_map_delete_elem(struct bpf_map *map, void *key) if (st_map->map.map_flags & BPF_F_LINK) return -EOPNOTSUPP; - prev_state = cmpxchg(&st_map->kvalue.state, + prev_state = cmpxchg(&st_map->kvalue.common.state, BPF_STRUCT_OPS_STATE_INUSE, BPF_STRUCT_OPS_STATE_TOBEFREE); switch (prev_state) { @@ -848,7 +875,7 @@ static bool bpf_struct_ops_valid_to_reg(struct bpf_map *map) return map->map_type == BPF_MAP_TYPE_STRUCT_OPS && map->map_flags & BPF_F_LINK && /* Pair with smp_store_release() during map_update */ - smp_load_acquire(&st_map->kvalue.state) == BPF_STRUCT_OPS_STATE_READY; + smp_load_acquire(&st_map->kvalue.common.state) == BPF_STRUCT_OPS_STATE_READY; } static void bpf_struct_ops_map_link_dealloc(struct bpf_link *link) From f6be98d19985411ca1f3d53413d94d5b7f41c200 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:50:02 -0800 Subject: [PATCH 0243/2255] bpf, net: switch to dynamic registration Replace the static list of struct_ops types with per-btf struct_ops_tab to enable dynamic registration. Both bpf_dummy_ops and bpf_tcp_ca now utilize the registration function instead of being listed in bpf_struct_ops_types.h. Cc: netdev@vger.kernel.org Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-12-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 27 +++++--- include/linux/btf.h | 12 ++++ kernel/bpf/bpf_struct_ops.c | 100 ++++-------------------------- kernel/bpf/bpf_struct_ops_types.h | 12 ---- kernel/bpf/btf.c | 86 +++++++++++++++++++++++-- net/bpf/bpf_dummy_struct_ops.c | 11 +++- net/ipv4/bpf_tcp_ca.c | 12 +++- 7 files changed, 142 insertions(+), 118 deletions(-) delete mode 100644 kernel/bpf/bpf_struct_ops_types.h diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7c178170f93f..75b7f9b19c6a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1701,9 +1701,20 @@ struct bpf_struct_ops_common_value { }; #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL) +/* This macro helps developer to register a struct_ops type and generate + * type information correctly. Developers should use this macro to register + * a struct_ops type instead of calling __register_bpf_struct_ops() directly. + */ +#define register_bpf_struct_ops(st_ops, type) \ + ({ \ + struct bpf_struct_ops_##type { \ + struct bpf_struct_ops_common_value common; \ + struct type data ____cacheline_aligned_in_smp; \ + }; \ + BTF_TYPE_EMIT(struct bpf_struct_ops_##type); \ + __register_bpf_struct_ops(st_ops); \ + }) #define BPF_MODULE_OWNER ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA)) -const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id); -void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log); bool bpf_struct_ops_get(const void *kdata); void bpf_struct_ops_put(const void *kdata); int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key, @@ -1745,16 +1756,12 @@ struct bpf_dummy_ops { int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, union bpf_attr __user *uattr); #endif +int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, + struct btf *btf, + struct bpf_verifier_log *log); void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map); #else -static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id) -{ - return NULL; -} -static inline void bpf_struct_ops_init(struct btf *btf, - struct bpf_verifier_log *log) -{ -} +#define register_bpf_struct_ops(st_ops, type) ({ (void *)(st_ops); 0; }) static inline bool bpf_try_module_get(const void *data, struct module *owner) { return try_module_get(owner); diff --git a/include/linux/btf.h b/include/linux/btf.h index 932af1680bb5..1ee8977b8c95 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -497,6 +497,18 @@ static inline void *btf_id_set8_contains(const struct btf_id_set8 *set, u32 id) struct bpf_verifier_log; +#if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL) +struct bpf_struct_ops; +int __register_bpf_struct_ops(struct bpf_struct_ops *st_ops); +const struct bpf_struct_ops_desc *bpf_struct_ops_find_value(struct btf *btf, u32 value_id); +const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id); +#else +static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id) +{ + return NULL; +} +#endif + #ifdef CONFIG_BPF_SYSCALL const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); const char *btf_name_by_offset(const struct btf *btf, u32 offset); diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 30ab34fab0f8..defc052e4622 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -62,35 +62,6 @@ static DEFINE_MUTEX(update_mutex); #define VALUE_PREFIX "bpf_struct_ops_" #define VALUE_PREFIX_LEN (sizeof(VALUE_PREFIX) - 1) -/* bpf_struct_ops_##_name (e.g. bpf_struct_ops_tcp_congestion_ops) is - * the map's value exposed to the userspace and its btf-type-id is - * stored at the map->btf_vmlinux_value_type_id. - * - */ -#define BPF_STRUCT_OPS_TYPE(_name) \ -extern struct bpf_struct_ops bpf_##_name; \ - \ -struct bpf_struct_ops_##_name { \ - struct bpf_struct_ops_common_value common; \ - struct _name data ____cacheline_aligned_in_smp; \ -}; -#include "bpf_struct_ops_types.h" -#undef BPF_STRUCT_OPS_TYPE - -enum { -#define BPF_STRUCT_OPS_TYPE(_name) BPF_STRUCT_OPS_TYPE_##_name, -#include "bpf_struct_ops_types.h" -#undef BPF_STRUCT_OPS_TYPE - __NR_BPF_STRUCT_OPS_TYPE, -}; - -static struct bpf_struct_ops_desc bpf_struct_ops[] = { -#define BPF_STRUCT_OPS_TYPE(_name) \ - [BPF_STRUCT_OPS_TYPE_##_name] = { .st_ops = &bpf_##_name }, -#include "bpf_struct_ops_types.h" -#undef BPF_STRUCT_OPS_TYPE -}; - const struct bpf_verifier_ops bpf_struct_ops_verifier_ops = { }; @@ -145,9 +116,9 @@ static bool is_valid_value_type(struct btf *btf, s32 value_id, return true; } -static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, - struct btf *btf, - struct bpf_verifier_log *log) +int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, + struct btf *btf, + struct bpf_verifier_log *log) { struct bpf_struct_ops *st_ops = st_ops_desc->st_ops; const struct btf_member *member; @@ -161,7 +132,7 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, sizeof(value_name)) { pr_warn("struct_ops name %s is too long\n", st_ops->name); - return; + return -EINVAL; } sprintf(value_name, "%s%s", VALUE_PREFIX, st_ops->name); @@ -170,13 +141,13 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, if (type_id < 0) { pr_warn("Cannot find struct %s in %s\n", st_ops->name, btf_get_name(btf)); - return; + return -EINVAL; } t = btf_type_by_id(btf, type_id); if (btf_type_vlen(t) > BPF_STRUCT_OPS_MAX_NR_MEMBERS) { pr_warn("Cannot support #%u members in struct %s\n", btf_type_vlen(t), st_ops->name); - return; + return -EINVAL; } value_id = btf_find_by_name_kind(btf, value_name, @@ -184,10 +155,10 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, if (value_id < 0) { pr_warn("Cannot find struct %s in %s\n", value_name, btf_get_name(btf)); - return; + return -EINVAL; } if (!is_valid_value_type(btf, value_id, t, value_name)) - return; + return -EINVAL; for_each_member(i, t, member) { const struct btf_type *func_proto; @@ -196,13 +167,13 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, if (!*mname) { pr_warn("anon member in struct %s is not supported\n", st_ops->name); - break; + return -EOPNOTSUPP; } if (__btf_member_bitfield_size(t, member)) { pr_warn("bit field member %s in struct %s is not supported\n", mname, st_ops->name); - break; + return -EOPNOTSUPP; } func_proto = btf_type_resolve_func_ptr(btf, @@ -214,7 +185,7 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, &st_ops->func_models[i])) { pr_warn("Error in parsing func ptr %s in struct %s\n", mname, st_ops->name); - break; + return -EINVAL; } } @@ -222,6 +193,7 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, if (st_ops->init(btf)) { pr_warn("Error in init bpf_struct_ops %s\n", st_ops->name); + return -EINVAL; } else { st_ops_desc->type_id = type_id; st_ops_desc->type = t; @@ -230,54 +202,8 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, value_id); } } -} -void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log) -{ - struct bpf_struct_ops_desc *st_ops_desc; - u32 i; - - /* Ensure BTF type is emitted for "struct bpf_struct_ops_##_name" */ -#define BPF_STRUCT_OPS_TYPE(_name) BTF_TYPE_EMIT(struct bpf_struct_ops_##_name); -#include "bpf_struct_ops_types.h" -#undef BPF_STRUCT_OPS_TYPE - - for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { - st_ops_desc = &bpf_struct_ops[i]; - bpf_struct_ops_desc_init(st_ops_desc, btf, log); - } -} - -static const struct bpf_struct_ops_desc * -bpf_struct_ops_find_value(struct btf *btf, u32 value_id) -{ - unsigned int i; - - if (!value_id || !btf) - return NULL; - - for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { - if (bpf_struct_ops[i].value_id == value_id) - return &bpf_struct_ops[i]; - } - - return NULL; -} - -const struct bpf_struct_ops_desc * -bpf_struct_ops_find(struct btf *btf, u32 type_id) -{ - unsigned int i; - - if (!type_id || !btf) - return NULL; - - for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) { - if (bpf_struct_ops[i].type_id == type_id) - return &bpf_struct_ops[i]; - } - - return NULL; + return 0; } static int bpf_struct_ops_map_get_next_key(struct bpf_map *map, void *key, diff --git a/kernel/bpf/bpf_struct_ops_types.h b/kernel/bpf/bpf_struct_ops_types.h deleted file mode 100644 index 5678a9ddf817..000000000000 --- a/kernel/bpf/bpf_struct_ops_types.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* internal file - do not include directly */ - -#ifdef CONFIG_BPF_JIT -#ifdef CONFIG_NET -BPF_STRUCT_OPS_TYPE(bpf_dummy_ops) -#endif -#ifdef CONFIG_INET -#include -BPF_STRUCT_OPS_TYPE(tcp_congestion_ops) -#endif -#endif diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 2e5e6ec5d965..5c3e526a2dec 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -5972,8 +5973,6 @@ struct btf *btf_parse_vmlinux(void) /* btf_parse_vmlinux() runs under bpf_verifier_lock */ bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]); - bpf_struct_ops_init(btf, log); - refcount_set(&btf->refcnt, 1); err = btf_alloc_id(btf); @@ -8706,11 +8705,13 @@ bool btf_type_ids_nocast_alias(struct bpf_verifier_log *log, return !strncmp(reg_name, arg_name, cmp_len); } +#ifdef CONFIG_BPF_JIT static int -btf_add_struct_ops(struct btf *btf, struct bpf_struct_ops *st_ops) +btf_add_struct_ops(struct btf *btf, struct bpf_struct_ops *st_ops, + struct bpf_verifier_log *log) { struct btf_struct_ops_tab *tab, *new_tab; - int i; + int i, err; tab = btf->struct_ops_tab; if (!tab) { @@ -8740,7 +8741,84 @@ btf_add_struct_ops(struct btf *btf, struct bpf_struct_ops *st_ops) tab->ops[btf->struct_ops_tab->cnt].st_ops = st_ops; + err = bpf_struct_ops_desc_init(&tab->ops[btf->struct_ops_tab->cnt], btf, log); + if (err) + return err; + btf->struct_ops_tab->cnt++; return 0; } + +const struct bpf_struct_ops_desc * +bpf_struct_ops_find_value(struct btf *btf, u32 value_id) +{ + const struct bpf_struct_ops_desc *st_ops_list; + unsigned int i; + u32 cnt; + + if (!value_id) + return NULL; + if (!btf->struct_ops_tab) + return NULL; + + cnt = btf->struct_ops_tab->cnt; + st_ops_list = btf->struct_ops_tab->ops; + for (i = 0; i < cnt; i++) { + if (st_ops_list[i].value_id == value_id) + return &st_ops_list[i]; + } + + return NULL; +} + +const struct bpf_struct_ops_desc * +bpf_struct_ops_find(struct btf *btf, u32 type_id) +{ + const struct bpf_struct_ops_desc *st_ops_list; + unsigned int i; + u32 cnt; + + if (!type_id) + return NULL; + if (!btf->struct_ops_tab) + return NULL; + + cnt = btf->struct_ops_tab->cnt; + st_ops_list = btf->struct_ops_tab->ops; + for (i = 0; i < cnt; i++) { + if (st_ops_list[i].type_id == type_id) + return &st_ops_list[i]; + } + + return NULL; +} + +int __register_bpf_struct_ops(struct bpf_struct_ops *st_ops) +{ + struct bpf_verifier_log *log; + struct btf *btf; + int err = 0; + + btf = btf_get_module_btf(st_ops->owner); + if (!btf) + return -EINVAL; + + log = kzalloc(sizeof(*log), GFP_KERNEL | __GFP_NOWARN); + if (!log) { + err = -ENOMEM; + goto errout; + } + + log->level = BPF_LOG_KERNEL; + + err = btf_add_struct_ops(btf, st_ops, log); + +errout: + kfree(log); + btf_put(btf); + + return err; +} +EXPORT_SYMBOL_GPL(__register_bpf_struct_ops); +#endif diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c index ba2c58dba2da..02de71719aed 100644 --- a/net/bpf/bpf_dummy_struct_ops.c +++ b/net/bpf/bpf_dummy_struct_ops.c @@ -7,7 +7,7 @@ #include #include -extern struct bpf_struct_ops bpf_bpf_dummy_ops; +static struct bpf_struct_ops bpf_bpf_dummy_ops; /* A common type for test_N with return value in bpf_dummy_ops */ typedef int (*dummy_ops_test_ret_fn)(struct bpf_dummy_ops_state *state, ...); @@ -256,7 +256,7 @@ static struct bpf_dummy_ops __bpf_bpf_dummy_ops = { .test_sleepable = bpf_dummy_test_sleepable, }; -struct bpf_struct_ops bpf_bpf_dummy_ops = { +static struct bpf_struct_ops bpf_bpf_dummy_ops = { .verifier_ops = &bpf_dummy_verifier_ops, .init = bpf_dummy_init, .check_member = bpf_dummy_ops_check_member, @@ -265,4 +265,11 @@ struct bpf_struct_ops bpf_bpf_dummy_ops = { .unreg = bpf_dummy_unreg, .name = "bpf_dummy_ops", .cfi_stubs = &__bpf_bpf_dummy_ops, + .owner = THIS_MODULE, }; + +static int __init bpf_dummy_struct_ops_init(void) +{ + return register_bpf_struct_ops(&bpf_bpf_dummy_ops, bpf_dummy_ops); +} +late_initcall(bpf_dummy_struct_ops_init); diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c index dffd8828079b..8e7716256d3c 100644 --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c @@ -12,7 +12,7 @@ #include /* "extern" is to avoid sparse warning. It is only used in bpf_struct_ops.c. */ -extern struct bpf_struct_ops bpf_tcp_congestion_ops; +static struct bpf_struct_ops bpf_tcp_congestion_ops; static u32 unsupported_ops[] = { offsetof(struct tcp_congestion_ops, get_info), @@ -345,7 +345,7 @@ static struct tcp_congestion_ops __bpf_ops_tcp_congestion_ops = { .release = __bpf_tcp_ca_release, }; -struct bpf_struct_ops bpf_tcp_congestion_ops = { +static struct bpf_struct_ops bpf_tcp_congestion_ops = { .verifier_ops = &bpf_tcp_ca_verifier_ops, .reg = bpf_tcp_ca_reg, .unreg = bpf_tcp_ca_unreg, @@ -356,10 +356,16 @@ struct bpf_struct_ops bpf_tcp_congestion_ops = { .validate = bpf_tcp_ca_validate, .name = "tcp_congestion_ops", .cfi_stubs = &__bpf_ops_tcp_congestion_ops, + .owner = THIS_MODULE, }; static int __init bpf_tcp_ca_kfunc_init(void) { - return register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &bpf_tcp_ca_kfunc_set); + int ret; + + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &bpf_tcp_ca_kfunc_set); + ret = ret ?: register_bpf_struct_ops(&bpf_tcp_congestion_ops, tcp_congestion_ops); + + return ret; } late_initcall(bpf_tcp_ca_kfunc_init); From 9e926acda0c2e21bca431a1818665ddcd6939755 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:50:03 -0800 Subject: [PATCH 0244/2255] libbpf: Find correct module BTFs for struct_ops maps and progs. Locate the module BTFs for struct_ops maps and progs and pass them to the kernel. This ensures that the kernel correctly resolves type IDs from the appropriate module BTFs. For the map of a struct_ops object, the FD of the module BTF is set to bpf_map to keep a reference to the module BTF. The FD is passed to the kernel as value_type_btf_obj_fd when the struct_ops object is loaded. For a bpf_struct_ops prog, attach_btf_obj_fd of bpf_prog is the FD of a module BTF in the kernel. Signed-off-by: Kui-Feng Lee Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240119225005.668602-13-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- tools/lib/bpf/bpf.c | 4 +++- tools/lib/bpf/bpf.h | 4 +++- tools/lib/bpf/libbpf.c | 41 ++++++++++++++++++++++++++--------- tools/lib/bpf/libbpf_probes.c | 1 + 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 9dc9625651dc..3a35472a17c5 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -169,7 +169,8 @@ int bpf_map_create(enum bpf_map_type map_type, __u32 max_entries, const struct bpf_map_create_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, map_extra); + const size_t attr_sz = offsetofend(union bpf_attr, + value_type_btf_obj_fd); union bpf_attr attr; int fd; @@ -191,6 +192,7 @@ int bpf_map_create(enum bpf_map_type map_type, attr.btf_key_type_id = OPTS_GET(opts, btf_key_type_id, 0); attr.btf_value_type_id = OPTS_GET(opts, btf_value_type_id, 0); attr.btf_vmlinux_value_type_id = OPTS_GET(opts, btf_vmlinux_value_type_id, 0); + attr.value_type_btf_obj_fd = OPTS_GET(opts, value_type_btf_obj_fd, -1); attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0); attr.map_flags = OPTS_GET(opts, map_flags, 0); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index d0f53772bdc0..53b0bee053ad 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -51,8 +51,10 @@ struct bpf_map_create_opts { __u32 numa_node; __u32 map_ifindex; + __s32 value_type_btf_obj_fd; + size_t:0; }; -#define bpf_map_create_opts__last_field map_ifindex +#define bpf_map_create_opts__last_field value_type_btf_obj_fd LIBBPF_API int bpf_map_create(enum bpf_map_type map_type, const char *map_name, diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index b8b00da62907..0569b4973a4f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -528,6 +528,7 @@ struct bpf_map { struct bpf_map_def def; __u32 numa_node; __u32 btf_var_idx; + int mod_btf_fd; __u32 btf_key_type_id; __u32 btf_value_type_id; __u32 btf_vmlinux_value_type_id; @@ -931,22 +932,29 @@ find_member_by_name(const struct btf *btf, const struct btf_type *t, return NULL; } +static int find_ksym_btf_id(struct bpf_object *obj, const char *ksym_name, + __u16 kind, struct btf **res_btf, + struct module_btf **res_mod_btf); + #define STRUCT_OPS_VALUE_PREFIX "bpf_struct_ops_" static int find_btf_by_prefix_kind(const struct btf *btf, const char *prefix, const char *name, __u32 kind); static int -find_struct_ops_kern_types(const struct btf *btf, const char *tname, +find_struct_ops_kern_types(struct bpf_object *obj, const char *tname, + struct module_btf **mod_btf, const struct btf_type **type, __u32 *type_id, const struct btf_type **vtype, __u32 *vtype_id, const struct btf_member **data_member) { const struct btf_type *kern_type, *kern_vtype; const struct btf_member *kern_data_member; + struct btf *btf; __s32 kern_vtype_id, kern_type_id; __u32 i; - kern_type_id = btf__find_by_name_kind(btf, tname, BTF_KIND_STRUCT); + kern_type_id = find_ksym_btf_id(obj, tname, BTF_KIND_STRUCT, + &btf, mod_btf); if (kern_type_id < 0) { pr_warn("struct_ops init_kern: struct %s is not found in kernel BTF\n", tname); @@ -1000,14 +1008,16 @@ static bool bpf_map__is_struct_ops(const struct bpf_map *map) } /* Init the map's fields that depend on kern_btf */ -static int bpf_map__init_kern_struct_ops(struct bpf_map *map, - const struct btf *btf, - const struct btf *kern_btf) +static int bpf_map__init_kern_struct_ops(struct bpf_map *map) { const struct btf_member *member, *kern_member, *kern_data_member; const struct btf_type *type, *kern_type, *kern_vtype; __u32 i, kern_type_id, kern_vtype_id, kern_data_off; + struct bpf_object *obj = map->obj; + const struct btf *btf = obj->btf; struct bpf_struct_ops *st_ops; + const struct btf *kern_btf; + struct module_btf *mod_btf; void *data, *kern_data; const char *tname; int err; @@ -1015,16 +1025,19 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map, st_ops = map->st_ops; type = st_ops->type; tname = st_ops->tname; - err = find_struct_ops_kern_types(kern_btf, tname, + err = find_struct_ops_kern_types(obj, tname, &mod_btf, &kern_type, &kern_type_id, &kern_vtype, &kern_vtype_id, &kern_data_member); if (err) return err; + kern_btf = mod_btf ? mod_btf->btf : obj->btf_vmlinux; + pr_debug("struct_ops init_kern %s: type_id:%u kern_type_id:%u kern_vtype_id:%u\n", map->name, st_ops->type_id, kern_type_id, kern_vtype_id); + map->mod_btf_fd = mod_btf ? mod_btf->fd : -1; map->def.value_size = kern_vtype->size; map->btf_vmlinux_value_type_id = kern_vtype_id; @@ -1100,6 +1113,8 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map, return -ENOTSUP; } + if (mod_btf) + prog->attach_btf_obj_fd = mod_btf->fd; prog->attach_btf_id = kern_type_id; prog->expected_attach_type = kern_member_idx; @@ -1142,8 +1157,7 @@ static int bpf_object__init_kern_struct_ops_maps(struct bpf_object *obj) if (!bpf_map__is_struct_ops(map)) continue; - err = bpf_map__init_kern_struct_ops(map, obj->btf, - obj->btf_vmlinux); + err = bpf_map__init_kern_struct_ops(map); if (err) return err; } @@ -5162,8 +5176,13 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b create_attr.numa_node = map->numa_node; create_attr.map_extra = map->map_extra; - if (bpf_map__is_struct_ops(map)) + if (bpf_map__is_struct_ops(map)) { create_attr.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; + if (map->mod_btf_fd >= 0) { + create_attr.value_type_btf_obj_fd = map->mod_btf_fd; + create_attr.map_flags |= BPF_F_VTYPE_BTF_OBJ_FD; + } + } if (obj->btf && btf__fd(obj->btf) >= 0) { create_attr.btf_fd = btf__fd(obj->btf); @@ -9970,7 +9989,9 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac *btf_obj_fd = 0; *btf_type_id = 1; } else { - err = find_kernel_btf_id(prog->obj, attach_name, attach_type, btf_obj_fd, btf_type_id); + err = find_kernel_btf_id(prog->obj, attach_name, + attach_type, btf_obj_fd, + btf_type_id); } if (err) { pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %d\n", diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index 9c4db90b92b6..98373d126d9d 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -326,6 +326,7 @@ static int probe_map_create(enum bpf_map_type map_type) case BPF_MAP_TYPE_STRUCT_OPS: /* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */ opts.btf_vmlinux_value_type_id = 1; + opts.value_type_btf_obj_fd = -1; exp_err = -524; /* -ENOTSUPP */ break; case BPF_MAP_TYPE_BLOOM_FILTER: From 7c81c2490c73e614c6d48e4f339f4f224140b565 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:50:04 -0800 Subject: [PATCH 0245/2255] bpf: export btf_ctx_access to modules. The module requires the use of btf_ctx_access() to invoke bpf_tracing_btf_ctx_access() from a module. This function is valuable for implementing validation functions that ensure proper access to ctx. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-14-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/btf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 5c3e526a2dec..edef96ceffa3 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6322,6 +6322,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, __btf_name_by_offset(btf, t->name_off)); return true; } +EXPORT_SYMBOL_GPL(btf_ctx_access); enum bpf_struct_walk_result { /* < 0 error */ From 0253e0590e2dc46996534371d56b5297099aed4e Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 19 Jan 2024 14:50:05 -0800 Subject: [PATCH 0246/2255] selftests/bpf: test case for register_bpf_struct_ops(). Create a new struct_ops type called bpf_testmod_ops within the bpf_testmod module. When a struct_ops object is registered, the bpf_testmod module will invoke test_2 from the module. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240119225005.668602-15-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- .../selftests/bpf/bpf_testmod/bpf_testmod.c | 66 ++++++++++++++++ .../selftests/bpf/bpf_testmod/bpf_testmod.h | 5 ++ .../bpf/prog_tests/test_struct_ops_module.c | 75 +++++++++++++++++++ .../selftests/bpf/progs/struct_ops_module.c | 30 ++++++++ 4 files changed, 176 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_module.c diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index e7c9e1c7fde0..8befaf17d454 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2020 Facebook */ +#include #include #include #include @@ -521,11 +522,75 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg) BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset) BTF_SET8_END(bpf_testmod_check_kfunc_ids) +static int bpf_testmod_ops_init(struct btf *btf) +{ + return 0; +} + +static bool bpf_testmod_ops_is_valid_access(int off, int size, + enum bpf_access_type type, + const struct bpf_prog *prog, + struct bpf_insn_access_aux *info) +{ + return bpf_tracing_btf_ctx_access(off, size, type, prog, info); +} + +static int bpf_testmod_ops_init_member(const struct btf_type *t, + const struct btf_member *member, + void *kdata, const void *udata) +{ + return 0; +} + static const struct btf_kfunc_id_set bpf_testmod_kfunc_set = { .owner = THIS_MODULE, .set = &bpf_testmod_check_kfunc_ids, }; +static const struct bpf_verifier_ops bpf_testmod_verifier_ops = { + .is_valid_access = bpf_testmod_ops_is_valid_access, +}; + +static int bpf_dummy_reg(void *kdata) +{ + struct bpf_testmod_ops *ops = kdata; + int r; + + r = ops->test_2(4, 3); + + return 0; +} + +static void bpf_dummy_unreg(void *kdata) +{ +} + +static int bpf_testmod_test_1(void) +{ + return 0; +} + +static int bpf_testmod_test_2(int a, int b) +{ + return 0; +} + +static struct bpf_testmod_ops __bpf_testmod_ops = { + .test_1 = bpf_testmod_test_1, + .test_2 = bpf_testmod_test_2, +}; + +struct bpf_struct_ops bpf_bpf_testmod_ops = { + .verifier_ops = &bpf_testmod_verifier_ops, + .init = bpf_testmod_ops_init, + .init_member = bpf_testmod_ops_init_member, + .reg = bpf_dummy_reg, + .unreg = bpf_dummy_unreg, + .cfi_stubs = &__bpf_testmod_ops, + .name = "bpf_testmod_ops", + .owner = THIS_MODULE, +}; + extern int bpf_fentry_test1(int a); static int bpf_testmod_init(void) @@ -536,6 +601,7 @@ static int bpf_testmod_init(void) ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_testmod_kfunc_set); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_testmod_kfunc_set); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set); + ret = ret ?: register_bpf_struct_ops(&bpf_bpf_testmod_ops, bpf_testmod_ops); if (ret < 0) return ret; if (bpf_fentry_test1(0) < 0) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h index f32793efe095..ca5435751c79 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h @@ -28,4 +28,9 @@ struct bpf_iter_testmod_seq { int cnt; }; +struct bpf_testmod_ops { + int (*test_1)(void); + int (*test_2)(int a, int b); +}; + #endif /* _BPF_TESTMOD_H */ diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c new file mode 100644 index 000000000000..8d833f0c7580 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include + +#include "struct_ops_module.skel.h" + +static void check_map_info(struct bpf_map_info *info) +{ + struct bpf_btf_info btf_info; + char btf_name[256]; + u32 btf_info_len = sizeof(btf_info); + int err, fd; + + fd = bpf_btf_get_fd_by_id(info->btf_vmlinux_id); + if (!ASSERT_GE(fd, 0, "get_value_type_btf_obj_fd")) + return; + + memset(&btf_info, 0, sizeof(btf_info)); + btf_info.name = ptr_to_u64(btf_name); + btf_info.name_len = sizeof(btf_name); + err = bpf_btf_get_info_by_fd(fd, &btf_info, &btf_info_len); + if (!ASSERT_OK(err, "get_value_type_btf_obj_info")) + goto cleanup; + + if (!ASSERT_EQ(strcmp(btf_name, "bpf_testmod"), 0, "get_value_type_btf_obj_name")) + goto cleanup; + +cleanup: + close(fd); +} + +static void test_struct_ops_load(void) +{ + DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts); + struct struct_ops_module *skel; + struct bpf_map_info info = {}; + struct bpf_link *link; + int err; + u32 len; + + skel = struct_ops_module__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "struct_ops_module_open")) + return; + + err = struct_ops_module__load(skel); + if (!ASSERT_OK(err, "struct_ops_module_load")) + goto cleanup; + + len = sizeof(info); + err = bpf_map_get_info_by_fd(bpf_map__fd(skel->maps.testmod_1), &info, + &len); + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd")) + goto cleanup; + + link = bpf_map__attach_struct_ops(skel->maps.testmod_1); + ASSERT_OK_PTR(link, "attach_test_mod_1"); + + /* test_2() will be called from bpf_dummy_reg() in bpf_testmod.c */ + ASSERT_EQ(skel->bss->test_2_result, 7, "test_2_result"); + + bpf_link__destroy(link); + + check_map_info(&info); + +cleanup: + struct_ops_module__destroy(skel); +} + +void serial_test_struct_ops_module(void) +{ + if (test__start_subtest("test_struct_ops_load")) + test_struct_ops_load(); +} + diff --git a/tools/testing/selftests/bpf/progs/struct_ops_module.c b/tools/testing/selftests/bpf/progs/struct_ops_module.c new file mode 100644 index 000000000000..e44ac55195ca --- /dev/null +++ b/tools/testing/selftests/bpf/progs/struct_ops_module.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include +#include "../bpf_testmod/bpf_testmod.h" + +char _license[] SEC("license") = "GPL"; + +int test_2_result = 0; + +SEC("struct_ops/test_1") +int BPF_PROG(test_1) +{ + return 0xdeadbeef; +} + +SEC("struct_ops/test_2") +int BPF_PROG(test_2, int a, int b) +{ + test_2_result = a + b; + return a + b; +} + +SEC(".struct_ops.link") +struct bpf_testmod_ops testmod_1 = { + .test_1 = (void *)test_1, + .test_2 = (void *)test_2, +}; + From a2a7f98aeeec48118fac73c22bd54f8889815e16 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 22 Jan 2024 13:02:22 +0100 Subject: [PATCH 0247/2255] net: ethernet: qualcomm: Remove QDF24xx support This SoC family was destined for server use, featuring Qualcomm's very interesting Kryo cores (before "Kryo" became a marketing term for Arm cores with small modifications). It did however not leave the labs of Qualcomm and presumably some partners, nor was it ever productized. Remove the related drivers, as they seem to be long obsolete. Signed-off-by: Konrad Dybcio Acked-by: Timur Tabi Link: https://lore.kernel.org/r/20240122-topic-qdf_cleanup_net-v1-1-caf0d9c4408a@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/qualcomm/emac/Makefile | 3 +- .../qualcomm/emac/emac-sgmii-qdf2400.c | 215 ------------------ .../qualcomm/emac/emac-sgmii-qdf2432.c | 202 ---------------- .../net/ethernet/qualcomm/emac/emac-sgmii.c | 124 ++-------- .../net/ethernet/qualcomm/emac/emac-sgmii.h | 2 - 5 files changed, 23 insertions(+), 523 deletions(-) delete mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c delete mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c diff --git a/drivers/net/ethernet/qualcomm/emac/Makefile b/drivers/net/ethernet/qualcomm/emac/Makefile index 61d15e091be2..ffc00995acb9 100644 --- a/drivers/net/ethernet/qualcomm/emac/Makefile +++ b/drivers/net/ethernet/qualcomm/emac/Makefile @@ -6,5 +6,4 @@ obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o emac-ethtool.o \ - emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o \ - emac-sgmii-qdf2400.o + emac-sgmii-fsm9900.o diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c deleted file mode 100644 index b29148ce7e05..000000000000 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c +++ /dev/null @@ -1,215 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - */ - -/* Qualcomm Technologies, Inc. QDF2400 EMAC SGMII Controller driver. - */ - -#include -#include "emac.h" - -/* EMAC_SGMII register offsets */ -#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x000C -#define EMAC_SGMII_PHY_LANE_CTRL1 0x0018 -#define EMAC_SGMII_PHY_CDR_CTRL0 0x0058 -#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x0080 -#define EMAC_SGMII_PHY_RESET_CTRL 0x00a8 -#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4 - -/* SGMII digital lane registers */ -#define EMAC_SGMII_LN_DRVR_CTRL0 0x000C -#define EMAC_SGMII_LN_DRVR_CTRL1 0x0010 -#define EMAC_SGMII_LN_DRVR_TAP_EN 0x0018 -#define EMAC_SGMII_LN_TX_MARGINING 0x001C -#define EMAC_SGMII_LN_TX_PRE 0x0020 -#define EMAC_SGMII_LN_TX_POST 0x0024 -#define EMAC_SGMII_LN_TX_BAND_MODE 0x0060 -#define EMAC_SGMII_LN_LANE_MODE 0x0064 -#define EMAC_SGMII_LN_PARALLEL_RATE 0x007C -#define EMAC_SGMII_LN_CML_CTRL_MODE0 0x00C0 -#define EMAC_SGMII_LN_MIXER_CTRL_MODE0 0x00D8 -#define EMAC_SGMII_LN_VGA_INITVAL 0x013C -#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0 0x0184 -#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0 0x0190 -#define EMAC_SGMII_LN_UCDR_SO_CONFIG 0x019C -#define EMAC_SGMII_LN_RX_BAND 0x01A4 -#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0 0x01C0 -#define EMAC_SGMII_LN_RSM_CONFIG 0x01F8 -#define EMAC_SGMII_LN_SIGDET_ENABLES 0x0230 -#define EMAC_SGMII_LN_SIGDET_CNTRL 0x0234 -#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL 0x0238 -#define EMAC_SGMII_LN_RX_EN_SIGNAL 0x02AC -#define EMAC_SGMII_LN_RX_MISC_CNTRL0 0x02B8 -#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV 0x02C8 -#define EMAC_SGMII_LN_RX_RESECODE_OFFSET 0x02CC - -/* SGMII digital lane register values */ -#define UCDR_STEP_BY_TWO_MODE0 BIT(7) -#define UCDR_xO_GAIN_MODE(x) ((x) & 0x7f) -#define UCDR_ENABLE BIT(6) -#define UCDR_SO_SATURATION(x) ((x) & 0x3f) - -#define SIGDET_LP_BYP_PS4 BIT(7) -#define SIGDET_EN_PS0_TO_PS2 BIT(6) - -#define TXVAL_VALID_INIT BIT(4) -#define KR_PCIGEN3_MODE BIT(0) - -#define MAIN_EN BIT(0) - -#define TX_MARGINING_MUX BIT(6) -#define TX_MARGINING(x) ((x) & 0x3f) - -#define TX_PRE_MUX BIT(6) - -#define TX_POST_MUX BIT(6) - -#define CML_GEAR_MODE(x) (((x) & 7) << 3) -#define CML2CMOS_IBOOST_MODE(x) ((x) & 7) - -#define RESCODE_OFFSET(x) ((x) & 0x1f) - -#define MIXER_LOADB_MODE(x) (((x) & 0xf) << 2) -#define MIXER_DATARATE_MODE(x) ((x) & 3) - -#define VGA_THRESH_DFE(x) ((x) & 0x3f) - -#define SIGDET_LP_BYP_PS0_TO_PS2 BIT(5) -#define SIGDET_FLT_BYP BIT(0) - -#define SIGDET_LVL(x) (((x) & 0xf) << 4) - -#define SIGDET_DEGLITCH_CTRL(x) (((x) & 0xf) << 1) - -#define INVERT_PCS_RX_CLK BIT(7) - -#define DRVR_LOGIC_CLK_EN BIT(4) -#define DRVR_LOGIC_CLK_DIV(x) ((x) & 0xf) - -#define PARALLEL_RATE_MODE0(x) ((x) & 0x3) - -#define BAND_MODE0(x) ((x) & 0x3) - -#define LANE_MODE(x) ((x) & 0x1f) - -#define CDR_PD_SEL_MODE0(x) (((x) & 0x3) << 5) -#define EN_DLL_MODE0 BIT(4) -#define EN_IQ_DCC_MODE0 BIT(3) -#define EN_IQCAL_MODE0 BIT(2) - -#define BYPASS_RSM_SAMP_CAL BIT(1) -#define BYPASS_RSM_DLL_CAL BIT(0) - -#define L0_RX_EQUALIZE_ENABLE BIT(6) - -#define PWRDN_B BIT(0) - -#define CDR_MAX_CNT(x) ((x) & 0xff) - -#define SERDES_START_WAIT_TIMES 100 - -struct emac_reg_write { - unsigned int offset; - u32 val; -}; - -static void emac_reg_write_all(void __iomem *base, - const struct emac_reg_write *itr, size_t size) -{ - size_t i; - - for (i = 0; i < size; ++itr, ++i) - writel(itr->val, base + itr->offset); -} - -static const struct emac_reg_write sgmii_laned[] = { - /* CDR Settings */ - {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0, - UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)}, - {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)}, - {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)}, - - /* TX/RX Settings */ - {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2}, - - {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE}, - {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN}, - {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)}, - {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX}, - {EMAC_SGMII_LN_TX_POST, TX_POST_MUX}, - - {EMAC_SGMII_LN_CML_CTRL_MODE0, - CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)}, - {EMAC_SGMII_LN_MIXER_CTRL_MODE0, - MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)}, - {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)}, - {EMAC_SGMII_LN_SIGDET_ENABLES, - SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP}, - {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)}, - - {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)}, - {EMAC_SGMII_LN_RX_MISC_CNTRL0, INVERT_PCS_RX_CLK}, - {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV, - DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)}, - - {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)}, - {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(1)}, - {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(2)}, - {EMAC_SGMII_LN_DRVR_CTRL1, RESCODE_OFFSET(7)}, - {EMAC_SGMII_LN_RX_RESECODE_OFFSET, RESCODE_OFFSET(9)}, - {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)}, - {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(2) | - EN_DLL_MODE0 | EN_IQ_DCC_MODE0 | EN_IQCAL_MODE0}, - {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL}, -}; - -static const struct emac_reg_write physical_coding_sublayer_programming[] = { - {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B}, - {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)}, - {EMAC_SGMII_PHY_TX_PWR_CTRL, 0}, - {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE}, -}; - -int emac_sgmii_init_qdf2400(struct emac_adapter *adpt) -{ - struct emac_sgmii *phy = &adpt->phy; - void __iomem *phy_regs = phy->base; - void __iomem *laned = phy->digital; - unsigned int i; - u32 lnstatus; - - /* PCS lane-x init */ - emac_reg_write_all(phy->base, physical_coding_sublayer_programming, - ARRAY_SIZE(physical_coding_sublayer_programming)); - - /* SGMII lane-x init */ - emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned)); - - /* Power up PCS and start reset lane state machine */ - - writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL); - writel(1, laned + SGMII_LN_RSM_START); - - /* Wait for c_ready assertion */ - for (i = 0; i < SERDES_START_WAIT_TIMES; i++) { - lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS); - if (lnstatus & BIT(1)) - break; - usleep_range(100, 200); - } - - if (i == SERDES_START_WAIT_TIMES) { - netdev_err(adpt->netdev, "SGMII failed to start\n"); - return -EIO; - } - - /* Disable digital and SERDES loopback */ - writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0); - writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2); - writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1); - - /* Mask out all the SGMII Interrupt */ - writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK); - - return 0; -} diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c deleted file mode 100644 index 65519eeebecd..000000000000 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - */ - -/* Qualcomm Technologies, Inc. QDF2432 EMAC SGMII Controller driver. - */ - -#include -#include "emac.h" - -/* EMAC_SGMII register offsets */ -#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x000C -#define EMAC_SGMII_PHY_LANE_CTRL1 0x0018 -#define EMAC_SGMII_PHY_CDR_CTRL0 0x0058 -#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x0080 -#define EMAC_SGMII_PHY_RESET_CTRL 0x00a8 -#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4 - -/* SGMII digital lane registers */ -#define EMAC_SGMII_LN_DRVR_CTRL0 0x000C -#define EMAC_SGMII_LN_DRVR_TAP_EN 0x0018 -#define EMAC_SGMII_LN_TX_MARGINING 0x001C -#define EMAC_SGMII_LN_TX_PRE 0x0020 -#define EMAC_SGMII_LN_TX_POST 0x0024 -#define EMAC_SGMII_LN_TX_BAND_MODE 0x0060 -#define EMAC_SGMII_LN_LANE_MODE 0x0064 -#define EMAC_SGMII_LN_PARALLEL_RATE 0x0078 -#define EMAC_SGMII_LN_CML_CTRL_MODE0 0x00B8 -#define EMAC_SGMII_LN_MIXER_CTRL_MODE0 0x00D0 -#define EMAC_SGMII_LN_VGA_INITVAL 0x0134 -#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0 0x017C -#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0 0x0188 -#define EMAC_SGMII_LN_UCDR_SO_CONFIG 0x0194 -#define EMAC_SGMII_LN_RX_BAND 0x019C -#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0 0x01B8 -#define EMAC_SGMII_LN_RSM_CONFIG 0x01F0 -#define EMAC_SGMII_LN_SIGDET_ENABLES 0x0224 -#define EMAC_SGMII_LN_SIGDET_CNTRL 0x0228 -#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL 0x022C -#define EMAC_SGMII_LN_RX_EN_SIGNAL 0x02A0 -#define EMAC_SGMII_LN_RX_MISC_CNTRL0 0x02AC -#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV 0x02BC - -/* SGMII digital lane register values */ -#define UCDR_STEP_BY_TWO_MODE0 BIT(7) -#define UCDR_xO_GAIN_MODE(x) ((x) & 0x7f) -#define UCDR_ENABLE BIT(6) -#define UCDR_SO_SATURATION(x) ((x) & 0x3f) - -#define SIGDET_LP_BYP_PS4 BIT(7) -#define SIGDET_EN_PS0_TO_PS2 BIT(6) - -#define TXVAL_VALID_INIT BIT(4) -#define KR_PCIGEN3_MODE BIT(0) - -#define MAIN_EN BIT(0) - -#define TX_MARGINING_MUX BIT(6) -#define TX_MARGINING(x) ((x) & 0x3f) - -#define TX_PRE_MUX BIT(6) - -#define TX_POST_MUX BIT(6) - -#define CML_GEAR_MODE(x) (((x) & 7) << 3) -#define CML2CMOS_IBOOST_MODE(x) ((x) & 7) - -#define MIXER_LOADB_MODE(x) (((x) & 0xf) << 2) -#define MIXER_DATARATE_MODE(x) ((x) & 3) - -#define VGA_THRESH_DFE(x) ((x) & 0x3f) - -#define SIGDET_LP_BYP_PS0_TO_PS2 BIT(5) -#define SIGDET_FLT_BYP BIT(0) - -#define SIGDET_LVL(x) (((x) & 0xf) << 4) - -#define SIGDET_DEGLITCH_CTRL(x) (((x) & 0xf) << 1) - -#define DRVR_LOGIC_CLK_EN BIT(4) -#define DRVR_LOGIC_CLK_DIV(x) ((x) & 0xf) - -#define PARALLEL_RATE_MODE0(x) ((x) & 0x3) - -#define BAND_MODE0(x) ((x) & 0x3) - -#define LANE_MODE(x) ((x) & 0x1f) - -#define CDR_PD_SEL_MODE0(x) (((x) & 0x3) << 5) -#define BYPASS_RSM_SAMP_CAL BIT(1) -#define BYPASS_RSM_DLL_CAL BIT(0) - -#define L0_RX_EQUALIZE_ENABLE BIT(6) - -#define PWRDN_B BIT(0) - -#define CDR_MAX_CNT(x) ((x) & 0xff) - -#define SERDES_START_WAIT_TIMES 100 - -struct emac_reg_write { - unsigned int offset; - u32 val; -}; - -static void emac_reg_write_all(void __iomem *base, - const struct emac_reg_write *itr, size_t size) -{ - size_t i; - - for (i = 0; i < size; ++itr, ++i) - writel(itr->val, base + itr->offset); -} - -static const struct emac_reg_write sgmii_laned[] = { - /* CDR Settings */ - {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0, - UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)}, - {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)}, - {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)}, - - /* TX/RX Settings */ - {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2}, - - {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE}, - {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN}, - {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)}, - {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX}, - {EMAC_SGMII_LN_TX_POST, TX_POST_MUX}, - - {EMAC_SGMII_LN_CML_CTRL_MODE0, - CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)}, - {EMAC_SGMII_LN_MIXER_CTRL_MODE0, - MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)}, - {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)}, - {EMAC_SGMII_LN_SIGDET_ENABLES, - SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP}, - {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)}, - - {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)}, - {EMAC_SGMII_LN_RX_MISC_CNTRL0, 0}, - {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV, - DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)}, - - {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)}, - {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)}, - {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)}, - {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)}, - {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)}, - {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL}, -}; - -static const struct emac_reg_write physical_coding_sublayer_programming[] = { - {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B}, - {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)}, - {EMAC_SGMII_PHY_TX_PWR_CTRL, 0}, - {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE}, -}; - -int emac_sgmii_init_qdf2432(struct emac_adapter *adpt) -{ - struct emac_sgmii *phy = &adpt->phy; - void __iomem *phy_regs = phy->base; - void __iomem *laned = phy->digital; - unsigned int i; - u32 lnstatus; - - /* PCS lane-x init */ - emac_reg_write_all(phy->base, physical_coding_sublayer_programming, - ARRAY_SIZE(physical_coding_sublayer_programming)); - - /* SGMII lane-x init */ - emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned)); - - /* Power up PCS and start reset lane state machine */ - - writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL); - writel(1, laned + SGMII_LN_RSM_START); - - /* Wait for c_ready assertion */ - for (i = 0; i < SERDES_START_WAIT_TIMES; i++) { - lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS); - if (lnstatus & BIT(1)) - break; - usleep_range(100, 200); - } - - if (i == SERDES_START_WAIT_TIMES) { - netdev_err(adpt->netdev, "SGMII failed to start\n"); - return -EIO; - } - - /* Disable digital and SERDES loopback */ - writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0); - writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2); - writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1); - - /* Mask out all the SGMII Interrupt */ - writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK); - - return 0; -} diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c index e4bc18009d08..573c82b21de5 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -275,76 +274,11 @@ static struct sgmii_ops fsm9900_ops = { .reset = emac_sgmii_common_reset, }; -static struct sgmii_ops qdf2432_ops = { - .init = emac_sgmii_init_qdf2432, - .open = emac_sgmii_common_open, - .close = emac_sgmii_common_close, - .link_change = emac_sgmii_common_link_change, - .reset = emac_sgmii_common_reset, -}; - -#ifdef CONFIG_ACPI -static struct sgmii_ops qdf2400_ops = { - .init = emac_sgmii_init_qdf2400, - .open = emac_sgmii_common_open, - .close = emac_sgmii_common_close, - .link_change = emac_sgmii_common_link_change, - .reset = emac_sgmii_common_reset, -}; -#endif - -static int emac_sgmii_acpi_match(struct device *dev, void *data) -{ -#ifdef CONFIG_ACPI - static const struct acpi_device_id match_table[] = { - { - .id = "QCOM8071", - }, - {} - }; - const struct acpi_device_id *id = acpi_match_device(match_table, dev); - struct sgmii_ops **ops = data; - - if (id) { - acpi_handle handle = ACPI_HANDLE(dev); - unsigned long long hrv; - acpi_status status; - - status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv); - if (status) { - if (status == AE_NOT_FOUND) - /* Older versions of the QDF2432 ACPI tables do - * not have an _HRV property. - */ - hrv = 1; - else - /* Something is wrong with the tables */ - return 0; - } - - switch (hrv) { - case 1: - *ops = &qdf2432_ops; - return 1; - case 2: - *ops = &qdf2400_ops; - return 1; - } - } -#endif - - return 0; -} - static const struct of_device_id emac_sgmii_dt_match[] = { { .compatible = "qcom,fsm9900-emac-sgmii", .data = &fsm9900_ops, }, - { - .compatible = "qcom,qdf2432-emac-sgmii", - .data = &qdf2432_ops, - }, {} }; @@ -355,45 +289,31 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) struct resource *res; int ret; - if (has_acpi_companion(&pdev->dev)) { - struct device *dev; + const struct of_device_id *match; + struct device_node *np; - dev = device_find_child(&pdev->dev, &phy->sgmii_ops, - emac_sgmii_acpi_match); - - if (!dev) { - dev_warn(&pdev->dev, "cannot find internal phy node\n"); - return 0; - } - - sgmii_pdev = to_platform_device(dev); - } else { - const struct of_device_id *match; - struct device_node *np; - - np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0); - if (!np) { - dev_err(&pdev->dev, "missing internal-phy property\n"); - return -ENODEV; - } - - sgmii_pdev = of_find_device_by_node(np); - of_node_put(np); - if (!sgmii_pdev) { - dev_err(&pdev->dev, "invalid internal-phy property\n"); - return -ENODEV; - } - - match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev); - if (!match) { - dev_err(&pdev->dev, "unrecognized internal phy node\n"); - ret = -ENODEV; - goto error_put_device; - } - - phy->sgmii_ops = (struct sgmii_ops *)match->data; + np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0); + if (!np) { + dev_err(&pdev->dev, "missing internal-phy property\n"); + return -ENODEV; } + sgmii_pdev = of_find_device_by_node(np); + of_node_put(np); + if (!sgmii_pdev) { + dev_err(&pdev->dev, "invalid internal-phy property\n"); + return -ENODEV; + } + + match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev); + if (!match) { + dev_err(&pdev->dev, "unrecognized internal phy node\n"); + ret = -ENODEV; + goto error_put_device; + } + + phy->sgmii_ops = (struct sgmii_ops *)match->data; + /* Base address is the first address */ res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h index 6daeddacbcfa..7b7b0dc44225 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h @@ -40,8 +40,6 @@ struct emac_sgmii { int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt); int emac_sgmii_init_fsm9900(struct emac_adapter *adpt); -int emac_sgmii_init_qdf2432(struct emac_adapter *adpt); -int emac_sgmii_init_qdf2400(struct emac_adapter *adpt); int emac_sgmii_init(struct emac_adapter *adpt); int emac_sgmii_open(struct emac_adapter *adpt); From a6348a7104e0dac7b9b4b7042c3c8c36b81d71e7 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 22 Jan 2024 10:19:54 -0800 Subject: [PATCH 0248/2255] net/ipv6: Remove unnecessary pr_debug() logs In the ipv6 system, we have some logs basically dumping the name of the function that is being called. This is not ideal, since ftrace give us "for free". Moreover, checkpatch is not happy when touching that code: WARNING: Unnecessary ftrace-like logging - prefer using ftrace Remove debug functions that only print the current function name. Signed-off-by: Breno Leitao Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20240122181955.2391676-1-leitao@debian.org Signed-off-by: Jakub Kicinski --- net/ipv6/ip6_fib.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 4fc2cae0d116..fb41bec6b4b5 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -751,8 +751,6 @@ static struct fib6_node *fib6_add_1(struct net *net, int bit; __be32 dir = 0; - RT6_TRACE("fib6_add_1\n"); - /* insert node in tree */ fn = root; @@ -1905,8 +1903,6 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn, struct net *net = info->nl_net; bool notify_del = false; - RT6_TRACE("fib6_del_route\n"); - /* If the deleted route is the first in the node and it is not part of * a multipath route, then we need to replace it with the next route * in the node, if exists. From 20df28fb5bd8081a05ec34542bd45e4f3feeced5 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 22 Jan 2024 10:19:55 -0800 Subject: [PATCH 0249/2255] net/ipv6: resolve warning in ip6_fib.c In some configurations, the 'iter' variable in function fib6_repair_tree() is unused, resulting the following warning when compiled with W=1. net/ipv6/ip6_fib.c:1781:6: warning: variable 'iter' set but not used [-Wunused-but-set-variable] 1781 | int iter = 0; | ^ It is unclear what is the advantage of this RT6_TRACE() macro[1], since users can control pr_debug() in runtime, which is better than at compilation time. pr_debug() has no overhead when disabled. Remove the RT6_TRACE() in favor of simple pr_debug() helpers. [1] Link: https://lore.kernel.org/all/ZZwSEJv2HgI0cD4J@gmail.com/ Signed-off-by: Breno Leitao Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20240122181955.2391676-2-leitao@debian.org Signed-off-by: Jakub Kicinski --- include/net/ip6_fib.h | 6 ------ net/ipv6/ip6_fib.c | 15 +++++++++------ net/ipv6/route.c | 8 ++++---- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 9ba6413fd2e3..360b12e61850 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -30,12 +30,6 @@ #define RT6_DEBUG 2 -#if RT6_DEBUG >= 3 -#define RT6_TRACE(x...) pr_debug(x) -#else -#define RT6_TRACE(x...) do { ; } while (0) -#endif - struct rt6_info; struct fib6_info; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index fb41bec6b4b5..38a0348b1d17 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1801,7 +1801,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net, lockdep_is_held(&table->tb6_lock)); struct fib6_info *new_fn_leaf; - RT6_TRACE("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter); + pr_debug("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter); iter++; WARN_ON(fn->fn_flags & RTN_RTINFO); @@ -1864,7 +1864,8 @@ static struct fib6_node *fib6_repair_tree(struct net *net, FOR_WALKERS(net, w) { if (!child) { if (w->node == fn) { - RT6_TRACE("W %p adjusted by delnode 1, s=%d/%d\n", w, w->state, nstate); + pr_debug("W %p adjusted by delnode 1, s=%d/%d\n", + w, w->state, nstate); w->node = pn; w->state = nstate; } @@ -1872,10 +1873,12 @@ static struct fib6_node *fib6_repair_tree(struct net *net, if (w->node == fn) { w->node = child; if (children&2) { - RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state); + pr_debug("W %p adjusted by delnode 2, s=%d\n", + w, w->state); w->state = w->state >= FWS_R ? FWS_U : FWS_INIT; } else { - RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state); + pr_debug("W %p adjusted by delnode 2, s=%d\n", + w, w->state); w->state = w->state >= FWS_C ? FWS_U : FWS_INIT; } } @@ -1951,7 +1954,7 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn, read_lock(&net->ipv6.fib6_walker_lock); FOR_WALKERS(net, w) { if (w->state == FWS_C && w->leaf == rt) { - RT6_TRACE("walker %p adjusted by delroute\n", w); + pr_debug("walker %p adjusted by delroute\n", w); w->leaf = rcu_dereference_protected(rt->fib6_next, lockdep_is_held(&table->tb6_lock)); if (!w->leaf) @@ -2289,7 +2292,7 @@ static int fib6_age(struct fib6_info *rt, void *arg) if (rt->fib6_flags & RTF_EXPIRES && rt->expires) { if (time_after(now, rt->expires)) { - RT6_TRACE("expiring %p\n", rt); + pr_debug("expiring %p\n", rt); return -1; } gc_args->more++; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ea1dec8448fc..63b4c6056582 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2085,12 +2085,12 @@ static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket, */ if (!(rt->rt6i_flags & RTF_EXPIRES)) { if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) { - RT6_TRACE("aging clone %p\n", rt); + pr_debug("aging clone %p\n", rt); rt6_remove_exception(bucket, rt6_ex); return; } } else if (time_after(jiffies, rt->dst.expires)) { - RT6_TRACE("purging expired route %p\n", rt); + pr_debug("purging expired route %p\n", rt); rt6_remove_exception(bucket, rt6_ex); return; } @@ -2101,8 +2101,8 @@ static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket, neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); if (!(neigh && (neigh->flags & NTF_ROUTER))) { - RT6_TRACE("purging route %p via non-router but gateway\n", - rt); + pr_debug("purging route %p via non-router but gateway\n", + rt); rt6_remove_exception(bucket, rt6_ex); return; } From 7cea48b9a4b2433a59826ee7cdb594faab3ac1e7 Mon Sep 17 00:00:00 2001 From: Shailend Chand Date: Mon, 22 Jan 2024 18:26:27 +0000 Subject: [PATCH 0250/2255] gve: Define config structs for queue allocation Queue allocation functions currently can only allocate into priv and free memory in priv. These new structs would be passed into the queue functions in a subsequent change to make them capable of returning newly allocated resources and not just writing them into priv. They also make it possible to allocate resources for queues with a different config than that of the currently active queues. Signed-off-by: Shailend Chand Reviewed-by: Willem de Bruijn Reviewed-by: Jeroen de Borst Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240122182632.1102721-2-shailend@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve.h | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index b80349154604..00e7f8b06d89 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -622,6 +622,55 @@ struct gve_ptype_lut { struct gve_ptype ptypes[GVE_NUM_PTYPES]; }; +/* Parameters for allocating queue page lists */ +struct gve_qpls_alloc_cfg { + struct gve_qpl_config *qpl_cfg; + struct gve_queue_config *tx_cfg; + struct gve_queue_config *rx_cfg; + + u16 num_xdp_queues; + bool raw_addressing; + bool is_gqi; + + /* Allocated resources are returned here */ + struct gve_queue_page_list *qpls; +}; + +/* Parameters for allocating resources for tx queues */ +struct gve_tx_alloc_rings_cfg { + struct gve_queue_config *qcfg; + + /* qpls and qpl_cfg must already be allocated */ + struct gve_queue_page_list *qpls; + struct gve_qpl_config *qpl_cfg; + + u16 ring_size; + u16 start_idx; + u16 num_rings; + bool raw_addressing; + + /* Allocated resources are returned here */ + struct gve_tx_ring *tx; +}; + +/* Parameters for allocating resources for rx queues */ +struct gve_rx_alloc_rings_cfg { + /* tx config is also needed to determine QPL ids */ + struct gve_queue_config *qcfg; + struct gve_queue_config *qcfg_tx; + + /* qpls and qpl_cfg must already be allocated */ + struct gve_queue_page_list *qpls; + struct gve_qpl_config *qpl_cfg; + + u16 ring_size; + bool raw_addressing; + bool enable_header_split; + + /* Allocated resources are returned here */ + struct gve_rx_ring *rx; +}; + /* GVE_QUEUE_FORMAT_UNSPECIFIED must be zero since 0 is the default value * when the entire configure_device_resources command is zeroed out and the * queue_format is not specified. From 1dfc2e46117e5c41037e27e859e75a7518881ee6 Mon Sep 17 00:00:00 2001 From: Shailend Chand Date: Mon, 22 Jan 2024 18:26:28 +0000 Subject: [PATCH 0251/2255] gve: Refactor napi add and remove functions This change makes the napi poll functions non-static and moves the gve_(add|remove)_napi functions to gve_utils.c, to make possible future "start queue" hooks in the datapath files. Signed-off-by: Shailend Chand Reviewed-by: Willem de Bruijn Reviewed-by: Jeroen de Borst Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240122182632.1102721-3-shailend@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve.h | 3 +++ drivers/net/ethernet/google/gve/gve_dqo.h | 2 ++ drivers/net/ethernet/google/gve/gve_main.c | 20 +++----------------- drivers/net/ethernet/google/gve/gve_utils.c | 15 +++++++++++++++ drivers/net/ethernet/google/gve/gve_utils.h | 3 +++ 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index 00e7f8b06d89..ba6819ac600e 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -1085,6 +1085,9 @@ static inline u32 gve_xdp_tx_start_queue_id(struct gve_priv *priv) return gve_xdp_tx_queue_id(priv, 0); } +/* gqi napi handler defined in gve_main.c */ +int gve_napi_poll(struct napi_struct *napi, int budget); + /* buffers */ int gve_alloc_page(struct gve_priv *priv, struct device *dev, struct page **page, dma_addr_t *dma, diff --git a/drivers/net/ethernet/google/gve/gve_dqo.h b/drivers/net/ethernet/google/gve/gve_dqo.h index c36b93f0de15..8058b09f8e3e 100644 --- a/drivers/net/ethernet/google/gve/gve_dqo.h +++ b/drivers/net/ethernet/google/gve/gve_dqo.h @@ -93,4 +93,6 @@ gve_set_itr_coalesce_usecs_dqo(struct gve_priv *priv, gve_write_irq_doorbell_dqo(priv, block, gve_setup_itr_interval_dqo(usecs)); } + +int gve_napi_poll_dqo(struct napi_struct *napi, int budget); #endif /* _GVE_DQO_H_ */ diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 619bf63ec935..e07048cd249e 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -22,6 +22,7 @@ #include "gve_dqo.h" #include "gve_adminq.h" #include "gve_register.h" +#include "gve_utils.h" #define GVE_DEFAULT_RX_COPYBREAK (256) @@ -252,7 +253,7 @@ static irqreturn_t gve_intr_dqo(int irq, void *arg) return IRQ_HANDLED; } -static int gve_napi_poll(struct napi_struct *napi, int budget) +int gve_napi_poll(struct napi_struct *napi, int budget) { struct gve_notify_block *block; __be32 __iomem *irq_doorbell; @@ -302,7 +303,7 @@ static int gve_napi_poll(struct napi_struct *napi, int budget) return work_done; } -static int gve_napi_poll_dqo(struct napi_struct *napi, int budget) +int gve_napi_poll_dqo(struct napi_struct *napi, int budget) { struct gve_notify_block *block = container_of(napi, struct gve_notify_block, napi); @@ -581,21 +582,6 @@ static void gve_teardown_device_resources(struct gve_priv *priv) gve_clear_device_resources_ok(priv); } -static void gve_add_napi(struct gve_priv *priv, int ntfy_idx, - int (*gve_poll)(struct napi_struct *, int)) -{ - struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; - - netif_napi_add(priv->dev, &block->napi, gve_poll); -} - -static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) -{ - struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; - - netif_napi_del(&block->napi); -} - static int gve_register_xdp_qpls(struct gve_priv *priv) { int start_id; diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index 26e08d753270..974a75623789 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -81,3 +81,18 @@ void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info) page_ref_add(page_info->page, INT_MAX - pagecount); } } + +void gve_add_napi(struct gve_priv *priv, int ntfy_idx, + int (*gve_poll)(struct napi_struct *, int)) +{ + struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + + netif_napi_add(priv->dev, &block->napi, gve_poll); +} + +void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) +{ + struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + + netif_napi_del(&block->napi); +} diff --git a/drivers/net/ethernet/google/gve/gve_utils.h b/drivers/net/ethernet/google/gve/gve_utils.h index 324fd98a6112..924516e9eaae 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.h +++ b/drivers/net/ethernet/google/gve/gve_utils.h @@ -23,5 +23,8 @@ struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi, /* Decrement pagecnt_bias. Set it back to INT_MAX if it reached zero. */ void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info); +void gve_add_napi(struct gve_priv *priv, int ntfy_idx, + int (*gve_poll)(struct napi_struct *, int)); +void gve_remove_napi(struct gve_priv *priv, int ntfy_idx); #endif /* _GVE_UTILS_H */ From f13697cc7a19225307d85b0a77ef1c15abe95a7d Mon Sep 17 00:00:00 2001 From: Shailend Chand Date: Mon, 22 Jan 2024 18:26:29 +0000 Subject: [PATCH 0252/2255] gve: Switch to config-aware queue allocation The new config-aware functions will help achieve the goal of being able to allocate resources for new queues while there already are active queues serving traffic. These new functions work off of arbitrary queue allocation configs rather than just the currently active config in priv, and they return the newly allocated resources instead of writing them into priv. Signed-off-by: Shailend Chand Reviewed-by: Willem de Bruijn Reviewed-by: Jeroen de Borst Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240122182632.1102721-4-shailend@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve.h | 92 +-- drivers/net/ethernet/google/gve/gve_dqo.h | 16 +- drivers/net/ethernet/google/gve/gve_main.c | 607 +++++++++++-------- drivers/net/ethernet/google/gve/gve_rx.c | 116 ++-- drivers/net/ethernet/google/gve/gve_rx_dqo.c | 91 ++- drivers/net/ethernet/google/gve/gve_tx.c | 128 ++-- drivers/net/ethernet/google/gve/gve_tx_dqo.c | 108 +++- drivers/net/ethernet/google/gve/gve_utils.c | 16 + drivers/net/ethernet/google/gve/gve_utils.h | 2 + 9 files changed, 748 insertions(+), 428 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index ba6819ac600e..fd290f3ad6ec 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -966,14 +966,14 @@ static inline bool gve_is_qpl(struct gve_priv *priv) priv->queue_format == GVE_DQO_QPL_FORMAT; } -/* Returns the number of tx queue page lists - */ -static inline u32 gve_num_tx_qpls(struct gve_priv *priv) +/* Returns the number of tx queue page lists */ +static inline u32 gve_num_tx_qpls(const struct gve_queue_config *tx_cfg, + int num_xdp_queues, + bool is_qpl) { - if (!gve_is_qpl(priv)) + if (!is_qpl) return 0; - - return priv->tx_cfg.num_queues + priv->num_xdp_queues; + return tx_cfg->num_queues + num_xdp_queues; } /* Returns the number of XDP tx queue page lists @@ -986,14 +986,13 @@ static inline u32 gve_num_xdp_qpls(struct gve_priv *priv) return priv->num_xdp_queues; } -/* Returns the number of rx queue page lists - */ -static inline u32 gve_num_rx_qpls(struct gve_priv *priv) +/* Returns the number of rx queue page lists */ +static inline u32 gve_num_rx_qpls(const struct gve_queue_config *rx_cfg, + bool is_qpl) { - if (!gve_is_qpl(priv)) + if (!is_qpl) return 0; - - return priv->rx_cfg.num_queues; + return rx_cfg->num_queues; } static inline u32 gve_tx_qpl_id(struct gve_priv *priv, int tx_qid) @@ -1006,59 +1005,59 @@ static inline u32 gve_rx_qpl_id(struct gve_priv *priv, int rx_qid) return priv->tx_cfg.max_queues + rx_qid; } +/* Returns the index into priv->qpls where a certain rx queue's QPL resides */ +static inline u32 gve_get_rx_qpl_id(const struct gve_queue_config *tx_cfg, int rx_qid) +{ + return tx_cfg->max_queues + rx_qid; +} + static inline u32 gve_tx_start_qpl_id(struct gve_priv *priv) { return gve_tx_qpl_id(priv, 0); } -static inline u32 gve_rx_start_qpl_id(struct gve_priv *priv) +/* Returns the index into priv->qpls where the first rx queue's QPL resides */ +static inline u32 gve_rx_start_qpl_id(const struct gve_queue_config *tx_cfg) { - return gve_rx_qpl_id(priv, 0); + return gve_get_rx_qpl_id(tx_cfg, 0); } -/* Returns a pointer to the next available tx qpl in the list of qpls - */ +/* Returns a pointer to the next available tx qpl in the list of qpls */ static inline -struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_priv *priv, int tx_qid) +struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_tx_alloc_rings_cfg *cfg, + int tx_qid) { - int id = gve_tx_qpl_id(priv, tx_qid); - /* QPL already in use */ - if (test_bit(id, priv->qpl_cfg.qpl_id_map)) + if (test_bit(tx_qid, cfg->qpl_cfg->qpl_id_map)) return NULL; - - set_bit(id, priv->qpl_cfg.qpl_id_map); - return &priv->qpls[id]; + set_bit(tx_qid, cfg->qpl_cfg->qpl_id_map); + return &cfg->qpls[tx_qid]; } -/* Returns a pointer to the next available rx qpl in the list of qpls - */ +/* Returns a pointer to the next available rx qpl in the list of qpls */ static inline -struct gve_queue_page_list *gve_assign_rx_qpl(struct gve_priv *priv, int rx_qid) +struct gve_queue_page_list *gve_assign_rx_qpl(struct gve_rx_alloc_rings_cfg *cfg, + int rx_qid) { - int id = gve_rx_qpl_id(priv, rx_qid); - + int id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx_qid); /* QPL already in use */ - if (test_bit(id, priv->qpl_cfg.qpl_id_map)) + if (test_bit(id, cfg->qpl_cfg->qpl_id_map)) return NULL; - - set_bit(id, priv->qpl_cfg.qpl_id_map); - return &priv->qpls[id]; + set_bit(id, cfg->qpl_cfg->qpl_id_map); + return &cfg->qpls[id]; } -/* Unassigns the qpl with the given id - */ -static inline void gve_unassign_qpl(struct gve_priv *priv, int id) +/* Unassigns the qpl with the given id */ +static inline void gve_unassign_qpl(struct gve_qpl_config *qpl_cfg, int id) { - clear_bit(id, priv->qpl_cfg.qpl_id_map); + clear_bit(id, qpl_cfg->qpl_id_map); } -/* Returns the correct dma direction for tx and rx qpls - */ +/* Returns the correct dma direction for tx and rx qpls */ static inline enum dma_data_direction gve_qpl_dma_dir(struct gve_priv *priv, int id) { - if (id < gve_rx_start_qpl_id(priv)) + if (id < gve_rx_start_qpl_id(&priv->tx_cfg)) return DMA_TO_DEVICE; else return DMA_FROM_DEVICE; @@ -1103,8 +1102,12 @@ int gve_xdp_xmit_one(struct gve_priv *priv, struct gve_tx_ring *tx, void gve_xdp_tx_flush(struct gve_priv *priv, u32 xdp_qid); bool gve_tx_poll(struct gve_notify_block *block, int budget); bool gve_xdp_poll(struct gve_notify_block *block, int budget); -int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings); -void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings); +int gve_tx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_free_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx); +void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx); u32 gve_tx_load_event_counter(struct gve_priv *priv, struct gve_tx_ring *tx); bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx); @@ -1113,7 +1116,12 @@ void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx); int gve_rx_poll(struct gve_notify_block *block, int budget); bool gve_rx_work_pending(struct gve_rx_ring *rx); int gve_rx_alloc_rings(struct gve_priv *priv); -void gve_rx_free_rings_gqi(struct gve_priv *priv); +int gve_rx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_free_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx); +void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx); /* Reset */ void gve_schedule_reset(struct gve_priv *priv); int gve_reset(struct gve_priv *priv, bool attempt_teardown); diff --git a/drivers/net/ethernet/google/gve/gve_dqo.h b/drivers/net/ethernet/google/gve/gve_dqo.h index 8058b09f8e3e..b81584829c40 100644 --- a/drivers/net/ethernet/google/gve/gve_dqo.h +++ b/drivers/net/ethernet/google/gve/gve_dqo.h @@ -38,10 +38,18 @@ netdev_features_t gve_features_check_dqo(struct sk_buff *skb, netdev_features_t features); bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean); int gve_rx_poll_dqo(struct gve_notify_block *block, int budget); -int gve_tx_alloc_rings_dqo(struct gve_priv *priv); -void gve_tx_free_rings_dqo(struct gve_priv *priv); -int gve_rx_alloc_rings_dqo(struct gve_priv *priv); -void gve_rx_free_rings_dqo(struct gve_priv *priv); +int gve_tx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_free_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_start_ring_dqo(struct gve_priv *priv, int idx); +void gve_tx_stop_ring_dqo(struct gve_priv *priv, int idx); +int gve_rx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_free_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx); +void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx); int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx, struct napi_struct *napi); void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx); diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index e07048cd249e..8049a47c38fc 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -582,61 +582,102 @@ static void gve_teardown_device_resources(struct gve_priv *priv) gve_clear_device_resources_ok(priv); } +static int gve_unregister_qpl(struct gve_priv *priv, u32 i) +{ + int err; + + err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); + if (err) { + netif_err(priv, drv, priv->dev, + "Failed to unregister queue page list %d\n", + priv->qpls[i].id); + return err; + } + + priv->num_registered_pages -= priv->qpls[i].num_entries; + return 0; +} + +static int gve_register_qpl(struct gve_priv *priv, u32 i) +{ + int num_rx_qpls; + int pages; + int err; + + /* Rx QPLs succeed Tx QPLs in the priv->qpls array. */ + num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv)); + if (i >= gve_rx_start_qpl_id(&priv->tx_cfg) + num_rx_qpls) { + netif_err(priv, drv, priv->dev, + "Cannot register nonexisting QPL at index %d\n", i); + return -EINVAL; + } + + pages = priv->qpls[i].num_entries; + + if (pages + priv->num_registered_pages > priv->max_registered_pages) { + netif_err(priv, drv, priv->dev, + "Reached max number of registered pages %llu > %llu\n", + pages + priv->num_registered_pages, + priv->max_registered_pages); + return -EINVAL; + } + + err = gve_adminq_register_page_list(priv, &priv->qpls[i]); + if (err) { + netif_err(priv, drv, priv->dev, + "failed to register queue page list %d\n", + priv->qpls[i].id); + /* This failure will trigger a reset - no need to clean + * up + */ + return err; + } + + priv->num_registered_pages += pages; + return 0; +} + static int gve_register_xdp_qpls(struct gve_priv *priv) { int start_id; int err; int i; - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); + start_id = gve_xdp_tx_start_queue_id(priv); for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) { - err = gve_adminq_register_page_list(priv, &priv->qpls[i]); - if (err) { - netif_err(priv, drv, priv->dev, - "failed to register queue page list %d\n", - priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean - * up - */ + err = gve_register_qpl(priv, i); + /* This failure will trigger a reset - no need to clean up */ + if (err) return err; - } } return 0; } static int gve_register_qpls(struct gve_priv *priv) { + int num_tx_qpls, num_rx_qpls; int start_id; int err; int i; - start_id = gve_tx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) { - err = gve_adminq_register_page_list(priv, &priv->qpls[i]); - if (err) { - netif_err(priv, drv, priv->dev, - "failed to register queue page list %d\n", - priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean - * up - */ + num_tx_qpls = gve_num_tx_qpls(&priv->tx_cfg, gve_num_xdp_qpls(priv), + gve_is_qpl(priv)); + num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv)); + + for (i = 0; i < num_tx_qpls; i++) { + err = gve_register_qpl(priv, i); + if (err) return err; - } } - start_id = gve_rx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) { - err = gve_adminq_register_page_list(priv, &priv->qpls[i]); - if (err) { - netif_err(priv, drv, priv->dev, - "failed to register queue page list %d\n", - priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean - * up - */ + /* there might be a gap between the tx and rx qpl ids */ + start_id = gve_rx_start_qpl_id(&priv->tx_cfg); + for (i = 0; i < num_rx_qpls; i++) { + err = gve_register_qpl(priv, start_id + i); + if (err) return err; - } } + return 0; } @@ -646,48 +687,40 @@ static int gve_unregister_xdp_qpls(struct gve_priv *priv) int err; int i; - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); + start_id = gve_xdp_tx_start_queue_id(priv); for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) { - err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean up */ - if (err) { - netif_err(priv, drv, priv->dev, - "Failed to unregister queue page list %d\n", - priv->qpls[i].id); + err = gve_unregister_qpl(priv, i); + /* This failure will trigger a reset - no need to clean */ + if (err) return err; - } } return 0; } static int gve_unregister_qpls(struct gve_priv *priv) { + int num_tx_qpls, num_rx_qpls; int start_id; int err; int i; - start_id = gve_tx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) { - err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean up */ - if (err) { - netif_err(priv, drv, priv->dev, - "Failed to unregister queue page list %d\n", - priv->qpls[i].id); + num_tx_qpls = gve_num_tx_qpls(&priv->tx_cfg, gve_num_xdp_qpls(priv), + gve_is_qpl(priv)); + num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv)); + + for (i = 0; i < num_tx_qpls; i++) { + err = gve_unregister_qpl(priv, i); + /* This failure will trigger a reset - no need to clean */ + if (err) return err; - } } - start_id = gve_rx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) { - err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean up */ - if (err) { - netif_err(priv, drv, priv->dev, - "Failed to unregister queue page list %d\n", - priv->qpls[i].id); + start_id = gve_rx_start_qpl_id(&priv->tx_cfg); + for (i = 0; i < num_rx_qpls; i++) { + err = gve_unregister_qpl(priv, start_id + i); + /* This failure will trigger a reset - no need to clean */ + if (err) return err; - } } return 0; } @@ -762,120 +795,124 @@ static int gve_create_rings(struct gve_priv *priv) return 0; } -static void add_napi_init_xdp_sync_stats(struct gve_priv *priv, - int (*napi_poll)(struct napi_struct *napi, - int budget)) +static void init_xdp_sync_stats(struct gve_priv *priv) { int start_id = gve_xdp_tx_start_queue_id(priv); int i; - /* Add xdp tx napi & init sync stats*/ + /* Init stats */ for (i = start_id; i < start_id + priv->num_xdp_queues; i++) { int ntfy_idx = gve_tx_idx_to_ntfy(priv, i); u64_stats_init(&priv->tx[i].statss); priv->tx[i].ntfy_id = ntfy_idx; - gve_add_napi(priv, ntfy_idx, napi_poll); } } -static void add_napi_init_sync_stats(struct gve_priv *priv, - int (*napi_poll)(struct napi_struct *napi, - int budget)) +static void gve_init_sync_stats(struct gve_priv *priv) { int i; - /* Add tx napi & init sync stats*/ - for (i = 0; i < gve_num_tx_queues(priv); i++) { - int ntfy_idx = gve_tx_idx_to_ntfy(priv, i); - + for (i = 0; i < priv->tx_cfg.num_queues; i++) u64_stats_init(&priv->tx[i].statss); - priv->tx[i].ntfy_id = ntfy_idx; - gve_add_napi(priv, ntfy_idx, napi_poll); - } - /* Add rx napi & init sync stats*/ - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - int ntfy_idx = gve_rx_idx_to_ntfy(priv, i); + /* Init stats for XDP TX queues */ + init_xdp_sync_stats(priv); + + for (i = 0; i < priv->rx_cfg.num_queues; i++) u64_stats_init(&priv->rx[i].statss); - priv->rx[i].ntfy_id = ntfy_idx; - gve_add_napi(priv, ntfy_idx, napi_poll); +} + +static void gve_tx_get_curr_alloc_cfg(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) +{ + cfg->qcfg = &priv->tx_cfg; + cfg->raw_addressing = !gve_is_qpl(priv); + cfg->qpls = priv->qpls; + cfg->qpl_cfg = &priv->qpl_cfg; + cfg->ring_size = priv->tx_desc_cnt; + cfg->start_idx = 0; + cfg->num_rings = gve_num_tx_queues(priv); + cfg->tx = priv->tx; +} + +static void gve_tx_stop_rings(struct gve_priv *priv, int start_id, int num_rings) +{ + int i; + + if (!priv->tx) + return; + + for (i = start_id; i < start_id + num_rings; i++) { + if (gve_is_gqi(priv)) + gve_tx_stop_ring_gqi(priv, i); + else + gve_tx_stop_ring_dqo(priv, i); } } -static void gve_tx_free_rings(struct gve_priv *priv, int start_id, int num_rings) +static void gve_tx_start_rings(struct gve_priv *priv, int start_id, + int num_rings) { - if (gve_is_gqi(priv)) { - gve_tx_free_rings_gqi(priv, start_id, num_rings); - } else { - gve_tx_free_rings_dqo(priv); + int i; + + for (i = start_id; i < start_id + num_rings; i++) { + if (gve_is_gqi(priv)) + gve_tx_start_ring_gqi(priv, i); + else + gve_tx_start_ring_dqo(priv, i); } } static int gve_alloc_xdp_rings(struct gve_priv *priv) { - int start_id; + struct gve_tx_alloc_rings_cfg cfg = {0}; int err = 0; if (!priv->num_xdp_queues) return 0; - start_id = gve_xdp_tx_start_queue_id(priv); - err = gve_tx_alloc_rings(priv, start_id, priv->num_xdp_queues); + gve_tx_get_curr_alloc_cfg(priv, &cfg); + cfg.start_idx = gve_xdp_tx_start_queue_id(priv); + cfg.num_rings = priv->num_xdp_queues; + + err = gve_tx_alloc_rings_gqi(priv, &cfg); if (err) return err; - add_napi_init_xdp_sync_stats(priv, gve_napi_poll); + + gve_tx_start_rings(priv, cfg.start_idx, cfg.num_rings); + init_xdp_sync_stats(priv); return 0; } -static int gve_alloc_rings(struct gve_priv *priv) +static int gve_alloc_rings(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) { int err; - /* Setup tx rings */ - priv->tx = kvcalloc(priv->tx_cfg.max_queues, sizeof(*priv->tx), - GFP_KERNEL); - if (!priv->tx) - return -ENOMEM; + if (gve_is_gqi(priv)) + err = gve_tx_alloc_rings_gqi(priv, tx_alloc_cfg); + else + err = gve_tx_alloc_rings_dqo(priv, tx_alloc_cfg); + if (err) + return err; if (gve_is_gqi(priv)) - err = gve_tx_alloc_rings(priv, 0, gve_num_tx_queues(priv)); + err = gve_rx_alloc_rings_gqi(priv, rx_alloc_cfg); else - err = gve_tx_alloc_rings_dqo(priv); + err = gve_rx_alloc_rings_dqo(priv, rx_alloc_cfg); if (err) goto free_tx; - /* Setup rx rings */ - priv->rx = kvcalloc(priv->rx_cfg.max_queues, sizeof(*priv->rx), - GFP_KERNEL); - if (!priv->rx) { - err = -ENOMEM; - goto free_tx_queue; - } - - if (gve_is_gqi(priv)) - err = gve_rx_alloc_rings(priv); - else - err = gve_rx_alloc_rings_dqo(priv); - if (err) - goto free_rx; - - if (gve_is_gqi(priv)) - add_napi_init_sync_stats(priv, gve_napi_poll); - else - add_napi_init_sync_stats(priv, gve_napi_poll_dqo); - return 0; -free_rx: - kvfree(priv->rx); - priv->rx = NULL; -free_tx_queue: - gve_tx_free_rings(priv, 0, gve_num_tx_queues(priv)); free_tx: - kvfree(priv->tx); - priv->tx = NULL; + if (gve_is_gqi(priv)) + gve_tx_free_rings_gqi(priv, tx_alloc_cfg); + else + gve_tx_free_rings_dqo(priv, tx_alloc_cfg); return err; } @@ -923,52 +960,30 @@ static int gve_destroy_rings(struct gve_priv *priv) return 0; } -static void gve_rx_free_rings(struct gve_priv *priv) -{ - if (gve_is_gqi(priv)) - gve_rx_free_rings_gqi(priv); - else - gve_rx_free_rings_dqo(priv); -} - static void gve_free_xdp_rings(struct gve_priv *priv) { - int ntfy_idx, start_id; - int i; + struct gve_tx_alloc_rings_cfg cfg = {0}; + + gve_tx_get_curr_alloc_cfg(priv, &cfg); + cfg.start_idx = gve_xdp_tx_start_queue_id(priv); + cfg.num_rings = priv->num_xdp_queues; - start_id = gve_xdp_tx_start_queue_id(priv); if (priv->tx) { - for (i = start_id; i < start_id + priv->num_xdp_queues; i++) { - ntfy_idx = gve_tx_idx_to_ntfy(priv, i); - gve_remove_napi(priv, ntfy_idx); - } - gve_tx_free_rings(priv, start_id, priv->num_xdp_queues); + gve_tx_stop_rings(priv, cfg.start_idx, cfg.num_rings); + gve_tx_free_rings_gqi(priv, &cfg); } } -static void gve_free_rings(struct gve_priv *priv) +static void gve_free_rings(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *tx_cfg, + struct gve_rx_alloc_rings_cfg *rx_cfg) { - int num_tx_queues = gve_num_tx_queues(priv); - int ntfy_idx; - int i; - - if (priv->tx) { - for (i = 0; i < num_tx_queues; i++) { - ntfy_idx = gve_tx_idx_to_ntfy(priv, i); - gve_remove_napi(priv, ntfy_idx); - } - gve_tx_free_rings(priv, 0, num_tx_queues); - kvfree(priv->tx); - priv->tx = NULL; - } - if (priv->rx) { - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - ntfy_idx = gve_rx_idx_to_ntfy(priv, i); - gve_remove_napi(priv, ntfy_idx); - } - gve_rx_free_rings(priv); - kvfree(priv->rx); - priv->rx = NULL; + if (gve_is_gqi(priv)) { + gve_tx_free_rings_gqi(priv, tx_cfg); + gve_rx_free_rings_gqi(priv, rx_cfg); + } else { + gve_tx_free_rings_dqo(priv, tx_cfg); + gve_rx_free_rings_dqo(priv, rx_cfg); } } @@ -990,21 +1005,13 @@ int gve_alloc_page(struct gve_priv *priv, struct device *dev, return 0; } -static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, - int pages) +static int gve_alloc_queue_page_list(struct gve_priv *priv, + struct gve_queue_page_list *qpl, + u32 id, int pages) { - struct gve_queue_page_list *qpl = &priv->qpls[id]; int err; int i; - if (pages + priv->num_registered_pages > priv->max_registered_pages) { - netif_err(priv, drv, priv->dev, - "Reached max number of registered pages %llu > %llu\n", - pages + priv->num_registered_pages, - priv->max_registered_pages); - return -EINVAL; - } - qpl->id = id; qpl->num_entries = 0; qpl->pages = kvcalloc(pages, sizeof(*qpl->pages), GFP_KERNEL); @@ -1025,7 +1032,6 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, return -ENOMEM; qpl->num_entries++; } - priv->num_registered_pages += pages; return 0; } @@ -1039,9 +1045,10 @@ void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma, put_page(page); } -static void gve_free_queue_page_list(struct gve_priv *priv, u32 id) +static void gve_free_queue_page_list(struct gve_priv *priv, + struct gve_queue_page_list *qpl, + int id) { - struct gve_queue_page_list *qpl = &priv->qpls[id]; int i; if (!qpl->pages) @@ -1058,19 +1065,30 @@ static void gve_free_queue_page_list(struct gve_priv *priv, u32 id) free_pages: kvfree(qpl->pages); qpl->pages = NULL; - priv->num_registered_pages -= qpl->num_entries; } -static int gve_alloc_xdp_qpls(struct gve_priv *priv) +static void gve_free_n_qpls(struct gve_priv *priv, + struct gve_queue_page_list *qpls, + int start_id, + int num_qpls) { - int start_id; - int i, j; - int err; + int i; - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); - for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) { - err = gve_alloc_queue_page_list(priv, i, - priv->tx_pages_per_qpl); + for (i = start_id; i < start_id + num_qpls; i++) + gve_free_queue_page_list(priv, &qpls[i], i); +} + +static int gve_alloc_n_qpls(struct gve_priv *priv, + struct gve_queue_page_list *qpls, + int page_count, + int start_id, + int num_qpls) +{ + int err; + int i; + + for (i = start_id; i < start_id + num_qpls; i++) { + err = gve_alloc_queue_page_list(priv, &qpls[i], i, page_count); if (err) goto free_qpls; } @@ -1078,95 +1096,89 @@ static int gve_alloc_xdp_qpls(struct gve_priv *priv) return 0; free_qpls: - for (j = start_id; j <= i; j++) - gve_free_queue_page_list(priv, j); + /* Must include the failing QPL too for gve_alloc_queue_page_list fails + * without cleaning up. + */ + gve_free_n_qpls(priv, qpls, start_id, i - start_id + 1); return err; } -static int gve_alloc_qpls(struct gve_priv *priv) +static int gve_alloc_qpls(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *cfg) { - int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues; + int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues; + int rx_start_id, tx_num_qpls, rx_num_qpls; + struct gve_queue_page_list *qpls; int page_count; - int start_id; - int i, j; int err; - if (!gve_is_qpl(priv)) + if (cfg->raw_addressing) return 0; - priv->qpls = kvcalloc(max_queues, sizeof(*priv->qpls), GFP_KERNEL); - if (!priv->qpls) + qpls = kvcalloc(max_queues, sizeof(*qpls), GFP_KERNEL); + if (!qpls) return -ENOMEM; - start_id = gve_tx_start_qpl_id(priv); - page_count = priv->tx_pages_per_qpl; - for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) { - err = gve_alloc_queue_page_list(priv, i, - page_count); - if (err) - goto free_qpls; + cfg->qpl_cfg->qpl_map_size = BITS_TO_LONGS(max_queues) * + sizeof(unsigned long) * BITS_PER_BYTE; + cfg->qpl_cfg->qpl_id_map = kvcalloc(BITS_TO_LONGS(max_queues), + sizeof(unsigned long), GFP_KERNEL); + if (!cfg->qpl_cfg->qpl_id_map) { + err = -ENOMEM; + goto free_qpl_array; } - start_id = gve_rx_start_qpl_id(priv); + /* Allocate TX QPLs */ + page_count = priv->tx_pages_per_qpl; + tx_num_qpls = gve_num_tx_qpls(cfg->tx_cfg, cfg->num_xdp_queues, + gve_is_qpl(priv)); + err = gve_alloc_n_qpls(priv, qpls, page_count, 0, tx_num_qpls); + if (err) + goto free_qpl_map; + /* Allocate RX QPLs */ + rx_start_id = gve_rx_start_qpl_id(cfg->tx_cfg); /* For GQI_QPL number of pages allocated have 1:1 relationship with * number of descriptors. For DQO, number of pages required are * more than descriptors (because of out of order completions). */ - page_count = priv->queue_format == GVE_GQI_QPL_FORMAT ? - priv->rx_data_slot_cnt : priv->rx_pages_per_qpl; - for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) { - err = gve_alloc_queue_page_list(priv, i, - page_count); - if (err) - goto free_qpls; - } - - priv->qpl_cfg.qpl_map_size = BITS_TO_LONGS(max_queues) * - sizeof(unsigned long) * BITS_PER_BYTE; - priv->qpl_cfg.qpl_id_map = kvcalloc(BITS_TO_LONGS(max_queues), - sizeof(unsigned long), GFP_KERNEL); - if (!priv->qpl_cfg.qpl_id_map) { - err = -ENOMEM; - goto free_qpls; - } + page_count = cfg->is_gqi ? priv->rx_data_slot_cnt : priv->rx_pages_per_qpl; + rx_num_qpls = gve_num_rx_qpls(cfg->rx_cfg, gve_is_qpl(priv)); + err = gve_alloc_n_qpls(priv, qpls, page_count, rx_start_id, rx_num_qpls); + if (err) + goto free_tx_qpls; + cfg->qpls = qpls; return 0; -free_qpls: - for (j = 0; j <= i; j++) - gve_free_queue_page_list(priv, j); - kvfree(priv->qpls); - priv->qpls = NULL; +free_tx_qpls: + gve_free_n_qpls(priv, qpls, 0, tx_num_qpls); +free_qpl_map: + kvfree(cfg->qpl_cfg->qpl_id_map); + cfg->qpl_cfg->qpl_id_map = NULL; +free_qpl_array: + kvfree(qpls); return err; } -static void gve_free_xdp_qpls(struct gve_priv *priv) +static void gve_free_qpls(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *cfg) { - int start_id; + int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues; + struct gve_queue_page_list *qpls = cfg->qpls; int i; - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); - for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) - gve_free_queue_page_list(priv, i); -} - -static void gve_free_qpls(struct gve_priv *priv) -{ - int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues; - int i; - - if (!priv->qpls) + if (!qpls) return; - kvfree(priv->qpl_cfg.qpl_id_map); - priv->qpl_cfg.qpl_id_map = NULL; + kvfree(cfg->qpl_cfg->qpl_id_map); + cfg->qpl_cfg->qpl_id_map = NULL; for (i = 0; i < max_queues; i++) - gve_free_queue_page_list(priv, i); + gve_free_queue_page_list(priv, &qpls[i], i); - kvfree(priv->qpls); - priv->qpls = NULL; + kvfree(qpls); + cfg->qpls = NULL; } /* Use this to schedule a reset when the device is capable of continuing @@ -1277,8 +1289,72 @@ static void gve_drain_page_cache(struct gve_priv *priv) } } +static void gve_qpls_get_curr_alloc_cfg(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *cfg) +{ + cfg->raw_addressing = !gve_is_qpl(priv); + cfg->is_gqi = gve_is_gqi(priv); + cfg->num_xdp_queues = priv->num_xdp_queues; + cfg->qpl_cfg = &priv->qpl_cfg; + cfg->tx_cfg = &priv->tx_cfg; + cfg->rx_cfg = &priv->rx_cfg; + cfg->qpls = priv->qpls; +} + +static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) +{ + cfg->qcfg = &priv->rx_cfg; + cfg->qcfg_tx = &priv->tx_cfg; + cfg->raw_addressing = !gve_is_qpl(priv); + cfg->qpls = priv->qpls; + cfg->qpl_cfg = &priv->qpl_cfg; + cfg->ring_size = priv->rx_desc_cnt; + cfg->rx = priv->rx; +} + +static void gve_get_curr_alloc_cfgs(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + gve_qpls_get_curr_alloc_cfg(priv, qpls_alloc_cfg); + gve_tx_get_curr_alloc_cfg(priv, tx_alloc_cfg); + gve_rx_get_curr_alloc_cfg(priv, rx_alloc_cfg); +} + +static void gve_rx_start_rings(struct gve_priv *priv, int num_rings) +{ + int i; + + for (i = 0; i < num_rings; i++) { + if (gve_is_gqi(priv)) + gve_rx_start_ring_gqi(priv, i); + else + gve_rx_start_ring_dqo(priv, i); + } +} + +static void gve_rx_stop_rings(struct gve_priv *priv, int num_rings) +{ + int i; + + if (!priv->rx) + return; + + for (i = 0; i < num_rings; i++) { + if (gve_is_gqi(priv)) + gve_rx_stop_ring_gqi(priv, i); + else + gve_rx_stop_ring_dqo(priv, i); + } +} + static int gve_open(struct net_device *dev) { + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; struct gve_priv *priv = netdev_priv(dev); int err; @@ -1287,14 +1363,22 @@ static int gve_open(struct net_device *dev) else priv->num_xdp_queues = 0; - err = gve_alloc_qpls(priv); + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + err = gve_alloc_qpls(priv, &qpls_alloc_cfg); if (err) return err; - - err = gve_alloc_rings(priv); + priv->qpls = qpls_alloc_cfg.qpls; + tx_alloc_cfg.qpls = priv->qpls; + rx_alloc_cfg.qpls = priv->qpls; + err = gve_alloc_rings(priv, &tx_alloc_cfg, &rx_alloc_cfg); if (err) goto free_qpls; + gve_tx_start_rings(priv, 0, tx_alloc_cfg.num_rings); + gve_rx_start_rings(priv, rx_alloc_cfg.qcfg->num_queues); + gve_init_sync_stats(priv); + err = netif_set_real_num_tx_queues(dev, priv->tx_cfg.num_queues); if (err) goto free_rings; @@ -1333,9 +1417,11 @@ static int gve_open(struct net_device *dev) return 0; free_rings: - gve_free_rings(priv); + gve_tx_stop_rings(priv, 0, tx_alloc_cfg.num_rings); + gve_rx_stop_rings(priv, rx_alloc_cfg.qcfg->num_queues); + gve_free_rings(priv, &tx_alloc_cfg, &rx_alloc_cfg); free_qpls: - gve_free_qpls(priv); + gve_free_qpls(priv, &qpls_alloc_cfg); return err; reset: @@ -1354,6 +1440,9 @@ reset: static int gve_close(struct net_device *dev) { + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; struct gve_priv *priv = netdev_priv(dev); int err; @@ -1372,8 +1461,14 @@ static int gve_close(struct net_device *dev) del_timer_sync(&priv->stats_report_timer); gve_unreg_xdp_info(priv); - gve_free_rings(priv); - gve_free_qpls(priv); + + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + gve_tx_stop_rings(priv, 0, tx_alloc_cfg.num_rings); + gve_rx_stop_rings(priv, rx_alloc_cfg.qcfg->num_queues); + gve_free_rings(priv, &tx_alloc_cfg, &rx_alloc_cfg); + gve_free_qpls(priv, &qpls_alloc_cfg); + priv->interface_down_cnt++; return 0; @@ -1390,8 +1485,11 @@ err: static int gve_remove_xdp_queues(struct gve_priv *priv) { + int qpl_start_id; int err; + qpl_start_id = gve_xdp_tx_start_queue_id(priv); + err = gve_destroy_xdp_rings(priv); if (err) return err; @@ -1402,18 +1500,22 @@ static int gve_remove_xdp_queues(struct gve_priv *priv) gve_unreg_xdp_info(priv); gve_free_xdp_rings(priv); - gve_free_xdp_qpls(priv); + + gve_free_n_qpls(priv, priv->qpls, qpl_start_id, gve_num_xdp_qpls(priv)); priv->num_xdp_queues = 0; return 0; } static int gve_add_xdp_queues(struct gve_priv *priv) { + int start_id; int err; - priv->num_xdp_queues = priv->tx_cfg.num_queues; + priv->num_xdp_queues = priv->rx_cfg.num_queues; - err = gve_alloc_xdp_qpls(priv); + start_id = gve_xdp_tx_start_queue_id(priv); + err = gve_alloc_n_qpls(priv, priv->qpls, priv->tx_pages_per_qpl, + start_id, gve_num_xdp_qpls(priv)); if (err) goto err; @@ -1438,7 +1540,7 @@ static int gve_add_xdp_queues(struct gve_priv *priv) free_xdp_rings: gve_free_xdp_rings(priv); free_xdp_qpls: - gve_free_xdp_qpls(priv); + gve_free_n_qpls(priv, priv->qpls, start_id, gve_num_xdp_qpls(priv)); err: priv->num_xdp_queues = 0; return err; @@ -2037,6 +2139,8 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device) goto err; } + priv->num_registered_pages = 0; + if (skip_describe_device) goto setup_device; @@ -2066,7 +2170,6 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device) if (!gve_is_gqi(priv)) netif_set_tso_max_size(priv->dev, GVE_DQO_TX_MAX); - priv->num_registered_pages = 0; priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK; /* gvnic has one Notification Block per MSI-x vector, except for the * management vector diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c index 7a8dc5386fff..c294a1595b6a 100644 --- a/drivers/net/ethernet/google/gve/gve_rx.c +++ b/drivers/net/ethernet/google/gve/gve_rx.c @@ -23,7 +23,9 @@ static void gve_rx_free_buffer(struct device *dev, gve_free_page(dev, page_info->page, dma, DMA_FROM_DEVICE); } -static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx) +static void gve_rx_unfill_pages(struct gve_priv *priv, + struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { u32 slots = rx->mask + 1; int i; @@ -36,7 +38,7 @@ static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx) for (i = 0; i < slots; i++) page_ref_sub(rx->data.page_info[i].page, rx->data.page_info[i].pagecnt_bias - 1); - gve_unassign_qpl(priv, rx->data.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, rx->data.qpl->id); rx->data.qpl = NULL; for (i = 0; i < rx->qpl_copy_pool_mask + 1; i++) { @@ -49,16 +51,26 @@ static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx) rx->data.page_info = NULL; } -static void gve_rx_free_ring(struct gve_priv *priv, int idx) +void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + if (!gve_rx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_rx_remove_from_block(priv, idx); +} + +static void gve_rx_free_ring_gqi(struct gve_priv *priv, struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *dev = &priv->pdev->dev; u32 slots = rx->mask + 1; + int idx = rx->q_num; size_t bytes; - gve_rx_remove_from_block(priv, idx); - - bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt; + bytes = sizeof(struct gve_rx_desc) * cfg->ring_size; dma_free_coherent(dev, bytes, rx->desc.desc_ring, rx->desc.bus); rx->desc.desc_ring = NULL; @@ -66,7 +78,7 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx) rx->q_resources, rx->q_resources_bus); rx->q_resources = NULL; - gve_rx_unfill_pages(priv, rx); + gve_rx_unfill_pages(priv, rx, cfg); bytes = sizeof(*rx->data.data_ring) * slots; dma_free_coherent(dev, bytes, rx->data.data_ring, @@ -108,7 +120,8 @@ static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev, return 0; } -static int gve_prefill_rx_pages(struct gve_rx_ring *rx) +static int gve_rx_prefill_pages(struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { struct gve_priv *priv = rx->gve; u32 slots; @@ -127,7 +140,7 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx) return -ENOMEM; if (!rx->data.raw_addressing) { - rx->data.qpl = gve_assign_rx_qpl(priv, rx->q_num); + rx->data.qpl = gve_assign_rx_qpl(cfg, rx->q_num); if (!rx->data.qpl) { kvfree(rx->data.page_info); rx->data.page_info = NULL; @@ -185,7 +198,7 @@ alloc_err_qpl: page_ref_sub(rx->data.page_info[i].page, rx->data.page_info[i].pagecnt_bias - 1); - gve_unassign_qpl(priv, rx->data.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, rx->data.qpl->id); rx->data.qpl = NULL; return err; @@ -207,13 +220,23 @@ static void gve_rx_ctx_clear(struct gve_rx_ctx *ctx) ctx->drop_pkt = false; } -static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) +void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + gve_rx_add_to_block(priv, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll); +} + +static int gve_rx_alloc_ring_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg, + struct gve_rx_ring *rx, + int idx) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *hdev = &priv->pdev->dev; + u32 slots = priv->rx_data_slot_cnt; int filled_pages; size_t bytes; - u32 slots; int err; netif_dbg(priv, drv, priv->dev, "allocating rx ring\n"); @@ -223,9 +246,8 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) rx->gve = priv; rx->q_num = idx; - slots = priv->rx_data_slot_cnt; rx->mask = slots - 1; - rx->data.raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT; + rx->data.raw_addressing = cfg->raw_addressing; /* alloc rx data ring */ bytes = sizeof(*rx->data.data_ring) * slots; @@ -246,7 +268,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) goto abort_with_slots; } - filled_pages = gve_prefill_rx_pages(rx); + filled_pages = gve_rx_prefill_pages(rx, cfg); if (filled_pages < 0) { err = -ENOMEM; goto abort_with_copy_pool; @@ -269,7 +291,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) (unsigned long)rx->data.data_bus); /* alloc rx desc ring */ - bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt; + bytes = sizeof(struct gve_rx_desc) * cfg->ring_size; rx->desc.desc_ring = dma_alloc_coherent(hdev, bytes, &rx->desc.bus, GFP_KERNEL); if (!rx->desc.desc_ring) { @@ -277,15 +299,11 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) goto abort_with_q_resources; } rx->cnt = 0; - rx->db_threshold = priv->rx_desc_cnt / 2; + rx->db_threshold = slots / 2; rx->desc.seqno = 1; - /* Allocating half-page buffers allows page-flipping which is faster - * than copying or allocating new pages. - */ rx->packet_buffer_size = GVE_DEFAULT_RX_BUFFER_SIZE; gve_rx_ctx_clear(&rx->ctx); - gve_rx_add_to_block(priv, idx); return 0; @@ -294,7 +312,7 @@ abort_with_q_resources: rx->q_resources, rx->q_resources_bus); rx->q_resources = NULL; abort_filled: - gve_rx_unfill_pages(priv, rx); + gve_rx_unfill_pages(priv, rx, cfg); abort_with_copy_pool: kvfree(rx->qpl_copy_pool); rx->qpl_copy_pool = NULL; @@ -306,36 +324,58 @@ abort_with_slots: return err; } -int gve_rx_alloc_rings(struct gve_priv *priv) +int gve_rx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { + struct gve_rx_ring *rx; int err = 0; - int i; + int i, j; - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - err = gve_rx_alloc_ring(priv, i); + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } + + rx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_rx_ring), + GFP_KERNEL); + if (!rx) + return -ENOMEM; + + for (i = 0; i < cfg->qcfg->num_queues; i++) { + err = gve_rx_alloc_ring_gqi(priv, cfg, &rx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc rx ring=%d: err=%d\n", i, err); - break; + goto cleanup; } } - /* Unallocate if there was an error */ - if (err) { - int j; - for (j = 0; j < i; j++) - gve_rx_free_ring(priv, j); - } + cfg->rx = rx; + return 0; + +cleanup: + for (j = 0; j < i; j++) + gve_rx_free_ring_gqi(priv, &rx[j], cfg); + kvfree(rx); return err; } -void gve_rx_free_rings_gqi(struct gve_priv *priv) +void gve_rx_free_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { + struct gve_rx_ring *rx = cfg->rx; int i; - for (i = 0; i < priv->rx_cfg.num_queues; i++) - gve_rx_free_ring(priv, i); + if (!rx) + return; + + for (i = 0; i < cfg->qcfg->num_queues; i++) + gve_rx_free_ring_gqi(priv, &rx[i], cfg); + + kvfree(rx); + cfg->rx = NULL; } void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx) diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index f281e42a7ef9..8e6aeb5b3ed4 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -199,20 +199,30 @@ static int gve_alloc_page_dqo(struct gve_rx_ring *rx, return 0; } -static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx) +void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + if (!gve_rx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_rx_remove_from_block(priv, idx); +} + +static void gve_rx_free_ring_dqo(struct gve_priv *priv, struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *hdev = &priv->pdev->dev; size_t completion_queue_slots; size_t buffer_queue_slots; + int idx = rx->q_num; size_t size; int i; completion_queue_slots = rx->dqo.complq.mask + 1; buffer_queue_slots = rx->dqo.bufq.mask + 1; - gve_rx_remove_from_block(priv, idx); - if (rx->q_resources) { dma_free_coherent(hdev, sizeof(*rx->q_resources), rx->q_resources, rx->q_resources_bus); @@ -226,7 +236,7 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx) gve_free_page_dqo(priv, bs, !rx->dqo.qpl); } if (rx->dqo.qpl) { - gve_unassign_qpl(priv, rx->dqo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, rx->dqo.qpl->id); rx->dqo.qpl = NULL; } @@ -251,17 +261,26 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx) netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx); } -static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) +void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + gve_rx_add_to_block(priv, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo); +} + +static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg, + struct gve_rx_ring *rx, + int idx) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *hdev = &priv->pdev->dev; size_t size; int i; - const u32 buffer_queue_slots = - priv->queue_format == GVE_DQO_RDA_FORMAT ? - priv->options_dqo_rda.rx_buff_ring_entries : priv->rx_desc_cnt; - const u32 completion_queue_slots = priv->rx_desc_cnt; + const u32 buffer_queue_slots = cfg->raw_addressing ? + priv->options_dqo_rda.rx_buff_ring_entries : cfg->ring_size; + const u32 completion_queue_slots = cfg->ring_size; netif_dbg(priv, drv, priv->dev, "allocating rx ring DQO\n"); @@ -274,7 +293,7 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) rx->ctx.skb_head = NULL; rx->ctx.skb_tail = NULL; - rx->dqo.num_buf_states = priv->queue_format == GVE_DQO_RDA_FORMAT ? + rx->dqo.num_buf_states = cfg->raw_addressing ? min_t(s16, S16_MAX, buffer_queue_slots * 4) : priv->rx_pages_per_qpl; rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states, @@ -308,8 +327,8 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) if (!rx->dqo.bufq.desc_ring) goto err; - if (priv->queue_format != GVE_DQO_RDA_FORMAT) { - rx->dqo.qpl = gve_assign_rx_qpl(priv, rx->q_num); + if (!cfg->raw_addressing) { + rx->dqo.qpl = gve_assign_rx_qpl(cfg, rx->q_num); if (!rx->dqo.qpl) goto err; rx->dqo.next_qpl_page_idx = 0; @@ -320,12 +339,10 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) if (!rx->q_resources) goto err; - gve_rx_add_to_block(priv, idx); - return 0; err: - gve_rx_free_ring_dqo(priv, idx); + gve_rx_free_ring_dqo(priv, rx, cfg); return -ENOMEM; } @@ -337,13 +354,26 @@ void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx) iowrite32(rx->dqo.bufq.tail, &priv->db_bar2[index]); } -int gve_rx_alloc_rings_dqo(struct gve_priv *priv) +int gve_rx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { - int err = 0; + struct gve_rx_ring *rx; + int err; int i; - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - err = gve_rx_alloc_ring_dqo(priv, i); + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } + + rx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_rx_ring), + GFP_KERNEL); + if (!rx) + return -ENOMEM; + + for (i = 0; i < cfg->qcfg->num_queues; i++) { + err = gve_rx_alloc_ring_dqo(priv, cfg, &rx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc rx ring=%d: err=%d\n", @@ -352,21 +382,30 @@ int gve_rx_alloc_rings_dqo(struct gve_priv *priv) } } + cfg->rx = rx; return 0; err: for (i--; i >= 0; i--) - gve_rx_free_ring_dqo(priv, i); - + gve_rx_free_ring_dqo(priv, &rx[i], cfg); + kvfree(rx); return err; } -void gve_rx_free_rings_dqo(struct gve_priv *priv) +void gve_rx_free_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { + struct gve_rx_ring *rx = cfg->rx; int i; - for (i = 0; i < priv->rx_cfg.num_queues; i++) - gve_rx_free_ring_dqo(priv, i); + if (!rx) + return; + + for (i = 0; i < cfg->qcfg->num_queues; i++) + gve_rx_free_ring_dqo(priv, &rx[i], cfg); + + kvfree(rx); + cfg->rx = NULL; } void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c index 07ba124780df..4b9853adc113 100644 --- a/drivers/net/ethernet/google/gve/gve_tx.c +++ b/drivers/net/ethernet/google/gve/gve_tx.c @@ -196,29 +196,36 @@ static int gve_clean_xdp_done(struct gve_priv *priv, struct gve_tx_ring *tx, static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx, u32 to_do, bool try_to_wake); -static void gve_tx_free_ring(struct gve_priv *priv, int idx) +void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; + + if (!gve_tx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_clean_tx_done(priv, tx, priv->tx_desc_cnt, false); + netdev_tx_reset_queue(tx->netdev_txq); + gve_tx_remove_from_block(priv, idx); +} + +static void gve_tx_free_ring_gqi(struct gve_priv *priv, struct gve_tx_ring *tx, + struct gve_tx_alloc_rings_cfg *cfg) +{ struct device *hdev = &priv->pdev->dev; + int idx = tx->q_num; size_t bytes; u32 slots; - gve_tx_remove_from_block(priv, idx); slots = tx->mask + 1; - if (tx->q_num < priv->tx_cfg.num_queues) { - gve_clean_tx_done(priv, tx, priv->tx_desc_cnt, false); - netdev_tx_reset_queue(tx->netdev_txq); - } else { - gve_clean_xdp_done(priv, tx, priv->tx_desc_cnt); - } - dma_free_coherent(hdev, sizeof(*tx->q_resources), tx->q_resources, tx->q_resources_bus); tx->q_resources = NULL; if (!tx->raw_addressing) { gve_tx_fifo_release(priv, &tx->tx_fifo); - gve_unassign_qpl(priv, tx->tx_fifo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, tx->tx_fifo.qpl->id); tx->tx_fifo.qpl = NULL; } @@ -232,11 +239,23 @@ static void gve_tx_free_ring(struct gve_priv *priv, int idx) netif_dbg(priv, drv, priv->dev, "freed tx queue %d\n", idx); } -static int gve_tx_alloc_ring(struct gve_priv *priv, int idx) +void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; + + gve_tx_add_to_block(priv, idx); + + tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll); +} + +static int gve_tx_alloc_ring_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg, + struct gve_tx_ring *tx, + int idx) +{ struct device *hdev = &priv->pdev->dev; - u32 slots = priv->tx_desc_cnt; size_t bytes; /* Make sure everything is zeroed to start */ @@ -245,23 +264,23 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx) spin_lock_init(&tx->xdp_lock); tx->q_num = idx; - tx->mask = slots - 1; + tx->mask = cfg->ring_size - 1; /* alloc metadata */ - tx->info = vcalloc(slots, sizeof(*tx->info)); + tx->info = vcalloc(cfg->ring_size, sizeof(*tx->info)); if (!tx->info) return -ENOMEM; /* alloc tx queue */ - bytes = sizeof(*tx->desc) * slots; + bytes = sizeof(*tx->desc) * cfg->ring_size; tx->desc = dma_alloc_coherent(hdev, bytes, &tx->bus, GFP_KERNEL); if (!tx->desc) goto abort_with_info; - tx->raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT; - tx->dev = &priv->pdev->dev; + tx->raw_addressing = cfg->raw_addressing; + tx->dev = hdev; if (!tx->raw_addressing) { - tx->tx_fifo.qpl = gve_assign_tx_qpl(priv, idx); + tx->tx_fifo.qpl = gve_assign_tx_qpl(cfg, idx); if (!tx->tx_fifo.qpl) goto abort_with_desc; /* map Tx FIFO */ @@ -277,12 +296,6 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx) if (!tx->q_resources) goto abort_with_fifo; - netif_dbg(priv, drv, priv->dev, "tx[%d]->bus=%lx\n", idx, - (unsigned long)tx->bus); - if (idx < priv->tx_cfg.num_queues) - tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); - gve_tx_add_to_block(priv, idx); - return 0; abort_with_fifo: @@ -290,7 +303,7 @@ abort_with_fifo: gve_tx_fifo_release(priv, &tx->tx_fifo); abort_with_qpl: if (!tx->raw_addressing) - gve_unassign_qpl(priv, tx->tx_fifo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, tx->tx_fifo.qpl->id); abort_with_desc: dma_free_coherent(hdev, bytes, tx->desc, tx->bus); tx->desc = NULL; @@ -300,36 +313,73 @@ abort_with_info: return -ENOMEM; } -int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings) +int gve_tx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int err = 0; - int i; + int i, j; - for (i = start_id; i < start_id + num_rings; i++) { - err = gve_tx_alloc_ring(priv, i); + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } + + if (cfg->start_idx + cfg->num_rings > cfg->qcfg->max_queues) { + netif_err(priv, drv, priv->dev, + "Cannot alloc more than the max num of Tx rings\n"); + return -EINVAL; + } + + if (cfg->start_idx == 0) { + tx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_tx_ring), + GFP_KERNEL); + if (!tx) + return -ENOMEM; + } else if (!tx) { + netif_err(priv, drv, priv->dev, + "Cannot alloc tx rings from a nonzero start idx without tx array\n"); + return -EINVAL; + } + + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) { + err = gve_tx_alloc_ring_gqi(priv, cfg, &tx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc tx ring=%d: err=%d\n", i, err); - break; + goto cleanup; } } - /* Unallocate if there was an error */ - if (err) { - int j; - for (j = start_id; j < i; j++) - gve_tx_free_ring(priv, j); - } + cfg->tx = tx; + return 0; + +cleanup: + for (j = 0; j < i; j++) + gve_tx_free_ring_gqi(priv, &tx[j], cfg); + if (cfg->start_idx == 0) + kvfree(tx); return err; } -void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings) +void gve_tx_free_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int i; - for (i = start_id; i < start_id + num_rings; i++) - gve_tx_free_ring(priv, i); + if (!tx) + return; + + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) + gve_tx_free_ring_gqi(priv, &tx[i], cfg); + + if (cfg->start_idx == 0) { + kvfree(tx); + cfg->tx = NULL; + } } /* gve_tx_avail - Calculates the number of slots available in the ring diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c index f59c4710f118..bc34b6cd3a3e 100644 --- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c @@ -188,13 +188,27 @@ static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx) } } -static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx) +void gve_tx_stop_ring_dqo(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; - struct device *hdev = &priv->pdev->dev; - size_t bytes; + if (!gve_tx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_clean_tx_done_dqo(priv, tx, /*napi=*/NULL); + netdev_tx_reset_queue(tx->netdev_txq); + gve_tx_clean_pending_packets(tx); gve_tx_remove_from_block(priv, idx); +} + +static void gve_tx_free_ring_dqo(struct gve_priv *priv, struct gve_tx_ring *tx, + struct gve_tx_alloc_rings_cfg *cfg) +{ + struct device *hdev = &priv->pdev->dev; + int idx = tx->q_num; + size_t bytes; if (tx->q_resources) { dma_free_coherent(hdev, sizeof(*tx->q_resources), @@ -223,7 +237,7 @@ static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx) tx->dqo.tx_qpl_buf_next = NULL; if (tx->dqo.qpl) { - gve_unassign_qpl(priv, tx->dqo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, tx->dqo.qpl->id); tx->dqo.qpl = NULL; } @@ -253,9 +267,22 @@ static int gve_tx_qpl_buf_init(struct gve_tx_ring *tx) return 0; } -static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) +void gve_tx_start_ring_dqo(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; + + gve_tx_add_to_block(priv, idx); + + tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo); +} + +static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg, + struct gve_tx_ring *tx, + int idx) +{ struct device *hdev = &priv->pdev->dev; int num_pending_packets; size_t bytes; @@ -263,12 +290,11 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) memset(tx, 0, sizeof(*tx)); tx->q_num = idx; - tx->dev = &priv->pdev->dev; - tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); + tx->dev = hdev; atomic_set_release(&tx->dqo_compl.hw_tx_head, 0); /* Queue sizes must be a power of 2 */ - tx->mask = priv->tx_desc_cnt - 1; + tx->mask = cfg->ring_size - 1; tx->dqo.complq_mask = priv->queue_format == GVE_DQO_RDA_FORMAT ? priv->options_dqo_rda.tx_comp_ring_entries - 1 : tx->mask; @@ -327,8 +353,8 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) if (!tx->q_resources) goto err; - if (gve_is_qpl(priv)) { - tx->dqo.qpl = gve_assign_tx_qpl(priv, idx); + if (!cfg->raw_addressing) { + tx->dqo.qpl = gve_assign_tx_qpl(cfg, idx); if (!tx->dqo.qpl) goto err; @@ -336,22 +362,45 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) goto err; } - gve_tx_add_to_block(priv, idx); - return 0; err: - gve_tx_free_ring_dqo(priv, idx); + gve_tx_free_ring_dqo(priv, tx, cfg); return -ENOMEM; } -int gve_tx_alloc_rings_dqo(struct gve_priv *priv) +int gve_tx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int err = 0; - int i; + int i, j; - for (i = 0; i < priv->tx_cfg.num_queues; i++) { - err = gve_tx_alloc_ring_dqo(priv, i); + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } + + if (cfg->start_idx + cfg->num_rings > cfg->qcfg->max_queues) { + netif_err(priv, drv, priv->dev, + "Cannot alloc more than the max num of Tx rings\n"); + return -EINVAL; + } + + if (cfg->start_idx == 0) { + tx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_tx_ring), + GFP_KERNEL); + if (!tx) + return -ENOMEM; + } else if (!tx) { + netif_err(priv, drv, priv->dev, + "Cannot alloc tx rings from a nonzero start idx without tx array\n"); + return -EINVAL; + } + + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) { + err = gve_tx_alloc_ring_dqo(priv, cfg, &tx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc tx ring=%d: err=%d\n", @@ -360,27 +409,32 @@ int gve_tx_alloc_rings_dqo(struct gve_priv *priv) } } + cfg->tx = tx; return 0; err: - for (i--; i >= 0; i--) - gve_tx_free_ring_dqo(priv, i); - + for (j = 0; j < i; j++) + gve_tx_free_ring_dqo(priv, &tx[j], cfg); + if (cfg->start_idx == 0) + kvfree(tx); return err; } -void gve_tx_free_rings_dqo(struct gve_priv *priv) +void gve_tx_free_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int i; - for (i = 0; i < priv->tx_cfg.num_queues; i++) { - struct gve_tx_ring *tx = &priv->tx[i]; + if (!tx) + return; - gve_clean_tx_done_dqo(priv, tx, /*napi=*/NULL); - netdev_tx_reset_queue(tx->netdev_txq); - gve_tx_clean_pending_packets(tx); + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) + gve_tx_free_ring_dqo(priv, &tx[i], cfg); - gve_tx_free_ring_dqo(priv, i); + if (cfg->start_idx == 0) { + kvfree(tx); + cfg->tx = NULL; } } diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index 974a75623789..535b1796b91d 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -8,6 +8,14 @@ #include "gve_adminq.h" #include "gve_utils.h" +bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx) +{ + struct gve_notify_block *block = + &priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)]; + + return block->tx != NULL; +} + void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx) { struct gve_notify_block *block = @@ -30,6 +38,14 @@ void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx) queue_idx); } +bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx) +{ + struct gve_notify_block *block = + &priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)]; + + return block->rx != NULL; +} + void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx) { struct gve_notify_block *block = diff --git a/drivers/net/ethernet/google/gve/gve_utils.h b/drivers/net/ethernet/google/gve/gve_utils.h index 924516e9eaae..277921a629f7 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.h +++ b/drivers/net/ethernet/google/gve/gve_utils.h @@ -11,9 +11,11 @@ #include "gve.h" +bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx); void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx); void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx); +bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx); void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx); void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx); From 92a6d7a4010c3e84894f4fb7f481e648f0b12e53 Mon Sep 17 00:00:00 2001 From: Shailend Chand Date: Mon, 22 Jan 2024 18:26:30 +0000 Subject: [PATCH 0253/2255] gve: Refactor gve_open and gve_close gve_open is rewritten to be composed of two funcs: gve_queues_mem_alloc and gve_queues_start. The former only allocates queue resources without doing anything to install the queues, which is taken up by the latter. Similarly gve_close is split into gve_queues_stop and gve_queues_mem_free. Separating the acts of queue resource allocation and making the queue become live help with subsequent changes that aim to not take down the datapath when applying new configurations. Signed-off-by: Shailend Chand Reviewed-by: Willem de Bruijn Reviewed-by: Jeroen de Borst Link: https://lore.kernel.org/r/20240122182632.1102721-5-shailend@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_main.c | 159 +++++++++++++++------ 1 file changed, 119 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 8049a47c38fc..3515484e4cea 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -1350,45 +1350,99 @@ static void gve_rx_stop_rings(struct gve_priv *priv, int num_rings) } } -static int gve_open(struct net_device *dev) +static void gve_queues_mem_free(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + gve_free_rings(priv, tx_alloc_cfg, rx_alloc_cfg); + gve_free_qpls(priv, qpls_alloc_cfg); +} + +static int gve_queues_mem_alloc(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + int err; + + err = gve_alloc_qpls(priv, qpls_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, "Failed to alloc QPLs\n"); + return err; + } + tx_alloc_cfg->qpls = qpls_alloc_cfg->qpls; + rx_alloc_cfg->qpls = qpls_alloc_cfg->qpls; + err = gve_alloc_rings(priv, tx_alloc_cfg, rx_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, "Failed to alloc rings\n"); + goto free_qpls; + } + + return 0; + +free_qpls: + gve_free_qpls(priv, qpls_alloc_cfg); + return err; +} + +static void gve_queues_mem_remove(struct gve_priv *priv) { struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; - struct gve_priv *priv = netdev_priv(dev); + + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + gve_queues_mem_free(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + priv->qpls = NULL; + priv->tx = NULL; + priv->rx = NULL; +} + +/* The passed-in queue memory is stored into priv and the queues are made live. + * No memory is allocated. Passed-in memory is freed on errors. + */ +static int gve_queues_start(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + struct net_device *dev = priv->dev; int err; + /* Record new resources into priv */ + priv->qpls = qpls_alloc_cfg->qpls; + priv->tx = tx_alloc_cfg->tx; + priv->rx = rx_alloc_cfg->rx; + + /* Record new configs into priv */ + priv->qpl_cfg = *qpls_alloc_cfg->qpl_cfg; + priv->tx_cfg = *tx_alloc_cfg->qcfg; + priv->rx_cfg = *rx_alloc_cfg->qcfg; + priv->tx_desc_cnt = tx_alloc_cfg->ring_size; + priv->rx_desc_cnt = rx_alloc_cfg->ring_size; + if (priv->xdp_prog) priv->num_xdp_queues = priv->rx_cfg.num_queues; else priv->num_xdp_queues = 0; - gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, - &tx_alloc_cfg, &rx_alloc_cfg); - err = gve_alloc_qpls(priv, &qpls_alloc_cfg); - if (err) - return err; - priv->qpls = qpls_alloc_cfg.qpls; - tx_alloc_cfg.qpls = priv->qpls; - rx_alloc_cfg.qpls = priv->qpls; - err = gve_alloc_rings(priv, &tx_alloc_cfg, &rx_alloc_cfg); - if (err) - goto free_qpls; - - gve_tx_start_rings(priv, 0, tx_alloc_cfg.num_rings); - gve_rx_start_rings(priv, rx_alloc_cfg.qcfg->num_queues); + gve_tx_start_rings(priv, 0, tx_alloc_cfg->num_rings); + gve_rx_start_rings(priv, rx_alloc_cfg->qcfg->num_queues); gve_init_sync_stats(priv); err = netif_set_real_num_tx_queues(dev, priv->tx_cfg.num_queues); if (err) - goto free_rings; + goto stop_and_free_rings; err = netif_set_real_num_rx_queues(dev, priv->rx_cfg.num_queues); if (err) - goto free_rings; + goto stop_and_free_rings; err = gve_reg_xdp_info(priv, dev); if (err) - goto free_rings; + goto stop_and_free_rings; err = gve_register_qpls(priv); if (err) @@ -1416,29 +1470,22 @@ static int gve_open(struct net_device *dev) priv->interface_up_cnt++; return 0; -free_rings: - gve_tx_stop_rings(priv, 0, tx_alloc_cfg.num_rings); - gve_rx_stop_rings(priv, rx_alloc_cfg.qcfg->num_queues); - gve_free_rings(priv, &tx_alloc_cfg, &rx_alloc_cfg); -free_qpls: - gve_free_qpls(priv, &qpls_alloc_cfg); - return err; - reset: - /* This must have been called from a reset due to the rtnl lock - * so just return at this point. - */ if (gve_get_reset_in_progress(priv)) - return err; - /* Otherwise reset before returning */ + goto stop_and_free_rings; gve_reset_and_teardown(priv, true); /* if this fails there is nothing we can do so just ignore the return */ gve_reset_recovery(priv, false); /* return the original error */ return err; +stop_and_free_rings: + gve_tx_stop_rings(priv, 0, gve_num_tx_queues(priv)); + gve_rx_stop_rings(priv, priv->rx_cfg.num_queues); + gve_queues_mem_remove(priv); + return err; } -static int gve_close(struct net_device *dev) +static int gve_open(struct net_device *dev) { struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; @@ -1446,7 +1493,30 @@ static int gve_close(struct net_device *dev) struct gve_priv *priv = netdev_priv(dev); int err; - netif_carrier_off(dev); + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + + err = gve_queues_mem_alloc(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + if (err) + return err; + + /* No need to free on error: ownership of resources is lost after + * calling gve_queues_start. + */ + err = gve_queues_start(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + if (err) + return err; + + return 0; +} + +static int gve_queues_stop(struct gve_priv *priv) +{ + int err; + + netif_carrier_off(priv->dev); if (gve_get_device_rings_ok(priv)) { gve_turndown(priv); gve_drain_page_cache(priv); @@ -1462,12 +1532,8 @@ static int gve_close(struct net_device *dev) gve_unreg_xdp_info(priv); - gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, - &tx_alloc_cfg, &rx_alloc_cfg); - gve_tx_stop_rings(priv, 0, tx_alloc_cfg.num_rings); - gve_rx_stop_rings(priv, rx_alloc_cfg.qcfg->num_queues); - gve_free_rings(priv, &tx_alloc_cfg, &rx_alloc_cfg); - gve_free_qpls(priv, &qpls_alloc_cfg); + gve_tx_stop_rings(priv, 0, gve_num_tx_queues(priv)); + gve_rx_stop_rings(priv, priv->rx_cfg.num_queues); priv->interface_down_cnt++; return 0; @@ -1483,6 +1549,19 @@ err: return gve_reset_recovery(priv, false); } +static int gve_close(struct net_device *dev) +{ + struct gve_priv *priv = netdev_priv(dev); + int err; + + err = gve_queues_stop(priv); + if (err) + return err; + + gve_queues_mem_remove(priv); + return 0; +} + static int gve_remove_xdp_queues(struct gve_priv *priv) { int qpl_start_id; From 5f08cd3d6423e7ea81467e7216426d65b65297fa Mon Sep 17 00:00:00 2001 From: Shailend Chand Date: Mon, 22 Jan 2024 18:26:31 +0000 Subject: [PATCH 0254/2255] gve: Alloc before freeing when adjusting queues Previously, existing queues were being freed before the resources for the new queues were being allocated. This would take down the interface if someone were to attempt to change queue counts under a resource crunch. Signed-off-by: Shailend Chand Reviewed-by: Willem de Bruijn Reviewed-by: Jeroen de Borst Link: https://lore.kernel.org/r/20240122182632.1102721-6-shailend@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_main.c | 91 ++++++++++++++++------ 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 3515484e4cea..78c9cdf1511f 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -1869,42 +1869,87 @@ static int gve_xdp(struct net_device *dev, struct netdev_bpf *xdp) } } +static int gve_adjust_config(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + int err; + + /* Allocate resources for the new confiugration */ + err = gve_queues_mem_alloc(priv, qpls_alloc_cfg, + tx_alloc_cfg, rx_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, + "Adjust config failed to alloc new queues"); + return err; + } + + /* Teardown the device and free existing resources */ + err = gve_close(priv->dev); + if (err) { + netif_err(priv, drv, priv->dev, + "Adjust config failed to close old queues"); + gve_queues_mem_free(priv, qpls_alloc_cfg, + tx_alloc_cfg, rx_alloc_cfg); + return err; + } + + /* Bring the device back up again with the new resources. */ + err = gve_queues_start(priv, qpls_alloc_cfg, + tx_alloc_cfg, rx_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, + "Adjust config failed to start new queues, !!! DISABLING ALL QUEUES !!!\n"); + /* No need to free on error: ownership of resources is lost after + * calling gve_queues_start. + */ + gve_turndown(priv); + return err; + } + + return 0; +} + int gve_adjust_queues(struct gve_priv *priv, struct gve_queue_config new_rx_config, struct gve_queue_config new_tx_config) { + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; + struct gve_qpl_config new_qpl_cfg; int err; + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + + /* qpl_cfg is not read-only, it contains a map that gets updated as + * rings are allocated, which is why we cannot use the yet unreleased + * one in priv. + */ + qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg; + tx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + rx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + + /* Relay the new config from ethtool */ + qpls_alloc_cfg.tx_cfg = &new_tx_config; + tx_alloc_cfg.qcfg = &new_tx_config; + rx_alloc_cfg.qcfg_tx = &new_tx_config; + qpls_alloc_cfg.rx_cfg = &new_rx_config; + rx_alloc_cfg.qcfg = &new_rx_config; + tx_alloc_cfg.num_rings = new_tx_config.num_queues; + if (netif_carrier_ok(priv->dev)) { - /* To make this process as simple as possible we teardown the - * device, set the new configuration, and then bring the device - * up again. - */ - err = gve_close(priv->dev); - /* we have already tried to reset in close, - * just fail at this point - */ - if (err) - return err; - priv->tx_cfg = new_tx_config; - priv->rx_cfg = new_rx_config; - - err = gve_open(priv->dev); - if (err) - goto err; - - return 0; + err = gve_adjust_config(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + return err; } /* Set the config for the next up. */ priv->tx_cfg = new_tx_config; priv->rx_cfg = new_rx_config; return 0; -err: - netif_err(priv, drv, priv->dev, - "Adjust queues failed! !!! DISABLING ALL QUEUES !!!\n"); - gve_turndown(priv); - return err; } static void gve_turndown(struct gve_priv *priv) From f3753771e7cc965c31eff20fa3d10056e64aa07c Mon Sep 17 00:00:00 2001 From: Shailend Chand Date: Mon, 22 Jan 2024 18:26:32 +0000 Subject: [PATCH 0255/2255] gve: Alloc before freeing when changing features Previously, existing queues were being freed before the resources for the new queues were being allocated. This would take down the interface if someone were to attempt to change feature flags under a resource crunch. Signed-off-by: Shailend Chand Reviewed-by: Willem de Bruijn Reviewed-by: Jeroen de Borst Link: https://lore.kernel.org/r/20240122182632.1102721-7-shailend@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_main.c | 41 +++++++++++----------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 78c9cdf1511f..db6d9ae7cd78 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -2069,36 +2069,37 @@ static int gve_set_features(struct net_device *netdev, netdev_features_t features) { const netdev_features_t orig_features = netdev->features; + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; struct gve_priv *priv = netdev_priv(netdev); + struct gve_qpl_config new_qpl_cfg; int err; + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + /* qpl_cfg is not read-only, it contains a map that gets updated as + * rings are allocated, which is why we cannot use the yet unreleased + * one in priv. + */ + qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg; + tx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + rx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + if ((netdev->features & NETIF_F_LRO) != (features & NETIF_F_LRO)) { netdev->features ^= NETIF_F_LRO; if (netif_carrier_ok(netdev)) { - /* To make this process as simple as possible we - * teardown the device, set the new configuration, - * and then bring the device up again. - */ - err = gve_close(netdev); - /* We have already tried to reset in close, just fail - * at this point. - */ - if (err) - goto err; - - err = gve_open(netdev); - if (err) - goto err; + err = gve_adjust_config(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + if (err) { + /* Revert the change on error. */ + netdev->features = orig_features; + return err; + } } } return 0; -err: - /* Reverts the change on error. */ - netdev->features = orig_features; - netif_err(priv, drv, netdev, - "Set features failed! !!! DISABLING ALL QUEUES !!!\n"); - return err; } static const struct net_device_ops gve_netdev_ops = { From 15b4f88dcc0a751f790bfea5ef9dcc6385c62236 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 23 Jan 2024 17:03:50 +0800 Subject: [PATCH 0256/2255] selftests/bpf: Move is_jit_enabled() into testing_helpers Currently, is_jit_enabled() is only used in test_progs, move it into testing_helpers so that it can be used in test_verifier. While at it, remove the second argument "0" of open() as Hou Tao suggested. Signed-off-by: Tiezhu Yang Signed-off-by: Andrii Nakryiko Acked-by: Hou Tao Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20240123090351.2207-2-yangtiezhu@loongson.cn --- tools/testing/selftests/bpf/test_progs.c | 18 ------------------ tools/testing/selftests/bpf/testing_helpers.c | 18 ++++++++++++++++++ tools/testing/selftests/bpf/testing_helpers.h | 1 + 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 1b9387890148..808550986f30 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -547,24 +547,6 @@ int bpf_find_map(const char *test, struct bpf_object *obj, const char *name) return bpf_map__fd(map); } -static bool is_jit_enabled(void) -{ - const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; - bool enabled = false; - int sysctl_fd; - - sysctl_fd = open(jit_sysctl, 0, O_RDONLY); - if (sysctl_fd != -1) { - char tmpc; - - if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1) - enabled = (tmpc != '0'); - close(sysctl_fd); - } - - return enabled; -} - int compare_map_keys(int map1_fd, int map2_fd) { __u32 key, next_key; diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 106ef05586b8..a59e56d804ee 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -457,3 +457,21 @@ out_free_buf: *buf = NULL; return -1; } + +bool is_jit_enabled(void) +{ + const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; + bool enabled = false; + int sysctl_fd; + + sysctl_fd = open(jit_sysctl, O_RDONLY); + if (sysctl_fd != -1) { + char tmpc; + + if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1) + enabled = (tmpc != '0'); + close(sysctl_fd); + } + + return enabled; +} diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index e099aa4da611..d14de81727e6 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -52,5 +52,6 @@ struct bpf_insn; */ int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt); int testing_prog_flags(void); +bool is_jit_enabled(void); #endif /* __TESTING_HELPERS_H */ From 0b50478fd8774f42721f4297293b711e17bc4b7b Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 23 Jan 2024 17:03:51 +0800 Subject: [PATCH 0257/2255] selftests/bpf: Skip callback tests if jit is disabled in test_verifier If CONFIG_BPF_JIT_ALWAYS_ON is not set and bpf_jit_enable is 0, there exist 6 failed tests. [root@linux bpf]# echo 0 > /proc/sys/net/core/bpf_jit_enable [root@linux bpf]# echo 0 > /proc/sys/kernel/unprivileged_bpf_disabled [root@linux bpf]# ./test_verifier | grep FAIL #106/p inline simple bpf_loop call FAIL #107/p don't inline bpf_loop call, flags non-zero FAIL #108/p don't inline bpf_loop call, callback non-constant FAIL #109/p bpf_loop_inline and a dead func FAIL #110/p bpf_loop_inline stack locations for loop vars FAIL #111/p inline bpf_loop call in a big program FAIL Summary: 768 PASSED, 15 SKIPPED, 6 FAILED The test log shows that callbacks are not allowed in non-JITed programs, interpreter doesn't support them yet, thus these tests should be skipped if jit is disabled. Add an explicit flag F_NEEDS_JIT_ENABLED to those tests to mark that they require JIT enabled in bpf_loop_inline.c, check the flag and jit_disabled at the beginning of do_test_single() to handle this case. With this patch: [root@linux bpf]# echo 0 > /proc/sys/net/core/bpf_jit_enable [root@linux bpf]# echo 0 > /proc/sys/kernel/unprivileged_bpf_disabled [root@linux bpf]# ./test_verifier | grep FAIL Summary: 768 PASSED, 21 SKIPPED, 0 FAILED Suggested-by: Andrii Nakryiko Signed-off-by: Tiezhu Yang Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240123090351.2207-3-yangtiezhu@loongson.cn --- tools/testing/selftests/bpf/test_verifier.c | 11 +++++++++++ .../testing/selftests/bpf/verifier/bpf_loop_inline.c | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 1a09fc34d093..e1a1dfe8d7fa 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -67,6 +67,7 @@ #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) #define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1) +#define F_NEEDS_JIT_ENABLED (1 << 2) /* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */ #define ADMIN_CAPS (1ULL << CAP_NET_ADMIN | \ @@ -74,6 +75,7 @@ 1ULL << CAP_BPF) #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled" static bool unpriv_disabled = false; +static bool jit_disabled; static int skips; static bool verbose = false; static int verif_log_level = 0; @@ -1524,6 +1526,13 @@ static void do_test_single(struct bpf_test *test, bool unpriv, __u32 pflags; int i, err; + if ((test->flags & F_NEEDS_JIT_ENABLED) && jit_disabled) { + printf("SKIP (requires BPF JIT)"); + skips++; + sched_yield(); + return; + } + fd_prog = -1; for (i = 0; i < MAX_NR_MAPS; i++) map_fds[i] = -1; @@ -1844,6 +1853,8 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + jit_disabled = !is_jit_enabled(); + /* Use libbpf 1.0 API mode */ libbpf_set_strict_mode(LIBBPF_STRICT_ALL); diff --git a/tools/testing/selftests/bpf/verifier/bpf_loop_inline.c b/tools/testing/selftests/bpf/verifier/bpf_loop_inline.c index a535d41dc20d..59125b22ae39 100644 --- a/tools/testing/selftests/bpf/verifier/bpf_loop_inline.c +++ b/tools/testing/selftests/bpf/verifier/bpf_loop_inline.c @@ -57,6 +57,7 @@ .expected_insns = { PSEUDO_CALL_INSN() }, .unexpected_insns = { HELPER_CALL_INSN() }, .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .flags = F_NEEDS_JIT_ENABLED, .result = ACCEPT, .runs = 0, .func_info = { { 0, MAIN_TYPE }, { 12, CALLBACK_TYPE } }, @@ -90,6 +91,7 @@ .expected_insns = { HELPER_CALL_INSN() }, .unexpected_insns = { PSEUDO_CALL_INSN() }, .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .flags = F_NEEDS_JIT_ENABLED, .result = ACCEPT, .runs = 0, .func_info = { { 0, MAIN_TYPE }, { 16, CALLBACK_TYPE } }, @@ -127,6 +129,7 @@ .expected_insns = { HELPER_CALL_INSN() }, .unexpected_insns = { PSEUDO_CALL_INSN() }, .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .flags = F_NEEDS_JIT_ENABLED, .result = ACCEPT, .runs = 0, .func_info = { @@ -165,6 +168,7 @@ .expected_insns = { PSEUDO_CALL_INSN() }, .unexpected_insns = { HELPER_CALL_INSN() }, .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .flags = F_NEEDS_JIT_ENABLED, .result = ACCEPT, .runs = 0, .func_info = { @@ -235,6 +239,7 @@ }, .unexpected_insns = { HELPER_CALL_INSN() }, .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .flags = F_NEEDS_JIT_ENABLED, .result = ACCEPT, .func_info = { { 0, MAIN_TYPE }, @@ -252,6 +257,7 @@ .unexpected_insns = { HELPER_CALL_INSN() }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .flags = F_NEEDS_JIT_ENABLED, .func_info = { { 0, MAIN_TYPE }, { 16, CALLBACK_TYPE } }, .func_info_cnt = 2, BTF_TYPES From d47b9f68d2899b390a3655f2365f332a63396adf Mon Sep 17 00:00:00 2001 From: Dima Tisnek Date: Sun, 21 Jan 2024 15:01:26 +0900 Subject: [PATCH 0258/2255] libbpf: Correct bpf_core_read.h comment wrt bpf_core_relo struct Past commit ([0]) removed the last vestiges of struct bpf_field_reloc, it's called struct bpf_core_relo now. [0] 28b93c64499a ("libbpf: Clean up and improve CO-RE reloc logging") Signed-off-by: Dima Tisnek Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240121060126.15650-1-dimaqq@gmail.com --- tools/lib/bpf/bpf_core_read.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/bpf_core_read.h b/tools/lib/bpf/bpf_core_read.h index 7325a12692a3..5aec301e9585 100644 --- a/tools/lib/bpf/bpf_core_read.h +++ b/tools/lib/bpf/bpf_core_read.h @@ -268,7 +268,7 @@ enum bpf_enum_value_kind { * a relocation, which records BTF type ID describing root struct/union and an * accessor string which describes exact embedded field that was used to take * an address. See detailed description of this relocation format and - * semantics in comments to struct bpf_field_reloc in libbpf_internal.h. + * semantics in comments to struct bpf_core_relo in include/uapi/linux/bpf.h. * * This relocation allows libbpf to adjust BPF instruction to use correct * actual field offset, based on target kernel BTF type that matches original From 67a48d937fac917947540c9f89630d472cd61fcb Mon Sep 17 00:00:00 2001 From: Sriram R Date: Wed, 17 Jan 2024 11:56:28 +0530 Subject: [PATCH 0259/2255] wifi: ath12k: Fix issues in channel list update Currently, the logic used to select the 6 GHz band is incorrect, which may cause 6 GHz supported channels to not be updated properly. This is because the 6 GHz Max frequency supported by the driver is being compared to the Max frequency supported on the board. If in some cases, the 6 GHz Max frequency supported on the board is less than the defined 6 GHz Max frequency, all 6 GHz channels are disabled. To address this, compare the max frequency supported by the board to the defined 6 GHz Minimum frequency by the driver. Similarly, when a dual mac card supports both 6 GHz and 5 GHz radios, if the 5 GHz radio gets enumerated first before 6 GHz, the checks in ath12k_mac_setup_channels_rates() can cause the 5 GHz channels which were enabled earlier to get disabled when the 6 GHz channel list is updated. This is because the Min 6 GHz frequency defined in the driver is 5945 MHz, which should be 5925 MHz since channel 2 is not considered currently, but the firmware can pass 5925 MHz as the minimum. Hence, update the Min frequency supported by the driver to 5925 MHz. In addition, ensure that the channel list update to firmware updates only the channels that the current radio (ar) supports rather than considering the wiphy support. This would be required when multiple pdevs are supported in a wiphy and they support different ranges of frequencies or bands as in single wiphy support. Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Sriram R Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117062628.8260-1-quic_srirrama@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 +- drivers/net/wireless/ath/ath12k/mac.c | 2 +- drivers/net/wireless/ath/ath12k/reg.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index a56fc74366b4..5c6c1e2eddb6 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -425,7 +425,7 @@ struct ath12k_sta { }; #define ATH12K_MIN_5G_FREQ 4150 -#define ATH12K_MIN_6G_FREQ 5945 +#define ATH12K_MIN_6G_FREQ 5925 #define ATH12K_MAX_6G_FREQ 7115 #define ATH12K_NUM_CHANS 100 #define ATH12K_MAX_5G_CHAN 173 diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index fe600dbef875..a27480a69b27 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7394,7 +7394,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, } if (supported_bands & WMI_HOST_WLAN_5G_CAP) { - if (reg_cap->high_5ghz_chan >= ATH12K_MAX_6G_FREQ) { + if (reg_cap->high_5ghz_chan >= ATH12K_MIN_6G_FREQ) { channels = kmemdup(ath12k_6ghz_channels, sizeof(ath12k_6ghz_channels), GFP_KERNEL); if (!channels) { diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index a164f15d1e2b..f308e9a6ed55 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -104,7 +104,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) bands = hw->wiphy->bands; for (band = 0; band < NUM_NL80211_BANDS; band++) { - if (!bands[band]) + if (!(ar->mac.sbands[band].channels && bands[band])) continue; for (i = 0; i < bands[band]->n_channels; i++) { @@ -130,7 +130,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) ch = arg->channel; for (band = 0; band < NUM_NL80211_BANDS; band++) { - if (!bands[band]) + if (!(ar->mac.sbands[band].channels && bands[band])) continue; for (i = 0; i < bands[band]->n_channels; i++) { From 16c595a53c5f37c2345f4b4b82f7eb927c2dda5e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 24 Jan 2024 09:43:30 -0800 Subject: [PATCH 0260/2255] Revert "net: ethernet: qualcomm: Remove QDF24xx support" This reverts commit a2a7f98aeeec48118fac73c22bd54f8889815e16. Konrad mentioned that Qualcomm appears to use these devices, still, internally, even tho they never made it to the broader market. Link: https://lore.kernel.org/all/0679f568-60e7-47d8-b86e-052a9eb4c103@linaro.org/ Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/qualcomm/emac/Makefile | 3 +- .../qualcomm/emac/emac-sgmii-qdf2400.c | 215 ++++++++++++++++++ .../qualcomm/emac/emac-sgmii-qdf2432.c | 202 ++++++++++++++++ .../net/ethernet/qualcomm/emac/emac-sgmii.c | 124 ++++++++-- .../net/ethernet/qualcomm/emac/emac-sgmii.h | 2 + 5 files changed, 523 insertions(+), 23 deletions(-) create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c diff --git a/drivers/net/ethernet/qualcomm/emac/Makefile b/drivers/net/ethernet/qualcomm/emac/Makefile index ffc00995acb9..61d15e091be2 100644 --- a/drivers/net/ethernet/qualcomm/emac/Makefile +++ b/drivers/net/ethernet/qualcomm/emac/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o emac-ethtool.o \ - emac-sgmii-fsm9900.o + emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o \ + emac-sgmii-qdf2400.o diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c new file mode 100644 index 000000000000..b29148ce7e05 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + */ + +/* Qualcomm Technologies, Inc. QDF2400 EMAC SGMII Controller driver. + */ + +#include +#include "emac.h" + +/* EMAC_SGMII register offsets */ +#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x000C +#define EMAC_SGMII_PHY_LANE_CTRL1 0x0018 +#define EMAC_SGMII_PHY_CDR_CTRL0 0x0058 +#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x0080 +#define EMAC_SGMII_PHY_RESET_CTRL 0x00a8 +#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4 + +/* SGMII digital lane registers */ +#define EMAC_SGMII_LN_DRVR_CTRL0 0x000C +#define EMAC_SGMII_LN_DRVR_CTRL1 0x0010 +#define EMAC_SGMII_LN_DRVR_TAP_EN 0x0018 +#define EMAC_SGMII_LN_TX_MARGINING 0x001C +#define EMAC_SGMII_LN_TX_PRE 0x0020 +#define EMAC_SGMII_LN_TX_POST 0x0024 +#define EMAC_SGMII_LN_TX_BAND_MODE 0x0060 +#define EMAC_SGMII_LN_LANE_MODE 0x0064 +#define EMAC_SGMII_LN_PARALLEL_RATE 0x007C +#define EMAC_SGMII_LN_CML_CTRL_MODE0 0x00C0 +#define EMAC_SGMII_LN_MIXER_CTRL_MODE0 0x00D8 +#define EMAC_SGMII_LN_VGA_INITVAL 0x013C +#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0 0x0184 +#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0 0x0190 +#define EMAC_SGMII_LN_UCDR_SO_CONFIG 0x019C +#define EMAC_SGMII_LN_RX_BAND 0x01A4 +#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0 0x01C0 +#define EMAC_SGMII_LN_RSM_CONFIG 0x01F8 +#define EMAC_SGMII_LN_SIGDET_ENABLES 0x0230 +#define EMAC_SGMII_LN_SIGDET_CNTRL 0x0234 +#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL 0x0238 +#define EMAC_SGMII_LN_RX_EN_SIGNAL 0x02AC +#define EMAC_SGMII_LN_RX_MISC_CNTRL0 0x02B8 +#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV 0x02C8 +#define EMAC_SGMII_LN_RX_RESECODE_OFFSET 0x02CC + +/* SGMII digital lane register values */ +#define UCDR_STEP_BY_TWO_MODE0 BIT(7) +#define UCDR_xO_GAIN_MODE(x) ((x) & 0x7f) +#define UCDR_ENABLE BIT(6) +#define UCDR_SO_SATURATION(x) ((x) & 0x3f) + +#define SIGDET_LP_BYP_PS4 BIT(7) +#define SIGDET_EN_PS0_TO_PS2 BIT(6) + +#define TXVAL_VALID_INIT BIT(4) +#define KR_PCIGEN3_MODE BIT(0) + +#define MAIN_EN BIT(0) + +#define TX_MARGINING_MUX BIT(6) +#define TX_MARGINING(x) ((x) & 0x3f) + +#define TX_PRE_MUX BIT(6) + +#define TX_POST_MUX BIT(6) + +#define CML_GEAR_MODE(x) (((x) & 7) << 3) +#define CML2CMOS_IBOOST_MODE(x) ((x) & 7) + +#define RESCODE_OFFSET(x) ((x) & 0x1f) + +#define MIXER_LOADB_MODE(x) (((x) & 0xf) << 2) +#define MIXER_DATARATE_MODE(x) ((x) & 3) + +#define VGA_THRESH_DFE(x) ((x) & 0x3f) + +#define SIGDET_LP_BYP_PS0_TO_PS2 BIT(5) +#define SIGDET_FLT_BYP BIT(0) + +#define SIGDET_LVL(x) (((x) & 0xf) << 4) + +#define SIGDET_DEGLITCH_CTRL(x) (((x) & 0xf) << 1) + +#define INVERT_PCS_RX_CLK BIT(7) + +#define DRVR_LOGIC_CLK_EN BIT(4) +#define DRVR_LOGIC_CLK_DIV(x) ((x) & 0xf) + +#define PARALLEL_RATE_MODE0(x) ((x) & 0x3) + +#define BAND_MODE0(x) ((x) & 0x3) + +#define LANE_MODE(x) ((x) & 0x1f) + +#define CDR_PD_SEL_MODE0(x) (((x) & 0x3) << 5) +#define EN_DLL_MODE0 BIT(4) +#define EN_IQ_DCC_MODE0 BIT(3) +#define EN_IQCAL_MODE0 BIT(2) + +#define BYPASS_RSM_SAMP_CAL BIT(1) +#define BYPASS_RSM_DLL_CAL BIT(0) + +#define L0_RX_EQUALIZE_ENABLE BIT(6) + +#define PWRDN_B BIT(0) + +#define CDR_MAX_CNT(x) ((x) & 0xff) + +#define SERDES_START_WAIT_TIMES 100 + +struct emac_reg_write { + unsigned int offset; + u32 val; +}; + +static void emac_reg_write_all(void __iomem *base, + const struct emac_reg_write *itr, size_t size) +{ + size_t i; + + for (i = 0; i < size; ++itr, ++i) + writel(itr->val, base + itr->offset); +} + +static const struct emac_reg_write sgmii_laned[] = { + /* CDR Settings */ + {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0, + UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)}, + {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)}, + {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)}, + + /* TX/RX Settings */ + {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2}, + + {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE}, + {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN}, + {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)}, + {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX}, + {EMAC_SGMII_LN_TX_POST, TX_POST_MUX}, + + {EMAC_SGMII_LN_CML_CTRL_MODE0, + CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)}, + {EMAC_SGMII_LN_MIXER_CTRL_MODE0, + MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)}, + {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)}, + {EMAC_SGMII_LN_SIGDET_ENABLES, + SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP}, + {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)}, + + {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)}, + {EMAC_SGMII_LN_RX_MISC_CNTRL0, INVERT_PCS_RX_CLK}, + {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV, + DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)}, + + {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)}, + {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(1)}, + {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(2)}, + {EMAC_SGMII_LN_DRVR_CTRL1, RESCODE_OFFSET(7)}, + {EMAC_SGMII_LN_RX_RESECODE_OFFSET, RESCODE_OFFSET(9)}, + {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)}, + {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(2) | + EN_DLL_MODE0 | EN_IQ_DCC_MODE0 | EN_IQCAL_MODE0}, + {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL}, +}; + +static const struct emac_reg_write physical_coding_sublayer_programming[] = { + {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B}, + {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)}, + {EMAC_SGMII_PHY_TX_PWR_CTRL, 0}, + {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE}, +}; + +int emac_sgmii_init_qdf2400(struct emac_adapter *adpt) +{ + struct emac_sgmii *phy = &adpt->phy; + void __iomem *phy_regs = phy->base; + void __iomem *laned = phy->digital; + unsigned int i; + u32 lnstatus; + + /* PCS lane-x init */ + emac_reg_write_all(phy->base, physical_coding_sublayer_programming, + ARRAY_SIZE(physical_coding_sublayer_programming)); + + /* SGMII lane-x init */ + emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned)); + + /* Power up PCS and start reset lane state machine */ + + writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL); + writel(1, laned + SGMII_LN_RSM_START); + + /* Wait for c_ready assertion */ + for (i = 0; i < SERDES_START_WAIT_TIMES; i++) { + lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS); + if (lnstatus & BIT(1)) + break; + usleep_range(100, 200); + } + + if (i == SERDES_START_WAIT_TIMES) { + netdev_err(adpt->netdev, "SGMII failed to start\n"); + return -EIO; + } + + /* Disable digital and SERDES loopback */ + writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0); + writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2); + writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1); + + /* Mask out all the SGMII Interrupt */ + writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK); + + return 0; +} diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c new file mode 100644 index 000000000000..65519eeebecd --- /dev/null +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + */ + +/* Qualcomm Technologies, Inc. QDF2432 EMAC SGMII Controller driver. + */ + +#include +#include "emac.h" + +/* EMAC_SGMII register offsets */ +#define EMAC_SGMII_PHY_TX_PWR_CTRL 0x000C +#define EMAC_SGMII_PHY_LANE_CTRL1 0x0018 +#define EMAC_SGMII_PHY_CDR_CTRL0 0x0058 +#define EMAC_SGMII_PHY_POW_DWN_CTRL0 0x0080 +#define EMAC_SGMII_PHY_RESET_CTRL 0x00a8 +#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4 + +/* SGMII digital lane registers */ +#define EMAC_SGMII_LN_DRVR_CTRL0 0x000C +#define EMAC_SGMII_LN_DRVR_TAP_EN 0x0018 +#define EMAC_SGMII_LN_TX_MARGINING 0x001C +#define EMAC_SGMII_LN_TX_PRE 0x0020 +#define EMAC_SGMII_LN_TX_POST 0x0024 +#define EMAC_SGMII_LN_TX_BAND_MODE 0x0060 +#define EMAC_SGMII_LN_LANE_MODE 0x0064 +#define EMAC_SGMII_LN_PARALLEL_RATE 0x0078 +#define EMAC_SGMII_LN_CML_CTRL_MODE0 0x00B8 +#define EMAC_SGMII_LN_MIXER_CTRL_MODE0 0x00D0 +#define EMAC_SGMII_LN_VGA_INITVAL 0x0134 +#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0 0x017C +#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0 0x0188 +#define EMAC_SGMII_LN_UCDR_SO_CONFIG 0x0194 +#define EMAC_SGMII_LN_RX_BAND 0x019C +#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0 0x01B8 +#define EMAC_SGMII_LN_RSM_CONFIG 0x01F0 +#define EMAC_SGMII_LN_SIGDET_ENABLES 0x0224 +#define EMAC_SGMII_LN_SIGDET_CNTRL 0x0228 +#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL 0x022C +#define EMAC_SGMII_LN_RX_EN_SIGNAL 0x02A0 +#define EMAC_SGMII_LN_RX_MISC_CNTRL0 0x02AC +#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV 0x02BC + +/* SGMII digital lane register values */ +#define UCDR_STEP_BY_TWO_MODE0 BIT(7) +#define UCDR_xO_GAIN_MODE(x) ((x) & 0x7f) +#define UCDR_ENABLE BIT(6) +#define UCDR_SO_SATURATION(x) ((x) & 0x3f) + +#define SIGDET_LP_BYP_PS4 BIT(7) +#define SIGDET_EN_PS0_TO_PS2 BIT(6) + +#define TXVAL_VALID_INIT BIT(4) +#define KR_PCIGEN3_MODE BIT(0) + +#define MAIN_EN BIT(0) + +#define TX_MARGINING_MUX BIT(6) +#define TX_MARGINING(x) ((x) & 0x3f) + +#define TX_PRE_MUX BIT(6) + +#define TX_POST_MUX BIT(6) + +#define CML_GEAR_MODE(x) (((x) & 7) << 3) +#define CML2CMOS_IBOOST_MODE(x) ((x) & 7) + +#define MIXER_LOADB_MODE(x) (((x) & 0xf) << 2) +#define MIXER_DATARATE_MODE(x) ((x) & 3) + +#define VGA_THRESH_DFE(x) ((x) & 0x3f) + +#define SIGDET_LP_BYP_PS0_TO_PS2 BIT(5) +#define SIGDET_FLT_BYP BIT(0) + +#define SIGDET_LVL(x) (((x) & 0xf) << 4) + +#define SIGDET_DEGLITCH_CTRL(x) (((x) & 0xf) << 1) + +#define DRVR_LOGIC_CLK_EN BIT(4) +#define DRVR_LOGIC_CLK_DIV(x) ((x) & 0xf) + +#define PARALLEL_RATE_MODE0(x) ((x) & 0x3) + +#define BAND_MODE0(x) ((x) & 0x3) + +#define LANE_MODE(x) ((x) & 0x1f) + +#define CDR_PD_SEL_MODE0(x) (((x) & 0x3) << 5) +#define BYPASS_RSM_SAMP_CAL BIT(1) +#define BYPASS_RSM_DLL_CAL BIT(0) + +#define L0_RX_EQUALIZE_ENABLE BIT(6) + +#define PWRDN_B BIT(0) + +#define CDR_MAX_CNT(x) ((x) & 0xff) + +#define SERDES_START_WAIT_TIMES 100 + +struct emac_reg_write { + unsigned int offset; + u32 val; +}; + +static void emac_reg_write_all(void __iomem *base, + const struct emac_reg_write *itr, size_t size) +{ + size_t i; + + for (i = 0; i < size; ++itr, ++i) + writel(itr->val, base + itr->offset); +} + +static const struct emac_reg_write sgmii_laned[] = { + /* CDR Settings */ + {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0, + UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)}, + {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)}, + {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)}, + + /* TX/RX Settings */ + {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2}, + + {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE}, + {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN}, + {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)}, + {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX}, + {EMAC_SGMII_LN_TX_POST, TX_POST_MUX}, + + {EMAC_SGMII_LN_CML_CTRL_MODE0, + CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)}, + {EMAC_SGMII_LN_MIXER_CTRL_MODE0, + MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)}, + {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)}, + {EMAC_SGMII_LN_SIGDET_ENABLES, + SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP}, + {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)}, + + {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)}, + {EMAC_SGMII_LN_RX_MISC_CNTRL0, 0}, + {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV, + DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)}, + + {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)}, + {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)}, + {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)}, + {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)}, + {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)}, + {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL}, +}; + +static const struct emac_reg_write physical_coding_sublayer_programming[] = { + {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B}, + {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)}, + {EMAC_SGMII_PHY_TX_PWR_CTRL, 0}, + {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE}, +}; + +int emac_sgmii_init_qdf2432(struct emac_adapter *adpt) +{ + struct emac_sgmii *phy = &adpt->phy; + void __iomem *phy_regs = phy->base; + void __iomem *laned = phy->digital; + unsigned int i; + u32 lnstatus; + + /* PCS lane-x init */ + emac_reg_write_all(phy->base, physical_coding_sublayer_programming, + ARRAY_SIZE(physical_coding_sublayer_programming)); + + /* SGMII lane-x init */ + emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned)); + + /* Power up PCS and start reset lane state machine */ + + writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL); + writel(1, laned + SGMII_LN_RSM_START); + + /* Wait for c_ready assertion */ + for (i = 0; i < SERDES_START_WAIT_TIMES; i++) { + lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS); + if (lnstatus & BIT(1)) + break; + usleep_range(100, 200); + } + + if (i == SERDES_START_WAIT_TIMES) { + netdev_err(adpt->netdev, "SGMII failed to start\n"); + return -EIO; + } + + /* Disable digital and SERDES loopback */ + writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0); + writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2); + writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1); + + /* Mask out all the SGMII Interrupt */ + writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK); + + return 0; +} diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c index 573c82b21de5..e4bc18009d08 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -274,11 +275,76 @@ static struct sgmii_ops fsm9900_ops = { .reset = emac_sgmii_common_reset, }; +static struct sgmii_ops qdf2432_ops = { + .init = emac_sgmii_init_qdf2432, + .open = emac_sgmii_common_open, + .close = emac_sgmii_common_close, + .link_change = emac_sgmii_common_link_change, + .reset = emac_sgmii_common_reset, +}; + +#ifdef CONFIG_ACPI +static struct sgmii_ops qdf2400_ops = { + .init = emac_sgmii_init_qdf2400, + .open = emac_sgmii_common_open, + .close = emac_sgmii_common_close, + .link_change = emac_sgmii_common_link_change, + .reset = emac_sgmii_common_reset, +}; +#endif + +static int emac_sgmii_acpi_match(struct device *dev, void *data) +{ +#ifdef CONFIG_ACPI + static const struct acpi_device_id match_table[] = { + { + .id = "QCOM8071", + }, + {} + }; + const struct acpi_device_id *id = acpi_match_device(match_table, dev); + struct sgmii_ops **ops = data; + + if (id) { + acpi_handle handle = ACPI_HANDLE(dev); + unsigned long long hrv; + acpi_status status; + + status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv); + if (status) { + if (status == AE_NOT_FOUND) + /* Older versions of the QDF2432 ACPI tables do + * not have an _HRV property. + */ + hrv = 1; + else + /* Something is wrong with the tables */ + return 0; + } + + switch (hrv) { + case 1: + *ops = &qdf2432_ops; + return 1; + case 2: + *ops = &qdf2400_ops; + return 1; + } + } +#endif + + return 0; +} + static const struct of_device_id emac_sgmii_dt_match[] = { { .compatible = "qcom,fsm9900-emac-sgmii", .data = &fsm9900_ops, }, + { + .compatible = "qcom,qdf2432-emac-sgmii", + .data = &qdf2432_ops, + }, {} }; @@ -289,31 +355,45 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) struct resource *res; int ret; - const struct of_device_id *match; - struct device_node *np; + if (has_acpi_companion(&pdev->dev)) { + struct device *dev; - np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0); - if (!np) { - dev_err(&pdev->dev, "missing internal-phy property\n"); - return -ENODEV; + dev = device_find_child(&pdev->dev, &phy->sgmii_ops, + emac_sgmii_acpi_match); + + if (!dev) { + dev_warn(&pdev->dev, "cannot find internal phy node\n"); + return 0; + } + + sgmii_pdev = to_platform_device(dev); + } else { + const struct of_device_id *match; + struct device_node *np; + + np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0); + if (!np) { + dev_err(&pdev->dev, "missing internal-phy property\n"); + return -ENODEV; + } + + sgmii_pdev = of_find_device_by_node(np); + of_node_put(np); + if (!sgmii_pdev) { + dev_err(&pdev->dev, "invalid internal-phy property\n"); + return -ENODEV; + } + + match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev); + if (!match) { + dev_err(&pdev->dev, "unrecognized internal phy node\n"); + ret = -ENODEV; + goto error_put_device; + } + + phy->sgmii_ops = (struct sgmii_ops *)match->data; } - sgmii_pdev = of_find_device_by_node(np); - of_node_put(np); - if (!sgmii_pdev) { - dev_err(&pdev->dev, "invalid internal-phy property\n"); - return -ENODEV; - } - - match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev); - if (!match) { - dev_err(&pdev->dev, "unrecognized internal phy node\n"); - ret = -ENODEV; - goto error_put_device; - } - - phy->sgmii_ops = (struct sgmii_ops *)match->data; - /* Base address is the first address */ res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h index 7b7b0dc44225..6daeddacbcfa 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h @@ -40,6 +40,8 @@ struct emac_sgmii { int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt); int emac_sgmii_init_fsm9900(struct emac_adapter *adpt); +int emac_sgmii_init_qdf2432(struct emac_adapter *adpt); +int emac_sgmii_init_qdf2400(struct emac_adapter *adpt); int emac_sgmii_init(struct emac_adapter *adpt); int emac_sgmii_open(struct emac_adapter *adpt); From 177f1d083a19af58f4b1206d299ed73689249fd8 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 19 Jan 2024 22:05:17 -0800 Subject: [PATCH 0261/2255] selftests/bpf: Fix the flaky tc_redirect_dtime test BPF CI has been reporting the tc_redirect_dtime test failing from time to time: test_inet_dtime:PASS:setns src 0 nsec (network_helpers.c:253: errno: No route to host) Failed to connect to server close_netns:PASS:setns 0 nsec test_inet_dtime:FAIL:connect_to_fd unexpected connect_to_fd: actual -1 < expected 0 test_tcp_clear_dtime:PASS:tcp ip6 clear dtime ingress_fwdns_p100 0 nsec The connect_to_fd failure (EHOSTUNREACH) is from the test_tcp_clear_dtime() test and it is the very first IPv6 traffic after setting up all the links, addresses, and routes. The symptom is this first connect() is always slow. In my setup, it could take ~3s. After some tracing and tcpdump, the slowness is mostly spent in the neighbor solicitation in the "ns_fwd" namespace while the "ns_src" and "ns_dst" are fine. I forced the kernel to drop the neighbor solicitation messages. I can then reproduce EHOSTUNREACH. What actually happen could be: - the neighbor advertisement came back a little slow. - the "ns_fwd" namespace concluded a neighbor discovery failure and triggered the ndisc_error_report() => ip6_link_failure() => icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0) - the client's connect() reports EHOSTUNREACH after receiving the ICMPV6_DEST_UNREACH message. The neigh table of both "ns_src" and "ns_dst" namespace has already been manually populated but not the "ns_fwd" namespace. This patch fixes it by manually populating the neigh table also in the "ns_fwd" namespace. Although the namespace configuration part had been existed before the tc_redirect_dtime test, still Fixes-tagging the patch when the tc_redirect_dtime test was added since it is the only test hitting it so far. Fixes: c803475fd8dd ("bpf: selftests: test skb->tstamp in redirect_neigh") Signed-off-by: Martin KaFai Lau Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240120060518.3604920-1-martin.lau@linux.dev --- tools/testing/selftests/bpf/prog_tests/tc_redirect.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c index 518f143c5b0f..610887157fd8 100644 --- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c +++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c @@ -188,6 +188,7 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) { struct nstoken *nstoken = NULL; char src_fwd_addr[IFADDR_STR_LEN+1] = {}; + char src_addr[IFADDR_STR_LEN + 1] = {}; int err; if (result->dev_mode == MODE_VETH) { @@ -208,6 +209,9 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) if (get_ifaddr("src_fwd", src_fwd_addr)) goto fail; + if (get_ifaddr("src", src_addr)) + goto fail; + result->ifindex_src = if_nametoindex("src"); if (!ASSERT_GT(result->ifindex_src, 0, "ifindex_src")) goto fail; @@ -270,6 +274,13 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) SYS(fail, "ip route add " IP4_DST "/32 dev dst_fwd scope global"); SYS(fail, "ip route add " IP6_DST "/128 dev dst_fwd scope global"); + if (result->dev_mode == MODE_VETH) { + SYS(fail, "ip neigh add " IP4_SRC " dev src_fwd lladdr %s", src_addr); + SYS(fail, "ip neigh add " IP6_SRC " dev src_fwd lladdr %s", src_addr); + SYS(fail, "ip neigh add " IP4_DST " dev dst_fwd lladdr %s", MAC_DST); + SYS(fail, "ip neigh add " IP6_DST " dev dst_fwd lladdr %s", MAC_DST); + } + close_netns(nstoken); /** setup in 'dst' namespace */ From ce6f6cffaeaa0a3bcdafcae7fe03c68c3afae631 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 19 Jan 2024 22:05:18 -0800 Subject: [PATCH 0262/2255] selftests/bpf: Wait for the netstamp_needed_key static key to be turned on After the previous patch that speeded up the test (by avoiding neigh discovery in IPv6), the BPF CI occasionally hits this error: rcv tstamp unexpected pkt rcv tstamp: actual 0 == expected 0 The test complains about the cmsg returned from the recvmsg() does not have the rcv timestamp. Setting skb->tstamp or not is controlled by a kernel static key "netstamp_needed_key". The static key is enabled whenever this is at least one sk with the SOCK_TIMESTAMP set. The test_redirect_dtime does use setsockopt() to turn on the SOCK_TIMESTAMP for the reading sk. In the kernel net_enable_timestamp() has a delay to enable the "netstamp_needed_key" when CONFIG_JUMP_LABEL is set. This potential delay is the likely reason for packet missing rcv timestamp occasionally. This patch is to create udp sockets with SOCK_TIMESTAMP set. It sends and receives some packets until the received packet has a rcv timestamp. It currently retries at most 5 times with 1s in between. This should be enough to wait for the "netstamp_needed_key". It then holds on to the socket and only closes it at the end of the test. This guarantees that the test has the "netstamp_needed_key" key turned on from the beginning. To simplify the udp sockets setup, they are sending/receiving packets in the same netns (ns_dst is used) and communicate over the "lo" dev. Hence, the patch enables the "lo" dev in the ns_dst. Fixes: c803475fd8dd ("bpf: selftests: test skb->tstamp in redirect_neigh") Signed-off-by: Martin KaFai Lau Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240120060518.3604920-2-martin.lau@linux.dev --- .../selftests/bpf/prog_tests/tc_redirect.c | 79 ++++++++++++++++++- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c index 610887157fd8..dbe06aeaa2b2 100644 --- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c +++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c @@ -291,6 +291,7 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) SYS(fail, "ip addr add " IP4_DST "/32 dev dst"); SYS(fail, "ip addr add " IP6_DST "/128 dev dst nodad"); SYS(fail, "ip link set dev dst up"); + SYS(fail, "ip link set dev lo up"); SYS(fail, "ip route add " IP4_SRC "/32 dev dst scope global"); SYS(fail, "ip route add " IP4_NET "/16 dev dst scope global"); @@ -468,7 +469,7 @@ static int set_forwarding(bool enable) return 0; } -static void rcv_tstamp(int fd, const char *expected, size_t s) +static int __rcv_tstamp(int fd, const char *expected, size_t s, __u64 *tstamp) { struct __kernel_timespec pkt_ts = {}; char ctl[CMSG_SPACE(sizeof(pkt_ts))]; @@ -489,7 +490,7 @@ static void rcv_tstamp(int fd, const char *expected, size_t s) ret = recvmsg(fd, &msg, 0); if (!ASSERT_EQ(ret, s, "recvmsg")) - return; + return -1; ASSERT_STRNEQ(data, expected, s, "expected rcv data"); cmsg = CMSG_FIRSTHDR(&msg); @@ -498,6 +499,12 @@ static void rcv_tstamp(int fd, const char *expected, size_t s) memcpy(&pkt_ts, CMSG_DATA(cmsg), sizeof(pkt_ts)); pkt_ns = pkt_ts.tv_sec * NSEC_PER_SEC + pkt_ts.tv_nsec; + if (tstamp) { + /* caller will check the tstamp itself */ + *tstamp = pkt_ns; + return 0; + } + ASSERT_NEQ(pkt_ns, 0, "pkt rcv tstamp"); ret = clock_gettime(CLOCK_REALTIME, &now_ts); @@ -507,6 +514,60 @@ static void rcv_tstamp(int fd, const char *expected, size_t s) if (ASSERT_GE(now_ns, pkt_ns, "check rcv tstamp")) ASSERT_LT(now_ns - pkt_ns, 5 * NSEC_PER_SEC, "check rcv tstamp"); + return 0; +} + +static void rcv_tstamp(int fd, const char *expected, size_t s) +{ + __rcv_tstamp(fd, expected, s, NULL); +} + +static int wait_netstamp_needed_key(void) +{ + int opt = 1, srv_fd = -1, cli_fd = -1, nretries = 0, err, n; + char buf[] = "testing testing"; + struct nstoken *nstoken; + __u64 tstamp = 0; + + nstoken = open_netns(NS_DST); + if (!nstoken) + return -1; + + srv_fd = start_server(AF_INET6, SOCK_DGRAM, "::1", 0, 0); + if (!ASSERT_GE(srv_fd, 0, "start_server")) + goto done; + + err = setsockopt(srv_fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW, + &opt, sizeof(opt)); + if (!ASSERT_OK(err, "setsockopt(SO_TIMESTAMPNS_NEW)")) + goto done; + + cli_fd = connect_to_fd(srv_fd, TIMEOUT_MILLIS); + if (!ASSERT_GE(cli_fd, 0, "connect_to_fd")) + goto done; + +again: + n = write(cli_fd, buf, sizeof(buf)); + if (!ASSERT_EQ(n, sizeof(buf), "send to server")) + goto done; + err = __rcv_tstamp(srv_fd, buf, sizeof(buf), &tstamp); + if (!ASSERT_OK(err, "__rcv_tstamp")) + goto done; + if (!tstamp && nretries++ < 5) { + sleep(1); + printf("netstamp_needed_key retry#%d\n", nretries); + goto again; + } + +done: + if (!tstamp && srv_fd != -1) { + close(srv_fd); + srv_fd = -1; + } + if (cli_fd != -1) + close(cli_fd); + close_netns(nstoken); + return srv_fd; } static void snd_tstamp(int fd, char *b, size_t s) @@ -843,11 +904,20 @@ static void test_tc_redirect_dtime(struct netns_setup_result *setup_result) { struct test_tc_dtime *skel; struct nstoken *nstoken; - int err; + int hold_tstamp_fd, err; + + /* Hold a sk with the SOCK_TIMESTAMP set to ensure there + * is no delay in the kernel net_enable_timestamp(). + * This ensures the following tests must have + * non zero rcv tstamp in the recvmsg(). + */ + hold_tstamp_fd = wait_netstamp_needed_key(); + if (!ASSERT_GE(hold_tstamp_fd, 0, "wait_netstamp_needed_key")) + return; skel = test_tc_dtime__open(); if (!ASSERT_OK_PTR(skel, "test_tc_dtime__open")) - return; + goto done; skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd; skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd; @@ -892,6 +962,7 @@ static void test_tc_redirect_dtime(struct netns_setup_result *setup_result) done: test_tc_dtime__destroy(skel); + close(hold_tstamp_fd); } static void test_tc_redirect_neigh_fib(struct netns_setup_result *setup_result) From c9f115564561af63db662791e9a35fcf1dfefd2a Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Wed, 24 Jan 2024 14:44:18 -0800 Subject: [PATCH 0263/2255] libbpf: Ensure undefined bpf_attr field stays 0 The commit 9e926acda0c2 ("libbpf: Find correct module BTFs for struct_ops maps and progs.") sets a newly added field (value_type_btf_obj_fd) to -1 in libbpf when the caller of the libbpf's bpf_map_create did not define this field by passing a NULL "opts" or passing in a "opts" that does not cover this new field. OPT_HAS(opts, field) is used to decide if the field is defined or not: ((opts) && opts->sz >= offsetofend(typeof(*(opts)), field)) Once OPTS_HAS decided the field is not defined, that field should be set to 0. For this particular new field (value_type_btf_obj_fd), its corresponding map_flags "BPF_F_VTYPE_BTF_OBJ_FD" is not set. Thus, the kernel does not treat it as an fd field. Fixes: 9e926acda0c2 ("libbpf: Find correct module BTFs for struct_ops maps and progs.") Reported-by: Andrii Nakryiko Signed-off-by: Martin KaFai Lau Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240124224418.2905133-1-martin.lau@linux.dev Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 3a35472a17c5..b133acfe08fb 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -192,7 +192,7 @@ int bpf_map_create(enum bpf_map_type map_type, attr.btf_key_type_id = OPTS_GET(opts, btf_key_type_id, 0); attr.btf_value_type_id = OPTS_GET(opts, btf_value_type_id, 0); attr.btf_vmlinux_value_type_id = OPTS_GET(opts, btf_vmlinux_value_type_id, 0); - attr.value_type_btf_obj_fd = OPTS_GET(opts, value_type_btf_obj_fd, -1); + attr.value_type_btf_obj_fd = OPTS_GET(opts, value_type_btf_obj_fd, 0); attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0); attr.map_flags = OPTS_GET(opts, map_flags, 0); From ed1ad5a7415de8be121055e7ab1303d2be5407e0 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:20:58 -0800 Subject: [PATCH 0264/2255] bpf: Align CAP_NET_ADMIN checks with bpf_capable() approach Within BPF syscall handling code CAP_NET_ADMIN checks stand out a bit compared to CAP_BPF and CAP_PERFMON checks. For the latter, CAP_BPF or CAP_PERFMON are checked first, but if they are not set, CAP_SYS_ADMIN takes over and grants whatever part of BPF syscall is required. Similar kind of checks that involve CAP_NET_ADMIN are not so consistent. One out of four uses does follow CAP_BPF/CAP_PERFMON model: during BPF_PROG_LOAD, if the type of BPF program is "network-related" either CAP_NET_ADMIN or CAP_SYS_ADMIN is required to proceed. But in three other cases CAP_NET_ADMIN is required even if CAP_SYS_ADMIN is set: - when creating DEVMAP/XDKMAP/CPU_MAP maps; - when attaching CGROUP_SKB programs; - when handling BPF_PROG_QUERY command. This patch is changing the latter three cases to follow BPF_PROG_LOAD model, that is allowing to proceed under either CAP_NET_ADMIN or CAP_SYS_ADMIN. This also makes it cleaner in subsequent BPF token patches to switch wholesomely to a generic bpf_token_capable(int cap) check, that always falls back to CAP_SYS_ADMIN if requested capability is missing. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: Yafang Shao Link: https://lore.kernel.org/bpf/20240124022127.2379740-2-andrii@kernel.org --- kernel/bpf/syscall.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f8124b3229e2..d5f1edee2d50 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1123,6 +1123,11 @@ free_map_tab: return ret; } +static bool bpf_net_capable(void) +{ + return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); +} + #define BPF_MAP_CREATE_LAST_FIELD value_type_btf_obj_fd /* called via syscall */ static int map_create(union bpf_attr *attr) @@ -1226,7 +1231,7 @@ static int map_create(union bpf_attr *attr) case BPF_MAP_TYPE_DEVMAP: case BPF_MAP_TYPE_DEVMAP_HASH: case BPF_MAP_TYPE_XSKMAP: - if (!capable(CAP_NET_ADMIN)) + if (!bpf_net_capable()) return -EPERM; break; default: @@ -2636,7 +2641,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) !bpf_capable()) return -EPERM; - if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) + if (is_net_admin_prog_type(type) && !bpf_net_capable()) return -EPERM; if (is_perfmon_prog_type(type) && !perfmon_capable()) return -EPERM; @@ -3822,7 +3827,7 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, case BPF_PROG_TYPE_SK_LOOKUP: return attach_type == prog->expected_attach_type ? 0 : -EINVAL; case BPF_PROG_TYPE_CGROUP_SKB: - if (!capable(CAP_NET_ADMIN)) + if (!bpf_net_capable()) /* cg-skb progs can be loaded by unpriv user. * check permissions at attach time. */ @@ -4025,7 +4030,7 @@ static int bpf_prog_detach(const union bpf_attr *attr) static int bpf_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) { - if (!capable(CAP_NET_ADMIN)) + if (!bpf_net_capable()) return -EPERM; if (CHECK_ATTR(BPF_PROG_QUERY)) return -EINVAL; From 6fe01d3cbb924a72493eb3f4722dfcfd1c194234 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:20:59 -0800 Subject: [PATCH 0265/2255] bpf: Add BPF token delegation mount options to BPF FS Add few new mount options to BPF FS that allow to specify that a given BPF FS instance allows creation of BPF token (added in the next patch), and what sort of operations are allowed under BPF token. As such, we get 4 new mount options, each is a bit mask - `delegate_cmds` allow to specify which bpf() syscall commands are allowed with BPF token derived from this BPF FS instance; - if BPF_MAP_CREATE command is allowed, `delegate_maps` specifies a set of allowable BPF map types that could be created with BPF token; - if BPF_PROG_LOAD command is allowed, `delegate_progs` specifies a set of allowable BPF program types that could be loaded with BPF token; - if BPF_PROG_LOAD command is allowed, `delegate_attachs` specifies a set of allowable BPF program attach types that could be loaded with BPF token; delegate_progs and delegate_attachs are meant to be used together, as full BPF program type is, in general, determined through both program type and program attach type. Currently, these mount options accept the following forms of values: - a special value "any", that enables all possible values of a given bit set; - numeric value (decimal or hexadecimal, determined by kernel automatically) that specifies a bit mask value directly; - all the values for a given mount option are combined, if specified multiple times. E.g., `mount -t bpf nodev /path/to/mount -o delegate_maps=0x1 -o delegate_maps=0x2` will result in a combined 0x3 mask. Ideally, more convenient (for humans) symbolic form derived from corresponding UAPI enums would be accepted (e.g., `-o delegate_progs=kprobe|tracepoint`) and I intend to implement this, but it requires a bunch of UAPI header churn, so I postponed it until this feature lands upstream or at least there is a definite consensus that this feature is acceptable and is going to make it, just to minimize amount of wasted effort and not increase amount of non-essential code to be reviewed. Attentive reader will notice that BPF FS is now marked as FS_USERNS_MOUNT, which theoretically makes it mountable inside non-init user namespace as long as the process has sufficient *namespaced* capabilities within that user namespace. But in reality we still restrict BPF FS to be mountable only by processes with CAP_SYS_ADMIN *in init userns* (extra check in bpf_fill_super()). FS_USERNS_MOUNT is added to allow creating BPF FS context object (i.e., fsopen("bpf")) from inside unprivileged process inside non-init userns, to capture that userns as the owning userns. It will still be required to pass this context object back to privileged process to instantiate and mount it. This manipulation is important, because capturing non-init userns as the owning userns of BPF FS instance (super block) allows to use that userns to constraint BPF token to that userns later on (see next patch). So creating BPF FS with delegation inside unprivileged userns will restrict derived BPF token objects to only "work" inside that intended userns, making it scoped to a intended "container". Also, setting these delegation options requires capable(CAP_SYS_ADMIN), so unprivileged process cannot set this up without involvement of a privileged process. There is a set of selftests at the end of the patch set that simulates this sequence of steps and validates that everything works as intended. But careful review is requested to make sure there are no missed gaps in the implementation and testing. This somewhat subtle set of aspects is the result of previous discussions ([0]) about various user namespace implications and interactions with BPF token functionality and is necessary to contain BPF token inside intended user namespace. [0] https://lore.kernel.org/bpf/20230704-hochverdient-lehne-eeb9eeef785e@brauner/ Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: Christian Brauner Link: https://lore.kernel.org/bpf/20240124022127.2379740-3-andrii@kernel.org --- include/linux/bpf.h | 12 ++++++ kernel/bpf/inode.c | 90 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 90 insertions(+), 12 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 75b7f9b19c6a..28374cec49df 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1609,6 +1609,18 @@ struct bpf_link_primer { u32 id; }; +struct bpf_mount_opts { + kuid_t uid; + kgid_t gid; + umode_t mode; + + /* BPF token-related delegation options */ + u64 delegate_cmds; + u64 delegate_maps; + u64 delegate_progs; + u64 delegate_attachs; +}; + struct bpf_struct_ops_value; struct btf_member; diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 41e0a55c35f5..70b748f6228c 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "preload/bpf_preload.h" enum bpf_type { @@ -601,6 +602,7 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) { struct inode *inode = d_inode(root); umode_t mode = inode->i_mode & S_IALLUGO & ~S_ISVTX; + struct bpf_mount_opts *opts = root->d_sb->s_fs_info; if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID)) seq_printf(m, ",uid=%u", @@ -610,6 +612,26 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) from_kgid_munged(&init_user_ns, inode->i_gid)); if (mode != S_IRWXUGO) seq_printf(m, ",mode=%o", mode); + + if (opts->delegate_cmds == ~0ULL) + seq_printf(m, ",delegate_cmds=any"); + else if (opts->delegate_cmds) + seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); + + if (opts->delegate_maps == ~0ULL) + seq_printf(m, ",delegate_maps=any"); + else if (opts->delegate_maps) + seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); + + if (opts->delegate_progs == ~0ULL) + seq_printf(m, ",delegate_progs=any"); + else if (opts->delegate_progs) + seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs); + + if (opts->delegate_attachs == ~0ULL) + seq_printf(m, ",delegate_attachs=any"); + else if (opts->delegate_attachs) + seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs); return 0; } @@ -635,28 +657,31 @@ enum { OPT_UID, OPT_GID, OPT_MODE, + OPT_DELEGATE_CMDS, + OPT_DELEGATE_MAPS, + OPT_DELEGATE_PROGS, + OPT_DELEGATE_ATTACHS, }; static const struct fs_parameter_spec bpf_fs_parameters[] = { fsparam_u32 ("uid", OPT_UID), fsparam_u32 ("gid", OPT_GID), fsparam_u32oct ("mode", OPT_MODE), + fsparam_string ("delegate_cmds", OPT_DELEGATE_CMDS), + fsparam_string ("delegate_maps", OPT_DELEGATE_MAPS), + fsparam_string ("delegate_progs", OPT_DELEGATE_PROGS), + fsparam_string ("delegate_attachs", OPT_DELEGATE_ATTACHS), {} }; -struct bpf_mount_opts { - kuid_t uid; - kgid_t gid; - umode_t mode; -}; - static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) { - struct bpf_mount_opts *opts = fc->fs_private; + struct bpf_mount_opts *opts = fc->s_fs_info; struct fs_parse_result result; kuid_t uid; kgid_t gid; - int opt; + int opt, err; + u64 msk; opt = fs_parse(fc, bpf_fs_parameters, param, &result); if (opt < 0) { @@ -708,6 +733,28 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) case OPT_MODE: opts->mode = result.uint_32 & S_IALLUGO; break; + case OPT_DELEGATE_CMDS: + case OPT_DELEGATE_MAPS: + case OPT_DELEGATE_PROGS: + case OPT_DELEGATE_ATTACHS: + if (strcmp(param->string, "any") == 0) { + msk = ~0ULL; + } else { + err = kstrtou64(param->string, 0, &msk); + if (err) + return err; + } + /* Setting delegation mount options requires privileges */ + if (msk && !capable(CAP_SYS_ADMIN)) + return -EPERM; + switch (opt) { + case OPT_DELEGATE_CMDS: opts->delegate_cmds |= msk; break; + case OPT_DELEGATE_MAPS: opts->delegate_maps |= msk; break; + case OPT_DELEGATE_PROGS: opts->delegate_progs |= msk; break; + case OPT_DELEGATE_ATTACHS: opts->delegate_attachs |= msk; break; + default: return -EINVAL; + } + break; } return 0; @@ -784,10 +831,14 @@ out: static int bpf_fill_super(struct super_block *sb, struct fs_context *fc) { static const struct tree_descr bpf_rfiles[] = { { "" } }; - struct bpf_mount_opts *opts = fc->fs_private; + struct bpf_mount_opts *opts = sb->s_fs_info; struct inode *inode; int ret; + /* Mounting an instance of BPF FS requires privileges */ + if (fc->user_ns != &init_user_ns && !capable(CAP_SYS_ADMIN)) + return -EPERM; + ret = simple_fill_super(sb, BPF_FS_MAGIC, bpf_rfiles); if (ret) return ret; @@ -811,7 +862,7 @@ static int bpf_get_tree(struct fs_context *fc) static void bpf_free_fc(struct fs_context *fc) { - kfree(fc->fs_private); + kfree(fc->s_fs_info); } static const struct fs_context_operations bpf_context_ops = { @@ -835,17 +886,32 @@ static int bpf_init_fs_context(struct fs_context *fc) opts->uid = current_fsuid(); opts->gid = current_fsgid(); - fc->fs_private = opts; + /* start out with no BPF token delegation enabled */ + opts->delegate_cmds = 0; + opts->delegate_maps = 0; + opts->delegate_progs = 0; + opts->delegate_attachs = 0; + + fc->s_fs_info = opts; fc->ops = &bpf_context_ops; return 0; } +static void bpf_kill_super(struct super_block *sb) +{ + struct bpf_mount_opts *opts = sb->s_fs_info; + + kill_litter_super(sb); + kfree(opts); +} + static struct file_system_type bpf_fs_type = { .owner = THIS_MODULE, .name = "bpf", .init_fs_context = bpf_init_fs_context, .parameters = bpf_fs_parameters, - .kill_sb = kill_litter_super, + .kill_sb = bpf_kill_super, + .fs_flags = FS_USERNS_MOUNT, }; static int __init bpf_init(void) From 35f96de04127d332a5c5e8a155d31f452f88c76d Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:00 -0800 Subject: [PATCH 0266/2255] bpf: Introduce BPF token object Add new kind of BPF kernel object, BPF token. BPF token is meant to allow delegating privileged BPF functionality, like loading a BPF program or creating a BPF map, from privileged process to a *trusted* unprivileged process, all while having a good amount of control over which privileged operations could be performed using provided BPF token. This is achieved through mounting BPF FS instance with extra delegation mount options, which determine what operations are delegatable, and also constraining it to the owning user namespace (as mentioned in the previous patch). BPF token itself is just a derivative from BPF FS and can be created through a new bpf() syscall command, BPF_TOKEN_CREATE, which accepts BPF FS FD, which can be attained through open() API by opening BPF FS mount point. Currently, BPF token "inherits" delegated command, map types, prog type, and attach type bit sets from BPF FS as is. In the future, having an BPF token as a separate object with its own FD, we can allow to further restrict BPF token's allowable set of things either at the creation time or after the fact, allowing the process to guard itself further from unintentionally trying to load undesired kind of BPF programs. But for now we keep things simple and just copy bit sets as is. When BPF token is created from BPF FS mount, we take reference to the BPF super block's owning user namespace, and then use that namespace for checking all the {CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN} capabilities that are normally only checked against init userns (using capable()), but now we check them using ns_capable() instead (if BPF token is provided). See bpf_token_capable() for details. Such setup means that BPF token in itself is not sufficient to grant BPF functionality. User namespaced process has to *also* have necessary combination of capabilities inside that user namespace. So while previously CAP_BPF was useless when granted within user namespace, now it gains a meaning and allows container managers and sys admins to have a flexible control over which processes can and need to use BPF functionality within the user namespace (i.e., container in practice). And BPF FS delegation mount options and derived BPF tokens serve as a per-container "flag" to grant overall ability to use bpf() (plus further restrict on which parts of bpf() syscalls are treated as namespaced). Note also, BPF_TOKEN_CREATE command itself requires ns_capable(CAP_BPF) within the BPF FS owning user namespace, rounding up the ns_capable() story of BPF token. Also creating BPF token in init user namespace is currently not supported, given BPF token doesn't have any effect in init user namespace anyways. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: Christian Brauner Link: https://lore.kernel.org/bpf/20240124022127.2379740-4-andrii@kernel.org --- include/linux/bpf.h | 41 +++++++ include/uapi/linux/bpf.h | 37 ++++++ kernel/bpf/Makefile | 2 +- kernel/bpf/inode.c | 12 +- kernel/bpf/syscall.c | 17 +++ kernel/bpf/token.c | 217 +++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 37 ++++++ 7 files changed, 357 insertions(+), 6 deletions(-) create mode 100644 kernel/bpf/token.c diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 28374cec49df..d9ff7ce547b4 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -52,6 +52,10 @@ struct module; struct bpf_func_state; struct ftrace_ops; struct cgroup; +struct bpf_token; +struct user_namespace; +struct super_block; +struct inode; extern struct idr btf_idr; extern spinlock_t btf_idr_lock; @@ -1621,6 +1625,13 @@ struct bpf_mount_opts { u64 delegate_attachs; }; +struct bpf_token { + struct work_struct work; + atomic64_t refcnt; + struct user_namespace *userns; + u64 allowed_cmds; +}; + struct bpf_struct_ops_value; struct btf_member; @@ -2109,6 +2120,7 @@ static inline void bpf_enable_instrumentation(void) migrate_enable(); } +extern const struct super_operations bpf_super_ops; extern const struct file_operations bpf_map_fops; extern const struct file_operations bpf_prog_fops; extern const struct file_operations bpf_iter_fops; @@ -2243,6 +2255,8 @@ static inline void bpf_map_dec_elem_count(struct bpf_map *map) extern int sysctl_unprivileged_bpf_disabled; +bool bpf_token_capable(const struct bpf_token *token, int cap); + static inline bool bpf_allow_ptr_leaks(void) { return perfmon_capable(); @@ -2277,8 +2291,17 @@ int bpf_link_new_fd(struct bpf_link *link); struct bpf_link *bpf_link_get_from_fd(u32 ufd); struct bpf_link *bpf_link_get_curr_or_next(u32 *id); +void bpf_token_inc(struct bpf_token *token); +void bpf_token_put(struct bpf_token *token); +int bpf_token_create(union bpf_attr *attr); +struct bpf_token *bpf_token_get_from_fd(u32 ufd); + +bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd); + int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname); int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags); +struct inode *bpf_get_inode(struct super_block *sb, const struct inode *dir, + umode_t mode); #define BPF_ITER_FUNC_PREFIX "bpf_iter_" #define DEFINE_BPF_ITER_FUNC(target, args...) \ @@ -2638,6 +2661,24 @@ static inline int bpf_obj_get_user(const char __user *pathname, int flags) return -EOPNOTSUPP; } +static inline bool bpf_token_capable(const struct bpf_token *token, int cap) +{ + return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN)); +} + +static inline void bpf_token_inc(struct bpf_token *token) +{ +} + +static inline void bpf_token_put(struct bpf_token *token) +{ +} + +static inline struct bpf_token *bpf_token_get_from_fd(u32 ufd) +{ + return ERR_PTR(-EOPNOTSUPP); +} + static inline void __dev_flush(void) { } diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 1fef6d5a1330..b9dc0cca172c 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -847,6 +847,36 @@ union bpf_iter_link_info { * Returns zero on success. On error, -1 is returned and *errno* * is set appropriately. * + * BPF_TOKEN_CREATE + * Description + * Create BPF token with embedded information about what + * BPF-related functionality it allows: + * - a set of allowed bpf() syscall commands; + * - a set of allowed BPF map types to be created with + * BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed; + * - a set of allowed BPF program types and BPF program attach + * types to be loaded with BPF_PROG_LOAD command, if + * BPF_PROG_LOAD itself is allowed. + * + * BPF token is created (derived) from an instance of BPF FS, + * assuming it has necessary delegation mount options specified. + * This BPF token can be passed as an extra parameter to various + * bpf() syscall commands to grant BPF subsystem functionality to + * unprivileged processes. + * + * When created, BPF token is "associated" with the owning + * user namespace of BPF FS instance (super block) that it was + * derived from, and subsequent BPF operations performed with + * BPF token would be performing capabilities checks (i.e., + * CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within + * that user namespace. Without BPF token, such capabilities + * have to be granted in init user namespace, making bpf() + * syscall incompatible with user namespace, for the most part. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * * NOTES * eBPF objects (maps and programs) can be shared between processes. * @@ -901,6 +931,8 @@ enum bpf_cmd { BPF_ITER_CREATE, BPF_LINK_DETACH, BPF_PROG_BIND_MAP, + BPF_TOKEN_CREATE, + __MAX_BPF_CMD, }; enum bpf_map_type { @@ -1722,6 +1754,11 @@ union bpf_attr { __u32 flags; /* extra flags */ } prog_bind_map; + struct { /* struct used by BPF_TOKEN_CREATE command */ + __u32 flags; + __u32 bpffs_fd; + } token_create; + } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile index f526b7573e97..4ce95acfcaa7 100644 --- a/kernel/bpf/Makefile +++ b/kernel/bpf/Makefile @@ -6,7 +6,7 @@ cflags-nogcse-$(CONFIG_X86)$(CONFIG_CC_IS_GCC) := -fno-gcse endif CFLAGS_core.o += $(call cc-disable-warning, override-init) $(cflags-nogcse-yy) -obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o +obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 70b748f6228c..565be1f3f1ea 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -99,9 +99,9 @@ static const struct inode_operations bpf_prog_iops = { }; static const struct inode_operations bpf_map_iops = { }; static const struct inode_operations bpf_link_iops = { }; -static struct inode *bpf_get_inode(struct super_block *sb, - const struct inode *dir, - umode_t mode) +struct inode *bpf_get_inode(struct super_block *sb, + const struct inode *dir, + umode_t mode) { struct inode *inode; @@ -603,6 +603,7 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) struct inode *inode = d_inode(root); umode_t mode = inode->i_mode & S_IALLUGO & ~S_ISVTX; struct bpf_mount_opts *opts = root->d_sb->s_fs_info; + u64 mask; if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID)) seq_printf(m, ",uid=%u", @@ -613,7 +614,8 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) if (mode != S_IRWXUGO) seq_printf(m, ",mode=%o", mode); - if (opts->delegate_cmds == ~0ULL) + mask = (1ULL << __MAX_BPF_CMD) - 1; + if ((opts->delegate_cmds & mask) == mask) seq_printf(m, ",delegate_cmds=any"); else if (opts->delegate_cmds) seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); @@ -646,7 +648,7 @@ static void bpf_free_inode(struct inode *inode) free_inode_nonrcu(inode); } -static const struct super_operations bpf_super_ops = { +const struct super_operations bpf_super_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .show_options = bpf_show_options, diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d5f1edee2d50..3ecba592b8ed 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -5426,6 +5426,20 @@ out_prog_put: return ret; } +#define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd + +static int token_create(union bpf_attr *attr) +{ + if (CHECK_ATTR(BPF_TOKEN_CREATE)) + return -EINVAL; + + /* no flags are supported yet */ + if (attr->token_create.flags) + return -EINVAL; + + return bpf_token_create(attr); +} + static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) { union bpf_attr attr; @@ -5559,6 +5573,9 @@ static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) case BPF_PROG_BIND_MAP: err = bpf_prog_bind_map(&attr); break; + case BPF_TOKEN_CREATE: + err = token_create(&attr); + break; default: err = -EINVAL; break; diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c new file mode 100644 index 000000000000..bdb6fe697568 --- /dev/null +++ b/kernel/bpf/token.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool bpf_ns_capable(struct user_namespace *ns, int cap) +{ + return ns_capable(ns, cap) || (cap != CAP_SYS_ADMIN && ns_capable(ns, CAP_SYS_ADMIN)); +} + +bool bpf_token_capable(const struct bpf_token *token, int cap) +{ + struct user_namespace *userns; + + /* BPF token allows ns_capable() level of capabilities */ + userns = token ? token->userns : &init_user_ns; + if (!bpf_ns_capable(userns, cap)) + return false; + return true; +} + +void bpf_token_inc(struct bpf_token *token) +{ + atomic64_inc(&token->refcnt); +} + +static void bpf_token_free(struct bpf_token *token) +{ + put_user_ns(token->userns); + kfree(token); +} + +static void bpf_token_put_deferred(struct work_struct *work) +{ + struct bpf_token *token = container_of(work, struct bpf_token, work); + + bpf_token_free(token); +} + +void bpf_token_put(struct bpf_token *token) +{ + if (!token) + return; + + if (!atomic64_dec_and_test(&token->refcnt)) + return; + + INIT_WORK(&token->work, bpf_token_put_deferred); + schedule_work(&token->work); +} + +static int bpf_token_release(struct inode *inode, struct file *filp) +{ + struct bpf_token *token = filp->private_data; + + bpf_token_put(token); + return 0; +} + +static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp) +{ + struct bpf_token *token = filp->private_data; + u64 mask; + + BUILD_BUG_ON(__MAX_BPF_CMD >= 64); + mask = (1ULL << __MAX_BPF_CMD) - 1; + if ((token->allowed_cmds & mask) == mask) + seq_printf(m, "allowed_cmds:\tany\n"); + else + seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds); +} + +#define BPF_TOKEN_INODE_NAME "bpf-token" + +static const struct inode_operations bpf_token_iops = { }; + +static const struct file_operations bpf_token_fops = { + .release = bpf_token_release, + .show_fdinfo = bpf_token_show_fdinfo, +}; + +int bpf_token_create(union bpf_attr *attr) +{ + struct bpf_mount_opts *mnt_opts; + struct bpf_token *token = NULL; + struct user_namespace *userns; + struct inode *inode; + struct file *file; + struct path path; + struct fd f; + umode_t mode; + int err, fd; + + f = fdget(attr->token_create.bpffs_fd); + if (!f.file) + return -EBADF; + + path = f.file->f_path; + path_get(&path); + fdput(f); + + if (path.dentry != path.mnt->mnt_sb->s_root) { + err = -EINVAL; + goto out_path; + } + if (path.mnt->mnt_sb->s_op != &bpf_super_ops) { + err = -EINVAL; + goto out_path; + } + err = path_permission(&path, MAY_ACCESS); + if (err) + goto out_path; + + userns = path.dentry->d_sb->s_user_ns; + /* + * Enforce that creators of BPF tokens are in the same user + * namespace as the BPF FS instance. This makes reasoning about + * permissions a lot easier and we can always relax this later. + */ + if (current_user_ns() != userns) { + err = -EPERM; + goto out_path; + } + if (!ns_capable(userns, CAP_BPF)) { + err = -EPERM; + goto out_path; + } + + /* Creating BPF token in init_user_ns doesn't make much sense. */ + if (current_user_ns() == &init_user_ns) { + err = -EOPNOTSUPP; + goto out_path; + } + + mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask()); + inode = bpf_get_inode(path.mnt->mnt_sb, NULL, mode); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out_path; + } + + inode->i_op = &bpf_token_iops; + inode->i_fop = &bpf_token_fops; + clear_nlink(inode); /* make sure it is unlinked */ + + file = alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME, O_RDWR, &bpf_token_fops); + if (IS_ERR(file)) { + iput(inode); + err = PTR_ERR(file); + goto out_path; + } + + token = kzalloc(sizeof(*token), GFP_USER); + if (!token) { + err = -ENOMEM; + goto out_file; + } + + atomic64_set(&token->refcnt, 1); + + /* remember bpffs owning userns for future ns_capable() checks */ + token->userns = get_user_ns(userns); + + mnt_opts = path.dentry->d_sb->s_fs_info; + token->allowed_cmds = mnt_opts->delegate_cmds; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + err = fd; + goto out_token; + } + + file->private_data = token; + fd_install(fd, file); + + path_put(&path); + return fd; + +out_token: + bpf_token_free(token); +out_file: + fput(file); +out_path: + path_put(&path); + return err; +} + +struct bpf_token *bpf_token_get_from_fd(u32 ufd) +{ + struct fd f = fdget(ufd); + struct bpf_token *token; + + if (!f.file) + return ERR_PTR(-EBADF); + if (f.file->f_op != &bpf_token_fops) { + fdput(f); + return ERR_PTR(-EINVAL); + } + + token = f.file->private_data; + bpf_token_inc(token); + fdput(f); + + return token; +} + +bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd) +{ + if (!token) + return false; + return token->allowed_cmds & (1ULL << cmd); +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 1fef6d5a1330..b9dc0cca172c 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -847,6 +847,36 @@ union bpf_iter_link_info { * Returns zero on success. On error, -1 is returned and *errno* * is set appropriately. * + * BPF_TOKEN_CREATE + * Description + * Create BPF token with embedded information about what + * BPF-related functionality it allows: + * - a set of allowed bpf() syscall commands; + * - a set of allowed BPF map types to be created with + * BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed; + * - a set of allowed BPF program types and BPF program attach + * types to be loaded with BPF_PROG_LOAD command, if + * BPF_PROG_LOAD itself is allowed. + * + * BPF token is created (derived) from an instance of BPF FS, + * assuming it has necessary delegation mount options specified. + * This BPF token can be passed as an extra parameter to various + * bpf() syscall commands to grant BPF subsystem functionality to + * unprivileged processes. + * + * When created, BPF token is "associated" with the owning + * user namespace of BPF FS instance (super block) that it was + * derived from, and subsequent BPF operations performed with + * BPF token would be performing capabilities checks (i.e., + * CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within + * that user namespace. Without BPF token, such capabilities + * have to be granted in init user namespace, making bpf() + * syscall incompatible with user namespace, for the most part. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * * NOTES * eBPF objects (maps and programs) can be shared between processes. * @@ -901,6 +931,8 @@ enum bpf_cmd { BPF_ITER_CREATE, BPF_LINK_DETACH, BPF_PROG_BIND_MAP, + BPF_TOKEN_CREATE, + __MAX_BPF_CMD, }; enum bpf_map_type { @@ -1722,6 +1754,11 @@ union bpf_attr { __u32 flags; /* extra flags */ } prog_bind_map; + struct { /* struct used by BPF_TOKEN_CREATE command */ + __u32 flags; + __u32 bpffs_fd; + } token_create; + } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF From a177fc2bf6fd83704854feaf7aae926b1df4f0b9 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:01 -0800 Subject: [PATCH 0267/2255] bpf: Add BPF token support to BPF_MAP_CREATE command Allow providing token_fd for BPF_MAP_CREATE command to allow controlled BPF map creation from unprivileged process through delegated BPF token. New BPF_F_TOKEN_FD flag is added to specify together with BPF token FD for BPF_MAP_CREATE command. Wire through a set of allowed BPF map types to BPF token, derived from BPF FS at BPF token creation time. This, in combination with allowed_cmds allows to create a narrowly-focused BPF token (controlled by privileged agent) with a restrictive set of BPF maps that application can attempt to create. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-5-andrii@kernel.org --- include/linux/bpf.h | 2 + include/uapi/linux/bpf.h | 8 +++ kernel/bpf/inode.c | 3 +- kernel/bpf/syscall.c | 59 ++++++++++++++----- kernel/bpf/token.c | 16 +++++ tools/include/uapi/linux/bpf.h | 8 +++ .../selftests/bpf/prog_tests/libbpf_probes.c | 2 + .../selftests/bpf/prog_tests/libbpf_str.c | 3 + 8 files changed, 86 insertions(+), 15 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index d9ff7ce547b4..8252452d0c4d 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1630,6 +1630,7 @@ struct bpf_token { atomic64_t refcnt; struct user_namespace *userns; u64 allowed_cmds; + u64 allowed_maps; }; struct bpf_struct_ops_value; @@ -2297,6 +2298,7 @@ int bpf_token_create(union bpf_attr *attr); struct bpf_token *bpf_token_get_from_fd(u32 ufd); bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd); +bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type); int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname); int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index b9dc0cca172c..c78cab8b462d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -983,6 +983,7 @@ enum bpf_map_type { BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_USER_RINGBUF, BPF_MAP_TYPE_CGRP_STORAGE, + __MAX_BPF_MAP_TYPE }; /* Note that tracing related programs such as @@ -1365,6 +1366,9 @@ enum { /* Flag for value_type_btf_obj_fd, the fd is available */ BPF_F_VTYPE_BTF_OBJ_FD = (1U << 15), + +/* BPF token FD is passed in a corresponding command's token_fd field */ + BPF_F_TOKEN_FD = (1U << 16), }; /* Flags for BPF_PROG_QUERY. */ @@ -1443,6 +1447,10 @@ union bpf_attr { * type data for * btf_vmlinux_value_type_id. */ + /* BPF token FD to use with BPF_MAP_CREATE operation. + * If provided, map_flags should have BPF_F_TOKEN_FD flag set. + */ + __s32 map_token_fd; }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 565be1f3f1ea..034b7e4d8f19 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -620,7 +620,8 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) else if (opts->delegate_cmds) seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); - if (opts->delegate_maps == ~0ULL) + mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; + if ((opts->delegate_maps & mask) == mask) seq_printf(m, ",delegate_maps=any"); else if (opts->delegate_maps) seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 3ecba592b8ed..b13a4bdcd3a0 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1011,8 +1011,8 @@ int map_check_no_btf(const struct bpf_map *map, return -ENOTSUPP; } -static int map_check_btf(struct bpf_map *map, const struct btf *btf, - u32 btf_key_id, u32 btf_value_id) +static int map_check_btf(struct bpf_map *map, struct bpf_token *token, + const struct btf *btf, u32 btf_key_id, u32 btf_value_id) { const struct btf_type *key_type, *value_type; u32 key_size, value_size; @@ -1040,7 +1040,7 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf, if (!IS_ERR_OR_NULL(map->record)) { int i; - if (!bpf_capable()) { + if (!bpf_token_capable(token, CAP_BPF)) { ret = -EPERM; goto free_map_tab; } @@ -1128,14 +1128,16 @@ static bool bpf_net_capable(void) return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); } -#define BPF_MAP_CREATE_LAST_FIELD value_type_btf_obj_fd +#define BPF_MAP_CREATE_LAST_FIELD map_token_fd /* called via syscall */ static int map_create(union bpf_attr *attr) { const struct bpf_map_ops *ops; + struct bpf_token *token = NULL; int numa_node = bpf_map_attr_numa_node(attr); u32 map_type = attr->map_type; struct bpf_map *map; + bool token_flag; int f_flags; int err; @@ -1143,6 +1145,12 @@ static int map_create(union bpf_attr *attr) if (err) return -EINVAL; + /* check BPF_F_TOKEN_FD flag, remember if it's set, and then clear it + * to avoid per-map type checks tripping on unknown flag + */ + token_flag = attr->map_flags & BPF_F_TOKEN_FD; + attr->map_flags &= ~BPF_F_TOKEN_FD; + if (attr->btf_vmlinux_value_type_id) { if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS || attr->btf_key_type_id || attr->btf_value_type_id) @@ -1183,14 +1191,32 @@ static int map_create(union bpf_attr *attr) if (!ops->map_mem_usage) return -EINVAL; + if (token_flag) { + token = bpf_token_get_from_fd(attr->map_token_fd); + if (IS_ERR(token)) + return PTR_ERR(token); + + /* if current token doesn't grant map creation permissions, + * then we can't use this token, so ignore it and rely on + * system-wide capabilities checks + */ + if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) || + !bpf_token_allow_map_type(token, attr->map_type)) { + bpf_token_put(token); + token = NULL; + } + } + + err = -EPERM; + /* Intent here is for unprivileged_bpf_disabled to block BPF map * creation for unprivileged users; other actions depend * on fd availability and access to bpffs, so are dependent on * object creation success. Even with unprivileged BPF disabled, * capability checks are still carried out. */ - if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) - return -EPERM; + if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF)) + goto put_token; /* check privileged map type permissions */ switch (map_type) { @@ -1223,25 +1249,27 @@ static int map_create(union bpf_attr *attr) case BPF_MAP_TYPE_LRU_PERCPU_HASH: case BPF_MAP_TYPE_STRUCT_OPS: case BPF_MAP_TYPE_CPUMAP: - if (!bpf_capable()) - return -EPERM; + if (!bpf_token_capable(token, CAP_BPF)) + goto put_token; break; case BPF_MAP_TYPE_SOCKMAP: case BPF_MAP_TYPE_SOCKHASH: case BPF_MAP_TYPE_DEVMAP: case BPF_MAP_TYPE_DEVMAP_HASH: case BPF_MAP_TYPE_XSKMAP: - if (!bpf_net_capable()) - return -EPERM; + if (!bpf_token_capable(token, CAP_NET_ADMIN)) + goto put_token; break; default: WARN(1, "unsupported map type %d", map_type); - return -EPERM; + goto put_token; } map = ops->map_alloc(attr); - if (IS_ERR(map)) - return PTR_ERR(map); + if (IS_ERR(map)) { + err = PTR_ERR(map); + goto put_token; + } map->ops = ops; map->map_type = map_type; @@ -1278,7 +1306,7 @@ static int map_create(union bpf_attr *attr) map->btf = btf; if (attr->btf_value_type_id) { - err = map_check_btf(map, btf, attr->btf_key_type_id, + err = map_check_btf(map, token, btf, attr->btf_key_type_id, attr->btf_value_type_id); if (err) goto free_map; @@ -1299,6 +1327,7 @@ static int map_create(union bpf_attr *attr) goto free_map_sec; bpf_map_save_memcg(map); + bpf_token_put(token); err = bpf_map_new_fd(map, f_flags); if (err < 0) { @@ -1319,6 +1348,8 @@ free_map_sec: free_map: btf_put(map->btf); map->ops->map_free(map); +put_token: + bpf_token_put(token); return err; } diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index bdb6fe697568..bc86be4ca567 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -73,6 +73,13 @@ static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp) seq_printf(m, "allowed_cmds:\tany\n"); else seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds); + + BUILD_BUG_ON(__MAX_BPF_MAP_TYPE >= 64); + mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; + if ((token->allowed_maps & mask) == mask) + seq_printf(m, "allowed_maps:\tany\n"); + else + seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps); } #define BPF_TOKEN_INODE_NAME "bpf-token" @@ -168,6 +175,7 @@ int bpf_token_create(union bpf_attr *attr) mnt_opts = path.dentry->d_sb->s_fs_info; token->allowed_cmds = mnt_opts->delegate_cmds; + token->allowed_maps = mnt_opts->delegate_maps; fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { @@ -215,3 +223,11 @@ bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd) return false; return token->allowed_cmds & (1ULL << cmd); } + +bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type) +{ + if (!token || type >= __MAX_BPF_MAP_TYPE) + return false; + + return token->allowed_maps & (1ULL << type); +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index b9dc0cca172c..c78cab8b462d 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -983,6 +983,7 @@ enum bpf_map_type { BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_USER_RINGBUF, BPF_MAP_TYPE_CGRP_STORAGE, + __MAX_BPF_MAP_TYPE }; /* Note that tracing related programs such as @@ -1365,6 +1366,9 @@ enum { /* Flag for value_type_btf_obj_fd, the fd is available */ BPF_F_VTYPE_BTF_OBJ_FD = (1U << 15), + +/* BPF token FD is passed in a corresponding command's token_fd field */ + BPF_F_TOKEN_FD = (1U << 16), }; /* Flags for BPF_PROG_QUERY. */ @@ -1443,6 +1447,10 @@ union bpf_attr { * type data for * btf_vmlinux_value_type_id. */ + /* BPF token FD to use with BPF_MAP_CREATE operation. + * If provided, map_flags should have BPF_F_TOKEN_FD flag set. + */ + __s32 map_token_fd; }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c index 9f766ddd946a..573249a2814d 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c @@ -68,6 +68,8 @@ void test_libbpf_probe_map_types(void) if (map_type == BPF_MAP_TYPE_UNSPEC) continue; + if (strcmp(map_type_name, "__MAX_BPF_MAP_TYPE") == 0) + continue; if (!test__start_subtest(map_type_name)) continue; diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c index eb34d612d6f8..1f328c0d8aff 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c @@ -132,6 +132,9 @@ static void test_libbpf_bpf_map_type_str(void) const char *map_type_str; char buf[256]; + if (map_type == __MAX_BPF_MAP_TYPE) + continue; + map_type_name = btf__str_by_offset(btf, e->name_off); map_type_str = libbpf_bpf_map_type_str(map_type); ASSERT_OK_PTR(map_type_str, map_type_name); From 9ea7c4bf17e39d463eb4782f948f401d9764b1b3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:02 -0800 Subject: [PATCH 0268/2255] bpf: Add BPF token support to BPF_BTF_LOAD command Accept BPF token FD in BPF_BTF_LOAD command to allow BTF data loading through delegated BPF token. BPF_F_TOKEN_FD flag has to be specified when passing BPF token FD. Given BPF_BTF_LOAD command didn't have flags field before, we also add btf_flags field. BTF loading is a pretty straightforward operation, so as long as BPF token is created with allow_cmds granting BPF_BTF_LOAD command, kernel proceeds to parsing BTF data and creating BTF object. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-6-andrii@kernel.org --- include/uapi/linux/bpf.h | 5 +++++ kernel/bpf/syscall.c | 23 +++++++++++++++++++++-- tools/include/uapi/linux/bpf.h | 5 +++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index c78cab8b462d..cb2c888e3bb4 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1632,6 +1632,11 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 btf_log_true_size; + __u32 btf_flags; + /* BPF token FD to use with BPF_BTF_LOAD operation. + * If provided, btf_flags should have BPF_F_TOKEN_FD flag set. + */ + __s32 btf_token_fd; }; struct { diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index b13a4bdcd3a0..45b3a55896eb 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4831,15 +4831,34 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, return err; } -#define BPF_BTF_LOAD_LAST_FIELD btf_log_true_size +#define BPF_BTF_LOAD_LAST_FIELD btf_token_fd static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size) { + struct bpf_token *token = NULL; + if (CHECK_ATTR(BPF_BTF_LOAD)) return -EINVAL; - if (!bpf_capable()) + if (attr->btf_flags & ~BPF_F_TOKEN_FD) + return -EINVAL; + + if (attr->btf_flags & BPF_F_TOKEN_FD) { + token = bpf_token_get_from_fd(attr->btf_token_fd); + if (IS_ERR(token)) + return PTR_ERR(token); + if (!bpf_token_allow_cmd(token, BPF_BTF_LOAD)) { + bpf_token_put(token); + token = NULL; + } + } + + if (!bpf_token_capable(token, CAP_BPF)) { + bpf_token_put(token); return -EPERM; + } + + bpf_token_put(token); return btf_new_fd(attr, uattr, uattr_size); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index c78cab8b462d..cb2c888e3bb4 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1632,6 +1632,11 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 btf_log_true_size; + __u32 btf_flags; + /* BPF token FD to use with BPF_BTF_LOAD operation. + * If provided, btf_flags should have BPF_F_TOKEN_FD flag set. + */ + __s32 btf_token_fd; }; struct { From caf8f28e036c4ba1e823355da6c0c01c39e70ab9 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:03 -0800 Subject: [PATCH 0269/2255] bpf: Add BPF token support to BPF_PROG_LOAD command Add basic support of BPF token to BPF_PROG_LOAD. BPF_F_TOKEN_FD flag should be set in prog_flags field when providing prog_token_fd. Wire through a set of allowed BPF program types and attach types, derived from BPF FS at BPF token creation time. Then make sure we perform bpf_token_capable() checks everywhere where it's relevant. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-7-andrii@kernel.org --- include/linux/bpf.h | 6 ++ include/uapi/linux/bpf.h | 5 ++ kernel/bpf/core.c | 1 + kernel/bpf/inode.c | 6 +- kernel/bpf/syscall.c | 90 +++++++++++++------ kernel/bpf/token.c | 27 ++++++ tools/include/uapi/linux/bpf.h | 5 ++ .../selftests/bpf/prog_tests/libbpf_probes.c | 2 + .../selftests/bpf/prog_tests/libbpf_str.c | 3 + 9 files changed, 118 insertions(+), 27 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8252452d0c4d..d0bf37e3f166 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1489,6 +1489,7 @@ struct bpf_prog_aux { #ifdef CONFIG_SECURITY void *security; #endif + struct bpf_token *token; struct bpf_prog_offload *offload; struct btf *btf; struct bpf_func_info *func_info; @@ -1631,6 +1632,8 @@ struct bpf_token { struct user_namespace *userns; u64 allowed_cmds; u64 allowed_maps; + u64 allowed_progs; + u64 allowed_attachs; }; struct bpf_struct_ops_value; @@ -2299,6 +2302,9 @@ struct bpf_token *bpf_token_get_from_fd(u32 ufd); bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd); bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type); +bool bpf_token_allow_prog_type(const struct bpf_token *token, + enum bpf_prog_type prog_type, + enum bpf_attach_type attach_type); int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname); int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index cb2c888e3bb4..d96708380e52 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1028,6 +1028,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SK_LOOKUP, BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */ BPF_PROG_TYPE_NETFILTER, + __MAX_BPF_PROG_TYPE }; enum bpf_attach_type { @@ -1520,6 +1521,10 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 log_true_size; + /* BPF token FD to use with BPF_PROG_LOAD operation. + * If provided, prog_flags should have BPF_F_TOKEN_FD flag set. + */ + __s32 prog_token_fd; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index fbb1d95a9b44..00dccba29769 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2779,6 +2779,7 @@ void bpf_prog_free(struct bpf_prog *fp) if (aux->dst_prog) bpf_prog_put(aux->dst_prog); + bpf_token_put(aux->token); INIT_WORK(&aux->work, bpf_prog_free_deferred); schedule_work(&aux->work); } diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 034b7e4d8f19..5fb10da5717f 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -626,12 +626,14 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) else if (opts->delegate_maps) seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); - if (opts->delegate_progs == ~0ULL) + mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; + if ((opts->delegate_progs & mask) == mask) seq_printf(m, ",delegate_progs=any"); else if (opts->delegate_progs) seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs); - if (opts->delegate_attachs == ~0ULL) + mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; + if ((opts->delegate_attachs & mask) == mask) seq_printf(m, ",delegate_attachs=any"); else if (opts->delegate_attachs) seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 45b3a55896eb..61b4bf4cc287 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2626,13 +2626,15 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type) } /* last field in 'union bpf_attr' used by this command */ -#define BPF_PROG_LOAD_LAST_FIELD log_true_size +#define BPF_PROG_LOAD_LAST_FIELD prog_token_fd static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) { enum bpf_prog_type type = attr->prog_type; struct bpf_prog *prog, *dst_prog = NULL; struct btf *attach_btf = NULL; + struct bpf_token *token = NULL; + bool bpf_cap; int err; char license[128]; @@ -2646,13 +2648,35 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) BPF_F_TEST_RND_HI32 | BPF_F_XDP_HAS_FRAGS | BPF_F_XDP_DEV_BOUND_ONLY | - BPF_F_TEST_REG_INVARIANTS)) + BPF_F_TEST_REG_INVARIANTS | + BPF_F_TOKEN_FD)) return -EINVAL; + bpf_prog_load_fixup_attach_type(attr); + + if (attr->prog_flags & BPF_F_TOKEN_FD) { + token = bpf_token_get_from_fd(attr->prog_token_fd); + if (IS_ERR(token)) + return PTR_ERR(token); + /* if current token doesn't grant prog loading permissions, + * then we can't use this token, so ignore it and rely on + * system-wide capabilities checks + */ + if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) || + !bpf_token_allow_prog_type(token, attr->prog_type, + attr->expected_attach_type)) { + bpf_token_put(token); + token = NULL; + } + } + + bpf_cap = bpf_token_capable(token, CAP_BPF); + err = -EPERM; + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && - !bpf_capable()) - return -EPERM; + !bpf_cap) + goto put_token; /* Intent here is for unprivileged_bpf_disabled to block BPF program * creation for unprivileged users; other actions depend @@ -2661,21 +2685,23 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) * capability checks are still carried out for these * and other operations. */ - if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) - return -EPERM; + if (sysctl_unprivileged_bpf_disabled && !bpf_cap) + goto put_token; if (attr->insn_cnt == 0 || - attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) - return -E2BIG; + attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) { + err = -E2BIG; + goto put_token; + } if (type != BPF_PROG_TYPE_SOCKET_FILTER && type != BPF_PROG_TYPE_CGROUP_SKB && - !bpf_capable()) - return -EPERM; + !bpf_cap) + goto put_token; - if (is_net_admin_prog_type(type) && !bpf_net_capable()) - return -EPERM; - if (is_perfmon_prog_type(type) && !perfmon_capable()) - return -EPERM; + if (is_net_admin_prog_type(type) && !bpf_token_capable(token, CAP_NET_ADMIN)) + goto put_token; + if (is_perfmon_prog_type(type) && !bpf_token_capable(token, CAP_PERFMON)) + goto put_token; /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog * or btf, we need to check which one it is @@ -2685,27 +2711,33 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (IS_ERR(dst_prog)) { dst_prog = NULL; attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); - if (IS_ERR(attach_btf)) - return -EINVAL; + if (IS_ERR(attach_btf)) { + err = -EINVAL; + goto put_token; + } if (!btf_is_kernel(attach_btf)) { /* attaching through specifying bpf_prog's BTF * objects directly might be supported eventually */ btf_put(attach_btf); - return -ENOTSUPP; + err = -ENOTSUPP; + goto put_token; } } } else if (attr->attach_btf_id) { /* fall back to vmlinux BTF, if BTF type ID is specified */ attach_btf = bpf_get_btf_vmlinux(); - if (IS_ERR(attach_btf)) - return PTR_ERR(attach_btf); - if (!attach_btf) - return -EINVAL; + if (IS_ERR(attach_btf)) { + err = PTR_ERR(attach_btf); + goto put_token; + } + if (!attach_btf) { + err = -EINVAL; + goto put_token; + } btf_get(attach_btf); } - bpf_prog_load_fixup_attach_type(attr); if (bpf_prog_load_check_attach(type, attr->expected_attach_type, attach_btf, attr->attach_btf_id, dst_prog)) { @@ -2713,7 +2745,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) bpf_prog_put(dst_prog); if (attach_btf) btf_put(attach_btf); - return -EINVAL; + err = -EINVAL; + goto put_token; } /* plain bpf_prog allocation */ @@ -2723,7 +2756,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) bpf_prog_put(dst_prog); if (attach_btf) btf_put(attach_btf); - return -ENOMEM; + err = -EINVAL; + goto put_token; } prog->expected_attach_type = attr->expected_attach_type; @@ -2734,6 +2768,10 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS; + /* move token into prog->aux, reuse taken refcnt */ + prog->aux->token = token; + token = NULL; + err = security_bpf_prog_alloc(prog->aux); if (err) goto free_prog; @@ -2851,6 +2889,8 @@ free_prog: if (prog->aux->attach_btf) btf_put(prog->aux->attach_btf); bpf_prog_free(prog); +put_token: + bpf_token_put(token); return err; } @@ -3858,7 +3898,7 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, case BPF_PROG_TYPE_SK_LOOKUP: return attach_type == prog->expected_attach_type ? 0 : -EINVAL; case BPF_PROG_TYPE_CGROUP_SKB: - if (!bpf_net_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_NET_ADMIN)) /* cg-skb progs can be loaded by unpriv user. * check permissions at attach time. */ diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index bc86be4ca567..c13c73788d8c 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -80,6 +80,20 @@ static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp) seq_printf(m, "allowed_maps:\tany\n"); else seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps); + + BUILD_BUG_ON(__MAX_BPF_PROG_TYPE >= 64); + mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; + if ((token->allowed_progs & mask) == mask) + seq_printf(m, "allowed_progs:\tany\n"); + else + seq_printf(m, "allowed_progs:\t0x%llx\n", token->allowed_progs); + + BUILD_BUG_ON(__MAX_BPF_ATTACH_TYPE >= 64); + mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; + if ((token->allowed_attachs & mask) == mask) + seq_printf(m, "allowed_attachs:\tany\n"); + else + seq_printf(m, "allowed_attachs:\t0x%llx\n", token->allowed_attachs); } #define BPF_TOKEN_INODE_NAME "bpf-token" @@ -176,6 +190,8 @@ int bpf_token_create(union bpf_attr *attr) mnt_opts = path.dentry->d_sb->s_fs_info; token->allowed_cmds = mnt_opts->delegate_cmds; token->allowed_maps = mnt_opts->delegate_maps; + token->allowed_progs = mnt_opts->delegate_progs; + token->allowed_attachs = mnt_opts->delegate_attachs; fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { @@ -231,3 +247,14 @@ bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type t return token->allowed_maps & (1ULL << type); } + +bool bpf_token_allow_prog_type(const struct bpf_token *token, + enum bpf_prog_type prog_type, + enum bpf_attach_type attach_type) +{ + if (!token || prog_type >= __MAX_BPF_PROG_TYPE || attach_type >= __MAX_BPF_ATTACH_TYPE) + return false; + + return (token->allowed_progs & (1ULL << prog_type)) && + (token->allowed_attachs & (1ULL << attach_type)); +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index cb2c888e3bb4..d96708380e52 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1028,6 +1028,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SK_LOOKUP, BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */ BPF_PROG_TYPE_NETFILTER, + __MAX_BPF_PROG_TYPE }; enum bpf_attach_type { @@ -1520,6 +1521,10 @@ union bpf_attr { * truncated), or smaller (if log buffer wasn't filled completely). */ __u32 log_true_size; + /* BPF token FD to use with BPF_PROG_LOAD operation. + * If provided, prog_flags should have BPF_F_TOKEN_FD flag set. + */ + __s32 prog_token_fd; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c index 573249a2814d..4ed46ed58a7b 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_probes.c @@ -30,6 +30,8 @@ void test_libbpf_probe_prog_types(void) if (prog_type == BPF_PROG_TYPE_UNSPEC) continue; + if (strcmp(prog_type_name, "__MAX_BPF_PROG_TYPE") == 0) + continue; if (!test__start_subtest(prog_type_name)) continue; diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c index 1f328c0d8aff..62ea855ec4d0 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c @@ -189,6 +189,9 @@ static void test_libbpf_bpf_prog_type_str(void) const char *prog_type_str; char buf[256]; + if (prog_type == __MAX_BPF_PROG_TYPE) + continue; + prog_type_name = btf__str_by_offset(btf, e->name_off); prog_type_str = libbpf_bpf_prog_type_str(prog_type); ASSERT_OK_PTR(prog_type_str, prog_type_name); From bbc1d24724e110b86a1a7c3c1724ce0d62cc1e2e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:04 -0800 Subject: [PATCH 0270/2255] bpf: Take into account BPF token when fetching helper protos Instead of performing unconditional system-wide bpf_capable() and perfmon_capable() calls inside bpf_base_func_proto() function (and other similar ones) to determine eligibility of a given BPF helper for a given program, use previously recorded BPF token during BPF_PROG_LOAD command handling to inform the decision. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-8-andrii@kernel.org --- drivers/media/rc/bpf-lirc.c | 2 +- include/linux/bpf.h | 5 +++-- kernel/bpf/cgroup.c | 6 +++--- kernel/bpf/helpers.c | 6 +++--- kernel/bpf/syscall.c | 5 +++-- kernel/trace/bpf_trace.c | 2 +- net/core/filter.c | 32 ++++++++++++++++---------------- net/ipv4/bpf_tcp_ca.c | 2 +- net/netfilter/nf_bpf_link.c | 2 +- 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c index fe17c7f98e81..6d07693c6b9f 100644 --- a/drivers/media/rc/bpf-lirc.c +++ b/drivers/media/rc/bpf-lirc.c @@ -110,7 +110,7 @@ lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_get_prandom_u32: return &bpf_get_prandom_u32_proto; case BPF_FUNC_trace_printk: - if (perfmon_capable()) + if (bpf_token_capable(prog->aux->token, CAP_PERFMON)) return bpf_get_trace_printk_proto(); fallthrough; default: diff --git a/include/linux/bpf.h b/include/linux/bpf.h index d0bf37e3f166..1325225bf602 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2550,7 +2550,8 @@ int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, struct bpf_prog *bpf_prog_by_id(u32 id); struct bpf_link *bpf_link_by_id(u32 id); -const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id); +const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id, + const struct bpf_prog *prog); void bpf_task_storage_free(struct task_struct *task); void bpf_cgrp_storage_free(struct cgroup *cgroup); bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog); @@ -2810,7 +2811,7 @@ static inline int btf_struct_access(struct bpf_verifier_log *log, } static inline const struct bpf_func_proto * -bpf_base_func_proto(enum bpf_func_id func_id) +bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { return NULL; } diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 491d20038cbe..98e0e3835b28 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1630,7 +1630,7 @@ cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_event_output_data_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -2191,7 +2191,7 @@ sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_event_output_data_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -2348,7 +2348,7 @@ cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_event_output_data_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index e04ca1af8927..bcb951a2ecf4 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1680,7 +1680,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto __weak; const struct bpf_func_proto bpf_task_pt_regs_proto __weak; const struct bpf_func_proto * -bpf_base_func_proto(enum bpf_func_id func_id) +bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { switch (func_id) { case BPF_FUNC_map_lookup_elem: @@ -1731,7 +1731,7 @@ bpf_base_func_proto(enum bpf_func_id func_id) break; } - if (!bpf_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_BPF)) return NULL; switch (func_id) { @@ -1789,7 +1789,7 @@ bpf_base_func_proto(enum bpf_func_id func_id) break; } - if (!perfmon_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_PERFMON)) return NULL; switch (func_id) { diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 61b4bf4cc287..f76408c957ce 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -5772,7 +5772,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = { const struct bpf_func_proto * __weak tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } BPF_CALL_1(bpf_sys_close, u32, fd) @@ -5822,7 +5822,8 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { switch (func_id) { case BPF_FUNC_sys_bpf: - return !perfmon_capable() ? NULL : &bpf_sys_bpf_proto; + return !bpf_token_capable(prog->aux->token, CAP_PERFMON) + ? NULL : &bpf_sys_bpf_proto; case BPF_FUNC_btf_find_by_name_kind: return &bpf_btf_find_by_name_kind_proto; case BPF_FUNC_sys_close: diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index c98c20abaf99..64fdaf79d113 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1629,7 +1629,7 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_trace_vprintk: return bpf_get_trace_vprintk_proto(); default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } diff --git a/net/core/filter.c b/net/core/filter.c index 6a7abbaa50b8..521bcd0f5e4d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -87,7 +87,7 @@ #include "dev.h" static const struct bpf_func_proto * -bpf_sk_base_func_proto(enum bpf_func_id func_id); +bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog); int copy_bpf_fprog_from_user(struct sock_fprog *dst, sockptr_t src, int len) { @@ -7862,7 +7862,7 @@ sock_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -7955,7 +7955,7 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return NULL; } default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -7974,7 +7974,7 @@ sk_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_perf_event_output: return &bpf_skb_event_output_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8161,7 +8161,7 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) #endif #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8220,7 +8220,7 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) #endif #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } #if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES) @@ -8281,7 +8281,7 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_tcp_sock_proto; #endif /* CONFIG_INET */ default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8323,7 +8323,7 @@ sk_msg_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_get_cgroup_classid_curr_proto; #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8367,7 +8367,7 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_skc_lookup_tcp_proto; #endif default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8378,7 +8378,7 @@ flow_dissector_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_skb_load_bytes: return &bpf_flow_dissector_load_bytes_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -8405,7 +8405,7 @@ lwt_out_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_skb_under_cgroup: return &bpf_skb_under_cgroup_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -11236,7 +11236,7 @@ sk_reuseport_func_proto(enum bpf_func_id func_id, case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } @@ -11418,7 +11418,7 @@ sk_lookup_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_sk_release: return &bpf_sk_release_proto; default: - return bpf_sk_base_func_proto(func_id); + return bpf_sk_base_func_proto(func_id, prog); } } @@ -11752,7 +11752,7 @@ const struct bpf_func_proto bpf_sock_from_file_proto = { }; static const struct bpf_func_proto * -bpf_sk_base_func_proto(enum bpf_func_id func_id) +bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { const struct bpf_func_proto *func; @@ -11781,10 +11781,10 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id) case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } - if (!perfmon_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_PERFMON)) return NULL; return func; diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c index 8e7716256d3c..834edc18463a 100644 --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c @@ -197,7 +197,7 @@ bpf_tcp_ca_get_func_proto(enum bpf_func_id func_id, case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } } diff --git a/net/netfilter/nf_bpf_link.c b/net/netfilter/nf_bpf_link.c index 0e4beae421f8..5257d5e7eb09 100644 --- a/net/netfilter/nf_bpf_link.c +++ b/net/netfilter/nf_bpf_link.c @@ -314,7 +314,7 @@ static bool nf_is_valid_access(int off, int size, enum bpf_access_type type, static const struct bpf_func_proto * bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { - return bpf_base_func_proto(func_id); + return bpf_base_func_proto(func_id, prog); } const struct bpf_verifier_ops netfilter_verifier_ops = { From d79a3549754725bb90e58104417449edddf3da3d Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:05 -0800 Subject: [PATCH 0271/2255] bpf: Consistently use BPF token throughout BPF verifier logic Remove remaining direct queries to perfmon_capable() and bpf_capable() in BPF verifier logic and instead use BPF token (if available) to make decisions about privileges. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-9-andrii@kernel.org --- include/linux/bpf.h | 16 ++++++++-------- include/linux/filter.h | 2 +- kernel/bpf/arraymap.c | 2 +- kernel/bpf/core.c | 2 +- kernel/bpf/verifier.c | 13 ++++++------- net/core/filter.c | 4 ++-- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1325225bf602..4e146e9708be 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2261,24 +2261,24 @@ extern int sysctl_unprivileged_bpf_disabled; bool bpf_token_capable(const struct bpf_token *token, int cap); -static inline bool bpf_allow_ptr_leaks(void) +static inline bool bpf_allow_ptr_leaks(const struct bpf_token *token) { - return perfmon_capable(); + return bpf_token_capable(token, CAP_PERFMON); } -static inline bool bpf_allow_uninit_stack(void) +static inline bool bpf_allow_uninit_stack(const struct bpf_token *token) { - return perfmon_capable(); + return bpf_token_capable(token, CAP_PERFMON); } -static inline bool bpf_bypass_spec_v1(void) +static inline bool bpf_bypass_spec_v1(const struct bpf_token *token) { - return cpu_mitigations_off() || perfmon_capable(); + return cpu_mitigations_off() || bpf_token_capable(token, CAP_PERFMON); } -static inline bool bpf_bypass_spec_v4(void) +static inline bool bpf_bypass_spec_v4(const struct bpf_token *token) { - return cpu_mitigations_off() || perfmon_capable(); + return cpu_mitigations_off() || bpf_token_capable(token, CAP_PERFMON); } int bpf_map_new_fd(struct bpf_map *map, int flags); diff --git a/include/linux/filter.h b/include/linux/filter.h index 35f067fd3840..fee070b9826e 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1140,7 +1140,7 @@ static inline bool bpf_jit_blinding_enabled(struct bpf_prog *prog) return false; if (!bpf_jit_harden) return false; - if (bpf_jit_harden == 1 && bpf_capable()) + if (bpf_jit_harden == 1 && bpf_token_capable(prog->aux->token, CAP_BPF)) return false; return true; diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 0bdbbbeab155..13358675ff2e 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -82,7 +82,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; int numa_node = bpf_map_attr_numa_node(attr); u32 elem_size, index_mask, max_entries; - bool bypass_spec_v1 = bpf_bypass_spec_v1(); + bool bypass_spec_v1 = bpf_bypass_spec_v1(NULL); u64 array_size, mask64; struct bpf_array *array; diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 00dccba29769..71c459a51d9e 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -682,7 +682,7 @@ static bool bpf_prog_kallsyms_candidate(const struct bpf_prog *fp) void bpf_prog_kallsyms_add(struct bpf_prog *fp) { if (!bpf_prog_kallsyms_candidate(fp) || - !bpf_capable()) + !bpf_token_capable(fp->aux->token, CAP_BPF)) return; bpf_prog_ksym_set_addr(fp); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f31868ba0c2d..fe833e831cb6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20830,7 +20830,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 env->prog = *prog; env->ops = bpf_verifier_ops[env->prog->type]; env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel); - is_priv = bpf_capable(); + + env->allow_ptr_leaks = bpf_allow_ptr_leaks(env->prog->aux->token); + env->allow_uninit_stack = bpf_allow_uninit_stack(env->prog->aux->token); + env->bypass_spec_v1 = bpf_bypass_spec_v1(env->prog->aux->token); + env->bypass_spec_v4 = bpf_bypass_spec_v4(env->prog->aux->token); + env->bpf_capable = is_priv = bpf_token_capable(env->prog->aux->token, CAP_BPF); bpf_get_btf_vmlinux(); @@ -20862,12 +20867,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 if (attr->prog_flags & BPF_F_ANY_ALIGNMENT) env->strict_alignment = false; - env->allow_ptr_leaks = bpf_allow_ptr_leaks(); - env->allow_uninit_stack = bpf_allow_uninit_stack(); - env->bypass_spec_v1 = bpf_bypass_spec_v1(); - env->bypass_spec_v4 = bpf_bypass_spec_v4(); - env->bpf_capable = bpf_capable(); - if (is_priv) env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ; env->test_reg_invariants = attr->prog_flags & BPF_F_TEST_REG_INVARIANTS; diff --git a/net/core/filter.c b/net/core/filter.c index 521bcd0f5e4d..40121475e8d1 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -8580,7 +8580,7 @@ static bool cg_skb_is_valid_access(int off, int size, return false; case bpf_ctx_range(struct __sk_buff, data): case bpf_ctx_range(struct __sk_buff, data_end): - if (!bpf_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_BPF)) return false; break; } @@ -8592,7 +8592,7 @@ static bool cg_skb_is_valid_access(int off, int size, case bpf_ctx_range_till(struct __sk_buff, cb[0], cb[4]): break; case bpf_ctx_range(struct __sk_buff, tstamp): - if (!bpf_capable()) + if (!bpf_token_capable(prog->aux->token, CAP_BPF)) return false; break; default: From 1b67772e4e3f16cd647b229cae95fc06d120be08 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:06 -0800 Subject: [PATCH 0272/2255] bpf,lsm: Refactor bpf_prog_alloc/bpf_prog_free LSM hooks Based on upstream discussion ([0]), rework existing bpf_prog_alloc_security LSM hook. Rename it to bpf_prog_load and instead of passing bpf_prog_aux, pass proper bpf_prog pointer for a full BPF program struct. Also, we pass bpf_attr union with all the user-provided arguments for BPF_PROG_LOAD command. This will give LSMs as much information as we can basically provide. The hook is also BPF token-aware now, and optional bpf_token struct is passed as a third argument. bpf_prog_load LSM hook is called after a bunch of sanity checks were performed, bpf_prog and bpf_prog_aux were allocated and filled out, but right before performing full-fledged BPF verification step. bpf_prog_free LSM hook is now accepting struct bpf_prog argument, for consistency. SELinux code is adjusted to all new names, types, and signatures. Note, given that bpf_prog_load (previously bpf_prog_alloc) hook can be used by some LSMs to allocate extra security blob, but also by other LSMs to reject BPF program loading, we need to make sure that bpf_prog_free LSM hook is called after bpf_prog_load/bpf_prog_alloc one *even* if the hook itself returned error. If we don't do that, we run the risk of leaking memory. This seems to be possible today when combining SELinux and BPF LSM, as one example, depending on their relative ordering. Also, for BPF LSM setup, add bpf_prog_load and bpf_prog_free to sleepable LSM hooks list, as they are both executed in sleepable context. Also drop bpf_prog_load hook from untrusted, as there is no issue with refcount or anything else anymore, that originally forced us to add it to untrusted list in c0c852dd1876 ("bpf: Do not mark certain LSM hook arguments as trusted"). We now trigger this hook much later and it should not be an issue anymore. [0] https://lore.kernel.org/bpf/9fe88aef7deabbe87d3fc38c4aea3c69.paul@paul-moore.com/ Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: Paul Moore Link: https://lore.kernel.org/bpf/20240124022127.2379740-10-andrii@kernel.org --- include/linux/lsm_hook_defs.h | 5 +++-- include/linux/security.h | 12 +++++++----- kernel/bpf/bpf_lsm.c | 5 +++-- kernel/bpf/syscall.c | 25 +++++++++++++------------ security/security.c | 25 +++++++++++++++---------- security/selinux/hooks.c | 15 ++++++++------- 6 files changed, 49 insertions(+), 38 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 185924c56378..370181aa685b 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -406,8 +406,9 @@ LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode) LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog) LSM_HOOK(int, 0, bpf_map_alloc_security, struct bpf_map *map) LSM_HOOK(void, LSM_RET_VOID, bpf_map_free_security, struct bpf_map *map) -LSM_HOOK(int, 0, bpf_prog_alloc_security, struct bpf_prog_aux *aux) -LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free_security, struct bpf_prog_aux *aux) +LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) +LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog) #endif /* CONFIG_BPF_SYSCALL */ LSM_HOOK(int, 0, locked_down, enum lockdown_reason what) diff --git a/include/linux/security.h b/include/linux/security.h index d0eb20f90b26..cb2932fce448 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2064,15 +2064,16 @@ static inline void securityfs_remove(struct dentry *dentry) union bpf_attr; struct bpf_map; struct bpf_prog; -struct bpf_prog_aux; +struct bpf_token; #ifdef CONFIG_SECURITY extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size); extern int security_bpf_map(struct bpf_map *map, fmode_t fmode); extern int security_bpf_prog(struct bpf_prog *prog); extern int security_bpf_map_alloc(struct bpf_map *map); extern void security_bpf_map_free(struct bpf_map *map); -extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux); -extern void security_bpf_prog_free(struct bpf_prog_aux *aux); +extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token); +extern void security_bpf_prog_free(struct bpf_prog *prog); #else static inline int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) @@ -2098,12 +2099,13 @@ static inline int security_bpf_map_alloc(struct bpf_map *map) static inline void security_bpf_map_free(struct bpf_map *map) { } -static inline int security_bpf_prog_alloc(struct bpf_prog_aux *aux) +static inline int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) { return 0; } -static inline void security_bpf_prog_free(struct bpf_prog_aux *aux) +static inline void security_bpf_prog_free(struct bpf_prog *prog) { } #endif /* CONFIG_SECURITY */ #endif /* CONFIG_BPF_SYSCALL */ diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index e8e910395bf6..7ee0dd011de4 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -263,6 +263,8 @@ BTF_ID(func, bpf_lsm_bpf_map) BTF_ID(func, bpf_lsm_bpf_map_alloc_security) BTF_ID(func, bpf_lsm_bpf_map_free_security) BTF_ID(func, bpf_lsm_bpf_prog) +BTF_ID(func, bpf_lsm_bpf_prog_load) +BTF_ID(func, bpf_lsm_bpf_prog_free) BTF_ID(func, bpf_lsm_bprm_check_security) BTF_ID(func, bpf_lsm_bprm_committed_creds) BTF_ID(func, bpf_lsm_bprm_committing_creds) @@ -358,8 +360,7 @@ BTF_SET_END(sleepable_lsm_hooks) BTF_SET_START(untrusted_lsm_hooks) BTF_ID(func, bpf_lsm_bpf_map_free_security) -BTF_ID(func, bpf_lsm_bpf_prog_alloc_security) -BTF_ID(func, bpf_lsm_bpf_prog_free_security) +BTF_ID(func, bpf_lsm_bpf_prog_free) BTF_ID(func, bpf_lsm_file_alloc_security) BTF_ID(func, bpf_lsm_file_free_security) #ifdef CONFIG_SECURITY_NETWORK diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f76408c957ce..3857a2a9ae7f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2180,7 +2180,7 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu) kvfree(aux->func_info); kfree(aux->func_info_aux); free_uid(aux->user); - security_bpf_prog_free(aux); + security_bpf_prog_free(aux->prog); bpf_prog_free(aux->prog); } @@ -2772,10 +2772,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) prog->aux->token = token; token = NULL; - err = security_bpf_prog_alloc(prog->aux); - if (err) - goto free_prog; - prog->aux->user = get_current_user(); prog->len = attr->insn_cnt; @@ -2783,12 +2779,12 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (copy_from_bpfptr(prog->insns, make_bpfptr(attr->insns, uattr.is_kernel), bpf_prog_insn_size(prog)) != 0) - goto free_prog_sec; + goto free_prog; /* copy eBPF program license from user space */ if (strncpy_from_bpfptr(license, make_bpfptr(attr->license, uattr.is_kernel), sizeof(license) - 1) < 0) - goto free_prog_sec; + goto free_prog; license[sizeof(license) - 1] = 0; /* eBPF programs must be GPL compatible to use GPL-ed functions */ @@ -2802,14 +2798,14 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (bpf_prog_is_dev_bound(prog->aux)) { err = bpf_prog_dev_bound_init(prog, attr); if (err) - goto free_prog_sec; + goto free_prog; } if (type == BPF_PROG_TYPE_EXT && dst_prog && bpf_prog_is_dev_bound(dst_prog->aux)) { err = bpf_prog_dev_bound_inherit(prog, dst_prog); if (err) - goto free_prog_sec; + goto free_prog; } /* @@ -2831,12 +2827,16 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) /* find program type: socket_filter vs tracing_filter */ err = find_prog_type(type, prog); if (err < 0) - goto free_prog_sec; + goto free_prog; prog->aux->load_time = ktime_get_boottime_ns(); err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, sizeof(attr->prog_name)); if (err < 0) + goto free_prog; + + err = security_bpf_prog_load(prog, attr, token); + if (err) goto free_prog_sec; /* run eBPF verifier */ @@ -2882,10 +2882,11 @@ free_used_maps: */ __bpf_prog_put_noref(prog, prog->aux->real_func_cnt); return err; + free_prog_sec: - free_uid(prog->aux->user); - security_bpf_prog_free(prog->aux); + security_bpf_prog_free(prog); free_prog: + free_uid(prog->aux->user); if (prog->aux->attach_btf) btf_put(prog->aux->attach_btf); bpf_prog_free(prog); diff --git a/security/security.c b/security/security.c index 0144a98d3712..eb159da4b146 100644 --- a/security/security.c +++ b/security/security.c @@ -5423,16 +5423,21 @@ int security_bpf_map_alloc(struct bpf_map *map) } /** - * security_bpf_prog_alloc() - Allocate a bpf program LSM blob - * @aux: bpf program aux info struct + * security_bpf_prog_load() - Check if loading of BPF program is allowed + * @prog: BPF program object + * @attr: BPF syscall attributes used to create BPF program + * @token: BPF token used to grant user access to BPF subsystem * - * Initialize the security field inside bpf program. + * Perform an access control check when the kernel loads a BPF program and + * allocates associated BPF program object. This hook is also responsible for + * allocating any required LSM state for the BPF program. * * Return: Returns 0 on success, error on failure. */ -int security_bpf_prog_alloc(struct bpf_prog_aux *aux) +int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) { - return call_int_hook(bpf_prog_alloc_security, 0, aux); + return call_int_hook(bpf_prog_load, 0, prog, attr, token); } /** @@ -5447,14 +5452,14 @@ void security_bpf_map_free(struct bpf_map *map) } /** - * security_bpf_prog_free() - Free a bpf program's LSM blob - * @aux: bpf program aux info struct + * security_bpf_prog_free() - Free a BPF program's LSM blob + * @prog: BPF program struct * - * Clean up the security information stored inside bpf prog. + * Clean up the security information stored inside BPF program. */ -void security_bpf_prog_free(struct bpf_prog_aux *aux) +void security_bpf_prog_free(struct bpf_prog *prog) { - call_void_hook(bpf_prog_free_security, aux); + call_void_hook(bpf_prog_free, prog); } #endif /* CONFIG_BPF_SYSCALL */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a6bf90ace84c..6d64fb189b1b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6942,7 +6942,8 @@ static void selinux_bpf_map_free(struct bpf_map *map) kfree(bpfsec); } -static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) +static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, + struct bpf_token *token) { struct bpf_security_struct *bpfsec; @@ -6951,16 +6952,16 @@ static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) return -ENOMEM; bpfsec->sid = current_sid(); - aux->security = bpfsec; + prog->aux->security = bpfsec; return 0; } -static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) +static void selinux_bpf_prog_free(struct bpf_prog *prog) { - struct bpf_security_struct *bpfsec = aux->security; + struct bpf_security_struct *bpfsec = prog->aux->security; - aux->security = NULL; + prog->aux->security = NULL; kfree(bpfsec); } #endif @@ -7325,7 +7326,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf_map, selinux_bpf_map), LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), - LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), + LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), #endif #ifdef CONFIG_PERF_EVENTS @@ -7383,7 +7384,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { #endif #ifdef CONFIG_BPF_SYSCALL LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), - LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc), + LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), #endif #ifdef CONFIG_PERF_EVENTS LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), From a2431c7eabcf9bd5a1e7a1f7ecded40fdda4a8c5 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:07 -0800 Subject: [PATCH 0273/2255] bpf,lsm: Refactor bpf_map_alloc/bpf_map_free LSM hooks Similarly to bpf_prog_alloc LSM hook, rename and extend bpf_map_alloc hook into bpf_map_create, taking not just struct bpf_map, but also bpf_attr and bpf_token, to give a fuller context to LSMs. Unlike bpf_prog_alloc, there is no need to move the hook around, as it currently is firing right before allocating BPF map ID and FD, which seems to be a sweet spot. But like bpf_prog_alloc/bpf_prog_free combo, make sure that bpf_map_free LSM hook is called even if bpf_map_create hook returned error, as if few LSMs are combined together it could be that one LSM successfully allocated security blob for its needs, while subsequent LSM rejected BPF map creation. The former LSM would still need to free up LSM blob, so we need to ensure security_bpf_map_free() is called regardless of the outcome. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: Paul Moore Link: https://lore.kernel.org/bpf/20240124022127.2379740-11-andrii@kernel.org --- include/linux/lsm_hook_defs.h | 5 +++-- include/linux/security.h | 6 ++++-- kernel/bpf/bpf_lsm.c | 6 +++--- kernel/bpf/syscall.c | 4 ++-- security/security.c | 16 ++++++++++------ security/selinux/hooks.c | 7 ++++--- 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 370181aa685b..1be4d3ca6efb 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -404,8 +404,9 @@ LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule) LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size) LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode) LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog) -LSM_HOOK(int, 0, bpf_map_alloc_security, struct bpf_map *map) -LSM_HOOK(void, LSM_RET_VOID, bpf_map_free_security, struct bpf_map *map) +LSM_HOOK(int, 0, bpf_map_create, struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) +LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map) LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token) LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog) diff --git a/include/linux/security.h b/include/linux/security.h index cb2932fce448..83fcdc974116 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2069,7 +2069,8 @@ struct bpf_token; extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size); extern int security_bpf_map(struct bpf_map *map, fmode_t fmode); extern int security_bpf_prog(struct bpf_prog *prog); -extern int security_bpf_map_alloc(struct bpf_map *map); +extern int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token); extern void security_bpf_map_free(struct bpf_map *map); extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token); @@ -2091,7 +2092,8 @@ static inline int security_bpf_prog(struct bpf_prog *prog) return 0; } -static inline int security_bpf_map_alloc(struct bpf_map *map) +static inline int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { return 0; } diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 7ee0dd011de4..76976908b302 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -260,8 +260,8 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) BTF_SET_START(sleepable_lsm_hooks) BTF_ID(func, bpf_lsm_bpf) BTF_ID(func, bpf_lsm_bpf_map) -BTF_ID(func, bpf_lsm_bpf_map_alloc_security) -BTF_ID(func, bpf_lsm_bpf_map_free_security) +BTF_ID(func, bpf_lsm_bpf_map_create) +BTF_ID(func, bpf_lsm_bpf_map_free) BTF_ID(func, bpf_lsm_bpf_prog) BTF_ID(func, bpf_lsm_bpf_prog_load) BTF_ID(func, bpf_lsm_bpf_prog_free) @@ -359,7 +359,7 @@ BTF_ID(func, bpf_lsm_userns_create) BTF_SET_END(sleepable_lsm_hooks) BTF_SET_START(untrusted_lsm_hooks) -BTF_ID(func, bpf_lsm_bpf_map_free_security) +BTF_ID(func, bpf_lsm_bpf_map_free) BTF_ID(func, bpf_lsm_bpf_prog_free) BTF_ID(func, bpf_lsm_file_alloc_security) BTF_ID(func, bpf_lsm_file_free_security) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 3857a2a9ae7f..b2750b79ac80 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1318,9 +1318,9 @@ static int map_create(union bpf_attr *attr) attr->btf_vmlinux_value_type_id; } - err = security_bpf_map_alloc(map); + err = security_bpf_map_create(map, attr, token); if (err) - goto free_map; + goto free_map_sec; err = bpf_map_alloc_id(map); if (err) diff --git a/security/security.c b/security/security.c index eb159da4b146..26fcab35b6cd 100644 --- a/security/security.c +++ b/security/security.c @@ -5410,16 +5410,20 @@ int security_bpf_prog(struct bpf_prog *prog) } /** - * security_bpf_map_alloc() - Allocate a bpf map LSM blob - * @map: bpf map + * security_bpf_map_create() - Check if BPF map creation is allowed + * @map: BPF map object + * @attr: BPF syscall attributes used to create BPF map + * @token: BPF token used to grant user access * - * Initialize the security field inside bpf map. + * Do a check when the kernel creates a new BPF map. This is also the + * point where LSM blob is allocated for LSMs that need them. * * Return: Returns 0 on success, error on failure. */ -int security_bpf_map_alloc(struct bpf_map *map) +int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { - return call_int_hook(bpf_map_alloc_security, 0, map); + return call_int_hook(bpf_map_create, 0, map, attr, token); } /** @@ -5448,7 +5452,7 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, */ void security_bpf_map_free(struct bpf_map *map) { - call_void_hook(bpf_map_free_security, map); + call_void_hook(bpf_map_free, map); } /** diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6d64fb189b1b..3d336a7952f7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6920,7 +6920,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog) BPF__PROG_RUN, NULL); } -static int selinux_bpf_map_alloc(struct bpf_map *map) +static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, + struct bpf_token *token) { struct bpf_security_struct *bpfsec; @@ -7325,7 +7326,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf, selinux_bpf), LSM_HOOK_INIT(bpf_map, selinux_bpf_map), LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), - LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), + LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), #endif @@ -7383,7 +7384,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init), #endif #ifdef CONFIG_BPF_SYSCALL - LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), + LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create), LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), #endif #ifdef CONFIG_PERF_EVENTS From f568a3d49af9aed813a184353592efe29b0e3d16 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:08 -0800 Subject: [PATCH 0274/2255] bpf,lsm: Add BPF token LSM hooks Wire up bpf_token_create and bpf_token_free LSM hooks, which allow to allocate LSM security blob (we add `void *security` field to struct bpf_token for that), but also control who can instantiate BPF token. This follows existing pattern for BPF map and BPF prog. Also add security_bpf_token_allow_cmd() and security_bpf_token_capable() LSM hooks that allow LSM implementation to control and negate (if necessary) BPF token's delegation of a specific bpf_cmd and capability, respectively. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: Paul Moore Link: https://lore.kernel.org/bpf/20240124022127.2379740-12-andrii@kernel.org --- include/linux/bpf.h | 3 ++ include/linux/lsm_hook_defs.h | 5 +++ include/linux/security.h | 25 +++++++++++++++ kernel/bpf/bpf_lsm.c | 4 +++ kernel/bpf/token.c | 12 ++++++- security/security.c | 60 +++++++++++++++++++++++++++++++++++ 6 files changed, 108 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 4e146e9708be..b86bd15a051d 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1634,6 +1634,9 @@ struct bpf_token { u64 allowed_maps; u64 allowed_progs; u64 allowed_attachs; +#ifdef CONFIG_SECURITY + void *security; +#endif }; struct bpf_struct_ops_value; diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 1be4d3ca6efb..cd6fbc7af3f8 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -410,6 +410,11 @@ LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map) LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token) LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog) +LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr, + struct path *path) +LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token) +LSM_HOOK(int, 0, bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd) +LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap) #endif /* CONFIG_BPF_SYSCALL */ LSM_HOOK(int, 0, locked_down, enum lockdown_reason what) diff --git a/include/linux/security.h b/include/linux/security.h index 83fcdc974116..15804af54f37 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -32,6 +32,7 @@ #include #include #include +#include #include struct linux_binprm; @@ -2075,6 +2076,11 @@ extern void security_bpf_map_free(struct bpf_map *map); extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token); extern void security_bpf_prog_free(struct bpf_prog *prog); +extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path); +extern void security_bpf_token_free(struct bpf_token *token); +extern int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd); +extern int security_bpf_token_capable(const struct bpf_token *token, int cap); #else static inline int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) @@ -2109,6 +2115,25 @@ static inline int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr * static inline void security_bpf_prog_free(struct bpf_prog *prog) { } + +static inline int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) +{ + return 0; +} + +static inline void security_bpf_token_free(struct bpf_token *token) +{ } + +static inline int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd) +{ + return 0; +} + +static inline int security_bpf_token_capable(const struct bpf_token *token, int cap) +{ + return 0; +} #endif /* CONFIG_SECURITY */ #endif /* CONFIG_BPF_SYSCALL */ diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 76976908b302..63b4dc495125 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -265,6 +265,10 @@ BTF_ID(func, bpf_lsm_bpf_map_free) BTF_ID(func, bpf_lsm_bpf_prog) BTF_ID(func, bpf_lsm_bpf_prog_load) BTF_ID(func, bpf_lsm_bpf_prog_free) +BTF_ID(func, bpf_lsm_bpf_token_create) +BTF_ID(func, bpf_lsm_bpf_token_free) +BTF_ID(func, bpf_lsm_bpf_token_cmd) +BTF_ID(func, bpf_lsm_bpf_token_capable) BTF_ID(func, bpf_lsm_bprm_check_security) BTF_ID(func, bpf_lsm_bprm_committed_creds) BTF_ID(func, bpf_lsm_bprm_committing_creds) diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index c13c73788d8c..64c568f47f69 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -7,6 +7,7 @@ #include #include #include +#include static bool bpf_ns_capable(struct user_namespace *ns, int cap) { @@ -21,6 +22,8 @@ bool bpf_token_capable(const struct bpf_token *token, int cap) userns = token ? token->userns : &init_user_ns; if (!bpf_ns_capable(userns, cap)) return false; + if (token && security_bpf_token_capable(token, cap) < 0) + return false; return true; } @@ -31,6 +34,7 @@ void bpf_token_inc(struct bpf_token *token) static void bpf_token_free(struct bpf_token *token) { + security_bpf_token_free(token); put_user_ns(token->userns); kfree(token); } @@ -193,6 +197,10 @@ int bpf_token_create(union bpf_attr *attr) token->allowed_progs = mnt_opts->delegate_progs; token->allowed_attachs = mnt_opts->delegate_attachs; + err = security_bpf_token_create(token, attr, &path); + if (err) + goto out_token; + fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { err = fd; @@ -237,7 +245,9 @@ bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd) { if (!token) return false; - return token->allowed_cmds & (1ULL << cmd); + if (!(token->allowed_cmds & (1ULL << cmd))) + return false; + return security_bpf_token_cmd(token, cmd) == 0; } bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type) diff --git a/security/security.c b/security/security.c index 26fcab35b6cd..73e009e3d937 100644 --- a/security/security.c +++ b/security/security.c @@ -5444,6 +5444,55 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, return call_int_hook(bpf_prog_load, 0, prog, attr, token); } +/** + * security_bpf_token_create() - Check if creating of BPF token is allowed + * @token: BPF token object + * @attr: BPF syscall attributes used to create BPF token + * @path: path pointing to BPF FS mount point from which BPF token is created + * + * Do a check when the kernel instantiates a new BPF token object from BPF FS + * instance. This is also the point where LSM blob can be allocated for LSMs. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) +{ + return call_int_hook(bpf_token_create, 0, token, attr, path); +} + +/** + * security_bpf_token_cmd() - Check if BPF token is allowed to delegate + * requested BPF syscall command + * @token: BPF token object + * @cmd: BPF syscall command requested to be delegated by BPF token + * + * Do a check when the kernel decides whether provided BPF token should allow + * delegation of requested BPF syscall command. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd) +{ + return call_int_hook(bpf_token_cmd, 0, token, cmd); +} + +/** + * security_bpf_token_capable() - Check if BPF token is allowed to delegate + * requested BPF-related capability + * @token: BPF token object + * @cap: capabilities requested to be delegated by BPF token + * + * Do a check when the kernel decides whether provided BPF token should allow + * delegation of requested BPF-related capabilities. + * + * Return: Returns 0 on success, error on failure. + */ +int security_bpf_token_capable(const struct bpf_token *token, int cap) +{ + return call_int_hook(bpf_token_capable, 0, token, cap); +} + /** * security_bpf_map_free() - Free a bpf map's LSM blob * @map: bpf map @@ -5465,6 +5514,17 @@ void security_bpf_prog_free(struct bpf_prog *prog) { call_void_hook(bpf_prog_free, prog); } + +/** + * security_bpf_token_free() - Free a BPF token's LSM blob + * @token: BPF token struct + * + * Clean up the security information stored inside BPF token. + */ +void security_bpf_token_free(struct bpf_token *token) +{ + call_void_hook(bpf_token_free, token); +} #endif /* CONFIG_BPF_SYSCALL */ /** From 639ecd7d6247c48a0175f5b458b648f5d4b6dc34 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:09 -0800 Subject: [PATCH 0275/2255] libbpf: Add bpf_token_create() API Add low-level wrapper API for BPF_TOKEN_CREATE command in bpf() syscall. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-13-andrii@kernel.org --- tools/lib/bpf/bpf.c | 17 +++++++++++++++++ tools/lib/bpf/bpf.h | 24 ++++++++++++++++++++++++ tools/lib/bpf/libbpf.map | 1 + 3 files changed, 42 insertions(+) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index b133acfe08fb..54978198147c 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -1289,3 +1289,20 @@ int bpf_prog_bind_map(int prog_fd, int map_fd, ret = sys_bpf(BPF_PROG_BIND_MAP, &attr, attr_sz); return libbpf_err_errno(ret); } + +int bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts) +{ + const size_t attr_sz = offsetofend(union bpf_attr, token_create); + union bpf_attr attr; + int fd; + + if (!OPTS_VALID(opts, bpf_token_create_opts)) + return libbpf_err(-EINVAL); + + memset(&attr, 0, attr_sz); + attr.token_create.bpffs_fd = bpffs_fd; + attr.token_create.flags = OPTS_GET(opts, flags, 0); + + fd = sys_bpf_fd(BPF_TOKEN_CREATE, &attr, attr_sz); + return libbpf_err_errno(fd); +} diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 53b0bee053ad..0a9f456698fe 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -642,6 +642,30 @@ struct bpf_test_run_opts { LIBBPF_API int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts); +struct bpf_token_create_opts { + size_t sz; /* size of this struct for forward/backward compatibility */ + __u32 flags; + size_t :0; +}; +#define bpf_token_create_opts__last_field flags + +/** + * @brief **bpf_token_create()** creates a new instance of BPF token derived + * from specified BPF FS mount point. + * + * BPF token created with this API can be passed to bpf() syscall for + * commands like BPF_PROG_LOAD, BPF_MAP_CREATE, etc. + * + * @param bpffs_fd FD for BPF FS instance from which to derive a BPF token + * instance. + * @param opts optional BPF token creation options, can be NULL + * + * @return BPF token FD > 0, on success; negative error code, otherwise (errno + * is also set to the error code) + */ +LIBBPF_API int bpf_token_create(int bpffs_fd, + struct bpf_token_create_opts *opts); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 91c5aef7dae7..d9e1f57534fa 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -411,4 +411,5 @@ LIBBPF_1.3.0 { } LIBBPF_1.2.0; LIBBPF_1.4.0 { + bpf_token_create; } LIBBPF_1.3.0; From 364f848375af311150210a1ad3c5bcb800b65b48 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:10 -0800 Subject: [PATCH 0276/2255] libbpf: Add BPF token support to bpf_map_create() API Add ability to provide token_fd for BPF_MAP_CREATE command through bpf_map_create() API. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-14-andrii@kernel.org --- tools/lib/bpf/bpf.c | 5 +++-- tools/lib/bpf/bpf.h | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 54978198147c..9b11ca25e977 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -169,8 +169,7 @@ int bpf_map_create(enum bpf_map_type map_type, __u32 max_entries, const struct bpf_map_create_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, - value_type_btf_obj_fd); + const size_t attr_sz = offsetofend(union bpf_attr, map_token_fd); union bpf_attr attr; int fd; @@ -200,6 +199,8 @@ int bpf_map_create(enum bpf_map_type map_type, attr.numa_node = OPTS_GET(opts, numa_node, 0); attr.map_ifindex = OPTS_GET(opts, map_ifindex, 0); + attr.map_token_fd = OPTS_GET(opts, token_fd, 0); + fd = sys_bpf_fd(BPF_MAP_CREATE, &attr, attr_sz); return libbpf_err_errno(fd); } diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 0a9f456698fe..6af90d50960b 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -52,9 +52,11 @@ struct bpf_map_create_opts { __u32 numa_node; __u32 map_ifindex; __s32 value_type_btf_obj_fd; - size_t:0; + + __u32 token_fd; + size_t :0; }; -#define bpf_map_create_opts__last_field value_type_btf_obj_fd +#define bpf_map_create_opts__last_field token_fd LIBBPF_API int bpf_map_create(enum bpf_map_type map_type, const char *map_name, From a3d63e85253b6c9b6aa34b99208e835358a91320 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:11 -0800 Subject: [PATCH 0277/2255] libbpf: Add BPF token support to bpf_btf_load() API Allow user to specify token_fd for bpf_btf_load() API that wraps kernel's BPF_BTF_LOAD command. This allows loading BTF from unprivileged process as long as it has BPF token allowing BPF_BTF_LOAD command, which can be created and delegated by privileged process. Wire through new btf_flags as well, so that user can provide BPF_F_TOKEN_FD flag, if necessary. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-15-andrii@kernel.org --- tools/lib/bpf/bpf.c | 6 +++++- tools/lib/bpf/bpf.h | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 9b11ca25e977..9ad7e39fed20 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -1185,7 +1185,7 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd) int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, btf_log_true_size); + const size_t attr_sz = offsetofend(union bpf_attr, btf_token_fd); union bpf_attr attr; char *log_buf; size_t log_size; @@ -1210,6 +1210,10 @@ int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts attr.btf = ptr_to_u64(btf_data); attr.btf_size = btf_size; + + attr.btf_flags = OPTS_GET(opts, btf_flags, 0); + attr.btf_token_fd = OPTS_GET(opts, token_fd, 0); + /* log_level == 0 and log_buf != NULL means "try loading without * log_buf, but retry with log_buf and log_level=1 on error", which is * consistent across low-level and high-level BTF and program loading diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 6af90d50960b..7fe28330c36e 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -134,9 +134,12 @@ struct bpf_btf_load_opts { * If kernel doesn't support this feature, log_size is left unchanged. */ __u32 log_true_size; + + __u32 btf_flags; + __u32 token_fd; size_t :0; }; -#define bpf_btf_load_opts__last_field log_true_size +#define bpf_btf_load_opts__last_field token_fd LIBBPF_API int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts *opts); From 404cbc149c3866e6ec2bfe1bce52c8864e1f81fc Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:12 -0800 Subject: [PATCH 0278/2255] libbpf: Add BPF token support to bpf_prog_load() API Wire through token_fd into bpf_prog_load(). Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-16-andrii@kernel.org --- tools/lib/bpf/bpf.c | 3 ++- tools/lib/bpf/bpf.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 9ad7e39fed20..42cde79a67c7 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -235,7 +235,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns, size_t insn_cnt, struct bpf_prog_load_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, log_true_size); + const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd); void *finfo = NULL, *linfo = NULL; const char *func_info, *line_info; __u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd; @@ -264,6 +264,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type, attr.prog_flags = OPTS_GET(opts, prog_flags, 0); attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0); attr.kern_version = OPTS_GET(opts, kern_version, 0); + attr.prog_token_fd = OPTS_GET(opts, token_fd, 0); if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME)) libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name)); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 7fe28330c36e..1441f642c563 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -106,9 +106,10 @@ struct bpf_prog_load_opts { * If kernel doesn't support this feature, log_size is left unchanged. */ __u32 log_true_size; + __u32 token_fd; size_t :0; }; -#define bpf_prog_load_opts__last_field log_true_size +#define bpf_prog_load_opts__last_field token_fd LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type, const char *prog_name, const char *license, From fcb9597ff7d1f7c772c1237dd2d04dd44e622501 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:13 -0800 Subject: [PATCH 0279/2255] selftests/bpf: Add BPF token-enabled tests Add a selftest that attempts to conceptually replicate intended BPF token use cases inside user namespaced container. Child process is forked. It is then put into its own userns and mountns. Child creates BPF FS context object. This ensures child userns is captured as the owning userns for this instance of BPF FS. Given setting delegation mount options is privileged operation, we ensure that child cannot set them. This context is passed back to privileged parent process through Unix socket, where parent sets up delegation options, creates, and mounts it as a detached mount. This mount FD is passed back to the child to be used for BPF token creation, which allows otherwise privileged BPF operations to succeed inside userns. We validate that all of token-enabled privileged commands (BPF_BTF_LOAD, BPF_MAP_CREATE, and BPF_PROG_LOAD) work as intended. They should only succeed inside the userns if a) BPF token is provided with proper allowed sets of commands and types; and b) namespaces CAP_BPF and other privileges are set. Lacking a) or b) should lead to -EPERM failures. Based on suggested workflow by Christian Brauner ([0]). [0] https://lore.kernel.org/bpf/20230704-hochverdient-lehne-eeb9eeef785e@brauner/ Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-17-andrii@kernel.org --- .../testing/selftests/bpf/prog_tests/token.c | 683 ++++++++++++++++++ 1 file changed, 683 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/token.c diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c new file mode 100644 index 000000000000..5394a0c880a9 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/token.c @@ -0,0 +1,683 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#define _GNU_SOURCE +#include +#include +#include "cap_helpers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline int sys_mount(const char *dev_name, const char *dir_name, + const char *type, unsigned long flags, + const void *data) +{ + return syscall(__NR_mount, dev_name, dir_name, type, flags, data); +} + +static inline int sys_fsopen(const char *fsname, unsigned flags) +{ + return syscall(__NR_fsopen, fsname, flags); +} + +static inline int sys_fspick(int dfd, const char *path, unsigned flags) +{ + return syscall(__NR_fspick, dfd, path, flags); +} + +static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key, const void *val, int aux) +{ + return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux); +} + +static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags) +{ + return syscall(__NR_fsmount, fs_fd, flags, ms_flags); +} + +static int drop_priv_caps(__u64 *old_caps) +{ + return cap_disable_effective((1ULL << CAP_BPF) | + (1ULL << CAP_PERFMON) | + (1ULL << CAP_NET_ADMIN) | + (1ULL << CAP_SYS_ADMIN), old_caps); +} + +static int restore_priv_caps(__u64 old_caps) +{ + return cap_enable_effective(old_caps, NULL); +} + +static int set_delegate_mask(int fs_fd, const char *key, __u64 mask) +{ + char buf[32]; + int err; + + snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask); + err = sys_fsconfig(fs_fd, FSCONFIG_SET_STRING, key, + mask == ~0ULL ? "any" : buf, 0); + if (err < 0) + err = -errno; + return err; +} + +#define zclose(fd) do { if (fd >= 0) close(fd); fd = -1; } while (0) + +struct bpffs_opts { + __u64 cmds; + __u64 maps; + __u64 progs; + __u64 attachs; +}; + +static int create_bpffs_fd(void) +{ + int fs_fd; + + /* create VFS context */ + fs_fd = sys_fsopen("bpf", 0); + ASSERT_GE(fs_fd, 0, "fs_fd"); + + return fs_fd; +} + +static int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts) +{ + int mnt_fd, err; + + /* set up token delegation mount options */ + err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds); + if (!ASSERT_OK(err, "fs_cfg_cmds")) + return err; + err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps); + if (!ASSERT_OK(err, "fs_cfg_maps")) + return err; + err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs); + if (!ASSERT_OK(err, "fs_cfg_progs")) + return err; + err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs); + if (!ASSERT_OK(err, "fs_cfg_attachs")) + return err; + + /* instantiate FS object */ + err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + if (err < 0) + return -errno; + + /* create O_PATH fd for detached mount */ + mnt_fd = sys_fsmount(fs_fd, 0, 0); + if (err < 0) + return -errno; + + return mnt_fd; +} + +/* send FD over Unix domain (AF_UNIX) socket */ +static int sendfd(int sockfd, int fd) +{ + struct msghdr msg = {}; + struct cmsghdr *cmsg; + int fds[1] = { fd }, err; + char iobuf[1]; + struct iovec io = { + .iov_base = iobuf, + .iov_len = sizeof(iobuf), + }; + union { + char buf[CMSG_SPACE(sizeof(fds))]; + struct cmsghdr align; + } u; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fds)); + memcpy(CMSG_DATA(cmsg), fds, sizeof(fds)); + + err = sendmsg(sockfd, &msg, 0); + if (err < 0) + err = -errno; + if (!ASSERT_EQ(err, 1, "sendmsg")) + return -EINVAL; + + return 0; +} + +/* receive FD over Unix domain (AF_UNIX) socket */ +static int recvfd(int sockfd, int *fd) +{ + struct msghdr msg = {}; + struct cmsghdr *cmsg; + int fds[1], err; + char iobuf[1]; + struct iovec io = { + .iov_base = iobuf, + .iov_len = sizeof(iobuf), + }; + union { + char buf[CMSG_SPACE(sizeof(fds))]; + struct cmsghdr align; + } u; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + + err = recvmsg(sockfd, &msg, 0); + if (err < 0) + err = -errno; + if (!ASSERT_EQ(err, 1, "recvmsg")) + return -EINVAL; + + cmsg = CMSG_FIRSTHDR(&msg); + if (!ASSERT_OK_PTR(cmsg, "cmsg_null") || + !ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(fds)), "cmsg_len") || + !ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET, "cmsg_level") || + !ASSERT_EQ(cmsg->cmsg_type, SCM_RIGHTS, "cmsg_type")) + return -EINVAL; + + memcpy(fds, CMSG_DATA(cmsg), sizeof(fds)); + *fd = fds[0]; + + return 0; +} + +static ssize_t write_nointr(int fd, const void *buf, size_t count) +{ + ssize_t ret; + + do { + ret = write(fd, buf, count); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +static int write_file(const char *path, const void *buf, size_t count) +{ + int fd; + ssize_t ret; + + fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); + if (fd < 0) + return -1; + + ret = write_nointr(fd, buf, count); + close(fd); + if (ret < 0 || (size_t)ret != count) + return -1; + + return 0; +} + +static int create_and_enter_userns(void) +{ + uid_t uid; + gid_t gid; + char map[100]; + + uid = getuid(); + gid = getgid(); + + if (unshare(CLONE_NEWUSER)) + return -1; + + if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) && + errno != ENOENT) + return -1; + + snprintf(map, sizeof(map), "0 %d 1", uid); + if (write_file("/proc/self/uid_map", map, strlen(map))) + return -1; + + + snprintf(map, sizeof(map), "0 %d 1", gid); + if (write_file("/proc/self/gid_map", map, strlen(map))) + return -1; + + if (setgid(0)) + return -1; + + if (setuid(0)) + return -1; + + return 0; +} + +typedef int (*child_callback_fn)(int); + +static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callback) +{ + LIBBPF_OPTS(bpf_map_create_opts, map_opts); + int mnt_fd = -1, fs_fd = -1, err = 0, bpffs_fd = -1; + + /* setup userns with root mappings */ + err = create_and_enter_userns(); + if (!ASSERT_OK(err, "create_and_enter_userns")) + goto cleanup; + + /* setup mountns to allow creating BPF FS (fsopen("bpf")) from unpriv process */ + err = unshare(CLONE_NEWNS); + if (!ASSERT_OK(err, "create_mountns")) + goto cleanup; + + err = sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); + if (!ASSERT_OK(err, "remount_root")) + goto cleanup; + + fs_fd = create_bpffs_fd(); + if (!ASSERT_GE(fs_fd, 0, "create_bpffs_fd")) { + err = -EINVAL; + goto cleanup; + } + + /* ensure unprivileged child cannot set delegation options */ + err = set_delegate_mask(fs_fd, "delegate_cmds", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm"); + err = set_delegate_mask(fs_fd, "delegate_maps", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_maps_eperm"); + err = set_delegate_mask(fs_fd, "delegate_progs", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_progs_eperm"); + err = set_delegate_mask(fs_fd, "delegate_attachs", 0x1); + ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm"); + + /* pass BPF FS context object to parent */ + err = sendfd(sock_fd, fs_fd); + if (!ASSERT_OK(err, "send_fs_fd")) + goto cleanup; + zclose(fs_fd); + + /* avoid mucking around with mount namespaces and mounting at + * well-known path, just get detach-mounted BPF FS fd back from parent + */ + err = recvfd(sock_fd, &mnt_fd); + if (!ASSERT_OK(err, "recv_mnt_fd")) + goto cleanup; + + /* try to fspick() BPF FS and try to add some delegation options */ + fs_fd = sys_fspick(mnt_fd, "", FSPICK_EMPTY_PATH); + if (!ASSERT_GE(fs_fd, 0, "bpffs_fspick")) { + err = -EINVAL; + goto cleanup; + } + + /* ensure unprivileged child cannot reconfigure to set delegation options */ + err = set_delegate_mask(fs_fd, "delegate_cmds", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + err = set_delegate_mask(fs_fd, "delegate_maps", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_maps_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + err = set_delegate_mask(fs_fd, "delegate_progs", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_progs_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + err = set_delegate_mask(fs_fd, "delegate_attachs", ~0ULL); + if (!ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm_reconfig")) { + err = -EINVAL; + goto cleanup; + } + zclose(fs_fd); + + bpffs_fd = openat(mnt_fd, ".", 0, O_RDWR); + if (!ASSERT_GE(bpffs_fd, 0, "bpffs_open")) { + err = -EINVAL; + goto cleanup; + } + + /* do custom test logic with customly set up BPF FS instance */ + err = callback(bpffs_fd); + if (!ASSERT_OK(err, "test_callback")) + goto cleanup; + + err = 0; +cleanup: + zclose(sock_fd); + zclose(mnt_fd); + zclose(fs_fd); + zclose(bpffs_fd); + + exit(-err); +} + +static int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + + return -1; + } + + if (!WIFEXITED(status)) + return -1; + + return WEXITSTATUS(status); +} + +static void parent(int child_pid, struct bpffs_opts *bpffs_opts, int sock_fd) +{ + int fs_fd = -1, mnt_fd = -1, err; + + err = recvfd(sock_fd, &fs_fd); + if (!ASSERT_OK(err, "recv_bpffs_fd")) + goto cleanup; + + mnt_fd = materialize_bpffs_fd(fs_fd, bpffs_opts); + if (!ASSERT_GE(mnt_fd, 0, "materialize_bpffs_fd")) { + err = -EINVAL; + goto cleanup; + } + zclose(fs_fd); + + /* pass BPF FS context object to parent */ + err = sendfd(sock_fd, mnt_fd); + if (!ASSERT_OK(err, "send_mnt_fd")) + goto cleanup; + zclose(mnt_fd); + + err = wait_for_pid(child_pid); + ASSERT_OK(err, "waitpid_child"); + +cleanup: + zclose(sock_fd); + zclose(fs_fd); + zclose(mnt_fd); + + if (child_pid > 0) + (void)kill(child_pid, SIGKILL); +} + +static void subtest_userns(struct bpffs_opts *bpffs_opts, child_callback_fn cb) +{ + int sock_fds[2] = { -1, -1 }; + int child_pid = 0, err; + + err = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds); + if (!ASSERT_OK(err, "socketpair")) + goto cleanup; + + child_pid = fork(); + if (!ASSERT_GE(child_pid, 0, "fork")) + goto cleanup; + + if (child_pid == 0) { + zclose(sock_fds[0]); + return child(sock_fds[1], bpffs_opts, cb); + + } else { + zclose(sock_fds[1]); + return parent(child_pid, bpffs_opts, sock_fds[0]); + } + +cleanup: + zclose(sock_fds[0]); + zclose(sock_fds[1]); + if (child_pid > 0) + (void)kill(child_pid, SIGKILL); +} + +static int userns_map_create(int mnt_fd) +{ + LIBBPF_OPTS(bpf_map_create_opts, map_opts); + int err, token_fd = -1, map_fd = -1; + __u64 old_caps = 0; + + /* create BPF token from BPF FS mount */ + token_fd = bpf_token_create(mnt_fd, NULL); + if (!ASSERT_GT(token_fd, 0, "token_create")) { + err = -EINVAL; + goto cleanup; + } + + /* while inside non-init userns, we need both a BPF token *and* + * CAP_BPF inside current userns to create privileged map; let's test + * that neither BPF token alone nor namespaced CAP_BPF is sufficient + */ + err = drop_priv_caps(&old_caps); + if (!ASSERT_OK(err, "drop_caps")) + goto cleanup; + + /* no token, no CAP_BPF -> fail */ + map_opts.map_flags = 0; + map_opts.token_fd = 0; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "wo_token_wo_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_LT(map_fd, 0, "stack_map_wo_token_wo_cap_bpf_should_fail")) { + err = -EINVAL; + goto cleanup; + } + + /* token without CAP_BPF -> fail */ + map_opts.map_flags = BPF_F_TOKEN_FD; + map_opts.token_fd = token_fd; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "w_token_wo_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_LT(map_fd, 0, "stack_map_w_token_wo_cap_bpf_should_fail")) { + err = -EINVAL; + goto cleanup; + } + + /* get back effective local CAP_BPF (and CAP_SYS_ADMIN) */ + err = restore_priv_caps(old_caps); + if (!ASSERT_OK(err, "restore_caps")) + goto cleanup; + + /* CAP_BPF without token -> fail */ + map_opts.map_flags = 0; + map_opts.token_fd = 0; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "wo_token_w_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_LT(map_fd, 0, "stack_map_wo_token_w_cap_bpf_should_fail")) { + err = -EINVAL; + goto cleanup; + } + + /* finally, namespaced CAP_BPF + token -> success */ + map_opts.map_flags = BPF_F_TOKEN_FD; + map_opts.token_fd = token_fd; + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "w_token_w_bpf", 0, 8, 1, &map_opts); + if (!ASSERT_GT(map_fd, 0, "stack_map_w_token_w_cap_bpf")) { + err = -EINVAL; + goto cleanup; + } + +cleanup: + zclose(token_fd); + zclose(map_fd); + return err; +} + +static int userns_btf_load(int mnt_fd) +{ + LIBBPF_OPTS(bpf_btf_load_opts, btf_opts); + int err, token_fd = -1, btf_fd = -1; + const void *raw_btf_data; + struct btf *btf = NULL; + __u32 raw_btf_size; + __u64 old_caps = 0; + + /* create BPF token from BPF FS mount */ + token_fd = bpf_token_create(mnt_fd, NULL); + if (!ASSERT_GT(token_fd, 0, "token_create")) { + err = -EINVAL; + goto cleanup; + } + + /* while inside non-init userns, we need both a BPF token *and* + * CAP_BPF inside current userns to create privileged map; let's test + * that neither BPF token alone nor namespaced CAP_BPF is sufficient + */ + err = drop_priv_caps(&old_caps); + if (!ASSERT_OK(err, "drop_caps")) + goto cleanup; + + /* setup a trivial BTF data to load to the kernel */ + btf = btf__new_empty(); + if (!ASSERT_OK_PTR(btf, "empty_btf")) + goto cleanup; + + ASSERT_GT(btf__add_int(btf, "int", 4, 0), 0, "int_type"); + + raw_btf_data = btf__raw_data(btf, &raw_btf_size); + if (!ASSERT_OK_PTR(raw_btf_data, "raw_btf_data")) + goto cleanup; + + /* no token + no CAP_BPF -> failure */ + btf_opts.btf_flags = 0; + btf_opts.token_fd = 0; + btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts); + if (!ASSERT_LT(btf_fd, 0, "no_token_no_cap_should_fail")) + goto cleanup; + + /* token + no CAP_BPF -> failure */ + btf_opts.btf_flags = BPF_F_TOKEN_FD; + btf_opts.token_fd = token_fd; + btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts); + if (!ASSERT_LT(btf_fd, 0, "token_no_cap_should_fail")) + goto cleanup; + + /* get back effective local CAP_BPF (and CAP_SYS_ADMIN) */ + err = restore_priv_caps(old_caps); + if (!ASSERT_OK(err, "restore_caps")) + goto cleanup; + + /* token + CAP_BPF -> success */ + btf_opts.btf_flags = BPF_F_TOKEN_FD; + btf_opts.token_fd = token_fd; + btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts); + if (!ASSERT_GT(btf_fd, 0, "token_and_cap_success")) + goto cleanup; + + err = 0; +cleanup: + btf__free(btf); + zclose(btf_fd); + zclose(token_fd); + return err; +} + +static int userns_prog_load(int mnt_fd) +{ + LIBBPF_OPTS(bpf_prog_load_opts, prog_opts); + int err, token_fd = -1, prog_fd = -1; + struct bpf_insn insns[] = { + /* bpf_jiffies64() requires CAP_BPF */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_jiffies64), + /* bpf_get_current_task() requires CAP_PERFMON */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_current_task), + /* r0 = 0; exit; */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + size_t insn_cnt = ARRAY_SIZE(insns); + __u64 old_caps = 0; + + /* create BPF token from BPF FS mount */ + token_fd = bpf_token_create(mnt_fd, NULL); + if (!ASSERT_GT(token_fd, 0, "token_create")) { + err = -EINVAL; + goto cleanup; + } + + /* validate we can successfully load BPF program with token; this + * being XDP program (CAP_NET_ADMIN) using bpf_jiffies64() (CAP_BPF) + * and bpf_get_current_task() (CAP_PERFMON) helpers validates we have + * BPF token wired properly in a bunch of places in the kernel + */ + prog_opts.prog_flags = BPF_F_TOKEN_FD; + prog_opts.token_fd = token_fd; + prog_opts.expected_attach_type = BPF_XDP; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_GT(prog_fd, 0, "prog_fd")) { + err = -EPERM; + goto cleanup; + } + + /* no token + caps -> failure */ + prog_opts.prog_flags = 0; + prog_opts.token_fd = 0; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) { + err = -EPERM; + goto cleanup; + } + + err = drop_priv_caps(&old_caps); + if (!ASSERT_OK(err, "drop_caps")) + goto cleanup; + + /* no caps + token -> failure */ + prog_opts.prog_flags = BPF_F_TOKEN_FD; + prog_opts.token_fd = token_fd; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) { + err = -EPERM; + goto cleanup; + } + + /* no caps + no token -> definitely a failure */ + prog_opts.prog_flags = 0; + prog_opts.token_fd = 0; + prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL", + insns, insn_cnt, &prog_opts); + if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) { + err = -EPERM; + goto cleanup; + } + + err = 0; +cleanup: + zclose(prog_fd); + zclose(token_fd); + return err; +} + +void test_token(void) +{ + if (test__start_subtest("map_token")) { + struct bpffs_opts opts = { + .cmds = 1ULL << BPF_MAP_CREATE, + .maps = 1ULL << BPF_MAP_TYPE_STACK, + }; + + subtest_userns(&opts, userns_map_create); + } + if (test__start_subtest("btf_token")) { + struct bpffs_opts opts = { + .cmds = 1ULL << BPF_BTF_LOAD, + }; + + subtest_userns(&opts, userns_btf_load); + } + if (test__start_subtest("prog_token")) { + struct bpffs_opts opts = { + .cmds = 1ULL << BPF_PROG_LOAD, + .progs = 1ULL << BPF_PROG_TYPE_XDP, + .attachs = 1ULL << BPF_XDP, + }; + + subtest_userns(&opts, userns_prog_load); + } +} From 0054493e5141b16e316b8c52d6aa534397e48b6c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:14 -0800 Subject: [PATCH 0280/2255] bpf,selinux: Allocate bpf_security_struct per BPF token Utilize newly added bpf_token_create/bpf_token_free LSM hooks to allocate struct bpf_security_struct for each BPF token object in SELinux. This just follows similar pattern for BPF prog and map. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-18-andrii@kernel.org --- security/selinux/hooks.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3d336a7952f7..8dd506ab9b1f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6965,6 +6965,29 @@ static void selinux_bpf_prog_free(struct bpf_prog *prog) prog->aux->security = NULL; kfree(bpfsec); } + +static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, + struct path *path) +{ + struct bpf_security_struct *bpfsec; + + bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); + if (!bpfsec) + return -ENOMEM; + + bpfsec->sid = current_sid(); + token->security = bpfsec; + + return 0; +} + +static void selinux_bpf_token_free(struct bpf_token *token) +{ + struct bpf_security_struct *bpfsec = token->security; + + token->security = NULL; + kfree(bpfsec); +} #endif struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { @@ -7328,6 +7351,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), + LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free), #endif #ifdef CONFIG_PERF_EVENTS @@ -7386,6 +7410,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { #ifdef CONFIG_BPF_SYSCALL LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create), LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), + LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create), #endif #ifdef CONFIG_PERF_EVENTS LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), From aeaa97b006ddc7a8bf13e4adfdd02b3526f648a7 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:15 -0800 Subject: [PATCH 0281/2255] bpf: Fail BPF_TOKEN_CREATE if no delegation option was set on BPF FS It's quite confusing in practice when it's possible to successfully create a BPF token from BPF FS that didn't have any of delegate_xxx mount options set up. While it's not wrong, it's actually more meaningful to reject BPF_TOKEN_CREATE with specific error code (-ENOENT) to let user-space know that no token delegation is setup up. So, instead of creating empty BPF token that will be always ignored because it doesn't have any of the allow_xxx bits set, reject it with -ENOENT. If we ever need empty BPF token to be possible, we can support that with extra flag passed into BPF_TOKEN_CREATE. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: Christian Brauner Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-19-andrii@kernel.org --- kernel/bpf/token.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index 64c568f47f69..0bca93b60c43 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -162,6 +162,15 @@ int bpf_token_create(union bpf_attr *attr) goto out_path; } + mnt_opts = path.dentry->d_sb->s_fs_info; + if (mnt_opts->delegate_cmds == 0 && + mnt_opts->delegate_maps == 0 && + mnt_opts->delegate_progs == 0 && + mnt_opts->delegate_attachs == 0) { + err = -ENOENT; /* no BPF token delegation is set up */ + goto out_path; + } + mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask()); inode = bpf_get_inode(path.mnt->mnt_sb, NULL, mode); if (IS_ERR(inode)) { @@ -191,7 +200,6 @@ int bpf_token_create(union bpf_attr *attr) /* remember bpffs owning userns for future ns_capable() checks */ token->userns = get_user_ns(userns); - mnt_opts = path.dentry->d_sb->s_fs_info; token->allowed_cmds = mnt_opts->delegate_cmds; token->allowed_maps = mnt_opts->delegate_maps; token->allowed_progs = mnt_opts->delegate_progs; From 6c1752e0b6ca8c7021d6da3926738d8d88f601a9 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:16 -0800 Subject: [PATCH 0282/2255] bpf: Support symbolic BPF FS delegation mount options Besides already supported special "any" value and hex bit mask, support string-based parsing of delegation masks based on exact enumerator names. Utilize BTF information of `enum bpf_cmd`, `enum bpf_map_type`, `enum bpf_prog_type`, and `enum bpf_attach_type` types to find supported symbolic names (ignoring __MAX_xxx guard values and stripping repetitive prefixes like BPF_ for cmd and attach types, BPF_MAP_TYPE_ for maps, and BPF_PROG_TYPE_ for prog types). The case doesn't matter, but it is normalized to lower case in mount option output. So "PROG_LOAD", "prog_load", and "MAP_create" are all valid values to specify for delegate_cmds options, "array" is among supported for map types, etc. Besides supporting string values, we also support multiple values specified at the same time, using colon (':') separator. There are corresponding changes on bpf_show_options side to use known values to print them in human-readable format, falling back to hex mask printing, if there are any unrecognized bits. This shouldn't be necessary when enum BTF information is present, but in general we should always be able to fall back to this even if kernel was built without BTF. As mentioned, emitted symbolic names are normalized to be all lower case. Example below shows various ways to specify delegate_cmds options through mount command and how mount options are printed back: 12/14 14:39:07.604 vmuser@archvm:~/local/linux/tools/testing/selftests/bpf $ mount | rg token $ sudo mkdir -p /sys/fs/bpf/token $ sudo mount -t bpf bpffs /sys/fs/bpf/token \ -o delegate_cmds=prog_load:MAP_CREATE \ -o delegate_progs=kprobe \ -o delegate_attachs=xdp $ mount | grep token bpffs on /sys/fs/bpf/token type bpf (rw,relatime,delegate_cmds=map_create:prog_load,delegate_progs=kprobe,delegate_attachs=xdp) Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-20-andrii@kernel.org --- kernel/bpf/inode.c | 243 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 208 insertions(+), 35 deletions(-) diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 5fb10da5717f..af5d2ffadd70 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -595,6 +595,136 @@ struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type typ } EXPORT_SYMBOL(bpf_prog_get_type_path); +struct bpffs_btf_enums { + const struct btf *btf; + const struct btf_type *cmd_t; + const struct btf_type *map_t; + const struct btf_type *prog_t; + const struct btf_type *attach_t; +}; + +static int find_bpffs_btf_enums(struct bpffs_btf_enums *info) +{ + const struct btf *btf; + const struct btf_type *t; + const char *name; + int i, n; + + memset(info, 0, sizeof(*info)); + + btf = bpf_get_btf_vmlinux(); + if (IS_ERR(btf)) + return PTR_ERR(btf); + if (!btf) + return -ENOENT; + + info->btf = btf; + + for (i = 1, n = btf_nr_types(btf); i < n; i++) { + t = btf_type_by_id(btf, i); + if (!btf_type_is_enum(t)) + continue; + + name = btf_name_by_offset(btf, t->name_off); + if (!name) + continue; + + if (strcmp(name, "bpf_cmd") == 0) + info->cmd_t = t; + else if (strcmp(name, "bpf_map_type") == 0) + info->map_t = t; + else if (strcmp(name, "bpf_prog_type") == 0) + info->prog_t = t; + else if (strcmp(name, "bpf_attach_type") == 0) + info->attach_t = t; + else + continue; + + if (info->cmd_t && info->map_t && info->prog_t && info->attach_t) + return 0; + } + + return -ESRCH; +} + +static bool find_btf_enum_const(const struct btf *btf, const struct btf_type *enum_t, + const char *prefix, const char *str, int *value) +{ + const struct btf_enum *e; + const char *name; + int i, n, pfx_len = strlen(prefix); + + *value = 0; + + if (!btf || !enum_t) + return false; + + for (i = 0, n = btf_vlen(enum_t); i < n; i++) { + e = &btf_enum(enum_t)[i]; + + name = btf_name_by_offset(btf, e->name_off); + if (!name || strncasecmp(name, prefix, pfx_len) != 0) + continue; + + /* match symbolic name case insensitive and ignoring prefix */ + if (strcasecmp(name + pfx_len, str) == 0) { + *value = e->val; + return true; + } + } + + return false; +} + +static void seq_print_delegate_opts(struct seq_file *m, + const char *opt_name, + const struct btf *btf, + const struct btf_type *enum_t, + const char *prefix, + u64 delegate_msk, u64 any_msk) +{ + const struct btf_enum *e; + bool first = true; + const char *name; + u64 msk; + int i, n, pfx_len = strlen(prefix); + + delegate_msk &= any_msk; /* clear unknown bits */ + + if (delegate_msk == 0) + return; + + seq_printf(m, ",%s", opt_name); + if (delegate_msk == any_msk) { + seq_printf(m, "=any"); + return; + } + + if (btf && enum_t) { + for (i = 0, n = btf_vlen(enum_t); i < n; i++) { + e = &btf_enum(enum_t)[i]; + name = btf_name_by_offset(btf, e->name_off); + if (!name || strncasecmp(name, prefix, pfx_len) != 0) + continue; + msk = 1ULL << e->val; + if (delegate_msk & msk) { + /* emit lower-case name without prefix */ + seq_printf(m, "%c", first ? '=' : ':'); + name += pfx_len; + while (*name) { + seq_printf(m, "%c", tolower(*name)); + name++; + } + + delegate_msk &= ~msk; + first = false; + } + } + } + if (delegate_msk) + seq_printf(m, "%c0x%llx", first ? '=' : ':', delegate_msk); +} + /* * Display the mount options in /proc/mounts. */ @@ -614,29 +744,34 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) if (mode != S_IRWXUGO) seq_printf(m, ",mode=%o", mode); - mask = (1ULL << __MAX_BPF_CMD) - 1; - if ((opts->delegate_cmds & mask) == mask) - seq_printf(m, ",delegate_cmds=any"); - else if (opts->delegate_cmds) - seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); + if (opts->delegate_cmds || opts->delegate_maps || + opts->delegate_progs || opts->delegate_attachs) { + struct bpffs_btf_enums info; - mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; - if ((opts->delegate_maps & mask) == mask) - seq_printf(m, ",delegate_maps=any"); - else if (opts->delegate_maps) - seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); + /* ignore errors, fallback to hex */ + (void)find_bpffs_btf_enums(&info); - mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; - if ((opts->delegate_progs & mask) == mask) - seq_printf(m, ",delegate_progs=any"); - else if (opts->delegate_progs) - seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs); + mask = (1ULL << __MAX_BPF_CMD) - 1; + seq_print_delegate_opts(m, "delegate_cmds", + info.btf, info.cmd_t, "BPF_", + opts->delegate_cmds, mask); + + mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; + seq_print_delegate_opts(m, "delegate_maps", + info.btf, info.map_t, "BPF_MAP_TYPE_", + opts->delegate_maps, mask); + + mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; + seq_print_delegate_opts(m, "delegate_progs", + info.btf, info.prog_t, "BPF_PROG_TYPE_", + opts->delegate_progs, mask); + + mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; + seq_print_delegate_opts(m, "delegate_attachs", + info.btf, info.attach_t, "BPF_", + opts->delegate_attachs, mask); + } - mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; - if ((opts->delegate_attachs & mask) == mask) - seq_printf(m, ",delegate_attachs=any"); - else if (opts->delegate_attachs) - seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs); return 0; } @@ -686,7 +821,6 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) kuid_t uid; kgid_t gid; int opt, err; - u64 msk; opt = fs_parse(fc, bpf_fs_parameters, param, &result); if (opt < 0) { @@ -741,24 +875,63 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) case OPT_DELEGATE_CMDS: case OPT_DELEGATE_MAPS: case OPT_DELEGATE_PROGS: - case OPT_DELEGATE_ATTACHS: - if (strcmp(param->string, "any") == 0) { - msk = ~0ULL; - } else { - err = kstrtou64(param->string, 0, &msk); - if (err) - return err; + case OPT_DELEGATE_ATTACHS: { + struct bpffs_btf_enums info; + const struct btf_type *enum_t; + const char *enum_pfx; + u64 *delegate_msk, msk = 0; + char *p; + int val; + + /* ignore errors, fallback to hex */ + (void)find_bpffs_btf_enums(&info); + + switch (opt) { + case OPT_DELEGATE_CMDS: + delegate_msk = &opts->delegate_cmds; + enum_t = info.cmd_t; + enum_pfx = "BPF_"; + break; + case OPT_DELEGATE_MAPS: + delegate_msk = &opts->delegate_maps; + enum_t = info.map_t; + enum_pfx = "BPF_MAP_TYPE_"; + break; + case OPT_DELEGATE_PROGS: + delegate_msk = &opts->delegate_progs; + enum_t = info.prog_t; + enum_pfx = "BPF_PROG_TYPE_"; + break; + case OPT_DELEGATE_ATTACHS: + delegate_msk = &opts->delegate_attachs; + enum_t = info.attach_t; + enum_pfx = "BPF_"; + break; + default: + return -EINVAL; } + + while ((p = strsep(¶m->string, ":"))) { + if (strcmp(p, "any") == 0) { + msk |= ~0ULL; + } else if (find_btf_enum_const(info.btf, enum_t, enum_pfx, p, &val)) { + msk |= 1ULL << val; + } else { + err = kstrtou64(p, 0, &msk); + if (err) + return err; + } + } + /* Setting delegation mount options requires privileges */ if (msk && !capable(CAP_SYS_ADMIN)) return -EPERM; - switch (opt) { - case OPT_DELEGATE_CMDS: opts->delegate_cmds |= msk; break; - case OPT_DELEGATE_MAPS: opts->delegate_maps |= msk; break; - case OPT_DELEGATE_PROGS: opts->delegate_progs |= msk; break; - case OPT_DELEGATE_ATTACHS: opts->delegate_attachs |= msk; break; - default: return -EINVAL; - } + + *delegate_msk |= msk; + break; + } + default: + /* ignore unknown mount options */ break; } From 0350f9d99ee538f2ccf179f0216e704a5f39b317 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:17 -0800 Subject: [PATCH 0283/2255] selftests/bpf: Utilize string values for delegate_xxx mount options Use both hex-based and string-based way to specify delegate mount options for BPF FS. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-21-andrii@kernel.org --- .../testing/selftests/bpf/prog_tests/token.c | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c index 5394a0c880a9..185ed2f79315 100644 --- a/tools/testing/selftests/bpf/prog_tests/token.c +++ b/tools/testing/selftests/bpf/prog_tests/token.c @@ -55,14 +55,22 @@ static int restore_priv_caps(__u64 old_caps) return cap_enable_effective(old_caps, NULL); } -static int set_delegate_mask(int fs_fd, const char *key, __u64 mask) +static int set_delegate_mask(int fs_fd, const char *key, __u64 mask, const char *mask_str) { char buf[32]; int err; - snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask); + if (!mask_str) { + if (mask == ~0ULL) { + mask_str = "any"; + } else { + snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask); + mask_str = buf; + } + } + err = sys_fsconfig(fs_fd, FSCONFIG_SET_STRING, key, - mask == ~0ULL ? "any" : buf, 0); + mask_str, 0); if (err < 0) err = -errno; return err; @@ -75,6 +83,10 @@ struct bpffs_opts { __u64 maps; __u64 progs; __u64 attachs; + const char *cmds_str; + const char *maps_str; + const char *progs_str; + const char *attachs_str; }; static int create_bpffs_fd(void) @@ -93,16 +105,16 @@ static int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts) int mnt_fd, err; /* set up token delegation mount options */ - err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds); + err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds, opts->cmds_str); if (!ASSERT_OK(err, "fs_cfg_cmds")) return err; - err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps); + err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps, opts->maps_str); if (!ASSERT_OK(err, "fs_cfg_maps")) return err; - err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs); + err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs, opts->progs_str); if (!ASSERT_OK(err, "fs_cfg_progs")) return err; - err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs); + err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs, opts->attachs_str); if (!ASSERT_OK(err, "fs_cfg_attachs")) return err; @@ -284,13 +296,13 @@ static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callba } /* ensure unprivileged child cannot set delegation options */ - err = set_delegate_mask(fs_fd, "delegate_cmds", 0x1); + err = set_delegate_mask(fs_fd, "delegate_cmds", 0x1, NULL); ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm"); - err = set_delegate_mask(fs_fd, "delegate_maps", 0x1); + err = set_delegate_mask(fs_fd, "delegate_maps", 0x1, NULL); ASSERT_EQ(err, -EPERM, "delegate_maps_eperm"); - err = set_delegate_mask(fs_fd, "delegate_progs", 0x1); + err = set_delegate_mask(fs_fd, "delegate_progs", 0x1, NULL); ASSERT_EQ(err, -EPERM, "delegate_progs_eperm"); - err = set_delegate_mask(fs_fd, "delegate_attachs", 0x1); + err = set_delegate_mask(fs_fd, "delegate_attachs", 0x1, NULL); ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm"); /* pass BPF FS context object to parent */ @@ -314,22 +326,22 @@ static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callba } /* ensure unprivileged child cannot reconfigure to set delegation options */ - err = set_delegate_mask(fs_fd, "delegate_cmds", ~0ULL); + err = set_delegate_mask(fs_fd, "delegate_cmds", 0, "any"); if (!ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm_reconfig")) { err = -EINVAL; goto cleanup; } - err = set_delegate_mask(fs_fd, "delegate_maps", ~0ULL); + err = set_delegate_mask(fs_fd, "delegate_maps", 0, "any"); if (!ASSERT_EQ(err, -EPERM, "delegate_maps_eperm_reconfig")) { err = -EINVAL; goto cleanup; } - err = set_delegate_mask(fs_fd, "delegate_progs", ~0ULL); + err = set_delegate_mask(fs_fd, "delegate_progs", 0, "any"); if (!ASSERT_EQ(err, -EPERM, "delegate_progs_eperm_reconfig")) { err = -EINVAL; goto cleanup; } - err = set_delegate_mask(fs_fd, "delegate_attachs", ~0ULL); + err = set_delegate_mask(fs_fd, "delegate_attachs", 0, "any"); if (!ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm_reconfig")) { err = -EINVAL; goto cleanup; @@ -658,8 +670,8 @@ void test_token(void) { if (test__start_subtest("map_token")) { struct bpffs_opts opts = { - .cmds = 1ULL << BPF_MAP_CREATE, - .maps = 1ULL << BPF_MAP_TYPE_STACK, + .cmds_str = "map_create", + .maps_str = "stack", }; subtest_userns(&opts, userns_map_create); @@ -673,9 +685,9 @@ void test_token(void) } if (test__start_subtest("prog_token")) { struct bpffs_opts opts = { - .cmds = 1ULL << BPF_PROG_LOAD, - .progs = 1ULL << BPF_PROG_TYPE_XDP, - .attachs = 1ULL << BPF_XDP, + .cmds_str = "PROG_LOAD", + .progs_str = "XDP", + .attachs_str = "xdp", }; subtest_userns(&opts, userns_prog_load); From ea4d587354eb5e32dfa93cebb055b072f518b193 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:18 -0800 Subject: [PATCH 0284/2255] libbpf: Split feature detectors definitions from cached results Split a list of supported feature detectors with their corresponding callbacks from actual cached supported/missing values. This will allow to have more flexible per-token or per-object feature detectors in subsequent refactorings. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-22-andrii@kernel.org --- tools/lib/bpf/libbpf.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 0569b4973a4f..227f9f63e259 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4958,12 +4958,17 @@ enum kern_feature_result { FEAT_MISSING = 2, }; +struct kern_feature_cache { + enum kern_feature_result res[__FEAT_CNT]; +}; + typedef int (*feature_probe_fn)(void); +static struct kern_feature_cache feature_cache; + static struct kern_feature_desc { const char *desc; feature_probe_fn probe; - enum kern_feature_result res; } feature_probes[__FEAT_CNT] = { [FEAT_PROG_NAME] = { "BPF program name", probe_kern_prog_name, @@ -5031,6 +5036,7 @@ static struct kern_feature_desc { bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) { struct kern_feature_desc *feat = &feature_probes[feat_id]; + struct kern_feature_cache *cache = &feature_cache; int ret; if (obj && obj->gen_loader) @@ -5039,19 +5045,19 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) */ return true; - if (READ_ONCE(feat->res) == FEAT_UNKNOWN) { + if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) { ret = feat->probe(); if (ret > 0) { - WRITE_ONCE(feat->res, FEAT_SUPPORTED); + WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED); } else if (ret == 0) { - WRITE_ONCE(feat->res, FEAT_MISSING); + WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); } else { pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret); - WRITE_ONCE(feat->res, FEAT_MISSING); + WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); } } - return READ_ONCE(feat->res) == FEAT_SUPPORTED; + return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED; } static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) From d6dd1d49367ab03832b3c4b6f8211765d488c82b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:19 -0800 Subject: [PATCH 0285/2255] libbpf: Further decouple feature checking logic from bpf_object Add feat_supported() helper that accepts feature cache instead of bpf_object. This allows low-level code in bpf.c to not know or care about higher-level concept of bpf_object, yet it will be able to utilize custom feature checking in cases where BPF token might influence the outcome. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-23-andrii@kernel.org --- tools/lib/bpf/bpf.c | 6 +++--- tools/lib/bpf/libbpf.c | 22 +++++++++++++++------- tools/lib/bpf/libbpf_internal.h | 5 ++++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 42cde79a67c7..1ebf224b8c56 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -146,7 +146,7 @@ int bump_rlimit_memlock(void) struct rlimit rlim; /* if kernel supports memcg-based accounting, skip bumping RLIMIT_MEMLOCK */ - if (memlock_bumped || kernel_supports(NULL, FEAT_MEMCG_ACCOUNT)) + if (memlock_bumped || feat_supported(NULL, FEAT_MEMCG_ACCOUNT)) return 0; memlock_bumped = true; @@ -181,7 +181,7 @@ int bpf_map_create(enum bpf_map_type map_type, return libbpf_err(-EINVAL); attr.map_type = map_type; - if (map_name && kernel_supports(NULL, FEAT_PROG_NAME)) + if (map_name && feat_supported(NULL, FEAT_PROG_NAME)) libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name)); attr.key_size = key_size; attr.value_size = value_size; @@ -266,7 +266,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type, attr.kern_version = OPTS_GET(opts, kern_version, 0); attr.prog_token_fd = OPTS_GET(opts, token_fd, 0); - if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME)) + if (prog_name && feat_supported(NULL, FEAT_PROG_NAME)) libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name)); attr.license = ptr_to_u64(license); diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 227f9f63e259..4d791660bb56 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -5033,17 +5033,14 @@ static struct kern_feature_desc { }, }; -bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) +bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id) { struct kern_feature_desc *feat = &feature_probes[feat_id]; - struct kern_feature_cache *cache = &feature_cache; int ret; - if (obj && obj->gen_loader) - /* To generate loader program assume the latest kernel - * to avoid doing extra prog_load, map_create syscalls. - */ - return true; + /* assume global feature cache, unless custom one is provided */ + if (!cache) + cache = &feature_cache; if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) { ret = feat->probe(); @@ -5060,6 +5057,17 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED; } +bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) +{ + if (obj && obj->gen_loader) + /* To generate loader program assume the latest kernel + * to avoid doing extra prog_load, map_create syscalls. + */ + return true; + + return feat_supported(NULL, feat_id); +} + static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) { struct bpf_map_info map_info; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 58c547d473e0..622892fc841d 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -361,8 +361,11 @@ enum kern_feature_id { __FEAT_CNT, }; -int probe_memcg_account(void); +struct kern_feature_cache; +bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id); bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id); + +int probe_memcg_account(void); int bump_rlimit_memlock(void); int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz); From 05f9cdd55d61cf9c6283fd3dc0edc7cad09bd7fe Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:20 -0800 Subject: [PATCH 0286/2255] libbpf: Move feature detection code into its own file It's quite a lot of well isolated code, so it seems like a good candidate to move it out of libbpf.c to reduce its size. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-24-andrii@kernel.org --- tools/lib/bpf/Build | 2 +- tools/lib/bpf/elf.c | 2 - tools/lib/bpf/features.c | 463 ++++++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.c | 463 +------------------------------- tools/lib/bpf/libbpf_internal.h | 14 +- tools/lib/bpf/str_error.h | 3 + 6 files changed, 481 insertions(+), 466 deletions(-) create mode 100644 tools/lib/bpf/features.c diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 2d0c282c8588..b6619199a706 100644 --- a/tools/lib/bpf/Build +++ b/tools/lib/bpf/Build @@ -1,4 +1,4 @@ libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \ netlink.o bpf_prog_linfo.o libbpf_probes.o hashmap.o \ btf_dump.o ringbuf.o strset.o linker.o gen_loader.o relo_core.o \ - usdt.o zip.o elf.o + usdt.o zip.o elf.o features.o diff --git a/tools/lib/bpf/elf.c b/tools/lib/bpf/elf.c index b02faec748a5..c92e02394159 100644 --- a/tools/lib/bpf/elf.c +++ b/tools/lib/bpf/elf.c @@ -11,8 +11,6 @@ #include "libbpf_internal.h" #include "str_error.h" -#define STRERR_BUFSIZE 128 - /* A SHT_GNU_versym section holds 16-bit words. This bit is set if * the symbol is hidden and can only be seen when referenced using an * explicit version number. This is a GNU extension. diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c new file mode 100644 index 000000000000..a4664526ab7f --- /dev/null +++ b/tools/lib/bpf/features.c @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include "bpf.h" +#include "libbpf.h" +#include "libbpf_common.h" +#include "libbpf_internal.h" +#include "str_error.h" + +static inline __u64 ptr_to_u64(const void *ptr) +{ + return (__u64)(unsigned long)ptr; +} + +int probe_fd(int fd) +{ + if (fd >= 0) + close(fd); + return fd >= 0; +} + +static int probe_kern_prog_name(void) +{ + const size_t attr_sz = offsetofend(union bpf_attr, prog_name); + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + union bpf_attr attr; + int ret; + + memset(&attr, 0, attr_sz); + attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; + attr.license = ptr_to_u64("GPL"); + attr.insns = ptr_to_u64(insns); + attr.insn_cnt = (__u32)ARRAY_SIZE(insns); + libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name)); + + /* make sure loading with name works */ + ret = sys_bpf_prog_load(&attr, attr_sz, PROG_LOAD_ATTEMPTS); + return probe_fd(ret); +} + +static int probe_kern_global_data(void) +{ + char *cp, errmsg[STRERR_BUFSIZE]; + struct bpf_insn insns[] = { + BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int ret, map, insn_cnt = ARRAY_SIZE(insns); + + map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, NULL); + if (map < 0) { + ret = -errno; + cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); + pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", + __func__, cp, -ret); + return ret; + } + + insns[0].imm = map; + + ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); + close(map); + return probe_fd(ret); +} + +static int probe_kern_btf(void) +{ + static const char strs[] = "\0int"; + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +static int probe_kern_btf_func(void) +{ + static const char strs[] = "\0int\0x\0a"; + /* void x(int a) {} */ + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* FUNC_PROTO */ /* [2] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), + BTF_PARAM_ENC(7, 1), + /* FUNC x */ /* [3] */ + BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +static int probe_kern_btf_func_global(void) +{ + static const char strs[] = "\0int\0x\0a"; + /* static void x(int a) {} */ + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* FUNC_PROTO */ /* [2] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), + BTF_PARAM_ENC(7, 1), + /* FUNC x BTF_FUNC_GLOBAL */ /* [3] */ + BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 2), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +static int probe_kern_btf_datasec(void) +{ + static const char strs[] = "\0x\0.data"; + /* static int a; */ + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* VAR x */ /* [2] */ + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), + BTF_VAR_STATIC, + /* DATASEC val */ /* [3] */ + BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4), + BTF_VAR_SECINFO_ENC(2, 0, 4), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +static int probe_kern_btf_float(void) +{ + static const char strs[] = "\0float"; + __u32 types[] = { + /* float */ + BTF_TYPE_FLOAT_ENC(1, 4), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +static int probe_kern_btf_decl_tag(void) +{ + static const char strs[] = "\0tag"; + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* VAR x */ /* [2] */ + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), + BTF_VAR_STATIC, + /* attr */ + BTF_TYPE_DECL_TAG_ENC(1, 2, -1), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +static int probe_kern_btf_type_tag(void) +{ + static const char strs[] = "\0tag"; + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* attr */ + BTF_TYPE_TYPE_TAG_ENC(1, 1), /* [2] */ + /* ptr */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), /* [3] */ + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +static int probe_kern_array_mmap(void) +{ + LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE); + int fd; + + fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts); + return probe_fd(fd); +} + +static int probe_kern_exp_attach_type(void) +{ + LIBBPF_OPTS(bpf_prog_load_opts, opts, .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE); + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int fd, insn_cnt = ARRAY_SIZE(insns); + + /* use any valid combination of program type and (optional) + * non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS) + * to see if kernel supports expected_attach_type field for + * BPF_PROG_LOAD command + */ + fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, insn_cnt, &opts); + return probe_fd(fd); +} + +static int probe_kern_probe_read_kernel(void) +{ + struct bpf_insn insns[] = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), /* r1 = r10 (fp) */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), /* r1 += -8 */ + BPF_MOV64_IMM(BPF_REG_2, 8), /* r2 = 8 */ + BPF_MOV64_IMM(BPF_REG_3, 0), /* r3 = 0 */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel), + BPF_EXIT_INSN(), + }; + int fd, insn_cnt = ARRAY_SIZE(insns); + + fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, NULL); + return probe_fd(fd); +} + +static int probe_prog_bind_map(void) +{ + char *cp, errmsg[STRERR_BUFSIZE]; + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int ret, map, prog, insn_cnt = ARRAY_SIZE(insns); + + map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, NULL); + if (map < 0) { + ret = -errno; + cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); + pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", + __func__, cp, -ret); + return ret; + } + + prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); + if (prog < 0) { + close(map); + return 0; + } + + ret = bpf_prog_bind_map(prog, map, NULL); + + close(map); + close(prog); + + return ret >= 0; +} + +static int probe_module_btf(void) +{ + static const char strs[] = "\0int"; + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), + }; + struct bpf_btf_info info; + __u32 len = sizeof(info); + char name[16]; + int fd, err; + + fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs)); + if (fd < 0) + return 0; /* BTF not supported at all */ + + memset(&info, 0, sizeof(info)); + info.name = ptr_to_u64(name); + info.name_len = sizeof(name); + + /* check that BPF_OBJ_GET_INFO_BY_FD supports specifying name pointer; + * kernel's module BTF support coincides with support for + * name/name_len fields in struct bpf_btf_info. + */ + err = bpf_btf_get_info_by_fd(fd, &info, &len); + close(fd); + return !err; +} + +static int probe_perf_link(void) +{ + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int prog_fd, link_fd, err; + + prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", + insns, ARRAY_SIZE(insns), NULL); + if (prog_fd < 0) + return -errno; + + /* use invalid perf_event FD to get EBADF, if link is supported; + * otherwise EINVAL should be returned + */ + link_fd = bpf_link_create(prog_fd, -1, BPF_PERF_EVENT, NULL); + err = -errno; /* close() can clobber errno */ + + if (link_fd >= 0) + close(link_fd); + close(prog_fd); + + return link_fd < 0 && err == -EBADF; +} + +static int probe_uprobe_multi_link(void) +{ + LIBBPF_OPTS(bpf_prog_load_opts, load_opts, + .expected_attach_type = BPF_TRACE_UPROBE_MULTI, + ); + LIBBPF_OPTS(bpf_link_create_opts, link_opts); + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int prog_fd, link_fd, err; + unsigned long offset = 0; + + prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", + insns, ARRAY_SIZE(insns), &load_opts); + if (prog_fd < 0) + return -errno; + + /* Creating uprobe in '/' binary should fail with -EBADF. */ + link_opts.uprobe_multi.path = "/"; + link_opts.uprobe_multi.offsets = &offset; + link_opts.uprobe_multi.cnt = 1; + + link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts); + err = -errno; /* close() can clobber errno */ + + if (link_fd >= 0) + close(link_fd); + close(prog_fd); + + return link_fd < 0 && err == -EBADF; +} + +static int probe_kern_bpf_cookie(void) +{ + struct bpf_insn insns[] = { + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie), + BPF_EXIT_INSN(), + }; + int ret, insn_cnt = ARRAY_SIZE(insns); + + ret = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", insns, insn_cnt, NULL); + return probe_fd(ret); +} + +static int probe_kern_btf_enum64(void) +{ + static const char strs[] = "\0enum64"; + __u32 types[] = { + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8), + }; + + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs))); +} + +typedef int (*feature_probe_fn)(void); + +static struct kern_feature_cache feature_cache; + +static struct kern_feature_desc { + const char *desc; + feature_probe_fn probe; +} feature_probes[__FEAT_CNT] = { + [FEAT_PROG_NAME] = { + "BPF program name", probe_kern_prog_name, + }, + [FEAT_GLOBAL_DATA] = { + "global variables", probe_kern_global_data, + }, + [FEAT_BTF] = { + "minimal BTF", probe_kern_btf, + }, + [FEAT_BTF_FUNC] = { + "BTF functions", probe_kern_btf_func, + }, + [FEAT_BTF_GLOBAL_FUNC] = { + "BTF global function", probe_kern_btf_func_global, + }, + [FEAT_BTF_DATASEC] = { + "BTF data section and variable", probe_kern_btf_datasec, + }, + [FEAT_ARRAY_MMAP] = { + "ARRAY map mmap()", probe_kern_array_mmap, + }, + [FEAT_EXP_ATTACH_TYPE] = { + "BPF_PROG_LOAD expected_attach_type attribute", + probe_kern_exp_attach_type, + }, + [FEAT_PROBE_READ_KERN] = { + "bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel, + }, + [FEAT_PROG_BIND_MAP] = { + "BPF_PROG_BIND_MAP support", probe_prog_bind_map, + }, + [FEAT_MODULE_BTF] = { + "module BTF support", probe_module_btf, + }, + [FEAT_BTF_FLOAT] = { + "BTF_KIND_FLOAT support", probe_kern_btf_float, + }, + [FEAT_PERF_LINK] = { + "BPF perf link support", probe_perf_link, + }, + [FEAT_BTF_DECL_TAG] = { + "BTF_KIND_DECL_TAG support", probe_kern_btf_decl_tag, + }, + [FEAT_BTF_TYPE_TAG] = { + "BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag, + }, + [FEAT_MEMCG_ACCOUNT] = { + "memcg-based memory accounting", probe_memcg_account, + }, + [FEAT_BPF_COOKIE] = { + "BPF cookie support", probe_kern_bpf_cookie, + }, + [FEAT_BTF_ENUM64] = { + "BTF_KIND_ENUM64 support", probe_kern_btf_enum64, + }, + [FEAT_SYSCALL_WRAPPER] = { + "Kernel using syscall wrapper", probe_kern_syscall_wrapper, + }, + [FEAT_UPROBE_MULTI_LINK] = { + "BPF multi-uprobe link support", probe_uprobe_multi_link, + }, +}; + +bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id) +{ + struct kern_feature_desc *feat = &feature_probes[feat_id]; + int ret; + + /* assume global feature cache, unless custom one is provided */ + if (!cache) + cache = &feature_cache; + + if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) { + ret = feat->probe(); + if (ret > 0) { + WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED); + } else if (ret == 0) { + WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); + } else { + pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret); + WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); + } + } + + return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED; +} diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4d791660bb56..a2b767bc0c5b 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4596,467 +4596,6 @@ bpf_object__probe_loading(struct bpf_object *obj) return 0; } -static int probe_fd(int fd) -{ - if (fd >= 0) - close(fd); - return fd >= 0; -} - -static int probe_kern_prog_name(void) -{ - const size_t attr_sz = offsetofend(union bpf_attr, prog_name); - struct bpf_insn insns[] = { - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }; - union bpf_attr attr; - int ret; - - memset(&attr, 0, attr_sz); - attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; - attr.license = ptr_to_u64("GPL"); - attr.insns = ptr_to_u64(insns); - attr.insn_cnt = (__u32)ARRAY_SIZE(insns); - libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name)); - - /* make sure loading with name works */ - ret = sys_bpf_prog_load(&attr, attr_sz, PROG_LOAD_ATTEMPTS); - return probe_fd(ret); -} - -static int probe_kern_global_data(void) -{ - char *cp, errmsg[STRERR_BUFSIZE]; - struct bpf_insn insns[] = { - BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), - BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }; - int ret, map, insn_cnt = ARRAY_SIZE(insns); - - map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, NULL); - if (map < 0) { - ret = -errno; - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); - pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", - __func__, cp, -ret); - return ret; - } - - insns[0].imm = map; - - ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); - close(map); - return probe_fd(ret); -} - -static int probe_kern_btf(void) -{ - static const char strs[] = "\0int"; - __u32 types[] = { - /* int */ - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_btf_func(void) -{ - static const char strs[] = "\0int\0x\0a"; - /* void x(int a) {} */ - __u32 types[] = { - /* int */ - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ - /* FUNC_PROTO */ /* [2] */ - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), - BTF_PARAM_ENC(7, 1), - /* FUNC x */ /* [3] */ - BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2), - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_btf_func_global(void) -{ - static const char strs[] = "\0int\0x\0a"; - /* static void x(int a) {} */ - __u32 types[] = { - /* int */ - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ - /* FUNC_PROTO */ /* [2] */ - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), - BTF_PARAM_ENC(7, 1), - /* FUNC x BTF_FUNC_GLOBAL */ /* [3] */ - BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 2), - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_btf_datasec(void) -{ - static const char strs[] = "\0x\0.data"; - /* static int a; */ - __u32 types[] = { - /* int */ - BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ - /* VAR x */ /* [2] */ - BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), - BTF_VAR_STATIC, - /* DATASEC val */ /* [3] */ - BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4), - BTF_VAR_SECINFO_ENC(2, 0, 4), - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_btf_float(void) -{ - static const char strs[] = "\0float"; - __u32 types[] = { - /* float */ - BTF_TYPE_FLOAT_ENC(1, 4), - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_btf_decl_tag(void) -{ - static const char strs[] = "\0tag"; - __u32 types[] = { - /* int */ - BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ - /* VAR x */ /* [2] */ - BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), - BTF_VAR_STATIC, - /* attr */ - BTF_TYPE_DECL_TAG_ENC(1, 2, -1), - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_btf_type_tag(void) -{ - static const char strs[] = "\0tag"; - __u32 types[] = { - /* int */ - BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ - /* attr */ - BTF_TYPE_TYPE_TAG_ENC(1, 1), /* [2] */ - /* ptr */ - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), /* [3] */ - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_array_mmap(void) -{ - LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE); - int fd; - - fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts); - return probe_fd(fd); -} - -static int probe_kern_exp_attach_type(void) -{ - LIBBPF_OPTS(bpf_prog_load_opts, opts, .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE); - struct bpf_insn insns[] = { - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }; - int fd, insn_cnt = ARRAY_SIZE(insns); - - /* use any valid combination of program type and (optional) - * non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS) - * to see if kernel supports expected_attach_type field for - * BPF_PROG_LOAD command - */ - fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, insn_cnt, &opts); - return probe_fd(fd); -} - -static int probe_kern_probe_read_kernel(void) -{ - struct bpf_insn insns[] = { - BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), /* r1 = r10 (fp) */ - BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), /* r1 += -8 */ - BPF_MOV64_IMM(BPF_REG_2, 8), /* r2 = 8 */ - BPF_MOV64_IMM(BPF_REG_3, 0), /* r3 = 0 */ - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel), - BPF_EXIT_INSN(), - }; - int fd, insn_cnt = ARRAY_SIZE(insns); - - fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, NULL); - return probe_fd(fd); -} - -static int probe_prog_bind_map(void) -{ - char *cp, errmsg[STRERR_BUFSIZE]; - struct bpf_insn insns[] = { - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }; - int ret, map, prog, insn_cnt = ARRAY_SIZE(insns); - - map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, NULL); - if (map < 0) { - ret = -errno; - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); - pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", - __func__, cp, -ret); - return ret; - } - - prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); - if (prog < 0) { - close(map); - return 0; - } - - ret = bpf_prog_bind_map(prog, map, NULL); - - close(map); - close(prog); - - return ret >= 0; -} - -static int probe_module_btf(void) -{ - static const char strs[] = "\0int"; - __u32 types[] = { - /* int */ - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), - }; - struct bpf_btf_info info; - __u32 len = sizeof(info); - char name[16]; - int fd, err; - - fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs)); - if (fd < 0) - return 0; /* BTF not supported at all */ - - memset(&info, 0, sizeof(info)); - info.name = ptr_to_u64(name); - info.name_len = sizeof(name); - - /* check that BPF_OBJ_GET_INFO_BY_FD supports specifying name pointer; - * kernel's module BTF support coincides with support for - * name/name_len fields in struct bpf_btf_info. - */ - err = bpf_btf_get_info_by_fd(fd, &info, &len); - close(fd); - return !err; -} - -static int probe_perf_link(void) -{ - struct bpf_insn insns[] = { - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }; - int prog_fd, link_fd, err; - - prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", - insns, ARRAY_SIZE(insns), NULL); - if (prog_fd < 0) - return -errno; - - /* use invalid perf_event FD to get EBADF, if link is supported; - * otherwise EINVAL should be returned - */ - link_fd = bpf_link_create(prog_fd, -1, BPF_PERF_EVENT, NULL); - err = -errno; /* close() can clobber errno */ - - if (link_fd >= 0) - close(link_fd); - close(prog_fd); - - return link_fd < 0 && err == -EBADF; -} - -static int probe_uprobe_multi_link(void) -{ - LIBBPF_OPTS(bpf_prog_load_opts, load_opts, - .expected_attach_type = BPF_TRACE_UPROBE_MULTI, - ); - LIBBPF_OPTS(bpf_link_create_opts, link_opts); - struct bpf_insn insns[] = { - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }; - int prog_fd, link_fd, err; - unsigned long offset = 0; - - prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", - insns, ARRAY_SIZE(insns), &load_opts); - if (prog_fd < 0) - return -errno; - - /* Creating uprobe in '/' binary should fail with -EBADF. */ - link_opts.uprobe_multi.path = "/"; - link_opts.uprobe_multi.offsets = &offset; - link_opts.uprobe_multi.cnt = 1; - - link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts); - err = -errno; /* close() can clobber errno */ - - if (link_fd >= 0) - close(link_fd); - close(prog_fd); - - return link_fd < 0 && err == -EBADF; -} - -static int probe_kern_bpf_cookie(void) -{ - struct bpf_insn insns[] = { - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie), - BPF_EXIT_INSN(), - }; - int ret, insn_cnt = ARRAY_SIZE(insns); - - ret = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", insns, insn_cnt, NULL); - return probe_fd(ret); -} - -static int probe_kern_btf_enum64(void) -{ - static const char strs[] = "\0enum64"; - __u32 types[] = { - BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8), - }; - - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); -} - -static int probe_kern_syscall_wrapper(void); - -enum kern_feature_result { - FEAT_UNKNOWN = 0, - FEAT_SUPPORTED = 1, - FEAT_MISSING = 2, -}; - -struct kern_feature_cache { - enum kern_feature_result res[__FEAT_CNT]; -}; - -typedef int (*feature_probe_fn)(void); - -static struct kern_feature_cache feature_cache; - -static struct kern_feature_desc { - const char *desc; - feature_probe_fn probe; -} feature_probes[__FEAT_CNT] = { - [FEAT_PROG_NAME] = { - "BPF program name", probe_kern_prog_name, - }, - [FEAT_GLOBAL_DATA] = { - "global variables", probe_kern_global_data, - }, - [FEAT_BTF] = { - "minimal BTF", probe_kern_btf, - }, - [FEAT_BTF_FUNC] = { - "BTF functions", probe_kern_btf_func, - }, - [FEAT_BTF_GLOBAL_FUNC] = { - "BTF global function", probe_kern_btf_func_global, - }, - [FEAT_BTF_DATASEC] = { - "BTF data section and variable", probe_kern_btf_datasec, - }, - [FEAT_ARRAY_MMAP] = { - "ARRAY map mmap()", probe_kern_array_mmap, - }, - [FEAT_EXP_ATTACH_TYPE] = { - "BPF_PROG_LOAD expected_attach_type attribute", - probe_kern_exp_attach_type, - }, - [FEAT_PROBE_READ_KERN] = { - "bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel, - }, - [FEAT_PROG_BIND_MAP] = { - "BPF_PROG_BIND_MAP support", probe_prog_bind_map, - }, - [FEAT_MODULE_BTF] = { - "module BTF support", probe_module_btf, - }, - [FEAT_BTF_FLOAT] = { - "BTF_KIND_FLOAT support", probe_kern_btf_float, - }, - [FEAT_PERF_LINK] = { - "BPF perf link support", probe_perf_link, - }, - [FEAT_BTF_DECL_TAG] = { - "BTF_KIND_DECL_TAG support", probe_kern_btf_decl_tag, - }, - [FEAT_BTF_TYPE_TAG] = { - "BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag, - }, - [FEAT_MEMCG_ACCOUNT] = { - "memcg-based memory accounting", probe_memcg_account, - }, - [FEAT_BPF_COOKIE] = { - "BPF cookie support", probe_kern_bpf_cookie, - }, - [FEAT_BTF_ENUM64] = { - "BTF_KIND_ENUM64 support", probe_kern_btf_enum64, - }, - [FEAT_SYSCALL_WRAPPER] = { - "Kernel using syscall wrapper", probe_kern_syscall_wrapper, - }, - [FEAT_UPROBE_MULTI_LINK] = { - "BPF multi-uprobe link support", probe_uprobe_multi_link, - }, -}; - -bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id) -{ - struct kern_feature_desc *feat = &feature_probes[feat_id]; - int ret; - - /* assume global feature cache, unless custom one is provided */ - if (!cache) - cache = &feature_cache; - - if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) { - ret = feat->probe(); - if (ret > 0) { - WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED); - } else if (ret == 0) { - WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); - } else { - pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret); - WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); - } - } - - return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED; -} - bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) { if (obj && obj->gen_loader) @@ -11067,7 +10606,7 @@ static const char *arch_specific_syscall_pfx(void) #endif } -static int probe_kern_syscall_wrapper(void) +int probe_kern_syscall_wrapper(void) { char syscall_name[64]; const char *ksys_pfx; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 622892fc841d..fa25e1232bc8 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -361,10 +361,20 @@ enum kern_feature_id { __FEAT_CNT, }; -struct kern_feature_cache; +enum kern_feature_result { + FEAT_UNKNOWN = 0, + FEAT_SUPPORTED = 1, + FEAT_MISSING = 2, +}; + +struct kern_feature_cache { + enum kern_feature_result res[__FEAT_CNT]; +}; + bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id); bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id); +int probe_kern_syscall_wrapper(void); int probe_memcg_account(void); int bump_rlimit_memlock(void); @@ -626,4 +636,6 @@ int elf_resolve_syms_offsets(const char *binary_path, int cnt, int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern, unsigned long **poffsets, size_t *pcnt); +int probe_fd(int fd); + #endif /* __LIBBPF_LIBBPF_INTERNAL_H */ diff --git a/tools/lib/bpf/str_error.h b/tools/lib/bpf/str_error.h index a139334d57b6..626d7ffb03d6 100644 --- a/tools/lib/bpf/str_error.h +++ b/tools/lib/bpf/str_error.h @@ -2,5 +2,8 @@ #ifndef __LIBBPF_STR_ERROR_H #define __LIBBPF_STR_ERROR_H +#define STRERR_BUFSIZE 128 + char *libbpf_strerror_r(int err, char *dst, int len); + #endif /* __LIBBPF_STR_ERROR_H */ From f3dcee938f485cf403ba2acf1f1548afe637c904 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:21 -0800 Subject: [PATCH 0287/2255] libbpf: Wire up token_fd into feature probing logic Adjust feature probing callbacks to take into account optional token_fd. In unprivileged contexts, some feature detectors would fail to detect kernel support just because BPF program, BPF map, or BTF object can't be loaded due to privileged nature of those operations. So when BPF object is loaded with BPF token, this token should be used for feature probing. This patch is setting support for this scenario, but we don't yet pass non-zero token FD. This will be added in the next patch. We also switched BPF cookie detector from using kprobe program to tracepoint one, as tracepoint is somewhat less dangerous BPF program type and has higher likelihood of being allowed through BPF token in the future. This change has no effect on detection behavior. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-25-andrii@kernel.org --- tools/lib/bpf/bpf.c | 5 +- tools/lib/bpf/features.c | 116 +++++++++++++++++++++----------- tools/lib/bpf/libbpf.c | 4 +- tools/lib/bpf/libbpf_internal.h | 8 ++- tools/lib/bpf/libbpf_probes.c | 11 ++- 5 files changed, 97 insertions(+), 47 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 1ebf224b8c56..97ec005c3c47 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -103,7 +103,7 @@ int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts) * [0] https://lore.kernel.org/bpf/20201201215900.3569844-1-guro@fb.com/ * [1] d05512618056 ("bpf: Add bpf_ktime_get_coarse_ns helper") */ -int probe_memcg_account(void) +int probe_memcg_account(int token_fd) { const size_t attr_sz = offsetofend(union bpf_attr, attach_btf_obj_fd); struct bpf_insn insns[] = { @@ -120,6 +120,9 @@ int probe_memcg_account(void) attr.insns = ptr_to_u64(insns); attr.insn_cnt = insn_cnt; attr.license = ptr_to_u64("GPL"); + attr.prog_token_fd = token_fd; + if (token_fd) + attr.prog_flags |= BPF_F_TOKEN_FD; prog_fd = sys_bpf_fd(BPF_PROG_LOAD, &attr, attr_sz); if (prog_fd >= 0) { diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c index a4664526ab7f..5a5c766bf615 100644 --- a/tools/lib/bpf/features.c +++ b/tools/lib/bpf/features.c @@ -20,7 +20,7 @@ int probe_fd(int fd) return fd >= 0; } -static int probe_kern_prog_name(void) +static int probe_kern_prog_name(int token_fd) { const size_t attr_sz = offsetofend(union bpf_attr, prog_name); struct bpf_insn insns[] = { @@ -35,6 +35,9 @@ static int probe_kern_prog_name(void) attr.license = ptr_to_u64("GPL"); attr.insns = ptr_to_u64(insns); attr.insn_cnt = (__u32)ARRAY_SIZE(insns); + attr.prog_token_fd = token_fd; + if (token_fd) + attr.prog_flags |= BPF_F_TOKEN_FD; libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name)); /* make sure loading with name works */ @@ -42,7 +45,7 @@ static int probe_kern_prog_name(void) return probe_fd(ret); } -static int probe_kern_global_data(void) +static int probe_kern_global_data(int token_fd) { char *cp, errmsg[STRERR_BUFSIZE]; struct bpf_insn insns[] = { @@ -51,9 +54,17 @@ static int probe_kern_global_data(void) BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }; + LIBBPF_OPTS(bpf_map_create_opts, map_opts, + .token_fd = token_fd, + .map_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); + LIBBPF_OPTS(bpf_prog_load_opts, prog_opts, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); int ret, map, insn_cnt = ARRAY_SIZE(insns); - map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, NULL); + map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, &map_opts); if (map < 0) { ret = -errno; cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); @@ -64,12 +75,12 @@ static int probe_kern_global_data(void) insns[0].imm = map; - ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); + ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts); close(map); return probe_fd(ret); } -static int probe_kern_btf(void) +static int probe_kern_btf(int token_fd) { static const char strs[] = "\0int"; __u32 types[] = { @@ -78,10 +89,10 @@ static int probe_kern_btf(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -static int probe_kern_btf_func(void) +static int probe_kern_btf_func(int token_fd) { static const char strs[] = "\0int\0x\0a"; /* void x(int a) {} */ @@ -96,10 +107,10 @@ static int probe_kern_btf_func(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -static int probe_kern_btf_func_global(void) +static int probe_kern_btf_func_global(int token_fd) { static const char strs[] = "\0int\0x\0a"; /* static void x(int a) {} */ @@ -114,10 +125,10 @@ static int probe_kern_btf_func_global(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -static int probe_kern_btf_datasec(void) +static int probe_kern_btf_datasec(int token_fd) { static const char strs[] = "\0x\0.data"; /* static int a; */ @@ -133,10 +144,10 @@ static int probe_kern_btf_datasec(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -static int probe_kern_btf_float(void) +static int probe_kern_btf_float(int token_fd) { static const char strs[] = "\0float"; __u32 types[] = { @@ -145,10 +156,10 @@ static int probe_kern_btf_float(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -static int probe_kern_btf_decl_tag(void) +static int probe_kern_btf_decl_tag(int token_fd) { static const char strs[] = "\0tag"; __u32 types[] = { @@ -162,10 +173,10 @@ static int probe_kern_btf_decl_tag(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -static int probe_kern_btf_type_tag(void) +static int probe_kern_btf_type_tag(int token_fd) { static const char strs[] = "\0tag"; __u32 types[] = { @@ -178,21 +189,28 @@ static int probe_kern_btf_type_tag(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -static int probe_kern_array_mmap(void) +static int probe_kern_array_mmap(int token_fd) { - LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE); + LIBBPF_OPTS(bpf_map_create_opts, opts, + .map_flags = BPF_F_MMAPABLE | (token_fd ? BPF_F_TOKEN_FD : 0), + .token_fd = token_fd, + ); int fd; fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts); return probe_fd(fd); } -static int probe_kern_exp_attach_type(void) +static int probe_kern_exp_attach_type(int token_fd) { - LIBBPF_OPTS(bpf_prog_load_opts, opts, .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE); + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), @@ -208,8 +226,12 @@ static int probe_kern_exp_attach_type(void) return probe_fd(fd); } -static int probe_kern_probe_read_kernel(void) +static int probe_kern_probe_read_kernel(int token_fd) { + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); struct bpf_insn insns[] = { BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), /* r1 = r10 (fp) */ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), /* r1 += -8 */ @@ -220,20 +242,28 @@ static int probe_kern_probe_read_kernel(void) }; int fd, insn_cnt = ARRAY_SIZE(insns); - fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, NULL); + fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); return probe_fd(fd); } -static int probe_prog_bind_map(void) +static int probe_prog_bind_map(int token_fd) { char *cp, errmsg[STRERR_BUFSIZE]; struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }; + LIBBPF_OPTS(bpf_map_create_opts, map_opts, + .token_fd = token_fd, + .map_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); + LIBBPF_OPTS(bpf_prog_load_opts, prog_opts, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); int ret, map, prog, insn_cnt = ARRAY_SIZE(insns); - map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, NULL); + map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, &map_opts); if (map < 0) { ret = -errno; cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); @@ -242,7 +272,7 @@ static int probe_prog_bind_map(void) return ret; } - prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); + prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts); if (prog < 0) { close(map); return 0; @@ -256,7 +286,7 @@ static int probe_prog_bind_map(void) return ret >= 0; } -static int probe_module_btf(void) +static int probe_module_btf(int token_fd) { static const char strs[] = "\0int"; __u32 types[] = { @@ -268,7 +298,7 @@ static int probe_module_btf(void) char name[16]; int fd, err; - fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs)); + fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd); if (fd < 0) return 0; /* BTF not supported at all */ @@ -285,16 +315,20 @@ static int probe_module_btf(void) return !err; } -static int probe_perf_link(void) +static int probe_perf_link(int token_fd) { struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }; + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); int prog_fd, link_fd, err; prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", - insns, ARRAY_SIZE(insns), NULL); + insns, ARRAY_SIZE(insns), &opts); if (prog_fd < 0) return -errno; @@ -311,10 +345,12 @@ static int probe_perf_link(void) return link_fd < 0 && err == -EBADF; } -static int probe_uprobe_multi_link(void) +static int probe_uprobe_multi_link(int token_fd) { LIBBPF_OPTS(bpf_prog_load_opts, load_opts, .expected_attach_type = BPF_TRACE_UPROBE_MULTI, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, ); LIBBPF_OPTS(bpf_link_create_opts, link_opts); struct bpf_insn insns[] = { @@ -344,19 +380,23 @@ static int probe_uprobe_multi_link(void) return link_fd < 0 && err == -EBADF; } -static int probe_kern_bpf_cookie(void) +static int probe_kern_bpf_cookie(int token_fd) { struct bpf_insn insns[] = { BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie), BPF_EXIT_INSN(), }; + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); int ret, insn_cnt = ARRAY_SIZE(insns); - ret = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", insns, insn_cnt, NULL); + ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); return probe_fd(ret); } -static int probe_kern_btf_enum64(void) +static int probe_kern_btf_enum64(int token_fd) { static const char strs[] = "\0enum64"; __u32 types[] = { @@ -364,10 +404,10 @@ static int probe_kern_btf_enum64(void) }; return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs))); + strs, sizeof(strs), token_fd)); } -typedef int (*feature_probe_fn)(void); +typedef int (*feature_probe_fn)(int /* token_fd */); static struct kern_feature_cache feature_cache; @@ -448,7 +488,7 @@ bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_ cache = &feature_cache; if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) { - ret = feat->probe(); + ret = feat->probe(cache->token_fd); if (ret > 0) { WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED); } else if (ret == 0) { diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index a2b767bc0c5b..a1d100df0c71 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -6440,7 +6440,7 @@ static int probe_kern_arg_ctx_tag(void) if (cached_result >= 0) return cached_result; - btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs)); + btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), 0); if (btf_fd < 0) return 0; @@ -10606,7 +10606,7 @@ static const char *arch_specific_syscall_pfx(void) #endif } -int probe_kern_syscall_wrapper(void) +int probe_kern_syscall_wrapper(int token_fd) { char syscall_name[64]; const char *ksys_pfx; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index fa25e1232bc8..28fabed1cd8f 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -369,19 +369,21 @@ enum kern_feature_result { struct kern_feature_cache { enum kern_feature_result res[__FEAT_CNT]; + int token_fd; }; bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id); bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id); -int probe_kern_syscall_wrapper(void); -int probe_memcg_account(void); +int probe_kern_syscall_wrapper(int token_fd); +int probe_memcg_account(int token_fd); int bump_rlimit_memlock(void); int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz); int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz); int libbpf__load_raw_btf(const char *raw_types, size_t types_len, - const char *str_sec, size_t str_len); + const char *str_sec, size_t str_len, + int token_fd); int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level); struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf); diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index 98373d126d9d..ee9b1dbea9eb 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -219,7 +219,8 @@ int libbpf_probe_bpf_prog_type(enum bpf_prog_type prog_type, const void *opts) } int libbpf__load_raw_btf(const char *raw_types, size_t types_len, - const char *str_sec, size_t str_len) + const char *str_sec, size_t str_len, + int token_fd) { struct btf_header hdr = { .magic = BTF_MAGIC, @@ -229,6 +230,10 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len, .str_off = types_len, .str_len = str_len, }; + LIBBPF_OPTS(bpf_btf_load_opts, opts, + .token_fd = token_fd, + .btf_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); int btf_fd, btf_len; __u8 *raw_btf; @@ -241,7 +246,7 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len, memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len); memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len); - btf_fd = bpf_btf_load(raw_btf, btf_len, NULL); + btf_fd = bpf_btf_load(raw_btf, btf_len, &opts); free(raw_btf); return btf_fd; @@ -271,7 +276,7 @@ static int load_local_storage_btf(void) }; return libbpf__load_raw_btf((char *)types, sizeof(types), - strs, sizeof(strs)); + strs, sizeof(strs), 0); } static int probe_map_create(enum bpf_map_type map_type) From 6b434b61b4d9e0e59f2947ce0f58f6fb4de048d8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:22 -0800 Subject: [PATCH 0288/2255] libbpf: Wire up BPF token support at BPF object level Add BPF token support to BPF object-level functionality. BPF token is supported by BPF object logic either as an explicitly provided BPF token from outside (through BPF FS path), or implicitly (unless prevented through bpf_object_open_opts). Implicit mode is assumed to be the most common one for user namespaced unprivileged workloads. The assumption is that privileged container manager sets up default BPF FS mount point at /sys/fs/bpf with BPF token delegation options (delegate_{cmds,maps,progs,attachs} mount options). BPF object during loading will attempt to create BPF token from /sys/fs/bpf location, and pass it for all relevant operations (currently, map creation, BTF load, and program load). In this implicit mode, if BPF token creation fails due to whatever reason (BPF FS is not mounted, or kernel doesn't support BPF token, etc), this is not considered an error. BPF object loading sequence will proceed with no BPF token. In explicit BPF token mode, user provides explicitly custom BPF FS mount point path. In such case, BPF object will attempt to create BPF token from provided BPF FS location. If BPF token creation fails, that is considered a critical error and BPF object load fails with an error. Libbpf provides a way to disable implicit BPF token creation, if it causes any troubles (BPF token is designed to be completely optional and shouldn't cause any problems even if provided, but in the world of BPF LSM, custom security logic can be installed that might change outcome depending on the presence of BPF token). To disable libbpf's default BPF token creation behavior user should provide either invalid BPF token FD (negative), or empty bpf_token_path option. BPF token presence can influence libbpf's feature probing, so if BPF object has associated BPF token, feature probing is instructed to use BPF object-specific feature detection cache and token FD. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-26-andrii@kernel.org --- tools/lib/bpf/btf.c | 10 +++- tools/lib/bpf/libbpf.c | 102 ++++++++++++++++++++++++++++++-- tools/lib/bpf/libbpf.h | 13 +++- tools/lib/bpf/libbpf_internal.h | 17 +++++- 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index ee95fd379d4d..ec92b87cae01 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1317,7 +1317,9 @@ struct btf *btf__parse_split(const char *path, struct btf *base_btf) static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian); -int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level) +int btf_load_into_kernel(struct btf *btf, + char *log_buf, size_t log_sz, __u32 log_level, + int token_fd) { LIBBPF_OPTS(bpf_btf_load_opts, opts); __u32 buf_sz = 0, raw_size; @@ -1367,6 +1369,10 @@ retry_load: opts.log_level = log_level; } + opts.token_fd = token_fd; + if (token_fd) + opts.btf_flags |= BPF_F_TOKEN_FD; + btf->fd = bpf_btf_load(raw_data, raw_size, &opts); if (btf->fd < 0) { /* time to turn on verbose mode and try again */ @@ -1394,7 +1400,7 @@ done: int btf__load_into_kernel(struct btf *btf) { - return btf_load_into_kernel(btf, NULL, 0, 0); + return btf_load_into_kernel(btf, NULL, 0, 0, 0); } int btf__fd(const struct btf *btf) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index a1d100df0c71..cefa607be335 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -59,6 +59,8 @@ #define BPF_FS_MAGIC 0xcafe4a11 #endif +#define BPF_FS_DEFAULT_PATH "/sys/fs/bpf" + #define BPF_INSN_SZ (sizeof(struct bpf_insn)) /* vsprintf() in __base_pr() uses nonliteral format string. It may break @@ -695,6 +697,10 @@ struct bpf_object { struct usdt_manager *usdt_man; + struct kern_feature_cache *feat_cache; + char *token_path; + int token_fd; + char path[]; }; @@ -2231,7 +2237,7 @@ static int build_map_pin_path(struct bpf_map *map, const char *path) int err; if (!path) - path = "/sys/fs/bpf"; + path = BPF_FS_DEFAULT_PATH; err = pathname_concat(buf, sizeof(buf), path, bpf_map__name(map)); if (err) @@ -3240,7 +3246,7 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj) } else { /* currently BPF_BTF_LOAD only supports log_level 1 */ err = btf_load_into_kernel(kern_btf, obj->log_buf, obj->log_size, - obj->log_level ? 1 : 0); + obj->log_level ? 1 : 0, obj->token_fd); } if (sanitize) { if (!err) { @@ -4561,6 +4567,58 @@ int bpf_map__set_max_entries(struct bpf_map *map, __u32 max_entries) return 0; } +static int bpf_object_prepare_token(struct bpf_object *obj) +{ + const char *bpffs_path; + int bpffs_fd = -1, token_fd, err; + bool mandatory; + enum libbpf_print_level level; + + /* token is explicitly prevented */ + if (obj->token_path && obj->token_path[0] == '\0') { + pr_debug("object '%s': token is prevented, skipping...\n", obj->name); + return 0; + } + + mandatory = obj->token_path != NULL; + level = mandatory ? LIBBPF_WARN : LIBBPF_DEBUG; + + bpffs_path = obj->token_path ?: BPF_FS_DEFAULT_PATH; + bpffs_fd = open(bpffs_path, O_DIRECTORY, O_RDWR); + if (bpffs_fd < 0) { + err = -errno; + __pr(level, "object '%s': failed (%d) to open BPF FS mount at '%s'%s\n", + obj->name, err, bpffs_path, + mandatory ? "" : ", skipping optional step..."); + return mandatory ? err : 0; + } + + token_fd = bpf_token_create(bpffs_fd, 0); + close(bpffs_fd); + if (token_fd < 0) { + if (!mandatory && token_fd == -ENOENT) { + pr_debug("object '%s': BPF FS at '%s' doesn't have BPF token delegation set up, skipping...\n", + obj->name, bpffs_path); + return 0; + } + __pr(level, "object '%s': failed (%d) to create BPF token from '%s'%s\n", + obj->name, token_fd, bpffs_path, + mandatory ? "" : ", skipping optional step..."); + return mandatory ? token_fd : 0; + } + + obj->feat_cache = calloc(1, sizeof(*obj->feat_cache)); + if (!obj->feat_cache) { + close(token_fd); + return -ENOMEM; + } + + obj->token_fd = token_fd; + obj->feat_cache->token_fd = token_fd; + + return 0; +} + static int bpf_object__probe_loading(struct bpf_object *obj) { @@ -4570,6 +4628,10 @@ bpf_object__probe_loading(struct bpf_object *obj) BPF_EXIT_INSN(), }; int ret, insn_cnt = ARRAY_SIZE(insns); + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .token_fd = obj->token_fd, + .prog_flags = obj->token_fd ? BPF_F_TOKEN_FD : 0, + ); if (obj->gen_loader) return 0; @@ -4579,9 +4641,9 @@ bpf_object__probe_loading(struct bpf_object *obj) pr_warn("Failed to bump RLIMIT_MEMLOCK (err = %d), you might need to do it explicitly!\n", ret); /* make sure basic loading works */ - ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); + ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &opts); if (ret < 0) - ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, NULL); + ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); if (ret < 0) { ret = errno; cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); @@ -4604,6 +4666,9 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) */ return true; + if (obj->token_fd) + return feat_supported(obj->feat_cache, feat_id); + return feat_supported(NULL, feat_id); } @@ -4728,6 +4793,9 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b create_attr.map_flags = def->map_flags; create_attr.numa_node = map->numa_node; create_attr.map_extra = map->map_extra; + create_attr.token_fd = obj->token_fd; + if (obj->token_fd) + create_attr.map_flags |= BPF_F_TOKEN_FD; if (bpf_map__is_struct_ops(map)) { create_attr.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; @@ -7049,6 +7117,10 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog load_attr.prog_flags = prog->prog_flags; load_attr.fd_array = obj->fd_array; + load_attr.token_fd = obj->token_fd; + if (obj->token_fd) + load_attr.prog_flags |= BPF_F_TOKEN_FD; + /* adjust load_attr if sec_def provides custom preload callback */ if (prog->sec_def && prog->sec_def->prog_prepare_load_fn) { err = prog->sec_def->prog_prepare_load_fn(prog, &load_attr, prog->sec_def->cookie); @@ -7494,7 +7566,7 @@ static int bpf_object_init_progs(struct bpf_object *obj, const struct bpf_object static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, size_t obj_buf_sz, const struct bpf_object_open_opts *opts) { - const char *obj_name, *kconfig, *btf_tmp_path; + const char *obj_name, *kconfig, *btf_tmp_path, *token_path; struct bpf_object *obj; char tmp_name[64]; int err; @@ -7531,6 +7603,10 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, if (log_size && !log_buf) return ERR_PTR(-EINVAL); + token_path = OPTS_GET(opts, bpf_token_path, NULL); + if (token_path && strlen(token_path) >= PATH_MAX) + return ERR_PTR(-ENAMETOOLONG); + obj = bpf_object__new(path, obj_buf, obj_buf_sz, obj_name); if (IS_ERR(obj)) return obj; @@ -7539,6 +7615,14 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, obj->log_size = log_size; obj->log_level = log_level; + if (token_path) { + obj->token_path = strdup(token_path); + if (!obj->token_path) { + err = -ENOMEM; + goto out; + } + } + btf_tmp_path = OPTS_GET(opts, btf_custom_path, NULL); if (btf_tmp_path) { if (strlen(btf_tmp_path) >= PATH_MAX) { @@ -8049,7 +8133,8 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch if (obj->gen_loader) bpf_gen__init(obj->gen_loader, extra_log_level, obj->nr_programs, obj->nr_maps); - err = bpf_object__probe_loading(obj); + err = bpf_object_prepare_token(obj); + err = err ? : bpf_object__probe_loading(obj); err = err ? : bpf_object__load_vmlinux_btf(obj, false); err = err ? : bpf_object__resolve_externs(obj, obj->kconfig); err = err ? : bpf_object__sanitize_maps(obj); @@ -8584,6 +8669,11 @@ void bpf_object__close(struct bpf_object *obj) } zfree(&obj->programs); + zfree(&obj->feat_cache); + zfree(&obj->token_path); + if (obj->token_fd > 0) + close(obj->token_fd); + free(obj); } diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 6cd9c501624f..535ae15ed493 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -177,10 +177,21 @@ struct bpf_object_open_opts { * logs through its print callback. */ __u32 kernel_log_level; + /* Path to BPF FS mount point to derive BPF token from. + * + * Created BPF token will be used for all bpf() syscall operations + * that accept BPF token (e.g., map creation, BTF and program loads, + * etc) automatically within instantiated BPF object. + * + * Setting bpf_token_path option to empty string disables libbpf's + * automatic attempt to create BPF token from default BPF FS mount + * point (/sys/fs/bpf), in case this default behavior is undesirable. + */ + const char *bpf_token_path; size_t :0; }; -#define bpf_object_open_opts__last_field kernel_log_level +#define bpf_object_open_opts__last_field bpf_token_path /** * @brief **bpf_object__open()** creates a bpf_object by opening diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 28fabed1cd8f..930cc9616527 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -384,7 +384,9 @@ int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz); int libbpf__load_raw_btf(const char *raw_types, size_t types_len, const char *str_sec, size_t str_len, int token_fd); -int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level); +int btf_load_into_kernel(struct btf *btf, + char *log_buf, size_t log_sz, __u32 log_level, + int token_fd); struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf); void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type, @@ -548,6 +550,17 @@ static inline bool is_ldimm64_insn(struct bpf_insn *insn) return insn->code == (BPF_LD | BPF_IMM | BPF_DW); } +/* Unconditionally dup FD, ensuring it doesn't use [0, 2] range. + * Original FD is not closed or altered in any other way. + * Preserves original FD value, if it's invalid (negative). + */ +static inline int dup_good_fd(int fd) +{ + if (fd < 0) + return fd; + return fcntl(fd, F_DUPFD_CLOEXEC, 3); +} + /* if fd is stdin, stdout, or stderr, dup to a fd greater than 2 * Takes ownership of the fd passed in, and closes it if calling * fcntl(fd, F_DUPFD_CLOEXEC, 3). @@ -559,7 +572,7 @@ static inline int ensure_good_fd(int fd) if (fd < 0) return fd; if (fd < 3) { - fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + fd = dup_good_fd(fd); saved_errno = errno; close(old_fd); errno = saved_errno; From d5baf0cac627fb3a00d9235955a388e5930b6d0e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:23 -0800 Subject: [PATCH 0289/2255] selftests/bpf: Add BPF object loading tests with explicit token passing Add a few tests that attempt to load BPF object containing privileged map, program, and the one requiring mandatory BTF uploading into the kernel (to validate token FD propagation to BPF_BTF_LOAD command). Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-27-andrii@kernel.org --- .../testing/selftests/bpf/prog_tests/token.c | 140 ++++++++++++++++++ tools/testing/selftests/bpf/progs/priv_map.c | 13 ++ tools/testing/selftests/bpf/progs/priv_prog.c | 13 ++ 3 files changed, 166 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/priv_map.c create mode 100644 tools/testing/selftests/bpf/progs/priv_prog.c diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c index 185ed2f79315..1594d9b94b13 100644 --- a/tools/testing/selftests/bpf/prog_tests/token.c +++ b/tools/testing/selftests/bpf/prog_tests/token.c @@ -14,6 +14,9 @@ #include #include #include +#include "priv_map.skel.h" +#include "priv_prog.skel.h" +#include "dummy_st_ops_success.skel.h" static inline int sys_mount(const char *dev_name, const char *dir_name, const char *type, unsigned long flags, @@ -666,6 +669,104 @@ cleanup: return err; } +static int userns_obj_priv_map(int mnt_fd) +{ + LIBBPF_OPTS(bpf_object_open_opts, opts); + char buf[256]; + struct priv_map *skel; + int err; + + skel = priv_map__open_and_load(); + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { + priv_map__destroy(skel); + return -EINVAL; + } + + /* use bpf_token_path to provide BPF FS path */ + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd); + opts.bpf_token_path = buf; + skel = priv_map__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "obj_token_path_open")) + return -EINVAL; + + err = priv_map__load(skel); + priv_map__destroy(skel); + if (!ASSERT_OK(err, "obj_token_path_load")) + return -EINVAL; + + return 0; +} + +static int userns_obj_priv_prog(int mnt_fd) +{ + LIBBPF_OPTS(bpf_object_open_opts, opts); + char buf[256]; + struct priv_prog *skel; + int err; + + skel = priv_prog__open_and_load(); + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { + priv_prog__destroy(skel); + return -EINVAL; + } + + /* use bpf_token_path to provide BPF FS path */ + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd); + opts.bpf_token_path = buf; + skel = priv_prog__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "obj_token_path_open")) + return -EINVAL; + + err = priv_prog__load(skel); + priv_prog__destroy(skel); + if (!ASSERT_OK(err, "obj_token_path_load")) + return -EINVAL; + + return 0; +} + +/* this test is called with BPF FS that doesn't delegate BPF_BTF_LOAD command, + * which should cause struct_ops application to fail, as BTF won't be uploaded + * into the kernel, even if STRUCT_OPS programs themselves are allowed + */ +static int validate_struct_ops_load(int mnt_fd, bool expect_success) +{ + LIBBPF_OPTS(bpf_object_open_opts, opts); + char buf[256]; + struct dummy_st_ops_success *skel; + int err; + + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd); + opts.bpf_token_path = buf; + skel = dummy_st_ops_success__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "obj_token_path_open")) + return -EINVAL; + + err = dummy_st_ops_success__load(skel); + dummy_st_ops_success__destroy(skel); + if (expect_success) { + if (!ASSERT_OK(err, "obj_token_path_load")) + return -EINVAL; + } else /* expect failure */ { + if (!ASSERT_ERR(err, "obj_token_path_load")) + return -EINVAL; + } + + return 0; +} + +static int userns_obj_priv_btf_fail(int mnt_fd) +{ + return validate_struct_ops_load(mnt_fd, false /* should fail */); +} + +static int userns_obj_priv_btf_success(int mnt_fd) +{ + return validate_struct_ops_load(mnt_fd, true /* should succeed */); +} + +#define bit(n) (1ULL << (n)) + void test_token(void) { if (test__start_subtest("map_token")) { @@ -692,4 +793,43 @@ void test_token(void) subtest_userns(&opts, userns_prog_load); } + if (test__start_subtest("obj_priv_map")) { + struct bpffs_opts opts = { + .cmds = bit(BPF_MAP_CREATE), + .maps = bit(BPF_MAP_TYPE_QUEUE), + }; + + subtest_userns(&opts, userns_obj_priv_map); + } + if (test__start_subtest("obj_priv_prog")) { + struct bpffs_opts opts = { + .cmds = bit(BPF_PROG_LOAD), + .progs = bit(BPF_PROG_TYPE_KPROBE), + .attachs = ~0ULL, + }; + + subtest_userns(&opts, userns_obj_priv_prog); + } + if (test__start_subtest("obj_priv_btf_fail")) { + struct bpffs_opts opts = { + /* disallow BTF loading */ + .cmds = bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), + .attachs = ~0ULL, + }; + + subtest_userns(&opts, userns_obj_priv_btf_fail); + } + if (test__start_subtest("obj_priv_btf_success")) { + struct bpffs_opts opts = { + /* allow BTF loading */ + .cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), + .attachs = ~0ULL, + }; + + subtest_userns(&opts, userns_obj_priv_btf_success); + } } diff --git a/tools/testing/selftests/bpf/progs/priv_map.c b/tools/testing/selftests/bpf/progs/priv_map.c new file mode 100644 index 000000000000..9085be50f03b --- /dev/null +++ b/tools/testing/selftests/bpf/progs/priv_map.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include + +char _license[] SEC("license") = "GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_QUEUE); + __uint(max_entries, 1); + __type(value, __u32); +} priv_map SEC(".maps"); diff --git a/tools/testing/selftests/bpf/progs/priv_prog.c b/tools/testing/selftests/bpf/progs/priv_prog.c new file mode 100644 index 000000000000..3c7b2b618c8a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/priv_prog.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include + +char _license[] SEC("license") = "GPL"; + +SEC("kprobe") +int kprobe_prog(void *ctx) +{ + return 1; +} From b73d08d1318a2dde5bacbab77d0e2fd2aa47c933 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:24 -0800 Subject: [PATCH 0290/2255] selftests/bpf: Add tests for BPF object load with implicit token Add a test to validate libbpf's implicit BPF token creation from default BPF FS location (/sys/fs/bpf). Also validate that disabling this implicit BPF token creation works. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20240124022127.2379740-28-andrii@kernel.org --- .../testing/selftests/bpf/prog_tests/token.c | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c index 1594d9b94b13..003f7c208f4c 100644 --- a/tools/testing/selftests/bpf/prog_tests/token.c +++ b/tools/testing/selftests/bpf/prog_tests/token.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "priv_map.skel.h" @@ -45,6 +46,13 @@ static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags) return syscall(__NR_fsmount, fs_fd, flags, ms_flags); } +static inline int sys_move_mount(int from_dfd, const char *from_path, + int to_dfd, const char *to_path, + unsigned flags) +{ + return syscall(__NR_move_mount, from_dfd, from_path, to_dfd, to_path, flags); +} + static int drop_priv_caps(__u64 *old_caps) { return cap_disable_effective((1ULL << CAP_BPF) | @@ -765,6 +773,51 @@ static int userns_obj_priv_btf_success(int mnt_fd) return validate_struct_ops_load(mnt_fd, true /* should succeed */); } +static int userns_obj_priv_implicit_token(int mnt_fd) +{ + LIBBPF_OPTS(bpf_object_open_opts, opts); + struct dummy_st_ops_success *skel; + int err; + + /* before we mount BPF FS with token delegation, struct_ops skeleton + * should fail to load + */ + skel = dummy_st_ops_success__open_and_load(); + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { + dummy_st_ops_success__destroy(skel); + return -EINVAL; + } + + /* mount custom BPF FS over /sys/fs/bpf so that libbpf can create BPF + * token automatically and implicitly + */ + err = sys_move_mount(mnt_fd, "", AT_FDCWD, "/sys/fs/bpf", MOVE_MOUNT_F_EMPTY_PATH); + if (!ASSERT_OK(err, "move_mount_bpffs")) + return -EINVAL; + + /* now the same struct_ops skeleton should succeed thanks to libppf + * creating BPF token from /sys/fs/bpf mount point + */ + skel = dummy_st_ops_success__open_and_load(); + if (!ASSERT_OK_PTR(skel, "obj_implicit_token_load")) + return -EINVAL; + + dummy_st_ops_success__destroy(skel); + + /* now disable implicit token through empty bpf_token_path, should fail */ + opts.bpf_token_path = ""; + skel = dummy_st_ops_success__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "obj_empty_token_path_open")) + return -EINVAL; + + err = dummy_st_ops_success__load(skel); + dummy_st_ops_success__destroy(skel); + if (!ASSERT_ERR(err, "obj_empty_token_path_load")) + return -EINVAL; + + return 0; +} + #define bit(n) (1ULL << (n)) void test_token(void) @@ -832,4 +885,15 @@ void test_token(void) subtest_userns(&opts, userns_obj_priv_btf_success); } + if (test__start_subtest("obj_priv_implicit_token")) { + struct bpffs_opts opts = { + /* allow BTF loading */ + .cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), + .attachs = ~0ULL, + }; + + subtest_userns(&opts, userns_obj_priv_implicit_token); + } } From cac270ad79afe212ed7986e8d271c72521cd8212 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:25 -0800 Subject: [PATCH 0291/2255] libbpf: Support BPF token path setting through LIBBPF_BPF_TOKEN_PATH envvar To allow external admin authority to override default BPF FS location (/sys/fs/bpf) for implicit BPF token creation, teach libbpf to recognize LIBBPF_BPF_TOKEN_PATH envvar. If it is specified and user application didn't explicitly specify bpf_token_path option, it will be treated exactly like bpf_token_path option, overriding default /sys/fs/bpf location and making BPF token mandatory. Suggested-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-29-andrii@kernel.org --- tools/lib/bpf/libbpf.c | 6 ++++++ tools/lib/bpf/libbpf.h | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index cefa607be335..fa7094ff3e66 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -7604,6 +7604,12 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, return ERR_PTR(-EINVAL); token_path = OPTS_GET(opts, bpf_token_path, NULL); + /* if user didn't specify bpf_token_path explicitly, check if + * LIBBPF_BPF_TOKEN_PATH envvar was set and treat it as bpf_token_path + * option + */ + if (!token_path) + token_path = getenv("LIBBPF_BPF_TOKEN_PATH"); if (token_path && strlen(token_path) >= PATH_MAX) return ERR_PTR(-ENAMETOOLONG); diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 535ae15ed493..5723cbbfcc41 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -183,6 +183,14 @@ struct bpf_object_open_opts { * that accept BPF token (e.g., map creation, BTF and program loads, * etc) automatically within instantiated BPF object. * + * If bpf_token_path is not specified, libbpf will consult + * LIBBPF_BPF_TOKEN_PATH environment variable. If set, it will be + * taken as a value of bpf_token_path option and will force libbpf to + * either create BPF token from provided custom BPF FS path, or will + * disable implicit BPF token creation, if envvar value is an empty + * string. bpf_token_path overrides LIBBPF_BPF_TOKEN_PATH, if both are + * set at the same time. + * * Setting bpf_token_path option to empty string disables libbpf's * automatic attempt to create BPF token from default BPF FS mount * point (/sys/fs/bpf), in case this default behavior is undesirable. From fadf54935e859c4d512aed6ad54f639b87a3b4d3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:26 -0800 Subject: [PATCH 0292/2255] selftests/bpf: Add tests for LIBBPF_BPF_TOKEN_PATH envvar Add new subtest validating LIBBPF_BPF_TOKEN_PATH envvar semantics. Extend existing test to validate that LIBBPF_BPF_TOKEN_PATH allows to disable implicit BPF token creation by setting envvar to empty string. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-30-andrii@kernel.org --- .../testing/selftests/bpf/prog_tests/token.c | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c index 003f7c208f4c..1f6aa685e6f7 100644 --- a/tools/testing/selftests/bpf/prog_tests/token.c +++ b/tools/testing/selftests/bpf/prog_tests/token.c @@ -773,6 +773,9 @@ static int userns_obj_priv_btf_success(int mnt_fd) return validate_struct_ops_load(mnt_fd, true /* should succeed */); } +#define TOKEN_ENVVAR "LIBBPF_BPF_TOKEN_PATH" +#define TOKEN_BPFFS_CUSTOM "/bpf-token-fs" + static int userns_obj_priv_implicit_token(int mnt_fd) { LIBBPF_OPTS(bpf_object_open_opts, opts); @@ -795,6 +798,20 @@ static int userns_obj_priv_implicit_token(int mnt_fd) if (!ASSERT_OK(err, "move_mount_bpffs")) return -EINVAL; + /* disable implicit BPF token creation by setting + * LIBBPF_BPF_TOKEN_PATH envvar to empty value, load should fail + */ + err = setenv(TOKEN_ENVVAR, "", 1 /*overwrite*/); + if (!ASSERT_OK(err, "setenv_token_path")) + return -EINVAL; + skel = dummy_st_ops_success__open_and_load(); + if (!ASSERT_ERR_PTR(skel, "obj_token_envvar_disabled_load")) { + unsetenv(TOKEN_ENVVAR); + dummy_st_ops_success__destroy(skel); + return -EINVAL; + } + unsetenv(TOKEN_ENVVAR); + /* now the same struct_ops skeleton should succeed thanks to libppf * creating BPF token from /sys/fs/bpf mount point */ @@ -818,6 +835,76 @@ static int userns_obj_priv_implicit_token(int mnt_fd) return 0; } +static int userns_obj_priv_implicit_token_envvar(int mnt_fd) +{ + LIBBPF_OPTS(bpf_object_open_opts, opts); + struct dummy_st_ops_success *skel; + int err; + + /* before we mount BPF FS with token delegation, struct_ops skeleton + * should fail to load + */ + skel = dummy_st_ops_success__open_and_load(); + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { + dummy_st_ops_success__destroy(skel); + return -EINVAL; + } + + /* mount custom BPF FS over custom location, so libbpf can't create + * BPF token implicitly, unless pointed to it through + * LIBBPF_BPF_TOKEN_PATH envvar + */ + rmdir(TOKEN_BPFFS_CUSTOM); + if (!ASSERT_OK(mkdir(TOKEN_BPFFS_CUSTOM, 0777), "mkdir_bpffs_custom")) + goto err_out; + err = sys_move_mount(mnt_fd, "", AT_FDCWD, TOKEN_BPFFS_CUSTOM, MOVE_MOUNT_F_EMPTY_PATH); + if (!ASSERT_OK(err, "move_mount_bpffs")) + goto err_out; + + /* even though we have BPF FS with delegation, it's not at default + * /sys/fs/bpf location, so we still fail to load until envvar is set up + */ + skel = dummy_st_ops_success__open_and_load(); + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load2")) { + dummy_st_ops_success__destroy(skel); + goto err_out; + } + + err = setenv(TOKEN_ENVVAR, TOKEN_BPFFS_CUSTOM, 1 /*overwrite*/); + if (!ASSERT_OK(err, "setenv_token_path")) + goto err_out; + + /* now the same struct_ops skeleton should succeed thanks to libppf + * creating BPF token from custom mount point + */ + skel = dummy_st_ops_success__open_and_load(); + if (!ASSERT_OK_PTR(skel, "obj_implicit_token_load")) + goto err_out; + + dummy_st_ops_success__destroy(skel); + + /* now disable implicit token through empty bpf_token_path, envvar + * will be ignored, should fail + */ + opts.bpf_token_path = ""; + skel = dummy_st_ops_success__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "obj_empty_token_path_open")) + goto err_out; + + err = dummy_st_ops_success__load(skel); + dummy_st_ops_success__destroy(skel); + if (!ASSERT_ERR(err, "obj_empty_token_path_load")) + goto err_out; + + rmdir(TOKEN_BPFFS_CUSTOM); + unsetenv(TOKEN_ENVVAR); + return 0; +err_out: + rmdir(TOKEN_BPFFS_CUSTOM); + unsetenv(TOKEN_ENVVAR); + return -EINVAL; +} + #define bit(n) (1ULL << (n)) void test_token(void) @@ -896,4 +983,15 @@ void test_token(void) subtest_userns(&opts, userns_obj_priv_implicit_token); } + if (test__start_subtest("obj_priv_implicit_token_envvar")) { + struct bpffs_opts opts = { + /* allow BTF loading */ + .cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), + .attachs = ~0ULL, + }; + + subtest_userns(&opts, userns_obj_priv_implicit_token_envvar); + } } From 906ee42cb1be1152ef24465704cc89edc3f571c1 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jan 2024 18:21:27 -0800 Subject: [PATCH 0293/2255] selftests/bpf: Incorporate LSM policy to token-based tests Add tests for LSM interactions (both bpf_token_capable and bpf_token_cmd LSM hooks) with BPF token in bpf() subsystem. Now child process passes back token FD for parent to be able to do tests with token originating in "wrong" userns. But we also create token in initns and check that token LSMs don't accidentally reject BPF operations when capable() checks pass without BPF token. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20240124022127.2379740-31-andrii@kernel.org --- .../testing/selftests/bpf/prog_tests/token.c | 89 +++++++++++++++---- tools/testing/selftests/bpf/progs/token_lsm.c | 32 +++++++ 2 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/token_lsm.c diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c index 1f6aa685e6f7..fc4a175d8d76 100644 --- a/tools/testing/selftests/bpf/prog_tests/token.c +++ b/tools/testing/selftests/bpf/prog_tests/token.c @@ -18,6 +18,7 @@ #include "priv_map.skel.h" #include "priv_prog.skel.h" #include "dummy_st_ops_success.skel.h" +#include "token_lsm.skel.h" static inline int sys_mount(const char *dev_name, const char *dir_name, const char *type, unsigned long flags, @@ -279,12 +280,23 @@ static int create_and_enter_userns(void) return 0; } -typedef int (*child_callback_fn)(int); +typedef int (*child_callback_fn)(int bpffs_fd, struct token_lsm *lsm_skel); static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callback) { - LIBBPF_OPTS(bpf_map_create_opts, map_opts); - int mnt_fd = -1, fs_fd = -1, err = 0, bpffs_fd = -1; + int mnt_fd = -1, fs_fd = -1, err = 0, bpffs_fd = -1, token_fd = -1; + struct token_lsm *lsm_skel = NULL; + + /* load and attach LSM "policy" before we go into unpriv userns */ + lsm_skel = token_lsm__open_and_load(); + if (!ASSERT_OK_PTR(lsm_skel, "lsm_skel_load")) { + err = -EINVAL; + goto cleanup; + } + lsm_skel->bss->my_pid = getpid(); + err = token_lsm__attach(lsm_skel); + if (!ASSERT_OK(err, "lsm_skel_attach")) + goto cleanup; /* setup userns with root mappings */ err = create_and_enter_userns(); @@ -365,8 +377,19 @@ static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callba goto cleanup; } + /* create BPF token FD and pass it to parent for some extra checks */ + token_fd = bpf_token_create(bpffs_fd, NULL); + if (!ASSERT_GT(token_fd, 0, "child_token_create")) { + err = -EINVAL; + goto cleanup; + } + err = sendfd(sock_fd, token_fd); + if (!ASSERT_OK(err, "send_token_fd")) + goto cleanup; + zclose(token_fd); + /* do custom test logic with customly set up BPF FS instance */ - err = callback(bpffs_fd); + err = callback(bpffs_fd, lsm_skel); if (!ASSERT_OK(err, "test_callback")) goto cleanup; @@ -376,6 +399,10 @@ cleanup: zclose(mnt_fd); zclose(fs_fd); zclose(bpffs_fd); + zclose(token_fd); + + lsm_skel->bss->my_pid = 0; + token_lsm__destroy(lsm_skel); exit(-err); } @@ -401,7 +428,7 @@ again: static void parent(int child_pid, struct bpffs_opts *bpffs_opts, int sock_fd) { - int fs_fd = -1, mnt_fd = -1, err; + int fs_fd = -1, mnt_fd = -1, token_fd = -1, err; err = recvfd(sock_fd, &fs_fd); if (!ASSERT_OK(err, "recv_bpffs_fd")) @@ -420,6 +447,11 @@ static void parent(int child_pid, struct bpffs_opts *bpffs_opts, int sock_fd) goto cleanup; zclose(mnt_fd); + /* receive BPF token FD back from child for some extra tests */ + err = recvfd(sock_fd, &token_fd); + if (!ASSERT_OK(err, "recv_token_fd")) + goto cleanup; + err = wait_for_pid(child_pid); ASSERT_OK(err, "waitpid_child"); @@ -427,12 +459,14 @@ cleanup: zclose(sock_fd); zclose(fs_fd); zclose(mnt_fd); + zclose(token_fd); if (child_pid > 0) (void)kill(child_pid, SIGKILL); } -static void subtest_userns(struct bpffs_opts *bpffs_opts, child_callback_fn cb) +static void subtest_userns(struct bpffs_opts *bpffs_opts, + child_callback_fn child_cb) { int sock_fds[2] = { -1, -1 }; int child_pid = 0, err; @@ -447,7 +481,7 @@ static void subtest_userns(struct bpffs_opts *bpffs_opts, child_callback_fn cb) if (child_pid == 0) { zclose(sock_fds[0]); - return child(sock_fds[1], bpffs_opts, cb); + return child(sock_fds[1], bpffs_opts, child_cb); } else { zclose(sock_fds[1]); @@ -461,7 +495,7 @@ cleanup: (void)kill(child_pid, SIGKILL); } -static int userns_map_create(int mnt_fd) +static int userns_map_create(int mnt_fd, struct token_lsm *lsm_skel) { LIBBPF_OPTS(bpf_map_create_opts, map_opts); int err, token_fd = -1, map_fd = -1; @@ -529,7 +563,7 @@ cleanup: return err; } -static int userns_btf_load(int mnt_fd) +static int userns_btf_load(int mnt_fd, struct token_lsm *lsm_skel) { LIBBPF_OPTS(bpf_btf_load_opts, btf_opts); int err, token_fd = -1, btf_fd = -1; @@ -598,7 +632,7 @@ cleanup: return err; } -static int userns_prog_load(int mnt_fd) +static int userns_prog_load(int mnt_fd, struct token_lsm *lsm_skel) { LIBBPF_OPTS(bpf_prog_load_opts, prog_opts); int err, token_fd = -1, prog_fd = -1; @@ -677,7 +711,7 @@ cleanup: return err; } -static int userns_obj_priv_map(int mnt_fd) +static int userns_obj_priv_map(int mnt_fd, struct token_lsm *lsm_skel) { LIBBPF_OPTS(bpf_object_open_opts, opts); char buf[256]; @@ -705,7 +739,7 @@ static int userns_obj_priv_map(int mnt_fd) return 0; } -static int userns_obj_priv_prog(int mnt_fd) +static int userns_obj_priv_prog(int mnt_fd, struct token_lsm *lsm_skel) { LIBBPF_OPTS(bpf_object_open_opts, opts); char buf[256]; @@ -724,12 +758,33 @@ static int userns_obj_priv_prog(int mnt_fd) skel = priv_prog__open_opts(&opts); if (!ASSERT_OK_PTR(skel, "obj_token_path_open")) return -EINVAL; - err = priv_prog__load(skel); priv_prog__destroy(skel); if (!ASSERT_OK(err, "obj_token_path_load")) return -EINVAL; + /* provide BPF token, but reject bpf_token_capable() with LSM */ + lsm_skel->bss->reject_capable = true; + lsm_skel->bss->reject_cmd = false; + skel = priv_prog__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "obj_token_lsm_reject_cap_open")) + return -EINVAL; + err = priv_prog__load(skel); + priv_prog__destroy(skel); + if (!ASSERT_ERR(err, "obj_token_lsm_reject_cap_load")) + return -EINVAL; + + /* provide BPF token, but reject bpf_token_cmd() with LSM */ + lsm_skel->bss->reject_capable = false; + lsm_skel->bss->reject_cmd = true; + skel = priv_prog__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "obj_token_lsm_reject_cmd_open")) + return -EINVAL; + err = priv_prog__load(skel); + priv_prog__destroy(skel); + if (!ASSERT_ERR(err, "obj_token_lsm_reject_cmd_load")) + return -EINVAL; + return 0; } @@ -763,12 +818,12 @@ static int validate_struct_ops_load(int mnt_fd, bool expect_success) return 0; } -static int userns_obj_priv_btf_fail(int mnt_fd) +static int userns_obj_priv_btf_fail(int mnt_fd, struct token_lsm *lsm_skel) { return validate_struct_ops_load(mnt_fd, false /* should fail */); } -static int userns_obj_priv_btf_success(int mnt_fd) +static int userns_obj_priv_btf_success(int mnt_fd, struct token_lsm *lsm_skel) { return validate_struct_ops_load(mnt_fd, true /* should succeed */); } @@ -776,7 +831,7 @@ static int userns_obj_priv_btf_success(int mnt_fd) #define TOKEN_ENVVAR "LIBBPF_BPF_TOKEN_PATH" #define TOKEN_BPFFS_CUSTOM "/bpf-token-fs" -static int userns_obj_priv_implicit_token(int mnt_fd) +static int userns_obj_priv_implicit_token(int mnt_fd, struct token_lsm *lsm_skel) { LIBBPF_OPTS(bpf_object_open_opts, opts); struct dummy_st_ops_success *skel; @@ -835,7 +890,7 @@ static int userns_obj_priv_implicit_token(int mnt_fd) return 0; } -static int userns_obj_priv_implicit_token_envvar(int mnt_fd) +static int userns_obj_priv_implicit_token_envvar(int mnt_fd, struct token_lsm *lsm_skel) { LIBBPF_OPTS(bpf_object_open_opts, opts); struct dummy_st_ops_success *skel; diff --git a/tools/testing/selftests/bpf/progs/token_lsm.c b/tools/testing/selftests/bpf/progs/token_lsm.c new file mode 100644 index 000000000000..e4d59b6ba743 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/token_lsm.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include + +char _license[] SEC("license") = "GPL"; + +int my_pid; +bool reject_capable; +bool reject_cmd; + +SEC("lsm/bpf_token_capable") +int BPF_PROG(token_capable, struct bpf_token *token, int cap) +{ + if (my_pid == 0 || my_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + if (reject_capable) + return -1; + return 0; +} + +SEC("lsm/bpf_token_cmd") +int BPF_PROG(token_cmd, struct bpf_token *token, enum bpf_cmd cmd) +{ + if (my_pid == 0 || my_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + if (reject_cmd) + return -1; + return 0; +} From e18c709230cb05886fdcf6b90ef21a0a733079d7 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Tue, 23 Jan 2024 10:27:50 +0300 Subject: [PATCH 0294/2255] vsock/test: add '--peer-port' input argument Implement port for given CID as input argument instead of using hardcoded value '1234'. This allows to run different test instances on a single CID. Port argument is not required parameter and if it is not set, then default value will be '1234' - thus we preserve previous behaviour. Signed-off-by: Arseniy Krasnov Reviewed-by: Stefano Garzarella Acked-by: Michael S. Tsirkin Link: https://lore.kernel.org/r/20240123072750.4084181-1-avkrasnov@salutedevices.com Signed-off-by: Jakub Kicinski --- tools/testing/vsock/util.c | 17 +++- tools/testing/vsock/util.h | 4 + tools/testing/vsock/vsock_diag_test.c | 21 +++-- tools/testing/vsock/vsock_test.c | 102 +++++++++++++--------- tools/testing/vsock/vsock_test_zerocopy.c | 12 +-- tools/testing/vsock/vsock_uring_test.c | 17 +++- 6 files changed, 115 insertions(+), 58 deletions(-) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index ae2b33c21c45..554b290fefdc 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -33,8 +33,7 @@ void init_signals(void) signal(SIGPIPE, SIG_IGN); } -/* Parse a CID in string representation */ -unsigned int parse_cid(const char *str) +static unsigned int parse_uint(const char *str, const char *err_str) { char *endptr = NULL; unsigned long n; @@ -42,12 +41,24 @@ unsigned int parse_cid(const char *str) errno = 0; n = strtoul(str, &endptr, 10); if (errno || *endptr != '\0') { - fprintf(stderr, "malformed CID \"%s\"\n", str); + fprintf(stderr, "malformed %s \"%s\"\n", err_str, str); exit(EXIT_FAILURE); } return n; } +/* Parse a CID in string representation */ +unsigned int parse_cid(const char *str) +{ + return parse_uint(str, "CID"); +} + +/* Parse a port in string representation */ +unsigned int parse_port(const char *str) +{ + return parse_uint(str, "port"); +} + /* Wait for the remote to close the connection */ void vsock_wait_remote_close(int fd) { diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index 03c88d0cb861..e95e62485959 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -12,10 +12,13 @@ enum test_mode { TEST_MODE_SERVER }; +#define DEFAULT_PEER_PORT 1234 + /* Test runner options */ struct test_opts { enum test_mode mode; unsigned int peer_cid; + unsigned int peer_port; }; /* A test case definition. Test functions must print failures to stderr and @@ -35,6 +38,7 @@ struct test_case { void init_signals(void); unsigned int parse_cid(const char *str); +unsigned int parse_port(const char *str); int vsock_stream_connect(unsigned int cid, unsigned int port); int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type); diff --git a/tools/testing/vsock/vsock_diag_test.c b/tools/testing/vsock/vsock_diag_test.c index fa927ad16f8a..9d61b1f1c4c3 100644 --- a/tools/testing/vsock/vsock_diag_test.c +++ b/tools/testing/vsock/vsock_diag_test.c @@ -342,7 +342,7 @@ static void test_listen_socket_server(const struct test_opts *opts) } addr = { .svm = { .svm_family = AF_VSOCK, - .svm_port = 1234, + .svm_port = opts->peer_port, .svm_cid = VMADDR_CID_ANY, }, }; @@ -378,7 +378,7 @@ static void test_connect_client(const struct test_opts *opts) LIST_HEAD(sockets); struct vsock_stat *st; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -403,7 +403,7 @@ static void test_connect_server(const struct test_opts *opts) LIST_HEAD(sockets); int client_fd; - client_fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + client_fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (client_fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -461,6 +461,11 @@ static const struct option longopts[] = { .has_arg = required_argument, .val = 'p', }, + { + .name = "peer-port", + .has_arg = required_argument, + .val = 'q', + }, { .name = "list", .has_arg = no_argument, @@ -481,7 +486,7 @@ static const struct option longopts[] = { static void usage(void) { - fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=] --control-port= --mode=client|server --peer-cid= [--list] [--skip=]\n" + fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=] --control-port= --mode=client|server --peer-cid= [--peer-port=] [--list] [--skip=]\n" "\n" " Server: vsock_diag_test --control-port=1234 --mode=server --peer-cid=3\n" " Client: vsock_diag_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" @@ -503,9 +508,11 @@ static void usage(void) " --control-port Server port to listen on/connect to\n" " --mode client|server Server or client mode\n" " --peer-cid CID of the other side\n" + " --peer-port AF_VSOCK port used for the test [default: %d]\n" " --list List of tests that will be executed\n" " --skip Test ID to skip;\n" - " use multiple --skip options to skip more tests\n" + " use multiple --skip options to skip more tests\n", + DEFAULT_PEER_PORT ); exit(EXIT_FAILURE); } @@ -517,6 +524,7 @@ int main(int argc, char **argv) struct test_opts opts = { .mode = TEST_MODE_UNSET, .peer_cid = VMADDR_CID_ANY, + .peer_port = DEFAULT_PEER_PORT, }; init_signals(); @@ -544,6 +552,9 @@ int main(int argc, char **argv) case 'p': opts.peer_cid = parse_cid(optarg); break; + case 'q': + opts.peer_port = parse_port(optarg); + break; case 'P': control_port = optarg; break; diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index 66246d81d654..f851f8961247 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -34,7 +34,7 @@ static void test_stream_connection_reset(const struct test_opts *opts) } addr = { .svm = { .svm_family = AF_VSOCK, - .svm_port = 1234, + .svm_port = opts->peer_port, .svm_cid = opts->peer_cid, }, }; @@ -70,7 +70,7 @@ static void test_stream_bind_only_client(const struct test_opts *opts) } addr = { .svm = { .svm_family = AF_VSOCK, - .svm_port = 1234, + .svm_port = opts->peer_port, .svm_cid = opts->peer_cid, }, }; @@ -112,7 +112,7 @@ static void test_stream_bind_only_server(const struct test_opts *opts) } addr = { .svm = { .svm_family = AF_VSOCK, - .svm_port = 1234, + .svm_port = opts->peer_port, .svm_cid = VMADDR_CID_ANY, }, }; @@ -138,7 +138,7 @@ static void test_stream_client_close_client(const struct test_opts *opts) { int fd; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -152,7 +152,7 @@ static void test_stream_client_close_server(const struct test_opts *opts) { int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -173,7 +173,7 @@ static void test_stream_server_close_client(const struct test_opts *opts) { int fd; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -194,7 +194,7 @@ static void test_stream_server_close_server(const struct test_opts *opts) { int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -215,7 +215,7 @@ static void test_stream_multiconn_client(const struct test_opts *opts) int i; for (i = 0; i < MULTICONN_NFDS; i++) { - fds[i] = vsock_stream_connect(opts->peer_cid, 1234); + fds[i] = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fds[i] < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -239,7 +239,7 @@ static void test_stream_multiconn_server(const struct test_opts *opts) int i; for (i = 0; i < MULTICONN_NFDS; i++) { - fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fds[i] = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fds[i] < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -267,9 +267,9 @@ static void test_msg_peek_client(const struct test_opts *opts, int i; if (seqpacket) - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); else - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); @@ -295,9 +295,9 @@ static void test_msg_peek_server(const struct test_opts *opts, int fd; if (seqpacket) - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); else - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); @@ -363,7 +363,7 @@ static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) int msg_count; int fd; - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -434,7 +434,7 @@ static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) struct msghdr msg = {0}; struct iovec iov = {0}; - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -505,7 +505,7 @@ static void test_seqpacket_msg_trunc_client(const struct test_opts *opts) int fd; char buf[MESSAGE_TRUNC_SZ]; - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -524,7 +524,7 @@ static void test_seqpacket_msg_trunc_server(const struct test_opts *opts) struct msghdr msg = {0}; struct iovec iov = {0}; - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -575,7 +575,7 @@ static void test_seqpacket_timeout_client(const struct test_opts *opts) time_t read_enter_ns; time_t read_overhead_ns; - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -620,7 +620,7 @@ static void test_seqpacket_timeout_server(const struct test_opts *opts) { int fd; - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -639,7 +639,7 @@ static void test_seqpacket_bigmsg_client(const struct test_opts *opts) len = sizeof(sock_buf_size); - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -671,7 +671,7 @@ static void test_seqpacket_bigmsg_server(const struct test_opts *opts) { int fd; - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -692,7 +692,7 @@ static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opt unsigned char *buf2; int buf_size = getpagesize() * 3; - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -732,7 +732,7 @@ static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opt int flags = MAP_PRIVATE | MAP_ANONYMOUS; int i; - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -808,7 +808,7 @@ static void test_stream_poll_rcvlowat_server(const struct test_opts *opts) int fd; int i; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -839,7 +839,7 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) short poll_flags; int fd; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -906,9 +906,9 @@ static void test_inv_buf_client(const struct test_opts *opts, bool stream) int fd; if (stream) - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); else - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); @@ -941,9 +941,9 @@ static void test_inv_buf_server(const struct test_opts *opts, bool stream) int fd; if (stream) - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); else - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); @@ -986,7 +986,7 @@ static void test_stream_virtio_skb_merge_client(const struct test_opts *opts) { int fd; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -1015,7 +1015,7 @@ static void test_stream_virtio_skb_merge_server(const struct test_opts *opts) unsigned char buf[64]; int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -1108,7 +1108,7 @@ static void test_stream_shutwr_client(const struct test_opts *opts) sigaction(SIGPIPE, &act, NULL); - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -1130,7 +1130,7 @@ static void test_stream_shutwr_server(const struct test_opts *opts) { int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -1151,7 +1151,7 @@ static void test_stream_shutrd_client(const struct test_opts *opts) sigaction(SIGPIPE, &act, NULL); - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -1170,7 +1170,7 @@ static void test_stream_shutrd_server(const struct test_opts *opts) { int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -1193,7 +1193,7 @@ static void test_double_bind_connect_server(const struct test_opts *opts) struct sockaddr_vm sa_client; socklen_t socklen_client = sizeof(sa_client); - listen_fd = vsock_stream_listen(VMADDR_CID_ANY, 1234); + listen_fd = vsock_stream_listen(VMADDR_CID_ANY, opts->peer_port); for (i = 0; i < 2; i++) { control_writeln("LISTENING"); @@ -1226,7 +1226,13 @@ static void test_double_bind_connect_client(const struct test_opts *opts) /* Wait until server is ready to accept a new connection */ control_expectln("LISTENING"); - client_fd = vsock_bind_connect(opts->peer_cid, 1234, 4321, SOCK_STREAM); + /* We use 'peer_port + 1' as "some" port for the 'bind()' + * call. It is safe for overflow, but must be considered, + * when running multiple test applications simultaneously + * where 'peer-port' argument differs by 1. + */ + client_fd = vsock_bind_connect(opts->peer_cid, opts->peer_port, + opts->peer_port + 1, SOCK_STREAM); close(client_fd); } @@ -1246,7 +1252,7 @@ static void test_stream_rcvlowat_def_cred_upd_client(const struct test_opts *opt void *buf; int fd; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -1282,7 +1288,7 @@ static void test_stream_credit_update_test(const struct test_opts *opts, void *buf; int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -1542,6 +1548,11 @@ static const struct option longopts[] = { .has_arg = required_argument, .val = 'p', }, + { + .name = "peer-port", + .has_arg = required_argument, + .val = 'q', + }, { .name = "list", .has_arg = no_argument, @@ -1562,7 +1573,7 @@ static const struct option longopts[] = { static void usage(void) { - fprintf(stderr, "Usage: vsock_test [--help] [--control-host=] --control-port= --mode=client|server --peer-cid= [--list] [--skip=]\n" + fprintf(stderr, "Usage: vsock_test [--help] [--control-host=] --control-port= --mode=client|server --peer-cid= [--peer-port=] [--list] [--skip=]\n" "\n" " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n" " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" @@ -1577,6 +1588,9 @@ static void usage(void) "connect to.\n" "\n" "The CID of the other side must be given with --peer-cid=.\n" + "During the test, two AF_VSOCK ports will be used: the port\n" + "specified with --peer-port= (or the default port)\n" + "and the next one.\n" "\n" "Options:\n" " --help This help message\n" @@ -1584,9 +1598,11 @@ static void usage(void) " --control-port Server port to listen on/connect to\n" " --mode client|server Server or client mode\n" " --peer-cid CID of the other side\n" + " --peer-port AF_VSOCK port used for the test [default: %d]\n" " --list List of tests that will be executed\n" " --skip Test ID to skip;\n" - " use multiple --skip options to skip more tests\n" + " use multiple --skip options to skip more tests\n", + DEFAULT_PEER_PORT ); exit(EXIT_FAILURE); } @@ -1598,6 +1614,7 @@ int main(int argc, char **argv) struct test_opts opts = { .mode = TEST_MODE_UNSET, .peer_cid = VMADDR_CID_ANY, + .peer_port = DEFAULT_PEER_PORT, }; srand(time(NULL)); @@ -1626,6 +1643,9 @@ int main(int argc, char **argv) case 'p': opts.peer_cid = parse_cid(optarg); break; + case 'q': + opts.peer_port = parse_port(optarg); + break; case 'P': control_port = optarg; break; diff --git a/tools/testing/vsock/vsock_test_zerocopy.c b/tools/testing/vsock/vsock_test_zerocopy.c index a16ff76484e6..04c376b6937f 100644 --- a/tools/testing/vsock/vsock_test_zerocopy.c +++ b/tools/testing/vsock/vsock_test_zerocopy.c @@ -152,9 +152,9 @@ static void test_client(const struct test_opts *opts, int fd; if (sock_seqpacket) - fd = vsock_seqpacket_connect(opts->peer_cid, 1234); + fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port); else - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); @@ -248,9 +248,9 @@ static void test_server(const struct test_opts *opts, int fd; if (sock_seqpacket) - fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL); else - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); @@ -323,7 +323,7 @@ void test_stream_msgzcopy_empty_errq_client(const struct test_opts *opts) ssize_t res; int fd; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -347,7 +347,7 @@ void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts) { int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); diff --git a/tools/testing/vsock/vsock_uring_test.c b/tools/testing/vsock/vsock_uring_test.c index d976d35f0ba9..6c3e6f70c457 100644 --- a/tools/testing/vsock/vsock_uring_test.c +++ b/tools/testing/vsock/vsock_uring_test.c @@ -66,7 +66,7 @@ static void vsock_io_uring_client(const struct test_opts *opts, struct msghdr msg; int fd; - fd = vsock_stream_connect(opts->peer_cid, 1234); + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); if (fd < 0) { perror("connect"); exit(EXIT_FAILURE); @@ -120,7 +120,7 @@ static void vsock_io_uring_server(const struct test_opts *opts, void *data; int fd; - fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); if (fd < 0) { perror("accept"); exit(EXIT_FAILURE); @@ -247,6 +247,11 @@ static const struct option longopts[] = { .has_arg = required_argument, .val = 'p', }, + { + .name = "peer-port", + .has_arg = required_argument, + .val = 'q', + }, { .name = "help", .has_arg = no_argument, @@ -257,7 +262,7 @@ static const struct option longopts[] = { static void usage(void) { - fprintf(stderr, "Usage: vsock_uring_test [--help] [--control-host=] --control-port= --mode=client|server --peer-cid=\n" + fprintf(stderr, "Usage: vsock_uring_test [--help] [--control-host=] --control-port= --mode=client|server --peer-cid= [--peer-port=]\n" "\n" " Server: vsock_uring_test --control-port=1234 --mode=server --peer-cid=3\n" " Client: vsock_uring_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" @@ -271,6 +276,8 @@ static void usage(void) " --control-port Server port to listen on/connect to\n" " --mode client|server Server or client mode\n" " --peer-cid CID of the other side\n" + " --peer-port AF_VSOCK port used for the test [default: %d]\n", + DEFAULT_PEER_PORT ); exit(EXIT_FAILURE); } @@ -282,6 +289,7 @@ int main(int argc, char **argv) struct test_opts opts = { .mode = TEST_MODE_UNSET, .peer_cid = VMADDR_CID_ANY, + .peer_port = DEFAULT_PEER_PORT, }; init_signals(); @@ -309,6 +317,9 @@ int main(int argc, char **argv) case 'p': opts.peer_cid = parse_cid(optarg); break; + case 'q': + opts.peer_port = parse_port(optarg); + break; case 'P': control_port = optarg; break; From 88bf1b8f3c3196c175c9291605ec741756979862 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 22 Jan 2024 21:12:01 -0800 Subject: [PATCH 0295/2255] tipc: socket: remove Excess struct member kernel-doc warning Remove a kernel-doc description to squelch a warning: socket.c:143: warning: Excess struct member 'blocking_link' description in 'tipc_sock' Signed-off-by: Randy Dunlap Cc: Jon Maloy Cc: Ying Xue Cc: Jonathan Corbet Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240123051201.24701-1-rdunlap@infradead.org Signed-off-by: Jakub Kicinski --- net/tipc/socket.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index bb1118d02f95..7e4135db5816 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -80,7 +80,6 @@ struct sockaddr_pair { * @phdr: preformatted message header used when sending messages * @cong_links: list of congested links * @publications: list of publications for port - * @blocking_link: address of the congested link we are currently sleeping on * @pub_count: total # of publications port has made during its lifetime * @conn_timeout: the time we can wait for an unresponded setup request * @probe_unacked: probe has not received ack yet From 5ca1a5153a28dc8bcfeeafa983915b76af457929 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 22 Jan 2024 21:11:52 -0800 Subject: [PATCH 0296/2255] tipc: node: remove Excess struct member kernel-doc warnings Remove 2 kernel-doc descriptions to squelch warnings: node.c:150: warning: Excess struct member 'inputq' description in 'tipc_node' node.c:150: warning: Excess struct member 'namedq' description in 'tipc_node' Signed-off-by: Randy Dunlap Cc: Jon Maloy Cc: Ying Xue Cc: Jonathan Corbet Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240123051152.23684-1-rdunlap@infradead.org Signed-off-by: Jakub Kicinski --- net/tipc/node.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 3105abe97bb9..c1e890a82434 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -86,8 +86,6 @@ struct tipc_bclink_entry { * @lock: rwlock governing access to structure * @net: the applicable net namespace * @hash: links to adjacent nodes in unsorted hash chain - * @inputq: pointer to input queue containing messages for msg event - * @namedq: pointer to name table input queue with name table messages * @active_links: bearer ids of active links, used as index into links[] array * @links: array containing references to all links to node * @bc_entry: broadcast link entry From 63b21caba17ef2df5982c7b75eb989100212b27b Mon Sep 17 00:00:00 2001 From: Antony Antony Date: Fri, 19 Jan 2024 12:27:42 +0100 Subject: [PATCH 0297/2255] xfrm: introduce forwarding of ICMP Error messages This commit aligns with RFC 4301, Section 6, and addresses the requirement to forward unauthenticated ICMP error messages that do not match any xfrm policies. It utilizes the ICMP payload as an skb and performs a reverse lookup. If a policy match is found, forward the packet. The ICMP payload typically contains a partial IP packet that is likely responsible for the error message. The following error types will be forwarded: - IPv4 ICMP error types: ICMP_DEST_UNREACH & ICMP_TIME_EXCEEDED - IPv6 ICMPv6 error types: ICMPV6_DEST_UNREACH, ICMPV6_PKT_TOOBIG, ICMPV6_TIME_EXCEED To implement this feature, a reverse lookup has been added to the xfrm forward path, making use of the ICMP payload as the skb. To enable this functionality from user space, the XFRM_POLICY_ICMP flag should be added to the outgoing and forward policies, and the XFRM_STATE_ICMP flag should be set on incoming states. e.g. ip xfrm policy add flag icmp tmpl ip xfrm policy src 192.0.2.0/24 dst 192.0.1.0/25 dir out priority 2084302 ptype main flag icmp ip xfrm state add ...flag icmp ip xfrm state root@west:~#ip x s src 192.1.2.23 dst 192.1.2.45 proto esp spi 0xa7b76872 reqid 16389 mode tunnel replay-window 32 flag icmp af-unspec Changes since v5: - fix return values bool->int, feedback from Steffen Changes since v4: - split the series to only ICMP erorr forwarding Changes since v3: no code chage - add missing white spaces detected by checkpatch.pl Changes since v2: reviewed by Steffen Klassert - user consume_skb instead of kfree_skb for the inner skb - fixed newskb leaks in error paths - free the newskb once inner flow is decoded with change due to commit 7a0207094f1b ("xfrm: policy: replace session decode with flow dissector") - if xfrm_decode_session_reverse() on inner payload fails ignore. do not increment error counter Changes since v1: - Move IPv6 variable declaration inside IS_ENABLED(CONFIG_IPV6) Changes since RFC: - Fix calculation of ICMPv6 header length Signed-off-by: Antony Antony Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_policy.c | 142 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 1b7e75159727..b4850a8f14ad 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -3503,6 +3504,128 @@ static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int return 0; } +static bool icmp_err_packet(const struct flowi *fl, unsigned short family) +{ + const struct flowi4 *fl4 = &fl->u.ip4; + + if (family == AF_INET && + fl4->flowi4_proto == IPPROTO_ICMP && + (fl4->fl4_icmp_type == ICMP_DEST_UNREACH || + fl4->fl4_icmp_type == ICMP_TIME_EXCEEDED)) + return true; + +#if IS_ENABLED(CONFIG_IPV6) + if (family == AF_INET6) { + const struct flowi6 *fl6 = &fl->u.ip6; + + if (fl6->flowi6_proto == IPPROTO_ICMPV6 && + (fl6->fl6_icmp_type == ICMPV6_DEST_UNREACH || + fl6->fl6_icmp_type == ICMPV6_PKT_TOOBIG || + fl6->fl6_icmp_type == ICMPV6_TIME_EXCEED)) + return true; + } +#endif + return false; +} + +static bool xfrm_icmp_flow_decode(struct sk_buff *skb, unsigned short family, + const struct flowi *fl, struct flowi *fl1) +{ + bool ret = true; + struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); + int hl = family == AF_INET ? (sizeof(struct iphdr) + sizeof(struct icmphdr)) : + (sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr)); + + if (!newskb) + return true; + + if (!pskb_pull(newskb, hl)) + goto out; + + skb_reset_network_header(newskb); + + if (xfrm_decode_session_reverse(dev_net(skb->dev), newskb, fl1, family) < 0) + goto out; + + fl1->flowi_oif = fl->flowi_oif; + fl1->flowi_mark = fl->flowi_mark; + fl1->flowi_tos = fl->flowi_tos; + nf_nat_decode_session(newskb, fl1, family); + ret = false; + +out: + consume_skb(newskb); + return ret; +} + +static bool xfrm_selector_inner_icmp_match(struct sk_buff *skb, unsigned short family, + const struct xfrm_selector *sel, + const struct flowi *fl) +{ + bool ret = false; + + if (icmp_err_packet(fl, family)) { + struct flowi fl1; + + if (xfrm_icmp_flow_decode(skb, family, fl, &fl1)) + return ret; + + ret = xfrm_selector_match(sel, &fl1, family); + } + + return ret; +} + +static inline struct +xfrm_policy *xfrm_in_fwd_icmp(struct sk_buff *skb, + const struct flowi *fl, unsigned short family, + u32 if_id) +{ + struct xfrm_policy *pol = NULL; + + if (icmp_err_packet(fl, family)) { + struct flowi fl1; + struct net *net = dev_net(skb->dev); + + if (xfrm_icmp_flow_decode(skb, family, fl, &fl1)) + return pol; + + pol = xfrm_policy_lookup(net, &fl1, family, XFRM_POLICY_FWD, if_id); + } + + return pol; +} + +static inline struct +dst_entry *xfrm_out_fwd_icmp(struct sk_buff *skb, struct flowi *fl, + unsigned short family, struct dst_entry *dst) +{ + if (icmp_err_packet(fl, family)) { + struct net *net = dev_net(skb->dev); + struct dst_entry *dst2; + struct flowi fl1; + + if (xfrm_icmp_flow_decode(skb, family, fl, &fl1)) + return dst; + + dst_hold(dst); + + dst2 = xfrm_lookup(net, dst, &fl1, NULL, (XFRM_LOOKUP_QUEUE | XFRM_LOOKUP_ICMP)); + + if (IS_ERR(dst2)) + return dst; + + if (dst2->xfrm) { + dst_release(dst); + dst = dst2; + } else { + dst_release(dst2); + } + } + + return dst; +} + int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) { @@ -3549,9 +3672,17 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, for (i = sp->len - 1; i >= 0; i--) { struct xfrm_state *x = sp->xvec[i]; + int ret = 0; + if (!xfrm_selector_match(&x->sel, &fl, family)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); - return 0; + ret = 1; + if (x->props.flags & XFRM_STATE_ICMP && + xfrm_selector_inner_icmp_match(skb, family, &x->sel, &fl)) + ret = 0; + if (ret) { + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); + return 0; + } } } } @@ -3574,6 +3705,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, return 0; } + if (!pol && dir == XFRM_POLICY_FWD) + pol = xfrm_in_fwd_icmp(skb, &fl, family, if_id); + if (!pol) { if (net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK) { XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS); @@ -3707,6 +3841,10 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) res = 0; dst = NULL; } + + if (dst && !dst->xfrm) + dst = xfrm_out_fwd_icmp(skb, &fl, family, dst); + skb_dst_set(skb, dst); return res; } From ab1e1a38de240057ed108075abd1309c02e2a2a4 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Wed, 24 Jan 2024 14:31:50 +0800 Subject: [PATCH 0298/2255] xfrm6_tunnel: Use KMEM_CACHE instead of kmem_cache_create Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Signed-off-by: Steffen Klassert --- net/ipv6/xfrm6_tunnel.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 1323f2f6928e..0f3df26878a3 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -355,10 +355,7 @@ static int __init xfrm6_tunnel_init(void) { int rv; - xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", - sizeof(struct xfrm6_tunnel_spi), - 0, SLAB_HWCACHE_ALIGN, - NULL); + xfrm6_tunnel_spi_kmem = KMEM_CACHE(xfrm6_tunnel_spi, SLAB_HWCACHE_ALIGN); if (!xfrm6_tunnel_spi_kmem) return -ENOMEM; rv = register_pernet_subsys(&xfrm6_tunnel_net_ops); From 91374ba537bd60caa9ae052c9f1c0fe055b39149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:34:31 +0300 Subject: [PATCH 0299/2255] net: dsa: mt7530: support OF-based registration of switch MDIO bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the MDIO bus of the switches the MT7530 DSA subdriver controls can only be registered as non-OF-based. Bring support for registering the bus OF-based. The subdrivers that control switches [with MDIO bus] probed on OF must follow this logic to support all cases properly: No switch MDIO bus defined: Populate ds->user_mii_bus, register the MDIO bus, set the interrupts for PHYs if "interrupt-controller" is defined at the switch node. This case should only be covered for the switches which their dt-bindings documentation didn't document the MDIO bus from the start. This is to keep supporting the device trees that do not describe the MDIO bus on the device tree but the MDIO bus is being used nonetheless. Switch MDIO bus defined: Don't populate ds->user_mii_bus, register the MDIO bus, set the interrupts for PHYs if ["interrupt-controller" is defined at the switch node and "interrupts" is defined at the PHY nodes under the switch MDIO bus node]. Switch MDIO bus defined but explicitly disabled: If the device tree says status = "disabled" for the MDIO bus, we shouldn't need an MDIO bus at all. Instead, just exit as early as possible and do not call any MDIO API. The use of ds->user_mii_bus is inappropriate when the MDIO bus of the switch is described on the device tree [1], which is why we don't populate ds->user_mii_bus in that case. Link: https://lore.kernel.org/netdev/20231213120656.x46fyad6ls7sqyzv@skbuf/ [1] Suggested-by: David Bauer Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122053431.7751-1-arinc.unal@arinc9.com Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 391c4dbdff42..cf2ff7680c15 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2146,24 +2146,40 @@ mt7530_free_irq_common(struct mt7530_priv *priv) static void mt7530_free_irq(struct mt7530_priv *priv) { - mt7530_free_mdio_irq(priv); + struct device_node *mnp, *np = priv->dev->of_node; + + mnp = of_get_child_by_name(np, "mdio"); + if (!mnp) + mt7530_free_mdio_irq(priv); + of_node_put(mnp); + mt7530_free_irq_common(priv); } static int mt7530_setup_mdio(struct mt7530_priv *priv) { + struct device_node *mnp, *np = priv->dev->of_node; struct dsa_switch *ds = priv->ds; struct device *dev = priv->dev; struct mii_bus *bus; static int idx; - int ret; + int ret = 0; + + mnp = of_get_child_by_name(np, "mdio"); + + if (mnp && !of_device_is_available(mnp)) + goto out; bus = devm_mdiobus_alloc(dev); - if (!bus) - return -ENOMEM; + if (!bus) { + ret = -ENOMEM; + goto out; + } + + if (!mnp) + ds->user_mii_bus = bus; - ds->user_mii_bus = bus; bus->priv = priv; bus->name = KBUILD_MODNAME "-mii"; snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++); @@ -2174,16 +2190,18 @@ mt7530_setup_mdio(struct mt7530_priv *priv) bus->parent = dev; bus->phy_mask = ~ds->phys_mii_mask; - if (priv->irq) + if (priv->irq && !mnp) mt7530_setup_mdio_irq(priv); - ret = devm_mdiobus_register(dev, bus); + ret = devm_of_mdiobus_register(dev, bus, mnp); if (ret) { dev_err(dev, "failed to register MDIO bus: %d\n", ret); - if (priv->irq) + if (priv->irq && !mnp) mt7530_free_mdio_irq(priv); } +out: + of_node_put(mnp); return ret; } From dbd73acb22d85873ecca51fdb33a0e50d11e8021 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 09:52:01 +0800 Subject: [PATCH 0300/2255] wifi: ath11k: enable 36 bit mask for stream DMA Currently 32 bit DMA mask is used, telling kernel to get us an DMA address under 4GB when mapping a buffer. This results in a very high CPU overhead in the case where IOMMU is disabled and more than 4GB system memory is installed. The reason is, with more than 4GB memory installed, kernel is likely to allocate a buffer whose physical address is above 4GB. While with IOMMU disabled, kernel has to involve SWIOTLB to map/unmap that buffer, which consumes lots of CPU cycles. We did hit an issue caused by the reason mentioned above: in a system that disables IOMMU and gets 8GB memory installed, a total of 40.5% CPU usage is observed in throughput test. CPU profiling shows nearly 60% of CPU cycles are consumed by SWIOTLB. By enabling 36 bit DMA mask, we can bypass SWIOTLB for any buffer whose physical address is below 64GB. There are two types of DMA mask within struct device, named dma_mask and coherent_dma_mask. Here we only enable 36 bit for dma_mask, because firmware crashes if coherent_dma_mask is also enabled, due to some unknown hardware limitations. This is acceptable because coherent_dma_mask is used for mapping a consistent DMA buffer, which generally does not happen in a hot path. With this change, the total CPU usage mentioned in above issue drops to 18.9%. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123015201.28939-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mhi.c | 4 ++-- drivers/net/wireless/ath/ath11k/pci.c | 19 +++++++++++++++---- drivers/net/wireless/ath/ath11k/pci.h | 3 ++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 6835c14b82cc..e6e69bb91103 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -423,7 +423,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) goto free_controller; } else { mhi_ctrl->iova_start = 0; - mhi_ctrl->iova_stop = 0xFFFFFFFF; + mhi_ctrl->iova_stop = ab_pci->dma_mask; } mhi_ctrl->rddm_size = RDDM_DUMP_SIZE; diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 09e65c5e55c4..d667d5e06a66 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -18,7 +18,8 @@ #include "qmi.h" #define ATH11K_PCI_BAR_NUM 0 -#define ATH11K_PCI_DMA_MASK 32 +#define ATH11K_PCI_DMA_MASK 36 +#define ATH11K_PCI_COHERENT_DMA_MASK 32 #define TCSR_SOC_HW_VERSION 0x0224 #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) @@ -526,14 +527,24 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) goto disable_device; } - ret = dma_set_mask_and_coherent(&pdev->dev, - DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); + ret = dma_set_mask(&pdev->dev, + DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); if (ret) { ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", ATH11K_PCI_DMA_MASK, ret); goto release_region; } + ab_pci->dma_mask = DMA_BIT_MASK(ATH11K_PCI_DMA_MASK); + + ret = dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(ATH11K_PCI_COHERENT_DMA_MASK)); + if (ret) { + ath11k_err(ab, "failed to set pci coherent dma mask to %d: %d\n", + ATH11K_PCI_COHERENT_DMA_MASK, ret); + goto release_region; + } + pci_set_master(pdev); ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index e9a01f344ec6..6be73333d90b 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_PCI_H #define _ATH11K_PCI_H @@ -72,6 +72,7 @@ struct ath11k_pci { /* enum ath11k_pci_flags */ unsigned long flags; u16 link_ctl; + u64 dma_mask; }; static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) From 171203f0c4093dfe7e73ceb6c38033595f329f56 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:57 +0800 Subject: [PATCH 0301/2255] wifi: ath11k: remove invalid peer create logic In ath11k_mac_op_assign_vif_chanctx(), there is a logic to create peer using ar->mac_addr for a STA vdev. This is invalid because a STA vdev should have a peer created using AP's MAC address. Besides, if we run into that logic, it means a peer has already been created earlier, we should not create it again. So remove it. This is found during code review. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index bf4a97967177..33ab66afb97f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -8108,7 +8108,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); int ret; - struct peer_create_params param; struct cur_regulatory_info *reg_info; enum ieee80211_ap_reg_power power_type; @@ -8151,21 +8150,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - if (ab->hw_params.vdev_start_delay && - arvif->vdev_type != WMI_VDEV_TYPE_AP && - arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { - param.vdev_id = arvif->vdev_id; - param.peer_type = WMI_PEER_TYPE_DEFAULT; - param.peer_addr = ar->mac_addr; - - ret = ath11k_peer_create(ar, arvif, NULL, ¶m); - if (ret) { - ath11k_warn(ab, "failed to create peer after vdev start delay: %d", - ret); - goto out; - } - } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath11k_mac_monitor_start(ar); if (ret) { From 629642fa8b25b8dfecefc9e2177a44c009858da7 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:58 +0800 Subject: [PATCH 0302/2255] wifi: ath11k: rename ath11k_start_vdev_delay() Rename ath11k_start_vdev_delay() as ath11k_mac_start_vdev_delay() to follow naming convention. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 33ab66afb97f..9d041065f81c 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -255,8 +255,8 @@ static const u32 ath11k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; -static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); +static int ath11k_mac_start_vdev_delay(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy) { @@ -4987,7 +4987,7 @@ static int ath11k_mac_station_add(struct ath11k *ar, if (ab->hw_params.vdev_start_delay && !arvif->is_started && arvif->vdev_type != WMI_VDEV_TYPE_AP) { - ret = ath11k_start_vdev_delay(ar->hw, vif); + ret = ath11k_mac_start_vdev_delay(ar->hw, vif); if (ret) { ath11k_warn(ab, "failed to delay vdev start: %d\n", ret); goto free_tx_stats; @@ -7581,8 +7581,8 @@ 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; From ce59902e56ea0477ad9bef0067d0e47b6c4d707d Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:59 +0800 Subject: [PATCH 0303/2255] wifi: ath11k: avoid forward declaration of ath11k_mac_start_vdev_delay() Currently ath11k_mac_start_vdev_delay() needs a forward declaration because it is defined after where it is called. Avoid this by re-arranging ath11k_mac_station_add() and ath11k_mac_op_sta_state(). No functional changes. Compile tested only. Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 459 +++++++++++++------------- 1 file changed, 228 insertions(+), 231 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 9d041065f81c..324bbb377eac 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -255,9 +255,6 @@ static const u32 ath11k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; -static int ath11k_mac_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); - enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy) { enum nl80211_he_ru_alloc ret; @@ -4917,100 +4914,6 @@ static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif, ar->num_stations--; } -static int ath11k_mac_station_add(struct ath11k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct ath11k_base *ab = ar->ab; - struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); - struct peer_create_params peer_param; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - ret = ath11k_mac_inc_num_stations(arvif, sta); - if (ret) { - ath11k_warn(ab, "refusing to associate station: too many connected already (%d)\n", - ar->max_num_stations); - goto exit; - } - - arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); - if (!arsta->rx_stats) { - ret = -ENOMEM; - goto dec_num_station; - } - - peer_param.vdev_id = arvif->vdev_id; - peer_param.peer_addr = sta->addr; - peer_param.peer_type = WMI_PEER_TYPE_DEFAULT; - - ret = ath11k_peer_create(ar, arvif, sta, &peer_param); - if (ret) { - ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - goto free_rx_stats; - } - - ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - - if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) { - arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL); - if (!arsta->tx_stats) { - ret = -ENOMEM; - goto free_peer; - } - } - - if (ieee80211_vif_is_mesh(vif)) { - ath11k_dbg(ab, ATH11K_DBG_MAC, - "setting USE_4ADDR for mesh STA %pM\n", sta->addr); - ret = ath11k_wmi_set_peer_param(ar, sta->addr, - arvif->vdev_id, - WMI_PEER_USE_4ADDR, 1); - if (ret) { - ath11k_warn(ab, "failed to set mesh STA %pM 4addr capability: %d\n", - sta->addr, ret); - goto free_tx_stats; - } - } - - ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr); - if (ret) { - ath11k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n", - sta->addr, arvif->vdev_id, ret); - goto free_tx_stats; - } - - if (ab->hw_params.vdev_start_delay && - !arvif->is_started && - arvif->vdev_type != WMI_VDEV_TYPE_AP) { - ret = ath11k_mac_start_vdev_delay(ar->hw, vif); - if (ret) { - ath11k_warn(ab, "failed to delay vdev start: %d\n", ret); - goto free_tx_stats; - } - } - - ewma_avg_rssi_init(&arsta->avg_rssi); - return 0; - -free_tx_stats: - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; -free_peer: - ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); -free_rx_stats: - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; -dec_num_station: - ath11k_mac_dec_num_stations(arvif, sta); -exit: - return ret; -} - static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, struct ieee80211_sta *sta) { @@ -5039,140 +4942,6 @@ static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, return bw; } -static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - enum ieee80211_sta_state old_state, - enum ieee80211_sta_state new_state) -{ - struct ath11k *ar = hw->priv; - struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); - struct ath11k_peer *peer; - int ret = 0; - - /* cancel must be done outside the mutex to avoid deadlock */ - if ((old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST)) { - cancel_work_sync(&arsta->update_wk); - cancel_work_sync(&arsta->set_4addr_wk); - } - - mutex_lock(&ar->conf_mutex); - - if (old_state == IEEE80211_STA_NOTEXIST && - new_state == IEEE80211_STA_NONE) { - memset(arsta, 0, sizeof(*arsta)); - arsta->arvif = arvif; - arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; - INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk); - INIT_WORK(&arsta->set_4addr_wk, ath11k_sta_set_4addr_wk); - - ret = ath11k_mac_station_add(ar, vif, sta); - if (ret) - ath11k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - } else if ((old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST)) { - bool skip_peer_delete = ar->ab->hw_params.vdev_start_delay && - vif->type == NL80211_IFTYPE_STATION; - - ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); - - if (!skip_peer_delete) { - ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); - if (ret) - ath11k_warn(ar->ab, - "Failed to delete peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - else - ath11k_dbg(ar->ab, - ATH11K_DBG_MAC, - "Removed peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - } - - ath11k_mac_dec_num_stations(arvif, sta); - mutex_lock(&ar->ab->tbl_mtx_lock); - spin_lock_bh(&ar->ab->base_lock); - peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); - if (skip_peer_delete && peer) { - peer->sta = NULL; - } else if (peer && peer->sta == sta) { - ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", - vif->addr, arvif->vdev_id); - ath11k_peer_rhash_delete(ar->ab, peer); - peer->sta = NULL; - list_del(&peer->list); - kfree(peer); - ar->num_peers--; - } - spin_unlock_bh(&ar->ab->base_lock); - mutex_unlock(&ar->ab->tbl_mtx_lock); - - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; - - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; - } else if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_ASSOC && - (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath11k_station_assoc(ar, vif, sta, false); - if (ret) - ath11k_warn(ar->ab, "Failed to associate station: %pM\n", - sta->addr); - - spin_lock_bh(&ar->data_lock); - /* Set arsta bw and prev bw */ - arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta); - arsta->bw_prev = arsta->bw; - spin_unlock_bh(&ar->data_lock); - } else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTHORIZED) { - spin_lock_bh(&ar->ab->base_lock); - - peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); - if (peer) - peer->is_authorized = true; - - spin_unlock_bh(&ar->ab->base_lock); - - if (vif->type == NL80211_IFTYPE_STATION && arvif->is_up) { - ret = ath11k_wmi_set_peer_param(ar, sta->addr, - arvif->vdev_id, - WMI_PEER_AUTHORIZE, - 1); - if (ret) - ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n", - sta->addr, arvif->vdev_id, ret); - } - } else if (old_state == IEEE80211_STA_AUTHORIZED && - new_state == IEEE80211_STA_ASSOC) { - spin_lock_bh(&ar->ab->base_lock); - - peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); - if (peer) - peer->is_authorized = false; - - spin_unlock_bh(&ar->ab->base_lock); - } else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTH && - (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath11k_station_disassoc(ar, vif, sta); - if (ret) - ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n", - sta->addr); - } - - mutex_unlock(&ar->conf_mutex); - return ret; -} - static int ath11k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -9610,6 +9379,234 @@ 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, From 9d5f28c1366f48efae7b1df0f622285519e74dce Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:57:00 +0800 Subject: [PATCH 0304/2255] wifi: ath11k: fix connection failure due to unexpected peer delete Currently ath11k_mac_op_unassign_vif_chanctx() deletes peer but ath11k_mac_op_assign_vif_chanctx() doesn't create it. This results in connection failure if MAC80211 calls drv_unassign_vif_chanctx() and drv_assign_vif_chanctx() during AUTH and ASSOC, see below log: [ 102.372431] wlan0: authenticated [ 102.372585] ath11k_pci 0000:01:00.0: wlan0: disabling HT/VHT/HE as WMM/QoS is not supported by the AP [ 102.372593] ath11k_pci 0000:01:00.0: mac chanctx unassign ptr ffff895084638598 vdev_id 0 [ 102.372808] ath11k_pci 0000:01:00.0: WMI vdev stop id 0x0 [ 102.383114] ath11k_pci 0000:01:00.0: vdev stopped for vdev id 0 [ 102.384689] ath11k_pci 0000:01:00.0: WMI peer delete vdev_id 0 peer_addr 20:e5:2a:21:c4:51 [ 102.396676] ath11k_pci 0000:01:00.0: htt peer unmap vdev 0 peer 20:e5:2a:21:c4:51 id 3 [ 102.396711] ath11k_pci 0000:01:00.0: peer delete resp for vdev id 0 addr 20:e5:2a:21:c4:51 [ 102.396722] ath11k_pci 0000:01:00.0: mac removed peer 20:e5:2a:21:c4:51 vdev 0 after vdev stop [ 102.396780] ath11k_pci 0000:01:00.0: mac chanctx assign ptr ffff895084639c18 vdev_id 0 [ 102.400628] wlan0: associate with 20:e5:2a:21:c4:51 (try 1/3) [ 102.508864] wlan0: associate with 20:e5:2a:21:c4:51 (try 2/3) [ 102.612815] wlan0: associate with 20:e5:2a:21:c4:51 (try 3/3) [ 102.720846] wlan0: association with 20:e5:2a:21:c4:51 timed out The peer delete logic in ath11k_mac_op_unassign_vif_chanctx() is introduced by commit b4a0f54156ac ("ath11k: move peer delete after vdev stop of station for QCA6390 and WCN6855") to fix firmware crash issue caused by unexpected vdev stop/peer delete sequence. Actually for a STA interface peer should be deleted in ath11k_mac_op_sta_state() when STA's state changes from IEEE80211_STA_NONE to IEEE80211_STA_NOTEXIST, which also coincides with current peer creation design that peer is created during IEEE80211_STA_NOTEXIST -> IEEE80211_STA_NONE transition. So move peer delete back to ath11k_mac_op_sta_state(), also stop vdev before deleting peer to fix the firmware crash issue mentioned there. In this way the connection failure mentioned here is also fixed. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Fixes: b4a0f54156ac ("ath11k: move peer delete after vdev stop of station for QCA6390 and WCN6855") Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 139 ++++++++++++++++---------- 1 file changed, 85 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 324bbb377eac..4a6ab45e9386 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7397,6 +7397,30 @@ static int ath11k_mac_start_vdev_delay(struct ieee80211_hw *hw, return 0; } +static int ath11k_mac_stop_vdev_early(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath11k *ar = hw->priv; + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + int ret; + + if (WARN_ON(!arvif->is_started)) + return -EBUSY; + + ret = ath11k_mac_vdev_stop(arvif); + if (ret) { + ath11k_warn(ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + arvif->is_started = false; + + /* TODO: Setup ps and cts/rts protection */ + return 0; +} + static u8 ath11k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt) { switch (txpwr_intrprt) { @@ -7931,15 +7955,17 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - ret = ath11k_mac_vdev_start(arvif, ctx); - if (ret) { - ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", - arvif->vdev_id, vif->addr, - ctx->def.chan->center_freq, ret); - goto out; - } + if (!arvif->is_started) { + ret = ath11k_mac_vdev_start(arvif, ctx); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", + arvif->vdev_id, vif->addr, + ctx->def.chan->center_freq, ret); + goto out; + } - arvif->is_started = true; + arvif->is_started = true; + } if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { @@ -7979,8 +8005,6 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, "chanctx unassign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); - WARN_ON(!arvif->is_started); - if (ab->hw_params.vdev_start_delay && arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { spin_lock_bh(&ab->base_lock); @@ -8004,24 +8028,13 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, return; } - ret = ath11k_mac_vdev_stop(arvif); - if (ret) - ath11k_warn(ab, "failed to stop vdev %i: %d\n", - arvif->vdev_id, ret); - - arvif->is_started = false; - - if (ab->hw_params.vdev_start_delay && - arvif->vdev_type == WMI_VDEV_TYPE_STA) { - ret = ath11k_peer_delete(ar, arvif->vdev_id, arvif->bssid); + if (arvif->is_started) { + ret = ath11k_mac_vdev_stop(arvif); if (ret) - ath11k_warn(ar->ab, - "failed to delete peer %pM for vdev %d: %d\n", - arvif->bssid, arvif->vdev_id, ret); - else - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "removed peer %pM vdev %d after vdev stop\n", - arvif->bssid, arvif->vdev_id); + ath11k_warn(ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + + arvif->is_started = false; } if (ab->hw_params.vdev_start_delay && @@ -9473,6 +9486,46 @@ 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; + ret = ath11k_mac_station_remove(ar, vif, sta); + if (ret) + ath11k_warn(ar->ab, "Failed to remove station: %pM for VDEV: %d\n", + sta->addr, arvif->vdev_id); - ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); - - if (!skip_peer_delete) { - ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); - if (ret) - ath11k_warn(ar->ab, - "Failed to delete peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - else - ath11k_dbg(ar->ab, - ATH11K_DBG_MAC, - "Removed peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - } - - ath11k_mac_dec_num_stations(arvif, sta); mutex_lock(&ar->ab->tbl_mtx_lock); spin_lock_bh(&ar->ab->base_lock); peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); - if (skip_peer_delete && peer) { - peer->sta = NULL; - } else if (peer && peer->sta == sta) { + if (peer && peer->sta == sta) { ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", vif->addr, arvif->vdev_id); ath11k_peer_rhash_delete(ar->ab, peer); @@ -9543,12 +9580,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, } spin_unlock_bh(&ar->ab->base_lock); mutex_unlock(&ar->ab->tbl_mtx_lock); - - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; - - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || From 14a12e6c0b7f03b08573f972789cd1a499d473f0 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 24 Jan 2024 15:19:29 -0300 Subject: [PATCH 0305/2255] selftests: tc-testing: add missing netfilter config On a default config + tc-testing config build, tdc will miss all the netfilter related tests because it's missing: CONFIG_NETFILTER=y Signed-off-by: Pedro Tammela Reviewed-by: Davide Caratti Acked-by: Jamal Hadi Salim Reviewed-by: Davide Caratti Link: https://lore.kernel.org/r/20240124181933.75724-2-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/config | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/tc-testing/config b/tools/testing/selftests/tc-testing/config index c60acba951c2..db176fe7d0c3 100644 --- a/tools/testing/selftests/tc-testing/config +++ b/tools/testing/selftests/tc-testing/config @@ -8,6 +8,7 @@ CONFIG_VETH=y # # Core Netfilter Configuration # +CONFIG_NETFILTER=y CONFIG_NETFILTER_ADVANCED=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_MARK=y From 4f4d3841214056b3a35c030ceaa52092c3ed7fb5 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 24 Jan 2024 15:19:30 -0300 Subject: [PATCH 0306/2255] selftests: tc-testing: check if 'jq' is available in taprio tests If 'jq' is not available the taprio tests might enter an infinite loop, use the "dependsOn" feature from tdc to check if jq is present. If it's not the test is skipped. Suggested-by: Davide Caratti Signed-off-by: Pedro Tammela Reviewed-by: Davide Caratti Acked-by: Jamal Hadi Salim Reviewed-by: Davide Caratti Link: https://lore.kernel.org/r/20240124181933.75724-3-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json index 2d603ef2e375..12da0a939e3e 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json @@ -167,6 +167,7 @@ "plugins": { "requires": "nsPlugin" }, + "dependsOn": "echo '' | jq", "setup": [ "echo \"1 1 8\" > /sys/bus/netdevsim/new_device", "$TC qdisc replace dev $ETH handle 8001: parent root stab overhead 24 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 0 sched-entry S ff 20000000 clockid CLOCK_TAI", @@ -192,6 +193,7 @@ "plugins": { "requires": "nsPlugin" }, + "dependsOn": "echo '' | jq", "setup": [ "echo \"1 1 8\" > /sys/bus/netdevsim/new_device", "$TC qdisc replace dev $ETH handle 8001: parent root stab overhead 24 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 0 sched-entry S ff 20000000 flags 0x2", From 3007d8712c9b0c8f5f72c2e8b72bf71496f52196 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 24 Jan 2024 15:19:31 -0300 Subject: [PATCH 0307/2255] selftests: tc-testing: adjust fq test to latest iproute2 Adjust the fq verify regex to the latest iproute2 Signed-off-by: Pedro Tammela Reviewed-by: Davide Caratti Acked-by: Jamal Hadi Salim Reviewed-by: Davide Caratti Link: https://lore.kernel.org/r/20240124181933.75724-4-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq.json index be293e7c6d18..3a537b2ec4c9 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/fq.json @@ -77,7 +77,7 @@ "cmdUnderTest": "$TC qdisc add dev $DUMMY handle 1: root fq quantum 9000", "expExitCode": "0", "verifyCmd": "$TC qdisc show dev $DUMMY", - "matchPattern": "qdisc fq 1: root refcnt [0-9]+ limit 10000p flow_limit 100p buckets.*orphan_mask 1023 quantum 9000b", + "matchPattern": "qdisc fq 1: root refcnt [0-9]+ limit 10000p flow_limit 100p.*quantum 9000b", "matchCount": "1", "teardown": [ "$TC qdisc del dev $DUMMY handle 1: root" From d17d0e333707a8437eb37b35945d233ddc431de3 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 24 Jan 2024 15:19:32 -0300 Subject: [PATCH 0308/2255] selftests: tc-testing: enable all tdc tests For the longest time tdc ran only actions and qdiscs tests. It's time to enable all the remaining tests so every user visible piece of TC is tested by the downstream CIs. Signed-off-by: Pedro Tammela Reviewed-by: Davide Caratti Acked-by: Jamal Hadi Salim Reviewed-by: Davide Caratti Link: https://lore.kernel.org/r/20240124181933.75724-5-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/tdc.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/testing/selftests/tc-testing/tdc.sh b/tools/testing/selftests/tc-testing/tdc.sh index c53ede8b730d..cddff1772e10 100755 --- a/tools/testing/selftests/tc-testing/tdc.sh +++ b/tools/testing/selftests/tc-testing/tdc.sh @@ -63,5 +63,4 @@ try_modprobe sch_hfsc try_modprobe sch_hhf try_modprobe sch_htb try_modprobe sch_teql -./tdc.py -J`nproc` -c actions -./tdc.py -J`nproc` -c qdisc +./tdc.py -J`nproc` From 8981a85e1ba792f1de035cf98ea3fd8592d7ffbd Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Wed, 24 Jan 2024 15:19:33 -0300 Subject: [PATCH 0309/2255] selftests: tc-testing: return fail if a test fails in setup/teardown As of today tests throwing exceptions in setup/teardown phase are treated as skipped but they should really be failures. Signed-off-by: Pedro Tammela Reviewed-by: Davide Caratti Acked-by: Jamal Hadi Salim Reviewed-by: Davide Caratti Link: https://lore.kernel.org/r/20240124181933.75724-6-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/tc-testing/tdc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index caeacc691587..ee349187636f 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -541,7 +541,7 @@ def test_runner(pm, args, filtered_tests): message = pmtf.message output = pmtf.output res = TestResult(tidx['id'], tidx['name']) - res.set_result(ResultState.skip) + res.set_result(ResultState.fail) res.set_errormsg(pmtf.message) res.set_failmsg(pmtf.output) tsr.add_resultdata(res) From 767ec326f98546a1c7ab556cd379cd625332b5e1 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Wed, 24 Jan 2024 22:32:55 +0300 Subject: [PATCH 0310/2255] vsock/test: print type for SOCK_SEQPACKET SOCK_SEQPACKET is supported for virtio transport, so do not interpret such type of socket as unknown. Signed-off-by: Arseniy Krasnov Reviewed-by: Stefano Garzarella Acked-by: Michael S. Tsirkin Link: https://lore.kernel.org/r/20240124193255.3417803-1-avkrasnov@salutedevices.com Signed-off-by: Jakub Kicinski --- tools/testing/vsock/vsock_diag_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/vsock/vsock_diag_test.c b/tools/testing/vsock/vsock_diag_test.c index 9d61b1f1c4c3..081e045f4696 100644 --- a/tools/testing/vsock/vsock_diag_test.c +++ b/tools/testing/vsock/vsock_diag_test.c @@ -39,6 +39,8 @@ static const char *sock_type_str(int type) return "DGRAM"; case SOCK_STREAM: return "STREAM"; + case SOCK_SEQPACKET: + return "SEQPACKET"; default: return "INVALID TYPE"; } From ad9b701aed48b0a682f56b4bee03731d9d1834bd Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 24 Jan 2024 14:41:15 -0700 Subject: [PATCH 0311/2255] selftest: Update PATH for nettest in fcnal-test Allow fcnal-test.sh to be run from top level directory in the kernel repo as well as from tools/testing/selftests/net by setting the PATH to find the in-tree nettest. Signed-off-by: David Ahern Link: https://lore.kernel.org/r/20240124214117.24687-2-dsahern@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/fcnal-test.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 0d4f252427e2..3d69fac6bcc0 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -38,6 +38,9 @@ # server / client nomenclature relative to ns-A source lib.sh + +PATH=$PWD:$PWD/tools/testing/selftests/net:$PATH + VERBOSE=0 NSA_DEV=eth1 From 79bf0d4a07d4af8fd646d07b70b11abd47c41083 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 24 Jan 2024 14:41:16 -0700 Subject: [PATCH 0312/2255] selftest: Fix set of ping_group_range in fcnal-test ping_group_range sysctl has a compound value which does not go through the various function layers in tact. Create a helper function to bypass the layers and correctly set the value. Signed-off-by: David Ahern Link: https://lore.kernel.org/r/20240124214117.24687-3-dsahern@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/fcnal-test.sh | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 3d69fac6bcc0..f590b0fb740e 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -190,6 +190,15 @@ kill_procs() sleep 1 } +set_ping_group() +{ + if [ "$VERBOSE" = "1" ]; then + echo "COMMAND: ${NSA_CMD} sysctl -q -w net.ipv4.ping_group_range='0 2147483647'" + fi + + ${NSA_CMD} sysctl -q -w net.ipv4.ping_group_range='0 2147483647' +} + do_run_cmd() { local cmd="$*" @@ -838,14 +847,14 @@ ipv4_ping() set_sysctl net.ipv4.raw_l3mdev_accept=1 2>/dev/null ipv4_ping_novrf setup - set_sysctl net.ipv4.ping_group_range='0 2147483647' 2>/dev/null + set_ping_group ipv4_ping_novrf log_subsection "With VRF" setup "yes" ipv4_ping_vrf setup "yes" - set_sysctl net.ipv4.ping_group_range='0 2147483647' 2>/dev/null + set_ping_group ipv4_ping_vrf } @@ -2056,12 +2065,12 @@ ipv4_addr_bind() log_subsection "No VRF" setup - set_sysctl net.ipv4.ping_group_range='0 2147483647' 2>/dev/null + set_ping_group ipv4_addr_bind_novrf log_subsection "With VRF" setup "yes" - set_sysctl net.ipv4.ping_group_range='0 2147483647' 2>/dev/null + set_ping_group ipv4_addr_bind_vrf } @@ -2524,14 +2533,14 @@ ipv6_ping() setup ipv6_ping_novrf setup - set_sysctl net.ipv4.ping_group_range='0 2147483647' 2>/dev/null + set_ping_group ipv6_ping_novrf log_subsection "With VRF" setup "yes" ipv6_ping_vrf setup "yes" - set_sysctl net.ipv4.ping_group_range='0 2147483647' 2>/dev/null + set_ping_group ipv6_ping_vrf } From 70863c902d76f8837652539698bc261c763a2869 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 24 Jan 2024 14:41:17 -0700 Subject: [PATCH 0313/2255] selftest: Show expected and actual return codes for test failures in fcnal-test Capture expected and actual return codes for a test that fails in the fcnal-test suite. Signed-off-by: David Ahern Link: https://lore.kernel.org/r/20240124214117.24687-4-dsahern@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/fcnal-test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index f590b0fb740e..d7cfb7c2b427 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -109,6 +109,7 @@ log_test() else nfail=$((nfail+1)) printf "TEST: %-70s [FAIL]\n" "${msg}" + echo " expected rc $expected; actual rc $rc" if [ "${PAUSE_ON_FAIL}" = "yes" ]; then echo echo "hit enter to continue, 'q' to quit" From 3df18416267bb0d390399f4e63f74f7d76c5d92e Mon Sep 17 00:00:00 2001 From: Ankit Garg Date: Wed, 24 Jan 2024 20:54:35 +0000 Subject: [PATCH 0314/2255] gve: Modify rx_buf_alloc_fail counter centrally and closer to failure Previously, each caller of gve_rx_alloc_buffer had to increase counter and as a result one caller was not tracking those failure. Increasing counters at a common location now so callers don't have to duplicate code or miss counter management. Signed-off-by: Ankit Garg Link: https://lore.kernel.org/r/20240124205435.1021490-1-nktgrg@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_rx.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c index c294a1595b6a..c32b3d40beb0 100644 --- a/drivers/net/ethernet/google/gve/gve_rx.c +++ b/drivers/net/ethernet/google/gve/gve_rx.c @@ -105,7 +105,8 @@ static void gve_setup_rx_buffer(struct gve_rx_slot_page_info *page_info, static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev, struct gve_rx_slot_page_info *page_info, - union gve_rx_data_slot *data_slot) + union gve_rx_data_slot *data_slot, + struct gve_rx_ring *rx) { struct page *page; dma_addr_t dma; @@ -113,8 +114,12 @@ static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev, err = gve_alloc_page(priv, dev, &page, &dma, DMA_FROM_DEVICE, GFP_ATOMIC); - if (err) + if (err) { + u64_stats_update_begin(&rx->statss); + rx->rx_buf_alloc_fail++; + u64_stats_update_end(&rx->statss); return err; + } gve_setup_rx_buffer(page_info, dma, page, &data_slot->addr); return 0; @@ -156,8 +161,9 @@ static int gve_rx_prefill_pages(struct gve_rx_ring *rx, &rx->data.data_ring[i].qpl_offset); continue; } - err = gve_rx_alloc_buffer(priv, &priv->pdev->dev, &rx->data.page_info[i], - &rx->data.data_ring[i]); + err = gve_rx_alloc_buffer(priv, &priv->pdev->dev, + &rx->data.page_info[i], + &rx->data.data_ring[i], rx); if (err) goto alloc_err_rda; } @@ -936,10 +942,7 @@ static bool gve_rx_refill_buffers(struct gve_priv *priv, struct gve_rx_ring *rx) gve_rx_free_buffer(dev, page_info, data_slot); page_info->page = NULL; if (gve_rx_alloc_buffer(priv, dev, page_info, - data_slot)) { - u64_stats_update_begin(&rx->statss); - rx->rx_buf_alloc_fail++; - u64_stats_update_end(&rx->statss); + data_slot, rx)) { break; } } From 5f76499fb541c3e8ae401414bfdf702940c8c531 Mon Sep 17 00:00:00 2001 From: Gerhard Engleder Date: Tue, 23 Jan 2024 21:01:51 +0100 Subject: [PATCH 0315/2255] tsnep: Add link down PHY loopback support PHY loopback turns off link state change signalling. Therefore, the loopback only works if the link is already up before the PHY loopback is activated. Ensure that PHY loopback works even if the link is not already up during activation by calling netif_carrier_on() explicitly. Signed-off-by: Gerhard Engleder Link: https://lore.kernel.org/r/20240123200151.60848-1-gerhard@engleder-embedded.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/engleder/tsnep_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index 9aeff2b37a61..ae0b8b37b9bf 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -229,8 +229,10 @@ static int tsnep_phy_loopback(struct tsnep_adapter *adapter, bool enable) * would delay a working loopback anyway, let's ensure that loopback * is working immediately by setting link mode directly */ - if (!retval && enable) + if (!retval && enable) { + netif_carrier_on(adapter->netdev); tsnep_set_link_mode(adapter); + } return retval; } From be4840b33eb2ea7d80830530aab5fcbeaa90e857 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Fri, 26 Jan 2024 05:25:54 +0200 Subject: [PATCH 0316/2255] bpf: One more maintainer for libbpf and BPF selftests I've been working on BPF verifier, BPF selftests and, to some extent, libbpf, for some time. As suggested by Andrii and Alexei, I humbly ask to add me to maintainers list: - As reviewer for BPF [GENERAL] - As maintainer for BPF [LIBRARY] - As maintainer for BPF [SELFTESTS] This patch adds dedicated entries to MAINTAINERS. Signed-off-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240126032554.9697-1-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8709c7cd3656..0707eeea689a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3792,6 +3792,7 @@ M: Alexei Starovoitov M: Daniel Borkmann M: Andrii Nakryiko R: Martin KaFai Lau +R: Eduard Zingerman R: Song Liu R: Yonghong Song R: John Fastabend @@ -3852,6 +3853,7 @@ F: net/unix/unix_bpf.c BPF [LIBRARY] (libbpf) M: Andrii Nakryiko +M: Eduard Zingerman L: bpf@vger.kernel.org S: Maintained F: tools/lib/bpf/ @@ -3909,6 +3911,7 @@ F: security/bpf/ BPF [SELFTESTS] (Test Runners & Infrastructure) M: Andrii Nakryiko +M: Eduard Zingerman R: Mykola Lysenko L: bpf@vger.kernel.org S: Maintained From e6be8cd5d3cf54ccd0ae66027d6f4697b15f4c3e Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 25 Jan 2024 18:31:13 -0800 Subject: [PATCH 0317/2255] bpf: Fix error checks against bpf_get_btf_vmlinux(). In bpf_struct_ops_map_alloc, it needs to check for NULL in the returned pointer of bpf_get_btf_vmlinux() when CONFIG_DEBUG_INFO_BTF is not set. ENOTSUPP is used to preserve the same behavior before the struct_ops kmod support. In the function check_struct_ops_btf_id(), instead of redoing the bpf_get_btf_vmlinux() that has already been done in syscall.c, the fix here is to check for prog->aux->attach_btf_id. BPF_PROG_TYPE_STRUCT_OPS must require attach_btf_id and syscall.c guarantees a valid attach_btf as long as attach_btf_id is set. When attach_btf_id is not set, this patch returns -ENOTSUPP because it is what the selftest in test_libbpf_probe_prog_types() and libbpf_probes.c are expecting for feature probing purpose. Changes from v1: - Remove an unnecessary NULL check in check_struct_ops_btf_id() Reported-by: syzbot+88f0aafe5f950d7489d7@syzkaller.appspotmail.com Closes: https://lore.kernel.org/bpf/00000000000040d68a060fc8db8c@google.com/ Reported-by: syzbot+1336f3d4b10bcda75b89@syzkaller.appspotmail.com Closes: https://lore.kernel.org/bpf/00000000000026353b060fc21c07@google.com/ Fixes: fcc2c1fb0651 ("bpf: pass attached BTF to the bpf_struct_ops subsystem") Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240126023113.1379504-1-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/bpf_struct_ops.c | 2 ++ kernel/bpf/verifier.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index defc052e4622..0decd862dfe0 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -669,6 +669,8 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) btf = bpf_get_btf_vmlinux(); if (IS_ERR(btf)) return ERR_CAST(btf); + if (!btf) + return ERR_PTR(-ENOTSUPP); } st_ops_desc = bpf_struct_ops_find_value(btf, attr->btf_vmlinux_value_type_id); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index fe833e831cb6..c5d68a9d8acc 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20298,7 +20298,10 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) return -EINVAL; } - btf = prog->aux->attach_btf ?: bpf_get_btf_vmlinux(); + if (!prog->aux->attach_btf_id) + return -ENOTSUPP; + + btf = prog->aux->attach_btf; if (btf_is_module(btf)) { /* Make sure st_ops is valid through the lifetime of env */ env->attach_btf_mod = btf_try_get_module(btf); From 7f78840cf4d4ac9ab36ddf574a025a45835375d0 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 10 Jan 2024 08:42:06 +0300 Subject: [PATCH 0318/2255] wifi: wireless: avoid strlen() in cfg80211_michael_mic_failure() In 'cfg80211_michael_mic_failure()', avoid extra call to 'strlen()' by using the value returned by 'sprintf()'. Compile tested only. Signed-off-by: Dmitry Antipov Link: https://msgid.link/20240110054246.371651-1-dmantipov@yandex.ru Signed-off-by: Johannes Berg --- net/wireless/mlme.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index f635a8b6ca2e..43ba7891e2a3 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -241,12 +241,12 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, char *buf = kmalloc(128, gfp); if (buf) { - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=%pM)", key_id, - key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni", - addr); memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); + wrqu.data.length = + sprintf(buf, "MLME-MICHAELMICFAILURE." + "indication(keyid=%d %scast addr=%pM)", + key_id, key_type == NL80211_KEYTYPE_GROUP + ? "broad" : "uni", addr); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); kfree(buf); } From 4d1d6b3f45999b1ddde53831d639a67e2655285f Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 2 Jan 2024 21:35:32 +0200 Subject: [PATCH 0319/2255] wifi: cfg80211: add RNR with reporting AP information If the reporting AP is part of the same MLD, then an entry in the RNR is required in order to discover it again from the BSS generated from the per-STA profile in the Multi-Link Probe Response. We need this because we do not have a direct concept of an MLD AP and just do the lookup from one to the other on the fly if needed. As such, we need to ensure that this lookup will work both ways. Fixes: 2481b5da9c6b ("wifi: cfg80211: handle BSS data contained in ML probe responses") Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.4cb3dbb1d84f.I7c74edec83c5d7598cdd578929fd0876d67aef7f@changeid [roll in off-by-one fix and test updates from Benjamin] Signed-off-by: Johannes Berg --- net/wireless/scan.c | 135 ++++++++++++++++++++++++++++++++++++-- net/wireless/tests/scan.c | 36 +++++++++- 2 files changed, 163 insertions(+), 8 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2249b1a89d1c..01618c4059f4 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2617,6 +2617,103 @@ cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, return 0; } +static struct element * +cfg80211_gen_reporter_rnr(struct cfg80211_bss *source_bss, bool is_mbssid, + bool same_mld, u8 link_id, u8 bss_change_count, + gfp_t gfp) +{ + const struct cfg80211_bss_ies *ies; + struct ieee80211_neighbor_ap_info ap_info; + struct ieee80211_tbtt_info_ge_11 tbtt_info; + u32 short_ssid; + const struct element *elem; + struct element *res; + + /* + * We only generate the RNR to permit ML lookups. For that we do not + * need an entry for the corresponding transmitting BSS, lets just skip + * it even though it would be easy to add. + */ + if (!same_mld) + return NULL; + + /* We could use tx_data->ies if we change cfg80211_calc_short_ssid */ + rcu_read_lock(); + ies = rcu_dereference(source_bss->ies); + + ap_info.tbtt_info_len = offsetofend(typeof(tbtt_info), mld_params); + ap_info.tbtt_info_hdr = + u8_encode_bits(IEEE80211_TBTT_INFO_TYPE_TBTT, + IEEE80211_AP_INFO_TBTT_HDR_TYPE) | + u8_encode_bits(0, IEEE80211_AP_INFO_TBTT_HDR_COUNT); + + ap_info.channel = ieee80211_frequency_to_channel(source_bss->channel->center_freq); + + /* operating class */ + elem = cfg80211_find_elem(WLAN_EID_SUPPORTED_REGULATORY_CLASSES, + ies->data, ies->len); + if (elem && elem->datalen >= 1) { + ap_info.op_class = elem->data[0]; + } else { + struct cfg80211_chan_def chandef; + + /* The AP is not providing us with anything to work with. So + * make up a somewhat reasonable operating class, but don't + * bother with it too much as no one will ever use the + * information. + */ + cfg80211_chandef_create(&chandef, source_bss->channel, + NL80211_CHAN_NO_HT); + + if (!ieee80211_chandef_to_operating_class(&chandef, + &ap_info.op_class)) + goto out_unlock; + } + + /* Just set TBTT offset and PSD 20 to invalid/unknown */ + tbtt_info.tbtt_offset = 255; + tbtt_info.psd_20 = IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED; + + memcpy(tbtt_info.bssid, source_bss->bssid, ETH_ALEN); + if (cfg80211_calc_short_ssid(ies, &elem, &short_ssid)) + goto out_unlock; + + rcu_read_unlock(); + + tbtt_info.short_ssid = cpu_to_le32(short_ssid); + + tbtt_info.bss_params = IEEE80211_RNR_TBTT_PARAMS_SAME_SSID; + + if (is_mbssid) { + tbtt_info.bss_params |= IEEE80211_RNR_TBTT_PARAMS_MULTI_BSSID; + tbtt_info.bss_params |= IEEE80211_RNR_TBTT_PARAMS_TRANSMITTED_BSSID; + } + + tbtt_info.mld_params.mld_id = 0; + tbtt_info.mld_params.params = + le16_encode_bits(link_id, IEEE80211_RNR_MLD_PARAMS_LINK_ID) | + le16_encode_bits(bss_change_count, + IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); + + res = kzalloc(struct_size(res, data, + sizeof(ap_info) + ap_info.tbtt_info_len), + gfp); + if (!res) + return NULL; + + /* Copy the data */ + res->id = WLAN_EID_REDUCED_NEIGHBOR_REPORT; + res->datalen = sizeof(ap_info) + ap_info.tbtt_info_len; + memcpy(res->data, &ap_info, sizeof(ap_info)); + memcpy(res->data + sizeof(ap_info), &tbtt_info, ap_info.tbtt_info_len); + + return res; + +out_unlock: + rcu_read_unlock(); + return NULL; +} + static void cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, struct cfg80211_inform_single_bss_data *tx_data, @@ -2630,13 +2727,14 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, .source_bss = source_bss, .bss_source = BSS_SOURCE_STA_PROFILE, }; + struct element *reporter_rnr = NULL; struct ieee80211_multi_link_elem *ml_elem; struct cfg80211_mle *mle; u16 control; u8 ml_common_len; - u8 *new_ie; + u8 *new_ie = NULL; struct cfg80211_bss *bss; - int mld_id; + u8 mld_id, reporter_link_id, bss_change_count; u16 seen_links = 0; const u8 *pos; u8 i; @@ -2658,8 +2756,14 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, ml_common_len = ml_elem->variable[0]; - /* length + MLD MAC address + link ID info + BSS Params Change Count */ - pos = ml_elem->variable + 1 + 6 + 1 + 1; + /* length + MLD MAC address */ + pos = ml_elem->variable + 1 + 6; + + reporter_link_id = pos[0]; + pos += 1; + + bss_change_count = pos[0]; + pos += 1; if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) pos += 2; @@ -2690,10 +2794,21 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, if (!mle) return; + /* No point in doing anything if there is no per-STA profile */ + if (!mle->sta_prof[0]) + goto out; + new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp); if (!new_ie) goto out; + reporter_rnr = cfg80211_gen_reporter_rnr(source_bss, + u16_get_bits(control, + IEEE80211_MLC_BASIC_PRES_MLD_ID), + mld_id == 0, reporter_link_id, + bss_change_count, + gfp); + for (i = 0; i < ARRAY_SIZE(mle->sta_prof) && mle->sta_prof[i]; i++) { const struct ieee80211_neighbor_ap_info *ap_info; enum nl80211_band band; @@ -2803,7 +2918,16 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, data.ielen += sizeof(*ml_elem) + ml_common_len; - /* TODO: Add an RNR containing only the reporting AP */ + if (reporter_rnr && (use_for & NL80211_BSS_USE_FOR_NORMAL)) { + if (data.ielen + sizeof(struct element) + + reporter_rnr->datalen > IEEE80211_MAX_DATA_LEN) + continue; + + memcpy(new_ie + data.ielen, reporter_rnr, + sizeof(struct element) + reporter_rnr->datalen); + data.ielen += sizeof(struct element) + + reporter_rnr->datalen; + } bss = cfg80211_inform_single_bss_data(wiphy, &data, gfp); if (!bss) @@ -2812,6 +2936,7 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, } out: + kfree(reporter_rnr); kfree(new_ie); kfree(mle); } diff --git a/net/wireless/tests/scan.c b/net/wireless/tests/scan.c index 77854161cd22..f9ea44aee995 100644 --- a/net/wireless/tests/scan.c +++ b/net/wireless/tests/scan.c @@ -2,7 +2,7 @@ /* * KUnit tests for inform_bss functions * - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation */ #include #include @@ -406,9 +406,27 @@ static struct inform_bss_ml_sta_case { const char *desc; int mld_id; bool sta_prof_vendor_elems; + bool include_oper_class; } inform_bss_ml_sta_cases[] = { - { .desc = "no_mld_id", .mld_id = 0, .sta_prof_vendor_elems = false }, - { .desc = "mld_id_eq_1", .mld_id = 1, .sta_prof_vendor_elems = true }, + { + .desc = "zero_mld_id", + .mld_id = 0, + .sta_prof_vendor_elems = false, + }, { + .desc = "zero_mld_id_with_oper_class", + .mld_id = 0, + .sta_prof_vendor_elems = false, + .include_oper_class = true, + }, { + .desc = "mld_id_eq_1", + .mld_id = 1, + .sta_prof_vendor_elems = true, + }, { + .desc = "mld_id_eq_1_with_oper_class", + .mld_id = 1, + .sta_prof_vendor_elems = true, + .include_oper_class = true, + }, }; KUNIT_ARRAY_PARAM_DESC(inform_bss_ml_sta, inform_bss_ml_sta_cases, desc) @@ -515,6 +533,12 @@ static void test_inform_bss_ml_sta(struct kunit *test) skb_put_u8(input, 4); skb_put_data(input, "TEST", 4); + if (params->include_oper_class) { + skb_put_u8(input, WLAN_EID_SUPPORTED_REGULATORY_CLASSES); + skb_put_u8(input, 1); + skb_put_u8(input, 81); + } + skb_put_u8(input, WLAN_EID_REDUCED_NEIGHBOR_REPORT); skb_put_u8(input, sizeof(rnr)); skb_put_data(input, &rnr, sizeof(rnr)); @@ -582,15 +606,21 @@ static void test_inform_bss_ml_sta(struct kunit *test) KUNIT_EXPECT_EQ(test, ies->tsf, tsf + le64_to_cpu(sta_prof.tsf_offset)); /* Resulting length should be: * SSID (inherited) + RNR (inherited) + vendor element(s) + + * operating class (if requested) + + * generated RNR (if MLD ID == 0) + * MLE common info + MLE header and control */ if (params->sta_prof_vendor_elems) KUNIT_EXPECT_EQ(test, ies->len, 6 + 2 + sizeof(rnr) + 2 + 160 + 2 + 165 + + (params->include_oper_class ? 3 : 0) + + (!params->mld_id ? 22 : 0) + mle_basic_common_info.var_len + 5); else KUNIT_EXPECT_EQ(test, ies->len, 6 + 2 + sizeof(rnr) + 2 + 155 + + (params->include_oper_class ? 3 : 0) + + (!params->mld_id ? 22 : 0) + mle_basic_common_info.var_len + 5); rcu_read_unlock(); From 83e897a961b801536dd1d736e9ede5b1ddb1c188 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 2 Jan 2024 21:35:33 +0200 Subject: [PATCH 0320/2255] wifi: ieee80211: add definitions for negotiated TID to Link map Add the relevant definitions and structures for TID to Link mapping negotiation request/response/teardown according to P802.11be_D4.0. Signed-off-by: Ayala Beker Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.9ef2b866c8c7.Ieaf7dadea9961e0edc55d19c99f0f9fbae591de6@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 83c4d060a559..eafa70e5ba94 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1454,6 +1454,20 @@ struct ieee80211_mgmt { u8 max_tod_error; u8 max_toa_error; } __packed wnm_timing_msr; + struct { + u8 action_code; + u8 dialog_token; + u8 variable[]; + } __packed ttlm_req; + struct { + u8 action_code; + u8 dialog_token; + u8 status_code; + u8 variable[]; + } __packed ttlm_res; + struct { + u8 action_code; + } __packed ttlm_tear_down; } u; } __packed action; DECLARE_FLEX_ARRAY(u8, body); /* Generic frame body */ @@ -3357,6 +3371,8 @@ enum ieee80211_statuscode { WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109, WLAN_STATUS_SAE_HASH_TO_ELEMENT = 126, WLAN_STATUS_SAE_PK = 127, + WLAN_STATUS_DENIED_TID_TO_LINK_MAPPING = 133, + WLAN_STATUS_PREF_TID_TO_LINK_MAPPING_SUGGESTED = 134, }; @@ -3682,6 +3698,7 @@ enum ieee80211_category { WLAN_CATEGORY_UNPROT_DMG = 20, WLAN_CATEGORY_VHT = 21, WLAN_CATEGORY_S1G = 22, + WLAN_CATEGORY_PROTECTED_EHT = 37, WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, WLAN_CATEGORY_VENDOR_SPECIFIC = 127, }; @@ -3745,6 +3762,13 @@ enum ieee80211_unprotected_wnm_actioncode { WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE = 1, }; +/* Protected EHT action codes */ +enum ieee80211_protected_eht_actioncode { + WLAN_PROTECTED_EHT_ACTION_TTLM_REQ = 0, + WLAN_PROTECTED_EHT_ACTION_TTLM_RES = 1, + WLAN_PROTECTED_EHT_ACTION_TTLM_TEARDOWN = 2, +}; + /* Security key length */ enum ieee80211_key_len { WLAN_KEY_LEN_WEP40 = 5, @@ -4845,6 +4869,10 @@ struct ieee80211_multi_link_elem { #define IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS 0x000f #define IEEE80211_MLD_CAP_OP_SRS_SUPPORT 0x0010 #define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP 0x0060 +#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_NO_SUPP 0 +#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME 1 +#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_RESERVED 2 +#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_DIFF 3 #define IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND 0x0f80 #define IEEE80211_MLD_CAP_OP_AAR_SUPPORT 0x1000 From 8f500fbc6c655976c8062b1f1e55bd0b3095d6c2 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 2 Jan 2024 21:35:34 +0200 Subject: [PATCH 0321/2255] wifi: mac80211: process and save negotiated TID to Link mapping request An MLD may send TID-to-Link mapping request frame to negotiate TID to link mapping with a peer MLD. Support handling negotiated TID-to-Link mapping request frame by parsing the frame, asking the driver whether it supports the received mapping or not, and sending a TID-to-Link mapping response to the AP MLD. Theoretically, links that became inactive due to the received TID-to-Link mapping request, can be selected to be activated but this would require tearing down the negotiated TID-to-Link mapping, which is still not supported. Signed-off-by: Ayala Beker Reviewed-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.0bc1a24fcc9d.Ie72e47dc6f8c77d4a2f0947b775ef6367fe0edac@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 46 ++++- net/mac80211/driver-ops.h | 19 +++ net/mac80211/ieee80211_i.h | 2 + net/mac80211/iface.c | 12 ++ net/mac80211/main.c | 3 +- net/mac80211/mlme.c | 335 +++++++++++++++++++++++++++++++++++-- net/mac80211/rx.c | 14 ++ net/mac80211/trace.h | 52 ++++++ 8 files changed, 465 insertions(+), 18 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d400fe2e8668..6490b92d5cc1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -342,6 +342,7 @@ struct ieee80211_vif_chanctx_switch { * 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 */ enum ieee80211_bss_change { BSS_CHANGED_ASSOC = 1<<0, @@ -378,6 +379,7 @@ enum ieee80211_bss_change { 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), /* when adding here, make sure to change ieee80211_reconfig */ }; @@ -1845,6 +1847,35 @@ struct ieee80211_vif_cfg { u8 ap_addr[ETH_ALEN] __aligned(2); }; +#define IEEE80211_TTLM_NUM_TIDS 8 + +/** + * struct ieee80211_neg_ttlm - negotiated TID to link map info + * + * @downlink: bitmap of active links per TID for downlink, or 0 if mapping for + * this TID is not included. + * @uplink: bitmap of active links per TID for uplink, or 0 if mapping for this + * TID is not included. + * @valid: info is valid or not. + */ +struct ieee80211_neg_ttlm { + u16 downlink[IEEE80211_TTLM_NUM_TIDS]; + u16 uplink[IEEE80211_TTLM_NUM_TIDS]; + bool valid; +}; + +/** + * enum ieee80211_neg_ttlm_res - return value for negotiated TTLM handling + * @NEG_TTLM_RES_ACCEPT: accept the request + * @NEG_TTLM_RES_REJECT: reject the request + * @NEG_TTLM_RES_SUGGEST_PREFERRED: reject and suggest a new mapping + */ +enum ieee80211_neg_ttlm_res { + NEG_TTLM_RES_ACCEPT, + NEG_TTLM_RES_REJECT, + NEG_TTLM_RES_SUGGEST_PREFERRED +}; + /** * struct ieee80211_vif - per-interface data * @@ -1863,6 +1894,11 @@ struct ieee80211_vif_cfg { * API calls meant for that purpose. * @dormant_links: bitmap of valid but disabled links, or 0 for non-MLO. * Must be a subset of valid_links. + * @suspended_links: subset of dormant_links representing links that are + * suspended. + * 0 for non-MLO. + * @neg_ttlm: negotiated TID to link mapping info. + * see &struct ieee80211_neg_ttlm. * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively @@ -1900,7 +1936,8 @@ struct ieee80211_vif { struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; - u16 valid_links, active_links, dormant_links; + u16 valid_links, active_links, dormant_links, suspended_links; + struct ieee80211_neg_ttlm neg_ttlm; u8 addr[ETH_ALEN] __aligned(2); bool p2p; @@ -4293,6 +4330,10 @@ struct ieee80211_prep_tx_info { * flow offloading for flows originating from the vif. * Note that the driver must not assume that the vif driver_data is valid * at this point, since the callback can be called during netdev teardown. + * @can_neg_ttlm: for managed interface, requests the driver to determine + * if the requested TID-To-Link mapping can be accepted or not. + * If it's not accepted the driver may suggest a preferred mapping and + * modify @ttlm parameter with the suggested TID-to-Link mapping. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4673,6 +4714,9 @@ struct ieee80211_ops { struct net_device *dev, enum tc_setup_type type, void *type_data); + enum ieee80211_neg_ttlm_res + (*can_neg_ttlm)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_neg_ttlm *ttlm); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index eb482fb8c3af..e20c64edb880 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1695,4 +1695,23 @@ int drv_change_sta_links(struct ieee80211_local *local, struct ieee80211_sta *sta, u16 old_links, u16 new_links); +static inline enum ieee80211_neg_ttlm_res +drv_can_neg_ttlm(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_neg_ttlm *neg_ttlm) +{ + enum ieee80211_neg_ttlm_res res = NEG_TTLM_RES_REJECT; + + might_sleep(); + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_can_neg_ttlm(local, sdata, neg_ttlm); + if (local->ops->can_neg_ttlm) + res = local->ops->can_neg_ttlm(&local->hw, &sdata->vif, + neg_ttlm); + trace_drv_neg_ttlm_res(local, sdata, res, neg_ttlm); + + return res; +} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0b2b53550bd9..38755f6f6fa0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2603,6 +2603,8 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, const struct ieee80211_eht_cap_elem *eht_cap_ie_elem, u8 eht_cap_len, struct link_sta_info *link_sta); +void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len); void ieee80211_check_wbrf_support(struct ieee80211_local *local); void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e4e7c0b38cb6..4a87d2d336ae 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1546,6 +1546,18 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, default: break; } + } else if (ieee80211_is_action(mgmt->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_EHT) { + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + switch (mgmt->u.action.u.ttlm_req.action_code) { + case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ: + ieee80211_process_neg_ttlm_req(sdata, mgmt, + skb->len); + break; + default: + break; + } + } } else if (ieee80211_is_ext(mgmt->frame_control)) { if (sdata->vif.type == NL80211_IFTYPE_STATION) ieee80211_sta_rx_queued_ext(sdata, skb); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f2ece7793573..13c417eda281 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -208,7 +208,8 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) BSS_CHANGED_IBSS |\ BSS_CHANGED_ARP_FILTER |\ BSS_CHANGED_SSID |\ - BSS_CHANGED_MLD_VALID_LINKS) + BSS_CHANGED_MLD_VALID_LINKS |\ + BSS_CHANGED_MLD_TTLM) void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u64 changed) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 073105deb424..b56f7de3b53f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1318,8 +1318,6 @@ static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata, cpu_to_le16(IEEE80211_MLC_BASIC_PRES_EML_CAPA); skb_put_data(skb, &eml_capa, sizeof(eml_capa)); } - /* need indication from userspace to support this */ - mld_capa_ops &= ~cpu_to_le16(IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP); skb_put_data(skb, &mld_capa_ops, sizeof(mld_capa_ops)); for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { @@ -5890,6 +5888,56 @@ static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata, TU_TO_JIFFIES(delay)); } +static int ieee80211_ttlm_set_links(struct ieee80211_sub_if_data *sdata, + u16 active_links, u16 dormant_links, + u16 suspended_links) +{ + u64 changed = 0; + int ret; + + if (!active_links) { + ret = -EINVAL; + goto out; + } + + /* If there is an active negotiated TTLM, it should be discarded by + * the new negotiated/advertised TTLM. + */ + if (sdata->vif.neg_ttlm.valid) { + memset(&sdata->vif.neg_ttlm, 0, sizeof(sdata->vif.neg_ttlm)); + sdata->vif.suspended_links = 0; + changed = BSS_CHANGED_MLD_TTLM; + } + + if (sdata->vif.active_links != active_links) { + ret = ieee80211_set_active_links(&sdata->vif, active_links); + if (ret) { + sdata_info(sdata, "Failed to set TTLM active links\n"); + goto out; + } + } + + ret = ieee80211_vif_set_links(sdata, sdata->vif.valid_links, + dormant_links); + if (ret) { + sdata_info(sdata, "Failed to set TTLM dormant links\n"); + goto out; + } + + changed |= BSS_CHANGED_MLD_VALID_LINKS; + sdata->vif.suspended_links = suspended_links; + if (sdata->vif.suspended_links) + changed |= BSS_CHANGED_MLD_TTLM; + + ieee80211_vif_cfg_change_notify(sdata, changed); + +out: + if (ret) + ieee80211_disconnect(&sdata->vif, false); + + return ret; +} + static void ieee80211_tid_to_link_map_work(struct wiphy *wiphy, struct wiphy_work *work) { @@ -5897,30 +5945,19 @@ static void ieee80211_tid_to_link_map_work(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.mgd.ttlm_work.work); - int ret; new_active_links = sdata->u.mgd.ttlm_info.map & sdata->vif.valid_links; new_dormant_links = ~sdata->u.mgd.ttlm_info.map & sdata->vif.valid_links; - if (!new_active_links) { - ieee80211_disconnect(&sdata->vif, false); - return; - } ieee80211_vif_set_links(sdata, sdata->vif.valid_links, 0); - new_active_links = BIT(ffs(new_active_links) - 1); - ieee80211_set_active_links(&sdata->vif, new_active_links); - - ret = ieee80211_vif_set_links(sdata, sdata->vif.valid_links, - new_dormant_links); + if (ieee80211_ttlm_set_links(sdata, new_active_links, new_dormant_links, + 0)) + return; sdata->u.mgd.ttlm_info.active = true; sdata->u.mgd.ttlm_info.switch_time = 0; - - if (!ret) - ieee80211_vif_cfg_change_notify(sdata, - BSS_CHANGED_MLD_VALID_LINKS); } static u16 ieee80211_get_ttlm(u8 bm_size, u8 *data) @@ -6437,6 +6474,272 @@ free: kfree(elems); } +static void ieee80211_apply_neg_ttlm(struct ieee80211_sub_if_data *sdata, + struct ieee80211_neg_ttlm neg_ttlm) +{ + u16 new_active_links, new_dormant_links, new_suspended_links, map = 0; + u8 i; + + for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) + map |= neg_ttlm.downlink[i] | neg_ttlm.uplink[i]; + + /* If there is an active TTLM, unset previously suspended links */ + if (sdata->vif.neg_ttlm.valid) + sdata->vif.dormant_links &= ~sdata->vif.suspended_links; + + /* exclude links that are already disabled by advertised TTLM */ + new_active_links = + map & sdata->vif.valid_links & ~sdata->vif.dormant_links; + new_suspended_links = + (~map & sdata->vif.valid_links) & ~sdata->vif.dormant_links; + new_dormant_links = sdata->vif.dormant_links | new_suspended_links; + if (ieee80211_ttlm_set_links(sdata, new_active_links, + new_dormant_links, new_suspended_links)) + return; + + sdata->vif.neg_ttlm = neg_ttlm; + sdata->vif.neg_ttlm.valid = true; +} + +static void +ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb, + struct ieee80211_neg_ttlm *neg_ttlm) +{ + u8 i, direction[IEEE80211_TTLM_MAX_CNT]; + + if (memcmp(neg_ttlm->downlink, neg_ttlm->uplink, + sizeof(neg_ttlm->downlink))) { + direction[0] = IEEE80211_TTLM_DIRECTION_DOWN; + direction[1] = IEEE80211_TTLM_DIRECTION_UP; + } else { + direction[0] = IEEE80211_TTLM_DIRECTION_BOTH; + } + + for (i = 0; i < ARRAY_SIZE(direction); i++) { + u8 tid, len, map_ind = 0, *len_pos, *map_ind_pos, *pos; + __le16 map; + + len = sizeof(struct ieee80211_ttlm_elem) + 1 + 1; + + pos = skb_put(skb, len + 2); + *pos++ = WLAN_EID_EXTENSION; + len_pos = pos++; + *pos++ = WLAN_EID_EXT_TID_TO_LINK_MAPPING; + *pos++ = direction[i]; + map_ind_pos = pos++; + for (tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) { + map = direction[i] == IEEE80211_TTLM_DIRECTION_UP ? + cpu_to_le16(neg_ttlm->uplink[tid]) : + cpu_to_le16(neg_ttlm->downlink[tid]); + if (!map) + continue; + + len += 2; + map_ind |= BIT(tid); + skb_put_data(skb, &map, sizeof(map)); + } + + *map_ind_pos = map_ind; + *len_pos = len; + + if (direction[i] == IEEE80211_TTLM_DIRECTION_BOTH) + break; + } +} + +static void +ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata, + enum ieee80211_neg_ttlm_res ttlm_res, + u8 dialog_token, + struct ieee80211_neg_ttlm *neg_ttlm) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_mgmt *mgmt; + struct sk_buff *skb; + int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.ttlm_res); + int ttlm_max_len = 2 + 1 + sizeof(struct ieee80211_ttlm_elem) + 1 + + 2 * 2 * IEEE80211_TTLM_NUM_TIDS; + + skb = dev_alloc_skb(local->tx_headroom + hdr_len + ttlm_max_len); + if (!skb) + return; + + skb_reserve(skb, local->tx_headroom); + mgmt = skb_put_zero(skb, hdr_len); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + memcpy(mgmt->da, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN); + + mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT; + mgmt->u.action.u.ttlm_res.action_code = + WLAN_PROTECTED_EHT_ACTION_TTLM_RES; + mgmt->u.action.u.ttlm_res.dialog_token = dialog_token; + switch (ttlm_res) { + default: + WARN_ON(1); + fallthrough; + case NEG_TTLM_RES_REJECT: + mgmt->u.action.u.ttlm_res.status_code = + WLAN_STATUS_DENIED_TID_TO_LINK_MAPPING; + break; + case NEG_TTLM_RES_ACCEPT: + mgmt->u.action.u.ttlm_res.status_code = WLAN_STATUS_SUCCESS; + break; + case NEG_TTLM_RES_SUGGEST_PREFERRED: + mgmt->u.action.u.ttlm_res.status_code = + WLAN_STATUS_PREF_TID_TO_LINK_MAPPING_SUGGESTED; + ieee80211_neg_ttlm_add_suggested_map(skb, neg_ttlm); + break; + } + + ieee80211_tx_skb(sdata, skb); +} + +static int +ieee80211_parse_neg_ttlm(struct ieee80211_sub_if_data *sdata, + const struct ieee80211_ttlm_elem *ttlm, + struct ieee80211_neg_ttlm *neg_ttlm, + u8 *direction) +{ + u8 control, link_map_presence, map_size, tid; + u8 *pos; + + /* The element size was already validated in + * ieee80211_tid_to_link_map_size_ok() + */ + pos = (void *)ttlm->optional; + + control = ttlm->control; + + /* mapping switch time and expected duration fields are not expected + * in case of negotiated TTLM + */ + if (control & (IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT | + IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT)) { + mlme_dbg(sdata, + "Invalid TTLM element in negotiated TTLM request\n"); + return -EINVAL; + } + + if (control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) { + for (tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) { + neg_ttlm->downlink[tid] = sdata->vif.valid_links; + neg_ttlm->uplink[tid] = sdata->vif.valid_links; + } + *direction = IEEE80211_TTLM_DIRECTION_BOTH; + return 0; + } + + *direction = u8_get_bits(control, IEEE80211_TTLM_CONTROL_DIRECTION); + if (*direction != IEEE80211_TTLM_DIRECTION_DOWN && + *direction != IEEE80211_TTLM_DIRECTION_UP && + *direction != IEEE80211_TTLM_DIRECTION_BOTH) + return -EINVAL; + + link_map_presence = *pos; + pos++; + + if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE) + map_size = 1; + else + map_size = 2; + + for (tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) { + u16 map; + + if (link_map_presence & BIT(tid)) { + map = ieee80211_get_ttlm(map_size, pos); + if (!map) { + mlme_dbg(sdata, + "No active links for TID %d", tid); + return -EINVAL; + } + } else { + map = 0; + } + + switch (*direction) { + case IEEE80211_TTLM_DIRECTION_BOTH: + neg_ttlm->downlink[tid] = map; + neg_ttlm->uplink[tid] = map; + break; + case IEEE80211_TTLM_DIRECTION_DOWN: + neg_ttlm->downlink[tid] = map; + break; + case IEEE80211_TTLM_DIRECTION_UP: + neg_ttlm->uplink[tid] = map; + break; + default: + return -EINVAL; + } + pos += map_size; + } + return 0; +} + +void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) +{ + u8 dialog_token, direction[IEEE80211_TTLM_MAX_CNT] = {}, i; + size_t ies_len; + enum ieee80211_neg_ttlm_res ttlm_res = NEG_TTLM_RES_ACCEPT; + struct ieee802_11_elems *elems = NULL; + struct ieee80211_neg_ttlm neg_ttlm = {}; + + BUILD_BUG_ON(ARRAY_SIZE(direction) != ARRAY_SIZE(elems->ttlm)); + + if (!ieee80211_vif_is_mld(&sdata->vif)) + return; + + dialog_token = mgmt->u.action.u.ttlm_req.dialog_token; + ies_len = len - offsetof(struct ieee80211_mgmt, + u.action.u.ttlm_req.variable); + elems = ieee802_11_parse_elems(mgmt->u.action.u.ttlm_req.variable, + ies_len, true, NULL); + if (!elems) { + ttlm_res = NEG_TTLM_RES_REJECT; + goto out; + } + + for (i = 0; i < elems->ttlm_num; i++) { + if (ieee80211_parse_neg_ttlm(sdata, elems->ttlm[i], + &neg_ttlm, &direction[i]) || + (direction[i] == IEEE80211_TTLM_DIRECTION_BOTH && + elems->ttlm_num != 1)) { + ttlm_res = NEG_TTLM_RES_REJECT; + goto out; + } + } + + if (!elems->ttlm_num || + (elems->ttlm_num == 2 && direction[0] == direction[1])) { + ttlm_res = NEG_TTLM_RES_REJECT; + goto out; + } + + for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) { + if ((neg_ttlm.downlink[i] && + (neg_ttlm.downlink[i] & ~sdata->vif.valid_links)) || + (neg_ttlm.uplink[i] && + (neg_ttlm.uplink[i] & ~sdata->vif.valid_links))) { + ttlm_res = NEG_TTLM_RES_REJECT; + goto out; + } + } + + ttlm_res = drv_can_neg_ttlm(sdata->local, sdata, &neg_ttlm); + + if (ttlm_res != NEG_TTLM_RES_ACCEPT) + goto out; + + ieee80211_apply_neg_ttlm(sdata, neg_ttlm); +out: + kfree(elems); + ieee80211_send_neg_ttlm_res(sdata, ttlm_res, dialog_token, &neg_ttlm); +} + void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0bf72928ccfc..75eb3e55eaec 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3763,6 +3763,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) break; } break; + case WLAN_CATEGORY_PROTECTED_EHT: + switch (mgmt->u.action.u.ttlm_req.action_code) { + case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ: + if (sdata->vif.type != NL80211_IFTYPE_STATION) + break; + + if (len < offsetofend(typeof(*mgmt), + u.action.u.ttlm_req)) + goto invalid; + goto queue; + default: + break; + } + break; } return RX_CONTINUE; diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 06835ed4c44f..1c0c46b11c6d 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -3088,6 +3088,58 @@ TRACE_EVENT(stop_queue, ) ); +TRACE_EVENT(drv_can_neg_ttlm, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_neg_ttlm *neg_ttlm), + + TP_ARGS(local, sdata, neg_ttlm), + + TP_STRUCT__entry(LOCAL_ENTRY + VIF_ENTRY + __array(u16, downlink, sizeof(u16) * 8) + __array(u16, uplink, sizeof(u16) * 8) + ), + + TP_fast_assign(LOCAL_ASSIGN; + VIF_ASSIGN; + memcpy(__entry->downlink, neg_ttlm->downlink, + sizeof(neg_ttlm->downlink)); + memcpy(__entry->uplink, neg_ttlm->uplink, + sizeof(neg_ttlm->uplink)); + ), + + TP_printk(LOCAL_PR_FMT ", " VIF_PR_FMT, LOCAL_PR_ARG, VIF_PR_ARG) +); + +TRACE_EVENT(drv_neg_ttlm_res, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + enum ieee80211_neg_ttlm_res res, + struct ieee80211_neg_ttlm *neg_ttlm), + + TP_ARGS(local, sdata, res, neg_ttlm), + + TP_STRUCT__entry(LOCAL_ENTRY + VIF_ENTRY + __field(u32, res) + __array(u16, downlink, sizeof(u16) * 8) + __array(u16, uplink, sizeof(u16) * 8) + ), + + TP_fast_assign(LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->res = res; + memcpy(__entry->downlink, neg_ttlm->downlink, + sizeof(neg_ttlm->downlink)); + memcpy(__entry->uplink, neg_ttlm->uplink, + sizeof(neg_ttlm->uplink)); + ), + + TP_printk(LOCAL_PR_FMT VIF_PR_FMT " response: %d\n ", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->res + ) +); #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH From 03d5110241eb3a7e25030e75b546f6f7a62d3007 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 2 Jan 2024 21:35:35 +0200 Subject: [PATCH 0322/2255] 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(+) 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 { From 9362fabcede336d2e780c6ae44eff0f882349dd2 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 2 Jan 2024 21:35:36 +0200 Subject: [PATCH 0323/2255] 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(-) 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) From f7660b3f584aadd25dde18aa1902488577a15863 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 2 Jan 2024 21:35:37 +0200 Subject: [PATCH 0324/2255] wifi: mac80211: add support for negotiated TTLM request Update neg_ttlm and active_links according to the new mapping, and send a negotiated TID-to-link map request with the new mapping. Signed-off-by: Ayala Beker Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.eeb385d771df.I2a5441c14421de884dbd93d1624ce7bb2c944833@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 37 ++++++++++++ include/net/mac80211.h | 7 ++- net/mac80211/cfg.c | 12 ++++ net/mac80211/ieee80211_i.h | 8 +++ net/mac80211/iface.c | 4 ++ net/mac80211/mlme.c | 114 +++++++++++++++++++++++++++++++++++++ net/mac80211/rx.c | 8 +++ 7 files changed, 188 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index eafa70e5ba94..f0c068446c79 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -5024,6 +5024,43 @@ static inline u16 ieee80211_mle_get_eml_cap(const u8 *data) return get_unaligned_le16(common); } +/** + * ieee80211_mle_get_mld_capa_op - returns the MLD capabilities and operations. + * @data: pointer to the multi link EHT IE + * + * The element is assumed to be of the correct type (BASIC) and big enough, + * this must be checked using ieee80211_mle_type_ok(). + * + * If the MLD capabilities and operations field is not present, 0 will be + * returned. + */ +static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control = le16_to_cpu(mle->control); + const u8 *common = mle->variable; + + /* + * common points now at the beginning of + * ieee80211_mle_basic_common_info + */ + common += sizeof(struct ieee80211_mle_basic_common_info); + + if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)) + return 0; + + if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) + common += 2; + + return get_unaligned_le16(common); +} + /** * ieee80211_mle_size_ok - validate multi-link element size * @data: pointer to the element data diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6490b92d5cc1..84cc66dd93c1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1810,9 +1810,11 @@ enum ieee80211_offload_flags { * @ps: power-save mode (STA only). This flag is NOT affected by * offchannel/dynamic_ps operations. * @aid: association ID number, valid only when @assoc is true - * @eml_cap: EML capabilities as described in P802.11be_D2.2 Figure 9-1002k. + * @eml_cap: EML capabilities as described in P802.11be_D4.1 Figure 9-1001j. * @eml_med_sync_delay: Medium Synchronization delay as described in - * P802.11be_D2.2 Figure 9-1002j. + * P802.11be_D4.1 Figure 9-1001i. + * @mld_capa_op: MLD Capabilities and Operations per P802.11be_D4.1 + * Figure 9-1001k * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The * may filter ARP queries targeted for other addresses than listed here. * The driver must allow ARP queries targeted for all address listed here @@ -1837,6 +1839,7 @@ struct ieee80211_vif_cfg { u16 aid; u16 eml_cap; u16 eml_med_sync_delay; + u16 mld_capa_op; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; int arp_addr_cnt; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 489dd97f5172..1e8da6372da2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4966,6 +4966,17 @@ static int ieee80211_set_hw_timestamp(struct wiphy *wiphy, return local->ops->set_hw_timestamp(&local->hw, &sdata->vif, hwts); } +static int +ieee80211_set_ttlm(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ttlm_params *params) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + lockdep_assert_wiphy(sdata->local->hw.wiphy); + + return ieee80211_req_neg_ttlm(sdata, params); +} + const struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -5078,4 +5089,5 @@ const struct cfg80211_ops mac80211_config_ops = { .mod_link_station = ieee80211_mod_link_station, .del_link_station = ieee80211_del_link_station, .set_hw_timestamp = ieee80211_set_hw_timestamp, + .set_ttlm = ieee80211_set_ttlm, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 38755f6f6fa0..79a5067ce82b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -579,6 +579,10 @@ struct ieee80211_if_managed { /* TID-to-link mapping support */ struct wiphy_delayed_work ttlm_work; struct ieee80211_adv_ttlm_info ttlm_info; + + /* dialog token enumerator for neg TTLM request */ + u8 dialog_token_alloc; + struct wiphy_delayed_work neg_ttlm_timeout_work; }; struct ieee80211_if_ibss { @@ -2605,6 +2609,10 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, struct link_sta_info *link_sta); void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len); +void ieee80211_process_neg_ttlm_res(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len); +int ieee80211_req_neg_ttlm(struct ieee80211_sub_if_data *sdata, + struct cfg80211_ttlm_params *params); void ieee80211_check_wbrf_support(struct ieee80211_local *local); void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4a87d2d336ae..df314222c2c9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1554,6 +1554,10 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, ieee80211_process_neg_ttlm_req(sdata, mgmt, skb->len); break; + case WLAN_PROTECTED_EHT_ACTION_TTLM_RES: + ieee80211_process_neg_ttlm_res(sdata, mgmt, + skb->len); + break; default: break; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b56f7de3b53f..5279af09fd53 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -46,6 +46,8 @@ #define IEEE80211_ADV_TTLM_SAFETY_BUFFER_MS msecs_to_jiffies(100) #define IEEE80211_ADV_TTLM_ST_UNDERFLOW 0xff00 +#define IEEE80211_NEG_TTLM_REQ_TIMEOUT (HZ / 5) + static int max_nullfunc_tries = 2; module_param(max_nullfunc_tries, int, 0644); MODULE_PARM_DESC(max_nullfunc_tries, @@ -3087,6 +3089,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(&sdata->u.mgd.ttlm_info, 0, sizeof(sdata->u.mgd.ttlm_info)); wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ttlm_work); + wiphy_delayed_work_cancel(sdata->local->hw.wiphy, + &ifmgd->neg_ttlm_timeout_work); ieee80211_vif_set_links(sdata, 0, 0); } @@ -4984,6 +4988,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1); sdata->vif.cfg.eml_med_sync_delay = ieee80211_mle_get_eml_med_sync_delay(eht_ml_elem->data + 1); + sdata->vif.cfg.mld_capa_op = + ieee80211_mle_get_mld_capa_op(eht_ml_elem->data + 1); } } @@ -6501,6 +6507,19 @@ static void ieee80211_apply_neg_ttlm(struct ieee80211_sub_if_data *sdata, sdata->vif.neg_ttlm.valid = true; } +static void ieee80211_neg_ttlm_timeout_work(struct wiphy *wiphy, + struct wiphy_work *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.neg_ttlm_timeout_work.work); + + sdata_info(sdata, + "No negotiated TTLM response from AP, disconnecting.\n"); + + __ieee80211_disconnect(sdata); +} + static void ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb, struct ieee80211_neg_ttlm *neg_ttlm) @@ -6547,6 +6566,74 @@ ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb, } } +static void +ieee80211_send_neg_ttlm_req(struct ieee80211_sub_if_data *sdata, + struct ieee80211_neg_ttlm *neg_ttlm, + u8 dialog_token) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_mgmt *mgmt; + struct sk_buff *skb; + int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.ttlm_req); + int ttlm_max_len = 2 + 1 + sizeof(struct ieee80211_ttlm_elem) + 1 + + 2 * 2 * IEEE80211_TTLM_NUM_TIDS; + + skb = dev_alloc_skb(local->tx_headroom + hdr_len + ttlm_max_len); + if (!skb) + return; + + skb_reserve(skb, local->tx_headroom); + mgmt = skb_put_zero(skb, hdr_len); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + memcpy(mgmt->da, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN); + + mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT; + mgmt->u.action.u.ttlm_req.action_code = + WLAN_PROTECTED_EHT_ACTION_TTLM_REQ; + mgmt->u.action.u.ttlm_req.dialog_token = dialog_token; + ieee80211_neg_ttlm_add_suggested_map(skb, neg_ttlm); + ieee80211_tx_skb(sdata, skb); +} + +int ieee80211_req_neg_ttlm(struct ieee80211_sub_if_data *sdata, + struct cfg80211_ttlm_params *params) +{ + struct ieee80211_neg_ttlm neg_ttlm = {}; + u8 i; + + if (!ieee80211_vif_is_mld(&sdata->vif) || + !(sdata->vif.cfg.mld_capa_op & + IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP)) + return -EINVAL; + + for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) { + if ((params->dlink[i] & ~sdata->vif.valid_links) || + (params->ulink[i] & ~sdata->vif.valid_links)) + return -EINVAL; + + neg_ttlm.downlink[i] = params->dlink[i]; + neg_ttlm.uplink[i] = params->ulink[i]; + } + + if (drv_can_neg_ttlm(sdata->local, sdata, &neg_ttlm) != + NEG_TTLM_RES_ACCEPT) + return -EINVAL; + + ieee80211_apply_neg_ttlm(sdata, neg_ttlm); + sdata->u.mgd.dialog_token_alloc++; + ieee80211_send_neg_ttlm_req(sdata, &sdata->vif.neg_ttlm, + sdata->u.mgd.dialog_token_alloc); + wiphy_delayed_work_cancel(sdata->local->hw.wiphy, + &sdata->u.mgd.neg_ttlm_timeout_work); + wiphy_delayed_work_queue(sdata->local->hw.wiphy, + &sdata->u.mgd.neg_ttlm_timeout_work, + IEEE80211_NEG_TTLM_REQ_TIMEOUT); + return 0; +} + static void ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata, enum ieee80211_neg_ttlm_res ttlm_res, @@ -6740,6 +6827,29 @@ out: ieee80211_send_neg_ttlm_res(sdata, ttlm_res, dialog_token, &neg_ttlm); } +void ieee80211_process_neg_ttlm_res(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) +{ + if (!ieee80211_vif_is_mld(&sdata->vif) || + mgmt->u.action.u.ttlm_req.dialog_token != + sdata->u.mgd.dialog_token_alloc) + return; + + wiphy_delayed_work_cancel(sdata->local->hw.wiphy, + &sdata->u.mgd.neg_ttlm_timeout_work); + + /* MLD station sends a TID to link mapping request, mainly to handle + * BTM (BSS transition management) request, in which case it needs to + * restrict the active links set. + * In this case it's not expected that the MLD AP will reject the + * negotiated TTLM request. + * This can be better implemented in the future, to handle request + * rejections. + */ + if (mgmt->u.action.u.ttlm_res.status_code != WLAN_STATUS_SUCCESS) + __ieee80211_disconnect(sdata); +} + void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -7369,6 +7479,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ieee80211_sta_handle_tspec_ac_params_wk); wiphy_delayed_work_init(&ifmgd->ttlm_work, ieee80211_tid_to_link_map_work); + wiphy_delayed_work_init(&ifmgd->neg_ttlm_timeout_work, + ieee80211_neg_ttlm_timeout_work); ifmgd->flags = 0; ifmgd->powersave = sdata->wdev.ps; @@ -8459,6 +8571,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ml_reconf_work); wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ttlm_work); + wiphy_delayed_work_cancel(sdata->local->hw.wiphy, + &ifmgd->neg_ttlm_timeout_work); if (ifmgd->assoc_data) ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 75eb3e55eaec..615795c4b052 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3773,6 +3773,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) u.action.u.ttlm_req)) goto invalid; goto queue; + case WLAN_PROTECTED_EHT_ACTION_TTLM_RES: + if (sdata->vif.type != NL80211_IFTYPE_STATION) + break; + + if (len < offsetofend(typeof(*mgmt), + u.action.u.ttlm_res)) + goto invalid; + goto queue; default: break; } From 34b5ff4617fa1145eec5a1c62fa1ce6ac2fb0b28 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Tue, 2 Jan 2024 21:35:38 +0200 Subject: [PATCH 0325/2255] 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(+) 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); From 2518e89d5b1913c360f8e4cd9fc6eda6146b8800 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jan 2024 21:35:39 +0200 Subject: [PATCH 0326/2255] wifi: cfg80211: add support for SPP A-MSDUs Add SPP (signaling and payload protected) AMSDU support. Since userspace has to build the RSNX element, add an extended feature flag to indicate that this is supported. In order to avoid downgrade/mismatch attacks, add a flag to the assoc command on the station side, so that we can be sure that the value of the flag comes from the same RSNX element that will be validated by the supplicant against the 4-way-handshake. If we just pulled the data out of a beacon/probe response, we could theoretically look an RSNX element from a different frame, with a different value for this flag, than the supplicant is using to validate in the 4-way-handshake. Note that this patch is only geared towards software crypto implementations or hardware ones that can perfectly implement SPP A-MSDUs, i.e. are able to switch the AAD construction on the fly for each TX/RX frame. For more limited hardware implementations, more capability advertisement would be required, e.g. if the hardware has no way to switch this on the fly but has only a global configuration that must apply to all stations. The driver could of course *reject* mismatches, but the supplicant must know so it can do things like not negotiating SPP A-MSDUs on a T-DLS link when connected to an AP that doesn't support it, or similar. Signed-off-by: Johannes Berg Signed-off-by: Daniel Gabay Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.fadac8df7030.I9240aebcba1be49636a73c647ed0af862713fc6f@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ include/uapi/linux/nl80211.h | 14 ++++++++++++++ net/wireless/nl80211.c | 24 +++++++++++++++++++++--- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index cf79656ce09c..56bce924bec6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3059,6 +3059,7 @@ struct cfg80211_assoc_link { * @CONNECT_REQ_MLO_SUPPORT: Userspace indicates support for handling MLD links. * Drivers shall disable MLO features for the current association if this * flag is not set. + * @ASSOC_REQ_SPP_AMSDU: SPP A-MSDUs will be used on this connection (if any) */ enum cfg80211_assoc_req_flags { ASSOC_REQ_DISABLE_HT = BIT(0), @@ -3068,6 +3069,7 @@ enum cfg80211_assoc_req_flags { ASSOC_REQ_DISABLE_HE = BIT(4), ASSOC_REQ_DISABLE_EHT = BIT(5), CONNECT_REQ_MLO_SUPPORT = BIT(6), + ASSOC_REQ_SPP_AMSDU = BIT(7), }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1ccdcae24372..3e239df3528f 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2851,6 +2851,10 @@ enum nl80211_commands { * mapping is as defined in section 9.4.2.314 (TID-To-Link Mapping element) * in Draft P802.11be_D4.0. * + * @NL80211_ATTR_ASSOC_SPP_AMSDU: flag attribute used with + * %NL80211_CMD_ASSOCIATE indicating the SPP A-MSDUs + * are used on this connection + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3394,6 +3398,8 @@ enum nl80211_attrs { NL80211_ATTR_MLO_TTLM_DLINK, NL80211_ATTR_MLO_TTLM_ULINK, + NL80211_ATTR_ASSOC_SPP_AMSDU, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3534,6 +3540,7 @@ enum nl80211_iftype { * @NL80211_STA_FLAG_ASSOCIATED: station is associated; used with drivers * that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a * previously added station into associated state + * @NL80211_STA_FLAG_SPP_AMSDU: station supports SPP A-MSDUs * @NL80211_STA_FLAG_MAX: highest station flag number currently defined * @__NL80211_STA_FLAG_AFTER_LAST: internal use */ @@ -3546,6 +3553,7 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_AUTHENTICATED, NL80211_STA_FLAG_TDLS_PEER, NL80211_STA_FLAG_ASSOCIATED, + NL80211_STA_FLAG_SPP_AMSDU, /* keep last */ __NL80211_STA_FLAG_AFTER_LAST, @@ -6520,6 +6528,11 @@ enum nl80211_feature_flags { * DFS master on the same channel as described in FCC-594280 D01 * (Section B.3). This, for example, allows P2P GO and P2P clients to * operate on DFS channels as long as there's a concurrent BSS connection. + * + * @NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT: The driver has support for SPP + * (signaling and payload protected) A-MSDUs and this shall be advertised + * in the RSNXE. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -6594,6 +6607,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_OWE_OFFLOAD, NL80211_EXT_FEATURE_OWE_OFFLOAD_AP, NL80211_EXT_FEATURE_DFS_CONCURRENT, + NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b09700400d09..b267317aa33c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -821,6 +821,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_BSS_DUMP_INCLUDE_USE_DATA] = { .type = NLA_FLAG }, [NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8), [NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8), + [NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -6874,7 +6875,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy, return -EINVAL; /* When you run into this, adjust the code below for the new flag */ - BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); + BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8); switch (statype) { case CFG80211_STA_MESH_PEER_KERNEL: @@ -6934,6 +6935,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy, params->link_sta_params.he_capa || params->link_sta_params.eht_capa) return -EINVAL; + if (params->sta_flags_mask & BIT(NL80211_STA_FLAG_SPP_AMSDU)) + return -EINVAL; } if (statype != CFG80211_STA_AP_CLIENT && @@ -6957,7 +6960,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy, BIT(NL80211_STA_FLAG_ASSOCIATED) | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | BIT(NL80211_STA_FLAG_WME) | - BIT(NL80211_STA_FLAG_MFP))) + BIT(NL80211_STA_FLAG_MFP) | + BIT(NL80211_STA_FLAG_SPP_AMSDU))) return -EINVAL; /* but authenticated/associated only if driver handles it */ @@ -7516,7 +7520,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) return -EINVAL; /* When you run into this, adjust the code below for the new flag */ - BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); + BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8); switch (dev->ieee80211_ptr->iftype) { case NL80211_IFTYPE_AP: @@ -7540,6 +7544,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.sta_flags_mask & auth_assoc) return -EINVAL; + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT) && + params.sta_flags_mask & BIT(NL80211_STA_FLAG_SPP_AMSDU)) + return -EINVAL; + /* Older userspace, or userspace wanting to be compatible with * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth * and assoc flags in the mask, but assumes the station will be @@ -11102,6 +11111,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) sizeof(req.s1g_capa)); } + if (nla_get_flag(info->attrs[NL80211_ATTR_ASSOC_SPP_AMSDU])) { + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT)) { + GENL_SET_ERR_MSG(info, "SPP A-MSDUs not supported"); + return -EINVAL; + } + req.flags |= ASSOC_REQ_SPP_AMSDU; + } + req.link_id = nl80211_link_id_or_invalid(info->attrs); if (info->attrs[NL80211_ATTR_MLO_LINKS]) { From 3b220ed8b2172fd8edb22a62a5c3a9a9c9f2b6bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jan 2024 21:35:40 +0200 Subject: [PATCH 0327/2255] wifi: mac80211: add support for SPP A-MSDUs If software crypto is used, simply add support for SPP A-MSDUs (and use it whenever enabled as required by the cfg80211 API). If hardware crypto is used, leave it up to the driver to set the NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT flag and then check sta->spp_amsdu or the IEEE80211_KEY_FLAG_SPP_AMSDU key flag. Signed-off-by: Johannes Berg Signed-off-by: Daniel Gabay Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.b8ada4514e2b.I1ac25d5f158165b5a88062a5a5e4c4fbeecf9a5d@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 +++++ net/mac80211/cfg.c | 3 +++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/key.c | 4 ++++ net/mac80211/main.c | 5 ++++- net/mac80211/mlme.c | 4 ++++ net/mac80211/wpa.c | 33 +++++++++++++++++++++++---------- 7 files changed, 44 insertions(+), 11 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 84cc66dd93c1..8d6ae22c09bf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2081,6 +2081,8 @@ static inline bool lockdep_vif_wiphy_mutex_held(struct ieee80211_vif *vif) * @IEEE80211_KEY_FLAG_GENERATE_MMIE: This flag should be set by the driver * for a AES_CMAC key to indicate that it requires sequence number * generation only + * @IEEE80211_KEY_FLAG_SPP_AMSDU: SPP A-MSDUs can be used with this key + * (set by mac80211 from the sta->spp_amsdu flag) */ enum ieee80211_key_flags { IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0), @@ -2094,6 +2096,7 @@ enum ieee80211_key_flags { IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8), IEEE80211_KEY_FLAG_NO_AUTO_TX = BIT(9), IEEE80211_KEY_FLAG_GENERATE_MMIE = BIT(10), + IEEE80211_KEY_FLAG_SPP_AMSDU = BIT(11), }; /** @@ -2392,6 +2395,7 @@ struct ieee80211_link_sta { * would be assigned to link[link_id] where link_id is the id assigned * by the AP. * @valid_links: bitmap of valid links, or 0 for non-MLO + * @spp_amsdu: indicates whether the STA uses SPP A-MSDU or not. */ struct ieee80211_sta { u8 addr[ETH_ALEN]; @@ -2405,6 +2409,7 @@ struct ieee80211_sta { bool tdls_initiator; bool mfp; bool mlo; + bool spp_amsdu; u8 max_amsdu_subframes; struct ieee80211_sta_aggregates *cur; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1e8da6372da2..dd237081dbe3 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1942,6 +1942,9 @@ static int sta_apply_parameters(struct ieee80211_local *local, clear_sta_flag(sta, WLAN_STA_TDLS_PEER); } + if (mask & BIT(NL80211_STA_FLAG_SPP_AMSDU)) + sta->sta.spp_amsdu = set & BIT(NL80211_STA_FLAG_SPP_AMSDU); + /* mark TDLS channel switch support, if the AP allows it */ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && !sdata->deflink.u.mgd.tdls_chan_switch_prohibited && diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 79a5067ce82b..eb32174984c3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -441,6 +441,7 @@ struct ieee80211_mgd_assoc_data { bool timeout_started; bool comeback; /* whether the AP has requested association comeback */ bool s1g; + bool spp_amsdu; unsigned int assoc_link_id; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index af74d7f9d94d..a2cce62c97b7 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -925,6 +925,10 @@ int ieee80211_key_link(struct ieee80211_key *key, */ key->color = atomic_inc_return(&key_color); + /* keep this flag for easier access later */ + if (sta && sta->sta.spp_amsdu) + key->conf.flags |= IEEE80211_KEY_FLAG_SPP_AMSDU; + increment_tailroom_need_count(sdata); ret = ieee80211_key_replace(sdata, link, sta, pairwise, old_key, key); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 13c417eda281..d48fa1147c14 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -735,8 +735,11 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); } - if (!ops->set_key) + if (!ops->set_key) { wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT); + } wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RRM); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5279af09fd53..fba596d81280 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5132,6 +5132,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!sta)) goto out_err; + sta->sta.spp_amsdu = assoc_data->spp_amsdu; + if (ieee80211_vif_is_mld(&sdata->vif)) { for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { if (!assoc_data->link[link_id].bss) @@ -8216,6 +8218,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->wmm = bss->wmm_used && (local->hw.queues >= IEEE80211_NUM_ACS); + assoc_data->spp_amsdu = req->flags & ASSOC_REQ_SPP_AMSDU; + /* * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. * We still associate in non-HT mode (11a/b/g) if any one of these diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 94dae7cb6dbd..e40529b8c5c9 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -315,7 +315,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) * Calculate AAD for CCMP/GCMP, returning qos_tid since we * need that in CCMP also for b_0. */ -static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad) +static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad, bool spp_amsdu) { struct ieee80211_hdr *hdr = (void *)skb->data; __le16 mask_fc; @@ -340,7 +340,14 @@ static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad) len_a += 6; if (ieee80211_is_data_qos(hdr->frame_control)) { - qos_tid = ieee80211_get_tid(hdr); + qos_tid = *ieee80211_get_qos_ctl(hdr); + + if (spp_amsdu) + qos_tid &= IEEE80211_QOS_CTL_TID_MASK | + IEEE80211_QOS_CTL_A_MSDU_PRESENT; + else + qos_tid &= IEEE80211_QOS_CTL_TID_MASK; + mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_ORDER); len_a += 2; } else { @@ -369,10 +376,11 @@ static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad) return qos_tid; } -static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) +static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad, + bool spp_amsdu) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u8 qos_tid = ccmp_gcmp_aad(skb, aad); + u8 qos_tid = ccmp_gcmp_aad(skb, aad, spp_amsdu); /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC * mode authentication are not allowed to collide, yet both are derived @@ -479,7 +487,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb, return 0; pos += IEEE80211_CCMP_HDR_LEN; - ccmp_special_blocks(skb, pn, b_0, aad); + ccmp_special_blocks(skb, pn, b_0, aad, + key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU); return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, skb_put(skb, mic_len)); } @@ -557,7 +566,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, u8 aad[2 * AES_BLOCK_SIZE]; u8 b_0[AES_BLOCK_SIZE]; /* hardware didn't decrypt/verify MIC */ - ccmp_special_blocks(skb, pn, b_0, aad); + ccmp_special_blocks(skb, pn, b_0, aad, + key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU); if (ieee80211_aes_ccm_decrypt( key->u.ccmp.tfm, b_0, aad, @@ -581,7 +591,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, return RX_CONTINUE; } -static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad) +static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad, + bool spp_amsdu) { struct ieee80211_hdr *hdr = (void *)skb->data; @@ -591,7 +602,7 @@ static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad) j_0[14] = 0; j_0[AES_BLOCK_SIZE - 1] = 0x01; - ccmp_gcmp_aad(skb, aad); + ccmp_gcmp_aad(skb, aad, spp_amsdu); } static inline void gcmp_pn2hdr(u8 *hdr, const u8 *pn, int key_id) @@ -680,7 +691,8 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) return 0; pos += IEEE80211_GCMP_HDR_LEN; - gcmp_special_blocks(skb, pn, j_0, aad); + gcmp_special_blocks(skb, pn, j_0, aad, + key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU); return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, skb_put(skb, IEEE80211_GCMP_MIC_LEN)); } @@ -753,7 +765,8 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) u8 aad[2 * AES_BLOCK_SIZE]; u8 j_0[AES_BLOCK_SIZE]; /* hardware didn't decrypt/verify MIC */ - gcmp_special_blocks(skb, pn, j_0, aad); + gcmp_special_blocks(skb, pn, j_0, aad, + key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU); if (ieee80211_aes_gcm_decrypt( key->u.gcmp.tfm, j_0, aad, From 6a19031da91515ebcc4ddaae87914bbcccede75e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jan 2024 21:35:41 +0200 Subject: [PATCH 0328/2255] 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(+) 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, }, }; From a8b652604e39ff73b8b7f91e7c29a18904eb8a7c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jan 2024 21:35:43 +0200 Subject: [PATCH 0329/2255] wifi: mac80211: take EML/MLD capa from assoc response The association response is more likely to be correct than a random scan result, which really also should be correct, but we generally prefer to take data from the association response, so do that here as well. Also reset the data so it doesn't hang around from an old connection to a non-MLO connection, drivers would hopefully not look at it, but less surprise this way. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.1d10f1d1dbab.I545e955675e2269a52496a22ae7822d95b40235e@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fba596d81280..576ba6b25db9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3086,9 +3086,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(sdata->vif.bss_conf.tx_pwr_env, 0, sizeof(sdata->vif.bss_conf.tx_pwr_env)); + sdata->vif.cfg.eml_cap = 0; + sdata->vif.cfg.eml_med_sync_delay = 0; + sdata->vif.cfg.mld_capa_op = 0; + memset(&sdata->u.mgd.ttlm_info, 0, sizeof(sdata->u.mgd.ttlm_info)); wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ttlm_work); + wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->neg_ttlm_timeout_work); ieee80211_vif_set_links(sdata, 0, 0); @@ -4981,16 +4986,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, eht_ml_elem && ieee80211_mle_type_ok(eht_ml_elem->data + 1, IEEE80211_ML_CONTROL_TYPE_BASIC, - eht_ml_elem->datalen - 1)) { + eht_ml_elem->datalen - 1)) supports_mlo = true; - - sdata->vif.cfg.eml_cap = - ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1); - sdata->vif.cfg.eml_med_sync_delay = - ieee80211_mle_get_eml_med_sync_delay(eht_ml_elem->data + 1); - sdata->vif.cfg.mld_capa_op = - ieee80211_mle_get_mld_capa_op(eht_ml_elem->data + 1); - } } /* Allow VHT if at least one channel on the sband supports 80 MHz */ @@ -5432,6 +5429,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, assoc_data->ap_addr); goto abandon_assoc; } + + sdata->vif.cfg.eml_cap = + ieee80211_mle_get_eml_cap((const void *)elems->ml_basic); + sdata->vif.cfg.eml_med_sync_delay = + ieee80211_mle_get_eml_med_sync_delay((const void *)elems->ml_basic); + sdata->vif.cfg.mld_capa_op = + ieee80211_mle_get_mld_capa_op((const void *)elems->ml_basic); } sdata->vif.cfg.aid = aid; From ccb964b4ab1663ce92f389b72c052fc47a0ffdb9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jan 2024 21:35:44 +0200 Subject: [PATCH 0330/2255] wifi: cfg80211: validate MLO connections better When going into an MLO connection, validate that the link IDs match what userspace indicated, and that the AP MLD addresses and capabilities are all matching between the links. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.ff83c034cb9a.I9962db0bfa8c73b37b8d5b59a3fad7f02f2129ae@changeid [roll in extra fix from Miri to actually check the return value] Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 24 +++++++ net/wireless/core.h | 3 +- net/wireless/mlme.c | 136 ++++++++++++++++++++++++++++++++++---- net/wireless/nl80211.c | 3 +- net/wireless/sme.c | 3 +- 5 files changed, 152 insertions(+), 17 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index f0c068446c79..a70388ae3a7b 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4935,6 +4935,30 @@ static inline u8 ieee80211_mle_common_size(const u8 *data) return sizeof(*mle) + common + mle->variable[0]; } +/** + * ieee80211_mle_get_link_id - returns the link ID + * @data: the basic multi link element + * + * The element is assumed to be of the correct type (BASIC) and big enough, + * this must be checked using ieee80211_mle_type_ok(). + * + * If the BSS link ID can't be found, -1 will be returned + */ +static inline int ieee80211_mle_get_link_id(const u8 *data) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control = le16_to_cpu(mle->control); + const u8 *common = mle->variable; + + /* common points now at the beginning of ieee80211_mle_basic_common_info */ + common += sizeof(struct ieee80211_mle_basic_common_info); + + if (!(control & IEEE80211_MLC_BASIC_PRES_LINK_ID)) + return -1; + + return *common; +} + /** * ieee80211_mle_get_bss_param_ch_cnt - returns the BSS parameter change count * @mle: the basic multi link element diff --git a/net/wireless/core.h b/net/wireless/core.h index 13657a85cf61..30434551b377 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -362,7 +362,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct cfg80211_auth_request *req); int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_assoc_request *req); + struct cfg80211_assoc_request *req, + struct netlink_ext_ack *extack); int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, const u8 *ie, int ie_len, u16 reason, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 43ba7891e2a3..4052041a19ea 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -4,7 +4,7 @@ * * Copyright (c) 2009, Jouni Malinen * Copyright (c) 2015 Intel Deutschland GmbH - * Copyright (C) 2019-2020, 2022-2023 Intel Corporation + * Copyright (C) 2019-2020, 2022-2024 Intel Corporation */ #include @@ -325,27 +325,135 @@ void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, p1[i] &= p2[i]; } +static int +cfg80211_mlme_check_mlo_compat(const struct ieee80211_multi_link_elem *mle_a, + const struct ieee80211_multi_link_elem *mle_b, + struct netlink_ext_ack *extack) +{ + const struct ieee80211_mle_basic_common_info *common_a, *common_b; + + common_a = (const void *)mle_a->variable; + common_b = (const void *)mle_b->variable; + + if (memcmp(common_a->mld_mac_addr, common_b->mld_mac_addr, ETH_ALEN)) { + NL_SET_ERR_MSG(extack, "AP MLD address mismatch"); + return -EINVAL; + } + + if (ieee80211_mle_get_eml_med_sync_delay((const u8 *)mle_a) != + ieee80211_mle_get_eml_med_sync_delay((const u8 *)mle_b)) { + NL_SET_ERR_MSG(extack, "link EML medium sync delay mismatch"); + return -EINVAL; + } + + if (ieee80211_mle_get_eml_cap((const u8 *)mle_a) != + ieee80211_mle_get_eml_cap((const u8 *)mle_b)) { + NL_SET_ERR_MSG(extack, "link EML capabilities mismatch"); + return -EINVAL; + } + + if (ieee80211_mle_get_mld_capa_op((const u8 *)mle_a) != + ieee80211_mle_get_mld_capa_op((const u8 *)mle_b)) { + NL_SET_ERR_MSG(extack, "link MLD capabilities/ops mismatch"); + return -EINVAL; + } + + return 0; +} + +static int cfg80211_mlme_check_mlo(struct net_device *dev, + struct cfg80211_assoc_request *req, + struct netlink_ext_ack *extack) +{ + const struct ieee80211_multi_link_elem *mles[ARRAY_SIZE(req->links)] = {}; + int i; + + if (req->link_id < 0) + return 0; + + if (!req->links[req->link_id].bss) { + NL_SET_ERR_MSG(extack, "no BSS for assoc link"); + return -EINVAL; + } + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(req->links); i++) { + const struct cfg80211_bss_ies *ies; + const struct element *ml; + + if (!req->links[i].bss) + continue; + + if (ether_addr_equal(req->links[i].bss->bssid, dev->dev_addr)) { + NL_SET_ERR_MSG(extack, "BSSID must not be our address"); + req->links[i].error = -EINVAL; + goto error; + } + + ies = rcu_dereference(req->links[i].bss->ies); + ml = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK, + ies->data, ies->len); + if (!ml) { + NL_SET_ERR_MSG(extack, "MLO BSS w/o ML element"); + req->links[i].error = -EINVAL; + goto error; + } + + if (!ieee80211_mle_type_ok(ml->data + 1, + IEEE80211_ML_CONTROL_TYPE_BASIC, + ml->datalen - 1)) { + NL_SET_ERR_MSG(extack, "BSS with invalid ML element"); + req->links[i].error = -EINVAL; + goto error; + } + + mles[i] = (const void *)(ml->data + 1); + + if (ieee80211_mle_get_link_id((const u8 *)mles[i]) != i) { + NL_SET_ERR_MSG(extack, "link ID mismatch"); + req->links[i].error = -EINVAL; + goto error; + } + } + + if (WARN_ON(!mles[req->link_id])) + goto error; + + for (i = 0; i < ARRAY_SIZE(req->links); i++) { + if (i == req->link_id || !req->links[i].bss) + continue; + + if (WARN_ON(!mles[i])) + goto error; + + if (cfg80211_mlme_check_mlo_compat(mles[req->link_id], mles[i], + extack)) { + req->links[i].error = -EINVAL; + goto error; + } + } + + rcu_read_unlock(); + return 0; +error: + rcu_read_unlock(); + return -EINVAL; +} + /* Note: caller must cfg80211_put_bss() regardless of result */ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_assoc_request *req) + struct cfg80211_assoc_request *req, + struct netlink_ext_ack *extack) { struct wireless_dev *wdev = dev->ieee80211_ptr; - int err, i, j; + int err; lockdep_assert_wiphy(wdev->wiphy); - for (i = 1; i < ARRAY_SIZE(req->links); i++) { - if (!req->links[i].bss) - continue; - for (j = 0; j < i; j++) { - if (req->links[i].bss == req->links[j].bss) - return -EINVAL; - } - - if (ether_addr_equal(req->links[i].bss->bssid, dev->dev_addr)) - return -EINVAL; - } + err = cfg80211_mlme_check_mlo(dev, req, extack); + if (err) + return err; if (wdev->connected && (!req->prev_bssid || diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b267317aa33c..0809f721f045 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11245,7 +11245,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct nlattr *link; int rem = 0; - err = cfg80211_mlme_assoc(rdev, dev, &req); + err = cfg80211_mlme_assoc(rdev, dev, &req, + info->extack); if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) { dev->ieee80211_ptr->conn_owner_nlportid = diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 195c8532734b..82e3ce42206c 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -209,7 +209,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev, if (!req.bss) { err = -ENOENT; } else { - err = cfg80211_mlme_assoc(rdev, wdev->netdev, &req); + err = cfg80211_mlme_assoc(rdev, wdev->netdev, + &req, NULL); cfg80211_put_bss(&rdev->wiphy, req.bss); } From 2b3e35d98bcaad9218ec3d4ab91e93022f76b6dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jan 2024 18:17:39 +0200 Subject: [PATCH 0331/2255] 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(-) 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[] = { { From d1155f2873cfd387ffb7f5423edbfb2bb22eaf32 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jan 2024 18:17:40 +0200 Subject: [PATCH 0332/2255] wifi: mac80211: simplify ieee80211_config_bw() prototype The only user of this function passes a lot of pointers directly from the parsed elements, so it's simpler to just pass the entire elements parsing struct. This also shows that the ht_cap is actually unused. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240111181514.f0653cd5e7dd.I8bd5ee848074029a9f0495c95e4339546ad8fe15@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 576ba6b25db9..6fa69ad3ad4f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -489,15 +489,15 @@ out: } static int ieee80211_config_bw(struct ieee80211_link_data *link, - const struct ieee80211_ht_cap *ht_cap, - const struct ieee80211_vht_cap *vht_cap, - const struct ieee80211_ht_operation *ht_oper, - const struct ieee80211_vht_operation *vht_oper, - const struct ieee80211_he_operation *he_oper, - const struct ieee80211_eht_operation *eht_oper, - const struct ieee80211_s1g_oper_ie *s1g_oper, + struct ieee802_11_elems *elems, const u8 *bssid, u64 *changed) { + const struct ieee80211_vht_cap *vht_cap = elems->vht_cap_elem; + const struct ieee80211_ht_operation *ht_oper = elems->ht_operation; + const struct ieee80211_vht_operation *vht_oper = elems->vht_operation; + const struct ieee80211_he_operation *he_oper = elems->he_operation; + const struct ieee80211_eht_operation *eht_oper = elems->eht_operation; + const struct ieee80211_s1g_oper_ie *s1g_oper = elems->s1g_oper; struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -6433,11 +6433,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, changed |= ieee80211_recalc_twt_req(sdata, sband, link, link_sta, elems); - if (ieee80211_config_bw(link, elems->ht_cap_elem, - elems->vht_cap_elem, elems->ht_operation, - elems->vht_operation, elems->he_operation, - elems->eht_operation, - elems->s1g_oper, bssid, &changed)) { + if (ieee80211_config_bw(link, elems, bssid, &changed)) { sdata_info(sdata, "failed to follow AP %pM bandwidth change, disconnect\n", bssid); From f73ef56c941248ae8b1e19862e11a7bb517b9af1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jan 2024 18:17:41 +0200 Subject: [PATCH 0333/2255] wifi: mac80211: remove extra element parsing We already parse all the BSS elements into elems, there's really no need to separately find EHT/ML again. Remove the extra code. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240111181514.c4a55da9f778.I112b1ef00904c4183ac7644800f8daa8a4449875@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6fa69ad3ad4f..45be270eaab7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4962,32 +4962,12 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, (IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT)) && he_oper) { - const struct cfg80211_bss_ies *cbss_ies; - const struct element *eht_ml_elem; - const u8 *eht_oper_ie; - - cbss_ies = rcu_dereference(cbss->ies); - eht_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_EHT_OPERATION, - cbss_ies->data, cbss_ies->len); - if (eht_oper_ie && eht_oper_ie[1] >= - 1 + sizeof(struct ieee80211_eht_operation)) - eht_oper = (void *)(eht_oper_ie + 3); - else - eht_oper = NULL; + eht_oper = elems->eht_operation; if (!ieee80211_verify_sta_eht_mcs_support(sdata, sband, eht_oper)) *conn_flags |= IEEE80211_CONN_DISABLE_EHT; - eht_ml_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK, - cbss_ies->data, cbss_ies->len); - - /* data + 1 / datalen - 1 since it's an extended element */ - if (!(*conn_flags & IEEE80211_CONN_DISABLE_EHT) && - eht_ml_elem && - ieee80211_mle_type_ok(eht_ml_elem->data + 1, - IEEE80211_ML_CONTROL_TYPE_BASIC, - eht_ml_elem->datalen - 1)) - supports_mlo = true; + supports_mlo = elems->ml_basic; } /* Allow VHT if at least one channel on the sband supports 80 MHz */ From 6593c7aec7fa15d59af4fbefdbb3d46d27d6e3ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jan 2024 18:17:42 +0200 Subject: [PATCH 0334/2255] wifi: mac80211: simplify HE capability access For verifying the required HE capabilities are supported locally, we access the HE capability element of the AP. Simplify that access, we've already parsed and validated it when parsing elements. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240111181514.2ef62b43caeb.I8baa604dd3f3399e08b86c99395a2c6a1185d35d@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 45be270eaab7..5b1bc84760d5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4547,41 +4547,17 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, static bool ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_bss_ies *ies, + const struct ieee80211_he_cap_elem *he_cap, const struct ieee80211_he_operation *he_op) { - const struct element *he_cap_elem; - const struct ieee80211_he_cap_elem *he_cap; struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp; u16 mcs_80_map_tx, mcs_80_map_rx; u16 ap_min_req_set; - int mcs_nss_size; int nss; - he_cap_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, - ies->data, ies->len); - - if (!he_cap_elem) + if (!he_cap) return false; - /* invalid HE IE */ - if (he_cap_elem->datalen < 1 + sizeof(*he_cap)) { - sdata_info(sdata, - "Invalid HE elem, Disable HE\n"); - return false; - } - - /* skip one byte ext_tag_id */ - he_cap = (void *)(he_cap_elem->data + 1); - mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap); - - /* invalid HE IE */ - if (he_cap_elem->datalen < 1 + sizeof(*he_cap) + mcs_nss_size) { - sdata_info(sdata, - "Invalid HE elem with nss size, Disable HE\n"); - return false; - } - /* mcs_nss is right after he_cap info */ he_mcs_nss_supp = (void *)(he_cap + 1); @@ -4946,7 +4922,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, } } - if (!ieee80211_verify_peer_he_mcs_support(sdata, ies, he_oper) || + if (!ieee80211_verify_peer_he_mcs_support(sdata, + (void *)elems->he_cap, + he_oper) || !ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper)) *conn_flags |= IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT; From f04d2c247e0407ff8219395bef11ddc0837b7397 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jan 2024 18:17:43 +0200 Subject: [PATCH 0335/2255] wifi: mac80211: disallow drivers with HT wider than HE To simplify the code in the next patch, disallow drivers supporting 40 MHz in HT but not HE, since we'd otherwise have to track local maximum bandwidth per mode there. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240111181514.da15fe3214d2.I4df51ad2f4c844615c168bf9bdb498925b3c77d4@changeid Signed-off-by: Johannes Berg --- net/mac80211/main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d48fa1147c14..e05bcc35bc1e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1119,8 +1119,26 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) supp_vht = supp_vht || sband->vht_cap.vht_supported; for_each_sband_iftype_data(sband, i, iftd) { + u8 he_40_mhz_cap; + supp_he = supp_he || iftd->he_cap.has_he; supp_eht = supp_eht || iftd->eht_cap.has_eht; + + if (sband->band == NL80211_BAND_2GHZ) + he_40_mhz_cap = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + else + he_40_mhz_cap = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + + /* currently no support for HE client where HT has 40 MHz but not HT */ + if (iftd->he_cap.has_he && + iftd->types_mask & (BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT)) && + sband->ht_cap.ht_supported && + sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && + !(iftd->he_cap.he_cap_elem.phy_cap_info[0] & he_40_mhz_cap)) + return -EINVAL; } /* HT, VHT, HE require QoS, thus >= 4 queues */ From bc8a0fac8677f729ab17176023be1a2653e8b9c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jan 2024 18:17:45 +0200 Subject: [PATCH 0336/2255] wifi: mac80211: don't set bss_conf in parsing When parsing 6 GHz operation, don't set the bss_conf values. We only commit to that later in association, so move the code there. Also clear it later. While at it, handle IEEE80211_6GHZ_CTRL_REG_VLP_AP. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240111181514.c2da4bc515e8.I219ca40e15c0fbaff0e7c3e83ca4b92ecbc1f8ae@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 27 +++++++++++++++++++++++++++ net/mac80211/util.c | 21 +-------------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5b1bc84760d5..99188bd84799 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3081,6 +3081,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); wiphy_delayed_work_cancel(local->hw.wiphy, &ifmgd->tx_tspec_wk); + sdata->vif.bss_conf.power_type = IEEE80211_REG_UNSET_AP; sdata->vif.bss_conf.pwr_reduction = 0; sdata->vif.bss_conf.tx_pwr_env_num = 0; memset(sdata->vif.bss_conf.tx_pwr_env, 0, @@ -4236,12 +4237,38 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && elems->he_cap) { + const struct ieee80211_he_6ghz_oper *he_6ghz_oper; + ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, elems->he_cap_len, elems->he_6ghz_capa, link_sta); + he_6ghz_oper = ieee80211_he_6ghz_oper(elems->he_operation); + + if (is_6ghz && he_6ghz_oper) { + switch (u8_get_bits(he_6ghz_oper->control, + IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { + case IEEE80211_6GHZ_CTRL_REG_LPI_AP: + bss_conf->power_type = IEEE80211_REG_LPI_AP; + break; + case IEEE80211_6GHZ_CTRL_REG_SP_AP: + bss_conf->power_type = IEEE80211_REG_SP_AP; + break; + case IEEE80211_6GHZ_CTRL_REG_VLP_AP: + bss_conf->power_type = IEEE80211_REG_VLP_AP; + break; + default: + bss_conf->power_type = IEEE80211_REG_UNSET_AP; + break; + } + } 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->he_support = link_sta->pub->he_cap.has_he; if (elems->rsnx && elems->rsnx_len && (elems->rsnx[0] & WLAN_RSNX_CAPA_PROTECTED_TWT) && diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 643c54855be6..685b55a053f3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3845,7 +3845,6 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, const struct ieee80211_sta_eht_cap *eht_cap; struct cfg80211_chan_def he_chandef = *chandef; const struct ieee80211_he_6ghz_oper *he_6ghz_oper; - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; bool support_80_80, support_160, support_320; u8 he_phy_cap, eht_phy_cap; u32 freq; @@ -3881,13 +3880,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, eht_oper = NULL; he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); - - if (!he_6ghz_oper) { - sdata_info(sdata, - "HE 6GHz operation missing (on %d MHz), expect issues\n", - chandef->chan->center_freq); + if (!he_6ghz_oper) return false; - } /* * The EHT operation IE does not contain the primary channel so the @@ -3898,19 +3892,6 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, NL80211_BAND_6GHZ); he_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq); - switch (u8_get_bits(he_6ghz_oper->control, - IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { - case IEEE80211_6GHZ_CTRL_REG_LPI_AP: - bss_conf->power_type = IEEE80211_REG_LPI_AP; - break; - case IEEE80211_6GHZ_CTRL_REG_SP_AP: - bss_conf->power_type = IEEE80211_REG_SP_AP; - break; - default: - bss_conf->power_type = IEEE80211_REG_UNSET_AP; - break; - } - if (!eht_oper || !(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) { switch (u8_get_bits(he_6ghz_oper->control, From e10322810ce0d0d4a5a319458c4e1e052c6fe9be Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 11 Jan 2024 18:17:46 +0200 Subject: [PATCH 0337/2255] wifi: mac80211: use deflink and fix typo in link ID check This does not change anything effectively, but it is closer to what the code is trying to achieve here. i.e. select the link data if it is an MLD and fall back to using the deflink otherwise. Fixes: 0f99f0878350 ("wifi: mac80211: Print local link address during authentication") Signed-off-by: Benjamin Berg Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://msgid.link/20240111181514.4c4b1c40eb3c.I2771621dee328c618536596b7e56232df42a79c8@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 99188bd84799..cc9a8eaffa6b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -7869,10 +7869,10 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (err) goto err_clear; - if (req->link_id > 0) + if (req->link_id >= 0) link = sdata_dereference(sdata->link[req->link_id], sdata); else - link = sdata_dereference(sdata->link[0], sdata); + link = &sdata->deflink; if (WARN_ON(!link)) { err = -ENOLINK; From d60277ac3fc9c9f7887ff813c98d0a71ac2abde2 Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Tue, 23 Jan 2024 13:47:52 +0800 Subject: [PATCH 0338/2255] wifi: mac80211: apply duration for SW scan This patch makes duration in scan request be applicable when using SW scan, but only accepts durations greater than the default value for the following reasons: 1. Most APs have a beacoon interval of 100ms. 2. Sending and receiving probe require some delay. 3. Setting channel to HW also requires some delays Signed-off-by: Michael-CY Lee Link: https://msgid.link/20240123054752.22833-1-michael-cy.lee@mediatek.com Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 645355e5f1bc..8adcb23262f5 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -671,7 +671,10 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, * After sending probe requests, wait for probe responses * on the channel. */ - *next_delay = IEEE80211_CHANNEL_TIME; + *next_delay = msecs_to_jiffies(scan_req->duration) > + IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME ? + msecs_to_jiffies(scan_req->duration) - IEEE80211_PROBE_DELAY : + IEEE80211_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; } @@ -994,7 +997,10 @@ set_channel: */ if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) || !scan_req->n_ssids) { - *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + *next_delay = msecs_to_jiffies(scan_req->duration) > + IEEE80211_PASSIVE_CHANNEL_TIME ? + msecs_to_jiffies(scan_req->duration) : + IEEE80211_PASSIVE_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; if (scan_req->n_ssids) set_bit(SCAN_BEACON_WAIT, &local->scanning); From cf74ce02e394109e16efcb4f15a8e885e9a834a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:09 +0200 Subject: [PATCH 0339/2255] 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 + .../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 +++- .../net/wireless/intel/iwlwifi/tests/Makefile | 7 +++ .../wireless/intel/iwlwifi/tests/devinfo.c | 54 +++++++++++++++++++ .../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 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"); From 099a47dbe71b758e6875d0297467f2b8d23014df Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Tue, 23 Jan 2024 20:08:10 +0200 Subject: [PATCH 0340/2255] 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 ++++ .../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(-) 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, From 47cde0942959ca11855e1aa5d66209d8625c2a2b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:12 +0200 Subject: [PATCH 0341/2255] 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(-) 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: From 84ec2d2e960f33edcee7c47118e59dde72826843 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Fri, 26 Jan 2024 09:00:30 +0200 Subject: [PATCH 0342/2255] 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(-) 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) From de0c2cdcb7eb8e08f3886b433277472d97af0f6e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:14 +0200 Subject: [PATCH 0343/2255] 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(-) 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 */ From dfdfe4be183b27b278d78225d48b98b3c1ca6285 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:15 +0200 Subject: [PATCH 0344/2255] 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 -- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +------ 3 files changed, 10 insertions(+), 31 deletions(-) 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); From 6c8ce23854b66db94d88e0957e531cb074806c16 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 23 Jan 2024 20:08:16 +0200 Subject: [PATCH 0345/2255] 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(-) 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), From 77b8b078440eb136efd03427404134e1d88dca50 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:17 +0200 Subject: [PATCH 0346/2255] 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(-) 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 } }, From 22d9987c79cb8d1d04625cde5f63fc01abae2b6a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 23 Jan 2024 20:08:18 +0200 Subject: [PATCH 0347/2255] 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(+) 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, From 38d84aaed52832945887ae8618bed68c89a3bf81 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 23 Jan 2024 20:08:20 +0200 Subject: [PATCH 0348/2255] 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 --- .../net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h | 16 ++++++++++++++-- .../net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) 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 */ From 289f57bbef09b0a2385a5187274e37d76031de14 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 23 Jan 2024 20:08:21 +0200 Subject: [PATCH 0349/2255] 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(-) 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 From c4d32f2745c75c9041937767f0329f6f1051778b Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 23 Jan 2024 20:08:22 +0200 Subject: [PATCH 0350/2255] 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 --- .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) 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, }; From fdccafad7e9b49e75fb484c5aa29954d34f3c63a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 23 Jan 2024 20:08:23 +0200 Subject: [PATCH 0351/2255] 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 --- .../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(-) 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; } } From a923ff876f4b6133a093482a6d465cde3bc2e65c Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 25 Jan 2024 14:55:47 -0800 Subject: [PATCH 0352/2255] Revert "nl80211/cfg80211: Specify band specific min RSSI thresholds with sched scan" This *mostly* reverts commit 1e1b11b6a111 ("nl80211/cfg80211: Specify band specific min RSSI thresholds with sched scan"). During the review of a new patch [1] it was observed that the functionality being modified was not actually being used by any in-tree driver. Further research determined that the functionality was originally introduced to support a new Android interface, but that interface was subsequently abandoned. Since the functionality has apparently never been used, remove it. However, to mantain the sanctity of the UABI, keep the nl80211.h assignments, but clearly mark them as obsolete. Cc: Lin Ma Cc: Vamsi Krishna Link: https://lore.kernel.org/linux-wireless/20240119151201.8670-1-linma@zju.edu.cn/ [1] Signed-off-by: Jeff Johnson Link: https://msgid.link/20240125-for-next-v1-1-fd79e01c6c09@quicinc.com Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 8 ------ include/uapi/linux/nl80211.h | 16 +++-------- net/wireless/nl80211.c | 55 ------------------------------------ 3 files changed, 4 insertions(+), 75 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 56bce924bec6..51b9e6fa12f8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2695,19 +2695,11 @@ static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask) * @bssid: BSSID to be matched; may be all-zero BSSID in case of SSID match * or no match (RSSI only) * @rssi_thold: don't report scan results below this threshold (in s32 dBm) - * @per_band_rssi_thold: Minimum rssi threshold for each band to be applied - * for filtering out scan results received. Drivers advertise this support - * of band specific rssi based filtering through the feature capability - * %NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD. These band - * specific rssi thresholds take precedence over rssi_thold, if specified. - * If not specified for any band, it will be assigned with rssi_thold of - * corresponding matchset. */ struct cfg80211_match_set { struct cfg80211_ssid ssid; u8 bssid[ETH_ALEN]; s32 rssi_thold; - s32 per_band_rssi_thold[NUM_NL80211_BANDS]; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 3e239df3528f..853ac538a686 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4463,14 +4463,7 @@ enum nl80211_reg_rule_attr { * value as specified by &struct nl80211_bss_select_rssi_adjust. * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching * (this cannot be used together with SSID). - * @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Nested attribute that carries the - * band specific minimum rssi thresholds for the bands defined in - * enum nl80211_band. The minimum rssi threshold value(s32) specific to a - * band shall be encapsulated in attribute with type value equals to one - * of the NL80211_BAND_* defined in enum nl80211_band. For example, the - * minimum rssi threshold value for 2.4GHZ band shall be encapsulated - * within an attribute of type NL80211_BAND_2GHZ. And one or more of such - * attributes will be nested within this attribute. + * @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Obsolete * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter * attribute number currently defined * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use @@ -4483,7 +4476,7 @@ enum nl80211_sched_scan_match_attr { NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST, NL80211_SCHED_SCAN_MATCH_ATTR_BSSID, - NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI, + NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI, /* obsolete */ /* keep last */ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, @@ -6418,8 +6411,7 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching * (set/del PMKSA operations) in AP mode. * - * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Driver supports - * filtering of sched scan results using band specific RSSI thresholds. + * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Obsolete * * @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power * to a station. @@ -6574,7 +6566,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS, NL80211_EXT_FEATURE_AP_PMKSA_CACHING, - NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD, + NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD, /* obsolete */ NL80211_EXT_FEATURE_EXT_KEY_ID, NL80211_EXT_FEATURE_STA_TX_PWR, NL80211_EXT_FEATURE_SAE_OFFLOAD, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0809f721f045..e4f41f86e295 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -906,23 +906,12 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { [NL80211_REKEY_DATA_AKM] = { .type = NLA_U32 }, }; -static const struct nla_policy -nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = { - [NL80211_BAND_2GHZ] = { .type = NLA_S32 }, - [NL80211_BAND_5GHZ] = { .type = NLA_S32 }, - [NL80211_BAND_6GHZ] = { .type = NLA_S32 }, - [NL80211_BAND_60GHZ] = { .type = NLA_S32 }, - [NL80211_BAND_LC] = { .type = NLA_S32 }, -}; - static const struct nla_policy nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_SSID_LEN }, [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN), [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, - [NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] = - NLA_POLICY_NESTED(nl80211_match_band_rssi_policy), }; static const struct nla_policy @@ -9490,41 +9479,6 @@ nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans, return 0; } -static int -nl80211_parse_sched_scan_per_band_rssi(struct wiphy *wiphy, - struct cfg80211_match_set *match_sets, - struct nlattr *tb_band_rssi, - s32 rssi_thold) -{ - struct nlattr *attr; - int i, tmp, ret = 0; - - if (!wiphy_ext_feature_isset(wiphy, - NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD)) { - if (tb_band_rssi) - ret = -EOPNOTSUPP; - else - for (i = 0; i < NUM_NL80211_BANDS; i++) - match_sets->per_band_rssi_thold[i] = - NL80211_SCAN_RSSI_THOLD_OFF; - return ret; - } - - for (i = 0; i < NUM_NL80211_BANDS; i++) - match_sets->per_band_rssi_thold[i] = rssi_thold; - - nla_for_each_nested(attr, tb_band_rssi, tmp) { - enum nl80211_band band = nla_type(attr); - - if (band < 0 || band >= NUM_NL80211_BANDS) - return -EINVAL; - - match_sets->per_band_rssi_thold[band] = nla_get_s32(attr); - } - - return 0; -} - static struct cfg80211_sched_scan_request * nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, struct nlattr **attrs, int max_match_sets) @@ -9799,15 +9753,6 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, if (rssi) request->match_sets[i].rssi_thold = nla_get_s32(rssi); - - /* Parse per band RSSI attribute */ - err = nl80211_parse_sched_scan_per_band_rssi(wiphy, - &request->match_sets[i], - tb[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI], - request->match_sets[i].rssi_thold); - if (err) - goto out_free; - i++; } From 28b3df1fe6ba2cb439ba109f095aa841fef3a54f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 Jan 2024 10:34:17 +0200 Subject: [PATCH 0353/2255] kunit: add wireless unit tests Add cfg80211, mac80211 and iwlwifi to the all_tests config so that the unit tests (enabled by KUNIT_ALL_TESTS) will be run by default. Signed-off-by: Johannes Berg --- tools/testing/kunit/configs/all_tests.config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index 3bf506d4a63c..12da4c493867 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -27,6 +27,11 @@ CONFIG_MCTP=y CONFIG_INET=y CONFIG_MPTCP=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_WLAN_VENDOR_INTEL=y +CONFIG_IWLWIFI=y + CONFIG_DAMON=y CONFIG_DAMON_VADDR=y CONFIG_DAMON_PADDR=y From e48f0f4a9bfed8947e4d1123e8b6a15c18ee1708 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 25 Jan 2024 20:00:50 -0800 Subject: [PATCH 0354/2255] bpf, docs: Clarify definitions of various instructions Clarify definitions of several instructions: * BPF_NEG does not support BPF_X * BPF_CALL does not support BPF_JMP32 or BPF_X * BPF_EXIT does not support BPF_X * BPF_JA does not support BPF_X (was implied but not explicitly stated) Also fix a typo in the wide instruction figure where the field is actually named "opcode" not "code". Signed-off-by: Dave Thaler Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240126040050.8464-1-dthaler1968@gmail.com --- .../bpf/standardization/instruction-set.rst | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index d17a96c6254f..af43227b6ee4 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -174,12 +174,12 @@ and imm containing the high 32 bits of the immediate value. This is depicted in the following figure:: basic_instruction - .-----------------------------. - | | - code:8 regs:8 offset:16 imm:32 unused:32 imm:32 - | | - '--------------' - pseudo instruction + .------------------------------. + | | + opcode:8 regs:8 offset:16 imm:32 unused:32 imm:32 + | | + '--------------' + pseudo instruction Thus the 64-bit immediate value is constructed as follows: @@ -320,6 +320,9 @@ bit operands, and zeroes the remaining upper 32 bits. operands into 64 bit operands. Unlike other arithmetic instructions, ``BPF_MOVSX`` is only defined for register source operands (``BPF_X``). +The ``BPF_NEG`` instruction is only defined when the source bit is clear +(``BPF_K``). + Shift operations use a mask of 0x3F (63) for 64-bit operations and 0x1F (31) for 32-bit operations. @@ -375,27 +378,27 @@ Jump instructions otherwise identical operations. The 'code' field encodes the operation as below: -======== ===== === =========================================== ========================================= -code value src description notes -======== ===== === =========================================== ========================================= -BPF_JA 0x0 0x0 PC += offset BPF_JMP class -BPF_JA 0x0 0x0 PC += imm BPF_JMP32 class +======== ===== === =============================== ============================================= +code value src description notes +======== ===== === =============================== ============================================= +BPF_JA 0x0 0x0 PC += offset BPF_JMP | BPF_K only +BPF_JA 0x0 0x0 PC += imm BPF_JMP32 | BPF_K only BPF_JEQ 0x1 any PC += offset if dst == src -BPF_JGT 0x2 any PC += offset if dst > src unsigned -BPF_JGE 0x3 any PC += offset if dst >= src unsigned +BPF_JGT 0x2 any PC += offset if dst > src unsigned +BPF_JGE 0x3 any PC += offset if dst >= src unsigned BPF_JSET 0x4 any PC += offset if dst & src BPF_JNE 0x5 any PC += offset if dst != src -BPF_JSGT 0x6 any PC += offset if dst > src signed -BPF_JSGE 0x7 any PC += offset if dst >= src signed -BPF_CALL 0x8 0x0 call helper function by address see `Helper functions`_ -BPF_CALL 0x8 0x1 call PC += imm see `Program-local functions`_ -BPF_CALL 0x8 0x2 call helper function by BTF ID see `Helper functions`_ -BPF_EXIT 0x9 0x0 return BPF_JMP only -BPF_JLT 0xa any PC += offset if dst < src unsigned -BPF_JLE 0xb any PC += offset if dst <= src unsigned -BPF_JSLT 0xc any PC += offset if dst < src signed -BPF_JSLE 0xd any PC += offset if dst <= src signed -======== ===== === =========================================== ========================================= +BPF_JSGT 0x6 any PC += offset if dst > src signed +BPF_JSGE 0x7 any PC += offset if dst >= src signed +BPF_CALL 0x8 0x0 call helper function by address BPF_JMP | BPF_K only, see `Helper functions`_ +BPF_CALL 0x8 0x1 call PC += imm BPF_JMP | BPF_K only, see `Program-local functions`_ +BPF_CALL 0x8 0x2 call helper function by BTF ID BPF_JMP | BPF_K only, see `Helper functions`_ +BPF_EXIT 0x9 0x0 return BPF_JMP | BPF_K only +BPF_JLT 0xa any PC += offset if dst < src unsigned +BPF_JLE 0xb any PC += offset if dst <= src unsigned +BPF_JSLT 0xc any PC += offset if dst < src signed +BPF_JSLE 0xd any PC += offset if dst <= src signed +======== ===== === =============================== ============================================= The BPF program needs to store the return value into register R0 before doing a ``BPF_EXIT``. From fa7178b0f12e55a4f2d4906df3f25d6d4f88d962 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Fri, 26 Jan 2024 09:57:36 +0800 Subject: [PATCH 0355/2255] selftests/bpf: Add missing line break in test_verifier There are no break lines in the test log for test_verifier #106 ~ #111 if jit is disabled, add the missing line break at the end of printf() to fix it. Without this patch: [root@linux bpf]# echo 0 > /proc/sys/net/core/bpf_jit_enable [root@linux bpf]# ./test_verifier 106 #106/p inline simple bpf_loop call SKIP (requires BPF JIT)Summary: 0 PASSED, 1 SKIPPED, 0 FAILED With this patch: [root@linux bpf]# echo 0 > /proc/sys/net/core/bpf_jit_enable [root@linux bpf]# ./test_verifier 106 #106/p inline simple bpf_loop call SKIP (requires BPF JIT) Summary: 0 PASSED, 1 SKIPPED, 0 FAILED Fixes: 0b50478fd877 ("selftests/bpf: Skip callback tests if jit is disabled in test_verifier") Signed-off-by: Tiezhu Yang Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240126015736.655-1-yangtiezhu@loongson.cn --- tools/testing/selftests/bpf/test_verifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index e1a1dfe8d7fa..df04bda1c927 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1527,7 +1527,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, int i, err; if ((test->flags & F_NEEDS_JIT_ENABLED) && jit_disabled) { - printf("SKIP (requires BPF JIT)"); + printf("SKIP (requires BPF JIT)\n"); skips++; sched_yield(); return; From fb4bb62aaac715e50c7c007714af19a2698db88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:34:51 +0300 Subject: [PATCH 0356/2255] net: dsa: mt7530: select MEDIATEK_GE_PHY for NET_DSA_MT7530_MDIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quoting from commit 4223f8651287 ("net: dsa: mt7530: make NET_DSA_MT7530 select MEDIATEK_GE_PHY"): Make MediaTek MT753x DSA driver enable MediaTek Gigabit PHYs driver to properly control MT7530 and MT7531 switch PHYs. A noticeable change is that the behaviour of switchport interfaces going up-down-up-down is no longer there. Now, the switch can be used without the PHYs but, at the moment, every hardware design out there that I have seen uses them. For that, it would make the most sense to force the selection of MEDIATEK_GE_PHY for the MDIO interface which currently controls the MT7530 and MT7531 switches. Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122053451.8004-1-arinc.unal@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index f8c1d73b251d..3092b391031a 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -48,7 +48,7 @@ config NET_DSA_MT7530 config NET_DSA_MT7530_MDIO tristate "MediaTek MT7530 MDIO interface driver" depends on NET_DSA_MT7530 - imply MEDIATEK_GE_PHY + select MEDIATEK_GE_PHY select PCS_MTK_LYNXI help This enables support for the MediaTek MT7530 and MT7531 switch From 31e03207119a535d0b0e3b3a7f91983aeb2cb14d Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 23 Jan 2024 09:08:52 -0800 Subject: [PATCH 0357/2255] af_unix: Annotate data-race of gc_in_progress in wait_for_unix_gc(). gc_in_progress is changed under spin_lock(&unix_gc_lock), but wait_for_unix_gc() reads it locklessly. Let's use READ_ONCE(). Fixes: 5f23b734963e ("net: Fix soft lockups/OOM issues w/ unix garbage collector") Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240123170856.41348-2-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/unix/garbage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 2405f0f9af31..af3d2221cf6a 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -198,7 +198,7 @@ void wait_for_unix_gc(void) if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && !READ_ONCE(gc_in_progress)) unix_gc(); - wait_event(unix_gc_wait, gc_in_progress == false); + wait_event(unix_gc_wait, !READ_ONCE(gc_in_progress)); } /* The external entry point: unix_gc() */ From 97af84a6bba2ab2b9c704c08e67de3b5ea551bb2 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 23 Jan 2024 09:08:53 -0800 Subject: [PATCH 0358/2255] af_unix: Do not use atomic ops for unix_sk(sk)->inflight. When touching unix_sk(sk)->inflight, we are always under spin_lock(&unix_gc_lock). Let's convert unix_sk(sk)->inflight to the normal unsigned long. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240123170856.41348-3-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/af_unix.h | 2 +- net/unix/af_unix.c | 4 ++-- net/unix/garbage.c | 17 ++++++++--------- net/unix/scm.c | 8 +++++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 49c4640027d8..ac38b63db554 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -61,7 +61,7 @@ struct unix_sock { struct mutex iolock, bindlock; struct sock *peer; struct list_head link; - atomic_long_t inflight; + unsigned long inflight; spinlock_t lock; unsigned long gc_flags; #define UNIX_GC_CANDIDATE 0 diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ac1f2bc18fc9..1e9378036dcc 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -993,11 +993,11 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern, sk->sk_write_space = unix_write_space; sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; sk->sk_destruct = unix_sock_destructor; - u = unix_sk(sk); + u = unix_sk(sk); + u->inflight = 0; u->path.dentry = NULL; u->path.mnt = NULL; spin_lock_init(&u->lock); - atomic_long_set(&u->inflight, 0); INIT_LIST_HEAD(&u->link); mutex_init(&u->iolock); /* single task reading lock */ mutex_init(&u->bindlock); /* single task binding lock */ diff --git a/net/unix/garbage.c b/net/unix/garbage.c index af3d2221cf6a..051f96a3ab02 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -166,17 +166,18 @@ static void scan_children(struct sock *x, void (*func)(struct unix_sock *), static void dec_inflight(struct unix_sock *usk) { - atomic_long_dec(&usk->inflight); + usk->inflight--; } static void inc_inflight(struct unix_sock *usk) { - atomic_long_inc(&usk->inflight); + usk->inflight++; } static void inc_inflight_move_tail(struct unix_sock *u) { - atomic_long_inc(&u->inflight); + u->inflight++; + /* If this still might be part of a cycle, move it to the end * of the list, so that it's checked even if it was already * passed over @@ -237,14 +238,12 @@ void unix_gc(void) */ list_for_each_entry_safe(u, next, &gc_inflight_list, link) { long total_refs; - long inflight_refs; total_refs = file_count(u->sk.sk_socket->file); - inflight_refs = atomic_long_read(&u->inflight); - BUG_ON(inflight_refs < 1); - BUG_ON(total_refs < inflight_refs); - if (total_refs == inflight_refs) { + BUG_ON(!u->inflight); + BUG_ON(total_refs < u->inflight); + if (total_refs == u->inflight) { list_move_tail(&u->link, &gc_candidates); __set_bit(UNIX_GC_CANDIDATE, &u->gc_flags); __set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags); @@ -271,7 +270,7 @@ void unix_gc(void) /* Move cursor to after the current position. */ list_move(&cursor, &u->link); - if (atomic_long_read(&u->inflight) > 0) { + if (u->inflight) { list_move_tail(&u->link, ¬_cycle_list); __clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags); scan_children(&u->sk, inc_inflight_move_tail, NULL); diff --git a/net/unix/scm.c b/net/unix/scm.c index 822ce0d0d791..e92f2fad6410 100644 --- a/net/unix/scm.c +++ b/net/unix/scm.c @@ -53,12 +53,13 @@ void unix_inflight(struct user_struct *user, struct file *fp) if (s) { struct unix_sock *u = unix_sk(s); - if (atomic_long_inc_return(&u->inflight) == 1) { + if (!u->inflight) { BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); } else { BUG_ON(list_empty(&u->link)); } + u->inflight++; /* Paired with READ_ONCE() in wait_for_unix_gc() */ WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1); } @@ -75,10 +76,11 @@ void unix_notinflight(struct user_struct *user, struct file *fp) if (s) { struct unix_sock *u = unix_sk(s); - BUG_ON(!atomic_long_read(&u->inflight)); + BUG_ON(!u->inflight); BUG_ON(list_empty(&u->link)); - if (atomic_long_dec_and_test(&u->inflight)) + u->inflight--; + if (!u->inflight) list_del_init(&u->link); /* Paired with READ_ONCE() in wait_for_unix_gc() */ WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1); From 5b17307bd0789edea0675d524a2b277b93bbde62 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 23 Jan 2024 09:08:54 -0800 Subject: [PATCH 0359/2255] af_unix: Return struct unix_sock from unix_get_socket(). Currently, unix_get_socket() returns struct sock, but after calling it, we always cast it to unix_sk(). Let's return struct unix_sock from unix_get_socket(). Signed-off-by: Kuniyuki Iwashima Acked-by: Pavel Begunkov Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240123170856.41348-4-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/af_unix.h | 2 +- net/unix/garbage.c | 19 +++++++------------ net/unix/scm.c | 19 +++++++------------ 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/include/net/af_unix.h b/include/net/af_unix.h index ac38b63db554..2c98ef95017b 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -14,7 +14,7 @@ void unix_destruct_scm(struct sk_buff *skb); void io_uring_destruct_scm(struct sk_buff *skb); void unix_gc(void); void wait_for_unix_gc(void); -struct sock *unix_get_socket(struct file *filp); +struct unix_sock *unix_get_socket(struct file *filp); struct sock *unix_peer_get(struct sock *sk); #define UNIX_HASH_MOD (256 - 1) diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 051f96a3ab02..d5ef46a75f1f 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -105,20 +105,15 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), while (nfd--) { /* Get the socket the fd matches if it indeed does so */ - struct sock *sk = unix_get_socket(*fp++); + struct unix_sock *u = unix_get_socket(*fp++); - if (sk) { - struct unix_sock *u = unix_sk(sk); + /* Ignore non-candidates, they could have been added + * to the queues after starting the garbage collection + */ + if (u && test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { + hit = true; - /* Ignore non-candidates, they could - * have been added to the queues after - * starting the garbage collection - */ - if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { - hit = true; - - func(u); - } + func(u); } } if (hit && hitlist != NULL) { diff --git a/net/unix/scm.c b/net/unix/scm.c index e92f2fad6410..b5ae5ab16777 100644 --- a/net/unix/scm.c +++ b/net/unix/scm.c @@ -21,9 +21,8 @@ EXPORT_SYMBOL(gc_inflight_list); DEFINE_SPINLOCK(unix_gc_lock); EXPORT_SYMBOL(unix_gc_lock); -struct sock *unix_get_socket(struct file *filp) +struct unix_sock *unix_get_socket(struct file *filp) { - struct sock *u_sock = NULL; struct inode *inode = file_inode(filp); /* Socket ? */ @@ -34,10 +33,10 @@ struct sock *unix_get_socket(struct file *filp) /* PF_UNIX ? */ if (s && ops && ops->family == PF_UNIX) - u_sock = s; + return unix_sk(s); } - return u_sock; + return NULL; } EXPORT_SYMBOL(unix_get_socket); @@ -46,13 +45,11 @@ EXPORT_SYMBOL(unix_get_socket); */ void unix_inflight(struct user_struct *user, struct file *fp) { - struct sock *s = unix_get_socket(fp); + struct unix_sock *u = unix_get_socket(fp); spin_lock(&unix_gc_lock); - if (s) { - struct unix_sock *u = unix_sk(s); - + if (u) { if (!u->inflight) { BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); @@ -69,13 +66,11 @@ void unix_inflight(struct user_struct *user, struct file *fp) void unix_notinflight(struct user_struct *user, struct file *fp) { - struct sock *s = unix_get_socket(fp); + struct unix_sock *u = unix_get_socket(fp); spin_lock(&unix_gc_lock); - if (s) { - struct unix_sock *u = unix_sk(s); - + if (u) { BUG_ON(!u->inflight); BUG_ON(list_empty(&u->link)); From 8b90a9f819dc2a06baae4ec1a64d875e53b824ec Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 23 Jan 2024 09:08:55 -0800 Subject: [PATCH 0360/2255] af_unix: Run GC on only one CPU. If more than 16000 inflight AF_UNIX sockets exist and the garbage collector is not running, unix_(dgram|stream)_sendmsg() call unix_gc(). Also, they wait for unix_gc() to complete. In unix_gc(), all inflight AF_UNIX sockets are traversed at least once, and more if they are the GC candidate. Thus, sendmsg() significantly slows down with too many inflight AF_UNIX sockets. There is a small window to invoke multiple unix_gc() instances, which will then be blocked by the same spinlock except for one. Let's convert unix_gc() to use struct work so that it will not consume CPUs unnecessarily. Note WRITE_ONCE(gc_in_progress, true) is moved before running GC. If we leave the WRITE_ONCE() as is and use the following test to call flush_work(), a process might not call it. CPU 0 CPU 1 --- --- start work and call __unix_gc() if (work_pending(&unix_gc_work) || <-- false READ_ONCE(gc_in_progress)) <-- false flush_work(); <-- missed! WRITE_ONCE(gc_in_progress, true) Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240123170856.41348-5-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/unix/garbage.c | 54 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/net/unix/garbage.c b/net/unix/garbage.c index d5ef46a75f1f..3f599db59f9d 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -86,7 +86,6 @@ /* Internal data structures and random procedures: */ static LIST_HEAD(gc_candidates); -static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) @@ -182,23 +181,8 @@ static void inc_inflight_move_tail(struct unix_sock *u) } static bool gc_in_progress; -#define UNIX_INFLIGHT_TRIGGER_GC 16000 -void wait_for_unix_gc(void) -{ - /* If number of inflight sockets is insane, - * force a garbage collect right now. - * Paired with the WRITE_ONCE() in unix_inflight(), - * unix_notinflight() and gc_in_progress(). - */ - if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && - !READ_ONCE(gc_in_progress)) - unix_gc(); - wait_event(unix_gc_wait, !READ_ONCE(gc_in_progress)); -} - -/* The external entry point: unix_gc() */ -void unix_gc(void) +static void __unix_gc(struct work_struct *work) { struct sk_buff *next_skb, *skb; struct unix_sock *u; @@ -209,13 +193,6 @@ void unix_gc(void) spin_lock(&unix_gc_lock); - /* Avoid a recursive GC. */ - if (gc_in_progress) - goto out; - - /* Paired with READ_ONCE() in wait_for_unix_gc(). */ - WRITE_ONCE(gc_in_progress, true); - /* First, select candidates for garbage collection. Only * in-flight sockets are considered, and from those only ones * which don't have any external reference. @@ -322,8 +299,31 @@ void unix_gc(void) /* Paired with READ_ONCE() in wait_for_unix_gc(). */ WRITE_ONCE(gc_in_progress, false); - wake_up(&unix_gc_wait); - - out: spin_unlock(&unix_gc_lock); } + +static DECLARE_WORK(unix_gc_work, __unix_gc); + +void unix_gc(void) +{ + WRITE_ONCE(gc_in_progress, true); + queue_work(system_unbound_wq, &unix_gc_work); +} + +#define UNIX_INFLIGHT_TRIGGER_GC 16000 + +void wait_for_unix_gc(void) +{ + /* If number of inflight sockets is insane, + * force a garbage collect right now. + * + * Paired with the WRITE_ONCE() in unix_inflight(), + * unix_notinflight(), and __unix_gc(). + */ + if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && + !READ_ONCE(gc_in_progress)) + unix_gc(); + + if (READ_ONCE(gc_in_progress)) + flush_work(&unix_gc_work); +} From d9f21b3613337b55cc9d4a6ead484dca68475143 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 23 Jan 2024 09:08:56 -0800 Subject: [PATCH 0361/2255] af_unix: Try to run GC async. If more than 16000 inflight AF_UNIX sockets exist and the garbage collector is not running, unix_(dgram|stream)_sendmsg() call unix_gc(). Also, they wait for unix_gc() to complete. In unix_gc(), all inflight AF_UNIX sockets are traversed at least once, and more if they are the GC candidate. Thus, sendmsg() significantly slows down with too many inflight AF_UNIX sockets. However, if a process sends data with no AF_UNIX FD, the sendmsg() call does not need to wait for GC. After this change, only the process that meets the condition below will be blocked under such a situation. 1) cmsg contains AF_UNIX socket 2) more than 32 AF_UNIX sent by the same user are still inflight Note that even a sendmsg() call that does not meet the condition but has AF_UNIX FD will be blocked later in unix_scm_to_skb() by the spinlock, but we allow that as a bonus for sane users. The results below are the time spent in unix_dgram_sendmsg() sending 1 byte of data with no FD 4096 times on a host where 32K inflight AF_UNIX sockets exist. Without series: the sane sendmsg() needs to wait gc unreasonably. $ sudo /usr/share/bcc/tools/funclatency -p 11165 unix_dgram_sendmsg Tracing 1 functions for "unix_dgram_sendmsg"... Hit Ctrl-C to end. ^C nsecs : count distribution [...] 524288 -> 1048575 : 0 | | 1048576 -> 2097151 : 3881 |****************************************| 2097152 -> 4194303 : 214 |** | 4194304 -> 8388607 : 1 | | avg = 1825567 nsecs, total: 7477526027 nsecs, count: 4096 With series: the sane sendmsg() can finish much faster. $ sudo /usr/share/bcc/tools/funclatency -p 8702 unix_dgram_sendmsg Tracing 1 functions for "unix_dgram_sendmsg"... Hit Ctrl-C to end. ^C nsecs : count distribution [...] 128 -> 255 : 0 | | 256 -> 511 : 4092 |****************************************| 512 -> 1023 : 2 | | 1024 -> 2047 : 0 | | 2048 -> 4095 : 0 | | 4096 -> 8191 : 1 | | 8192 -> 16383 : 1 | | avg = 410 nsecs, total: 1680510 nsecs, count: 4096 Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240123170856.41348-6-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/af_unix.h | 12 ++++++++++-- include/net/scm.h | 1 + net/core/scm.c | 5 +++++ net/unix/af_unix.c | 6 ++++-- net/unix/garbage.c | 10 +++++++++- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 2c98ef95017b..f045bbd9017d 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -8,13 +8,21 @@ #include #include +#if IS_ENABLED(CONFIG_UNIX) +struct unix_sock *unix_get_socket(struct file *filp); +#else +static inline struct unix_sock *unix_get_socket(struct file *filp) +{ + return NULL; +} +#endif + void unix_inflight(struct user_struct *user, struct file *fp); void unix_notinflight(struct user_struct *user, struct file *fp); void unix_destruct_scm(struct sk_buff *skb); void io_uring_destruct_scm(struct sk_buff *skb); void unix_gc(void); -void wait_for_unix_gc(void); -struct unix_sock *unix_get_socket(struct file *filp); +void wait_for_unix_gc(struct scm_fp_list *fpl); struct sock *unix_peer_get(struct sock *sk); #define UNIX_HASH_MOD (256 - 1) diff --git a/include/net/scm.h b/include/net/scm.h index cf68acec4d70..92276a2c5543 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -25,6 +25,7 @@ struct scm_creds { struct scm_fp_list { short count; + short count_unix; short max; struct user_struct *user; struct file *fp[SCM_MAX_FD]; diff --git a/net/core/scm.c b/net/core/scm.c index d0e0852a24d5..9cd4b0a01cd6 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -36,6 +36,7 @@ #include #include #include +#include /* @@ -85,6 +86,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) return -ENOMEM; *fplp = fpl; fpl->count = 0; + fpl->count_unix = 0; fpl->max = SCM_MAX_FD; fpl->user = NULL; } @@ -109,6 +111,9 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) fput(file); return -EINVAL; } + if (unix_get_socket(file)) + fpl->count_unix++; + *fpp++ = file; fpl->count++; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 1e9378036dcc..1720419d93d6 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1923,11 +1923,12 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, long timeo; int err; - wait_for_unix_gc(); err = scm_send(sock, msg, &scm, false); if (err < 0) return err; + wait_for_unix_gc(scm.fp); + err = -EOPNOTSUPP; if (msg->msg_flags&MSG_OOB) goto out; @@ -2199,11 +2200,12 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, bool fds_sent = false; int data_len; - wait_for_unix_gc(); err = scm_send(sock, msg, &scm, false); if (err < 0) return err; + wait_for_unix_gc(scm.fp); + err = -EOPNOTSUPP; if (msg->msg_flags & MSG_OOB) { #if IS_ENABLED(CONFIG_AF_UNIX_OOB) diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 3f599db59f9d..4046c606f0e6 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -311,8 +311,9 @@ void unix_gc(void) } #define UNIX_INFLIGHT_TRIGGER_GC 16000 +#define UNIX_INFLIGHT_SANE_USER (SCM_MAX_FD * 8) -void wait_for_unix_gc(void) +void wait_for_unix_gc(struct scm_fp_list *fpl) { /* If number of inflight sockets is insane, * force a garbage collect right now. @@ -324,6 +325,13 @@ void wait_for_unix_gc(void) !READ_ONCE(gc_in_progress)) unix_gc(); + /* Penalise users who want to send AF_UNIX sockets + * but whose sockets have not been received yet. + */ + if (!fpl || !fpl->count_unix || + READ_ONCE(fpl->user->unix_inflight) < UNIX_INFLIGHT_SANE_USER) + return; + if (READ_ONCE(gc_in_progress)) flush_work(&unix_gc_work); } From 8d0293302dfb62dd436622d8bfae23b8074ce2bd Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Thu, 25 Jan 2024 09:53:29 +0800 Subject: [PATCH 0362/2255] drivers/ptp: Convert snprintf to sysfs_emit Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). > ./drivers/ptp/ptp_sysfs.c:27:8-16: WARNING: please use sysfs_emit No functional change intended Signed-off-by: Li Zhijian Acked-by: Richard Cochran Link: https://lore.kernel.org/r/20240125015329.123023-1-lizhijian@fujitsu.com Signed-off-by: Jakub Kicinski --- drivers/ptp/ptp_sysfs.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c index f7a499a1bd39..a15460aaa03b 100644 --- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -24,8 +24,7 @@ static ssize_t max_phase_adjustment_show(struct device *dev, { struct ptp_clock *ptp = dev_get_drvdata(dev); - return snprintf(page, PAGE_SIZE - 1, "%d\n", - ptp->info->getmaxphase(ptp->info)); + return sysfs_emit(page, "%d\n", ptp->info->getmaxphase(ptp->info)); } static DEVICE_ATTR_RO(max_phase_adjustment); @@ -34,7 +33,7 @@ static ssize_t var##_show(struct device *dev, \ struct device_attribute *attr, char *page) \ { \ struct ptp_clock *ptp = dev_get_drvdata(dev); \ - return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->var); \ + return sysfs_emit(page, "%d\n", ptp->info->var); \ } \ static DEVICE_ATTR(name, 0444, var##_show, NULL); @@ -102,8 +101,8 @@ static ssize_t extts_fifo_show(struct device *dev, if (!qcnt) goto out; - cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n", - event.index, event.t.sec, event.t.nsec); + cnt = sysfs_emit(page, "%u %lld %u\n", + event.index, event.t.sec, event.t.nsec); out: return cnt; } @@ -194,7 +193,7 @@ static ssize_t n_vclocks_show(struct device *dev, if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) return -ERESTARTSYS; - size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->n_vclocks); + size = sysfs_emit(page, "%u\n", ptp->n_vclocks); mutex_unlock(&ptp->n_vclocks_mux); @@ -270,7 +269,7 @@ static ssize_t max_vclocks_show(struct device *dev, struct ptp_clock *ptp = dev_get_drvdata(dev); ssize_t size; - size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->max_vclocks); + size = sysfs_emit(page, "%u\n", ptp->max_vclocks); return size; } From 5642c82b9463c3263c086efb002516244bd4c668 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 25 Jan 2024 20:10:48 -0800 Subject: [PATCH 0363/2255] bnx2x: Fix firmware version string character counts A potential string truncation was reported in bnx2x_fill_fw_str(), when a long bp->fw_ver and a long phy_fw_ver might coexist, but seems unlikely with real-world hardware. Use scnprintf() to indicate the intent that truncations are tolerated. While reading this code, I found a collection of various buffer size counting issues. None looked like they might lead to a buffer overflow with current code (the small buffers are 20 bytes and might only ever consume 10 bytes twice with a trailing %NUL). However, early truncation (due to a %NUL in the middle of the string) might be happening under likely rare conditions. Regardless fix the formatters and related functions: - Switch from a separate strscpy() to just adding an additional "%s" to the format string that immediately follows it in bnx2x_fill_fw_str(). - Use sizeof() universally instead of using unbound defines. - Fix bnx2x_7101_format_ver() and bnx2x_null_format_ver() to report the number of characters written, not including the trailing %NUL (as already done with the other firmware formatting functions). - Require space for at least 1 byte in bnx2x_get_ext_phy_fw_version() for the trailing %NUL. - Correct the needed buffer size in bnx2x_3_seq_format_ver(). Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401260858.jZN6vD1k-lkp@intel.com/ Cc: Ariel Elior Cc: Sudarsana Kalluru Cc: Manish Chopra Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20240126041044.work.220-kees@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 9 +++++---- .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 14 +++++++------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index e9c1e1bb5580..528441b28c4e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -147,10 +147,11 @@ void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len) phy_fw_ver[0] = '\0'; bnx2x_get_ext_phy_fw_version(&bp->link_params, - phy_fw_ver, PHY_FW_VER_LEN); - strscpy(buf, bp->fw_ver, buf_len); - snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver), - "bc %d.%d.%d%s%s", + phy_fw_ver, sizeof(phy_fw_ver)); + /* This may become truncated. */ + scnprintf(buf, buf_len, + "%sbc %d.%d.%d%s%s", + bp->fw_ver, (bp->common.bc_ver & 0xff0000) >> 16, (bp->common.bc_ver & 0xff00) >> 8, (bp->common.bc_ver & 0xff), diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 81d232e6d05f..0bc7690cdee1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1132,7 +1132,7 @@ static void bnx2x_get_drvinfo(struct net_device *dev, } memset(version, 0, sizeof(version)); - bnx2x_fill_fw_str(bp, version, ETHTOOL_FWVERS_LEN); + bnx2x_fill_fw_str(bp, version, sizeof(version)); strlcat(info->fw_version, version, sizeof(info->fw_version)); strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 02808513ffe4..ea310057fe3a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -6163,8 +6163,8 @@ static void bnx2x_link_int_ack(struct link_params *params, static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) { - str[0] = '\0'; - (*len)--; + if (*len) + str[0] = '\0'; return 0; } @@ -6173,7 +6173,7 @@ static int bnx2x_format_ver(u32 num, u8 *str, u16 *len) u16 ret; if (*len < 10) { - /* Need more than 10chars for this format */ + /* Need more than 10 chars for this format */ bnx2x_null_format_ver(num, str, len); return -EINVAL; } @@ -6188,8 +6188,8 @@ static int bnx2x_3_seq_format_ver(u32 num, u8 *str, u16 *len) { u16 ret; - if (*len < 10) { - /* Need more than 10chars for this format */ + if (*len < 9) { + /* Need more than 9 chars for this format */ bnx2x_null_format_ver(num, str, len); return -EINVAL; } @@ -6208,7 +6208,7 @@ int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 *version, int status = 0; u8 *ver_p = version; u16 remain_len = len; - if (version == NULL || params == NULL) + if (version == NULL || params == NULL || len == 0) return -EINVAL; bp = params->bp; @@ -11546,7 +11546,7 @@ static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len) str[2] = (spirom_ver & 0xFF0000) >> 16; str[3] = (spirom_ver & 0xFF000000) >> 24; str[4] = '\0'; - *len -= 5; + *len -= 4; return 0; } From c94d1783136eb66f2a464a6891a32eeb55eaeacc Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 25 Jan 2024 21:36:57 +0100 Subject: [PATCH 0364/2255] dt-bindings: net: phy: Make LED active-low property common Move LED active-low property to common.yaml. This property is currently defined multiple times by bcm LEDs. This property will now be supported in a generic way for PHY LEDs with the use of a generic function. With active-low bool property not defined, active-high is always assumed. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Acked-by: Lee Jones Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240125203702.4552-2-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/leds/common.yaml | 6 ++++++ Documentation/devicetree/bindings/leds/leds-bcm63138.yaml | 4 ---- Documentation/devicetree/bindings/leds/leds-bcm6328.yaml | 4 ---- Documentation/devicetree/bindings/leds/leds-bcm6358.txt | 2 -- .../devicetree/bindings/leds/leds-pwm-multicolor.yaml | 4 ---- Documentation/devicetree/bindings/leds/leds-pwm.yaml | 5 ----- 6 files changed, 6 insertions(+), 19 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index 55a8d1385e21..5633e0aa6bdf 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -200,6 +200,12 @@ properties: #trigger-source-cells property in the source node. $ref: /schemas/types.yaml#/definitions/phandle-array + active-low: + type: boolean + description: + Makes LED active low. To turn the LED ON, line needs to be + set to low voltage instead of high. + # Required properties for flash LED child nodes: flash-max-microamp: description: diff --git a/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml index 52252fb6bb32..bb20394fca5c 100644 --- a/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml +++ b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml @@ -52,10 +52,6 @@ patternProperties: maxItems: 1 description: LED pin number - active-low: - type: boolean - description: Makes LED active low - required: - reg diff --git a/Documentation/devicetree/bindings/leds/leds-bcm6328.yaml b/Documentation/devicetree/bindings/leds/leds-bcm6328.yaml index 51cc0d82c12e..f3a3ef992929 100644 --- a/Documentation/devicetree/bindings/leds/leds-bcm6328.yaml +++ b/Documentation/devicetree/bindings/leds/leds-bcm6328.yaml @@ -78,10 +78,6 @@ patternProperties: - maximum: 23 description: LED pin number (only LEDs 0 to 23 are valid). - active-low: - type: boolean - description: Makes LED active low. - brcm,hardware-controlled: type: boolean description: Makes this LED hardware controlled. diff --git a/Documentation/devicetree/bindings/leds/leds-bcm6358.txt b/Documentation/devicetree/bindings/leds/leds-bcm6358.txt index 6e51c6b91ee5..211ffc3c4a20 100644 --- a/Documentation/devicetree/bindings/leds/leds-bcm6358.txt +++ b/Documentation/devicetree/bindings/leds/leds-bcm6358.txt @@ -25,8 +25,6 @@ LED sub-node required properties: LED sub-node optional properties: - label : see Documentation/devicetree/bindings/leds/common.txt - - active-low : Boolean, makes LED active low. - Default : false - default-state : see Documentation/devicetree/bindings/leds/common.txt - linux,default-trigger : see diff --git a/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml b/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml index bd6ec04a8727..5edfbe347341 100644 --- a/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml +++ b/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml @@ -41,10 +41,6 @@ properties: pwm-names: true - active-low: - description: For PWMs where the LED is wired to supply rather than ground. - type: boolean - color: true required: diff --git a/Documentation/devicetree/bindings/leds/leds-pwm.yaml b/Documentation/devicetree/bindings/leds/leds-pwm.yaml index 7de6da58be3c..113b7c218303 100644 --- a/Documentation/devicetree/bindings/leds/leds-pwm.yaml +++ b/Documentation/devicetree/bindings/leds/leds-pwm.yaml @@ -34,11 +34,6 @@ patternProperties: Maximum brightness possible for the LED $ref: /schemas/types.yaml#/definitions/uint32 - active-low: - description: - For PWMs where the LED is wired to supply rather than ground. - type: boolean - required: - pwms - max-brightness From 355c6dc37efa7fe6a64d155254cec8e180e5e6cb Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 25 Jan 2024 21:36:58 +0100 Subject: [PATCH 0365/2255] dt-bindings: net: phy: Document LED inactive high impedance mode Document LED inactive high impedance mode to set the LED to require high impedance configuration to be turned OFF. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Acked-by: Lee Jones Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240125203702.4552-3-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/leds/common.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index 5633e0aa6bdf..8a3c2398b10c 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -206,6 +206,12 @@ properties: Makes LED active low. To turn the LED ON, line needs to be set to low voltage instead of high. + inactive-high-impedance: + type: boolean + description: + Set LED to high-impedance mode to turn the LED OFF. LED might also + describe this mode as tristate. + # Required properties for flash LED child nodes: flash-max-microamp: description: From 7ae215ee7bb855f13c80565470fc7f67db4ba82f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 25 Jan 2024 21:36:59 +0100 Subject: [PATCH 0366/2255] net: phy: add support for PHY LEDs polarity modes Add support for PHY LEDs polarity modes. Some PHY require LED to be set to active low to be turned ON. Adds support for this by declaring active-low property in DT. PHY driver needs to declare .led_polarity_set() to configure LED polarity modes. Function will pass the index with the LED index and a bitmap with all the required modes to set. Current supported modes are: - active-low with the flag PHY_LED_ACTIVE_LOW. LED is set to active-low to turn it ON. - inactive-high-impedance with the flag PHY_LED_INACTIVE_HIGH_IMPEDANCE. LED is set to high impedance to turn it OFF. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240125203702.4552-4-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy_device.c | 16 ++++++++++++++++ include/linux/phy.h | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 3611ea64875e..dd778c7fde1d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -3097,6 +3097,7 @@ static int of_phy_led(struct phy_device *phydev, struct device *dev = &phydev->mdio.dev; struct led_init_data init_data = {}; struct led_classdev *cdev; + unsigned long modes = 0; struct phy_led *phyled; u32 index; int err; @@ -3114,6 +3115,21 @@ static int of_phy_led(struct phy_device *phydev, if (index > U8_MAX) return -EINVAL; + if (of_property_read_bool(led, "active-low")) + set_bit(PHY_LED_ACTIVE_LOW, &modes); + if (of_property_read_bool(led, "inactive-high-impedance")) + set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes); + + if (modes) { + /* Return error if asked to set polarity modes but not supported */ + if (!phydev->drv->led_polarity_set) + return -EINVAL; + + err = phydev->drv->led_polarity_set(phydev, index, modes); + if (err) + return err; + } + phyled->index = index; if (phydev->drv->led_brightness_set) cdev->brightness_set_blocking = phy_led_set_brightness; diff --git a/include/linux/phy.h b/include/linux/phy.h index 684efaeca07c..c9994a59ca2e 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -852,6 +852,15 @@ struct phy_plca_status { bool pst; }; +/* Modes for PHY LED configuration */ +enum phy_led_modes { + PHY_LED_ACTIVE_LOW = 0, + PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1, + + /* keep it last */ + __PHY_LED_MODES_NUM, +}; + /** * struct phy_led: An LED driven by the PHY * @@ -1145,6 +1154,19 @@ struct phy_driver { int (*led_hw_control_get)(struct phy_device *dev, u8 index, unsigned long *rules); + /** + * @led_polarity_set: Set the LED polarity modes + * @dev: PHY device which has the LED + * @index: Which LED of the PHY device + * @modes: bitmap of LED polarity modes + * + * Configure LED with all the required polarity modes in @modes + * to make it correctly turn ON or OFF. + * + * Returns 0, or an error code. + */ + int (*led_polarity_set)(struct phy_device *dev, int index, + unsigned long modes); }; #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \ struct phy_driver, mdiodrv) From 91e893b43d1c8e8b6f4ba0737b597091423024f3 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 25 Jan 2024 21:37:00 +0100 Subject: [PATCH 0367/2255] dt-bindings: net: Document QCA808x PHYs Add Documentation for QCA808x PHYs for the additional LED configuration for this PHY. Signed-off-by: Christian Marangi Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240125203702.4552-5-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- .../devicetree/bindings/net/qca,qca808x.yaml | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/qca,qca808x.yaml diff --git a/Documentation/devicetree/bindings/net/qca,qca808x.yaml b/Documentation/devicetree/bindings/net/qca,qca808x.yaml new file mode 100644 index 000000000000..e2552655902a --- /dev/null +++ b/Documentation/devicetree/bindings/net/qca,qca808x.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/qca,qca808x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Atheros QCA808X PHY + +maintainers: + - Christian Marangi + +description: + QCA808X PHYs can have up to 3 LEDs attached. + All 3 LEDs are disabled by default. + 2 LEDs have dedicated pins with the 3rd LED having the + double function of Interrupt LEDs/GPIO or additional LED. + + By default this special PIN is set to LED function. + +allOf: + - $ref: ethernet-phy.yaml# + +properties: + compatible: + enum: + - ethernet-phy-id004d.d101 + +unevaluatedProperties: false + +examples: + - | + #include + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-phy@0 { + compatible = "ethernet-phy-id004d.d101"; + reg = <0>; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_WAN; + default-state = "keep"; + }; + }; + }; + }; From 7196062b64ee470b91015f3d2e82d225948258ea Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 25 Jan 2024 21:37:01 +0100 Subject: [PATCH 0368/2255] net: phy: at803x: add LED support for qca808x Add LED support for QCA8081 PHY. Documentation for this LEDs PHY is very scarce even with NDA access to Documentation for OEMs. Only the blink pattern are documented and are very confusing most of the time. No documentation is present about forcing the LED on/off or to always blink. Those settings were reversed by poking the regs and trying to find the correct bits to trigger these modes. Some bits mode are not clear and maybe the documentation option are not 100% correct. For the sake of LED support the reversed option are enough to add support for current LED APIs. Supported HW control modes are: - tx - rx - link_10 - link_100 - link_1000 - link_2500 - half_duplex - full_duplex Also add support for LED polarity set to set LED polarity to active high or low. QSDK sets this value to high by default but PHY reset value doesn't have this enabled by default. QSDK also sets 2 additional bits but their usage is not clear, info about this is added in the header. It was verified that for correct function of the LED if active high is needed, only BIT 6 is needed. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240125203702.4552-6-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/at803x.c | 327 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index a62442a55774..9c07a6cc6e67 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -301,6 +301,87 @@ /* Added for reference of existence but should be handled by wait_for_completion already */ #define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) +#define QCA808X_MMD7_LED_GLOBAL 0x8073 +#define QCA808X_LED_BLINK_1 GENMASK(11, 6) +#define QCA808X_LED_BLINK_2 GENMASK(5, 0) +/* Values are the same for both BLINK_1 and BLINK_2 */ +#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) +#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) +#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) +#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) +#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) +#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) +#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) +#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) +#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) +#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) +#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) +#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) +#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) +#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) +#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) +#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) +#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) +#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) + +#define QCA808X_MMD7_LED2_CTRL 0x8074 +#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075 +#define QCA808X_MMD7_LED1_CTRL 0x8076 +#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077 +#define QCA808X_MMD7_LED0_CTRL 0x8078 +#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2)) + +/* LED hw control pattern is the same for every LED */ +#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) +#define QCA808X_LED_SPEED2500_ON BIT(15) +#define QCA808X_LED_SPEED2500_BLINK BIT(14) +/* Follow blink trigger even if duplex or speed condition doesn't match */ +#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) +#define QCA808X_LED_FULL_DUPLEX_ON BIT(12) +#define QCA808X_LED_HALF_DUPLEX_ON BIT(11) +#define QCA808X_LED_TX_BLINK BIT(10) +#define QCA808X_LED_RX_BLINK BIT(9) +#define QCA808X_LED_TX_ON_10MS BIT(8) +#define QCA808X_LED_RX_ON_10MS BIT(7) +#define QCA808X_LED_SPEED1000_ON BIT(6) +#define QCA808X_LED_SPEED100_ON BIT(5) +#define QCA808X_LED_SPEED10_ON BIT(4) +#define QCA808X_LED_COLLISION_BLINK BIT(3) +#define QCA808X_LED_SPEED1000_BLINK BIT(2) +#define QCA808X_LED_SPEED100_BLINK BIT(1) +#define QCA808X_LED_SPEED10_BLINK BIT(0) + +#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079 +#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2)) + +/* LED force ctrl is the same for every LED + * No documentation exist for this, not even internal one + * with NDA as QCOM gives only info about configuring + * hw control pattern rules and doesn't indicate any way + * to force the LED to specific mode. + * These define comes from reverse and testing and maybe + * lack of some info or some info are not entirely correct. + * For the basic LED control and hw control these finding + * are enough to support LED control in all the required APIs. + * + * On doing some comparison with implementation with qca807x, + * it was found that it's 1:1 equal to it and confirms all the + * reverse done. It was also found further specification with the + * force mode and the blink modes. + */ +#define QCA808X_LED_FORCE_EN BIT(15) +#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) +#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) +#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) +#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) +#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) + +#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a +/* QSDK sets by default 0x46 to this reg that sets BIT 6 for + * LED to active high. It's not clear what BIT 3 and BIT 4 does. + */ +#define QCA808X_LED_ACTIVE_HIGH BIT(6) + /* QCA808X 1G chip type */ #define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d #define QCA808X_PHY_CHIP_TYPE_1G BIT(0) @@ -346,6 +427,7 @@ struct at803x_priv { struct regulator_dev *vddio_rdev; struct regulator_dev *vddh_rdev; u64 stats[ARRAY_SIZE(qca83xx_hw_stats)]; + int led_polarity_mode; }; struct at803x_context { @@ -706,6 +788,9 @@ static int at803x_probe(struct phy_device *phydev) if (!priv) return -ENOMEM; + /* Init LED polarity mode to -1 */ + priv->led_polarity_mode = -1; + phydev->priv = priv; ret = at803x_parse_dt(phydev); @@ -2235,6 +2320,242 @@ static void qca808x_link_change_notify(struct phy_device *phydev) phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); } +static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules, + u16 *offload_trigger) +{ + /* Parsing specific to netdev trigger */ + if (test_bit(TRIGGER_NETDEV_TX, &rules)) + *offload_trigger |= QCA808X_LED_TX_BLINK; + if (test_bit(TRIGGER_NETDEV_RX, &rules)) + *offload_trigger |= QCA808X_LED_RX_BLINK; + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + *offload_trigger |= QCA808X_LED_SPEED10_ON; + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + *offload_trigger |= QCA808X_LED_SPEED100_ON; + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + *offload_trigger |= QCA808X_LED_SPEED1000_ON; + if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules)) + *offload_trigger |= QCA808X_LED_SPEED2500_ON; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON; + + if (rules && !*offload_trigger) + return -EOPNOTSUPP; + + /* Enable BLINK_CHECK_BYPASS by default to make the LED + * blink even with duplex or speed mode not enabled. + */ + *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS; + + return 0; +} + +static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN); +} + +static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 offload_trigger = 0; + + if (index > 2) + return -EINVAL; + + return qca808x_led_parse_netdev(phydev, rules, &offload_trigger); +} + +static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 reg, offload_trigger = 0; + int ret; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger); + if (ret) + return ret; + + ret = qca808x_led_hw_control_enable(phydev, index); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_PATTERN_MASK, + offload_trigger); +} + +static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index) +{ + u16 reg; + int val; + + if (index > 2) + return false; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + + return !(val & QCA808X_LED_FORCE_EN); +} + +static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + u16 reg; + int val; + + if (index > 2) + return -EINVAL; + + /* Check if we have hw control enabled */ + if (qca808x_led_hw_control_status(phydev, index)) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + if (val & QCA808X_LED_TX_BLINK) + set_bit(TRIGGER_NETDEV_TX, rules); + if (val & QCA808X_LED_RX_BLINK) + set_bit(TRIGGER_NETDEV_RX, rules); + if (val & QCA808X_LED_SPEED10_ON) + set_bit(TRIGGER_NETDEV_LINK_10, rules); + if (val & QCA808X_LED_SPEED100_ON) + set_bit(TRIGGER_NETDEV_LINK_100, rules); + if (val & QCA808X_LED_SPEED1000_ON) + set_bit(TRIGGER_NETDEV_LINK_1000, rules); + if (val & QCA808X_LED_SPEED2500_ON) + set_bit(TRIGGER_NETDEV_LINK_2500, rules); + if (val & QCA808X_LED_HALF_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); + if (val & QCA808X_LED_FULL_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); + + return 0; +} + +static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_PATTERN_MASK); +} + +static int qca808x_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + u16 reg; + int ret; + + if (index > 2) + return -EINVAL; + + if (!value) { + ret = qca808x_led_hw_control_reset(phydev, index); + if (ret) + return ret; + } + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON : + QCA808X_LED_FORCE_OFF); +} + +static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) +{ + int ret; + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + /* Set blink to 50% off, 50% on at 4Hz by default */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, + QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, + QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); + if (ret) + return ret; + + /* We use BLINK_1 for normal blinking */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); + if (ret) + return ret; + + /* We set blink to 4Hz, aka 250ms */ + *delay_on = 250 / 2; + *delay_off = 250 / 2; + + return 0; +} + +static int qca808x_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + struct at803x_priv *priv = phydev->priv; + bool active_low = false; + u32 mode; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + active_low = true; + break; + default: + return -EINVAL; + } + } + + /* PHY polarity is global and can't be set per LED. + * To detect this, check if last requested polarity mode + * match the new one. + */ + if (priv->led_polarity_mode >= 0 && + priv->led_polarity_mode != active_low) { + phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n"); + return -EINVAL; + } + + /* Save the last PHY polarity mode */ + priv->led_polarity_mode = active_low; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, + QCA808X_MMD7_LED_POLARITY_CTRL, + QCA808X_LED_ACTIVE_HIGH, + active_low ? 0 : QCA808X_LED_ACTIVE_HIGH); +} + static struct phy_driver at803x_driver[] = { { /* Qualcomm Atheros AR8035 */ @@ -2411,6 +2732,12 @@ static struct phy_driver at803x_driver[] = { .cable_test_start = qca808x_cable_test_start, .cable_test_get_status = qca808x_cable_test_get_status, .link_change_notify = qca808x_link_change_notify, + .led_brightness_set = qca808x_led_brightness_set, + .led_blink_set = qca808x_led_blink_set, + .led_hw_is_supported = qca808x_led_hw_is_supported, + .led_hw_control_set = qca808x_led_hw_control_set, + .led_hw_control_get = qca808x_led_hw_control_get, + .led_polarity_set = qca808x_led_polarity_set, }, }; module_phy_driver(at803x_driver); From 0c657f860e675e051553c579669804d21da52364 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 24 Jan 2024 13:33:12 +0100 Subject: [PATCH 0369/2255] net: dsa: microchip: ksz8: move BMCR specific code to separate function Isolate the Basic Mode Control Register (BMCR) operations in the ksz8795 driver by moving the BMCR-related code segments from the ksz8_r_phy() and ksz8_w_phy() functions to newly created ksz8_r_phy_bmcr() and ksz8_w_phy_bmcr() functions. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Acked-by: Arun Ramadoss Link: https://lore.kernel.org/r/20240124123314.734815-2-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8795.c | 386 ++++++++++++++++++---------- 1 file changed, 250 insertions(+), 136 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 61b71bcfe396..1269dde832bd 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -676,59 +676,118 @@ static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val) return 0; } +/** + * ksz8_r_phy_bmcr - Translates and reads from the SMI interface to a MIIM PHY + * Basic mode control register (Reg. 0). + * @dev: The KSZ device instance. + * @port: The port number to be read. + * @val: The value read from the SMI interface. + * + * This function reads the SMI interface and translates the hardware register + * bit values into their corresponding control settings for a MIIM PHY Basic + * mode control register. + * + * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873 + * ------------------------------------------------------------------- + * MIIM Bit | KSZ8794 Reg/Bit | KSZ8873 Reg/Bit + * ----------------------------+-----------------------------+---------------- + * Bit 15 - Soft Reset | 0xF/4 | Not supported + * Bit 14 - Loopback | 0xD/0 (MAC), 0xF/7 (PHY) ~ 0xD/0 (PHY) + * Bit 13 - Force 100 | 0xC/6 = 0xC/6 + * Bit 12 - AN Enable | 0xC/7 (reverse logic) ~ 0xC/7 + * Bit 11 - Power Down | 0xD/3 = 0xD/3 + * Bit 10 - PHY Isolate | 0xF/5 | Not supported + * Bit 9 - Restart AN | 0xD/5 = 0xD/5 + * Bit 8 - Force Full-Duplex | 0xC/5 = 0xC/5 + * Bit 7 - Collision Test/Res. | Not supported | Not supported + * Bit 6 - Reserved | Not supported | Not supported + * Bit 5 - Hp_mdix | 0x9/7 ~ 0xF/7 + * Bit 4 - Force MDI | 0xD/1 = 0xD/1 + * Bit 3 - Disable MDIX | 0xD/2 = 0xD/2 + * Bit 2 - Disable Far-End F. | ???? | 0xD/4 + * Bit 1 - Disable Transmit | 0xD/6 = 0xD/6 + * Bit 0 - Disable LED | 0xD/7 = 0xD/7 + * ------------------------------------------------------------------- + * + * Return: 0 on success, error code on failure. + */ +static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val) +{ + const u16 *regs = dev->info->regs; + u8 restart, speed, ctrl; + int ret; + + *val = 0; + + ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart); + if (ret) + return ret; + + ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed); + if (ret) + return ret; + + ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl); + if (ret) + return ret; + + if (restart & PORT_PHY_LOOPBACK) + *val |= BMCR_LOOPBACK; + + if (ctrl & PORT_FORCE_100_MBIT) + *val |= BMCR_SPEED100; + + if (ksz_is_ksz88x3(dev)) { + if ((ctrl & PORT_AUTO_NEG_ENABLE)) + *val |= BMCR_ANENABLE; + } else { + if (!(ctrl & PORT_AUTO_NEG_DISABLE)) + *val |= BMCR_ANENABLE; + } + + if (restart & PORT_POWER_DOWN) + *val |= BMCR_PDOWN; + + if (restart & PORT_AUTO_NEG_RESTART) + *val |= BMCR_ANRESTART; + + if (ctrl & PORT_FORCE_FULL_DUPLEX) + *val |= BMCR_FULLDPLX; + + if (speed & PORT_HP_MDIX) + *val |= KSZ886X_BMCR_HP_MDIX; + + if (restart & PORT_FORCE_MDIX) + *val |= KSZ886X_BMCR_FORCE_MDI; + + if (restart & PORT_AUTO_MDIX_DISABLE) + *val |= KSZ886X_BMCR_DISABLE_AUTO_MDIX; + + if (restart & PORT_TX_DISABLE) + *val |= KSZ886X_BMCR_DISABLE_TRANSMIT; + + if (restart & PORT_LED_OFF) + *val |= KSZ886X_BMCR_DISABLE_LED; + + return 0; +} + int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) { - u8 restart, speed, ctrl, link; + u8 ctrl, link, val1, val2; int processed = true; const u16 *regs; - u8 val1, val2; u16 data = 0; - u8 p = phy; + u16 p = phy; int ret; regs = dev->info->regs; switch (reg) { case MII_BMCR: - ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); + ret = ksz8_r_phy_bmcr(dev, p, &data); if (ret) return ret; - - ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); - if (ret) - return ret; - - ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); - if (ret) - return ret; - - if (restart & PORT_PHY_LOOPBACK) - data |= BMCR_LOOPBACK; - if (ctrl & PORT_FORCE_100_MBIT) - data |= BMCR_SPEED100; - if (ksz_is_ksz88x3(dev)) { - if ((ctrl & PORT_AUTO_NEG_ENABLE)) - data |= BMCR_ANENABLE; - } else { - if (!(ctrl & PORT_AUTO_NEG_DISABLE)) - data |= BMCR_ANENABLE; - } - if (restart & PORT_POWER_DOWN) - data |= BMCR_PDOWN; - if (restart & PORT_AUTO_NEG_RESTART) - data |= BMCR_ANRESTART; - if (ctrl & PORT_FORCE_FULL_DUPLEX) - data |= BMCR_FULLDPLX; - if (speed & PORT_HP_MDIX) - data |= KSZ886X_BMCR_HP_MDIX; - if (restart & PORT_FORCE_MDIX) - data |= KSZ886X_BMCR_FORCE_MDI; - if (restart & PORT_AUTO_MDIX_DISABLE) - data |= KSZ886X_BMCR_DISABLE_AUTO_MDIX; - if (restart & PORT_TX_DISABLE) - data |= KSZ886X_BMCR_DISABLE_TRANSMIT; - if (restart & PORT_LED_OFF) - data |= KSZ886X_BMCR_DISABLE_LED; break; case MII_BMSR: ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); @@ -860,113 +919,168 @@ static int ksz8_w_phy_ctrl(struct ksz_device *dev, int port, u16 val) return ret; } +/** + * ksz8_w_phy_bmcr - Translates and writes to the SMI interface from a MIIM PHY + * Basic mode control register (Reg. 0). + * @dev: The KSZ device instance. + * @port: The port number to be configured. + * @val: The register value to be written. + * + * This function translates control settings from a MIIM PHY Basic mode control + * register into their corresponding hardware register bit values for the SMI + * interface. + * + * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873 + * ------------------------------------------------------------------- + * MIIM Bit | KSZ8794 Reg/Bit | KSZ8873 Reg/Bit + * ----------------------------+-----------------------------+---------------- + * Bit 15 - Soft Reset | 0xF/4 | Not supported + * Bit 14 - Loopback | 0xD/0 (MAC), 0xF/7 (PHY) ~ 0xD/0 (PHY) + * Bit 13 - Force 100 | 0xC/6 = 0xC/6 + * Bit 12 - AN Enable | 0xC/7 (reverse logic) ~ 0xC/7 + * Bit 11 - Power Down | 0xD/3 = 0xD/3 + * Bit 10 - PHY Isolate | 0xF/5 | Not supported + * Bit 9 - Restart AN | 0xD/5 = 0xD/5 + * Bit 8 - Force Full-Duplex | 0xC/5 = 0xC/5 + * Bit 7 - Collision Test/Res. | Not supported | Not supported + * Bit 6 - Reserved | Not supported | Not supported + * Bit 5 - Hp_mdix | 0x9/7 ~ 0xF/7 + * Bit 4 - Force MDI | 0xD/1 = 0xD/1 + * Bit 3 - Disable MDIX | 0xD/2 = 0xD/2 + * Bit 2 - Disable Far-End F. | ???? | 0xD/4 + * Bit 1 - Disable Transmit | 0xD/6 = 0xD/6 + * Bit 0 - Disable LED | 0xD/7 = 0xD/7 + * ------------------------------------------------------------------- + * + * Return: 0 on success, error code on failure. + */ +static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val) +{ + const u16 *regs = dev->info->regs; + u8 restart, ctrl, speed, data; + int ret; + + /* Do not support PHY reset function. */ + if (val & BMCR_RESET) + return 0; + + ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed); + if (ret) + return ret; + + data = speed; + if (val & KSZ886X_BMCR_HP_MDIX) + data |= PORT_HP_MDIX; + else + data &= ~PORT_HP_MDIX; + + if (data != speed) { + ret = ksz_pwrite8(dev, port, regs[P_SPEED_STATUS], data); + if (ret) + return ret; + } + + ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl); + if (ret) + return ret; + + data = ctrl; + if (ksz_is_ksz88x3(dev)) { + if ((val & BMCR_ANENABLE)) + data |= PORT_AUTO_NEG_ENABLE; + else + data &= ~PORT_AUTO_NEG_ENABLE; + } else { + if (!(val & BMCR_ANENABLE)) + data |= PORT_AUTO_NEG_DISABLE; + else + data &= ~PORT_AUTO_NEG_DISABLE; + + /* Fiber port does not support auto-negotiation. */ + if (dev->ports[port].fiber) + data |= PORT_AUTO_NEG_DISABLE; + } + + if (val & BMCR_SPEED100) + data |= PORT_FORCE_100_MBIT; + else + data &= ~PORT_FORCE_100_MBIT; + + if (val & BMCR_FULLDPLX) + data |= PORT_FORCE_FULL_DUPLEX; + else + data &= ~PORT_FORCE_FULL_DUPLEX; + + if (data != ctrl) { + ret = ksz_pwrite8(dev, port, regs[P_FORCE_CTRL], data); + if (ret) + return ret; + } + + ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart); + if (ret) + return ret; + + data = restart; + if (val & KSZ886X_BMCR_DISABLE_LED) + data |= PORT_LED_OFF; + else + data &= ~PORT_LED_OFF; + + if (val & KSZ886X_BMCR_DISABLE_TRANSMIT) + data |= PORT_TX_DISABLE; + else + data &= ~PORT_TX_DISABLE; + + if (val & BMCR_ANRESTART) + data |= PORT_AUTO_NEG_RESTART; + else + data &= ~(PORT_AUTO_NEG_RESTART); + + if (val & BMCR_PDOWN) + data |= PORT_POWER_DOWN; + else + data &= ~PORT_POWER_DOWN; + + if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX) + data |= PORT_AUTO_MDIX_DISABLE; + else + data &= ~PORT_AUTO_MDIX_DISABLE; + + if (val & KSZ886X_BMCR_FORCE_MDI) + data |= PORT_FORCE_MDIX; + else + data &= ~PORT_FORCE_MDIX; + + if (val & BMCR_LOOPBACK) + data |= PORT_PHY_LOOPBACK; + else + data &= ~PORT_PHY_LOOPBACK; + + if (data != restart) { + ret = ksz_pwrite8(dev, port, regs[P_NEG_RESTART_CTRL], + data); + if (ret) + return ret; + } + + return 0; +} + int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) { - u8 restart, speed, ctrl, data; const u16 *regs; - u8 p = phy; + u8 ctrl, data; + u16 p = phy; int ret; regs = dev->info->regs; switch (reg) { case MII_BMCR: - - /* Do not support PHY reset function. */ - if (val & BMCR_RESET) - break; - ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); + ret = ksz8_w_phy_bmcr(dev, p, val); if (ret) return ret; - - data = speed; - if (val & KSZ886X_BMCR_HP_MDIX) - data |= PORT_HP_MDIX; - else - data &= ~PORT_HP_MDIX; - - if (data != speed) { - ret = ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); - if (ret) - return ret; - } - - ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); - if (ret) - return ret; - - data = ctrl; - if (ksz_is_ksz88x3(dev)) { - if ((val & BMCR_ANENABLE)) - data |= PORT_AUTO_NEG_ENABLE; - else - data &= ~PORT_AUTO_NEG_ENABLE; - } else { - if (!(val & BMCR_ANENABLE)) - data |= PORT_AUTO_NEG_DISABLE; - else - data &= ~PORT_AUTO_NEG_DISABLE; - - /* Fiber port does not support auto-negotiation. */ - if (dev->ports[p].fiber) - data |= PORT_AUTO_NEG_DISABLE; - } - - if (val & BMCR_SPEED100) - data |= PORT_FORCE_100_MBIT; - else - data &= ~PORT_FORCE_100_MBIT; - if (val & BMCR_FULLDPLX) - data |= PORT_FORCE_FULL_DUPLEX; - else - data &= ~PORT_FORCE_FULL_DUPLEX; - - if (data != ctrl) { - ret = ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data); - if (ret) - return ret; - } - - ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); - if (ret) - return ret; - - data = restart; - if (val & KSZ886X_BMCR_DISABLE_LED) - data |= PORT_LED_OFF; - else - data &= ~PORT_LED_OFF; - if (val & KSZ886X_BMCR_DISABLE_TRANSMIT) - data |= PORT_TX_DISABLE; - else - data &= ~PORT_TX_DISABLE; - if (val & BMCR_ANRESTART) - data |= PORT_AUTO_NEG_RESTART; - else - data &= ~(PORT_AUTO_NEG_RESTART); - if (val & BMCR_PDOWN) - data |= PORT_POWER_DOWN; - else - data &= ~PORT_POWER_DOWN; - if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX) - data |= PORT_AUTO_MDIX_DISABLE; - else - data &= ~PORT_AUTO_MDIX_DISABLE; - if (val & KSZ886X_BMCR_FORCE_MDI) - data |= PORT_FORCE_MDIX; - else - data &= ~PORT_FORCE_MDIX; - if (val & BMCR_LOOPBACK) - data |= PORT_PHY_LOOPBACK; - else - data &= ~PORT_PHY_LOOPBACK; - - if (data != restart) { - ret = ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], - data); - if (ret) - return ret; - } break; case MII_ADVERTISE: ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); From d1b7d0d85d59bfe6f57b1604a922466e4f8ee734 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 24 Jan 2024 13:33:13 +0100 Subject: [PATCH 0370/2255] net: dsa: microchip: Remove redundant optimization in ksz8_w_phy_bmcr Remove the manual checks for register value changes in the ksz8_w_phy_bmcr function. Instead, rely on regmap_update_bits() for optimizing register updates. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Acked-by: Arun Ramadoss Link: https://lore.kernel.org/r/20240124123314.734815-3-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8795.c | 96 +++++++++-------------------- 1 file changed, 29 insertions(+), 67 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 1269dde832bd..51e0194453df 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -956,115 +956,77 @@ static int ksz8_w_phy_ctrl(struct ksz_device *dev, int port, u16 val) */ static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val) { + u8 restart, speed, ctrl, restart_mask; const u16 *regs = dev->info->regs; - u8 restart, ctrl, speed, data; int ret; /* Do not support PHY reset function. */ if (val & BMCR_RESET) return 0; - ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed); - if (ret) - return ret; - - data = speed; + speed = 0; if (val & KSZ886X_BMCR_HP_MDIX) - data |= PORT_HP_MDIX; - else - data &= ~PORT_HP_MDIX; + speed |= PORT_HP_MDIX; - if (data != speed) { - ret = ksz_pwrite8(dev, port, regs[P_SPEED_STATUS], data); - if (ret) - return ret; - } - - ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl); + ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed); if (ret) return ret; - data = ctrl; + ctrl = 0; if (ksz_is_ksz88x3(dev)) { if ((val & BMCR_ANENABLE)) - data |= PORT_AUTO_NEG_ENABLE; - else - data &= ~PORT_AUTO_NEG_ENABLE; + ctrl |= PORT_AUTO_NEG_ENABLE; } else { if (!(val & BMCR_ANENABLE)) - data |= PORT_AUTO_NEG_DISABLE; - else - data &= ~PORT_AUTO_NEG_DISABLE; + ctrl |= PORT_AUTO_NEG_DISABLE; /* Fiber port does not support auto-negotiation. */ if (dev->ports[port].fiber) - data |= PORT_AUTO_NEG_DISABLE; + ctrl |= PORT_AUTO_NEG_DISABLE; } if (val & BMCR_SPEED100) - data |= PORT_FORCE_100_MBIT; - else - data &= ~PORT_FORCE_100_MBIT; + ctrl |= PORT_FORCE_100_MBIT; if (val & BMCR_FULLDPLX) - data |= PORT_FORCE_FULL_DUPLEX; - else - data &= ~PORT_FORCE_FULL_DUPLEX; + ctrl |= PORT_FORCE_FULL_DUPLEX; - if (data != ctrl) { - ret = ksz_pwrite8(dev, port, regs[P_FORCE_CTRL], data); - if (ret) - return ret; - } - - ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart); + ret = ksz_prmw8(dev, port, regs[P_FORCE_CTRL], PORT_FORCE_100_MBIT | + /* PORT_AUTO_NEG_ENABLE and PORT_AUTO_NEG_DISABLE are the same + * bits + */ + PORT_FORCE_FULL_DUPLEX | PORT_AUTO_NEG_ENABLE, ctrl); if (ret) return ret; - data = restart; + restart = 0; + restart_mask = PORT_LED_OFF | PORT_TX_DISABLE | PORT_AUTO_NEG_RESTART | + PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX | + PORT_PHY_LOOPBACK; + if (val & KSZ886X_BMCR_DISABLE_LED) - data |= PORT_LED_OFF; - else - data &= ~PORT_LED_OFF; + restart |= PORT_LED_OFF; if (val & KSZ886X_BMCR_DISABLE_TRANSMIT) - data |= PORT_TX_DISABLE; - else - data &= ~PORT_TX_DISABLE; + restart |= PORT_TX_DISABLE; if (val & BMCR_ANRESTART) - data |= PORT_AUTO_NEG_RESTART; - else - data &= ~(PORT_AUTO_NEG_RESTART); + restart |= PORT_AUTO_NEG_RESTART; if (val & BMCR_PDOWN) - data |= PORT_POWER_DOWN; - else - data &= ~PORT_POWER_DOWN; + restart |= PORT_POWER_DOWN; if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX) - data |= PORT_AUTO_MDIX_DISABLE; - else - data &= ~PORT_AUTO_MDIX_DISABLE; + restart |= PORT_AUTO_MDIX_DISABLE; if (val & KSZ886X_BMCR_FORCE_MDI) - data |= PORT_FORCE_MDIX; - else - data &= ~PORT_FORCE_MDIX; + restart |= PORT_FORCE_MDIX; if (val & BMCR_LOOPBACK) - data |= PORT_PHY_LOOPBACK; - else - data &= ~PORT_PHY_LOOPBACK; + restart |= PORT_PHY_LOOPBACK; - if (data != restart) { - ret = ksz_pwrite8(dev, port, regs[P_NEG_RESTART_CTRL], - data); - if (ret) - return ret; - } - - return 0; + return ksz_prmw8(dev, port, regs[P_NEG_RESTART_CTRL], restart_mask, + restart); } int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) From 9e62bed6e105f2f522e360a024fc93c64c58a207 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 24 Jan 2024 13:33:14 +0100 Subject: [PATCH 0371/2255] net: dsa: microchip: implement PHY loopback configuration for KSZ8794 and KSZ8873 Correct the PHY loopback bit handling in the ksz8_w_phy_bmcr and ksz8_r_phy_bmcr functions for KSZ8794 and KSZ8873 variants in the ksz8795 driver. Previously, the code erroneously used Bit 7 of port register 0xD for both chip variants, which is actually for LED configuration. This update ensures the correct registers and bits are used for the PHY loopback feature: - For KSZ8794: Use 0xF / Bit 7. - For KSZ8873: Use 0xD / Bit 0. The lack of loopback support was seen on KSZ8873 system by using "ethtool -t lanX". After this patch, the ethtool selftest will work, but only if port is not part of a bridge. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Acked-by: Arun Ramadoss Link: https://lore.kernel.org/r/20240124123314.734815-4-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8795.c | 76 ++++++++++++++++++++++--- drivers/net/dsa/microchip/ksz8795_reg.h | 1 + 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 51e0194453df..50351cef6ca5 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -632,6 +632,57 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan) ksz8_w_table(dev, TABLE_VLAN, addr, buf); } +/** + * ksz879x_get_loopback - KSZ879x specific function to get loopback + * configuration status for a specific port + * @dev: Pointer to the device structure + * @port: Port number to query + * @val: Pointer to store the result + * + * This function reads the SMI registers to determine whether loopback mode + * is enabled for a specific port. + * + * Return: 0 on success, error code on failure. + */ +static int ksz879x_get_loopback(struct ksz_device *dev, u16 port, + u16 *val) +{ + u8 stat3; + int ret; + + ret = ksz_pread8(dev, port, REG_PORT_STATUS_3, &stat3); + if (ret) + return ret; + + if (stat3 & PORT_PHY_LOOPBACK) + *val |= BMCR_LOOPBACK; + + return 0; +} + +/** + * ksz879x_set_loopback - KSZ879x specific function to set loopback mode for + * a specific port + * @dev: Pointer to the device structure. + * @port: Port number to modify. + * @val: Value indicating whether to enable or disable loopback mode. + * + * This function translates loopback bit of the BMCR register into the + * corresponding hardware register bit value and writes it to the SMI interface. + * + * Return: 0 on success, error code on failure. + */ +static int ksz879x_set_loopback(struct ksz_device *dev, u16 port, u16 val) +{ + u8 stat3 = 0; + + if (val & BMCR_LOOPBACK) + stat3 |= PORT_PHY_LOOPBACK; + + return ksz_prmw8(dev, port, REG_PORT_STATUS_3, PORT_PHY_LOOPBACK, + stat3); +} + /** * ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY * Control register (Reg. 31). @@ -731,16 +782,20 @@ static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val) if (ret) return ret; - if (restart & PORT_PHY_LOOPBACK) - *val |= BMCR_LOOPBACK; - if (ctrl & PORT_FORCE_100_MBIT) *val |= BMCR_SPEED100; if (ksz_is_ksz88x3(dev)) { + if (restart & KSZ8873_PORT_PHY_LOOPBACK) + *val |= BMCR_LOOPBACK; + if ((ctrl & PORT_AUTO_NEG_ENABLE)) *val |= BMCR_ANENABLE; } else { + ret = ksz879x_get_loopback(dev, port, val); + if (ret) + return ret; + if (!(ctrl & PORT_AUTO_NEG_DISABLE)) *val |= BMCR_ANENABLE; } @@ -1001,8 +1056,7 @@ static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val) restart = 0; restart_mask = PORT_LED_OFF | PORT_TX_DISABLE | PORT_AUTO_NEG_RESTART | - PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX | - PORT_PHY_LOOPBACK; + PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX; if (val & KSZ886X_BMCR_DISABLE_LED) restart |= PORT_LED_OFF; @@ -1022,8 +1076,16 @@ static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val) if (val & KSZ886X_BMCR_FORCE_MDI) restart |= PORT_FORCE_MDIX; - if (val & BMCR_LOOPBACK) - restart |= PORT_PHY_LOOPBACK; + if (ksz_is_ksz88x3(dev)) { + restart_mask |= KSZ8873_PORT_PHY_LOOPBACK; + + if (val & BMCR_LOOPBACK) + restart |= KSZ8873_PORT_PHY_LOOPBACK; + } else { + ret = ksz879x_set_loopback(dev, port, val); + if (ret) + return ret; + } return ksz_prmw8(dev, port, regs[P_NEG_RESTART_CTRL], restart_mask, restart); diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h index beca974e0171..7c9341ef73b0 100644 --- a/drivers/net/dsa/microchip/ksz8795_reg.h +++ b/drivers/net/dsa/microchip/ksz8795_reg.h @@ -265,6 +265,7 @@ #define PORT_AUTO_MDIX_DISABLE BIT(2) #define PORT_FORCE_MDIX BIT(1) #define PORT_MAC_LOOPBACK BIT(0) +#define KSZ8873_PORT_PHY_LOOPBACK BIT(0) #define REG_PORT_1_STATUS_2 0x1E #define REG_PORT_2_STATUS_2 0x2E From df3fc228dead6298ac9e985a270b8521e41471e6 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Fri, 12 Jan 2024 17:37:46 +0100 Subject: [PATCH 0372/2255] batman-adv: Start new development cycle This version will contain all the (major or even only minor) changes for Linux 6.9. The version number isn't a semantic version number with major and minor information. It is just encoding the year of the expected publishing as Linux -rc1 and the number of published versions this year (starting at 0). Signed-off-by: Simon Wunderlich --- net/batman-adv/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 870dcd7f1786..8ca854a75a32 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -13,7 +13,7 @@ #define BATADV_DRIVER_DEVICE "batman-adv" #ifndef BATADV_SOURCE_VERSION -#define BATADV_SOURCE_VERSION "2024.0" +#define BATADV_SOURCE_VERSION "2024.1" #endif /* B.A.T.M.A.N. parameters */ From ffc15626c861f811f9778914be004fcf43810a91 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 2 Jan 2024 07:27:45 +0100 Subject: [PATCH 0373/2255] batman-adv: Return directly after a failed batadv_dat_select_candidates() in batadv_dat_forward_data() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kfree() function was called in one case by the batadv_dat_forward_data() function during error handling even if the passed variable contained a null pointer. This issue was detected by using the Coccinelle software. * Thus return directly after a batadv_dat_select_candidates() call failed at the beginning. * Delete the label “out” which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Acked-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/distributed-arp-table.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 28a939d56090..4c7e85534324 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -684,7 +684,7 @@ static bool batadv_dat_forward_data(struct batadv_priv *bat_priv, cand = batadv_dat_select_candidates(bat_priv, ip, vid); if (!cand) - goto out; + return ret; batadv_dbg(BATADV_DBG_DAT, bat_priv, "DHT_SEND for %pI4\n", &ip); @@ -728,7 +728,6 @@ free_orig: batadv_orig_node_put(cand[i].orig_node); } -out: kfree(cand); return ret; } From 5593e9abf1cf2bf096366d8c7fd933bc69d561ce Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 2 Jan 2024 07:52:21 +0100 Subject: [PATCH 0374/2255] batman-adv: Improve exception handling in batadv_throw_uevent() The kfree() function was called in up to three cases by the batadv_throw_uevent() function during error handling even if the passed variable contained a null pointer. This issue was detected by using the Coccinelle software. * Thus adjust jump targets. * Reorder kfree() calls at the end. Signed-off-by: Markus Elfring Acked-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/main.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 5fc754b0b3f7..75119f1ffccc 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -691,29 +691,31 @@ int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, "%s%s", BATADV_UEV_TYPE_VAR, batadv_uev_type_str[type]); if (!uevent_env[0]) - goto out; + goto report_error; uevent_env[1] = kasprintf(GFP_ATOMIC, "%s%s", BATADV_UEV_ACTION_VAR, batadv_uev_action_str[action]); if (!uevent_env[1]) - goto out; + goto free_first_env; /* If the event is DEL, ignore the data field */ if (action != BATADV_UEV_DEL) { uevent_env[2] = kasprintf(GFP_ATOMIC, "%s%s", BATADV_UEV_DATA_VAR, data); if (!uevent_env[2]) - goto out; + goto free_second_env; } ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); -out: - kfree(uevent_env[0]); - kfree(uevent_env[1]); kfree(uevent_env[2]); +free_second_env: + kfree(uevent_env[1]); +free_first_env: + kfree(uevent_env[0]); if (ret) +report_error: batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Impossible to send uevent for (%s,%s,%s) event (err: %d)\n", batadv_uev_type_str[type], From db60ad8b21cee0394cb0a1092d9f9190d310562c Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Jan 2024 14:03:38 +0100 Subject: [PATCH 0375/2255] batman-adv: Drop usage of export.h The linux/export.h include was introduced in commit 9bcb94c8617e ("batman-adv: Introduce missing headers for genetlink restructure") to have access to THIS_MODULE. But with commit 5b20755b7780 ("init: move THIS_MODULE from to "), it was moved and the include for export.h is no longer needed. Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/netlink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 1f7ed9d4f6fd..0954757f0b8b 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include From 1d4046b5714200ad3a20be09843a63c1c1c9dafe Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 25 Jan 2024 10:45:01 +0900 Subject: [PATCH 0376/2255] rust: phy: use `srctree`-relative links The relative paths like the following are bothersome and don't work with `O=` builds: //! C headers: [`include/linux/phy.h`](../../../../../../../include/linux/phy.h). This updates such links by using the `srctree`-relative link feature introduced in 6.8-rc1 like: //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h). Signed-off-by: FUJITA Tomonori Reviewed-by: Trevor Gross Signed-off-by: David S. Miller --- rust/kernel/net/phy.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index e457b3c7cb2f..203918192a1f 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -4,7 +4,7 @@ //! Network PHY device. //! -//! C headers: [`include/linux/phy.h`](../../../../../../../include/linux/phy.h). +//! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h). use crate::{bindings, error::*, prelude::*, str::CStr, types::Opaque}; @@ -16,7 +16,7 @@ use core::marker::PhantomData; /// /// Some of PHY drivers access to the state of PHY's software state machine. /// -/// [`enum phy_state`]: ../../../../../../../include/linux/phy.h +/// [`enum phy_state`]: srctree/include/linux/phy.h #[derive(PartialEq, Eq)] pub enum DeviceState { /// PHY device and driver are not ready for anything. @@ -61,7 +61,7 @@ pub enum DuplexMode { /// Referencing a `phy_device` using this struct asserts that you are in /// a context where all methods defined on this struct are safe to call. /// -/// [`struct phy_device`]: ../../../../../../../include/linux/phy.h +/// [`struct phy_device`]: srctree/include/linux/phy.h // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is // unique for every instance of [`Device`]. `PHYLIB` uses a different serialization technique for // [`Driver::resume`] and [`Driver::suspend`]: `PHYLIB` updates `phy_device`'s state with @@ -486,7 +486,7 @@ impl Adapter { /// /// `self.0` is always in a valid state. /// -/// [`struct phy_driver`]: ../../../../../../../include/linux/phy.h +/// [`struct phy_driver`]: srctree/include/linux/phy.h #[repr(transparent)] pub struct DriverVTable(Opaque); From 599b75a3b753ad06444a4e9667cb0b7545c297c3 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 25 Jan 2024 10:45:02 +0900 Subject: [PATCH 0377/2255] rust: phy: use VTABLE_DEFAULT_ERROR Since 6.8-rc1, using VTABLE_DEFAULT_ERROR for optional functions (never called) in #[vtable] is the recommended way. Note that no functional changes in this patch. Signed-off-by: FUJITA Tomonori Reviewed-by: Trevor Gross Signed-off-by: David S. Miller --- rust/kernel/net/phy.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index 203918192a1f..96e09c6e8530 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -580,12 +580,12 @@ pub trait Driver { /// Issues a PHY software reset. fn soft_reset(_dev: &mut Device) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Probes the hardware to determine what abilities it has. fn get_features(_dev: &mut Device) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Returns true if this is a suitable driver for the given phydev. @@ -597,32 +597,32 @@ pub trait Driver { /// Configures the advertisement and resets auto-negotiation /// if auto-negotiation is enabled. fn config_aneg(_dev: &mut Device) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Determines the negotiated speed and duplex. fn read_status(_dev: &mut Device) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Suspends the hardware, saving state if needed. fn suspend(_dev: &mut Device) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Resumes the hardware, restoring state if needed. fn resume(_dev: &mut Device) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Overrides the default MMD read function for reading a MMD register. fn read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Overrides the default MMD write function for writing a MMD register. fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result { - Err(code::ENOTSUPP) + kernel::build_error(VTABLE_DEFAULT_ERROR) } /// Callback for notification of link change. From 6f83b62283edc295be1cfa18dd49d4f278575118 Mon Sep 17 00:00:00 2001 From: William Tu Date: Wed, 24 Jan 2024 20:00:41 -0800 Subject: [PATCH 0378/2255] Documentation: mlx5.rst: Add note for eswitch MD Add a note when using esw_port_metadata. The parameter has runtime mode but setting it does not take effect immediately. Setting it must happen in legacy mode, and the port metadata takes effects when the switchdev mode is enabled. Disable eswitch port metadata:: $ devlink dev param set pci/0000:06:00.0 name esw_port_metadata value \ false cmode runtime Change eswitch mode to switchdev mode where after choosing the metadata value:: $ devlink dev eswitch set pci/0000:06:00.0 mode switchdev Note that other mlx5 devlink runtime parameters, esw_multiport and flow_steering_mode, do not have this limitation. Signed-off-by: William Tu Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/networking/devlink/mlx5.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/networking/devlink/mlx5.rst b/Documentation/networking/devlink/mlx5.rst index 702f204a3dbd..b9587b3400b9 100644 --- a/Documentation/networking/devlink/mlx5.rst +++ b/Documentation/networking/devlink/mlx5.rst @@ -97,6 +97,10 @@ parameters. When metadata is disabled, the above use cases will fail to initialize if users try to enable them. + + Note: Setting this parameter does not take effect immediately. Setting + must happen in legacy mode and eswitch port metadata takes effect after + enabling switchdev mode. * - ``hairpin_num_queues`` - u32 - driverinit From 63aabc3ef1961a5eb3049d02a323b3b7fabb9a23 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Thu, 25 Jan 2024 14:22:12 +0800 Subject: [PATCH 0379/2255] net: txgbe: move interrupt codes to a separate file In order to change the interrupt response structure, there will be a lot of code added next. Move these interrupt codes to a new file, to make the codes cleaner. Signed-off-by: Jiawen Wu Signed-off-by: David S. Miller --- drivers/net/ethernet/wangxun/txgbe/Makefile | 1 + .../net/ethernet/wangxun/txgbe/txgbe_irq.c | 137 ++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_irq.h | 5 + .../net/ethernet/wangxun/txgbe/txgbe_main.c | 128 +--------------- 4 files changed, 144 insertions(+), 127 deletions(-) create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile index 7507f762edfe..42718875277c 100644 --- a/drivers/net/ethernet/wangxun/txgbe/Makefile +++ b/drivers/net/ethernet/wangxun/txgbe/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_TXGBE) += txgbe.o txgbe-objs := txgbe_main.o \ txgbe_hw.o \ txgbe_phy.o \ + txgbe_irq.o \ txgbe_ethtool.o diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c new file mode 100644 index 000000000000..d26ee4cb1767 --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ + +#include + +#include "../libwx/wx_type.h" +#include "../libwx/wx_lib.h" +#include "../libwx/wx_hw.h" +#include "txgbe_type.h" +#include "txgbe_irq.h" + +/** + * txgbe_irq_enable - Enable default interrupt generation settings + * @wx: pointer to private structure + * @queues: enable irqs for queues + **/ +void txgbe_irq_enable(struct wx *wx, bool queues) +{ + wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); + + /* unmask interrupt */ + wx_intr_enable(wx, TXGBE_INTR_MISC); + if (queues) + wx_intr_enable(wx, TXGBE_INTR_QALL(wx)); +} + +/** + * txgbe_intr - msi/legacy mode Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t txgbe_intr(int __always_unused irq, void *data) +{ + struct wx_q_vector *q_vector; + struct wx *wx = data; + struct pci_dev *pdev; + u32 eicr; + + q_vector = wx->q_vector[0]; + pdev = wx->pdev; + + eicr = wx_misc_isb(wx, WX_ISB_VEC0); + if (!eicr) { + /* shared interrupt alert! + * the interrupt that we masked before the ICR read. + */ + if (netif_running(wx->netdev)) + txgbe_irq_enable(wx, true); + return IRQ_NONE; /* Not our interrupt */ + } + wx->isb_mem[WX_ISB_VEC0] = 0; + if (!(pdev->msi_enabled)) + wr32(wx, WX_PX_INTA, 1); + + wx->isb_mem[WX_ISB_MISC] = 0; + /* would disable interrupts here but it is auto disabled */ + napi_schedule_irqoff(&q_vector->napi); + + /* re-enable link(maybe) and non-queue interrupts, no flush. + * txgbe_poll will re-enable the queue interrupts + */ + if (netif_running(wx->netdev)) + txgbe_irq_enable(wx, false); + + return IRQ_HANDLED; +} + +/** + * txgbe_request_msix_irqs - Initialize MSI-X interrupts + * @wx: board private structure + * + * Allocate MSI-X vectors and request interrupts from the kernel. + **/ +static int txgbe_request_msix_irqs(struct wx *wx) +{ + struct net_device *netdev = wx->netdev; + int vector, err; + + for (vector = 0; vector < wx->num_q_vectors; vector++) { + struct wx_q_vector *q_vector = wx->q_vector[vector]; + struct msix_entry *entry = &wx->msix_q_entries[vector]; + + if (q_vector->tx.ring && q_vector->rx.ring) + snprintf(q_vector->name, sizeof(q_vector->name) - 1, + "%s-TxRx-%d", netdev->name, entry->entry); + else + /* skip this unused q_vector */ + continue; + + err = request_irq(entry->vector, wx_msix_clean_rings, 0, + q_vector->name, q_vector); + if (err) { + wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", + q_vector->name, err); + goto free_queue_irqs; + } + } + + return 0; + +free_queue_irqs: + while (vector) { + vector--; + free_irq(wx->msix_q_entries[vector].vector, + wx->q_vector[vector]); + } + wx_reset_interrupt_capability(wx); + return err; +} + +/** + * txgbe_request_irq - initialize interrupts + * @wx: board private structure + * + * Attempt to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +int txgbe_request_irq(struct wx *wx) +{ + struct net_device *netdev = wx->netdev; + struct pci_dev *pdev = wx->pdev; + int err; + + if (pdev->msix_enabled) + err = txgbe_request_msix_irqs(wx); + else if (pdev->msi_enabled) + err = request_irq(wx->pdev->irq, &txgbe_intr, 0, + netdev->name, wx); + else + err = request_irq(wx->pdev->irq, &txgbe_intr, IRQF_SHARED, + netdev->name, wx); + + if (err) + wx_err(wx, "request_irq failed, Error %d\n", err); + + return err; +} diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h new file mode 100644 index 000000000000..02c536421f7d --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ + +void txgbe_irq_enable(struct wx *wx, bool queues); +int txgbe_request_irq(struct wx *wx); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 3b151c410a5c..8cf8c0d016df 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -17,6 +17,7 @@ #include "txgbe_type.h" #include "txgbe_hw.h" #include "txgbe_phy.h" +#include "txgbe_irq.h" #include "txgbe_ethtool.h" char txgbe_driver_name[] = "txgbe"; @@ -76,133 +77,6 @@ static int txgbe_enumerate_functions(struct wx *wx) return physfns; } -/** - * txgbe_irq_enable - Enable default interrupt generation settings - * @wx: pointer to private structure - * @queues: enable irqs for queues - **/ -static void txgbe_irq_enable(struct wx *wx, bool queues) -{ - wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); - - /* unmask interrupt */ - wx_intr_enable(wx, TXGBE_INTR_MISC); - if (queues) - wx_intr_enable(wx, TXGBE_INTR_QALL(wx)); -} - -/** - * txgbe_intr - msi/legacy mode Interrupt Handler - * @irq: interrupt number - * @data: pointer to a network interface device structure - **/ -static irqreturn_t txgbe_intr(int __always_unused irq, void *data) -{ - struct wx_q_vector *q_vector; - struct wx *wx = data; - struct pci_dev *pdev; - u32 eicr; - - q_vector = wx->q_vector[0]; - pdev = wx->pdev; - - eicr = wx_misc_isb(wx, WX_ISB_VEC0); - if (!eicr) { - /* shared interrupt alert! - * the interrupt that we masked before the ICR read. - */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, true); - return IRQ_NONE; /* Not our interrupt */ - } - wx->isb_mem[WX_ISB_VEC0] = 0; - if (!(pdev->msi_enabled)) - wr32(wx, WX_PX_INTA, 1); - - wx->isb_mem[WX_ISB_MISC] = 0; - /* would disable interrupts here but it is auto disabled */ - napi_schedule_irqoff(&q_vector->napi); - - /* re-enable link(maybe) and non-queue interrupts, no flush. - * txgbe_poll will re-enable the queue interrupts - */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, false); - - return IRQ_HANDLED; -} - -/** - * txgbe_request_msix_irqs - Initialize MSI-X interrupts - * @wx: board private structure - * - * Allocate MSI-X vectors and request interrupts from the kernel. - **/ -static int txgbe_request_msix_irqs(struct wx *wx) -{ - struct net_device *netdev = wx->netdev; - int vector, err; - - for (vector = 0; vector < wx->num_q_vectors; vector++) { - struct wx_q_vector *q_vector = wx->q_vector[vector]; - struct msix_entry *entry = &wx->msix_q_entries[vector]; - - if (q_vector->tx.ring && q_vector->rx.ring) - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-TxRx-%d", netdev->name, entry->entry); - else - /* skip this unused q_vector */ - continue; - - err = request_irq(entry->vector, wx_msix_clean_rings, 0, - q_vector->name, q_vector); - if (err) { - wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", - q_vector->name, err); - goto free_queue_irqs; - } - } - - return 0; - -free_queue_irqs: - while (vector) { - vector--; - free_irq(wx->msix_q_entries[vector].vector, - wx->q_vector[vector]); - } - wx_reset_interrupt_capability(wx); - return err; -} - -/** - * txgbe_request_irq - initialize interrupts - * @wx: board private structure - * - * Attempt to configure interrupts using the best available - * capabilities of the hardware and kernel. - **/ -static int txgbe_request_irq(struct wx *wx) -{ - struct net_device *netdev = wx->netdev; - struct pci_dev *pdev = wx->pdev; - int err; - - if (pdev->msix_enabled) - err = txgbe_request_msix_irqs(wx); - else if (pdev->msi_enabled) - err = request_irq(wx->pdev->irq, &txgbe_intr, 0, - netdev->name, wx); - else - err = request_irq(wx->pdev->irq, &txgbe_intr, IRQF_SHARED, - netdev->name, wx); - - if (err) - wx_err(wx, "request_irq failed, Error %d\n", err); - - return err; -} - static void txgbe_up_complete(struct wx *wx) { struct net_device *netdev = wx->netdev; From aefd013624a10f39b0bfaee8432a235128705380 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Thu, 25 Jan 2024 14:22:13 +0800 Subject: [PATCH 0380/2255] net: txgbe: use irq_domain for interrupt controller In the current interrupt controller, the MAC interrupt acts as the parent interrupt in the GPIO IRQ chip. But when the number of Rx/Tx ring changes, the PCI IRQ vector needs to be reallocated. Then this interrupt controller would be corrupted. So use irq_domain structure to avoid the above problem. Signed-off-by: Jiawen Wu Signed-off-by: David S. Miller --- drivers/net/ethernet/wangxun/libwx/wx_hw.c | 2 - drivers/net/ethernet/wangxun/libwx/wx_lib.c | 20 ++- drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 - .../net/ethernet/wangxun/txgbe/txgbe_irq.c | 132 ++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_irq.h | 2 + .../net/ethernet/wangxun/txgbe/txgbe_main.c | 12 +- .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 59 +++----- .../net/ethernet/wangxun/txgbe/txgbe_phy.h | 2 + .../net/ethernet/wangxun/txgbe/txgbe_type.h | 17 +++ 9 files changed, 193 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c index 1db754615cca..945c13d1a982 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c @@ -1958,8 +1958,6 @@ int wx_sw_init(struct wx *wx) return -ENOMEM; } - wx->msix_in_use = false; - return 0; } EXPORT_SYMBOL(wx_sw_init); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 8706223a6e5a..7cf02ab6de68 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1614,14 +1614,12 @@ static int wx_acquire_msix_vectors(struct wx *wx) /* One for non-queue interrupts */ nvecs += 1; - if (!wx->msix_in_use) { - wx->msix_entry = kcalloc(1, sizeof(struct msix_entry), - GFP_KERNEL); - if (!wx->msix_entry) { - kfree(wx->msix_q_entries); - wx->msix_q_entries = NULL; - return -ENOMEM; - } + wx->msix_entry = kcalloc(1, sizeof(struct msix_entry), + GFP_KERNEL); + if (!wx->msix_entry) { + kfree(wx->msix_q_entries); + wx->msix_q_entries = NULL; + return -ENOMEM; } nvecs = pci_alloc_irq_vectors_affinity(wx->pdev, nvecs, @@ -1931,10 +1929,8 @@ void wx_reset_interrupt_capability(struct wx *wx) if (pdev->msix_enabled) { kfree(wx->msix_q_entries); wx->msix_q_entries = NULL; - if (!wx->msix_in_use) { - kfree(wx->msix_entry); - wx->msix_entry = NULL; - } + kfree(wx->msix_entry); + wx->msix_entry = NULL; } pci_free_irq_vectors(wx->pdev); } diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index b4dc4f341117..1fdeb464d5f4 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -1047,7 +1047,6 @@ struct wx { unsigned int queues_per_pool; struct msix_entry *msix_q_entries; struct msix_entry *msix_entry; - bool msix_in_use; struct wx_ring_feature ring_feature[RING_F_ARRAY_SIZE]; /* misc interrupt status block */ diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c index d26ee4cb1767..b3e3605d1edb 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ +#include #include #include "../libwx/wx_type.h" #include "../libwx/wx_lib.h" #include "../libwx/wx_hw.h" #include "txgbe_type.h" +#include "txgbe_phy.h" #include "txgbe_irq.h" /** @@ -135,3 +137,133 @@ int txgbe_request_irq(struct wx *wx) return err; } + +static int txgbe_request_gpio_irq(struct txgbe *txgbe) +{ + txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); + return request_threaded_irq(txgbe->gpio_irq, NULL, + txgbe_gpio_irq_handler, + IRQF_ONESHOT, "txgbe-gpio-irq", txgbe); +} + +static int txgbe_request_link_irq(struct txgbe *txgbe) +{ + txgbe->link_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); + return request_threaded_irq(txgbe->link_irq, NULL, + txgbe_link_irq_handler, + IRQF_ONESHOT, "txgbe-link-irq", txgbe); +} + +static const struct irq_chip txgbe_irq_chip = { + .name = "txgbe-misc-irq", +}; + +static int txgbe_misc_irq_domain_map(struct irq_domain *d, + unsigned int irq, + irq_hw_number_t hwirq) +{ + struct txgbe *txgbe = d->host_data; + + irq_set_chip_data(irq, txgbe); + irq_set_chip(irq, &txgbe->misc.chip); + irq_set_nested_thread(irq, true); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops txgbe_misc_irq_domain_ops = { + .map = txgbe_misc_irq_domain_map, +}; + +static irqreturn_t txgbe_misc_irq_handle(int irq, void *data) +{ + struct txgbe *txgbe = data; + struct wx *wx = txgbe->wx; + unsigned int nhandled = 0; + unsigned int sub_irq; + u32 eicr; + + eicr = wx_misc_isb(wx, WX_ISB_MISC); + if (eicr & TXGBE_PX_MISC_GPIO) { + sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); + handle_nested_irq(sub_irq); + nhandled++; + } + if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | + TXGBE_PX_MISC_ETH_AN)) { + sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); + handle_nested_irq(sub_irq); + nhandled++; + } + + wx_intr_enable(wx, TXGBE_INTR_MISC); + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static void txgbe_del_irq_domain(struct txgbe *txgbe) +{ + int hwirq, virq; + + for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) { + virq = irq_find_mapping(txgbe->misc.domain, hwirq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(txgbe->misc.domain); +} + +void txgbe_free_misc_irq(struct txgbe *txgbe) +{ + free_irq(txgbe->gpio_irq, txgbe); + free_irq(txgbe->link_irq, txgbe); + free_irq(txgbe->misc.irq, txgbe); + txgbe_del_irq_domain(txgbe); +} + +int txgbe_setup_misc_irq(struct txgbe *txgbe) +{ + struct wx *wx = txgbe->wx; + int hwirq, err; + + txgbe->misc.nirqs = 2; + txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0, + &txgbe_misc_irq_domain_ops, txgbe); + if (!txgbe->misc.domain) + return -ENOMEM; + + for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) + irq_create_mapping(txgbe->misc.domain, hwirq); + + txgbe->misc.chip = txgbe_irq_chip; + if (wx->pdev->msix_enabled) + txgbe->misc.irq = wx->msix_entry->vector; + else + txgbe->misc.irq = wx->pdev->irq; + + err = request_threaded_irq(txgbe->misc.irq, NULL, + txgbe_misc_irq_handle, + IRQF_ONESHOT, + wx->netdev->name, txgbe); + if (err) + goto del_misc_irq; + + err = txgbe_request_gpio_irq(txgbe); + if (err) + goto free_msic_irq; + + err = txgbe_request_link_irq(txgbe); + if (err) + goto free_gpio_irq; + + return 0; + +free_gpio_irq: + free_irq(txgbe->gpio_irq, txgbe); +free_msic_irq: + free_irq(txgbe->misc.irq, txgbe); +del_misc_irq: + txgbe_del_irq_domain(txgbe); + + return err; +} diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h index 02c536421f7d..b77945e7a0f2 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h @@ -3,3 +3,5 @@ void txgbe_irq_enable(struct wx *wx, bool queues); int txgbe_request_irq(struct wx *wx); +void txgbe_free_misc_irq(struct txgbe *txgbe); +int txgbe_setup_misc_irq(struct txgbe *txgbe); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 8cf8c0d016df..e67a21294158 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -392,6 +392,7 @@ static void txgbe_shutdown(struct pci_dev *pdev) int txgbe_setup_tc(struct net_device *dev, u8 tc) { struct wx *wx = netdev_priv(dev); + struct txgbe *txgbe = wx->priv; /* Hardware has to reinitialize queues and interrupts to * match packet buffer alignment. Unfortunately, the @@ -402,6 +403,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc) else txgbe_reset(wx); + txgbe_free_misc_irq(txgbe); wx_clear_interrupt_scheme(wx); if (tc) @@ -410,6 +412,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc) netdev_reset_tc(dev); wx_init_interrupt_scheme(wx); + txgbe_setup_misc_irq(txgbe); if (netif_running(dev)) txgbe_open(dev); @@ -625,10 +628,14 @@ static int txgbe_probe(struct pci_dev *pdev, txgbe->wx = wx; wx->priv = txgbe; - err = txgbe_init_phy(txgbe); + err = txgbe_setup_misc_irq(txgbe); if (err) goto err_release_hw; + err = txgbe_init_phy(txgbe); + if (err) + goto err_free_misc_irq; + err = register_netdev(netdev); if (err) goto err_remove_phy; @@ -655,6 +662,8 @@ static int txgbe_probe(struct pci_dev *pdev, err_remove_phy: txgbe_remove_phy(txgbe); +err_free_misc_irq: + txgbe_free_misc_irq(txgbe); err_release_hw: wx_clear_interrupt_scheme(wx); wx_control_hw(wx, false); @@ -687,6 +696,7 @@ static void txgbe_remove(struct pci_dev *pdev) unregister_netdev(netdev); txgbe_remove_phy(txgbe); + txgbe_free_misc_irq(txgbe); pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 1b84d495d14e..bae0a8ee7014 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -292,6 +292,21 @@ static int txgbe_phylink_init(struct txgbe *txgbe) return 0; } +irqreturn_t txgbe_link_irq_handler(int irq, void *data) +{ + struct txgbe *txgbe = data; + struct wx *wx = txgbe->wx; + u32 status; + bool up; + + status = rd32(wx, TXGBE_CFG_PORT_ST); + up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP); + + phylink_mac_change(wx->phylink, up); + + return IRQ_HANDLED; +} + static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct wx *wx = gpiochip_get_data(chip); @@ -437,7 +452,7 @@ static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type) } static const struct irq_chip txgbe_gpio_irq_chip = { - .name = "txgbe_gpio_irq", + .name = "txgbe-gpio-irq", .irq_ack = txgbe_gpio_irq_ack, .irq_mask = txgbe_gpio_irq_mask, .irq_unmask = txgbe_gpio_irq_unmask, @@ -446,20 +461,14 @@ static const struct irq_chip txgbe_gpio_irq_chip = { GPIOCHIP_IRQ_RESOURCE_HELPERS, }; -static void txgbe_irq_handler(struct irq_desc *desc) +irqreturn_t txgbe_gpio_irq_handler(int irq, void *data) { - struct irq_chip *chip = irq_desc_get_chip(desc); - struct wx *wx = irq_desc_get_handler_data(desc); - struct txgbe *txgbe = wx->priv; + struct txgbe *txgbe = data; + struct wx *wx = txgbe->wx; irq_hw_number_t hwirq; unsigned long gpioirq; struct gpio_chip *gc; unsigned long flags; - u32 eicr; - - eicr = wx_misc_isb(wx, WX_ISB_MISC); - - chained_irq_enter(chip, desc); gpioirq = rd32(wx, WX_GPIO_INTSTATUS); @@ -468,7 +477,7 @@ static void txgbe_irq_handler(struct irq_desc *desc) int gpio = irq_find_mapping(gc->irq.domain, hwirq); u32 irq_type = irq_get_trigger_type(gpio); - generic_handle_domain_irq(gc->irq.domain, hwirq); + handle_nested_irq(gpio); if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { raw_spin_lock_irqsave(&wx->gpio_lock, flags); @@ -477,17 +486,7 @@ static void txgbe_irq_handler(struct irq_desc *desc) } } - chained_irq_exit(chip, desc); - - if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | - TXGBE_PX_MISC_ETH_AN)) { - u32 reg = rd32(wx, TXGBE_CFG_PORT_ST); - - phylink_mac_change(wx->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); - } - - /* unmask interrupt */ - wx_intr_enable(wx, TXGBE_INTR_MISC); + return IRQ_HANDLED; } static int txgbe_gpio_init(struct txgbe *txgbe) @@ -524,19 +523,6 @@ static int txgbe_gpio_init(struct txgbe *txgbe) girq = &gc->irq; gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip); - girq->parent_handler = txgbe_irq_handler; - girq->parent_handler_data = wx; - girq->num_parents = 1; - girq->parents = devm_kcalloc(dev, girq->num_parents, - sizeof(*girq->parents), GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - - /* now only suuported on MSI-X interrupt */ - if (!wx->msix_entry) - return -EPERM; - - girq->parents[0] = wx->msix_entry->vector; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; @@ -754,8 +740,6 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err_unregister_i2c; } - wx->msix_in_use = true; - return 0; err_unregister_i2c: @@ -788,5 +772,4 @@ void txgbe_remove_phy(struct txgbe *txgbe) phylink_destroy(txgbe->wx->phylink); xpcs_destroy(txgbe->xpcs); software_node_unregister_node_group(txgbe->nodes.group); - txgbe->wx->msix_in_use = false; } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h index 1ab592124986..9855d44076cb 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h @@ -4,6 +4,8 @@ #ifndef _TXGBE_PHY_H_ #define _TXGBE_PHY_H_ +irqreturn_t txgbe_gpio_irq_handler(int irq, void *data); +irqreturn_t txgbe_link_irq_handler(int irq, void *data); int txgbe_init_phy(struct txgbe *txgbe); void txgbe_remove_phy(struct txgbe *txgbe); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 270a6fd9ad0b..1b4ff50d5857 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -5,6 +5,7 @@ #define _TXGBE_TYPE_H_ #include +#include /* Device IDs */ #define TXGBE_DEV_ID_SP1000 0x1001 @@ -169,15 +170,31 @@ struct txgbe_nodes { const struct software_node *group[SWNODE_MAX + 1]; }; +enum txgbe_misc_irqs { + TXGBE_IRQ_GPIO = 0, + TXGBE_IRQ_LINK, + TXGBE_IRQ_MAX +}; + +struct txgbe_irq { + struct irq_chip chip; + struct irq_domain *domain; + int nirqs; + int irq; +}; + struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct txgbe_irq misc; struct dw_xpcs *xpcs; struct platform_device *sfp_dev; struct platform_device *i2c_dev; struct clk_lookup *clock; struct clk *clk; struct gpio_chip *gpio; + unsigned int gpio_irq; + unsigned int link_irq; }; #endif /* _TXGBE_TYPE_H_ */ From c57e32fb29f20535bfa8b5ec45285d0bf0370ecd Mon Sep 17 00:00:00 2001 From: Suman Ghosh Date: Wed, 24 Jan 2024 15:23:38 +0530 Subject: [PATCH 0381/2255] octeontx2-af: Add filter profiles in hardware to extract packet headers This patch adds hardware profile supports for extracting packet headers. It makes sure that hardware is capabale of extracting ICMP, CPT, ERSPAN headers. Signed-off-by: Suman Ghosh Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 1 + .../net/ethernet/marvell/octeontx2/af/npc.h | 15 +- .../marvell/octeontx2/af/npc_profile.h | 621 ++++++++++++++++-- .../ethernet/marvell/octeontx2/af/rvu_nix.c | 7 + 4 files changed, 573 insertions(+), 71 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index edeb0f737312..bb8d60e7bab1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1114,6 +1114,7 @@ struct nix_rss_flowkey_cfg { #define NIX_FLOW_KEY_TYPE_INNR_UDP BIT(15) #define NIX_FLOW_KEY_TYPE_INNR_SCTP BIT(16) #define NIX_FLOW_KEY_TYPE_INNR_ETH_DMAC BIT(17) +#define NIX_FLOW_KEY_TYPE_CUSTOM0 BIT(19) #define NIX_FLOW_KEY_TYPE_VLAN BIT(20) #define NIX_FLOW_KEY_TYPE_IPV4_PROTO BIT(21) #define NIX_FLOW_KEY_TYPE_AH BIT(22) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h index b0b4dea548e1..3e6de9d7dde3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h @@ -85,8 +85,7 @@ enum npc_kpu_lc_ltype { enum npc_kpu_ld_ltype { NPC_LT_LD_TCP = 1, NPC_LT_LD_UDP, - NPC_LT_LD_ICMP, - NPC_LT_LD_SCTP, + NPC_LT_LD_SCTP = 4, NPC_LT_LD_ICMP6, NPC_LT_LD_CUSTOM0, NPC_LT_LD_CUSTOM1, @@ -97,6 +96,7 @@ enum npc_kpu_ld_ltype { NPC_LT_LD_NSH, NPC_LT_LD_TU_MPLS_IN_NSH, NPC_LT_LD_TU_MPLS_IN_IP, + NPC_LT_LD_ICMP, }; enum npc_kpu_le_ltype { @@ -140,14 +140,14 @@ enum npc_kpu_lg_ltype { enum npc_kpu_lh_ltype { NPC_LT_LH_TU_TCP = 1, NPC_LT_LH_TU_UDP, - NPC_LT_LH_TU_ICMP, - NPC_LT_LH_TU_SCTP, + NPC_LT_LH_TU_SCTP = 4, NPC_LT_LH_TU_ICMP6, + NPC_LT_LH_CUSTOM0, + NPC_LT_LH_CUSTOM1, NPC_LT_LH_TU_IGMP = 8, NPC_LT_LH_TU_ESP, NPC_LT_LH_TU_AH, - NPC_LT_LH_CUSTOM0 = 0xE, - NPC_LT_LH_CUSTOM1 = 0xF, + NPC_LT_LH_TU_ICMP = 0xF, }; /* NPC port kind defines how the incoming or outgoing packets @@ -155,10 +155,11 @@ enum npc_kpu_lh_ltype { * Software assigns pkind for each incoming port such as CGX * Ethernet interfaces, LBK interfaces, etc. */ -#define NPC_UNRESERVED_PKIND_COUNT NPC_RX_CUSTOM_PRE_L2_PKIND +#define NPC_UNRESERVED_PKIND_COUNT NPC_RX_CPT_HDR_PTP_PKIND enum npc_pkind_type { NPC_RX_LBK_PKIND = 0ULL, + NPC_RX_CPT_HDR_PTP_PKIND = 54ULL, NPC_RX_CUSTOM_PRE_L2_PKIND = 55ULL, NPC_RX_VLAN_EXDSA_PKIND = 56ULL, NPC_RX_CHLEN24B_PKIND = 57ULL, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h index a820bad3abb2..41de72c8607f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h @@ -35,6 +35,7 @@ #define NPC_ETYPE_NSH 0x894f #define NPC_ETYPE_DSA 0xdada #define NPC_ETYPE_PPPOE 0x8864 +#define NPC_ETYPE_ERSPA 0x88be #define NPC_PPP_IP 0x0021 #define NPC_PPP_IP6 0x0057 @@ -59,6 +60,9 @@ #define NPC_IPNH_MPLS 137 #define NPC_IPNH_HOSTID 139 #define NPC_IPNH_SHIM6 140 +#define NPC_IPNH_CUSTOM 253 + +#define NPC_IP6_ROUTE_TYPE 4 #define NPC_UDP_PORT_PTP_E 319 #define NPC_UDP_PORT_PTP_G 320 @@ -187,6 +191,7 @@ enum npc_kpu_parser_state { NPC_S_KPU2_EXDSA, NPC_S_KPU2_CPT_CTAG, NPC_S_KPU2_CPT_QINQ, + NPC_S_KPU2_MT, NPC_S_KPU3_CTAG, NPC_S_KPU3_STAG, NPC_S_KPU3_QINQ, @@ -231,6 +236,7 @@ enum npc_kpu_parser_state { NPC_S_KPU8_ICMP6, NPC_S_KPU8_GRE, NPC_S_KPU8_AH, + NPC_S_KPU8_CUSTOM, NPC_S_KPU9_TU_MPLS_IN_GRE, NPC_S_KPU9_TU_MPLS_IN_NSH, NPC_S_KPU9_TU_MPLS_IN_IP, @@ -242,6 +248,7 @@ enum npc_kpu_parser_state { NPC_S_KPU9_GTPC, NPC_S_KPU9_GTPU, NPC_S_KPU9_ESP, + NPC_S_KPU9_CUSTOM, NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, NPC_S_KPU10_TU_MPLS_PL, NPC_S_KPU10_TU_MPLS, @@ -318,10 +325,10 @@ enum npc_kpu_lc_uflag { NPC_F_LC_U_UNK_PROTO = 0x10, NPC_F_LC_U_IP_FRAG = 0x20, NPC_F_LC_U_IP6_FRAG = 0x40, + NPC_F_LC_L_6TO4 = 0x80, }; enum npc_kpu_lc_lflag { NPC_F_LC_L_IP_IN_IP = 1, - NPC_F_LC_L_6TO4, NPC_F_LC_L_MPLS_IN_IP, NPC_F_LC_L_IP6_TUN_IP6, NPC_F_LC_L_IP6_MPLS_IN_IP, @@ -334,6 +341,8 @@ enum npc_kpu_lc_lflag { NPC_F_LC_L_EXT_MOBILITY, NPC_F_LC_L_EXT_HOSTID, NPC_F_LC_L_EXT_SHIM6, + NPC_F_LC_L_IP6_SRH_SEG_1, + NPC_F_LC_L_IP6_SRH_SEG_2, }; enum npc_kpu_ld_lflag { @@ -970,10 +979,10 @@ static struct npc_kpu_profile_action ikpu_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, 0, 0, - NPC_S_KPU1_ETHER, 0, 0, + NPC_S_KPU1_CPT_HDR, 48, 0, NPC_LID_LA, NPC_LT_NA, 0, - 0, 0, 0, 0, + 0, 7, 0, 0, }, { @@ -2785,6 +2794,24 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU2_MT, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_MT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_NA, 0X00, 0x0000, @@ -4495,6 +4522,24 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ROUT << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + (NPC_IP6_ROUTE_TYPE << 8) | 1, + 0xffff, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ROUT << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + (NPC_IP6_ROUTE_TYPE << 8) | 2, + 0xffff, + }, { NPC_S_KPU5_IP6, 0xff, NPC_IPNH_ROUT << 8, @@ -4774,6 +4819,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU5_CPT_IP, 0xff, + NPC_IPNH_CUSTOM, + 0x00ff, + NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, { NPC_S_KPU5_CPT_IP, 0xff, 0x0000, @@ -4882,6 +4936,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU5_CPT_IP, 0xff, + NPC_IPNH_CUSTOM, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, { NPC_S_KPU5_CPT_IP, 0xff, 0x0000, @@ -5062,6 +5125,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU5_CPT_IP6, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, { NPC_S_KPU5_CPT_IP6, 0xff, 0x0000, @@ -5206,6 +5278,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, { NPC_S_KPU6_IP6_FRAG, 0xff, 0x0000, @@ -5323,6 +5404,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_KPU6_IP6_HOP_DEST, 0xff, 0x0000, @@ -5431,6 +5521,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_KPU6_IP6_ROUT, 0xff, 0x0000, @@ -5530,6 +5629,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU6_IP6_CPT_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_KPU6_IP6_CPT_FRAG, 0xff, 0x0000, @@ -5647,6 +5755,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff, 0x0000, @@ -5755,6 +5872,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU6_IP6_CPT_ROUT, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_KPU6_IP6_CPT_ROUT, 0xff, 0x0000, @@ -5881,6 +6007,15 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_KPU7_IP6_ROUT, 0xff, 0x0000, @@ -5980,6 +6115,15 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, { NPC_S_KPU7_IP6_FRAG, 0xff, 0x0000, @@ -6079,6 +6223,15 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU7_CPT_IP6_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_KPU7_CPT_IP6_FRAG, 0xff, 0x0000, @@ -6304,6 +6457,15 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_ESP, + 0xffff, + 0x0000, + 0x0000, + 0x0009, + 0xffff, + }, { NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_ESP, @@ -6754,6 +6916,78 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM | NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_KEY | NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, { NPC_S_KPU8_GRE, 0xff, 0x0000, @@ -6835,6 +7069,15 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU8_CUSTOM, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_NA, 0X00, 0x0000, @@ -7303,6 +7546,24 @@ static struct npc_kpu_profile_cam kpu9_cam_entries[] = { 0x0000, 0x0000, }, + { + NPC_S_KPU9_CUSTOM, 0xff, + 0x4000, + 0xf000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_CUSTOM, 0xff, + 0x6000, + 0xf000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, { NPC_S_NA, 0X00, 0x0000, @@ -8384,7 +8645,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LA, NPC_LT_LA_ETHER, 0, @@ -8536,7 +8797,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 22, 1, NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, NPC_F_LA_U_HAS_IH_NIX, @@ -8693,7 +8954,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 30, 1, NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, NPC_F_LA_U_HAS_HIGIG2, @@ -8818,7 +9079,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 38, 1, NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, @@ -8947,7 +9208,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 14, 0, NPC_LID_LA, NPC_LT_NA, 0, @@ -9124,7 +9385,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 6, 1, NPC_LID_LB, NPC_LT_LB_CTAG, 0, @@ -9204,7 +9465,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, @@ -9213,7 +9474,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, - NPC_S_NA, 0, 1, + NPC_S_NA, 6, 1, NPC_LID_LB, NPC_LT_LB_CTAG, NPC_F_LB_U_UNK_ETYPE, 0, 0, 0, 0, @@ -9228,7 +9489,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, @@ -9324,7 +9585,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 24, 1, NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG, @@ -9428,7 +9689,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, @@ -9532,7 +9793,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_ETAG, 0, @@ -9628,7 +9889,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 28, 1, NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG, @@ -9684,7 +9945,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -9757,7 +10018,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, - NPC_S_NA, 0, 1, + NPC_S_NA, 8, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, NPC_F_LB_U_UNK_ETYPE, 0, 0, 0, 0, @@ -9772,7 +10033,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 18, 1, NPC_LID_LB, NPC_LT_LB_EDSA, NPC_F_LB_L_EDSA, @@ -9836,7 +10097,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_EXDSA, NPC_F_LB_L_EXDSA, @@ -9922,6 +10183,22 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 0, 0, 0, 0, + NPC_S_KPU3_CTAG, 0, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU3_CTAG_C, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_LB, NPC_EC_L2_K3, 0, 0, 0, 0, 1, @@ -9949,7 +10226,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 6, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10029,7 +10306,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10101,7 +10378,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10165,7 +10442,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10237,7 +10514,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10310,80 +10587,80 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 6, 1, 0, - NPC_S_KPU5_IP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_IP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, - NPC_S_KPU5_IP6, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + 6, 0, 42, 1, 0, + NPC_S_KPU5_IP6, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_ARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_ARP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_RARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_RARP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_PTP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_PTP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_FCOE, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_FCOE, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, 0, 0, - NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU4_MPLS, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, 0, 0, - NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU4_MPLS, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, 0, 0, - NPC_S_KPU4_NSH, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU4_NSH, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, 0, 1, - NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, @@ -10397,7 +10674,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10469,7 +10746,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10533,7 +10810,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10605,7 +10882,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10685,7 +10962,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_DSA, NPC_F_LB_L_DSA, @@ -10733,7 +11010,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LB, NPC_LT_LB_DSA_VLAN, NPC_F_LB_L_DSA_VLAN, @@ -10894,7 +11171,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 6, 1, NPC_LID_LB, NPC_LT_LB_FDSA, NPC_F_LB_L_FDSA, @@ -10942,7 +11219,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_FDSA, NPC_F_LB_L_FDSA, @@ -10990,7 +11267,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, @@ -11014,7 +11291,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 2, 0, NPC_LID_LC, NPC_LT_NA, 0, @@ -11063,15 +11340,15 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 6, 0, 0, - NPC_S_KPU5_IP, 10, 0, + NPC_S_KPU5_IP, 10, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, - NPC_S_KPU5_IP6, 10, 0, + 6, 0, 42, 0, 0, + NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, 0, 0, 0, 0, @@ -11119,7 +11396,7 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 2, 0, 0, 2, 0, + 2, 0, 4, 2, 0, NPC_S_KPU8_UDP, 20, 1, NPC_LID_LC, NPC_LT_LC_IP, 0, @@ -11223,7 +11500,7 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 2, 8, 10, 2, 0, + 2, 8, 4, 2, 0, NPC_S_KPU8_UDP, 0, 1, NPC_LID_LC, NPC_LT_LC_IP_OPT, 0, @@ -11445,6 +11722,22 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { NPC_F_LC_L_EXT_DEST, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU6_IP6_ROUT, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_IP6_SRH_SEG_1, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU6_IP6_ROUT, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_IP6_SRH_SEG_2, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 0, @@ -11693,6 +11986,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { NPC_F_LC_L_MPLS_IN_IP, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_CUSTOM, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -11789,6 +12090,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { NPC_F_LC_L_MPLS_IN_IP, 0, 0xf, 0, 2, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_CUSTOM, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -11949,6 +12258,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { NPC_F_LC_L_EXT_SHIM6, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_CUSTOM, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12078,6 +12395,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { 0, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12182,6 +12507,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { 0, 1, 0xff, 0, 3, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12278,6 +12611,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { 0, 1, 0xff, 0, 3, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12366,6 +12707,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { 0, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12470,6 +12819,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { 0, 1, 0xff, 0, 3, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12566,6 +12923,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { 0, 1, 0xff, 0, 3, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12679,6 +13044,22 @@ static struct npc_kpu_profile_action kpu7_action_entries[] = { 0, 1, 0xff, 0, 3, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -12761,8 +13142,8 @@ static struct npc_kpu_profile_action kpu7_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 0, 0, 0, 0, 1, - NPC_S_NA, 0, 0, + 0, 0, 0, 0, 0, + NPC_S_KPU8_CUSTOM, 8, 0, NPC_LID_LC, NPC_LT_NA, 0, 0, 0, 0, 0, @@ -12855,6 +13236,14 @@ static struct npc_kpu_profile_action kpu7_action_entries[] = { 0, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -13056,6 +13445,14 @@ static struct npc_kpu_profile_action kpu8_action_entries[] = { 0, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 0, @@ -13456,6 +13853,70 @@ static struct npc_kpu_profile_action kpu8_action_entries[] = { NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_SEQ, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 20, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 20, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 20, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 24, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + 0, 0, 0, 0, + }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, @@ -13528,6 +13989,14 @@ static struct npc_kpu_profile_action kpu8_action_entries[] = { 0, 0, 0, 0, 0, }, + { + NPC_ERRLEV_LD, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU9_CUSTOM, 0, 1, + NPC_LID_LF, NPC_LT_LF_CUSTOM0, + 0, + 0, 0xff, 0, 0, + }, { NPC_ERRLEV_LD, NPC_EC_UNK, 0, 0, 0, 0, 1, @@ -13945,6 +14414,22 @@ static struct npc_kpu_profile_action kpu9_action_entries[] = { 0, 0, 0, 0, 0, }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 0, 0, + NPC_LID_LE, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 0, 0, + NPC_LID_LE, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0, 0, 1, @@ -15105,7 +15590,9 @@ static struct npc_lt_def_cfg npc_lt_defaults = { }, .rx_et = { { - .lid = NPC_LID_LB, + .offset = -2, + .valid = 1, + .lid = NPC_LID_LC, .ltype_match = NPC_LT_NA, .ltype_mask = 0x0, }, @@ -15139,6 +15626,12 @@ static struct npc_mcam_kex npc_mkex_default = { /* Ethertype: 2 bytes, KW0[55:40] */ KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, 0x5), }, + [NPC_LT_LA_CPT_HDR] = { + /* DMAC: 6 bytes, KW1[55:8] */ + KEX_LD_CFG(0x05, 0x0, 0x1, 0x0, NPC_KEXOF_DMAC), + /* Ethertype: 2 bytes, KW0[55:40] */ + KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, 0x5), + }, /* Layer A: HiGig2: */ [NPC_LT_LA_HIGIG2_ETHER] = { /* Classification: 2 bytes, KW1[23:8] */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 66203a90f052..febd00c63bf6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -4039,6 +4039,13 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) field->ltype_match = NPC_LT_LE_GTPU; field->ltype_mask = 0xF; break; + case NIX_FLOW_KEY_TYPE_CUSTOM0: + field->lid = NPC_LID_LC; + field->hdr_offset = 6; + field->bytesm1 = 1; /* 2 Bytes*/ + field->ltype_match = NPC_LT_LC_CUSTOM0; + field->ltype_mask = 0xF; + break; case NIX_FLOW_KEY_TYPE_VLAN: field->lid = NPC_LID_LB; field->hdr_offset = 2; /* Skip TPID (2-bytes) */ From 0efc7e541fd51ed11a328c43ccf10a12f1727746 Mon Sep 17 00:00:00 2001 From: Alessandro Marcolini Date: Thu, 25 Jan 2024 17:59:42 +0100 Subject: [PATCH 0382/2255] taprio: validate TCA_TAPRIO_ATTR_FLAGS through policy instead of open-coding As of now, the field TCA_TAPRIO_ATTR_FLAGS is being validated by manually checking its value, using the function taprio_flags_valid(). With this patch, the field will be validated through the netlink policy NLA_POLICY_MASK, where the mask is defined by TAPRIO_SUPPORTED_FLAGS. The mutual exclusivity of the two flags TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD and TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST is still checked manually. Changes since RFC: - fixed reversed xmas tree - use NL_SET_ERR_MSG_MOD() for both invalid configuration Changes since v1: - Changed NL_SET_ERR_MSG_MOD to NL_SET_ERR_MSG_ATTR when wrong flags issued - Changed __u32 to u32 Changes since v2: - Added the missing parameter for NL_SET_ERR_MSG_ATTR (sorry again for the noise) Signed-off-by: Alessandro Marcolini Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/sched/sch_taprio.c | 72 +++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 31a8252bd09c..827cb683efbf 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -40,6 +40,8 @@ static struct static_key_false taprio_have_working_mqprio; #define TXTIME_ASSIST_IS_ENABLED(flags) ((flags) & TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST) #define FULL_OFFLOAD_IS_ENABLED(flags) ((flags) & TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD) +#define TAPRIO_SUPPORTED_FLAGS \ + (TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST | TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD) #define TAPRIO_FLAGS_INVALID U32_MAX struct sched_entry { @@ -408,19 +410,6 @@ static bool is_valid_interval(struct sk_buff *skb, struct Qdisc *sch) return entry; } -static bool taprio_flags_valid(u32 flags) -{ - /* Make sure no other flag bits are set. */ - if (flags & ~(TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST | - TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD)) - return false; - /* txtime-assist and full offload are mutually exclusive */ - if ((flags & TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST) && - (flags & TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD)) - return false; - return true; -} - /* This returns the tstamp value set by TCP in terms of the set clock. */ static ktime_t get_tcp_tstamp(struct taprio_sched *q, struct sk_buff *skb) { @@ -1031,7 +1020,8 @@ static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = { [TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME] = NLA_POLICY_FULL_RANGE_SIGNED(NLA_S64, &taprio_cycle_time_range), [TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION] = { .type = NLA_S64 }, - [TCA_TAPRIO_ATTR_FLAGS] = { .type = NLA_U32 }, + [TCA_TAPRIO_ATTR_FLAGS] = + NLA_POLICY_MASK(NLA_U32, TAPRIO_SUPPORTED_FLAGS), [TCA_TAPRIO_ATTR_TXTIME_DELAY] = { .type = NLA_U32 }, [TCA_TAPRIO_ATTR_TC_ENTRY] = { .type = NLA_NESTED }, }; @@ -1815,33 +1805,6 @@ static int taprio_mqprio_cmp(const struct net_device *dev, return 0; } -/* The semantics of the 'flags' argument in relation to 'change()' - * requests, are interpreted following two rules (which are applied in - * this order): (1) an omitted 'flags' argument is interpreted as - * zero; (2) the 'flags' of a "running" taprio instance cannot be - * changed. - */ -static int taprio_new_flags(const struct nlattr *attr, u32 old, - struct netlink_ext_ack *extack) -{ - u32 new = 0; - - if (attr) - new = nla_get_u32(attr); - - if (old != TAPRIO_FLAGS_INVALID && old != new) { - NL_SET_ERR_MSG_MOD(extack, "Changing 'flags' of a running schedule is not supported"); - return -EOPNOTSUPP; - } - - if (!taprio_flags_valid(new)) { - NL_SET_ERR_MSG_MOD(extack, "Specified 'flags' are not valid"); - return -EINVAL; - } - - return new; -} - static int taprio_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { @@ -1852,6 +1815,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, struct net_device *dev = qdisc_dev(sch); struct tc_mqprio_qopt *mqprio = NULL; unsigned long flags; + u32 taprio_flags; ktime_t start; int i, err; @@ -1863,12 +1827,28 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, if (tb[TCA_TAPRIO_ATTR_PRIOMAP]) mqprio = nla_data(tb[TCA_TAPRIO_ATTR_PRIOMAP]); - err = taprio_new_flags(tb[TCA_TAPRIO_ATTR_FLAGS], - q->flags, extack); - if (err < 0) - return err; + /* The semantics of the 'flags' argument in relation to 'change()' + * requests, are interpreted following two rules (which are applied in + * this order): (1) an omitted 'flags' argument is interpreted as + * zero; (2) the 'flags' of a "running" taprio instance cannot be + * changed. + */ + taprio_flags = tb[TCA_TAPRIO_ATTR_FLAGS] ? nla_get_u32(tb[TCA_TAPRIO_ATTR_FLAGS]) : 0; - q->flags = err; + /* txtime-assist and full offload are mutually exclusive */ + if ((taprio_flags & TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST) && + (taprio_flags & TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD)) { + NL_SET_ERR_MSG_ATTR(extack, tb[TCA_TAPRIO_ATTR_FLAGS], + "TXTIME_ASSIST and FULL_OFFLOAD are mutually exclusive"); + return -EINVAL; + } + + if (q->flags != TAPRIO_FLAGS_INVALID && q->flags != taprio_flags) { + NL_SET_ERR_MSG_MOD(extack, + "Changing 'flags' of a running schedule is not supported"); + return -EOPNOTSUPP; + } + q->flags = taprio_flags; err = taprio_parse_mqprio_opt(dev, mqprio, extack, q->flags); if (err < 0) From dec836ed69d1d3641ea881671fa2ac6ec6b9dc3d Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:11 -0800 Subject: [PATCH 0383/2255] net: fill in MODULE_DESCRIPTION()s for encx24j600 W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the Microchip ENCX24J600 helpers driver. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/encx24j600-regmap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c index 5693784eec5b..2e0fe16a4082 100644 --- a/drivers/net/ethernet/microchip/encx24j600-regmap.c +++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c @@ -513,4 +513,5 @@ int devm_regmap_init_encx24j600(struct device *dev, } EXPORT_SYMBOL_GPL(devm_regmap_init_encx24j600); +MODULE_DESCRIPTION("Microchip ENCX24J600 helpers"); MODULE_LICENSE("GPL"); From 1c870c63d7d2474646472b13ac3d4a75d5aec368 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:12 -0800 Subject: [PATCH 0384/2255] net: fill in MODULE_DESCRIPTION()s for ocelot W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the Ocelot SoCs (VSC7514) helpers driver. Signed-off-by: Breno Leitao Reviewed-by: Horatiu Vultur Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 56ccbd4c37fe..2194f2a7ab27 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -3078,4 +3078,5 @@ void ocelot_deinit_port(struct ocelot *ocelot, int port) } EXPORT_SYMBOL(ocelot_deinit_port); +MODULE_DESCRIPTION("Microsemi Ocelot (VSC7514) Switch driver"); MODULE_LICENSE("Dual MIT/GPL"); From 9ba4295b2eab99fa0a1768432b5e54e214d47310 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:13 -0800 Subject: [PATCH 0385/2255] net: fill in MODULE_DESCRIPTION()s for SMSC drivers W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the SMSC 91x/911x/9420 Ethernet drivers. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smc91x.c | 1 + drivers/net/ethernet/smsc/smsc911x.c | 1 + drivers/net/ethernet/smsc/smsc9420.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 758347616535..78ff3af7911a 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -98,6 +98,7 @@ static int watchdog = 1000; module_param(watchdog, int, 0400); MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); +MODULE_DESCRIPTION("SMC 91C9x/91C1xxx Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:smc91x"); diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 31cb7d0166f0..74f1ccc96459 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -56,6 +56,7 @@ #define SMSC_MDIONAME "smsc911x-mdio" #define SMSC_DRV_VERSION "2008-10-21" +MODULE_DESCRIPTION("SMSC LAN911x/LAN921x Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(SMSC_DRV_VERSION); MODULE_ALIAS("platform:smsc911x"); diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index e1c4a11c1f18..15cb96c2506d 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -26,6 +26,7 @@ #define DRV_DESCRIPTION "SMSC LAN9420 driver" #define DRV_VERSION "1.01" +MODULE_DESCRIPTION("SMSC LAN9420 Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); From 66c164633bb04f00d920415b6f8b14c749c06a9d Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:14 -0800 Subject: [PATCH 0386/2255] net: fill in MODULE_DESCRIPTION()s for Qualcom drivers W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the Qualcom rmnet and emac drivers. Signed-off-by: Breno Leitao Reviewed-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac.c | 1 + drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 3270df72541b..4c06f55878de 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -771,5 +771,6 @@ static struct platform_driver emac_platform_driver = { module_platform_driver(emac_platform_driver); +MODULE_DESCRIPTION("Qualcomm EMAC Gigabit Ethernet driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:qcom-emac"); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 5b69b9268c75..f3bea196a8f9 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -520,4 +520,5 @@ static void __exit rmnet_exit(void) module_init(rmnet_init) module_exit(rmnet_exit) MODULE_ALIAS_RTNL_LINK("rmnet"); +MODULE_DESCRIPTION("Qualcomm RmNet MAP driver"); MODULE_LICENSE("GPL v2"); From 23f487f70c73e31e72ecc0293ee3657da6c67425 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:15 -0800 Subject: [PATCH 0387/2255] net: fill in MODULE_DESCRIPTION()s for dwmac-socfpga W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the STMicro DWMAC for Altera SOCs. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index ba2ce776bd4d..68f85e4605cb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -585,4 +585,5 @@ static struct platform_driver socfpga_dwmac_driver = { }; module_platform_driver(socfpga_dwmac_driver); +MODULE_DESCRIPTION("Altera SOC DWMAC Specific Glue layer"); MODULE_LICENSE("GPL v2"); From 3e4620c891480e2058b0fb6dd1d1bbcd90aba72a Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:16 -0800 Subject: [PATCH 0388/2255] net: fill in MODULE_DESCRIPTION()s for cpsw-common W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the TI CPSW switch module. Signed-off-by: Breno Leitao Reviewed-by: Roger Quadros Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c index 26dc906eae90..57fe936bb177 100644 --- a/drivers/net/ethernet/ti/cpsw-common.c +++ b/drivers/net/ethernet/ti/cpsw-common.c @@ -90,4 +90,5 @@ int ti_cm_get_macid(struct device *dev, int slave, u8 *mac_addr) } EXPORT_SYMBOL_GPL(ti_cm_get_macid); +MODULE_DESCRIPTION("TI CPSW Switch common module"); MODULE_LICENSE("GPL"); From ad979679d64befabd9bdfa0756aefd8c4a34fd91 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:17 -0800 Subject: [PATCH 0389/2255] net: fill in MODULE_DESCRIPTION()s for ec_bhf W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the Beckhoff CX5020 EtherCAT Ethernet driver. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/ethernet/ec_bhf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c index c2c5c589a5e3..44af1d13d931 100644 --- a/drivers/net/ethernet/ec_bhf.c +++ b/drivers/net/ethernet/ec_bhf.c @@ -590,5 +590,6 @@ module_pci_driver(pci_driver); module_param(polling_frequency, long, 0444); MODULE_PARM_DESC(polling_frequency, "Polling timer frequency in ns"); +MODULE_DESCRIPTION("Beckhoff CX5020 EtherCAT Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dariusz Marcinkiewicz "); From be884c15de370804238f5801afb545a71b5af658 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:18 -0800 Subject: [PATCH 0390/2255] net: fill in MODULE_DESCRIPTION()s for PCS drivers W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to the Lynx, XPCS and LynxI PCS drivers. Signed-off-by: Breno Leitao Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-lynx.c | 1 + drivers/net/pcs/pcs-mtk-lynxi.c | 1 + drivers/net/pcs/pcs-xpcs.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index dc3962b2aa6b..853b8c138718 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -398,4 +398,5 @@ void lynx_pcs_destroy(struct phylink_pcs *pcs) } EXPORT_SYMBOL(lynx_pcs_destroy); +MODULE_DESCRIPTION("NXP Lynx PCS phylink library"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 8501dd365279..4f63abe638c4 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -303,4 +303,5 @@ void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs) } EXPORT_SYMBOL(mtk_pcs_lynxi_destroy); +MODULE_DESCRIPTION("MediaTek SGMII library for LynxI"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 31f0beba638a..52a7757ee419 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -1456,4 +1456,5 @@ struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, } EXPORT_SYMBOL_GPL(xpcs_create_mdiodev); +MODULE_DESCRIPTION("Synopsys DesignWare XPCS library"); MODULE_LICENSE("GPL v2"); From 6aa89bf8ac9a1f5e420c0f00bdc0101994544736 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:19 -0800 Subject: [PATCH 0391/2255] net: fill in MODULE_DESCRIPTION()s for ieee802154 W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to ieee802154 modules. Signed-off-by: Breno Leitao Acked-by: Miquel Raynal Acked-by: Stefan Schmidt Signed-off-by: David S. Miller --- net/ieee802154/6lowpan/core.c | 1 + net/ieee802154/socket.c | 1 + 2 files changed, 2 insertions(+) diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index 2c087b7f17c5..e643f52663f9 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -280,5 +280,6 @@ static void __exit lowpan_cleanup_module(void) module_init(lowpan_init_module); module_exit(lowpan_cleanup_module); +MODULE_DESCRIPTION("IPv6 over Low power Wireless Personal Area Network IEEE 802.15.4 core"); MODULE_LICENSE("GPL"); MODULE_ALIAS_RTNL_LINK("lowpan"); diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index 00302e8b9615..990a83455dcf 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -1137,4 +1137,5 @@ module_init(af_ieee802154_init); module_exit(af_ieee802154_remove); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IEEE 802.15.4 socket interface"); MODULE_ALIAS_NETPROTO(PF_IEEE802154); From d06aa0eb0a7052b580fc06c16e30e5df872d4b7c Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 25 Jan 2024 11:34:20 -0800 Subject: [PATCH 0392/2255] net: fill in MODULE_DESCRIPTION()s for arcnet W=1 builds now warn if module is built without a MODULE_DESCRIPTION(). Add descriptions to arcnet module. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/arcnet/arcnet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index d9e052c49ba1..166bfc3c8e6c 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -108,6 +108,7 @@ static int go_tx(struct net_device *dev); static int debug = ARCNET_DEBUG; module_param(debug, int, 0); +MODULE_DESCRIPTION("ARCnet core driver"); MODULE_LICENSE("GPL"); static int __init arcnet_init(void) From ea1cc3ee34a5f3144f6c2cdc07c19c914ccb9526 Mon Sep 17 00:00:00 2001 From: Min Li Date: Wed, 24 Jan 2024 13:49:46 -0500 Subject: [PATCH 0393/2255] ptp: introduce PTP_CLOCK_EXTOFF event for the measured external offset This change is for the PHC devices that can measure the phase offset between PHC signal and the external signal, such as the 1PPS signal of GNSS. Reporting PTP_CLOCK_EXTOFF to user space will be piggy-backed to the existing ptp_extts_event so that application such as ts2phc can poll the external offset the same way as extts. Hence, ts2phc can use the offset to achieve the alignment between PHC and the external signal by the help of either SW or HW filters. Signed-off-by: Min Li Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/ptp/ptp_clock.c | 16 +++++++++++++++- include/linux/ptp_clock_kernel.h | 3 +++ include/uapi/linux/ptp_clock.h | 13 ++++++++++--- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 15b804ba4868..3aaf1a3430c5 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -44,18 +44,31 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue, struct ptp_clock_event *src) { struct ptp_extts_event *dst; + struct timespec64 offset_ts; unsigned long flags; s64 seconds; u32 remainder; - seconds = div_u64_rem(src->timestamp, 1000000000, &remainder); + if (src->type == PTP_CLOCK_EXTTS) { + seconds = div_u64_rem(src->timestamp, 1000000000, &remainder); + } else if (src->type == PTP_CLOCK_EXTOFF) { + offset_ts = ns_to_timespec64(src->offset); + seconds = offset_ts.tv_sec; + remainder = offset_ts.tv_nsec; + } else { + WARN(1, "%s: unknown type %d\n", __func__, src->type); + return; + } spin_lock_irqsave(&queue->lock, flags); dst = &queue->buf[queue->tail]; dst->index = src->index; + dst->flags = PTP_EXTTS_EVENT_VALID; dst->t.sec = seconds; dst->t.nsec = remainder; + if (src->type == PTP_CLOCK_EXTOFF) + dst->flags |= PTP_EXT_OFFSET; /* Both WRITE_ONCE() are paired with READ_ONCE() in queue_cnt() */ if (!queue_free(queue)) @@ -417,6 +430,7 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) break; case PTP_CLOCK_EXTTS: + case PTP_CLOCK_EXTOFF: /* Enqueue timestamp on selected queues */ spin_lock_irqsave(&ptp->tsevqs_lock, flags); list_for_each_entry(tsevq, &ptp->tsevqs, qlist) { diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h index 1ef4e0f9bd2a..6e4b8206c7d0 100644 --- a/include/linux/ptp_clock_kernel.h +++ b/include/linux/ptp_clock_kernel.h @@ -200,6 +200,7 @@ struct ptp_clock; enum ptp_clock_events { PTP_CLOCK_ALARM, PTP_CLOCK_EXTTS, + PTP_CLOCK_EXTOFF, PTP_CLOCK_PPS, PTP_CLOCK_PPSUSR, }; @@ -210,6 +211,7 @@ enum ptp_clock_events { * @type: One of the ptp_clock_events enumeration values. * @index: Identifies the source of the event. * @timestamp: When the event occurred (%PTP_CLOCK_EXTTS only). + * @offset: When the event occurred (%PTP_CLOCK_EXTOFF only). * @pps_times: When the event occurred (%PTP_CLOCK_PPSUSR only). */ @@ -218,6 +220,7 @@ struct ptp_clock_event { int index; union { u64 timestamp; + s64 offset; struct pps_event_time pps_times; }; }; diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h index da700999cad4..053b40d642de 100644 --- a/include/uapi/linux/ptp_clock.h +++ b/include/uapi/linux/ptp_clock.h @@ -32,6 +32,7 @@ #define PTP_RISING_EDGE (1<<1) #define PTP_FALLING_EDGE (1<<2) #define PTP_STRICT_FLAGS (1<<3) +#define PTP_EXT_OFFSET (1<<4) #define PTP_EXTTS_EDGES (PTP_RISING_EDGE | PTP_FALLING_EDGE) /* @@ -40,7 +41,8 @@ #define PTP_EXTTS_VALID_FLAGS (PTP_ENABLE_FEATURE | \ PTP_RISING_EDGE | \ PTP_FALLING_EDGE | \ - PTP_STRICT_FLAGS) + PTP_STRICT_FLAGS | \ + PTP_EXT_OFFSET) /* * flag fields valid for the original PTP_EXTTS_REQUEST ioctl. @@ -50,6 +52,11 @@ PTP_RISING_EDGE | \ PTP_FALLING_EDGE) +/* + * flag fields valid for the ptp_extts_event report. + */ +#define PTP_EXTTS_EVENT_VALID (PTP_ENABLE_FEATURE) + /* * Bits of the ptp_perout_request.flags field: */ @@ -228,9 +235,9 @@ struct ptp_pin_desc { #define PTP_MASK_EN_SINGLE _IOW(PTP_CLK_MAGIC, 20, unsigned int) struct ptp_extts_event { - struct ptp_clock_time t; /* Time event occured. */ + struct ptp_clock_time t; /* Time event occurred. */ unsigned int index; /* Which channel produced the event. */ - unsigned int flags; /* Reserved for future use. */ + unsigned int flags; /* Event type. */ unsigned int rsv[2]; /* Reserved for future use. */ }; From 1ddfecafabf71e0e5345dff877d2680083c7e078 Mon Sep 17 00:00:00 2001 From: Min Li Date: Wed, 24 Jan 2024 13:49:47 -0500 Subject: [PATCH 0394/2255] ptp: add FemtoClock3 Wireless as ptp hardware clock The RENESAS FemtoClock3 Wireless is a high-performance jitter attenuator, frequency translator, and clock synthesizer. The device is comprised of 3 digital PLLs (DPLL) to track CLKIN inputs and three independent low phase noise fractional output dividers (FOD) that output low phase noise clocks. FemtoClock3 supports one Time Synchronization (Time Sync) channel to enable an external processor to control the phase and frequency of the Time Sync channel and to take phase measurements using the TDC. Intended applications are synchronization using the precision time protocol (PTP) and synchronization with 0.5 Hz and 1 Hz signals from GNSS. Signed-off-by: Min Li Acked-by: Lee Jones Signed-off-by: David S. Miller --- drivers/ptp/Kconfig | 12 + drivers/ptp/Makefile | 1 + drivers/ptp/ptp_fc3.c | 1016 ++++++++++++++++++++++++++++ drivers/ptp/ptp_fc3.h | 45 ++ include/linux/mfd/idtRC38xxx_reg.h | 273 ++++++++ 5 files changed, 1347 insertions(+) create mode 100644 drivers/ptp/ptp_fc3.c create mode 100644 drivers/ptp/ptp_fc3.h create mode 100644 include/linux/mfd/idtRC38xxx_reg.h diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 5dd5f188e14f..604541dcb320 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -155,6 +155,18 @@ config PTP_1588_CLOCK_IDTCM To compile this driver as a module, choose M here: the module will be called ptp_clockmatrix. +config PTP_1588_CLOCK_FC3W + tristate "RENESAS FemtoClock3 Wireless as PTP clock" + depends on PTP_1588_CLOCK && I2C + default n + help + This driver adds support for using Renesas FemtoClock3 Wireless + as a PTP clock. This clock is only useful if your time stamping + MAC is connected to the RENESAS chip. + + To compile this driver as a module, choose M here: the module + will be called ptp_fc3. + config PTP_1588_CLOCK_MOCK tristate "Mock-up PTP clock" depends on PTP_1588_CLOCK diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index dea0cebd2303..68bf02078053 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp-qoriq.o ptp-qoriq-y += ptp_qoriq.o ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o obj-$(CONFIG_PTP_1588_CLOCK_IDTCM) += ptp_clockmatrix.o +obj-$(CONFIG_PTP_1588_CLOCK_FC3W) += ptp_fc3.o obj-$(CONFIG_PTP_1588_CLOCK_IDT82P33) += ptp_idt82p33.o obj-$(CONFIG_PTP_1588_CLOCK_MOCK) += ptp_mock.o obj-$(CONFIG_PTP_1588_CLOCK_VMW) += ptp_vmw.o diff --git a/drivers/ptp/ptp_fc3.c b/drivers/ptp/ptp_fc3.c new file mode 100644 index 000000000000..0e2286ba088a --- /dev/null +++ b/drivers/ptp/ptp_fc3.c @@ -0,0 +1,1016 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PTP hardware clock driver for the FemtoClock3 family of timing and + * synchronization devices. + * + * Copyright (C) 2023 Integrated Device Technology, Inc., a Renesas Company. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ptp_private.h" +#include "ptp_fc3.h" + +MODULE_DESCRIPTION("Driver for IDT FemtoClock3(TM) family"); +MODULE_AUTHOR("IDT support-1588 "); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +/* + * The name of the firmware file to be loaded + * over-rides any automatic selection + */ +static char *firmware; +module_param(firmware, charp, 0); + +static s64 ns2counters(struct idtfc3 *idtfc3, s64 nsec, u32 *sub_ns) +{ + s64 sync; + s32 rem; + + if (likely(nsec >= 0)) { + sync = div_u64_rem(nsec, idtfc3->ns_per_sync, &rem); + *sub_ns = rem; + } else { + sync = -div_u64_rem(-nsec - 1, idtfc3->ns_per_sync, &rem) - 1; + *sub_ns = idtfc3->ns_per_sync - rem - 1; + } + + return sync * idtfc3->ns_per_sync; +} + +static s64 tdc_meas2offset(struct idtfc3 *idtfc3, u64 meas_read) +{ + s64 coarse, fine; + + fine = sign_extend64(FIELD_GET(FINE_MEAS_MASK, meas_read), 12); + coarse = sign_extend64(FIELD_GET(COARSE_MEAS_MASK, meas_read), (39 - 13)); + + fine = div64_s64(fine * NSEC_PER_SEC, idtfc3->tdc_apll_freq * 62LL); + coarse = div64_s64(coarse * NSEC_PER_SEC, idtfc3->time_ref_freq); + + return coarse + fine; +} + +static s64 tdc_offset2phase(struct idtfc3 *idtfc3, s64 offset_ns) +{ + if (offset_ns > idtfc3->ns_per_sync / 2) + offset_ns -= idtfc3->ns_per_sync; + + return offset_ns * idtfc3->tdc_offset_sign; +} + +static int idtfc3_set_lpf_mode(struct idtfc3 *idtfc3, u8 mode) +{ + int err; + + if (mode >= LPF_INVALID) + return -EINVAL; + + if (idtfc3->lpf_mode == mode) + return 0; + + err = regmap_bulk_write(idtfc3->regmap, LPF_MODE_CNFG, &mode, sizeof(mode)); + if (err) + return err; + + idtfc3->lpf_mode = mode; + + return 0; +} + +static int idtfc3_enable_lpf(struct idtfc3 *idtfc3, bool enable) +{ + u8 val; + int err; + + err = regmap_bulk_read(idtfc3->regmap, LPF_CTRL, &val, sizeof(val)); + if (err) + return err; + + if (enable == true) + val |= LPF_EN; + else + val &= ~LPF_EN; + + return regmap_bulk_write(idtfc3->regmap, LPF_CTRL, &val, sizeof(val)); +} + +static int idtfc3_get_time_ref_freq(struct idtfc3 *idtfc3) +{ + int err; + u8 buf[4]; + u8 time_ref_div; + u8 time_clk_div; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_MEAS_DIV_CNFG, buf, sizeof(buf)); + if (err) + return err; + time_ref_div = FIELD_GET(TIME_REF_DIV_MASK, get_unaligned_le32(buf)) + 1; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_COUNT, buf, 1); + if (err) + return err; + time_clk_div = (buf[0] & TIME_CLOCK_COUNT_MASK) + 1; + idtfc3->time_ref_freq = idtfc3->hw_param.time_clk_freq * + time_clk_div / time_ref_div; + + return 0; +} + +static int idtfc3_get_tdc_offset_sign(struct idtfc3 *idtfc3) +{ + int err; + u8 buf[4]; + u32 val; + u8 sig1, sig2; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_TDC_FANOUT_CNFG, buf, sizeof(buf)); + if (err) + return err; + + val = get_unaligned_le32(buf); + if ((val & TIME_SYNC_TO_TDC_EN) != TIME_SYNC_TO_TDC_EN) { + dev_err(idtfc3->dev, "TIME_SYNC_TO_TDC_EN is off !!!"); + return -EINVAL; + } + + sig1 = FIELD_GET(SIG1_MUX_SEL_MASK, val); + sig2 = FIELD_GET(SIG2_MUX_SEL_MASK, val); + + if ((sig1 == sig2) || ((sig1 != TIME_SYNC) && (sig2 != TIME_SYNC))) { + dev_err(idtfc3->dev, "Invalid tdc_mux_sel sig1=%d sig2=%d", sig1, sig2); + return -EINVAL; + } else if (sig1 == TIME_SYNC) { + idtfc3->tdc_offset_sign = 1; + } else if (sig2 == TIME_SYNC) { + idtfc3->tdc_offset_sign = -1; + } + + return 0; +} + +static int idtfc3_lpf_bw(struct idtfc3 *idtfc3, u8 shift, u8 mult) +{ + u8 val = FIELD_PREP(LPF_BW_SHIFT, shift) | FIELD_PREP(LPF_BW_MULT, mult); + + return regmap_bulk_write(idtfc3->regmap, LPF_BW_CNFG, &val, sizeof(val)); +} + +static int idtfc3_enable_tdc(struct idtfc3 *idtfc3, bool enable, u8 meas_mode) +{ + int err; + u8 val = 0; + + /* Disable TDC first */ + err = regmap_bulk_write(idtfc3->regmap, TIME_CLOCK_MEAS_CTRL, &val, sizeof(val)); + if (err) + return err; + + if (enable == false) + return idtfc3_lpf_bw(idtfc3, LPF_BW_SHIFT_DEFAULT, LPF_BW_MULT_DEFAULT); + + if (meas_mode >= MEAS_MODE_INVALID) + return -EINVAL; + + /* Change TDC meas mode */ + err = regmap_bulk_write(idtfc3->regmap, TIME_CLOCK_MEAS_CNFG, + &meas_mode, sizeof(meas_mode)); + if (err) + return err; + + /* Enable TDC */ + val = TDC_MEAS_EN; + if (meas_mode == CONTINUOUS) + val |= TDC_MEAS_START; + err = regmap_bulk_write(idtfc3->regmap, TIME_CLOCK_MEAS_CTRL, &val, sizeof(val)); + if (err) + return err; + + return idtfc3_lpf_bw(idtfc3, LPF_BW_SHIFT_1PPS, LPF_BW_MULT_DEFAULT); +} + +static bool get_tdc_meas(struct idtfc3 *idtfc3, s64 *offset_ns) +{ + bool valid = false; + u8 buf[9]; + u8 val; + int err; + + while (true) { + err = regmap_bulk_read(idtfc3->regmap, TDC_FIFO_STS, + &val, sizeof(val)); + if (err) + return false; + + if (val & FIFO_EMPTY) + break; + + err = regmap_bulk_read(idtfc3->regmap, TDC_FIFO_READ_REQ, + &buf, sizeof(buf)); + if (err) + return false; + + valid = true; + } + + if (valid) + *offset_ns = tdc_meas2offset(idtfc3, get_unaligned_le64(&buf[1])); + + return valid; +} + +static int check_tdc_fifo_overrun(struct idtfc3 *idtfc3) +{ + u8 val; + int err; + + /* Check if FIFO is overrun */ + err = regmap_bulk_read(idtfc3->regmap, TDC_FIFO_STS, &val, sizeof(val)); + if (err) + return err; + + if (!(val & FIFO_FULL)) + return 0; + + dev_warn(idtfc3->dev, "TDC FIFO overrun !!!"); + + err = idtfc3_enable_tdc(idtfc3, true, CONTINUOUS); + if (err) + return err; + + return 0; +} + +static int get_tdc_meas_continuous(struct idtfc3 *idtfc3) +{ + int err; + s64 offset_ns; + struct ptp_clock_event event; + + err = check_tdc_fifo_overrun(idtfc3); + if (err) + return err; + + if (get_tdc_meas(idtfc3, &offset_ns) && offset_ns >= 0) { + event.index = 0; + event.offset = tdc_offset2phase(idtfc3, offset_ns); + event.type = PTP_CLOCK_EXTOFF; + ptp_clock_event(idtfc3->ptp_clock, &event); + } + + return 0; +} + +static int idtfc3_read_subcounter(struct idtfc3 *idtfc3) +{ + u8 buf[5] = {0}; + int err; + + err = regmap_bulk_read(idtfc3->regmap, TOD_COUNTER_READ_REQ, + &buf, sizeof(buf)); + if (err) + return err; + + /* sync_counter_value is [31:82] and sub_sync_counter_value is [0:30] */ + return get_unaligned_le32(&buf[1]) & SUB_SYNC_COUNTER_MASK; +} + +static int idtfc3_tod_update_is_done(struct idtfc3 *idtfc3) +{ + int err; + u8 req; + + err = read_poll_timeout_atomic(regmap_bulk_read, err, !req, USEC_PER_MSEC, + idtfc3->tc_write_timeout, true, idtfc3->regmap, + TOD_SYNC_LOAD_REQ_CTRL, &req, 1); + if (err) + dev_err(idtfc3->dev, "TOD counter write timeout !!!"); + + return err; +} + +static int idtfc3_write_subcounter(struct idtfc3 *idtfc3, u32 counter) +{ + u8 buf[18] = {0}; + int err; + + /* sync_counter_value is [31:82] and sub_sync_counter_value is [0:30] */ + put_unaligned_le32(counter & SUB_SYNC_COUNTER_MASK, &buf[0]); + + buf[16] = SUB_SYNC_LOAD_ENABLE | SYNC_LOAD_ENABLE; + buf[17] = SYNC_LOAD_REQ; + + err = regmap_bulk_write(idtfc3->regmap, TOD_SYNC_LOAD_VAL_CTRL, + &buf, sizeof(buf)); + if (err) + return err; + + return idtfc3_tod_update_is_done(idtfc3); +} + +static int idtfc3_timecounter_update(struct idtfc3 *idtfc3, u32 counter, s64 ns) +{ + int err; + + err = idtfc3_write_subcounter(idtfc3, counter); + if (err) + return err; + + /* Update time counter */ + idtfc3->ns = ns; + idtfc3->last_counter = counter; + + return 0; +} + +static int idtfc3_timecounter_read(struct idtfc3 *idtfc3) +{ + int now, delta; + + now = idtfc3_read_subcounter(idtfc3); + if (now < 0) + return now; + + /* calculate the delta since the last idtfc3_timecounter_read(): */ + if (now >= idtfc3->last_counter) + delta = now - idtfc3->last_counter; + else + delta = idtfc3->sub_sync_count - idtfc3->last_counter + now; + + /* Update time counter */ + idtfc3->ns += delta * idtfc3->ns_per_counter; + idtfc3->last_counter = now; + + return 0; +} + +static int _idtfc3_gettime(struct idtfc3 *idtfc3, struct timespec64 *ts) +{ + int err; + + err = idtfc3_timecounter_read(idtfc3); + if (err) + return err; + + *ts = ns_to_timespec64(idtfc3->ns); + + return 0; +} + +static int idtfc3_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_gettime(idtfc3, ts); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_settime(struct idtfc3 *idtfc3, const struct timespec64 *ts) +{ + s64 offset_ns, now_ns; + u32 counter, sub_ns; + int now; + + if (timespec64_valid(ts) == false) { + dev_err(idtfc3->dev, "%s: invalid timespec", __func__); + return -EINVAL; + } + + now = idtfc3_read_subcounter(idtfc3); + if (now < 0) + return now; + + offset_ns = (idtfc3->sub_sync_count - now) * idtfc3->ns_per_counter; + now_ns = timespec64_to_ns(ts); + (void)ns2counters(idtfc3, offset_ns + now_ns, &sub_ns); + + counter = sub_ns / idtfc3->ns_per_counter; + return idtfc3_timecounter_update(idtfc3, counter, now_ns); +} + +static int idtfc3_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_settime(idtfc3, ts); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_adjtime(struct idtfc3 *idtfc3, s64 delta) +{ + /* + * The TOD counter can be synchronously loaded with any value, + * to be loaded on the next Time Sync pulse + */ + s64 sync_ns; + u32 sub_ns; + u32 counter; + + if (idtfc3->ns + delta < 0) { + dev_err(idtfc3->dev, "%lld ns adj is too large", delta); + return -EINVAL; + } + + sync_ns = ns2counters(idtfc3, delta + idtfc3->ns_per_sync, &sub_ns); + + counter = sub_ns / idtfc3->ns_per_counter; + return idtfc3_timecounter_update(idtfc3, counter, idtfc3->ns + sync_ns + + counter * idtfc3->ns_per_counter); +} + +static int idtfc3_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_adjtime(idtfc3, delta); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_adjphase(struct idtfc3 *idtfc3, s32 delta) +{ + u8 buf[8] = {0}; + int err; + s64 pcw; + + err = idtfc3_set_lpf_mode(idtfc3, LPF_WP); + if (err) + return err; + + /* + * Phase Control Word unit is: 10^9 / (TDC_APLL_FREQ * 124) + * + * delta * TDC_APLL_FREQ * 124 + * PCW = --------------------------- + * 10^9 + * + */ + pcw = div_s64((s64)delta * idtfc3->tdc_apll_freq * 124, NSEC_PER_SEC); + + put_unaligned_le64(pcw, buf); + + return regmap_bulk_write(idtfc3->regmap, LPF_WR_PHASE_CTRL, buf, sizeof(buf)); +} + +static int idtfc3_adjphase(struct ptp_clock_info *ptp, s32 delta) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_adjphase(idtfc3, delta); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_adjfine(struct idtfc3 *idtfc3, long scaled_ppm) +{ + u8 buf[8] = {0}; + int err; + s64 fcw; + + err = idtfc3_set_lpf_mode(idtfc3, LPF_WF); + if (err) + return err; + + /* + * Frequency Control Word unit is: 2^-44 * 10^6 ppm + * + * adjfreq: + * ppb * 2^44 + * FCW = ---------- + * 10^9 + * + * adjfine: + * ppm_16 * 2^28 + * FCW = ------------- + * 10^6 + */ + fcw = scaled_ppm * BIT(28); + fcw = div_s64(fcw, 1000000); + + put_unaligned_le64(fcw, buf); + + return regmap_bulk_write(idtfc3->regmap, LPF_WR_FREQ_CTRL, buf, sizeof(buf)); +} + +static int idtfc3_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_adjfine(idtfc3, scaled_ppm); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int idtfc3_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err = -EOPNOTSUPP; + + mutex_lock(idtfc3->lock); + switch (rq->type) { + case PTP_CLK_REQ_PEROUT: + if (!on) + err = 0; + /* Only accept a 1-PPS aligned to the second. */ + else if (rq->perout.start.nsec || rq->perout.period.sec != 1 || + rq->perout.period.nsec) + err = -ERANGE; + else + err = 0; + break; + case PTP_CLK_REQ_EXTTS: + if (on) { + /* Only accept requests for external phase offset */ + if ((rq->extts.flags & PTP_EXT_OFFSET) != (PTP_EXT_OFFSET)) + err = -EOPNOTSUPP; + else + err = idtfc3_enable_tdc(idtfc3, true, CONTINUOUS); + } else { + err = idtfc3_enable_tdc(idtfc3, false, MEAS_MODE_INVALID); + } + break; + default: + break; + } + mutex_unlock(idtfc3->lock); + + if (err) + dev_err(idtfc3->dev, "Failed in %s with err %d!", __func__, err); + + return err; +} + +static long idtfc3_aux_work(struct ptp_clock_info *ptp) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + static int tdc_get; + + mutex_lock(idtfc3->lock); + tdc_get %= TDC_GET_PERIOD; + if ((tdc_get == 0) || (tdc_get == TDC_GET_PERIOD / 2)) + idtfc3_timecounter_read(idtfc3); + get_tdc_meas_continuous(idtfc3); + tdc_get++; + mutex_unlock(idtfc3->lock); + + return idtfc3->tc_update_period; +} + +static const struct ptp_clock_info idtfc3_caps = { + .owner = THIS_MODULE, + .max_adj = MAX_FFO_PPB, + .n_per_out = 1, + .n_ext_ts = 1, + .adjphase = &idtfc3_adjphase, + .adjfine = &idtfc3_adjfine, + .adjtime = &idtfc3_adjtime, + .gettime64 = &idtfc3_gettime, + .settime64 = &idtfc3_settime, + .enable = &idtfc3_enable, + .do_aux_work = &idtfc3_aux_work, +}; + +static int idtfc3_hw_calibrate(struct idtfc3 *idtfc3) +{ + int err = 0; + u8 val; + + mdelay(10); + /* + * Toggle TDC_DAC_RECAL_REQ: + * (1) set tdc_en to 1 + * (2) set tdc_dac_recal_req to 0 + * (3) set tdc_dac_recal_req to 1 + */ + val = TDC_EN; + err = regmap_bulk_write(idtfc3->regmap, TDC_CTRL, + &val, sizeof(val)); + if (err) + return err; + val = TDC_EN | TDC_DAC_RECAL_REQ; + err = regmap_bulk_write(idtfc3->regmap, TDC_CTRL, + &val, sizeof(val)); + if (err) + return err; + mdelay(10); + + /* + * Toggle APLL_REINIT: + * (1) set apll_reinit to 0 + * (2) set apll_reinit to 1 + */ + val = 0; + err = regmap_bulk_write(idtfc3->regmap, SOFT_RESET_CTRL, + &val, sizeof(val)); + if (err) + return err; + val = APLL_REINIT; + err = regmap_bulk_write(idtfc3->regmap, SOFT_RESET_CTRL, + &val, sizeof(val)); + if (err) + return err; + mdelay(10); + + return err; +} + +static int idtfc3_init_timecounter(struct idtfc3 *idtfc3) +{ + int err; + u32 period_ms; + + period_ms = idtfc3->sub_sync_count * MSEC_PER_SEC / + idtfc3->hw_param.time_clk_freq; + + idtfc3->tc_update_period = msecs_to_jiffies(period_ms / TDC_GET_PERIOD); + idtfc3->tc_write_timeout = period_ms * USEC_PER_MSEC; + + err = idtfc3_timecounter_update(idtfc3, 0, 0); + if (err) + return err; + + err = idtfc3_timecounter_read(idtfc3); + if (err) + return err; + + ptp_schedule_worker(idtfc3->ptp_clock, idtfc3->tc_update_period); + + return 0; +} + +static int idtfc3_get_tdc_apll_freq(struct idtfc3 *idtfc3) +{ + int err; + u8 tdc_fb_div_int; + u8 tdc_ref_div; + struct idtfc3_hw_param *param = &idtfc3->hw_param; + + err = regmap_bulk_read(idtfc3->regmap, TDC_REF_DIV_CNFG, + &tdc_ref_div, sizeof(tdc_ref_div)); + if (err) + return err; + + err = regmap_bulk_read(idtfc3->regmap, TDC_FB_DIV_INT_CNFG, + &tdc_fb_div_int, sizeof(tdc_fb_div_int)); + if (err) + return err; + + tdc_fb_div_int &= TDC_FB_DIV_INT_MASK; + tdc_ref_div &= TDC_REF_DIV_CONFIG_MASK; + + idtfc3->tdc_apll_freq = div_u64(param->xtal_freq * (u64)tdc_fb_div_int, + 1 << tdc_ref_div); + + return 0; +} + +static int idtfc3_get_fod(struct idtfc3 *idtfc3) +{ + int err; + u8 fod; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_SRC, &fod, sizeof(fod)); + if (err) + return err; + + switch (fod) { + case 0: + idtfc3->fod_n = FOD_0; + break; + case 1: + idtfc3->fod_n = FOD_1; + break; + case 2: + idtfc3->fod_n = FOD_2; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int idtfc3_get_sync_count(struct idtfc3 *idtfc3) +{ + int err; + u8 buf[4]; + + err = regmap_bulk_read(idtfc3->regmap, SUB_SYNC_GEN_CNFG, buf, sizeof(buf)); + if (err) + return err; + + idtfc3->sub_sync_count = (get_unaligned_le32(buf) & SUB_SYNC_COUNTER_MASK) + 1; + idtfc3->ns_per_counter = NSEC_PER_SEC / idtfc3->hw_param.time_clk_freq; + idtfc3->ns_per_sync = idtfc3->sub_sync_count * idtfc3->ns_per_counter; + + return 0; +} + +static int idtfc3_setup_hw_param(struct idtfc3 *idtfc3) +{ + int err; + + err = idtfc3_get_fod(idtfc3); + if (err) + return err; + + err = idtfc3_get_sync_count(idtfc3); + if (err) + return err; + + err = idtfc3_get_time_ref_freq(idtfc3); + if (err) + return err; + + return idtfc3_get_tdc_apll_freq(idtfc3); +} + +static int idtfc3_configure_hw(struct idtfc3 *idtfc3) +{ + int err = 0; + + err = idtfc3_hw_calibrate(idtfc3); + if (err) + return err; + + err = idtfc3_enable_lpf(idtfc3, true); + if (err) + return err; + + err = idtfc3_enable_tdc(idtfc3, false, MEAS_MODE_INVALID); + if (err) + return err; + + err = idtfc3_get_tdc_offset_sign(idtfc3); + if (err) + return err; + + return idtfc3_setup_hw_param(idtfc3); +} + +static int idtfc3_set_overhead(struct idtfc3 *idtfc3) +{ + s64 current_ns = 0; + s64 lowest_ns = 0; + int err; + u8 i; + ktime_t start; + ktime_t stop; + ktime_t diff; + + char buf[18] = {0}; + + for (i = 0; i < 5; i++) { + start = ktime_get_raw(); + + err = regmap_bulk_write(idtfc3->regmap, TOD_SYNC_LOAD_VAL_CTRL, + &buf, sizeof(buf)); + if (err) + return err; + + stop = ktime_get_raw(); + + diff = ktime_sub(stop, start); + + current_ns = ktime_to_ns(diff); + + if (i == 0) { + lowest_ns = current_ns; + } else { + if (current_ns < lowest_ns) + lowest_ns = current_ns; + } + } + + idtfc3->tod_write_overhead = lowest_ns; + + return err; +} + +static int idtfc3_enable_ptp(struct idtfc3 *idtfc3) +{ + int err; + + idtfc3->caps = idtfc3_caps; + snprintf(idtfc3->caps.name, sizeof(idtfc3->caps.name), "IDT FC3W"); + idtfc3->ptp_clock = ptp_clock_register(&idtfc3->caps, NULL); + + if (IS_ERR(idtfc3->ptp_clock)) { + err = PTR_ERR(idtfc3->ptp_clock); + idtfc3->ptp_clock = NULL; + return err; + } + + err = idtfc3_set_overhead(idtfc3); + if (err) + return err; + + err = idtfc3_init_timecounter(idtfc3); + if (err) + return err; + + dev_info(idtfc3->dev, "TIME_SYNC_CHANNEL registered as ptp%d", + idtfc3->ptp_clock->index); + + return 0; +} + +static int idtfc3_load_firmware(struct idtfc3 *idtfc3) +{ + char fname[128] = FW_FILENAME; + const struct firmware *fw; + struct idtfc3_fwrc *rec; + u16 addr; + u8 val; + int err; + s32 len; + + idtfc3_default_hw_param(&idtfc3->hw_param); + + if (firmware) /* module parameter */ + snprintf(fname, sizeof(fname), "%s", firmware); + + dev_info(idtfc3->dev, "requesting firmware '%s'\n", fname); + + err = request_firmware(&fw, fname, idtfc3->dev); + + if (err) { + dev_err(idtfc3->dev, + "requesting firmware failed with err %d!\n", err); + return err; + } + + dev_dbg(idtfc3->dev, "firmware size %zu bytes\n", fw->size); + + rec = (struct idtfc3_fwrc *)fw->data; + + for (len = fw->size; len > 0; len -= sizeof(*rec)) { + if (rec->reserved) { + dev_err(idtfc3->dev, + "bad firmware, reserved field non-zero\n"); + err = -EINVAL; + } else { + val = rec->value; + addr = rec->hiaddr << 8 | rec->loaddr; + + rec++; + + err = idtfc3_set_hw_param(&idtfc3->hw_param, addr, val); + } + + if (err != -EINVAL) { + err = 0; + + /* Max register */ + if (addr >= 0xE88) + continue; + + err = regmap_bulk_write(idtfc3->regmap, addr, + &val, sizeof(val)); + } + + if (err) + goto out; + } + + err = idtfc3_configure_hw(idtfc3); +out: + release_firmware(fw); + return err; +} + +static int idtfc3_read_device_id(struct idtfc3 *idtfc3, u16 *device_id) +{ + int err; + u8 buf[2] = {0}; + + err = regmap_bulk_read(idtfc3->regmap, DEVICE_ID, + &buf, sizeof(buf)); + if (err) { + dev_err(idtfc3->dev, "%s failed with %d", __func__, err); + return err; + } + + *device_id = get_unaligned_le16(buf); + + return 0; +} + +static int idtfc3_check_device_compatibility(struct idtfc3 *idtfc3) +{ + int err; + u16 device_id; + + err = idtfc3_read_device_id(idtfc3, &device_id); + if (err) + return err; + + if ((device_id & DEVICE_ID_MASK) == 0) { + dev_err(idtfc3->dev, "invalid device"); + return -EINVAL; + } + + return 0; +} + +static int idtfc3_probe(struct platform_device *pdev) +{ + struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent); + struct idtfc3 *idtfc3; + int err; + + idtfc3 = devm_kzalloc(&pdev->dev, sizeof(struct idtfc3), GFP_KERNEL); + + if (!idtfc3) + return -ENOMEM; + + idtfc3->dev = &pdev->dev; + idtfc3->mfd = pdev->dev.parent; + idtfc3->lock = &ddata->lock; + idtfc3->regmap = ddata->regmap; + + mutex_lock(idtfc3->lock); + + err = idtfc3_check_device_compatibility(idtfc3); + if (err) { + mutex_unlock(idtfc3->lock); + return err; + } + + err = idtfc3_load_firmware(idtfc3); + if (err) { + if (err == -ENOENT) { + mutex_unlock(idtfc3->lock); + return -EPROBE_DEFER; + } + dev_warn(idtfc3->dev, "loading firmware failed with %d", err); + } + + err = idtfc3_enable_ptp(idtfc3); + if (err) { + dev_err(idtfc3->dev, "idtfc3_enable_ptp failed with %d", err); + mutex_unlock(idtfc3->lock); + return err; + } + + mutex_unlock(idtfc3->lock); + + if (err) { + ptp_clock_unregister(idtfc3->ptp_clock); + return err; + } + + platform_set_drvdata(pdev, idtfc3); + + return 0; +} + +static int idtfc3_remove(struct platform_device *pdev) +{ + struct idtfc3 *idtfc3 = platform_get_drvdata(pdev); + + ptp_clock_unregister(idtfc3->ptp_clock); + + return 0; +} + +static struct platform_driver idtfc3_driver = { + .driver = { + .name = "rc38xxx-phc", + }, + .probe = idtfc3_probe, + .remove = idtfc3_remove, +}; + +module_platform_driver(idtfc3_driver); diff --git a/drivers/ptp/ptp_fc3.h b/drivers/ptp/ptp_fc3.h new file mode 100644 index 000000000000..897101579207 --- /dev/null +++ b/drivers/ptp/ptp_fc3.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * PTP hardware clock driver for the FemtoClock3 family of timing and + * synchronization devices. + * + * Copyright (C) 2023 Integrated Device Technology, Inc., a Renesas Company. + */ +#ifndef PTP_IDTFC3_H +#define PTP_IDTFC3_H + +#include +#include +#include + +#define FW_FILENAME "idtfc3.bin" + +#define MAX_FFO_PPB (244000) +#define TDC_GET_PERIOD (10) + +struct idtfc3 { + struct ptp_clock_info caps; + struct ptp_clock *ptp_clock; + struct device *dev; + /* Mutex to protect operations from being interrupted */ + struct mutex *lock; + struct device *mfd; + struct regmap *regmap; + struct idtfc3_hw_param hw_param; + u32 sub_sync_count; + u32 ns_per_sync; + int tdc_offset_sign; + u64 tdc_apll_freq; + u32 time_ref_freq; + u16 fod_n; + u8 lpf_mode; + /* Time counter */ + u32 last_counter; + s64 ns; + u32 ns_per_counter; + u32 tc_update_period; + u32 tc_write_timeout; + s64 tod_write_overhead; +}; + +#endif /* PTP_IDTFC3_H */ diff --git a/include/linux/mfd/idtRC38xxx_reg.h b/include/linux/mfd/idtRC38xxx_reg.h new file mode 100644 index 000000000000..ec11872f51ad --- /dev/null +++ b/include/linux/mfd/idtRC38xxx_reg.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Register Map - Based on PolarBear_CSRs.RevA.xlsx (2023-04-21) + * + * Copyright (C) 2023 Integrated Device Technology, Inc., a Renesas Company. + */ +#ifndef MFD_IDTRC38XXX_REG +#define MFD_IDTRC38XXX_REG + +/* GLOBAL */ +#define SOFT_RESET_CTRL (0x15) /* Specific to FC3W */ +#define MISC_CTRL (0x14) /* Specific to FC3A */ +#define APLL_REINIT BIT(1) +#define APLL_REINIT_VFC3A BIT(2) + +#define DEVICE_ID (0x2) +#define DEVICE_ID_MASK (0x1000) /* Bit 12 is 1 if FC3W and 0 if FC3A */ +#define DEVICE_ID_SHIFT (12) + +/* FOD */ +#define FOD_0 (0x300) +#define FOD_0_VFC3A (0x400) +#define FOD_1 (0x340) +#define FOD_1_VFC3A (0x440) +#define FOD_2 (0x380) +#define FOD_2_VFC3A (0x480) + +/* TDCAPLL */ +#define TDC_CTRL (0x44a) /* Specific to FC3W */ +#define TDC_ENABLE_CTRL (0x169) /* Specific to FC3A */ +#define TDC_DAC_CAL_CTRL (0x16a) /* Specific to FC3A */ +#define TDC_EN BIT(0) +#define TDC_DAC_RECAL_REQ BIT(1) +#define TDC_DAC_RECAL_REQ_VFC3A BIT(0) + +#define TDC_FB_DIV_INT_CNFG (0x442) +#define TDC_FB_DIV_INT_CNFG_VFC3A (0x162) +#define TDC_FB_DIV_INT_MASK GENMASK(7, 0) +#define TDC_REF_DIV_CNFG (0x443) +#define TDC_REF_DIV_CNFG_VFC3A (0x163) +#define TDC_REF_DIV_CONFIG_MASK GENMASK(2, 0) + +/* TIME SYNC CHANNEL */ +#define TIME_CLOCK_SRC (0xa01) /* Specific to FC3W */ +#define TIME_CLOCK_COUNT (0xa00) /* Specific to FC3W */ +#define TIME_CLOCK_COUNT_MASK GENMASK(5, 0) + +#define SUB_SYNC_GEN_CNFG (0xa04) + +#define TOD_COUNTER_READ_REQ (0xa5f) +#define TOD_COUNTER_READ_REQ_VFC3A (0x6df) +#define TOD_SYNC_LOAD_VAL_CTRL (0xa10) +#define TOD_SYNC_LOAD_VAL_CTRL_VFC3A (0x690) +#define SYNC_COUNTER_MASK GENMASK_ULL(51, 0) +#define SUB_SYNC_COUNTER_MASK GENMASK(30, 0) +#define TOD_SYNC_LOAD_REQ_CTRL (0xa21) +#define TOD_SYNC_LOAD_REQ_CTRL_VFC3A (0x6a1) +#define SYNC_LOAD_ENABLE BIT(1) +#define SUB_SYNC_LOAD_ENABLE BIT(0) +#define SYNC_LOAD_REQ BIT(0) + +#define LPF_MODE_CNFG (0xa80) +#define LPF_MODE_CNFG_VFC3A (0x700) +enum lpf_mode { + LPF_DISABLED = 0, + LPF_WP = 1, + LPF_HOLDOVER = 2, + LPF_WF = 3, + LPF_INVALID = 4 +}; +#define LPF_CTRL (0xa98) +#define LPF_CTRL_VFC3A (0x718) +#define LPF_EN BIT(0) + +#define LPF_BW_CNFG (0xa81) +#define LPF_BW_SHIFT GENMASK(7, 3) +#define LPF_BW_MULT GENMASK(2, 0) +#define LPF_BW_SHIFT_DEFAULT (0xb) +#define LPF_BW_MULT_DEFAULT (0x0) +#define LPF_BW_SHIFT_1PPS (0x5) + +#define LPF_WR_PHASE_CTRL (0xaa8) +#define LPF_WR_PHASE_CTRL_VFC3A (0x728) +#define LPF_WR_FREQ_CTRL (0xab0) +#define LPF_WR_FREQ_CTRL_VFC3A (0x730) + +#define TIME_CLOCK_TDC_FANOUT_CNFG (0xB00) +#define TIME_SYNC_TO_TDC_EN BIT(0) +#define SIG1_MUX_SEL_MASK GENMASK(7, 4) +#define SIG2_MUX_SEL_MASK GENMASK(11, 8) +enum tdc_mux_sel { + REF0 = 0, + REF1 = 1, + REF2 = 2, + REF3 = 3, + REF_CLK5 = 4, + REF_CLK6 = 5, + DPLL_FB_TO_TDC = 6, + DPLL_FB_DIVIDED_TO_TDC = 7, + TIME_CLK_DIVIDED = 8, + TIME_SYNC = 9, +}; + +#define TIME_CLOCK_MEAS_CNFG (0xB04) +#define TDC_MEAS_MODE BIT(0) +enum tdc_meas_mode { + CONTINUOUS = 0, + ONE_SHOT = 1, + MEAS_MODE_INVALID = 2, +}; + +#define TIME_CLOCK_MEAS_DIV_CNFG (0xB08) +#define TIME_REF_DIV_MASK GENMASK(29, 24) + +#define TIME_CLOCK_MEAS_CTRL (0xB10) +#define TDC_MEAS_EN BIT(0) +#define TDC_MEAS_START BIT(1) + +#define TDC_FIFO_READ_REQ (0xB2F) +#define TDC_FIFO_READ (0xB30) +#define COARSE_MEAS_MASK GENMASK_ULL(39, 13) +#define FINE_MEAS_MASK GENMASK(12, 0) + +#define TDC_FIFO_CTRL (0xB12) +#define FIFO_CLEAR BIT(0) +#define TDC_FIFO_STS (0xB38) +#define FIFO_FULL BIT(1) +#define FIFO_EMPTY BIT(0) +#define TDC_FIFO_EVENT (0xB39) +#define FIFO_OVERRUN BIT(1) + +/* DPLL */ +#define MAX_REFERENCE_INDEX (3) +#define MAX_NUM_REF_PRIORITY (4) + +#define MAX_DPLL_INDEX (2) + +#define DPLL_STS (0x580) +#define DPLL_STS_VFC3A (0x571) +#define DPLL_STATE_STS_MASK (0x70) +#define DPLL_STATE_STS_SHIFT (4) +#define DPLL_REF_SEL_STS_MASK (0x6) +#define DPLL_REF_SEL_STS_SHIFT (1) + +#define DPLL_REF_PRIORITY_CNFG (0x502) +#define DPLL_REFX_PRIORITY_DISABLE_MASK (0xf) +#define DPLL_REF0_PRIORITY_ENABLE_AND_SET_MASK (0x31) +#define DPLL_REF1_PRIORITY_ENABLE_AND_SET_MASK (0xc2) +#define DPLL_REF2_PRIORITY_ENABLE_AND_SET_MASK (0x304) +#define DPLL_REF3_PRIORITY_ENABLE_AND_SET_MASK (0xc08) +#define DPLL_REF0_PRIORITY_SHIFT (4) +#define DPLL_REF1_PRIORITY_SHIFT (6) +#define DPLL_REF2_PRIORITY_SHIFT (8) +#define DPLL_REF3_PRIORITY_SHIFT (10) + +enum dpll_state { + DPLL_STATE_MIN = 0, + DPLL_STATE_FREERUN = DPLL_STATE_MIN, + DPLL_STATE_LOCKED = 1, + DPLL_STATE_HOLDOVER = 2, + DPLL_STATE_WRITE_FREQUENCY = 3, + DPLL_STATE_ACQUIRE = 4, + DPLL_STATE_HITLESS_SWITCH = 5, + DPLL_STATE_MAX = DPLL_STATE_HITLESS_SWITCH +}; + +/* REFMON */ +#define LOSMON_STS_0 (0x81e) +#define LOSMON_STS_0_VFC3A (0x18e) +#define LOSMON_STS_1 (0x82e) +#define LOSMON_STS_1_VFC3A (0x19e) +#define LOSMON_STS_2 (0x83e) +#define LOSMON_STS_2_VFC3A (0x1ae) +#define LOSMON_STS_3 (0x84e) +#define LOSMON_STS_3_VFC3A (0x1be) +#define LOS_STS_MASK (0x1) + +#define FREQMON_STS_0 (0x874) +#define FREQMON_STS_0_VFC3A (0x1d4) +#define FREQMON_STS_1 (0x894) +#define FREQMON_STS_1_VFC3A (0x1f4) +#define FREQMON_STS_2 (0x8b4) +#define FREQMON_STS_2_VFC3A (0x214) +#define FREQMON_STS_3 (0x8d4) +#define FREQMON_STS_3_VFC3A (0x234) +#define FREQ_FAIL_STS_SHIFT (31) + +/* Firmware interface */ +#define TIME_CLK_FREQ_ADDR (0xffa0) +#define XTAL_FREQ_ADDR (0xffa1) + +/* + * Return register address and field mask based on passed in firmware version + */ +#define IDTFC3_FW_REG(FW, VER, REG) (((FW) < (VER)) ? (REG) : (REG##_##VER)) +#define IDTFC3_FW_FIELD(FW, VER, FIELD) (((FW) < (VER)) ? (FIELD) : (FIELD##_##VER)) +enum fw_version { + V_DEFAULT = 0, + VFC3W = 1, + VFC3A = 2 +}; + +/* XTAL_FREQ_ADDR/TIME_CLK_FREQ_ADDR */ +enum { + FREQ_MIN = 0, + FREQ_25M = 1, + FREQ_49_152M = 2, + FREQ_50M = 3, + FREQ_100M = 4, + FREQ_125M = 5, + FREQ_250M = 6, + FREQ_MAX +}; + +struct idtfc3_hw_param { + u32 xtal_freq; + u32 time_clk_freq; +}; + +struct idtfc3_fwrc { + u8 hiaddr; + u8 loaddr; + u8 value; + u8 reserved; +} __packed; + +static inline void idtfc3_default_hw_param(struct idtfc3_hw_param *hw_param) +{ + hw_param->xtal_freq = 49152000; + hw_param->time_clk_freq = 25000000; +} + +static inline int idtfc3_set_hw_param(struct idtfc3_hw_param *hw_param, + u16 addr, u8 val) +{ + if (addr == XTAL_FREQ_ADDR) + switch (val) { + case FREQ_49_152M: + hw_param->xtal_freq = 49152000; + break; + case FREQ_50M: + hw_param->xtal_freq = 50000000; + break; + default: + return -EINVAL; + } + else if (addr == TIME_CLK_FREQ_ADDR) + switch (val) { + case FREQ_25M: + hw_param->time_clk_freq = 25000000; + break; + case FREQ_50M: + hw_param->time_clk_freq = 50000000; + break; + case FREQ_100M: + hw_param->time_clk_freq = 100000000; + break; + case FREQ_125M: + hw_param->time_clk_freq = 125000000; + break; + case FREQ_250M: + hw_param->time_clk_freq = 250000000; + break; + default: + return -EINVAL; + } + else + return -EFAULT; + + return 0; +} + +#endif From 9e1aa985d61eacd5931496b80fbd1c2d2cdeece5 Mon Sep 17 00:00:00 2001 From: Tobias Schramm Date: Thu, 25 Jan 2024 21:15:05 +0100 Subject: [PATCH 0395/2255] dt-bindings: nfc: ti,trf7970a: fix usage example The TRF7970A is a SPI device, not I2C. Signed-off-by: Tobias Schramm Reviewed-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml b/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml index 9cc236ec42f2..d0332eb76ad2 100644 --- a/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml +++ b/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml @@ -73,7 +73,7 @@ examples: #include #include - i2c { + spi { #address-cells = <1>; #size-cells = <0>; From 723de3ebef03bc14bd72531f00f9094337654009 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 26 Jan 2024 12:14:49 -0800 Subject: [PATCH 0396/2255] net: free altname using an RCU callback We had to add another synchronize_rcu() in recent fix. Bite the bullet and add an rcu_head to netdev_name_node, free from RCU. Note that name_node does not hold any reference on dev to which it points, but there must be a synchronize_rcu() on device removal path, so we should be fine. Signed-off-by: Jakub Kicinski Reviewed-by: Jiri Pirko Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 27 ++++++++++++++++----------- net/core/dev.h | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index cb2dab0feee0..b53b9c94de40 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -341,13 +341,22 @@ int netdev_name_node_alt_create(struct net_device *dev, const char *name) return 0; } -static void __netdev_name_node_alt_destroy(struct netdev_name_node *name_node) +static void netdev_name_node_alt_free(struct rcu_head *head) { - list_del(&name_node->list); + struct netdev_name_node *name_node = + container_of(head, struct netdev_name_node, rcu); + kfree(name_node->name); netdev_name_node_free(name_node); } +static void __netdev_name_node_alt_destroy(struct netdev_name_node *name_node) +{ + netdev_name_node_del(name_node); + list_del(&name_node->list); + call_rcu(&name_node->rcu, netdev_name_node_alt_free); +} + int netdev_name_node_alt_destroy(struct net_device *dev, const char *name) { struct netdev_name_node *name_node; @@ -362,10 +371,7 @@ int netdev_name_node_alt_destroy(struct net_device *dev, const char *name) if (name_node == dev->name_node || name_node->dev != dev) return -EINVAL; - netdev_name_node_del(name_node); - synchronize_rcu(); __netdev_name_node_alt_destroy(name_node); - return 0; } @@ -373,8 +379,10 @@ static void netdev_name_node_alt_flush(struct net_device *dev) { struct netdev_name_node *name_node, *tmp; - list_for_each_entry_safe(name_node, tmp, &dev->name_node->list, list) - __netdev_name_node_alt_destroy(name_node); + list_for_each_entry_safe(name_node, tmp, &dev->name_node->list, list) { + list_del(&name_node->list); + netdev_name_node_alt_free(&name_node->rcu); + } } /* Device list insertion */ @@ -11576,11 +11584,8 @@ static void __net_exit default_device_exit_net(struct net *net) snprintf(fb_name, IFNAMSIZ, "dev%%d"); netdev_for_each_altname_safe(dev, name_node, tmp) - if (netdev_name_in_use(&init_net, name_node->name)) { - netdev_name_node_del(name_node); - synchronize_rcu(); + if (netdev_name_in_use(&init_net, name_node->name)) __netdev_name_node_alt_destroy(name_node); - } err = dev_change_net_namespace(dev, &init_net, fb_name); if (err) { diff --git a/net/core/dev.h b/net/core/dev.h index 7480b4c84298..a43dfe3de50e 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -56,6 +56,7 @@ struct netdev_name_node { struct list_head list; struct net_device *dev; const char *name; + struct rcu_head rcu; }; int netdev_get_name(struct net *net, char *name, int ifindex); From 941988af572434e4aa93fb0f2f509f92adfd691a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 21 Dec 2023 14:31:57 +0100 Subject: [PATCH 0397/2255] netfilter: uapi: Document NFT_TABLE_F_OWNER flag Add at least this one-liner describing the obvious. Fixes: 6001a930ce03 ("netfilter: nftables: introduce table ownership") Signed-off-by: Phil Sutter Signed-off-by: Florian Westphal --- include/uapi/linux/netfilter/nf_tables.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index ca30232b7bc8..fbce238abdc1 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -179,6 +179,7 @@ enum nft_hook_attributes { * enum nft_table_flags - nf_tables table flags * * @NFT_TABLE_F_DORMANT: this table is not active + * @NFT_TABLE_F_OWNER: this table is owned by a process */ enum nft_table_flags { NFT_TABLE_F_DORMANT = 0x1, From da5141bbe0c2693d85f14a89ee991921904f4d0c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 21 Dec 2023 14:31:58 +0100 Subject: [PATCH 0398/2255] netfilter: nf_tables: Introduce NFT_TABLE_F_PERSIST This companion flag to NFT_TABLE_F_OWNER requests the kernel to keep the table around after the process has exited. It marks such table as orphaned (by dropping OWNER flag but keeping PERSIST flag in place), which opens it for other processes to manipulate. For the sake of simplicity, PERSIST flag may not be altered though. Signed-off-by: Phil Sutter Signed-off-by: Florian Westphal --- include/uapi/linux/netfilter/nf_tables.h | 5 ++++- net/netfilter/nf_tables_api.c | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index fbce238abdc1..3fee994721cd 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -180,13 +180,16 @@ enum nft_hook_attributes { * * @NFT_TABLE_F_DORMANT: this table is not active * @NFT_TABLE_F_OWNER: this table is owned by a process + * @NFT_TABLE_F_PERSIST: this table shall outlive its owner */ enum nft_table_flags { NFT_TABLE_F_DORMANT = 0x1, NFT_TABLE_F_OWNER = 0x2, + NFT_TABLE_F_PERSIST = 0x4, }; #define NFT_TABLE_F_MASK (NFT_TABLE_F_DORMANT | \ - NFT_TABLE_F_OWNER) + NFT_TABLE_F_OWNER | \ + NFT_TABLE_F_PERSIST) /** * enum nft_table_attributes - nf_tables table netlink attributes diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index c537104411e7..6a96f0003faa 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1219,6 +1219,9 @@ static int nf_tables_updtable(struct nft_ctx *ctx) flags & NFT_TABLE_F_OWNER)) return -EOPNOTSUPP; + if ((flags ^ ctx->table->flags) & NFT_TABLE_F_PERSIST) + return -EOPNOTSUPP; + /* No dormant off/on/off/on games in single transaction */ if (ctx->table->flags & __NFT_TABLE_F_UPDATE) return -EINVAL; @@ -11345,6 +11348,10 @@ again: list_for_each_entry(table, &nft_net->tables, list) { if (nft_table_has_owner(table) && n->portid == table->nlpid) { + if (table->flags & NFT_TABLE_F_PERSIST) { + table->flags &= ~NFT_TABLE_F_OWNER; + continue; + } __nft_release_hook(net, table); list_del_rcu(&table->list); to_delete[deleted++] = table; From 31bf508be656a429a17e3adb31e9acae5c1a6299 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 21 Dec 2023 14:31:59 +0100 Subject: [PATCH 0399/2255] netfilter: nf_tables: Implement table adoption support Allow a new process to take ownership of a previously owned table, useful mostly for firewall management services restarting or suspending when idle. By extending __NFT_TABLE_F_UPDATE, the on/off/on check in nf_tables_updtable() also covers table adoption, although it is actually not needed: Table adoption is irreversible because nf_tables_updtable() rejects attempts to drop NFT_TABLE_F_OWNER so table->nlpid setting can happen just once within the transaction. If the transaction commences, table's nlpid and flags fields are already set and no further action is required. If it aborts, the table returns to orphaned state. Signed-off-by: Phil Sutter Signed-off-by: Florian Westphal --- include/net/netfilter/nf_tables.h | 6 ++++++ net/netfilter/nf_tables_api.c | 19 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 4e1ea18eb5f0..ac7c94d3648e 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -1271,6 +1271,12 @@ static inline bool nft_table_has_owner(const struct nft_table *table) return table->flags & NFT_TABLE_F_OWNER; } +static inline bool nft_table_is_orphan(const struct nft_table *table) +{ + return (table->flags & (NFT_TABLE_F_OWNER | NFT_TABLE_F_PERSIST)) == + NFT_TABLE_F_PERSIST; +} + static inline bool nft_base_chain_netdev(int family, u32 hooknum) { return family == NFPROTO_NETDEV || diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 6a96f0003faa..b0e0d039897e 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1194,8 +1194,10 @@ static void nf_tables_table_disable(struct net *net, struct nft_table *table) #define __NFT_TABLE_F_INTERNAL (NFT_TABLE_F_MASK + 1) #define __NFT_TABLE_F_WAS_DORMANT (__NFT_TABLE_F_INTERNAL << 0) #define __NFT_TABLE_F_WAS_AWAKEN (__NFT_TABLE_F_INTERNAL << 1) +#define __NFT_TABLE_F_WAS_ORPHAN (__NFT_TABLE_F_INTERNAL << 2) #define __NFT_TABLE_F_UPDATE (__NFT_TABLE_F_WAS_DORMANT | \ - __NFT_TABLE_F_WAS_AWAKEN) + __NFT_TABLE_F_WAS_AWAKEN | \ + __NFT_TABLE_F_WAS_ORPHAN) static int nf_tables_updtable(struct nft_ctx *ctx) { @@ -1215,8 +1217,8 @@ static int nf_tables_updtable(struct nft_ctx *ctx) if ((nft_table_has_owner(ctx->table) && !(flags & NFT_TABLE_F_OWNER)) || - (!nft_table_has_owner(ctx->table) && - flags & NFT_TABLE_F_OWNER)) + (flags & NFT_TABLE_F_OWNER && + !nft_table_is_orphan(ctx->table))) return -EOPNOTSUPP; if ((flags ^ ctx->table->flags) & NFT_TABLE_F_PERSIST) @@ -1248,6 +1250,13 @@ static int nf_tables_updtable(struct nft_ctx *ctx) } } + if ((flags & NFT_TABLE_F_OWNER) && + !nft_table_has_owner(ctx->table)) { + ctx->table->nlpid = ctx->portid; + ctx->table->flags |= NFT_TABLE_F_OWNER | + __NFT_TABLE_F_WAS_ORPHAN; + } + nft_trans_table_update(trans) = true; nft_trans_commit_list_add_tail(ctx->net, trans); @@ -10423,6 +10432,10 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) } else if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_AWAKEN) { trans->ctx.table->flags &= ~NFT_TABLE_F_DORMANT; } + if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_ORPHAN) { + trans->ctx.table->flags &= ~NFT_TABLE_F_OWNER; + trans->ctx.table->nlpid = 0; + } trans->ctx.table->flags &= ~__NFT_TABLE_F_UPDATE; nft_trans_destroy(trans); } else { From a128885ace60ff3da326dab7208fd7a04ce0b138 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 4 Jan 2024 13:26:09 +0100 Subject: [PATCH 0400/2255] netfilter: nf_tables: pass flags to set backend selection routine No need to refetch the flag from the netlink attribute, pass the existing flags variable which already provide validated flags. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- net/netfilter/nf_tables_api.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index b0e0d039897e..7f25a04e4b81 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4247,23 +4247,18 @@ static bool nft_set_ops_candidate(const struct nft_set_type *type, u32 flags) * given, in that case the amount of memory per element is used. */ static const struct nft_set_ops * -nft_select_set_ops(const struct nft_ctx *ctx, - const struct nlattr * const nla[], +nft_select_set_ops(const struct nft_ctx *ctx, u32 flags, const struct nft_set_desc *desc) { struct nftables_pernet *nft_net = nft_pernet(ctx->net); const struct nft_set_ops *ops, *bops; struct nft_set_estimate est, best; const struct nft_set_type *type; - u32 flags = 0; int i; lockdep_assert_held(&nft_net->commit_mutex); lockdep_nfnl_nft_mutex_not_held(); - if (nla[NFTA_SET_FLAGS] != NULL) - flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS])); - bops = NULL; best.size = ~0; best.lookup = ~0; @@ -5149,7 +5144,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, if (!(info->nlh->nlmsg_flags & NLM_F_CREATE)) return -ENOENT; - ops = nft_select_set_ops(&ctx, nla, &desc); + ops = nft_select_set_ops(&ctx, flags, &desc); if (IS_ERR(ops)) return PTR_ERR(ops); From 2ae6e9a03dadee5b2749d391d2e6df3056c5b6dd Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 23 Jan 2024 10:46:31 +0800 Subject: [PATCH 0401/2255] netfilter: nf_conncount: Use KMEM_CACHE instead of kmem_cache_create() Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Signed-off-by: Florian Westphal --- net/netfilter/nf_conncount.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index 5d8ed6c90b7e..8715617b02fe 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -605,15 +605,11 @@ static int __init nf_conncount_modinit(void) for (i = 0; i < CONNCOUNT_SLOTS; ++i) spin_lock_init(&nf_conncount_locks[i]); - conncount_conn_cachep = kmem_cache_create("nf_conncount_tuple", - sizeof(struct nf_conncount_tuple), - 0, 0, NULL); + conncount_conn_cachep = KMEM_CACHE(nf_conncount_tuple, 0); if (!conncount_conn_cachep) return -ENOMEM; - conncount_rb_cachep = kmem_cache_create("nf_conncount_rb", - sizeof(struct nf_conncount_rb), - 0, 0, NULL); + conncount_rb_cachep = KMEM_CACHE(nf_conncount_rb, 0); if (!conncount_rb_cachep) { kmem_cache_destroy(conncount_conn_cachep); return -ENOMEM; From d5f9142fb96d4386ff4d06745bbd8f8c73b3791b Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Wed, 17 Jan 2024 15:20:45 +0800 Subject: [PATCH 0402/2255] ipvs: Simplify the allocation of ip_vs_conn slab caches Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Acked-by: Simon Horman Signed-off-by: Florian Westphal --- net/netfilter/ipvs/ip_vs_conn.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index a743db073887..98d7dbe3d787 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -1511,9 +1511,7 @@ int __init ip_vs_conn_init(void) return -ENOMEM; /* Allocate ip_vs_conn slab cache */ - ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn", - sizeof(struct ip_vs_conn), 0, - SLAB_HWCACHE_ALIGN, NULL); + ip_vs_conn_cachep = KMEM_CACHE(ip_vs_conn, SLAB_HWCACHE_ALIGN); if (!ip_vs_conn_cachep) { kvfree(ip_vs_conn_tab); return -ENOMEM; From 4654467dc7e111e84f43ed1b70322873ae77e7be Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 23 Jan 2024 16:42:48 +0100 Subject: [PATCH 0403/2255] netfilter: arptables: allow xtables-nft only builds Allows to build kernel that supports the arptables mangle target via nftables' compat infra but without the arptables get/setsockopt interface or the old arptables filter interpreter. IOW, setting IP_NF_ARPFILTER=n will break arptables-legacy, but arptables-nft will continue to work as long as nftables compat support is enabled. Signed-off-by: Florian Westphal Reviewed-by: Phil Sutter --- net/ipv4/netfilter/Kconfig | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index f71a7e9a7de6..070475392236 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -309,36 +309,34 @@ endif # IP_NF_IPTABLES # ARP tables config IP_NF_ARPTABLES - tristate "ARP tables support" - select NETFILTER_XTABLES - select NETFILTER_FAMILY_ARP - depends on NETFILTER_ADVANCED - help - arptables is a general, extensible packet identification framework. - The ARP packet filtering and mangling (manipulation)subsystems - use this: say Y or M here if you want to use either of those. + tristate - To compile it as a module, choose M here. If unsure, say N. - -if IP_NF_ARPTABLES +config NFT_COMPAT_ARP + tristate + depends on NF_TABLES_ARP && NFT_COMPAT + default m if NFT_COMPAT=m + default y if NFT_COMPAT=y config IP_NF_ARPFILTER - tristate "ARP packet filtering" + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES help ARP packet filtering defines a table `filter', which has a series of rules for simple ARP packet filtering at local input and - local output. On a bridge, you can also specify filtering rules - for forwarded ARP packets. See the man page for arptables(8). + local output. This is only needed for arptables-legacy(8). + Neither arptables-nft nor nftables need this to work. To compile it as a module, choose M here. If unsure, say N. config IP_NF_ARP_MANGLE tristate "ARP payload mangling" + depends on IP_NF_ARPTABLES || NFT_COMPAT_ARP help Allows altering the ARP packet payload: source and destination hardware and network addresses. -endif # IP_NF_ARPTABLES + This option is needed by both arptables-legacy and arptables-nft. + It is not used by nftables. endmenu From a9525c7f6219cee9284c0031c5930e8d41384677 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 24 Jan 2024 10:21:11 +0100 Subject: [PATCH 0404/2255] netfilter: xtables: allow xtables-nft only builds Add hidden IP(6)_NF_IPTABLES_LEGACY symbol. When any of the "old" builtin tables are enabled the "old" iptables interface will be supported. To disable the old set/getsockopt interface the existing options for the builtin tables need to be turned off: CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_FILTER is not set CONFIG_IP_NF_NAT is not set CONFIG_IP_NF_MANGLE is not set CONFIG_IP_NF_RAW is not set CONFIG_IP_NF_SECURITY is not set Same for CONFIG_IP6_NF_ variants. This allows to build a kernel that only supports ip(6)tables-nft (iptables-over-nftables api). In the future the _LEGACY symbol will become visible and the select statements will be turned into 'depends on', but for now be on safe side so "make oldconfig" won't break things. Signed-off-by: Florian Westphal --- net/ipv4/netfilter/Kconfig | 15 ++++++++++++--- net/ipv4/netfilter/Makefile | 2 +- net/ipv6/netfilter/Kconfig | 20 ++++++++++++++------ net/ipv6/netfilter/Makefile | 2 +- net/netfilter/Kconfig | 12 ++++++------ 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 070475392236..783523087281 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -10,6 +10,10 @@ config NF_DEFRAG_IPV4 tristate default n +# old sockopt interface and eval loop +config IP_NF_IPTABLES_LEGACY + tristate + config NF_SOCKET_IPV4 tristate "IPv4 socket lookup support" help @@ -152,7 +156,7 @@ config IP_NF_MATCH_ECN config IP_NF_MATCH_RPFILTER tristate '"rpfilter" reverse path filter match support' depends on NETFILTER_ADVANCED - depends on IP_NF_MANGLE || IP_NF_RAW + depends on IP_NF_MANGLE || IP_NF_RAW || NFT_COMPAT help This option allows you to match packets whose replies would go out via the interface the packet came in. @@ -173,6 +177,7 @@ config IP_NF_MATCH_TTL config IP_NF_FILTER tristate "Packet filtering" default m if NETFILTER_ADVANCED=n + select IP_NF_IPTABLES_LEGACY help Packet filtering defines a table `filter', which has a series of rules for simple packet filtering at local input, forwarding and @@ -182,7 +187,7 @@ config IP_NF_FILTER config IP_NF_TARGET_REJECT tristate "REJECT target support" - depends on IP_NF_FILTER + depends on IP_NF_FILTER || NFT_COMPAT select NF_REJECT_IPV4 default m if NETFILTER_ADVANCED=n help @@ -212,6 +217,7 @@ config IP_NF_NAT default m if NETFILTER_ADVANCED=n select NF_NAT select NETFILTER_XT_NAT + select IP6_NF_IPTABLES_LEGACY help This enables the `nat' table in iptables. This allows masquerading, port forwarding and other forms of full Network Address Port @@ -252,6 +258,7 @@ endif # IP_NF_NAT config IP_NF_MANGLE tristate "Packet mangling" default m if NETFILTER_ADVANCED=n + select IP_NF_IPTABLES_LEGACY help This option adds a `mangle' table to iptables: see the man page for iptables(8). This table is used for various packet alterations @@ -261,7 +268,7 @@ config IP_NF_MANGLE config IP_NF_TARGET_ECN tristate "ECN target support" - depends on IP_NF_MANGLE + depends on IP_NF_MANGLE || NFT_COMPAT depends on NETFILTER_ADVANCED help This option adds a `ECN' target, which can be used in the iptables mangle @@ -286,6 +293,7 @@ config IP_NF_TARGET_TTL # raw + specific targets config IP_NF_RAW tristate 'raw table support (required for NOTRACK/TRACE)' + select IP_NF_IPTABLES_LEGACY help This option adds a `raw' table to iptables. This table is the very first in the netfilter framework and hooks in at the PREROUTING @@ -299,6 +307,7 @@ config IP_NF_SECURITY tristate "Security table" depends on SECURITY depends on NETFILTER_ADVANCED + select IP_NF_IPTABLES_LEGACY help This option adds a `security' table to iptables, for use with Mandatory Access Control (MAC) policy. diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 5a26f9de1ab9..85502d4dfbb4 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_NFT_FIB_IPV4) += nft_fib_ipv4.o obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o # generic IP tables -obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +obj-$(CONFIG_IP_NF_IPTABLES_LEGACY) += ip_tables.o # the three instances of ip_tables obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 0ba62f4868f9..f3c8e2d918e1 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -6,6 +6,10 @@ menu "IPv6: Netfilter Configuration" depends on INET && IPV6 && NETFILTER +# old sockopt interface and eval loop +config IP6_NF_IPTABLES_LEGACY + tristate + config NF_SOCKET_IPV6 tristate "IPv6 socket lookup support" help @@ -147,7 +151,7 @@ config IP6_NF_MATCH_MH config IP6_NF_MATCH_RPFILTER tristate '"rpfilter" reverse path filter match support' depends on NETFILTER_ADVANCED - depends on IP6_NF_MANGLE || IP6_NF_RAW + depends on IP6_NF_MANGLE || IP6_NF_RAW || NFT_COMPAT help This option allows you to match packets whose replies would go out via the interface the packet came in. @@ -186,6 +190,8 @@ config IP6_NF_TARGET_HL config IP6_NF_FILTER tristate "Packet filtering" default m if NETFILTER_ADVANCED=n + select IP6_NF_IPTABLES_LEGACY + tristate help Packet filtering defines a table `filter', which has a series of rules for simple packet filtering at local input, forwarding and @@ -195,7 +201,7 @@ config IP6_NF_FILTER config IP6_NF_TARGET_REJECT tristate "REJECT target support" - depends on IP6_NF_FILTER + depends on IP6_NF_FILTER || NFT_COMPAT select NF_REJECT_IPV6 default m if NETFILTER_ADVANCED=n help @@ -221,6 +227,7 @@ config IP6_NF_TARGET_SYNPROXY config IP6_NF_MANGLE tristate "Packet mangling" default m if NETFILTER_ADVANCED=n + select IP6_NF_IPTABLES_LEGACY help This option adds a `mangle' table to iptables: see the man page for iptables(8). This table is used for various packet alterations @@ -230,6 +237,7 @@ config IP6_NF_MANGLE config IP6_NF_RAW tristate 'raw table support (required for TRACE)' + select IP6_NF_IPTABLES_LEGACY help This option adds a `raw' table to ip6tables. This table is the very first in the netfilter framework and hooks in at the PREROUTING @@ -243,6 +251,7 @@ config IP6_NF_SECURITY tristate "Security table" depends on SECURITY depends on NETFILTER_ADVANCED + select IP6_NF_IPTABLES_LEGACY help This option adds a `security' table to iptables, for use with Mandatory Access Control (MAC) policy. @@ -254,6 +263,7 @@ config IP6_NF_NAT depends on NF_CONNTRACK depends on NETFILTER_ADVANCED select NF_NAT + select IP6_NF_IPTABLES_LEGACY select NETFILTER_XT_NAT help This enables the `nat' table in ip6tables. This allows masquerading, @@ -262,25 +272,23 @@ config IP6_NF_NAT To compile it as a module, choose M here. If unsure, say N. -if IP6_NF_NAT - config IP6_NF_TARGET_MASQUERADE tristate "MASQUERADE target support" select NETFILTER_XT_TARGET_MASQUERADE + depends on IP6_NF_NAT help This is a backwards-compat option for the user's convenience (e.g. when running oldconfig). It selects NETFILTER_XT_TARGET_MASQUERADE. config IP6_NF_TARGET_NPT tristate "NPT (Network Prefix translation) target support" + depends on IP6_NF_NAT || NFT_COMPAT help This option adds the `SNPT' and `DNPT' target, which perform stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296. To compile it as a module, choose M here. If unsure, say N. -endif # IP6_NF_NAT - endif # IP6_NF_IPTABLES endmenu diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index b8d6dc9aeeb6..66ce6fa5b2f5 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -4,7 +4,7 @@ # # Link order matters here. -obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o +obj-$(CONFIG_IP6_NF_IPTABLES_LEGACY) += ip6_tables.o obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 441d1f134110..df2dc21304ef 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -818,7 +818,7 @@ config NETFILTER_XT_TARGET_AUDIT config NETFILTER_XT_TARGET_CHECKSUM tristate "CHECKSUM target support" - depends on IP_NF_MANGLE || IP6_NF_MANGLE + depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT depends on NETFILTER_ADVANCED help This option adds a `CHECKSUM' target, which can be used in the iptables mangle @@ -869,7 +869,7 @@ config NETFILTER_XT_TARGET_CONNSECMARK config NETFILTER_XT_TARGET_CT tristate '"CT" target support' depends on NF_CONNTRACK - depends on IP_NF_RAW || IP6_NF_RAW + depends on IP_NF_RAW || IP6_NF_RAW || NFT_COMPAT depends on NETFILTER_ADVANCED help This options adds a `CT' target, which allows to specify initial @@ -880,7 +880,7 @@ config NETFILTER_XT_TARGET_CT config NETFILTER_XT_TARGET_DSCP tristate '"DSCP" and "TOS" target support' - depends on IP_NF_MANGLE || IP6_NF_MANGLE + depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT depends on NETFILTER_ADVANCED help This option adds a `DSCP' target, which allows you to manipulate @@ -896,7 +896,7 @@ config NETFILTER_XT_TARGET_DSCP config NETFILTER_XT_TARGET_HL tristate '"HL" hoplimit target support' - depends on IP_NF_MANGLE || IP6_NF_MANGLE + depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT depends on NETFILTER_ADVANCED help This option adds the "HL" (for IPv6) and "TTL" (for IPv4) @@ -1080,7 +1080,7 @@ config NETFILTER_XT_TARGET_TPROXY depends on NETFILTER_ADVANCED depends on IPV6 || IPV6=n depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n - depends on IP_NF_MANGLE + depends on IP_NF_MANGLE || NFT_COMPAT select NF_DEFRAG_IPV4 select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n select NF_TPROXY_IPV4 @@ -1147,7 +1147,7 @@ config NETFILTER_XT_TARGET_TCPMSS config NETFILTER_XT_TARGET_TCPOPTSTRIP tristate '"TCPOPTSTRIP" target support' - depends on IP_NF_MANGLE || IP6_NF_MANGLE + depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT depends on NETFILTER_ADVANCED help This option adds a "TCPOPTSTRIP" target, which allows you to strip From 7ad269787b6615ca56bb161063331991fce51abf Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 24 Jan 2024 10:21:12 +0100 Subject: [PATCH 0405/2255] netfilter: ebtables: allow xtables-nft only builds Same patch as previous one, but for ebtables. To build a kernel that only supports ebtables-nft, the builtin tables need to be disabled, i.e.: CONFIG_BRIDGE_EBT_BROUTE=n CONFIG_BRIDGE_EBT_T_FILTER=n CONFIG_BRIDGE_EBT_T_NAT=n The ebtables specific extensions can then be used nftables' NFT_COMPAT interface. Signed-off-by: Florian Westphal --- net/bridge/netfilter/Kconfig | 7 +++++++ net/bridge/netfilter/Makefile | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 7f304a19ac1b..104c0125e32e 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -39,6 +39,10 @@ config NF_CONNTRACK_BRIDGE To compile it as a module, choose M here. If unsure, say N. +# old sockopt interface and eval loop +config BRIDGE_NF_EBTABLES_LEGACY + tristate + menuconfig BRIDGE_NF_EBTABLES tristate "Ethernet Bridge tables (ebtables) support" depends on BRIDGE && NETFILTER && NETFILTER_XTABLES @@ -55,6 +59,7 @@ if BRIDGE_NF_EBTABLES # config BRIDGE_EBT_BROUTE tristate "ebt: broute table support" + select BRIDGE_NF_EBTABLES_LEGACY help The ebtables broute table is used to define rules that decide between bridging and routing frames, giving Linux the functionality of a @@ -65,6 +70,7 @@ config BRIDGE_EBT_BROUTE config BRIDGE_EBT_T_FILTER tristate "ebt: filter table support" + select BRIDGE_NF_EBTABLES_LEGACY help The ebtables filter table is used to define frame filtering rules at local input, forwarding and local output. See the man page for @@ -74,6 +80,7 @@ config BRIDGE_EBT_T_FILTER config BRIDGE_EBT_T_NAT tristate "ebt: nat table support" + select BRIDGE_NF_EBTABLES_LEGACY help The ebtables nat table is used to define rules that alter the MAC source address (MAC SNAT) or the MAC destination address (MAC DNAT). diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 1c9ce49ab651..b9a1303da977 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_NFT_BRIDGE_REJECT) += nft_reject_bridge.o # connection tracking obj-$(CONFIG_NF_CONNTRACK_BRIDGE) += nf_conntrack_bridge.o -obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o +obj-$(CONFIG_BRIDGE_NF_EBTABLES_LEGACY) += ebtables.o # tables obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o From 29788f39a4171dd48a6d19eb78cf2ab168c4349a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 29 Jan 2024 11:33:26 -0300 Subject: [PATCH 0406/2255] bpftool: Be more portable by using POSIX's basename() musl libc had the basename() prototype in string.h, but this is a glibc-ism, now they removed the _GNU_SOURCE bits in their devel distro, Alpine Linux edge: https://git.musl-libc.org/cgit/musl/commit/?id=725e17ed6dff4d0cd22487bb64470881e86a92e7 So lets use the POSIX version, the whole rationale is spelled out at: https://gitlab.alpinelinux.org/alpine/aports/-/issues/15643 Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Daniel Borkmann Acked-by: Jiri Olsa Acked-by: Quentin Monnet Link: https://lore.kernel.org/lkml/ZZhsPs00TI75RdAr@kernel.org Link: https://lore.kernel.org/bpf/Zbe3NuOgaupvUcpF@kernel.org --- tools/bpf/bpftool/gen.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index ee3ce2b8000d..a9334c57e859 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -56,9 +57,11 @@ static bool str_has_suffix(const char *str, const char *suffix) static void get_obj_name(char *name, const char *file) { - /* Using basename() GNU version which doesn't modify arg. */ - strncpy(name, basename(file), MAX_OBJ_NAME_LEN - 1); - name[MAX_OBJ_NAME_LEN - 1] = '\0'; + char file_copy[PATH_MAX]; + + /* Using basename() POSIX version to be more portable. */ + strncpy(file_copy, file, PATH_MAX - 1)[PATH_MAX - 1] = '\0'; + strncpy(name, basename(file_copy), MAX_OBJ_NAME_LEN - 1)[MAX_OBJ_NAME_LEN - 1] = '\0'; if (str_has_suffix(name, ".o")) name[strlen(name) - 2] = '\0'; sanitize_identifier(name); From ad57654053805bf9a62602aaec74cc78edb6f235 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 26 Jan 2024 14:09:44 -0800 Subject: [PATCH 0407/2255] libbpf: Fix faccessat() usage on Android Android implementation of libc errors out with -EINVAL in faccessat() if passed AT_EACCESS ([0]), this leads to ridiculous issue with libbpf refusing to load /sys/kernel/btf/vmlinux on Androids ([1]). Fix by detecting Android and redefining AT_EACCESS to 0, it's equivalent on Android. [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#50 [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-1911324250 Fixes: 6a4ab8869d0b ("libbpf: Fix the case of running as non-root with capabilities") Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/20240126220944.2497665-1-andrii@kernel.org --- tools/lib/bpf/libbpf_internal.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 930cc9616527..5b30f3b67a02 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -19,6 +19,20 @@ #include #include "relo_core.h" +/* Android's libc doesn't support AT_EACCESS in faccessat() implementation + * ([0]), and just returns -EINVAL even if file exists and is accessible. + * See [1] for issues caused by this. + * + * So just redefine it to 0 on Android. + * + * [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#50 + * [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-1911324250 + */ +#ifdef __ANDROID__ +#undef AT_EACCESS +#define AT_EACCESS 0 +#endif + /* make sure libbpf doesn't use kernel-only integer typedefs */ #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64 From e33758f7493c9ad8cf6960bcf7c70f5761f3acfb Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Mon, 15 Jan 2024 13:12:30 +0000 Subject: [PATCH 0408/2255] riscv, bpf: Unify 32-bit sign-extension to emit_sextw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For code unification, add emit_sextw wrapper to unify all the 32-bit sign-extension operations. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20240115131235.2914289-2-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 5 +++++ arch/riscv/net/bpf_jit_comp64.c | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index a5ce1ab76ece..f9f8d86e762f 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -1087,6 +1087,11 @@ static inline void emit_subw(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx) emit(rv_subw(rd, rs1, rs2), ctx); } +static inline void emit_sextw(u8 rd, u8 rs, struct rv_jit_context *ctx) +{ + emit_addiw(rd, rs, 0, ctx); +} + #endif /* __riscv_xlen == 64 */ void bpf_jit_build_prologue(struct rv_jit_context *ctx); diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 719a97e7edb2..46aaf5c1f95c 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -417,8 +417,8 @@ static void emit_zext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) static void emit_sext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) { - emit_addiw(RV_REG_T2, *rd, 0, ctx); - emit_addiw(RV_REG_T1, *rs, 0, ctx); + emit_sextw(RV_REG_T2, *rd, ctx); + emit_sextw(RV_REG_T1, *rs, ctx); *rd = RV_REG_T2; *rs = RV_REG_T1; } @@ -433,7 +433,7 @@ static void emit_zext_32_rd_t1(u8 *rd, struct rv_jit_context *ctx) static void emit_sext_32_rd(u8 *rd, struct rv_jit_context *ctx) { - emit_addiw(RV_REG_T2, *rd, 0, ctx); + emit_sextw(RV_REG_T2, *rd, ctx); *rd = RV_REG_T2; } @@ -1104,7 +1104,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, emit_srai(rd, RV_REG_T1, 64 - insn->off, ctx); break; case 32: - emit_addiw(rd, rs, 0, ctx); + emit_sextw(rd, rs, ctx); break; } if (!is64 && !aux->verifier_zext) @@ -1504,7 +1504,7 @@ out_be: * as t1 is used only in comparison against zero. */ if (!is64 && imm < 0) - emit_addiw(RV_REG_T1, RV_REG_T1, 0, ctx); + emit_sextw(RV_REG_T1, RV_REG_T1, ctx); e = ctx->ninsns; rvoff -= ninsns_rvoff(e - s); emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, ctx); From 914c7a5ff18a225f7df254ae3433574f3d47b711 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Mon, 15 Jan 2024 13:12:31 +0000 Subject: [PATCH 0409/2255] riscv, bpf: Unify 32-bit zero-extension to emit_zextw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For code unification, add emit_zextw wrapper to unify all the 32-bit zero-extension operations. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20240115131235.2914289-3-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 6 +++ arch/riscv/net/bpf_jit_comp64.c | 80 +++++++++++++++------------------ 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index f9f8d86e762f..e30501b46f8f 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -1092,6 +1092,12 @@ static inline void emit_sextw(u8 rd, u8 rs, struct rv_jit_context *ctx) emit_addiw(rd, rs, 0, ctx); } +static inline void emit_zextw(u8 rd, u8 rs, struct rv_jit_context *ctx) +{ + emit_slli(rd, rs, 32, ctx); + emit_srli(rd, rd, 32, ctx); +} + #endif /* __riscv_xlen == 64 */ void bpf_jit_build_prologue(struct rv_jit_context *ctx); diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 46aaf5c1f95c..d3d764ed32a2 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -326,12 +326,6 @@ static void emit_branch(u8 cond, u8 rd, u8 rs, int rvoff, emit(rv_jalr(RV_REG_ZERO, RV_REG_T1, lower), ctx); } -static void emit_zext_32(u8 reg, struct rv_jit_context *ctx) -{ - emit_slli(reg, reg, 32, ctx); - emit_srli(reg, reg, 32, ctx); -} - static int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx) { int tc_ninsn, off, start_insn = ctx->ninsns; @@ -346,7 +340,7 @@ static int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx) */ tc_ninsn = insn ? ctx->offset[insn] - ctx->offset[insn - 1] : ctx->offset[0]; - emit_zext_32(RV_REG_A2, ctx); + emit_zextw(RV_REG_A2, RV_REG_A2, ctx); off = offsetof(struct bpf_array, map.max_entries); if (is_12b_check(off, insn)) @@ -408,9 +402,9 @@ static void init_regs(u8 *rd, u8 *rs, const struct bpf_insn *insn, static void emit_zext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) { emit_mv(RV_REG_T2, *rd, ctx); - emit_zext_32(RV_REG_T2, ctx); + emit_zextw(RV_REG_T2, RV_REG_T2, ctx); emit_mv(RV_REG_T1, *rs, ctx); - emit_zext_32(RV_REG_T1, ctx); + emit_zextw(RV_REG_T1, RV_REG_T1, ctx); *rd = RV_REG_T2; *rs = RV_REG_T1; } @@ -426,8 +420,8 @@ static void emit_sext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) static void emit_zext_32_rd_t1(u8 *rd, struct rv_jit_context *ctx) { emit_mv(RV_REG_T2, *rd, ctx); - emit_zext_32(RV_REG_T2, ctx); - emit_zext_32(RV_REG_T1, ctx); + emit_zextw(RV_REG_T2, RV_REG_T2, ctx); + emit_zextw(RV_REG_T1, RV_REG_T2, ctx); *rd = RV_REG_T2; } @@ -519,32 +513,32 @@ static void emit_atomic(u8 rd, u8 rs, s16 off, s32 imm, bool is64, emit(is64 ? rv_amoadd_d(rs, rs, rd, 0, 0) : rv_amoadd_w(rs, rs, rd, 0, 0), ctx); if (!is64) - emit_zext_32(rs, ctx); + emit_zextw(rs, rs, ctx); break; case BPF_AND | BPF_FETCH: emit(is64 ? rv_amoand_d(rs, rs, rd, 0, 0) : rv_amoand_w(rs, rs, rd, 0, 0), ctx); if (!is64) - emit_zext_32(rs, ctx); + emit_zextw(rs, rs, ctx); break; case BPF_OR | BPF_FETCH: emit(is64 ? rv_amoor_d(rs, rs, rd, 0, 0) : rv_amoor_w(rs, rs, rd, 0, 0), ctx); if (!is64) - emit_zext_32(rs, ctx); + emit_zextw(rs, rs, ctx); break; case BPF_XOR | BPF_FETCH: emit(is64 ? rv_amoxor_d(rs, rs, rd, 0, 0) : rv_amoxor_w(rs, rs, rd, 0, 0), ctx); if (!is64) - emit_zext_32(rs, ctx); + emit_zextw(rs, rs, ctx); break; /* src_reg = atomic_xchg(dst_reg + off16, src_reg); */ case BPF_XCHG: emit(is64 ? rv_amoswap_d(rs, rs, rd, 0, 0) : rv_amoswap_w(rs, rs, rd, 0, 0), ctx); if (!is64) - emit_zext_32(rs, ctx); + emit_zextw(rs, rs, ctx); break; /* r0 = atomic_cmpxchg(dst_reg + off16, r0, src_reg); */ case BPF_CMPXCHG: @@ -1091,7 +1085,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, case BPF_ALU64 | BPF_MOV | BPF_X: if (imm == 1) { /* Special mov32 for zext */ - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; } switch (insn->off) { @@ -1108,7 +1102,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, break; } if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; /* dst = dst OP src */ @@ -1116,7 +1110,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, case BPF_ALU64 | BPF_ADD | BPF_X: emit_add(rd, rd, rs, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_SUB | BPF_X: case BPF_ALU64 | BPF_SUB | BPF_X: @@ -1126,31 +1120,31 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, emit_subw(rd, rd, rs, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_AND | BPF_X: case BPF_ALU64 | BPF_AND | BPF_X: emit_and(rd, rd, rs, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_OR | BPF_X: case BPF_ALU64 | BPF_OR | BPF_X: emit_or(rd, rd, rs, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_XOR | BPF_X: case BPF_ALU64 | BPF_XOR | BPF_X: emit_xor(rd, rd, rs, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_MUL | BPF_X: case BPF_ALU64 | BPF_MUL | BPF_X: emit(is64 ? rv_mul(rd, rd, rs) : rv_mulw(rd, rd, rs), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_DIV | BPF_X: case BPF_ALU64 | BPF_DIV | BPF_X: @@ -1159,7 +1153,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, else emit(is64 ? rv_divu(rd, rd, rs) : rv_divuw(rd, rd, rs), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_MOD | BPF_X: case BPF_ALU64 | BPF_MOD | BPF_X: @@ -1168,25 +1162,25 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, else emit(is64 ? rv_remu(rd, rd, rs) : rv_remuw(rd, rd, rs), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_LSH | BPF_X: case BPF_ALU64 | BPF_LSH | BPF_X: emit(is64 ? rv_sll(rd, rd, rs) : rv_sllw(rd, rd, rs), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_RSH | BPF_X: case BPF_ALU64 | BPF_RSH | BPF_X: emit(is64 ? rv_srl(rd, rd, rs) : rv_srlw(rd, rd, rs), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_ARSH | BPF_X: case BPF_ALU64 | BPF_ARSH | BPF_X: emit(is64 ? rv_sra(rd, rd, rs) : rv_sraw(rd, rd, rs), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; /* dst = -dst */ @@ -1194,7 +1188,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, case BPF_ALU64 | BPF_NEG: emit_sub(rd, RV_REG_ZERO, rd, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; /* dst = BSWAP##imm(dst) */ @@ -1206,7 +1200,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, break; case 32: if (!aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case 64: /* Do nothing */ @@ -1268,7 +1262,7 @@ out_be: case BPF_ALU64 | BPF_MOV | BPF_K: emit_imm(rd, imm, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; /* dst = dst OP imm */ @@ -1281,7 +1275,7 @@ out_be: emit_add(rd, rd, RV_REG_T1, ctx); } if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_SUB | BPF_K: case BPF_ALU64 | BPF_SUB | BPF_K: @@ -1292,7 +1286,7 @@ out_be: emit_sub(rd, rd, RV_REG_T1, ctx); } if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_AND | BPF_K: case BPF_ALU64 | BPF_AND | BPF_K: @@ -1303,7 +1297,7 @@ out_be: emit_and(rd, rd, RV_REG_T1, ctx); } if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_OR | BPF_K: case BPF_ALU64 | BPF_OR | BPF_K: @@ -1314,7 +1308,7 @@ out_be: emit_or(rd, rd, RV_REG_T1, ctx); } if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_XOR | BPF_K: case BPF_ALU64 | BPF_XOR | BPF_K: @@ -1325,7 +1319,7 @@ out_be: emit_xor(rd, rd, RV_REG_T1, ctx); } if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_MUL | BPF_K: case BPF_ALU64 | BPF_MUL | BPF_K: @@ -1333,7 +1327,7 @@ out_be: emit(is64 ? rv_mul(rd, rd, RV_REG_T1) : rv_mulw(rd, rd, RV_REG_T1), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_DIV | BPF_K: case BPF_ALU64 | BPF_DIV | BPF_K: @@ -1345,7 +1339,7 @@ out_be: emit(is64 ? rv_divu(rd, rd, RV_REG_T1) : rv_divuw(rd, rd, RV_REG_T1), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_MOD | BPF_K: case BPF_ALU64 | BPF_MOD | BPF_K: @@ -1357,14 +1351,14 @@ out_be: emit(is64 ? rv_remu(rd, rd, RV_REG_T1) : rv_remuw(rd, rd, RV_REG_T1), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_LSH | BPF_K: case BPF_ALU64 | BPF_LSH | BPF_K: emit_slli(rd, rd, imm, ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_RSH | BPF_K: case BPF_ALU64 | BPF_RSH | BPF_K: @@ -1374,7 +1368,7 @@ out_be: emit(rv_srliw(rd, rd, imm), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; case BPF_ALU | BPF_ARSH | BPF_K: case BPF_ALU64 | BPF_ARSH | BPF_K: @@ -1384,7 +1378,7 @@ out_be: emit(rv_sraiw(rd, rd, imm), ctx); if (!is64 && !aux->verifier_zext) - emit_zext_32(rd, ctx); + emit_zextw(rd, rd, ctx); break; /* JUMP off */ From 361db44c3c59cde05e9926647f16255e274a37f4 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Mon, 15 Jan 2024 13:12:32 +0000 Subject: [PATCH 0410/2255] riscv, bpf: Simplify sext and zext logics in branch instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are many extension helpers in the current branch instructions, and the implementation is a bit complicated. We simplify this logic through two simple extension helpers with alternate register. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20240115131235.2914289-4-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit_comp64.c | 79 +++++++++++++-------------------- 1 file changed, 31 insertions(+), 48 deletions(-) diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index d3d764ed32a2..0a26842535ea 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -141,6 +141,19 @@ static bool in_auipc_jalr_range(s64 val) val < ((1L << 31) - (1L << 11)); } +/* Modify rd pointer to alternate reg to avoid corrupting original reg */ +static void emit_sextw_alt(u8 *rd, u8 ra, struct rv_jit_context *ctx) +{ + emit_sextw(ra, *rd, ctx); + *rd = ra; +} + +static void emit_zextw_alt(u8 *rd, u8 ra, struct rv_jit_context *ctx) +{ + emit_zextw(ra, *rd, ctx); + *rd = ra; +} + /* Emit fixed-length instructions for address */ static int emit_addr(u8 rd, u64 addr, bool extra_pass, struct rv_jit_context *ctx) { @@ -399,38 +412,6 @@ static void init_regs(u8 *rd, u8 *rs, const struct bpf_insn *insn, *rs = bpf_to_rv_reg(insn->src_reg, ctx); } -static void emit_zext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) -{ - emit_mv(RV_REG_T2, *rd, ctx); - emit_zextw(RV_REG_T2, RV_REG_T2, ctx); - emit_mv(RV_REG_T1, *rs, ctx); - emit_zextw(RV_REG_T1, RV_REG_T1, ctx); - *rd = RV_REG_T2; - *rs = RV_REG_T1; -} - -static void emit_sext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) -{ - emit_sextw(RV_REG_T2, *rd, ctx); - emit_sextw(RV_REG_T1, *rs, ctx); - *rd = RV_REG_T2; - *rs = RV_REG_T1; -} - -static void emit_zext_32_rd_t1(u8 *rd, struct rv_jit_context *ctx) -{ - emit_mv(RV_REG_T2, *rd, ctx); - emit_zextw(RV_REG_T2, RV_REG_T2, ctx); - emit_zextw(RV_REG_T1, RV_REG_T2, ctx); - *rd = RV_REG_T2; -} - -static void emit_sext_32_rd(u8 *rd, struct rv_jit_context *ctx) -{ - emit_sextw(RV_REG_T2, *rd, ctx); - *rd = RV_REG_T2; -} - static int emit_jump_and_link(u8 rd, s64 rvoff, bool fixed_addr, struct rv_jit_context *ctx) { @@ -1419,10 +1400,13 @@ out_be: rvoff = rv_offset(i, off, ctx); if (!is64) { s = ctx->ninsns; - if (is_signed_bpf_cond(BPF_OP(code))) - emit_sext_32_rd_rs(&rd, &rs, ctx); - else - emit_zext_32_rd_rs(&rd, &rs, ctx); + if (is_signed_bpf_cond(BPF_OP(code))) { + emit_sextw_alt(&rs, RV_REG_T1, ctx); + emit_sextw_alt(&rd, RV_REG_T2, ctx); + } else { + emit_zextw_alt(&rs, RV_REG_T1, ctx); + emit_zextw_alt(&rd, RV_REG_T2, ctx); + } e = ctx->ninsns; /* Adjust for extra insns */ @@ -1433,8 +1417,7 @@ out_be: /* Adjust for and */ rvoff -= 4; emit_and(RV_REG_T1, rd, rs, ctx); - emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, - ctx); + emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, ctx); } else { emit_branch(BPF_OP(code), rd, rs, rvoff, ctx); } @@ -1463,18 +1446,18 @@ out_be: case BPF_JMP32 | BPF_JSLE | BPF_K: rvoff = rv_offset(i, off, ctx); s = ctx->ninsns; - if (imm) { + if (imm) emit_imm(RV_REG_T1, imm, ctx); - rs = RV_REG_T1; - } else { - /* If imm is 0, simply use zero register. */ - rs = RV_REG_ZERO; - } + rs = imm ? RV_REG_T1 : RV_REG_ZERO; if (!is64) { - if (is_signed_bpf_cond(BPF_OP(code))) - emit_sext_32_rd(&rd, ctx); - else - emit_zext_32_rd_t1(&rd, ctx); + if (is_signed_bpf_cond(BPF_OP(code))) { + emit_sextw_alt(&rd, RV_REG_T2, ctx); + /* rs has been sign extended */ + } else { + emit_zextw_alt(&rd, RV_REG_T2, ctx); + if (imm) + emit_zextw(rs, rs, ctx); + } } e = ctx->ninsns; From 647b93f65daa128d9a0e4aac744a5fcf5f58b2d2 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Mon, 15 Jan 2024 13:12:33 +0000 Subject: [PATCH 0411/2255] riscv, bpf: Add necessary Zbb instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add necessary Zbb instructions introduced by [0] to reduce code size and improve performance of RV64 JIT. Meanwhile, a runtime deteted helper is added to check whether the CPU supports Zbb instructions. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Acked-by: Björn Töpel Link: https://github.com/riscv/riscv-bitmanip/releases/download/1.0.0/bitmanip-1.0.0-38-g865e7a7.pdf [0] Link: https://lore.kernel.org/bpf/20240115131235.2914289-5-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index e30501b46f8f..51f6d214086f 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -18,6 +18,11 @@ static inline bool rvc_enabled(void) return IS_ENABLED(CONFIG_RISCV_ISA_C); } +static inline bool rvzbb_enabled(void) +{ + return IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && riscv_has_extension_likely(RISCV_ISA_EXT_ZBB); +} + enum { RV_REG_ZERO = 0, /* The constant value 0 */ RV_REG_RA = 1, /* Return address */ @@ -730,6 +735,33 @@ static inline u16 rvc_swsp(u32 imm8, u8 rs2) return rv_css_insn(0x6, imm, rs2, 0x2); } +/* RVZBB instrutions. */ +static inline u32 rvzbb_sextb(u8 rd, u8 rs1) +{ + return rv_i_insn(0x604, rs1, 1, rd, 0x13); +} + +static inline u32 rvzbb_sexth(u8 rd, u8 rs1) +{ + return rv_i_insn(0x605, rs1, 1, rd, 0x13); +} + +static inline u32 rvzbb_zexth(u8 rd, u8 rs) +{ + if (IS_ENABLED(CONFIG_64BIT)) + return rv_i_insn(0x80, rs, 4, rd, 0x3b); + + return rv_i_insn(0x80, rs, 4, rd, 0x33); +} + +static inline u32 rvzbb_rev8(u8 rd, u8 rs) +{ + if (IS_ENABLED(CONFIG_64BIT)) + return rv_i_insn(0x6b8, rs, 5, rd, 0x13); + + return rv_i_insn(0x698, rs, 5, rd, 0x13); +} + /* * RV64-only instructions. * From 519fb722bea09ae2664ad21f8ef4360fb799eb2f Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Mon, 15 Jan 2024 13:12:34 +0000 Subject: [PATCH 0412/2255] riscv, bpf: Optimize sign-extention mov insns with Zbb support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 8-bit and 16-bit sign-extention wraper with Zbb support to optimize sign-extension mov instructions. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20240115131235.2914289-6-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 22 ++++++++++++++++++++++ arch/riscv/net/bpf_jit_comp64.c | 5 +++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index 51f6d214086f..b00c5c0591d2 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -1119,6 +1119,28 @@ static inline void emit_subw(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx) emit(rv_subw(rd, rs1, rs2), ctx); } +static inline void emit_sextb(u8 rd, u8 rs, struct rv_jit_context *ctx) +{ + if (rvzbb_enabled()) { + emit(rvzbb_sextb(rd, rs), ctx); + return; + } + + emit_slli(rd, rs, 56, ctx); + emit_srai(rd, rd, 56, ctx); +} + +static inline void emit_sexth(u8 rd, u8 rs, struct rv_jit_context *ctx) +{ + if (rvzbb_enabled()) { + emit(rvzbb_sexth(rd, rs), ctx); + return; + } + + emit_slli(rd, rs, 48, ctx); + emit_srai(rd, rd, 48, ctx); +} + static inline void emit_sextw(u8 rd, u8 rs, struct rv_jit_context *ctx) { emit_addiw(rd, rs, 0, ctx); diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 0a26842535ea..fc1a334e2f70 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1074,9 +1074,10 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, emit_mv(rd, rs, ctx); break; case 8: + emit_sextb(rd, rs, ctx); + break; case 16: - emit_slli(RV_REG_T1, rs, 64 - insn->off, ctx); - emit_srai(rd, RV_REG_T1, 64 - insn->off, ctx); + emit_sexth(rd, rs, ctx); break; case 32: emit_sextw(rd, rs, ctx); From 06a33d024838414432b6c0f51f994e7f1695b74f Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Mon, 15 Jan 2024 13:12:35 +0000 Subject: [PATCH 0413/2255] riscv, bpf: Optimize bswap insns with Zbb support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Optimize bswap instructions by rev8 Zbb instruction conbined with srli instruction. And Optimize 16-bit zero-extension with Zbb support. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20240115131235.2914289-7-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 69 +++++++++++++++++++++++++++++++++ arch/riscv/net/bpf_jit_comp64.c | 50 +----------------------- 2 files changed, 71 insertions(+), 48 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index b00c5c0591d2..8b35f12a4452 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -1146,12 +1146,81 @@ static inline void emit_sextw(u8 rd, u8 rs, struct rv_jit_context *ctx) emit_addiw(rd, rs, 0, ctx); } +static inline void emit_zexth(u8 rd, u8 rs, struct rv_jit_context *ctx) +{ + if (rvzbb_enabled()) { + emit(rvzbb_zexth(rd, rs), ctx); + return; + } + + emit_slli(rd, rs, 48, ctx); + emit_srli(rd, rd, 48, ctx); +} + static inline void emit_zextw(u8 rd, u8 rs, struct rv_jit_context *ctx) { emit_slli(rd, rs, 32, ctx); emit_srli(rd, rd, 32, ctx); } +static inline void emit_bswap(u8 rd, s32 imm, struct rv_jit_context *ctx) +{ + if (rvzbb_enabled()) { + int bits = 64 - imm; + + emit(rvzbb_rev8(rd, rd), ctx); + if (bits) + emit_srli(rd, rd, bits, ctx); + return; + } + + emit_li(RV_REG_T2, 0, ctx); + + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); + emit_srli(rd, rd, 8, ctx); + if (imm == 16) + goto out_be; + + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); + emit_srli(rd, rd, 8, ctx); + + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); + emit_srli(rd, rd, 8, ctx); + if (imm == 32) + goto out_be; + + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); + emit_srli(rd, rd, 8, ctx); + + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); + emit_srli(rd, rd, 8, ctx); + + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); + emit_srli(rd, rd, 8, ctx); + + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); + emit_srli(rd, rd, 8, ctx); +out_be: + emit_andi(RV_REG_T1, rd, 0xff, ctx); + emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); + + emit_mv(rd, RV_REG_T2, ctx); +} + #endif /* __riscv_xlen == 64 */ void bpf_jit_build_prologue(struct rv_jit_context *ctx); diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index fc1a334e2f70..fda6b4f6a4c1 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1177,8 +1177,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, case BPF_ALU | BPF_END | BPF_FROM_LE: switch (imm) { case 16: - emit_slli(rd, rd, 48, ctx); - emit_srli(rd, rd, 48, ctx); + emit_zexth(rd, rd, ctx); break; case 32: if (!aux->verifier_zext) @@ -1189,54 +1188,9 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, break; } break; - case BPF_ALU | BPF_END | BPF_FROM_BE: case BPF_ALU64 | BPF_END | BPF_FROM_LE: - emit_li(RV_REG_T2, 0, ctx); - - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); - emit_srli(rd, rd, 8, ctx); - if (imm == 16) - goto out_be; - - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); - emit_srli(rd, rd, 8, ctx); - - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); - emit_srli(rd, rd, 8, ctx); - if (imm == 32) - goto out_be; - - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); - emit_srli(rd, rd, 8, ctx); - - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); - emit_srli(rd, rd, 8, ctx); - - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); - emit_srli(rd, rd, 8, ctx); - - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); - emit_srli(rd, rd, 8, ctx); -out_be: - emit_andi(RV_REG_T1, rd, 0xff, ctx); - emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); - - emit_mv(rd, RV_REG_T2, ctx); + emit_bswap(rd, imm, ctx); break; /* dst = imm */ From f149d03f450b4afab11f5e1ebd8fdfaf7eb24a28 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sun, 28 Jan 2024 19:43:57 +0800 Subject: [PATCH 0414/2255] selftests/bpf: Drop return in bpf_testmod_exit bpf_testmod_exit() does not need to have a return value (given the void), so this patch drops this useless 'return' in it. Signed-off-by: Geliang Tang Signed-off-by: Daniel Borkmann Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/5765b287ea088f0c820f2a834faf9b20fb2f8215.1706442113.git.tanggeliang@kylinos.cn --- tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 8befaf17d454..6f163a0f1c94 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -619,7 +619,7 @@ static void bpf_testmod_exit(void) while (refcount_read(&prog_test_struct.cnt) > 1) msleep(20); - return sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file); + sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file); } module_init(bpf_testmod_init); From efaa47db92451608499ab7edf108bf30141c33db Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Sun, 28 Jan 2024 13:54:43 +0800 Subject: [PATCH 0415/2255] bpf: Remove unused field "mod" in struct bpf_trampoline It seems that the field "mod" in struct bpf_trampoline is not used anywhere after the commit 31bf1dbccfb0 ("bpf: Fix attaching fentry/fexit/fmod_ret/lsm to modules"). So we can just remove it now. Fixes: 31bf1dbccfb0 ("bpf: Fix attaching fentry/fexit/fmod_ret/lsm to modules") Signed-off-by: Menglong Dong Signed-off-by: Daniel Borkmann Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/20240128055443.413291-1-dongmenglong.8@bytedance.com --- include/linux/bpf.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b86bd15a051d..1ebbee1d648e 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1189,7 +1189,6 @@ struct bpf_trampoline { int progs_cnt[BPF_TRAMP_MAX]; /* Executable image of trampoline */ struct bpf_tramp_image *cur_image; - struct module *mod; }; struct bpf_attach_target_info { From ced33f2cfa21a14a292a00e31dc9f85c1bfbda1c Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Sat, 27 Jan 2024 11:46:29 -0800 Subject: [PATCH 0416/2255] docs/bpf: Improve documentation of 64-bit immediate instructions For 64-bit immediate instruction, 'BPF_IMM | BPF_DW | BPF_LD' and src_reg=[0-6], the current documentation describes the 64-bit immediate is constructed by: imm64 = (next_imm << 32) | imm But actually imm64 is only used when src_reg=0. For all other variants (src_reg != 0), 'imm' and 'next_imm' have separate special encoding requirement and imm64 cannot be easily used to describe instruction semantics. This patch clarifies that 64-bit immediate instructions use two 32-bit immediate values instead of a 64-bit immediate value, so later describing individual 64-bit immediate instructions becomes less confusing. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Acked-by: Dave Thaler Link: https://lore.kernel.org/bpf/20240127194629.737589-1-yonghong.song@linux.dev --- .../bpf/standardization/instruction-set.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index af43227b6ee4..fceacca46299 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -166,7 +166,7 @@ Note that most instructions do not use all of the fields. Unused fields shall be cleared to zero. As discussed below in `64-bit immediate instructions`_, a 64-bit immediate -instruction uses a 64-bit immediate value that is constructed as follows. +instruction uses two 32-bit immediate values that are constructed as follows. The 64 bits following the basic instruction contain a pseudo instruction using the same format but with opcode, dst_reg, src_reg, and offset all set to zero, and imm containing the high 32 bits of the immediate value. @@ -181,13 +181,8 @@ This is depicted in the following figure:: '--------------' pseudo instruction -Thus the 64-bit immediate value is constructed as follows: - - imm64 = (next_imm << 32) | imm - -where 'next_imm' refers to the imm value of the pseudo instruction -following the basic instruction. The unused bytes in the pseudo -instruction are reserved and shall be cleared to zero. +Here, the imm value of the pseudo instruction is called 'next_imm'. The unused +bytes in the pseudo instruction are reserved and shall be cleared to zero. Instruction classes ------------------- @@ -590,7 +585,7 @@ defined further below: ========================= ====== === ========================================= =========== ============== opcode construction opcode src pseudocode imm type dst type ========================= ====== === ========================================= =========== ============== -BPF_IMM | BPF_DW | BPF_LD 0x18 0x0 dst = imm64 integer integer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x0 dst = (next_imm << 32) | imm integer integer BPF_IMM | BPF_DW | BPF_LD 0x18 0x1 dst = map_by_fd(imm) map fd map BPF_IMM | BPF_DW | BPF_LD 0x18 0x2 dst = map_val(map_by_fd(imm)) + next_imm map fd data pointer BPF_IMM | BPF_DW | BPF_LD 0x18 0x3 dst = var_addr(imm) variable id data pointer From 0e6d0a9d2348b64df74239e859fa9d6e86cdcdef Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 25 Jan 2024 12:55:04 -0800 Subject: [PATCH 0417/2255] libbpf: integrate __arg_ctx feature detector into kernel_supports() Now that feature detection code is in bpf-next tree, integrate __arg_ctx kernel-side support into kernel_supports() framework. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240125205510.3642094-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/features.c | 58 +++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.c | 65 +-------------------------------- tools/lib/bpf/libbpf_internal.h | 2 + 3 files changed, 61 insertions(+), 64 deletions(-) diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c index 5a5c766bf615..6b0738ad7063 100644 --- a/tools/lib/bpf/features.c +++ b/tools/lib/bpf/features.c @@ -407,6 +407,61 @@ static int probe_kern_btf_enum64(int token_fd) strs, sizeof(strs), token_fd)); } +static int probe_kern_arg_ctx_tag(int token_fd) +{ + static const char strs[] = "\0a\0b\0arg:ctx\0"; + const __u32 types[] = { + /* [1] INT */ + BTF_TYPE_INT_ENC(1 /* "a" */, BTF_INT_SIGNED, 0, 32, 4), + /* [2] PTR -> VOID */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0), + /* [3] FUNC_PROTO `int(void *a)` */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1), + BTF_PARAM_ENC(1 /* "a" */, 2), + /* [4] FUNC 'a' -> FUNC_PROTO (main prog) */ + BTF_TYPE_ENC(1 /* "a" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 3), + /* [5] FUNC_PROTO `int(void *b __arg_ctx)` */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1), + BTF_PARAM_ENC(3 /* "b" */, 2), + /* [6] FUNC 'b' -> FUNC_PROTO (subprog) */ + BTF_TYPE_ENC(3 /* "b" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 5), + /* [7] DECL_TAG 'arg:ctx' -> func 'b' arg 'b' */ + BTF_TYPE_DECL_TAG_ENC(5 /* "arg:ctx" */, 6, 0), + }; + const struct bpf_insn insns[] = { + /* main prog */ + BPF_CALL_REL(+1), + BPF_EXIT_INSN(), + /* global subprog */ + BPF_EMIT_CALL(BPF_FUNC_get_func_ip), /* needs PTR_TO_CTX */ + BPF_EXIT_INSN(), + }; + const struct bpf_func_info_min func_infos[] = { + { 0, 4 }, /* main prog -> FUNC 'a' */ + { 2, 6 }, /* subprog -> FUNC 'b' */ + }; + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .token_fd = token_fd, + .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, + ); + int prog_fd, btf_fd, insn_cnt = ARRAY_SIZE(insns); + + btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd); + if (btf_fd < 0) + return 0; + + opts.prog_btf_fd = btf_fd; + opts.func_info = &func_infos; + opts.func_info_cnt = ARRAY_SIZE(func_infos); + opts.func_info_rec_size = sizeof(func_infos[0]); + + prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, "det_arg_ctx", + "GPL", insns, insn_cnt, &opts); + close(btf_fd); + + return probe_fd(prog_fd); +} + typedef int (*feature_probe_fn)(int /* token_fd */); static struct kern_feature_cache feature_cache; @@ -476,6 +531,9 @@ static struct kern_feature_desc { [FEAT_UPROBE_MULTI_LINK] = { "BPF multi-uprobe link support", probe_uprobe_multi_link, }, + [FEAT_ARG_CTX_TAG] = { + "kernel-side __arg_ctx tag", probe_kern_arg_ctx_tag, + }, }; bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index fa7094ff3e66..41ab7a21f868 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -6462,69 +6462,6 @@ static int clone_func_btf_info(struct btf *btf, int orig_fn_id, struct bpf_progr return fn_id; } -static int probe_kern_arg_ctx_tag(void) -{ - /* To minimize merge conflicts with BPF token series that refactors - * feature detection code a lot, we don't integrate - * probe_kern_arg_ctx_tag() into kernel_supports() feature-detection - * framework yet, doing our own caching internally. - * This will be cleaned up a bit later when bpf/bpf-next trees settle. - */ - static int cached_result = -1; - static const char strs[] = "\0a\0b\0arg:ctx\0"; - const __u32 types[] = { - /* [1] INT */ - BTF_TYPE_INT_ENC(1 /* "a" */, BTF_INT_SIGNED, 0, 32, 4), - /* [2] PTR -> VOID */ - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0), - /* [3] FUNC_PROTO `int(void *a)` */ - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1), - BTF_PARAM_ENC(1 /* "a" */, 2), - /* [4] FUNC 'a' -> FUNC_PROTO (main prog) */ - BTF_TYPE_ENC(1 /* "a" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 3), - /* [5] FUNC_PROTO `int(void *b __arg_ctx)` */ - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1), - BTF_PARAM_ENC(3 /* "b" */, 2), - /* [6] FUNC 'b' -> FUNC_PROTO (subprog) */ - BTF_TYPE_ENC(3 /* "b" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 5), - /* [7] DECL_TAG 'arg:ctx' -> func 'b' arg 'b' */ - BTF_TYPE_DECL_TAG_ENC(5 /* "arg:ctx" */, 6, 0), - }; - const struct bpf_insn insns[] = { - /* main prog */ - BPF_CALL_REL(+1), - BPF_EXIT_INSN(), - /* global subprog */ - BPF_EMIT_CALL(BPF_FUNC_get_func_ip), /* needs PTR_TO_CTX */ - BPF_EXIT_INSN(), - }; - const struct bpf_func_info_min func_infos[] = { - { 0, 4 }, /* main prog -> FUNC 'a' */ - { 2, 6 }, /* subprog -> FUNC 'b' */ - }; - LIBBPF_OPTS(bpf_prog_load_opts, opts); - int prog_fd, btf_fd, insn_cnt = ARRAY_SIZE(insns); - - if (cached_result >= 0) - return cached_result; - - btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), 0); - if (btf_fd < 0) - return 0; - - opts.prog_btf_fd = btf_fd; - opts.func_info = &func_infos; - opts.func_info_cnt = ARRAY_SIZE(func_infos); - opts.func_info_rec_size = sizeof(func_infos[0]); - - prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, "det_arg_ctx", - "GPL", insns, insn_cnt, &opts); - close(btf_fd); - - cached_result = probe_fd(prog_fd); - return cached_result; -} - /* Check if main program or global subprog's function prototype has `arg:ctx` * argument tags, and, if necessary, substitute correct type to match what BPF * verifier would expect, taking into account specific program type. This @@ -6549,7 +6486,7 @@ static int bpf_program_fixup_func_info(struct bpf_object *obj, struct bpf_progra return 0; /* don't do any fix ups if kernel natively supports __arg_ctx */ - if (probe_kern_arg_ctx_tag() > 0) + if (kernel_supports(obj, FEAT_ARG_CTX_TAG)) return 0; /* some BPF program types just don't have named context structs, so diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 5b30f3b67a02..ad936ac5e639 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -372,6 +372,8 @@ enum kern_feature_id { FEAT_SYSCALL_WRAPPER, /* BPF multi-uprobe link support */ FEAT_UPROBE_MULTI_LINK, + /* Kernel supports arg:ctx tag (__arg_ctx) for global subprogs natively */ + FEAT_ARG_CTX_TAG, __FEAT_CNT, }; From 9eea8fafe33eb70868f6ace2fc1e17c4ff5539c3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 25 Jan 2024 12:55:05 -0800 Subject: [PATCH 0418/2255] libbpf: fix __arg_ctx type enforcement for perf_event programs Adjust PERF_EVENT type enforcement around __arg_ctx to match exactly what kernel is doing. Fixes: 76ec90a996e3 ("libbpf: warn on unexpected __arg_ctx type when rewriting BTF") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240125205510.3642094-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 41ab7a21f868..db65ea59a05a 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -6339,6 +6340,14 @@ static struct { /* all other program types don't have "named" context structs */ }; +/* forward declarations for arch-specific underlying types of bpf_user_pt_regs_t typedef, + * for below __builtin_types_compatible_p() checks; + * with this approach we don't need any extra arch-specific #ifdef guards + */ +struct pt_regs; +struct user_pt_regs; +struct user_regs_struct; + static bool need_func_arg_type_fixup(const struct btf *btf, const struct bpf_program *prog, const char *subprog_name, int arg_idx, int arg_type_id, const char *ctx_name) @@ -6379,11 +6388,21 @@ static bool need_func_arg_type_fixup(const struct btf *btf, const struct bpf_pro /* special cases */ switch (prog->type) { case BPF_PROG_TYPE_KPROBE: - case BPF_PROG_TYPE_PERF_EVENT: /* `struct pt_regs *` is expected, but we need to fix up */ if (btf_is_struct(t) && strcmp(tname, "pt_regs") == 0) return true; break; + case BPF_PROG_TYPE_PERF_EVENT: + if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct pt_regs) && + btf_is_struct(t) && strcmp(tname, "pt_regs") == 0) + return 0; + if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_pt_regs) && + btf_is_struct(t) && strcmp(tname, "user_pt_regs") == 0) + return 0; + if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_regs_struct) && + btf_is_struct(t) && strcmp(tname, "user_regs_struct") == 0) + return 0; + break; case BPF_PROG_TYPE_RAW_TRACEPOINT: case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: /* allow u64* as ctx */ From add9c58cd44e88a15f285945e26bf0d9d81c5890 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 25 Jan 2024 12:55:06 -0800 Subject: [PATCH 0419/2255] bpf: move arg:ctx type enforcement check inside the main logic loop Now that bpf and bpf-next trees converged and we don't run the risk of merge conflicts, move btf_validate_prog_ctx_type() into its most logical place inside the main logic loop. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240125205510.3642094-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index edef96ceffa3..9ec08cfb2967 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -7112,6 +7112,10 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) bpf_log(log, "arg#%d has invalid combination of tags\n", i); return -EINVAL; } + if ((tags & ARG_TAG_CTX) && + btf_validate_prog_ctx_type(log, btf, t, i, prog_type, + prog->expected_attach_type)) + return -EINVAL; sub->args[i].arg_type = ARG_PTR_TO_CTX; continue; } @@ -7156,23 +7160,6 @@ skip_pointer: return -EINVAL; } - for (i = 0; i < nargs; i++) { - const char *tag; - - if (sub->args[i].arg_type != ARG_PTR_TO_CTX) - continue; - - /* check if arg has "arg:ctx" tag */ - t = btf_type_by_id(btf, args[i].type); - tag = btf_find_decl_tag_value(btf, fn_t, i, "arg:"); - if (IS_ERR_OR_NULL(tag) || strcmp(tag, "ctx") != 0) - continue; - - if (btf_validate_prog_ctx_type(log, btf, t, i, prog_type, - prog->expected_attach_type)) - return -EINVAL; - } - sub->arg_cnt = nargs; sub->args_cached = true; From fbaf59a9f513416c05f4b4e87d26898d3dccd1cc Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 26 Jan 2024 18:50:17 -0800 Subject: [PATCH 0420/2255] selftests/bpf: Remove "&>" usage in the selftests In s390, CI reported that the sock_iter_batch selftest hits this error very often: 2024-01-26T16:56:49.3091804Z Bind /proc/self/ns/net -> /run/netns/sock_iter_batch_netns failed: No such file or directory 2024-01-26T16:56:49.3149524Z Cannot remove namespace file "/run/netns/sock_iter_batch_netns": No such file or directory 2024-01-26T16:56:49.3772213Z test_sock_iter_batch:FAIL:ip netns add sock_iter_batch_netns unexpected error: 256 (errno 0) It happens very often in s390 but Manu also noticed it happens very sparsely in other arch also. It turns out the default dash shell does not recognize "&>" as a redirection operator, so the command went to the background. In the sock_iter_batch selftest, the "ip netns delete" went into background and then race with the following "ip netns add" command. This patch replaces the "&> /dev/null" usage with ">/dev/null 2>&1" and does this redirection in the SYS_NOFAIL macro instead of doing it individually by its caller. The SYS_NOFAIL callers do not care about failure, so it is no harm to do this redirection even if some of the existing callers do not redirect to /dev/null now. It touches different test files, so I skipped the Fixes tags in this patch. Some of the changed tests do not use "&>" but they use the SYS_NOFAIL, so these tests are also changed to avoid doing its own redirection because SYS_NOFAIL does it internally now. Signed-off-by: Martin KaFai Lau Link: https://lore.kernel.org/r/20240127025017.950825-1-martin.lau@linux.dev Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/decap_sanity.c | 2 +- .../selftests/bpf/prog_tests/fib_lookup.c | 2 +- .../selftests/bpf/prog_tests/ip_check_defrag.c | 4 ++-- .../selftests/bpf/prog_tests/lwt_redirect.c | 2 +- .../selftests/bpf/prog_tests/lwt_reroute.c | 2 +- tools/testing/selftests/bpf/prog_tests/mptcp.c | 2 +- .../selftests/bpf/prog_tests/sock_destroy.c | 2 +- .../selftests/bpf/prog_tests/sock_iter_batch.c | 4 ++-- .../selftests/bpf/prog_tests/test_tunnel.c | 18 +++++++++--------- tools/testing/selftests/bpf/test_progs.h | 7 ++++++- 10 files changed, 25 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/decap_sanity.c b/tools/testing/selftests/bpf/prog_tests/decap_sanity.c index 5c0ebe6ba866..dcb9e5070cc3 100644 --- a/tools/testing/selftests/bpf/prog_tests/decap_sanity.c +++ b/tools/testing/selftests/bpf/prog_tests/decap_sanity.c @@ -72,6 +72,6 @@ fail: bpf_tc_hook_destroy(&qdisc_hook); close_netns(nstoken); } - SYS_NOFAIL("ip netns del " NS_TEST " &> /dev/null"); + SYS_NOFAIL("ip netns del " NS_TEST); decap_sanity__destroy(skel); } diff --git a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c index 4ad4cd69152e..3379df2d4cf2 100644 --- a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c +++ b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c @@ -298,6 +298,6 @@ void test_fib_lookup(void) fail: if (nstoken) close_netns(nstoken); - SYS_NOFAIL("ip netns del " NS_TEST " &> /dev/null"); + SYS_NOFAIL("ip netns del " NS_TEST); fib_lookup__destroy(skel); } diff --git a/tools/testing/selftests/bpf/prog_tests/ip_check_defrag.c b/tools/testing/selftests/bpf/prog_tests/ip_check_defrag.c index 57c814f5f6a7..8dd2af9081f4 100644 --- a/tools/testing/selftests/bpf/prog_tests/ip_check_defrag.c +++ b/tools/testing/selftests/bpf/prog_tests/ip_check_defrag.c @@ -59,9 +59,9 @@ static int setup_topology(bool ipv6) /* Wait for up to 5s for links to come up */ for (i = 0; i < 5; ++i) { if (ipv6) - up = !system("ip netns exec " NS0 " ping -6 -c 1 -W 1 " VETH1_ADDR6 " &>/dev/null"); + up = !SYS_NOFAIL("ip netns exec " NS0 " ping -6 -c 1 -W 1 " VETH1_ADDR6); else - up = !system("ip netns exec " NS0 " ping -c 1 -W 1 " VETH1_ADDR " &>/dev/null"); + up = !SYS_NOFAIL("ip netns exec " NS0 " ping -c 1 -W 1 " VETH1_ADDR); if (up) break; diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c index 59b38569f310..beeb3ac1c361 100644 --- a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c +++ b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c @@ -85,7 +85,7 @@ static void ping_dev(const char *dev, bool is_ingress) snprintf(ip, sizeof(ip), "20.0.0.%d", link_index); /* We won't get a reply. Don't fail here */ - SYS_NOFAIL("ping %s -c1 -W1 -s %d >/dev/null 2>&1", + SYS_NOFAIL("ping %s -c1 -W1 -s %d", ip, ICMP_PAYLOAD_SIZE); } diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c b/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c index f4bb2d5fcae0..5610bc76928d 100644 --- a/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c +++ b/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c @@ -63,7 +63,7 @@ static void ping_once(const char *ip) { /* We won't get a reply. Don't fail here */ - SYS_NOFAIL("ping %s -c1 -W1 -s %d >/dev/null 2>&1", + SYS_NOFAIL("ping %s -c1 -W1 -s %d", ip, ICMP_PAYLOAD_SIZE); } diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index 7c0be7cf550b..8f8d792307c1 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -79,7 +79,7 @@ static void cleanup_netns(struct nstoken *nstoken) if (nstoken) close_netns(nstoken); - SYS_NOFAIL("ip netns del %s &> /dev/null", NS_TEST); + SYS_NOFAIL("ip netns del %s", NS_TEST); } static int verify_tsk(int map_fd, int client_fd) diff --git a/tools/testing/selftests/bpf/prog_tests/sock_destroy.c b/tools/testing/selftests/bpf/prog_tests/sock_destroy.c index b0583309a94e..9c11938fe597 100644 --- a/tools/testing/selftests/bpf/prog_tests/sock_destroy.c +++ b/tools/testing/selftests/bpf/prog_tests/sock_destroy.c @@ -214,7 +214,7 @@ void test_sock_destroy(void) cleanup: if (nstoken) close_netns(nstoken); - SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null"); + SYS_NOFAIL("ip netns del " TEST_NS); if (cgroup_fd >= 0) close(cgroup_fd); sock_destroy_prog__destroy(skel); diff --git a/tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c b/tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c index 0c365f36c73b..d56e18b25528 100644 --- a/tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c +++ b/tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c @@ -112,7 +112,7 @@ void test_sock_iter_batch(void) { struct nstoken *nstoken = NULL; - SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null"); + SYS_NOFAIL("ip netns del " TEST_NS); SYS(done, "ip netns add %s", TEST_NS); SYS(done, "ip -net %s link set dev lo up", TEST_NS); @@ -131,5 +131,5 @@ void test_sock_iter_batch(void) close_netns(nstoken); done: - SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null"); + SYS_NOFAIL("ip netns del " TEST_NS); } diff --git a/tools/testing/selftests/bpf/prog_tests/test_tunnel.c b/tools/testing/selftests/bpf/prog_tests/test_tunnel.c index 2b3c6dd66259..5f1fb0a2ea56 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_tunnel.c +++ b/tools/testing/selftests/bpf/prog_tests/test_tunnel.c @@ -118,9 +118,9 @@ fail: static void cleanup(void) { SYS_NOFAIL("test -f /var/run/netns/at_ns0 && ip netns delete at_ns0"); - SYS_NOFAIL("ip link del veth1 2> /dev/null"); - SYS_NOFAIL("ip link del %s 2> /dev/null", VXLAN_TUNL_DEV1); - SYS_NOFAIL("ip link del %s 2> /dev/null", IP6VXLAN_TUNL_DEV1); + SYS_NOFAIL("ip link del veth1"); + SYS_NOFAIL("ip link del %s", VXLAN_TUNL_DEV1); + SYS_NOFAIL("ip link del %s", IP6VXLAN_TUNL_DEV1); } static int add_vxlan_tunnel(void) @@ -265,9 +265,9 @@ fail: static void delete_ipip_tunnel(void) { SYS_NOFAIL("ip -n at_ns0 link delete dev %s", IPIP_TUNL_DEV0); - SYS_NOFAIL("ip -n at_ns0 fou del port 5555 2> /dev/null"); + SYS_NOFAIL("ip -n at_ns0 fou del port 5555"); SYS_NOFAIL("ip link delete dev %s", IPIP_TUNL_DEV1); - SYS_NOFAIL("ip fou del port 5555 2> /dev/null"); + SYS_NOFAIL("ip fou del port 5555"); } static int add_xfrm_tunnel(void) @@ -346,13 +346,13 @@ fail: static void delete_xfrm_tunnel(void) { - SYS_NOFAIL("ip xfrm policy delete dir out src %s/32 dst %s/32 2> /dev/null", + SYS_NOFAIL("ip xfrm policy delete dir out src %s/32 dst %s/32", IP4_ADDR_TUNL_DEV1, IP4_ADDR_TUNL_DEV0); - SYS_NOFAIL("ip xfrm policy delete dir in src %s/32 dst %s/32 2> /dev/null", + SYS_NOFAIL("ip xfrm policy delete dir in src %s/32 dst %s/32", IP4_ADDR_TUNL_DEV0, IP4_ADDR_TUNL_DEV1); - SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d 2> /dev/null", + SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d", IP4_ADDR_VETH0, IP4_ADDR1_VETH1, XFRM_SPI_IN_TO_OUT); - SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d 2> /dev/null", + SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d", IP4_ADDR1_VETH1, IP4_ADDR_VETH0, XFRM_SPI_OUT_TO_IN); } diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index 2f9f6f250f17..80df51244886 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -385,10 +385,15 @@ int test__join_cgroup(const char *path); goto goto_label; \ }) +#define ALL_TO_DEV_NULL " >/dev/null 2>&1" + #define SYS_NOFAIL(fmt, ...) \ ({ \ char cmd[1024]; \ - snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ + int n; \ + n = snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ + if (n < sizeof(cmd) && sizeof(cmd) - n >= sizeof(ALL_TO_DEV_NULL)) \ + strcat(cmd, ALL_TO_DEV_NULL); \ system(cmd); \ }) From 646751d523587cfd7ebcf1733298ecd470879eda Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Sat, 27 Jan 2024 11:07:02 +0100 Subject: [PATCH 0421/2255] bpf: Use -Wno-error in certain tests when building with GCC Certain BPF selftests contain code that, albeit being legal C, trigger warnings in GCC that cannot be disabled. This is the case for example for the tests progs/btf_dump_test_case_bitfields.c progs/btf_dump_test_case_namespacing.c progs/btf_dump_test_case_packing.c progs/btf_dump_test_case_padding.c progs/btf_dump_test_case_syntax.c which contain struct type declarations inside function parameter lists. This is problematic, because: - The BPF selftests are built with -Werror. - The Clang and GCC compilers sometimes differ when it comes to handle warnings. in the handling of warnings. One compiler may emit warnings for code that the other compiles compiles silently, and one compiler may offer the possibility to disable certain warnings, while the other doesn't. In order to overcome this problem, this patch modifies the tools/testing/selftests/bpf/Makefile in order to: 1. Enable the possibility of specifing per-source-file extra CFLAGS. This is done by defining a make variable like: -CFLAGS := And then modifying the proper Make rule in order to use these flags when compiling . 2. Use the mechanism above to add -Wno-error to CFLAGS for the following selftests: progs/btf_dump_test_case_bitfields.c progs/btf_dump_test_case_namespacing.c progs/btf_dump_test_case_packing.c progs/btf_dump_test_case_padding.c progs/btf_dump_test_case_syntax.c Note the corresponding -CFLAGS variables for these files are defined only if the selftests are being built with GCC. Note that, while compiler pragmas can generally be used to disable particular warnings per file, this 1) is only possible for warning that actually can be disabled in the command line, i.e. that have -Wno-FOO options, and 2) doesn't apply to -Wno-error. Tested in bpf-next master branch. No regressions. Signed-off-by: Jose E. Marchesi Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20240127100702.21549-1-jose.marchesi@oracle.com --- tools/testing/selftests/bpf/Makefile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index fd15017ed3b1..1a3654bcb5dd 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -64,6 +64,15 @@ TEST_INST_SUBDIRS := no_alu32 ifneq ($(BPF_GCC),) TEST_GEN_PROGS += test_progs-bpf_gcc TEST_INST_SUBDIRS += bpf_gcc + +# The following tests contain C code that, although technically legal, +# triggers GCC warnings that cannot be disabled: declaration of +# anonymous struct types in function parameter lists. +progs/btf_dump_test_case_bitfields.c-CFLAGS := -Wno-error +progs/btf_dump_test_case_namespacing.c-CFLAGS := -Wno-error +progs/btf_dump_test_case_packing.c-CFLAGS := -Wno-error +progs/btf_dump_test_case_padding.c-CFLAGS := -Wno-error +progs/btf_dump_test_case_syntax.c-CFLAGS := -Wno-error endif ifneq ($(CLANG_CPUV4),) @@ -504,7 +513,8 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o: \ $(wildcard $(BPFDIR)/*.bpf.h) \ | $(TRUNNER_OUTPUT) $$(BPFOBJ) $$(call $(TRUNNER_BPF_BUILD_RULE),$$<,$$@, \ - $(TRUNNER_BPF_CFLAGS)) + $(TRUNNER_BPF_CFLAGS) \ + $$($$<-CFLAGS)) $(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT) $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@) From aecaa3ed48c3ae74c06f5e8ef0746b69c62397f1 Mon Sep 17 00:00:00 2001 From: Florian Lehner Date: Sat, 20 Jan 2024 16:09:20 +0100 Subject: [PATCH 0422/2255] perf/bpf: Fix duplicate type check Remove the duplicate check on type and unify result. Signed-off-by: Florian Lehner Signed-off-by: Daniel Borkmann Acked-by: Daniel Borkmann Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20240120150920.3370-1-dev@der-flo.net --- kernel/events/core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index f0f0f71213a1..5ecfa57e3b97 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9302,10 +9302,6 @@ void perf_event_bpf_event(struct bpf_prog *prog, { struct perf_bpf_event bpf_event; - if (type <= PERF_BPF_EVENT_UNKNOWN || - type >= PERF_BPF_EVENT_MAX) - return; - switch (type) { case PERF_BPF_EVENT_PROG_LOAD: case PERF_BPF_EVENT_PROG_UNLOAD: @@ -9313,7 +9309,7 @@ void perf_event_bpf_event(struct bpf_prog *prog, perf_event_bpf_emit_ksymbols(prog, type); break; default: - break; + return; } if (!atomic_read(&nr_bpf_events)) From f2e4040c82d3fddd11fa7c64e8f810e6f9cb7460 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Jan 2024 15:18:40 -0800 Subject: [PATCH 0423/2255] libbpf: Add some details for BTF parsing failures As CONFIG_DEBUG_INFO_BTF is default off the existing "failed to find valid kernel BTF" message makes diagnosing the kernel build issue somewhat cryptic. Add a little more detail with the hope of helping users. Before: ``` libbpf: failed to find valid kernel BTF libbpf: Error loading vmlinux BTF: -3 ``` After not accessible: ``` libbpf: kernel BTF is missing at '/sys/kernel/btf/vmlinux', was CONFIG_DEBUG_INFO_BTF enabled? libbpf: failed to find valid kernel BTF libbpf: Error loading vmlinux BTF: -3 ``` After not readable: ``` libbpf: failed to read kernel BTF from (/sys/kernel/btf/vmlinux): -1 ``` Closes: https://lore.kernel.org/bpf/CAP-5=fU+DN_+Y=Y4gtELUsJxKNDDCOvJzPHvjUVaUoeFAzNnig@mail.gmail.com/ Signed-off-by: Ian Rogers Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240125231840.1647951-1-irogers@google.com --- tools/lib/bpf/btf.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index ec92b87cae01..95db88b36cf3 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -4932,10 +4932,9 @@ static int btf_dedup_remap_types(struct btf_dedup *d) */ struct btf *btf__load_vmlinux_btf(void) { + const char *sysfs_btf_path = "/sys/kernel/btf/vmlinux"; + /* fall back locations, trying to find vmlinux on disk */ const char *locations[] = { - /* try canonical vmlinux BTF through sysfs first */ - "/sys/kernel/btf/vmlinux", - /* fall back to trying to find vmlinux on disk otherwise */ "/boot/vmlinux-%1$s", "/lib/modules/%1$s/vmlinux-%1$s", "/lib/modules/%1$s/build/vmlinux", @@ -4949,8 +4948,23 @@ struct btf *btf__load_vmlinux_btf(void) struct btf *btf; int i, err; - uname(&buf); + /* is canonical sysfs location accessible? */ + if (faccessat(AT_FDCWD, sysfs_btf_path, F_OK, AT_EACCESS) < 0) { + pr_warn("kernel BTF is missing at '%s', was CONFIG_DEBUG_INFO_BTF enabled?\n", + sysfs_btf_path); + } else { + btf = btf__parse(sysfs_btf_path, NULL); + if (!btf) { + err = -errno; + pr_warn("failed to read kernel BTF from '%s': %d\n", sysfs_btf_path, err); + return libbpf_err_ptr(err); + } + pr_debug("loaded kernel BTF from '%s'\n", path); + return btf; + } + /* try fallback locations */ + uname(&buf); for (i = 0; i < ARRAY_SIZE(locations); i++) { snprintf(path, PATH_MAX, locations[i], buf.release); From ff2071a7b7fd77908417603c4a785822939b3841 Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Sat, 27 Jan 2024 19:50:31 +0100 Subject: [PATCH 0424/2255] bpf: Generate const static pointers for kernel helpers The generated bpf_helper_defs.h file currently contains definitions like this for the kernel helpers, which are static objects: static void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1; These work well in both clang and GCC because both compilers do constant propagation with -O1 and higher optimization, resulting in `call 1' BPF instructions being generated, which are calls to kernel helpers. However, there is a discrepancy on how the -Wunused-variable warning (activated by -Wall) is handled in these compilers: - clang will not emit -Wunused-variable warnings for static variables defined in C header files, be them constant or not constant. - GCC will not emit -Wunused-variable warnings for _constant_ static variables defined in header files, but it will emit warnings for non-constant static variables defined in header files. There is no reason for these bpf_helpers_def.h pointers to not be declared constant, and it is actually desirable to do so, since their values are not to be changed. So this patch modifies bpf_doc.py to generate prototypes like: static void *(* const bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1; This allows GCC to not error while compiling BPF programs with `-Wall -Werror', while still being able to detect and error on legitimate unused variables in the program themselves. This change doesn't impact the desired constant propagation in neither Clang nor GCC with -O1 and higher. On the contrary, being declared as constant may increase the odds they get constant folded when used/referred to in certain circumstances. Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240127185031.29854-1-jose.marchesi@oracle.com --- scripts/bpf_doc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index 61b7dddedc46..2b94749c99cc 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -827,7 +827,7 @@ class PrinterHelpers(Printer): print(' *{}{}'.format(' \t' if line else '', line)) print(' */') - print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), + print('static %s %s(* const %s)(' % (self.map_type(proto['ret_type']), proto['ret_star'], proto['name']), end='') comma = '' for i, a in enumerate(proto['args']): From 024d8577f534347b21a33bd098874867bbe50347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:35:52 +0300 Subject: [PATCH 0425/2255] net: dsa: mt7530: always trap frames to active CPU port on MT7530 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the MT7530 switch, the CPU_PORT field indicates which CPU port to trap frames to, regardless of the affinity of the inbound user port. When multiple CPU ports are in use, if the DSA conduit interface is down, trapped frames won't be passed to the conduit interface. To make trapping frames work including this case, implement ds->ops->conduit_state_change() on this subdriver and set the CPU_PORT field to the numerically smallest CPU port whose conduit interface is up. Introduce the active_cpu_ports field to store the information of the active CPU ports. Correct the macros, CPU_PORT is bits 4 through 6 of the register. Add a comment to explain frame trapping for this switch. Currently, the driver doesn't support the use of multiple CPU ports so this is not necessarily a bug fix. Suggested-by: Vladimir Oltean Suggested-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-1-042401f2b279@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 35 +++++++++++++++++++++++++++++++---- drivers/net/dsa/mt7530.h | 6 ++++-- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index cf2ff7680c15..b282e526d709 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1035,10 +1035,6 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port) mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | UNU_FFP(BIT(port))); - /* Set CPU port number */ - if (priv->id == ID_MT7530 || priv->id == ID_MT7621) - mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port)); - /* Add the CPU port to the CPU port bitmap for MT7531 and the switch on * the MT7988 SoC. Trapped frames will be forwarded to the CPU port that * is affine to the inbound user port. @@ -3093,6 +3089,36 @@ static int mt753x_set_mac_eee(struct dsa_switch *ds, int port, return 0; } +static void +mt753x_conduit_state_change(struct dsa_switch *ds, + const struct net_device *conduit, + bool operational) +{ + struct dsa_port *cpu_dp = conduit->dsa_ptr; + struct mt7530_priv *priv = ds->priv; + int val = 0; + u8 mask; + + /* Set the CPU port to trap frames to for MT7530. Trapped frames will be + * forwarded to the numerically smallest CPU port whose conduit + * interface is up. + */ + if (priv->id != ID_MT7530 && priv->id != ID_MT7621) + return; + + mask = BIT(cpu_dp->index); + + if (operational) + priv->active_cpu_ports |= mask; + else + priv->active_cpu_ports &= ~mask; + + if (priv->active_cpu_ports) + val = CPU_EN | CPU_PORT(__ffs(priv->active_cpu_ports)); + + mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val); +} + static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface) { return 0; @@ -3148,6 +3174,7 @@ const struct dsa_switch_ops mt7530_switch_ops = { .phylink_mac_link_up = mt753x_phylink_mac_link_up, .get_mac_eee = mt753x_get_mac_eee, .set_mac_eee = mt753x_set_mac_eee, + .conduit_state_change = mt753x_conduit_state_change, }; EXPORT_SYMBOL_GPL(mt7530_switch_ops); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 17e42d30fff4..ebfb3a7acfcd 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -41,8 +41,8 @@ enum mt753x_id { #define UNU_FFP(x) (((x) & 0xff) << 8) #define UNU_FFP_MASK UNU_FFP(~0) #define CPU_EN BIT(7) -#define CPU_PORT(x) ((x) << 4) -#define CPU_MASK (0xf << 4) +#define CPU_PORT_MASK GENMASK(6, 4) +#define CPU_PORT(x) FIELD_PREP(CPU_PORT_MASK, x) #define MIRROR_EN BIT(3) #define MIRROR_PORT(x) ((x) & 0x7) #define MIRROR_MASK 0x7 @@ -760,6 +760,7 @@ struct mt753x_info { * @irq_domain: IRQ domain of the switch irq_chip * @irq_enable: IRQ enable bits, synced to SYS_INT_EN * @create_sgmii: Pointer to function creating SGMII PCS instance(s) + * @active_cpu_ports: Holding the active CPU ports */ struct mt7530_priv { struct device *dev; @@ -786,6 +787,7 @@ struct mt7530_priv { struct irq_domain *irq_domain; u32 irq_enable; int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii); + u8 active_cpu_ports; }; struct mt7530_hw_vlan_entry { From b198c9097f0659da80e675a9df94f83ec9495076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:35:53 +0300 Subject: [PATCH 0426/2255] net: dsa: mt7530: use p5_interface_select as data type for p5_intf_sel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the p5_interface_select enumeration as the data type for the p5_intf_sel field. This ensures p5_intf_sel can only take the values defined in the p5_interface_select enumeration. Remove the explicit assignment of 0 to P5_DISABLED as the first enum item is automatically assigned 0. Signed-off-by: Arınç ÜNAL Acked-by: Daniel Golle Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-2-042401f2b279@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index ebfb3a7acfcd..9cbf18efa416 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -683,7 +683,7 @@ struct mt7530_port { /* Port 5 interface select definitions */ enum p5_interface_select { - P5_DISABLED = 0, + P5_DISABLED, P5_INTF_SEL_PHY_P0, P5_INTF_SEL_PHY_P4, P5_INTF_SEL_GMAC5, @@ -776,7 +776,7 @@ struct mt7530_priv { bool mcm; phy_interface_t p6_interface; phy_interface_t p5_interface; - unsigned int p5_intf_sel; + enum p5_interface_select p5_intf_sel; u8 mirror_rx; u8 mirror_tx; struct mt7530_port ports[MT7530_NUM_PORTS]; From 1f4a85f2eaa8f21ea19c27d63258fd46f8b45290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:35:54 +0300 Subject: [PATCH 0427/2255] net: dsa: mt7530: store port 5 SGMII capability of MT7531 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the p5_sgmii field to store the information for whether port 5 has got SGMII or not. Instead of reading the MT7531_TOP_SIG_SR register multiple times, the register will be read once and the value will be stored on the p5_sgmii field. This saves unnecessary reads of the register. Move the comment about MT7531AE and MT7531BE to mt7531_setup(), where the switch is identified. Get rid of mt7531_dual_sgmii_supported() now that priv->p5_sgmii stores the information. Address the code where mt7531_dual_sgmii_supported() is used. Get rid of mt7531_is_rgmii_port() which just prints the opposite of priv->p5_sgmii. Instead of calling mt7531_pll_setup() then returning, do not call it if port 5 is SGMII. Remove P5_INTF_SEL_GMAC5_SGMII. The p5_interface_select enum is supposed to represent the mode that port 5 is being used in, not the hardware information of port 5. Set p5_intf_sel to P5_INTF_SEL_GMAC5 instead, if port 5 is not dsa_is_unused_port(). Signed-off-by: Arınç ÜNAL Acked-by: Daniel Golle Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-3-042401f2b279@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530-mdio.c | 7 ++--- drivers/net/dsa/mt7530.c | 48 ++++++++++++----------------------- drivers/net/dsa/mt7530.h | 6 +++-- 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c index 088533663b83..fa3ee85a99c1 100644 --- a/drivers/net/dsa/mt7530-mdio.c +++ b/drivers/net/dsa/mt7530-mdio.c @@ -81,17 +81,14 @@ static const struct regmap_bus mt7530_regmap_bus = { }; static int -mt7531_create_sgmii(struct mt7530_priv *priv, bool dual_sgmii) +mt7531_create_sgmii(struct mt7530_priv *priv) { struct regmap_config *mt7531_pcs_config[2] = {}; struct phylink_pcs *pcs; struct regmap *regmap; int i, ret = 0; - /* MT7531AE has two SGMII units for port 5 and port 6 - * MT7531BE has only one SGMII unit for port 6 - */ - for (i = dual_sgmii ? 0 : 1; i < 2; i++) { + for (i = priv->p5_sgmii ? 0 : 1; i < 2; i++) { mt7531_pcs_config[i] = devm_kzalloc(priv->dev, sizeof(struct regmap_config), GFP_KERNEL); diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b282e526d709..cf61ff16f9aa 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -487,15 +487,6 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) return 0; } -static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv) -{ - u32 val; - - val = mt7530_read(priv, MT7531_TOP_SIG_SR); - - return (val & PAD_DUAL_SGMII_EN) != 0; -} - static int mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface) { @@ -510,9 +501,6 @@ mt7531_pll_setup(struct mt7530_priv *priv) u32 xtal; u32 val; - if (mt7531_dual_sgmii_supported(priv)) - return; - val = mt7530_read(priv, MT7531_CREV); top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR); hwstrap = mt7530_read(priv, MT7531_HWTRAP); @@ -920,8 +908,6 @@ static const char *p5_intf_modes(unsigned int p5_interface) return "PHY P4"; case P5_INTF_SEL_GMAC5: return "GMAC5"; - case P5_INTF_SEL_GMAC5_SGMII: - return "GMAC5_SGMII"; default: return "unknown"; } @@ -2488,6 +2474,12 @@ mt7531_setup(struct dsa_switch *ds) return -ENODEV; } + /* MT7531AE has got two SGMII units. One for port 5, one for port 6. + * MT7531BE has got only one SGMII unit which is for port 6. + */ + val = mt7530_read(priv, MT7531_TOP_SIG_SR); + priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN); + /* all MACs must be forced link-down before sw reset */ for (i = 0; i < MT7530_NUM_PORTS; i++) mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK); @@ -2497,21 +2489,18 @@ mt7531_setup(struct dsa_switch *ds) SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | SYS_CTRL_REG_RST); - mt7531_pll_setup(priv); - - if (mt7531_dual_sgmii_supported(priv)) { - priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII; - + if (!priv->p5_sgmii) { + mt7531_pll_setup(priv); + } else { /* Let ds->user_mii_bus be able to access external phy. */ mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK, MT7531_EXT_P_MDC_11); mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK, MT7531_EXT_P_MDIO_12); - } else { - priv->p5_intf_sel = P5_INTF_SEL_GMAC5; } - dev_dbg(ds->dev, "P5 support %s interface\n", - p5_intf_modes(priv->p5_intf_sel)); + + if (!dsa_is_unused_port(ds, 5)) + priv->p5_intf_sel = P5_INTF_SEL_GMAC5; mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK, MT7531_GPIO0_INTERRUPT); @@ -2571,11 +2560,6 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, } } -static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) -{ - return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); -} - static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { @@ -2588,7 +2572,7 @@ static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, break; case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ - if (mt7531_is_rgmii_port(priv, port)) { + if (!priv->p5_sgmii) { phy_interface_set_rgmii(config->supported_interfaces); break; } @@ -2655,7 +2639,7 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port, { u32 val; - if (!mt7531_is_rgmii_port(priv, port)) { + if (priv->p5_sgmii) { dev_err(priv->dev, "RGMII mode is not available for port %d\n", port); return -EINVAL; @@ -2899,7 +2883,7 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port) switch (port) { case 5: - if (mt7531_is_rgmii_port(priv, port)) + if (!priv->p5_sgmii) interface = PHY_INTERFACE_MODE_RGMII; else interface = PHY_INTERFACE_MODE_2500BASEX; @@ -3051,7 +3035,7 @@ mt753x_setup(struct dsa_switch *ds) mt7530_free_irq_common(priv); if (priv->create_sgmii) { - ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv)); + ret = priv->create_sgmii(priv); if (ret && priv->irq) mt7530_free_irq(priv); } diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 9cbf18efa416..80060cc740d2 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -687,7 +687,6 @@ enum p5_interface_select { P5_INTF_SEL_PHY_P0, P5_INTF_SEL_PHY_P4, P5_INTF_SEL_GMAC5, - P5_INTF_SEL_GMAC5_SGMII, }; struct mt7530_priv; @@ -756,6 +755,8 @@ struct mt753x_info { * registers * @p6_interface Holding the current port 6 interface * @p5_intf_sel: Holding the current port 5 interface select + * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch + * has got SGMII * @irq: IRQ number of the switch * @irq_domain: IRQ domain of the switch irq_chip * @irq_enable: IRQ enable bits, synced to SYS_INT_EN @@ -777,6 +778,7 @@ struct mt7530_priv { phy_interface_t p6_interface; phy_interface_t p5_interface; enum p5_interface_select p5_intf_sel; + bool p5_sgmii; u8 mirror_rx; u8 mirror_tx; struct mt7530_port ports[MT7530_NUM_PORTS]; @@ -786,7 +788,7 @@ struct mt7530_priv { int irq; struct irq_domain *irq_domain; u32 irq_enable; - int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii); + int (*create_sgmii)(struct mt7530_priv *priv); u8 active_cpu_ports; }; From 05957aa77ed8713ccaea6bbf1edc7e6a33af00bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:35:55 +0300 Subject: [PATCH 0428/2255] net: dsa: mt7530: improve comments regarding switch ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no logic to numerically order the CPU ports. Just state the port number instead. Remove the irrelevant PHY muxing information from mt7530_mac_port_get_caps(). Explain the supported MII modes instead. Remove the out of place PHY muxing information from mt753x_phylink_mac_config(). The function is for MT7530, MT7531, and the switch on the MT7988 SoC but there's no PHY muxing on MT7531 or the switch on the MT7988 SoC. These comments were gradually introduced with the commits below. commit ca366d6c889b ("net: dsa: mt7530: Convert to PHYLINK API") commit 38f790a80560 ("net: dsa: mt7530: Add support for port 5") commit 88bdef8be9f6 ("net: dsa: mt7530: Extend device data ready for adding a new hardware") commit c288575f7810 ("net: dsa: mt7530: Add the support of MT7531 switch") Signed-off-by: Arınç ÜNAL Acked-by: Daniel Golle Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-4-042401f2b279@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index cf61ff16f9aa..d51f669a8c05 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2538,12 +2538,14 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { switch (port) { - case 0 ... 4: /* Internal phy */ + /* Ports which are connected to switch PHYs. There is no MII pinout. */ + case 0 ... 4: __set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces); break; - case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ + /* Port 5 supports rgmii with delays, mii, and gmii. */ + case 5: phy_interface_set_rgmii(config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); @@ -2551,7 +2553,8 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, config->supported_interfaces); break; - case 6: /* 1st cpu port */ + /* Port 6 supports rgmii and trgmii. */ + case 6: __set_bit(PHY_INTERFACE_MODE_RGMII, config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_TRGMII, @@ -2566,19 +2569,24 @@ static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, struct mt7530_priv *priv = ds->priv; switch (port) { - case 0 ... 4: /* Internal phy */ + /* Ports which are connected to switch PHYs. There is no MII pinout. */ + case 0 ... 4: __set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces); break; - case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ + /* Port 5 supports rgmii with delays on MT7531BE, sgmii/802.3z on + * MT7531AE. + */ + case 5: if (!priv->p5_sgmii) { phy_interface_set_rgmii(config->supported_interfaces); break; } fallthrough; - case 6: /* 1st cpu port supports sgmii/8023z only */ + /* Port 6 supports sgmii/802.3z. */ + case 6: __set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_1000BASEX, @@ -2597,11 +2605,13 @@ static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, phy_interface_zero(config->supported_interfaces); switch (port) { - case 0 ... 4: /* Internal phy */ + /* Ports which are connected to switch PHYs. There is no MII pinout. */ + case 0 ... 4: __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); break; + /* Port 6 is connected to SoC's XGMII MAC. There is no MII pinout. */ case 6: __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); @@ -2765,12 +2775,12 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, u32 mcr_cur, mcr_new; switch (port) { - case 0 ... 4: /* Internal phy */ + case 0 ... 4: if (state->interface != PHY_INTERFACE_MODE_GMII && state->interface != PHY_INTERFACE_MODE_INTERNAL) goto unsupported; break; - case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ + case 5: if (priv->p5_interface == state->interface) break; @@ -2780,7 +2790,7 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, if (priv->p5_intf_sel != P5_DISABLED) priv->p5_interface = state->interface; break; - case 6: /* 1st cpu port */ + case 6: if (priv->p6_interface == state->interface) break; From 152f8e8e7458f39720886c8ed1d55f456096499e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:35:56 +0300 Subject: [PATCH 0429/2255] net: dsa: mt7530: improve code path for setting up port 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There're two code paths for setting up port 5: mt7530_setup() -> mt7530_setup_port5() mt753x_phylink_mac_config() -> mt753x_mac_config() -> mt7530_mac_config() -> mt7530_setup_port5() Currently mt7530_setup_port5() from mt7530_setup() always runs. If port 5 is used as a CPU, DSA, or user port, mt7530_setup_port5() from mt753x_phylink_mac_config() won't run. That is because priv->p5_interface set on mt7530_setup_port5() will match state->interface on mt753x_phylink_mac_config() which will stop running mt7530_setup_port5() again. Therefore, mt7530_setup_port5() will never run from mt753x_phylink_mac_config(). Address this by not running mt7530_setup_port5() from mt7530_setup() if port 5 is used as a CPU, DSA, or user port. This driver isn't in the dsa_switches_apply_workarounds[] array so phylink will always be present. To keep the cases where port 5 isn't controlled by phylink working as before, preserve the mt7530_setup_port5() call from mt7530_setup(). Do not set priv->p5_intf_sel to P5_DISABLED. It is already set to that when "priv" is allocated. Move setting the interface to a more specific location. It's supposed to be overwritten if PHY muxing is detected. Improve the comment which explains the process. Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-5-042401f2b279@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index d51f669a8c05..b44f831c4621 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2326,16 +2326,15 @@ mt7530_setup(struct dsa_switch *ds) return ret; /* Setup port 5 */ - priv->p5_intf_sel = P5_DISABLED; - interface = PHY_INTERFACE_MODE_NA; - if (!dsa_is_unused_port(ds, 5)) { priv->p5_intf_sel = P5_INTF_SEL_GMAC5; - ret = of_get_phy_mode(dsa_to_port(ds, 5)->dn, &interface); - if (ret && ret != -ENODEV) - return ret; } else { - /* Scan the ethernet nodes. look for GMAC1, lookup used phy */ + /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY. + * Set priv->p5_intf_sel to the appropriate value if PHY muxing + * is detected. + */ + interface = PHY_INTERFACE_MODE_NA; + for_each_child_of_node(dn, mac_np) { if (!of_device_is_compatible(mac_np, "mediatek,eth-mac")) @@ -2366,6 +2365,8 @@ mt7530_setup(struct dsa_switch *ds) of_node_put(phy_node); break; } + + mt7530_setup_port5(ds, interface); } #ifdef CONFIG_GPIOLIB @@ -2376,8 +2377,6 @@ mt7530_setup(struct dsa_switch *ds) } #endif /* CONFIG_GPIOLIB */ - mt7530_setup_port5(ds, interface); - /* Flush the FDB table */ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); if (ret < 0) From 6537973f2a5dc3e83a424142366fd15a2b97199f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:35:57 +0300 Subject: [PATCH 0430/2255] net: dsa: mt7530: do not set priv->p5_interface on mt7530_setup_port5() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running mt7530_setup_port5() from mt7530_setup() used to handle all cases of configuring port 5, including phylink. Setting priv->p5_interface under mt7530_setup_port5() makes sure that mt7530_setup_port5() from mt753x_phylink_mac_config() won't run. The commit ("net: dsa: mt7530: improve code path for setting up port 5") makes so that mt7530_setup_port5() from mt7530_setup() runs only on non-phylink cases. Get rid of unnecessarily setting priv->p5_interface under mt7530_setup_port5() as port 5 phylink configuration will be done by running mt7530_setup_port5() from mt753x_phylink_mac_config() now. Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-6-042401f2b279@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b44f831c4621..07e8e5202b57 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -978,8 +978,6 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n", val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface)); - priv->p5_interface = interface; - unlock_exit: mutex_unlock(&priv->reg_mutex); } From 04a22bef5fc2c3123fb8e517fecb650d510c5a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 22 Jan 2024 08:35:58 +0300 Subject: [PATCH 0431/2255] net: dsa: mt7530: do not run mt7530_setup_port5() if port 5 is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to run all the code on mt7530_setup_port5() if port 5 is disabled. The only case for calling mt7530_setup_port5() from mt7530_setup() is when PHY muxing is enabled. That is because port 5 is not defined as a port on the devicetree, therefore, it cannot be controlled by phylink. Because of this, run mt7530_setup_port5() if priv->p5_intf_sel is P5_INTF_SEL_PHY_P0 or P5_INTF_SEL_PHY_P4. Remove the P5_DISABLED case from mt7530_setup_port5(). Stop initialising the interface variable as the remaining cases will always call mt7530_setup_port5() with it initialised. Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-7-042401f2b279@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 07e8e5202b57..68be38ae66e0 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -942,9 +942,6 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) /* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */ val &= ~MHWTRAP_P5_DIS; break; - case P5_DISABLED: - interface = PHY_INTERFACE_MODE_NA; - break; default: dev_err(ds->dev, "Unsupported p5_intf_sel %d\n", priv->p5_intf_sel); @@ -2331,8 +2328,6 @@ mt7530_setup(struct dsa_switch *ds) * Set priv->p5_intf_sel to the appropriate value if PHY muxing * is detected. */ - interface = PHY_INTERFACE_MODE_NA; - for_each_child_of_node(dn, mac_np) { if (!of_device_is_compatible(mac_np, "mediatek,eth-mac")) @@ -2364,7 +2359,9 @@ mt7530_setup(struct dsa_switch *ds) break; } - mt7530_setup_port5(ds, interface); + if (priv->p5_intf_sel == P5_INTF_SEL_PHY_P0 || + priv->p5_intf_sel == P5_INTF_SEL_PHY_P4) + mt7530_setup_port5(ds, interface); } #ifdef CONFIG_GPIOLIB From 795a7dfbc3d95e4c7c09569f319f026f8c7f5a9c Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Fri, 26 Jan 2024 12:05:19 +0800 Subject: [PATCH 0432/2255] net: tcp: accept old ack during closing For now, the packet with an old ack is not accepted if we are in FIN_WAIT1 state, which can cause retransmission. Taking the following case as an example: Client Server | | FIN_WAIT1(Send FIN, seq=10) FIN_WAIT1(Send FIN, seq=20, ack=10) | | | Send ACK(seq=21, ack=11) Recv ACK(seq=21, ack=11) | Recv FIN(seq=20, ack=10) In the case above, simultaneous close is happening, and the FIN and ACK packet that send from the server is out of order. Then, the FIN will be dropped by the client, as it has an old ack. Then, the server has to retransmit the FIN, which can cause delay if the server has set the SO_LINGER on the socket. Old ack is accepted in the ESTABLISHED and TIME_WAIT state, and I think it should be better to keep the same logic. In this commit, we accept old ack in FIN_WAIT1/FIN_WAIT2/CLOSING/LAST_ACK states. Maybe we should limit it to FIN_WAIT1 for now? Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20240126040519.1846345-1-menglong8.dong@gmail.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_input.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index df7b13f0e5e0..2d20edf652e6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6699,17 +6699,21 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) return 0; /* step 5: check the ACK field */ - acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH | - FLAG_UPDATE_TS_RECENT | - FLAG_NO_CHALLENGE_ACK) > 0; + reason = tcp_ack(sk, skb, FLAG_SLOWPATH | + FLAG_UPDATE_TS_RECENT | + FLAG_NO_CHALLENGE_ACK); - if (!acceptable) { + if ((int)reason <= 0) { if (sk->sk_state == TCP_SYN_RECV) return 1; /* send one RST */ - tcp_send_challenge_ack(sk); - SKB_DR_SET(reason, TCP_OLD_ACK); - goto discard; + /* accept old ack during closing */ + if ((int)reason < 0) { + tcp_send_challenge_ack(sk); + reason = -reason; + goto discard; + } } + SKB_DR_SET(reason, NOT_SPECIFIED); switch (sk->sk_state) { case TCP_SYN_RECV: tp->delivered++; /* SYN-ACK delivery isn't tracked in tcp_ack */ From 6668e818f960b0f32110a9efa7c97351a5771b35 Mon Sep 17 00:00:00 2001 From: Haiyue Wang Date: Sat, 27 Jan 2024 21:48:56 +0800 Subject: [PATCH 0433/2255] bpf,token: Use BIT_ULL() to convert the bit mask Replace the '(1ULL << *)' with the macro BIT_ULL(nr). Signed-off-by: Haiyue Wang Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240127134901.3698613-1-haiyue.wang@intel.com --- kernel/bpf/token.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/token.c b/kernel/bpf/token.c index 0bca93b60c43..d6ccf8d00eab 100644 --- a/kernel/bpf/token.c +++ b/kernel/bpf/token.c @@ -72,28 +72,28 @@ static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp) u64 mask; BUILD_BUG_ON(__MAX_BPF_CMD >= 64); - mask = (1ULL << __MAX_BPF_CMD) - 1; + mask = BIT_ULL(__MAX_BPF_CMD) - 1; if ((token->allowed_cmds & mask) == mask) seq_printf(m, "allowed_cmds:\tany\n"); else seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds); BUILD_BUG_ON(__MAX_BPF_MAP_TYPE >= 64); - mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; + mask = BIT_ULL(__MAX_BPF_MAP_TYPE) - 1; if ((token->allowed_maps & mask) == mask) seq_printf(m, "allowed_maps:\tany\n"); else seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps); BUILD_BUG_ON(__MAX_BPF_PROG_TYPE >= 64); - mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; + mask = BIT_ULL(__MAX_BPF_PROG_TYPE) - 1; if ((token->allowed_progs & mask) == mask) seq_printf(m, "allowed_progs:\tany\n"); else seq_printf(m, "allowed_progs:\t0x%llx\n", token->allowed_progs); BUILD_BUG_ON(__MAX_BPF_ATTACH_TYPE >= 64); - mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; + mask = BIT_ULL(__MAX_BPF_ATTACH_TYPE) - 1; if ((token->allowed_attachs & mask) == mask) seq_printf(m, "allowed_attachs:\tany\n"); else @@ -253,7 +253,7 @@ bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd) { if (!token) return false; - if (!(token->allowed_cmds & (1ULL << cmd))) + if (!(token->allowed_cmds & BIT_ULL(cmd))) return false; return security_bpf_token_cmd(token, cmd) == 0; } @@ -263,7 +263,7 @@ bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type t if (!token || type >= __MAX_BPF_MAP_TYPE) return false; - return token->allowed_maps & (1ULL << type); + return token->allowed_maps & BIT_ULL(type); } bool bpf_token_allow_prog_type(const struct bpf_token *token, @@ -273,6 +273,6 @@ bool bpf_token_allow_prog_type(const struct bpf_token *token, if (!token || prog_type >= __MAX_BPF_PROG_TYPE || attach_type >= __MAX_BPF_ATTACH_TYPE) return false; - return (token->allowed_progs & (1ULL << prog_type)) && - (token->allowed_attachs & (1ULL << attach_type)); + return (token->allowed_progs & BIT_ULL(prog_type)) && + (token->allowed_attachs & BIT_ULL(attach_type)); } From 8293e4cb2ff54b1ec4f7206dcb74c908f62a3fb8 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 25 Jan 2024 13:57:49 -0800 Subject: [PATCH 0434/2255] ice: introduce PTP state machine Add PTP state machine so that the driver can correctly identify PTP state around resets. When the driver got information about ungraceful reset, PTP was not prepared for reset and it returned error. When this situation occurs, prepare PTP before rebuilding its structures. Signed-off-by: Jacob Keller Co-developed-by: Karol Kolacinski Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice.h | 1 - drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +- drivers/net/ethernet/intel/ice/ice_ptp.c | 110 +++++++++++-------- drivers/net/ethernet/intel/ice/ice_ptp.h | 10 ++ 4 files changed, 74 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 367b613d92c0..97c2a5fb5dbf 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -493,7 +493,6 @@ enum ice_pf_flags { ICE_FLAG_DCB_ENA, ICE_FLAG_FD_ENA, ICE_FLAG_PTP_SUPPORTED, /* PTP is supported by NVM */ - ICE_FLAG_PTP, /* PTP is enabled by software */ ICE_FLAG_ADV_FEATURES, ICE_FLAG_TC_MQPRIO, /* support for Multi queue TC */ ICE_FLAG_CLS_FLOWER, diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index a19b06f18e40..55fcf17d503e 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3360,7 +3360,7 @@ ice_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) struct ice_pf *pf = ice_netdev_to_pf(dev); /* only report timestamping if PTP is enabled */ - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return ethtool_op_get_ts_info(dev, info); info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 3b6605c8585e..8ed4af219f9b 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -1430,7 +1430,7 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) struct ice_ptp_port *ptp_port; struct ice_hw *hw = &pf->hw; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return; if (WARN_ON_ONCE(port >= ICE_NUM_EXTERNAL_PORTS)) @@ -2162,7 +2162,7 @@ int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) { struct hwtstamp_config *config; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return -EIO; config = &pf->ptp.tstamp_config; @@ -2232,7 +2232,7 @@ int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr) struct hwtstamp_config config; int err; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return -EAGAIN; if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) @@ -2616,7 +2616,7 @@ static void ice_ptp_periodic_work(struct kthread_work *work) struct ice_pf *pf = container_of(ptp, struct ice_pf, ptp); int err; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return; err = ice_ptp_update_cached_phctime(pf); @@ -2628,6 +2628,42 @@ static void ice_ptp_periodic_work(struct kthread_work *work) msecs_to_jiffies(err ? 10 : 500)); } +/** + * ice_ptp_prepare_for_reset - Prepare PTP for reset + * @pf: Board private structure + */ +void ice_ptp_prepare_for_reset(struct ice_pf *pf) +{ + struct ice_ptp *ptp = &pf->ptp; + u8 src_tmr; + + if (ptp->state != ICE_PTP_READY) + return; + + ptp->state = ICE_PTP_RESETTING; + + /* Disable timestamping for both Tx and Rx */ + ice_ptp_disable_timestamp_mode(pf); + + kthread_cancel_delayed_work_sync(&ptp->work); + + if (test_bit(ICE_PFR_REQ, pf->state)) + return; + + ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); + + /* Disable periodic outputs */ + ice_ptp_disable_all_clkout(pf); + + src_tmr = ice_get_ptp_src_clock_index(&pf->hw); + + /* Disable source clock */ + wr32(&pf->hw, GLTSYN_ENA(src_tmr), (u32)~GLTSYN_ENA_TSYN_ENA_M); + + /* Acquire PHC and system timer to restore after reset */ + ptp->reset_time = ktime_get_real_ns(); +} + /** * ice_ptp_reset - Initialize PTP hardware clock support after reset * @pf: Board private structure @@ -2640,6 +2676,14 @@ void ice_ptp_reset(struct ice_pf *pf) int err, itr = 1; u64 time_diff; + if (ptp->state == ICE_PTP_READY) { + ice_ptp_prepare_for_reset(pf); + } else if (ptp->state != ICE_PTP_RESETTING) { + err = -EINVAL; + dev_err(ice_pf_to_dev(pf), "PTP was not initialized\n"); + goto err; + } + if (test_bit(ICE_PFR_REQ, pf->state) || !ice_pf_src_tmr_owned(pf)) goto pfr; @@ -2700,7 +2744,7 @@ pfr: if (err) goto err; - set_bit(ICE_FLAG_PTP, pf->flags); + ptp->state = ICE_PTP_READY; /* Restart the PHY timestamping block */ if (!test_bit(ICE_PFR_REQ, pf->state) && @@ -2714,6 +2758,7 @@ pfr: return; err: + ptp->state = ICE_PTP_ERROR; dev_err(ice_pf_to_dev(pf), "PTP reset failed %d\n", err); } @@ -2922,39 +2967,6 @@ int ice_ptp_clock_index(struct ice_pf *pf) return clock ? ptp_clock_index(clock) : -1; } -/** - * ice_ptp_prepare_for_reset - Prepare PTP for reset - * @pf: Board private structure - */ -void ice_ptp_prepare_for_reset(struct ice_pf *pf) -{ - struct ice_ptp *ptp = &pf->ptp; - u8 src_tmr; - - clear_bit(ICE_FLAG_PTP, pf->flags); - - /* Disable timestamping for both Tx and Rx */ - ice_ptp_disable_timestamp_mode(pf); - - kthread_cancel_delayed_work_sync(&ptp->work); - - if (test_bit(ICE_PFR_REQ, pf->state)) - return; - - ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); - - /* Disable periodic outputs */ - ice_ptp_disable_all_clkout(pf); - - src_tmr = ice_get_ptp_src_clock_index(&pf->hw); - - /* Disable source clock */ - wr32(&pf->hw, GLTSYN_ENA(src_tmr), (u32)~GLTSYN_ENA_TSYN_ENA_M); - - /* Acquire PHC and system timer to restore after reset */ - ptp->reset_time = ktime_get_real_ns(); -} - /** * ice_ptp_init_owner - Initialize PTP_1588_CLOCK device * @pf: Board private structure @@ -3195,6 +3207,8 @@ void ice_ptp_init(struct ice_pf *pf) struct ice_hw *hw = &pf->hw; int err; + ptp->state = ICE_PTP_INITIALIZING; + ice_ptp_init_phy_model(hw); ice_ptp_init_tx_interrupt_mode(pf); @@ -3219,12 +3233,13 @@ void ice_ptp_init(struct ice_pf *pf) /* Configure initial Tx interrupt settings */ ice_ptp_cfg_tx_interrupt(pf); - set_bit(ICE_FLAG_PTP, pf->flags); - err = ice_ptp_init_work(pf, ptp); + err = ice_ptp_create_auxbus_device(pf); if (err) goto err; - err = ice_ptp_create_auxbus_device(pf); + ptp->state = ICE_PTP_READY; + + err = ice_ptp_init_work(pf, ptp); if (err) goto err; @@ -3237,7 +3252,7 @@ err: ptp_clock_unregister(ptp->clock); pf->ptp.clock = NULL; } - clear_bit(ICE_FLAG_PTP, pf->flags); + ptp->state = ICE_PTP_ERROR; dev_err(ice_pf_to_dev(pf), "PTP failed %d\n", err); } @@ -3250,9 +3265,11 @@ err: */ void ice_ptp_release(struct ice_pf *pf) { - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return; + pf->ptp.state = ICE_PTP_UNINIT; + /* Disable timestamping for both Tx and Rx */ ice_ptp_disable_timestamp_mode(pf); @@ -3260,8 +3277,6 @@ void ice_ptp_release(struct ice_pf *pf) ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); - clear_bit(ICE_FLAG_PTP, pf->flags); - kthread_cancel_delayed_work_sync(&pf->ptp.work); ice_ptp_port_phy_stop(&pf->ptp.port); @@ -3271,6 +3286,9 @@ void ice_ptp_release(struct ice_pf *pf) pf->ptp.kworker = NULL; } + if (ice_pf_src_tmr_owned(pf)) + ice_ptp_unregister_auxbus_driver(pf); + if (!pf->ptp.clock) return; @@ -3280,7 +3298,5 @@ void ice_ptp_release(struct ice_pf *pf) ptp_clock_unregister(pf->ptp.clock); pf->ptp.clock = NULL; - ice_ptp_unregister_auxbus_driver(pf); - dev_info(ice_pf_to_dev(pf), "Removed PTP clock\n"); } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 087dd32d8762..2457380142e1 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -203,8 +203,17 @@ struct ice_ptp_port_owner { #define GLTSYN_TGT_H_IDX_MAX 4 +enum ice_ptp_state { + ICE_PTP_UNINIT = 0, + ICE_PTP_INITIALIZING, + ICE_PTP_READY, + ICE_PTP_RESETTING, + ICE_PTP_ERROR, +}; + /** * struct ice_ptp - data used for integrating with CONFIG_PTP_1588_CLOCK + * @state: current state of PTP state machine * @tx_interrupt_mode: the TX interrupt mode for the PTP clock * @port: data for the PHY port initialization procedure * @ports_owner: data for the auxiliary driver owner @@ -227,6 +236,7 @@ struct ice_ptp_port_owner { * @late_cached_phc_updates: number of times cached PHC update is late */ struct ice_ptp { + enum ice_ptp_state state; enum ice_ptp_tx_interrupt tx_interrupt_mode; struct ice_ptp_port port; struct ice_ptp_port_owner ports_owner; From c75d5e675a8542274fa0f7e52f3c4db1d4859a0c Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 25 Jan 2024 13:57:50 -0800 Subject: [PATCH 0435/2255] ice: pass reset type to PTP reset functions The ice_ptp_prepare_for_reset() and ice_ptp_reset() functions currently check the pf->flags ICE_FLAG_PFR_REQ bit to determine if the current reset is a PF reset or not. This is problematic, because it is possible that a PF reset and a higher level reset (CORE reset, GLOBAL reset, EMP reset) are requested simultaneously. In that case, the driver performs the highest level reset requested. However, the ICE_FLAG_PFR_REQ flag will still be set. The main driver reset functions take an enum ice_reset_req indicating which reset is actually being performed. Pass this data into the PTP functions and rely on this instead of relying on the driver flags. This ensures that the PTP code performs the proper level of reset that the driver is actually undergoing. Signed-off-by: Jacob Keller Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_main.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_ptp.c | 13 +++++++------ drivers/net/ethernet/intel/ice/ice_ptp.h | 16 ++++++++++++---- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index dd4a9bc0dfdc..0c589524cf43 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -613,7 +613,7 @@ skip: ice_pf_dis_all_vsi(pf, false); if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) - ice_ptp_prepare_for_reset(pf); + ice_ptp_prepare_for_reset(pf, reset_type); if (ice_is_feature_supported(pf, ICE_F_GNSS)) ice_gnss_exit(pf); @@ -7548,7 +7548,7 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) * fail. */ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) - ice_ptp_reset(pf); + ice_ptp_reset(pf, reset_type); if (ice_is_feature_supported(pf, ICE_F_GNSS)) ice_gnss_init(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 8ed4af219f9b..96b5f992f127 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2631,8 +2631,9 @@ static void ice_ptp_periodic_work(struct kthread_work *work) /** * ice_ptp_prepare_for_reset - Prepare PTP for reset * @pf: Board private structure + * @reset_type: the reset type being performed */ -void ice_ptp_prepare_for_reset(struct ice_pf *pf) +void ice_ptp_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type) { struct ice_ptp *ptp = &pf->ptp; u8 src_tmr; @@ -2647,7 +2648,7 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf) kthread_cancel_delayed_work_sync(&ptp->work); - if (test_bit(ICE_PFR_REQ, pf->state)) + if (reset_type == ICE_RESET_PFR) return; ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); @@ -2667,8 +2668,9 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf) /** * ice_ptp_reset - Initialize PTP hardware clock support after reset * @pf: Board private structure + * @reset_type: the reset type being performed */ -void ice_ptp_reset(struct ice_pf *pf) +void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type) { struct ice_ptp *ptp = &pf->ptp; struct ice_hw *hw = &pf->hw; @@ -2677,15 +2679,14 @@ void ice_ptp_reset(struct ice_pf *pf) u64 time_diff; if (ptp->state == ICE_PTP_READY) { - ice_ptp_prepare_for_reset(pf); + ice_ptp_prepare_for_reset(pf, reset_type); } else if (ptp->state != ICE_PTP_RESETTING) { err = -EINVAL; dev_err(ice_pf_to_dev(pf), "PTP was not initialized\n"); goto err; } - if (test_bit(ICE_PFR_REQ, pf->state) || - !ice_pf_src_tmr_owned(pf)) + if (reset_type == ICE_RESET_PFR || !ice_pf_src_tmr_owned(pf)) goto pfr; err = ice_ptp_init_phc(hw); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 2457380142e1..afe454abe997 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -314,8 +314,9 @@ enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf); u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, const struct ice_pkt_ctx *pkt_ctx); -void ice_ptp_reset(struct ice_pf *pf); -void ice_ptp_prepare_for_reset(struct ice_pf *pf); +void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type); +void ice_ptp_prepare_for_reset(struct ice_pf *pf, + enum ice_reset_req reset_type); void ice_ptp_init(struct ice_pf *pf); void ice_ptp_release(struct ice_pf *pf); void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup); @@ -355,8 +356,15 @@ ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, return 0; } -static inline void ice_ptp_reset(struct ice_pf *pf) { } -static inline void ice_ptp_prepare_for_reset(struct ice_pf *pf) { } +static inline void ice_ptp_reset(struct ice_pf *pf, + enum ice_reset_req reset_type) +{ +} + +static inline void ice_ptp_prepare_for_reset(struct ice_pf *pf, + enum ice_reset_req reset_type) +{ +} static inline void ice_ptp_init(struct ice_pf *pf) { } static inline void ice_ptp_release(struct ice_pf *pf) { } static inline void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) From 3f2216e8dbce04da5376ea7df410541f7b687cb0 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 25 Jan 2024 13:57:51 -0800 Subject: [PATCH 0436/2255] ice: rename verify_cached to has_ready_bitmap The tx->verify_cached flag is used to inform the Tx timestamp tracking code whether it needs to verify the cached Tx timestamp value against a previous captured value. This is necessary on E810 hardware which does not have a Tx timestamp ready bitmap. In addition, we currently rely on the fact that the ice_get_phy_tx_tstamp_ready() function returns all 1s for E810 hardware. Instead of introducing a brand new flag, rename and verify_cached to has_ready_bitmap, inverting the relevant checks. Signed-off-by: Jacob Keller Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_ptp.c | 12 ++++++------ drivers/net/ethernet/intel/ice/ice_ptp.h | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 96b5f992f127..a10e0018b2e2 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -606,11 +606,11 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx) * timestamp. If it is not, skip this for now assuming it hasn't yet * been captured by hardware. */ - if (!drop_ts && tx->verify_cached && + if (!drop_ts && !tx->has_ready_bitmap && raw_tstamp == tx->tstamps[idx].cached_tstamp) return; - if (tx->verify_cached && raw_tstamp) + if (!tx->has_ready_bitmap && raw_tstamp) tx->tstamps[idx].cached_tstamp = raw_tstamp; clear_bit(idx, tx->in_use); skb = tx->tstamps[idx].skb; @@ -751,7 +751,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) * from the last cached timestamp. If it is not, skip this for * now assuming it hasn't yet been captured by hardware. */ - if (!drop_ts && tx->verify_cached && + if (!drop_ts && !tx->has_ready_bitmap && raw_tstamp == tx->tstamps[idx].cached_tstamp) continue; @@ -761,7 +761,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) skip_ts_read: spin_lock_irqsave(&tx->lock, flags); - if (tx->verify_cached && raw_tstamp) + if (!tx->has_ready_bitmap && raw_tstamp) tx->tstamps[idx].cached_tstamp = raw_tstamp; clear_bit(idx, tx->in_use); skb = tx->tstamps[idx].skb; @@ -1014,7 +1014,7 @@ ice_ptp_init_tx_e82x(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port) tx->block = port / ICE_PORTS_PER_QUAD; tx->offset = (port % ICE_PORTS_PER_QUAD) * INDEX_PER_PORT_E82X; tx->len = INDEX_PER_PORT_E82X; - tx->verify_cached = 0; + tx->has_ready_bitmap = 1; return ice_ptp_alloc_tx_tracker(tx); } @@ -1037,7 +1037,7 @@ ice_ptp_init_tx_e810(struct ice_pf *pf, struct ice_ptp_tx *tx) * verify new timestamps against cached copy of the last read * timestamp. */ - tx->verify_cached = 1; + tx->has_ready_bitmap = 0; return ice_ptp_alloc_tx_tracker(tx); } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index afe454abe997..aa7a5588d11d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -100,7 +100,7 @@ struct ice_perout_channel { * the last timestamp we read for a given index. If the current timestamp * value is the same as the cached value, we assume a new timestamp hasn't * been captured. This avoids reporting stale timestamps to the stack. This is - * only done if the verify_cached flag is set in ice_ptp_tx structure. + * only done if the has_ready_bitmap flag is not set in ice_ptp_tx structure. */ struct ice_tx_tstamp { struct sk_buff *skb; @@ -130,7 +130,9 @@ enum ice_tx_tstamp_work { * @init: if true, the tracker is initialized; * @calibrating: if true, the PHY is calibrating the Tx offset. During this * window, timestamps are temporarily disabled. - * @verify_cached: if true, verify new timestamp differs from last read value + * @has_ready_bitmap: if true, the hardware has a valid Tx timestamp ready + * bitmap register. If false, fall back to verifying new + * timestamp values against previously cached copy. * @last_ll_ts_idx_read: index of the last LL TS read by the FW */ struct ice_ptp_tx { @@ -143,7 +145,7 @@ struct ice_ptp_tx { u8 len; u8 init : 1; u8 calibrating : 1; - u8 verify_cached : 1; + u8 has_ready_bitmap : 1; s8 last_ll_ts_idx_read; }; From fea82915fca626eaa83f36d8a23194e8593ef4b4 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 25 Jan 2024 13:57:52 -0800 Subject: [PATCH 0437/2255] ice: don't check has_ready_bitmap in E810 functions E810 hardware does not have a Tx timestamp ready bitmap. Don't check has_ready_bitmap in E810-specific functions. Add has_ready_bitmap check in ice_ptp_process_tx_tstamp() to stop relying on the fact that ice_get_phy_tx_tstamp_ready() returns all 1s. Signed-off-by: Jacob Keller Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_ptp.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index a10e0018b2e2..69d11dbda22c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -601,17 +601,13 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx) /* Read the low 32 bit value */ raw_tstamp |= (u64)rd32(&pf->hw, PF_SB_ATQBAH); - /* For PHYs which don't implement a proper timestamp ready bitmap, - * verify that the timestamp value is different from the last cached - * timestamp. If it is not, skip this for now assuming it hasn't yet - * been captured by hardware. + /* Devices using this interface always verify the timestamp differs + * relative to the last cached timestamp value. */ - if (!drop_ts && !tx->has_ready_bitmap && - raw_tstamp == tx->tstamps[idx].cached_tstamp) + if (raw_tstamp == tx->tstamps[idx].cached_tstamp) return; - if (!tx->has_ready_bitmap && raw_tstamp) - tx->tstamps[idx].cached_tstamp = raw_tstamp; + tx->tstamps[idx].cached_tstamp = raw_tstamp; clear_bit(idx, tx->in_use); skb = tx->tstamps[idx].skb; tx->tstamps[idx].skb = NULL; @@ -701,9 +697,11 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) hw = &pf->hw; /* Read the Tx ready status first */ - err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready); - if (err) - return; + if (tx->has_ready_bitmap) { + err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready); + if (err) + return; + } /* Drop packets if the link went down */ link_up = ptp_port->link_up; @@ -731,7 +729,8 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) * If we do not, the hardware logic for generating a new * interrupt can get stuck on some devices. */ - if (!(tstamp_ready & BIT_ULL(phy_idx))) { + if (tx->has_ready_bitmap && + !(tstamp_ready & BIT_ULL(phy_idx))) { if (drop_ts) goto skip_ts_read; From 1abefdca85e8664374f53c7bc80d5f5f827ce711 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 25 Jan 2024 13:57:53 -0800 Subject: [PATCH 0438/2255] ice: rename ice_ptp_tx_cfg_intr The ice_ptp_tx_cfg_intr() function sends a control queue message to configure the PHY timestamp interrupt block. This is a very similar name to a function which is used to configure the MAC Other Interrupt Cause Enable register. Rename this function to ice_ptp_cfg_phy_interrupt in order to make it more obvious to the reader what action it performs, and distinguish it from other similarly named functions. Signed-off-by: Jacob Keller Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_ptp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 69d11dbda22c..6f2a1ad5c2a3 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -1455,14 +1455,14 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) } /** - * ice_ptp_tx_ena_intr - Enable or disable the Tx timestamp interrupt + * ice_ptp_cfg_phy_interrupt - Configure PHY interrupt settings * @pf: PF private structure * @ena: bool value to enable or disable interrupt * @threshold: Minimum number of packets at which intr is triggered * * Utility function to enable or disable Tx timestamp interrupt and threshold */ -static int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold) +static int ice_ptp_cfg_phy_interrupt(struct ice_pf *pf, bool ena, u32 threshold) { struct ice_hw *hw = &pf->hw; int err = 0; @@ -2674,8 +2674,8 @@ void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type) struct ice_ptp *ptp = &pf->ptp; struct ice_hw *hw = &pf->hw; struct timespec64 ts; - int err, itr = 1; u64 time_diff; + int err; if (ptp->state == ICE_PTP_READY) { ice_ptp_prepare_for_reset(pf, reset_type); @@ -2726,7 +2726,7 @@ void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type) if (!ice_is_e810(hw)) { /* Enable quad interrupts */ - err = ice_ptp_tx_ena_intr(pf, true, itr); + err = ice_ptp_cfg_phy_interrupt(pf, true, 1); if (err) goto err; } @@ -2979,7 +2979,7 @@ static int ice_ptp_init_owner(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; struct timespec64 ts; - int err, itr = 1; + int err; err = ice_ptp_init_phc(hw); if (err) { @@ -3014,7 +3014,7 @@ static int ice_ptp_init_owner(struct ice_pf *pf) if (!ice_is_e810(hw)) { /* Enable quad interrupts */ - err = ice_ptp_tx_ena_intr(pf, true, itr); + err = ice_ptp_cfg_phy_interrupt(pf, true, 1); if (err) goto err_exit; } From 803bef817807d2d36c930dada20c96fffae0dd19 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 25 Jan 2024 13:57:54 -0800 Subject: [PATCH 0439/2255] ice: factor out ice_ptp_rebuild_owner() The ice_ptp_reset() function uses a goto to skip past clock owner operations if performing a PF reset or if the device is not the clock owner. This is a bit confusing. Factor this out into ice_ptp_rebuild_owner() instead. The ice_ptp_reset() function is called by ice_rebuild() to restore PTP functionality after a device reset. Follow the convention set by the ice_main.c file and rename this function to ice_ptp_rebuild(), in the same way that we have ice_prepare_for_reset() and ice_ptp_prepare_for_reset(). Signed-off-by: Jacob Keller Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- drivers/net/ethernet/intel/ice/ice_ptp.c | 62 ++++++++++++++--------- drivers/net/ethernet/intel/ice/ice_ptp.h | 6 +-- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 0c589524cf43..2b7960824bc3 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -7548,7 +7548,7 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) * fail. */ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) - ice_ptp_reset(pf, reset_type); + ice_ptp_rebuild(pf, reset_type); if (ice_is_feature_supported(pf, ICE_F_GNSS)) ice_gnss_init(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 6f2a1ad5c2a3..5ede4f61c054 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2665,11 +2665,13 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type) } /** - * ice_ptp_reset - Initialize PTP hardware clock support after reset + * ice_ptp_rebuild_owner - Initialize PTP clock owner after reset * @pf: Board private structure - * @reset_type: the reset type being performed + * + * Companion function for ice_ptp_rebuild() which handles tasks that only the + * PTP clock owner instance should perform. */ -void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type) +static int ice_ptp_rebuild_owner(struct ice_pf *pf) { struct ice_ptp *ptp = &pf->ptp; struct ice_hw *hw = &pf->hw; @@ -2677,32 +2679,21 @@ void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type) u64 time_diff; int err; - if (ptp->state == ICE_PTP_READY) { - ice_ptp_prepare_for_reset(pf, reset_type); - } else if (ptp->state != ICE_PTP_RESETTING) { - err = -EINVAL; - dev_err(ice_pf_to_dev(pf), "PTP was not initialized\n"); - goto err; - } - - if (reset_type == ICE_RESET_PFR || !ice_pf_src_tmr_owned(pf)) - goto pfr; - err = ice_ptp_init_phc(hw); if (err) - goto err; + return err; /* Acquire the global hardware lock */ if (!ice_ptp_lock(hw)) { err = -EBUSY; - goto err; + return err; } /* Write the increment time value to PHY and LAN */ err = ice_ptp_write_incval(hw, ice_base_incval(pf)); if (err) { ice_ptp_unlock(hw); - goto err; + return err; } /* Write the initial Time value to PHY and LAN using the cached PHC @@ -2718,7 +2709,7 @@ void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type) err = ice_ptp_write_init(pf, &ts); if (err) { ice_ptp_unlock(hw); - goto err; + return err; } /* Release the global hardware lock */ @@ -2727,11 +2718,39 @@ void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type) if (!ice_is_e810(hw)) { /* Enable quad interrupts */ err = ice_ptp_cfg_phy_interrupt(pf, true, 1); + if (err) + return err; + + ice_ptp_restart_all_phy(pf); + } + + return 0; +} + +/** + * ice_ptp_rebuild - Initialize PTP hardware clock support after reset + * @pf: Board private structure + * @reset_type: the reset type being performed + */ +void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) +{ + struct ice_ptp *ptp = &pf->ptp; + int err; + + if (ptp->state == ICE_PTP_READY) { + ice_ptp_prepare_for_reset(pf, reset_type); + } else if (ptp->state != ICE_PTP_RESETTING) { + err = -EINVAL; + dev_err(ice_pf_to_dev(pf), "PTP was not initialized\n"); + goto err; + } + + if (ice_pf_src_tmr_owned(pf) && reset_type != ICE_RESET_PFR) { + err = ice_ptp_rebuild_owner(pf); if (err) goto err; } -pfr: /* Init Tx structures */ if (ice_is_e810(&pf->hw)) { err = ice_ptp_init_tx_e810(pf, &ptp->port.tx); @@ -2746,11 +2765,6 @@ pfr: ptp->state = ICE_PTP_READY; - /* Restart the PHY timestamping block */ - if (!test_bit(ICE_PFR_REQ, pf->state) && - ice_pf_src_tmr_owned(pf)) - ice_ptp_restart_all_phy(pf); - /* Start periodic work going */ kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index aa7a5588d11d..3af20025043a 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -316,7 +316,7 @@ enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf); u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, const struct ice_pkt_ctx *pkt_ctx); -void ice_ptp_reset(struct ice_pf *pf, enum ice_reset_req reset_type); +void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type); void ice_ptp_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type); void ice_ptp_init(struct ice_pf *pf); @@ -358,8 +358,8 @@ ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, return 0; } -static inline void ice_ptp_reset(struct ice_pf *pf, - enum ice_reset_req reset_type) +static inline void ice_ptp_rebuild(struct ice_pf *pf, + enum ice_reset_req reset_type) { } From 7a25fe5cd5fb2265065ac6765c53c0a1f1e874d3 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 25 Jan 2024 13:57:55 -0800 Subject: [PATCH 0440/2255] ice: stop destroying and reinitalizing Tx tracker during reset The ice driver currently attempts to destroy and re-initialize the Tx timestamp tracker during the reset flow. The release of the Tx tracker only happened during CORE reset or GLOBAL reset. The ice_ptp_rebuild() function always calls the ice_ptp_init_tx function which will allocate a new tracker data structure, resulting in memory leaks during PF reset. Certainly the driver should not be allocating a new tracker without removing the old tracker data, as this results in a memory leak. Additionally, there's no reason to remove the tracker memory during a reset. Remove this logic from the reset and rebuild flow. Instead of releasing the Tx tracker, flush outstanding timestamps just before we reset the PHY timestamp block in ice_ptp_cfg_phy_interrupt(). Signed-off-by: Jacob Keller Signed-off-by: Karol Kolacinski Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/ice/ice_ptp.c | 33 +++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 5ede4f61c054..c11eba07283c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -963,6 +963,22 @@ ice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx) spin_unlock_irqrestore(&tx->lock, flags); } +/** + * ice_ptp_flush_all_tx_tracker - Flush all timestamp trackers on this clock + * @pf: Board private structure + * + * Called by the clock owner to flush all the Tx timestamp trackers associated + * with the clock. + */ +static void +ice_ptp_flush_all_tx_tracker(struct ice_pf *pf) +{ + struct ice_ptp_port *port; + + list_for_each_entry(port, &pf->ptp.ports_owner.ports, list_member) + ice_ptp_flush_tx_tracker(ptp_port_to_pf(port), &port->tx); +} + /** * ice_ptp_release_tx_tracker - Release allocated memory for Tx tracker * @pf: Board private structure @@ -2715,6 +2731,11 @@ static int ice_ptp_rebuild_owner(struct ice_pf *pf) /* Release the global hardware lock */ ice_ptp_unlock(hw); + /* Flush software tracking of any outstanding timestamps since we're + * about to flush the PHY timestamp block. + */ + ice_ptp_flush_all_tx_tracker(pf); + if (!ice_is_e810(hw)) { /* Enable quad interrupts */ err = ice_ptp_cfg_phy_interrupt(pf, true, 1); @@ -2751,18 +2772,6 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) goto err; } - /* Init Tx structures */ - if (ice_is_e810(&pf->hw)) { - err = ice_ptp_init_tx_e810(pf, &ptp->port.tx); - } else { - kthread_init_delayed_work(&ptp->port.ov_work, - ice_ptp_wait_for_offsets); - err = ice_ptp_init_tx_e82x(pf, &ptp->port.tx, - ptp->port.port_num); - } - if (err) - goto err; - ptp->state = ICE_PTP_READY; /* Start periodic work going */ From 3f3ebe53620818f6e9b029850cb47b96a4ac5b3b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 25 Jan 2024 16:25:11 -0800 Subject: [PATCH 0441/2255] net/tun: use reciprocal_scale Use the inline function reciprocal_scale rather than open coding the scale optimization. Also, remove unnecessary initializations. Resulting compiled code is unchanged (according to godbolt). Signed-off-by: Stephen Hemminger Reviewed-by: Willem de Bruijn Acked-by: Jason Wang Link: https://lore.kernel.org/r/20240126002550.169608-1-stephen@networkplumber.org Signed-off-by: Paolo Abeni --- drivers/net/tun.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4a4f8c8e79fa..e335ece47dec 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -523,8 +524,7 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb) { struct tun_flow_entry *e; - u32 txq = 0; - u32 numqueues = 0; + u32 txq, numqueues; numqueues = READ_ONCE(tun->numqueues); @@ -534,8 +534,7 @@ static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb) tun_flow_save_rps_rxhash(e, txq); txq = e->queue_index; } else { - /* use multiply and shift instead of expensive divide */ - txq = ((u64)txq * numqueues) >> 32; + txq = reciprocal_scale(txq, numqueues); } return txq; From 8e41d6644f9aff1f898997418e4f2fee6bb959e5 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Fri, 26 Jan 2024 08:30:42 +0100 Subject: [PATCH 0442/2255] net: micrel: Fix set/get PHC time for lan8814 When setting or getting PHC time, the higher bits of the second time (>32 bits) they were ignored. Meaning that setting some time in the future like year 2150, it was failing to set this. The issue can be reproduced like this: # phc_ctl /dev/ptp1 set 10000000000 phc_ctl[12.290]: set clock time to 10000000000.000000000 or Sat Nov 20 17:46:40 2286 # phc_ctl /dev/ptp1 get phc_ctl[15.309]: clock time is 1410065411.018055420 or Sun Sep 7 04:50:11 2014 Signed-off-by: Horatiu Vultur Reviewed-by: Maxime Chevallier Reviewed-by: Divya Koppera Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240126073042.1845153-1-horatiu.vultur@microchip.com Signed-off-by: Paolo Abeni --- drivers/net/phy/micrel.c | 61 +++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index dad720138baa..40bea9293ddd 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -154,11 +154,13 @@ #define PTP_CMD_CTL_PTP_LTC_STEP_SEC_ BIT(5) #define PTP_CMD_CTL_PTP_LTC_STEP_NSEC_ BIT(6) +#define PTP_CLOCK_SET_SEC_HI 0x0205 #define PTP_CLOCK_SET_SEC_MID 0x0206 #define PTP_CLOCK_SET_SEC_LO 0x0207 #define PTP_CLOCK_SET_NS_HI 0x0208 #define PTP_CLOCK_SET_NS_LO 0x0209 +#define PTP_CLOCK_READ_SEC_HI 0x0229 #define PTP_CLOCK_READ_SEC_MID 0x022A #define PTP_CLOCK_READ_SEC_LO 0x022B #define PTP_CLOCK_READ_NS_HI 0x022C @@ -2592,35 +2594,31 @@ static bool lan8814_rxtstamp(struct mii_timestamper *mii_ts, struct sk_buff *skb } static void lan8814_ptp_clock_set(struct phy_device *phydev, - u32 seconds, u32 nano_seconds) + time64_t sec, u32 nsec) { - u32 sec_low, sec_high, nsec_low, nsec_high; - - sec_low = seconds & 0xffff; - sec_high = (seconds >> 16) & 0xffff; - nsec_low = nano_seconds & 0xffff; - nsec_high = (nano_seconds >> 16) & 0x3fff; - - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_LO, sec_low); - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_MID, sec_high); - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_LO, nsec_low); - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_HI, nsec_high); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_LO, lower_16_bits(sec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_MID, upper_16_bits(sec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_HI, upper_32_bits(sec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_LO, lower_16_bits(nsec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_HI, upper_16_bits(nsec)); lanphy_write_page_reg(phydev, 4, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_); } static void lan8814_ptp_clock_get(struct phy_device *phydev, - u32 *seconds, u32 *nano_seconds) + time64_t *sec, u32 *nsec) { lanphy_write_page_reg(phydev, 4, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); - *seconds = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_MID); - *seconds = (*seconds << 16) | - lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_LO); + *sec = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_HI); + *sec <<= 16; + *sec |= lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_MID); + *sec <<= 16; + *sec |= lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_LO); - *nano_seconds = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_HI); - *nano_seconds = ((*nano_seconds & 0x3fff) << 16) | - lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_LO); + *nsec = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_HI); + *nsec <<= 16; + *nsec |= lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_LO); } static int lan8814_ptpci_gettime64(struct ptp_clock_info *ptpci, @@ -2630,7 +2628,7 @@ static int lan8814_ptpci_gettime64(struct ptp_clock_info *ptpci, ptp_clock_info); struct phy_device *phydev = shared->phydev; u32 nano_seconds; - u32 seconds; + time64_t seconds; mutex_lock(&shared->shared_lock); lan8814_ptp_clock_get(phydev, &seconds, &nano_seconds); @@ -2660,38 +2658,37 @@ static void lan8814_ptp_clock_step(struct phy_device *phydev, { u32 nano_seconds_step; u64 abs_time_step_ns; - u32 unsigned_seconds; + time64_t set_seconds; u32 nano_seconds; u32 remainder; s32 seconds; if (time_step_ns > 15000000000LL) { /* convert to clock set */ - lan8814_ptp_clock_get(phydev, &unsigned_seconds, &nano_seconds); - unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL, - &remainder); + lan8814_ptp_clock_get(phydev, &set_seconds, &nano_seconds); + set_seconds += div_u64_rem(time_step_ns, 1000000000LL, + &remainder); nano_seconds += remainder; if (nano_seconds >= 1000000000) { - unsigned_seconds++; + set_seconds++; nano_seconds -= 1000000000; } - lan8814_ptp_clock_set(phydev, unsigned_seconds, nano_seconds); + lan8814_ptp_clock_set(phydev, set_seconds, nano_seconds); return; } else if (time_step_ns < -15000000000LL) { /* convert to clock set */ time_step_ns = -time_step_ns; - lan8814_ptp_clock_get(phydev, &unsigned_seconds, &nano_seconds); - unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL, - &remainder); + lan8814_ptp_clock_get(phydev, &set_seconds, &nano_seconds); + set_seconds -= div_u64_rem(time_step_ns, 1000000000LL, + &remainder); nano_seconds_step = remainder; if (nano_seconds < nano_seconds_step) { - unsigned_seconds--; + set_seconds--; nano_seconds += 1000000000; } nano_seconds -= nano_seconds_step; - lan8814_ptp_clock_set(phydev, unsigned_seconds, - nano_seconds); + lan8814_ptp_clock_set(phydev, set_seconds, nano_seconds); return; } From 4acf4e62cd572b0c806035046b3698f5585ab821 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 26 Jan 2024 17:36:16 +0100 Subject: [PATCH 0443/2255] selftests: forwarding: Add missing config entries The config file contains a partial kernel configuration to be used by `virtme-configkernel --custom'. The presumption is that the config file contains all Kconfig options needed by the selftests from the directory. In net/forwarding/config, many are missing, which manifests as spurious failures when running the selftests, with messages about unknown device types, qdisc kinds or classifier actions. Add the missing configurations. Tested the resulting configuration using virtme-ng as follows: # vng -b -f tools/testing/selftests/net/forwarding/config # vng --user root (within the VM:) # make -C tools/testing/selftests TARGETS=net/forwarding run_tests Signed-off-by: Petr Machata Link: https://lore.kernel.org/r/025abded7ff9cea5874a7fe35dcd3fd41bf5e6ac.1706286755.git.petrm@nvidia.com Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/forwarding/config | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/config b/tools/testing/selftests/net/forwarding/config index 697994a9278b..ba2343514582 100644 --- a/tools/testing/selftests/net/forwarding/config +++ b/tools/testing/selftests/net/forwarding/config @@ -6,14 +6,42 @@ CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_NET_VRF=m CONFIG_BPF_SYSCALL=y CONFIG_CGROUP_BPF=y +CONFIG_DUMMY=m +CONFIG_IPV6=y +CONFIG_IPV6_GRE=m +CONFIG_MACVLAN=m CONFIG_NET_ACT_CT=m CONFIG_NET_ACT_MIRRED=m CONFIG_NET_ACT_MPLS=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SAMPLE=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_TUNNEL_KEY=m CONFIG_NET_ACT_VLAN=m CONFIG_NET_CLS_FLOWER=m CONFIG_NET_CLS_MATCHALL=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_META=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPIP=m +CONFIG_NET_SCH_ETS=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_ACT_GACT=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_TC_SKB_EXT=y +CONFIG_NET_TEAM=y +CONFIG_NET_TEAM_MODE_LOADBALANCE=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NF_TABLES=m CONFIG_VETH=m CONFIG_NAMESPACES=y CONFIG_NET_NS=y +CONFIG_VXLAN=m +CONFIG_XFRM_USER=m From 6dce962c4cf9407c099c2e45b04288c3fada2061 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Fri, 26 Jan 2024 19:58:26 +0100 Subject: [PATCH 0444/2255] mlxsw: spectrum: Change mlxsw_sp_upper to LAG structure The structure mlxsw_sp_upper is used only as LAG. Rename it to mlxsw_sp_lag and move it to spectrum.c file, as it is used only there. Move the function mlxsw_sp_lag_get() with the structure. Signed-off-by: Amit Cohen Reviewed-by: Ido Schimmel Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlxsw/spectrum.c | 19 +++++++++++++++---- .../net/ethernet/mellanox/mlxsw/spectrum.h | 14 ++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 5d3413636a62..38428d2ef0e2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2751,6 +2751,11 @@ static void mlxsw_sp_lag_pgt_fini(struct mlxsw_sp *mlxsw_sp) #define MLXSW_SP_LAG_SEED_INIT 0xcafecafe +struct mlxsw_sp_lag { + struct net_device *dev; + unsigned int ref_count; +}; + static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; @@ -2784,7 +2789,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) if (err) return err; - mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_upper), + mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_lag), GFP_KERNEL); if (!mlxsw_sp->lags) { err = -ENOMEM; @@ -4329,11 +4334,17 @@ static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); } +static struct mlxsw_sp_lag * +mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) +{ + return &mlxsw_sp->lags[lag_id]; +} + static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev, u16 *p_lag_id) { - struct mlxsw_sp_upper *lag; + struct mlxsw_sp_lag *lag; int free_lag_id = -1; u16 max_lag; int err, i; @@ -4482,7 +4493,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct mlxsw_sp_upper *lag; + struct mlxsw_sp_lag *lag; u16 lag_id; u8 port_index; int err; @@ -4560,7 +4571,7 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u16 lag_id = mlxsw_sp_port->lag_id; - struct mlxsw_sp_upper *lag; + struct mlxsw_sp_lag *lag; if (!mlxsw_sp_port->lagged) return; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index a0c9775fa955..dd2f05a6d909 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -78,11 +78,6 @@ struct mlxsw_sp_span_entry; enum mlxsw_sp_l3proto; union mlxsw_sp_l3addr; -struct mlxsw_sp_upper { - struct net_device *dev; - unsigned int ref_count; -}; - enum mlxsw_sp_rif_type { MLXSW_SP_RIF_TYPE_SUBPORT, MLXSW_SP_RIF_TYPE_VLAN, @@ -136,6 +131,7 @@ struct mlxsw_sp_span_ops; struct mlxsw_sp_qdisc_state; struct mlxsw_sp_mall_entry; struct mlxsw_sp_pgt; +struct mlxsw_sp_lag; struct mlxsw_sp_port_mapping { u8 module; @@ -164,7 +160,7 @@ struct mlxsw_sp { const struct mlxsw_bus_info *bus_info; unsigned char base_mac[ETH_ALEN]; const unsigned char *mac_mask; - struct mlxsw_sp_upper *lags; + struct mlxsw_sp_lag *lags; struct mlxsw_sp_port_mapping *port_mapping; struct mlxsw_sp_port_mapping_events port_mapping_events; struct rhashtable sample_trigger_ht; @@ -257,12 +253,6 @@ struct mlxsw_sp_fid_core_ops { void (*fini)(struct mlxsw_sp *mlxsw_sp); }; -static inline struct mlxsw_sp_upper * -mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) -{ - return &mlxsw_sp->lags[lag_id]; -} - struct mlxsw_sp_port_pcpu_stats { u64 rx_packets; u64 rx_bytes; From 5a448905e37ecf121ede090495540230b5d03946 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Fri, 26 Jan 2024 19:58:27 +0100 Subject: [PATCH 0445/2255] mlxsw: spectrum: Remove mlxsw_sp_lag_get() A next patch will add mlxsw_sp_lag_{get,put}() functions to handle LAG reference counting and create/destroy it only for first user/last user. Remove mlxsw_sp_lag_get() function and access LAG array directly. Signed-off-by: Amit Cohen Reviewed-by: Ido Schimmel Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 38428d2ef0e2..ff52028a957b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4334,12 +4334,6 @@ static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); } -static struct mlxsw_sp_lag * -mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) -{ - return &mlxsw_sp->lags[lag_id]; -} - static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev, u16 *p_lag_id) @@ -4354,7 +4348,7 @@ static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, return err; for (i = 0; i < max_lag; i++) { - lag = mlxsw_sp_lag_get(mlxsw_sp, i); + lag = &mlxsw_sp->lags[i]; if (lag->ref_count) { if (lag->dev == lag_dev) { *p_lag_id = i; @@ -4501,7 +4495,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id); if (err) return err; - lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); + lag = &mlxsw_sp->lags[lag_id]; if (!lag->ref_count) { err = mlxsw_sp_lag_create(mlxsw_sp, lag_id); if (err) @@ -4575,7 +4569,7 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, if (!mlxsw_sp_port->lagged) return; - lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); + lag = &mlxsw_sp->lags[lag_id]; WARN_ON(lag->ref_count == 0); mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); From c6ca2884ba043e89c3588a77ce0724a7e5868f85 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Fri, 26 Jan 2024 19:58:28 +0100 Subject: [PATCH 0446/2255] mlxsw: spectrum: Query max_lag once The maximum number of LAGs is queried from core several times. It is used to allocate LAG array, and then to iterate over it. In addition, it is used for PGT initialization. To simplify the code, instead of querying it several times, store the value as part of 'mlxsw_sp' and use it. Signed-off-by: Amit Cohen Reviewed-by: Ido Schimmel Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlxsw/spectrum.c | 32 ++++--------------- .../net/ethernet/mellanox/mlxsw/spectrum.h | 1 + 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ff52028a957b..75fea062a984 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2695,23 +2695,18 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp) { char sgcr_pl[MLXSW_REG_SGCR_LEN]; - u16 max_lag; int err; if (mlxsw_core_lag_mode(mlxsw_sp->core) != MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW) return 0; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); - if (err) - return err; - /* In DDD mode, which we by default use, each LAG entry is 8 PGT * entries. The LAG table address needs to be 8-aligned, but that ought * to be the case, since the LAG table is allocated first. */ err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &mlxsw_sp->lag_pgt_base, - max_lag * 8); + mlxsw_sp->max_lag * 8); if (err) return err; if (WARN_ON_ONCE(mlxsw_sp->lag_pgt_base % 8)) { @@ -2728,25 +2723,18 @@ static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp) err_mid_alloc_range: mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base, - max_lag * 8); + mlxsw_sp->max_lag * 8); return err; } static void mlxsw_sp_lag_pgt_fini(struct mlxsw_sp *mlxsw_sp) { - u16 max_lag; - int err; - if (mlxsw_core_lag_mode(mlxsw_sp->core) != MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW) return; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); - if (err) - return; - mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base, - max_lag * 8); + mlxsw_sp->max_lag * 8); } #define MLXSW_SP_LAG_SEED_INIT 0xcafecafe @@ -2759,7 +2747,6 @@ struct mlxsw_sp_lag { static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; - u16 max_lag; u32 seed; int err; @@ -2778,7 +2765,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) if (err) return err; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); + err = mlxsw_core_max_lag(mlxsw_sp->core, &mlxsw_sp->max_lag); if (err) return err; @@ -2789,7 +2776,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) if (err) return err; - mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_lag), + mlxsw_sp->lags = kcalloc(mlxsw_sp->max_lag, sizeof(struct mlxsw_sp_lag), GFP_KERNEL); if (!mlxsw_sp->lags) { err = -ENOMEM; @@ -4340,14 +4327,9 @@ static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_lag *lag; int free_lag_id = -1; - u16 max_lag; - int err, i; + int i; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); - if (err) - return err; - - for (i = 0; i < max_lag; i++) { + for (i = 0; i < mlxsw_sp->max_lag; i++) { lag = &mlxsw_sp->lags[i]; if (lag->ref_count) { if (lag->dev == lag_dev) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index dd2f05a6d909..898d24232935 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -161,6 +161,7 @@ struct mlxsw_sp { unsigned char base_mac[ETH_ALEN]; const unsigned char *mac_mask; struct mlxsw_sp_lag *lags; + u16 max_lag; struct mlxsw_sp_port_mapping *port_mapping; struct mlxsw_sp_port_mapping_events port_mapping_events; struct rhashtable sample_trigger_ht; From 8d8d33d4e38b5c60cdb3dcd6f190fcf91e306dd0 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Fri, 26 Jan 2024 19:58:29 +0100 Subject: [PATCH 0447/2255] mlxsw: spectrum: Search for free LAD ID once Currently, the function mlxsw_sp_lag_index_get() is called twice - first as part of NETDEV_PRECHANGEUPPER event and later as part of NETDEV_CHANGEUPPER. This function will be changed in the next patch. To simplify the code, call it only once as part of NETDEV_CHANGEUPPER event and set an error message using 'extack' in case of failure. Signed-off-by: Amit Cohen Reviewed-by: Ido Schimmel Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 75fea062a984..556dfddff005 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4323,7 +4323,7 @@ static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev, - u16 *p_lag_id) + u16 *p_lag_id, struct netlink_ext_ack *extack) { struct mlxsw_sp_lag *lag; int free_lag_id = -1; @@ -4340,8 +4340,11 @@ static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, free_lag_id = i; } } - if (free_lag_id < 0) + if (free_lag_id < 0) { + NL_SET_ERR_MSG_MOD(extack, + "Exceeded number of supported LAG devices"); return -EBUSY; + } *p_lag_id = free_lag_id; return 0; } @@ -4352,12 +4355,6 @@ mlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp, struct netdev_lag_upper_info *lag_upper_info, struct netlink_ext_ack *extack) { - u16 lag_id; - - if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) { - NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices"); - return false; - } if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type"); return false; @@ -4474,7 +4471,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, u8 port_index; int err; - err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id); + err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id, extack); if (err) return err; lag = &mlxsw_sp->lags[lag_id]; From be2f16a994f09b7f95db57f106520dd5e2585050 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Fri, 26 Jan 2024 19:58:30 +0100 Subject: [PATCH 0448/2255] mlxsw: spectrum: Refactor LAG create and destroy code mlxsw_sp stores an array of LAGs. When a port joins a LAG, in case that this LAG is already in use, we only have to increase the reference counter. Otherwise, we have to search for an unused LAG ID and configure it in hardware. When a port leaves a LAG, we have to destroy it only for the last user. This code can be simplified, for such requirements we usually add get() and put() functions which create and destroy the object. Add mlxsw_sp_lag_{get,put}() and use them. These functions take care of the reference counter and hardware configuration if needed. Change the reference counter to refcount_t type which catches overflow and underflow issues. Signed-off-by: Amit Cohen Reviewed-by: Ido Schimmel Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlxsw/spectrum.c | 116 +++++++++++------- 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 556dfddff005..ecde2086c703 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2741,7 +2741,8 @@ static void mlxsw_sp_lag_pgt_fini(struct mlxsw_sp *mlxsw_sp) struct mlxsw_sp_lag { struct net_device *dev; - unsigned int ref_count; + refcount_t ref_count; + u16 lag_id; }; static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) @@ -4261,19 +4262,48 @@ mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port, } } -static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id) +static struct mlxsw_sp_lag * +mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev, + struct netlink_ext_ack *extack) { char sldr_pl[MLXSW_REG_SLDR_LEN]; + struct mlxsw_sp_lag *lag; + u16 lag_id; + int i, err; + for (i = 0; i < mlxsw_sp->max_lag; i++) { + if (!mlxsw_sp->lags[i].dev) + break; + } + + if (i == mlxsw_sp->max_lag) { + NL_SET_ERR_MSG_MOD(extack, + "Exceeded number of supported LAG devices"); + return ERR_PTR(-EBUSY); + } + + lag_id = i; mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); + if (err) + return ERR_PTR(err); + + lag = &mlxsw_sp->lags[lag_id]; + lag->lag_id = lag_id; + lag->dev = lag_dev; + refcount_set(&lag->ref_count, 1); + + return lag; } -static int mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, u16 lag_id) +static int +mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag) { char sldr_pl[MLXSW_REG_SLDR_LEN]; - mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag_id); + lag->dev = NULL; + + mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag->lag_id); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); } @@ -4321,32 +4351,44 @@ static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); } -static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, - struct net_device *lag_dev, - u16 *p_lag_id, struct netlink_ext_ack *extack) +static struct mlxsw_sp_lag * +mlxsw_sp_lag_find(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev) { - struct mlxsw_sp_lag *lag; - int free_lag_id = -1; int i; for (i = 0; i < mlxsw_sp->max_lag; i++) { - lag = &mlxsw_sp->lags[i]; - if (lag->ref_count) { - if (lag->dev == lag_dev) { - *p_lag_id = i; - return 0; - } - } else if (free_lag_id < 0) { - free_lag_id = i; - } + if (!mlxsw_sp->lags[i].dev) + continue; + + if (mlxsw_sp->lags[i].dev == lag_dev) + return &mlxsw_sp->lags[i]; } - if (free_lag_id < 0) { - NL_SET_ERR_MSG_MOD(extack, - "Exceeded number of supported LAG devices"); - return -EBUSY; + + return NULL; +} + +static struct mlxsw_sp_lag * +mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev, + struct netlink_ext_ack *extack) +{ + struct mlxsw_sp_lag *lag; + + lag = mlxsw_sp_lag_find(mlxsw_sp, lag_dev); + if (lag) { + refcount_inc(&lag->ref_count); + return lag; } - *p_lag_id = free_lag_id; - return 0; + + return mlxsw_sp_lag_create(mlxsw_sp, lag_dev, extack); +} + +static void +mlxsw_sp_lag_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag) +{ + if (!refcount_dec_and_test(&lag->ref_count)) + return; + + mlxsw_sp_lag_destroy(mlxsw_sp, lag); } static bool @@ -4471,17 +4513,11 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, u8 port_index; int err; - err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id, extack); - if (err) - return err; - lag = &mlxsw_sp->lags[lag_id]; - if (!lag->ref_count) { - err = mlxsw_sp_lag_create(mlxsw_sp, lag_id); - if (err) - return err; - lag->dev = lag_dev; - } + lag = mlxsw_sp_lag_get(mlxsw_sp, lag_dev, extack); + if (IS_ERR(lag)) + return PTR_ERR(lag); + lag_id = lag->lag_id; err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index); if (err) return err; @@ -4499,7 +4535,6 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->local_port); mlxsw_sp_port->lag_id = lag_id; mlxsw_sp_port->lagged = 1; - lag->ref_count++; err = mlxsw_sp_fid_port_join_lag(mlxsw_sp_port); if (err) @@ -4526,7 +4561,6 @@ err_replay: err_router_join: mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); err_fid_port_join_lag: - lag->ref_count--; mlxsw_sp_port->lagged = 0; mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, mlxsw_sp_port->local_port); @@ -4534,8 +4568,7 @@ err_fid_port_join_lag: err_col_port_add: mlxsw_sp_lag_uppers_bridge_leave(mlxsw_sp_port, lag_dev); err_lag_uppers_bridge_join: - if (!lag->ref_count) - mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); + mlxsw_sp_lag_put(mlxsw_sp, lag); return err; } @@ -4549,7 +4582,6 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, if (!mlxsw_sp_port->lagged) return; lag = &mlxsw_sp->lags[lag_id]; - WARN_ON(lag->ref_count == 0); mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); @@ -4563,13 +4595,11 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); - if (lag->ref_count == 1) - mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); + mlxsw_sp_lag_put(mlxsw_sp, lag); mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, mlxsw_sp_port->local_port); mlxsw_sp_port->lagged = 0; - lag->ref_count--; /* Make sure untagged frames are allowed to ingress */ mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID, From 1267f7223bec186dc26ef4e6075496c6217355de Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Fri, 26 Jan 2024 19:58:31 +0100 Subject: [PATCH 0449/2255] mlxsw: Use refcount_t for reference counting mlxsw driver uses 'unsigned int' for reference counters in several structures. Instead, use refcount_t type which allows us to catch overflow and underflow issues. Change the type of the counters and use the appropriate API. Signed-off-by: Amit Cohen Reviewed-by: Ido Schimmel Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- .../mellanox/mlxsw/core_acl_flex_actions.c | 16 ++++++++-------- .../mellanox/mlxsw/core_acl_flex_keys.c | 9 +++++---- .../net/ethernet/mellanox/mlxsw/spectrum_acl.c | 11 ++++++----- .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 17 +++++++++-------- .../ethernet/mellanox/mlxsw/spectrum_router.c | 15 ++++++++------- .../mellanox/mlxsw/spectrum_switchdev.c | 8 ++++---- 6 files changed, 40 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index faa63ea9b83e..1915fa41c622 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@ -95,7 +95,7 @@ struct mlxsw_afa_set { */ has_trap:1, has_police:1; - unsigned int ref_count; + refcount_t ref_count; struct mlxsw_afa_set *next; /* Pointer to the next set. */ struct mlxsw_afa_set *prev; /* Pointer to the previous set, * note that set may have multiple @@ -120,7 +120,7 @@ struct mlxsw_afa_fwd_entry { struct rhash_head ht_node; struct mlxsw_afa_fwd_entry_ht_key ht_key; u32 kvdl_index; - unsigned int ref_count; + refcount_t ref_count; }; static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = { @@ -282,7 +282,7 @@ static struct mlxsw_afa_set *mlxsw_afa_set_create(bool is_first) /* Need to initialize the set to pass by default */ mlxsw_afa_set_goto_set(set, MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0); set->ht_key.is_first = is_first; - set->ref_count = 1; + refcount_set(&set->ref_count, 1); return set; } @@ -330,7 +330,7 @@ static void mlxsw_afa_set_unshare(struct mlxsw_afa *mlxsw_afa, static void mlxsw_afa_set_put(struct mlxsw_afa *mlxsw_afa, struct mlxsw_afa_set *set) { - if (--set->ref_count) + if (!refcount_dec_and_test(&set->ref_count)) return; if (set->shared) mlxsw_afa_set_unshare(mlxsw_afa, set); @@ -350,7 +350,7 @@ static struct mlxsw_afa_set *mlxsw_afa_set_get(struct mlxsw_afa *mlxsw_afa, set = rhashtable_lookup_fast(&mlxsw_afa->set_ht, &orig_set->ht_key, mlxsw_afa_set_ht_params); if (set) { - set->ref_count++; + refcount_inc(&set->ref_count); mlxsw_afa_set_put(mlxsw_afa, orig_set); } else { set = orig_set; @@ -564,7 +564,7 @@ mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u16 local_port) if (!fwd_entry) return ERR_PTR(-ENOMEM); fwd_entry->ht_key.local_port = local_port; - fwd_entry->ref_count = 1; + refcount_set(&fwd_entry->ref_count, 1); err = rhashtable_insert_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node, @@ -607,7 +607,7 @@ mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port) fwd_entry = rhashtable_lookup_fast(&mlxsw_afa->fwd_entry_ht, &ht_key, mlxsw_afa_fwd_entry_ht_params); if (fwd_entry) { - fwd_entry->ref_count++; + refcount_inc(&fwd_entry->ref_count); return fwd_entry; } return mlxsw_afa_fwd_entry_create(mlxsw_afa, local_port); @@ -616,7 +616,7 @@ mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port) static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa, struct mlxsw_afa_fwd_entry *fwd_entry) { - if (--fwd_entry->ref_count) + if (!refcount_dec_and_test(&fwd_entry->ref_count)) return; mlxsw_afa_fwd_entry_destroy(mlxsw_afa, fwd_entry); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c index 0d5e6f9b466e..947500f8ed71 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "item.h" #include "core_acl_flex_keys.h" @@ -107,7 +108,7 @@ EXPORT_SYMBOL(mlxsw_afk_destroy); struct mlxsw_afk_key_info { struct list_head list; - unsigned int ref_count; + refcount_t ref_count; unsigned int blocks_count; int element_to_block[MLXSW_AFK_ELEMENT_MAX]; /* index is element, value * is index inside "blocks" @@ -334,7 +335,7 @@ mlxsw_afk_key_info_create(struct mlxsw_afk *mlxsw_afk, if (err) goto err_picker; list_add(&key_info->list, &mlxsw_afk->key_info_list); - key_info->ref_count = 1; + refcount_set(&key_info->ref_count, 1); return key_info; err_picker: @@ -356,7 +357,7 @@ mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk, key_info = mlxsw_afk_key_info_find(mlxsw_afk, elusage); if (key_info) { - key_info->ref_count++; + refcount_inc(&key_info->ref_count); return key_info; } return mlxsw_afk_key_info_create(mlxsw_afk, elusage); @@ -365,7 +366,7 @@ EXPORT_SYMBOL(mlxsw_afk_key_info_get); void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info) { - if (--key_info->ref_count) + if (!refcount_dec_and_test(&key_info->ref_count)) return; mlxsw_afk_key_info_destroy(key_info); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 7c59c8a13584..b01b000bc71c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,7 @@ struct mlxsw_sp_acl_ruleset { struct rhash_head ht_node; /* Member of acl HT */ struct mlxsw_sp_acl_ruleset_ht_key ht_key; struct rhashtable rule_ht; - unsigned int ref_count; + refcount_t ref_count; unsigned int min_prio; unsigned int max_prio; unsigned long priv[]; @@ -99,7 +100,7 @@ static bool mlxsw_sp_acl_ruleset_is_singular(const struct mlxsw_sp_acl_ruleset *ruleset) { /* We hold a reference on ruleset ourselves */ - return ruleset->ref_count == 2; + return refcount_read(&ruleset->ref_count) == 2; } int mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp, @@ -176,7 +177,7 @@ mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp, ruleset = kzalloc(alloc_size, GFP_KERNEL); if (!ruleset) return ERR_PTR(-ENOMEM); - ruleset->ref_count = 1; + refcount_set(&ruleset->ref_count, 1); ruleset->ht_key.block = block; ruleset->ht_key.chain_index = chain_index; ruleset->ht_key.ops = ops; @@ -222,13 +223,13 @@ static void mlxsw_sp_acl_ruleset_destroy(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_acl_ruleset_ref_inc(struct mlxsw_sp_acl_ruleset *ruleset) { - ruleset->ref_count++; + refcount_inc(&ruleset->ref_count); } static void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_ruleset *ruleset) { - if (--ruleset->ref_count) + if (!refcount_dec_and_test(&ruleset->ref_count)) return; mlxsw_sp_acl_ruleset_destroy(mlxsw_sp, ruleset); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 50ea1eff02b2..f20052776b3f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -155,7 +156,7 @@ struct mlxsw_sp_acl_tcam_vregion { struct mlxsw_sp_acl_tcam_rehash_ctx ctx; } rehash; struct mlxsw_sp *mlxsw_sp; - unsigned int ref_count; + refcount_t ref_count; }; struct mlxsw_sp_acl_tcam_vchunk; @@ -176,7 +177,7 @@ struct mlxsw_sp_acl_tcam_vchunk { unsigned int priority; /* Priority within the vregion and group */ struct mlxsw_sp_acl_tcam_vgroup *vgroup; struct mlxsw_sp_acl_tcam_vregion *vregion; - unsigned int ref_count; + refcount_t ref_count; }; struct mlxsw_sp_acl_tcam_entry { @@ -769,7 +770,7 @@ mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp, vregion->tcam = tcam; vregion->mlxsw_sp = mlxsw_sp; vregion->vgroup = vgroup; - vregion->ref_count = 1; + refcount_set(&vregion->ref_count, 1); vregion->key_info = mlxsw_afk_key_info_get(afk, elusage); if (IS_ERR(vregion->key_info)) { @@ -856,7 +857,7 @@ mlxsw_sp_acl_tcam_vregion_get(struct mlxsw_sp *mlxsw_sp, */ return ERR_PTR(-EOPNOTSUPP); } - vregion->ref_count++; + refcount_inc(&vregion->ref_count); return vregion; } @@ -871,7 +872,7 @@ static void mlxsw_sp_acl_tcam_vregion_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion) { - if (--vregion->ref_count) + if (!refcount_dec_and_test(&vregion->ref_count)) return; mlxsw_sp_acl_tcam_vregion_destroy(mlxsw_sp, vregion); } @@ -924,7 +925,7 @@ mlxsw_sp_acl_tcam_vchunk_create(struct mlxsw_sp *mlxsw_sp, INIT_LIST_HEAD(&vchunk->ventry_list); vchunk->priority = priority; vchunk->vgroup = vgroup; - vchunk->ref_count = 1; + refcount_set(&vchunk->ref_count, 1); vregion = mlxsw_sp_acl_tcam_vregion_get(mlxsw_sp, vgroup, priority, elusage); @@ -1008,7 +1009,7 @@ mlxsw_sp_acl_tcam_vchunk_get(struct mlxsw_sp *mlxsw_sp, if (WARN_ON(!mlxsw_afk_key_info_subset(vchunk->vregion->key_info, elusage))) return ERR_PTR(-EINVAL); - vchunk->ref_count++; + refcount_inc(&vchunk->ref_count); return vchunk; } return mlxsw_sp_acl_tcam_vchunk_create(mlxsw_sp, vgroup, @@ -1019,7 +1020,7 @@ static void mlxsw_sp_acl_tcam_vchunk_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vchunk *vchunk) { - if (--vchunk->ref_count) + if (!refcount_dec_and_test(&vchunk->ref_count)) return; mlxsw_sp_acl_tcam_vchunk_destroy(mlxsw_sp, vchunk); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 7164f9e6370f..87617df694ab 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -501,7 +501,7 @@ struct mlxsw_sp_rt6 { struct mlxsw_sp_lpm_tree { u8 id; /* tree ID */ - unsigned int ref_count; + refcount_t ref_count; enum mlxsw_sp_l3proto proto; unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT]; struct mlxsw_sp_prefix_usage prefix_usage; @@ -578,7 +578,7 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp) for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { lpm_tree = &mlxsw_sp->router->lpm.trees[i]; - if (lpm_tree->ref_count == 0) + if (refcount_read(&lpm_tree->ref_count) == 0) return lpm_tree; } return NULL; @@ -654,7 +654,7 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp, sizeof(lpm_tree->prefix_usage)); memset(&lpm_tree->prefix_ref_count, 0, sizeof(lpm_tree->prefix_ref_count)); - lpm_tree->ref_count = 1; + refcount_set(&lpm_tree->ref_count, 1); return lpm_tree; err_left_struct_set: @@ -678,7 +678,7 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { lpm_tree = &mlxsw_sp->router->lpm.trees[i]; - if (lpm_tree->ref_count != 0 && + if (refcount_read(&lpm_tree->ref_count) && lpm_tree->proto == proto && mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage, prefix_usage)) { @@ -691,14 +691,15 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree) { - lpm_tree->ref_count++; + refcount_inc(&lpm_tree->ref_count); } static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lpm_tree *lpm_tree) { - if (--lpm_tree->ref_count == 0) - mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree); + if (!refcount_dec_and_test(&lpm_tree->ref_count)) + return; + mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree); } #define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 6c749c148148..6397ff0dc951 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -61,7 +61,7 @@ struct mlxsw_sp_bridge_port { struct mlxsw_sp_bridge_device *bridge_device; struct list_head list; struct list_head vlans_list; - unsigned int ref_count; + refcount_t ref_count; u8 stp_state; unsigned long flags; bool mrouter; @@ -495,7 +495,7 @@ mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device, BR_MCAST_FLOOD; INIT_LIST_HEAD(&bridge_port->vlans_list); list_add(&bridge_port->list, &bridge_device->ports_list); - bridge_port->ref_count = 1; + refcount_set(&bridge_port->ref_count, 1); err = switchdev_bridge_port_offload(brport_dev, mlxsw_sp_port->dev, NULL, NULL, NULL, false, extack); @@ -531,7 +531,7 @@ mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge, bridge_port = mlxsw_sp_bridge_port_find(bridge, brport_dev); if (bridge_port) { - bridge_port->ref_count++; + refcount_inc(&bridge_port->ref_count); return bridge_port; } @@ -558,7 +558,7 @@ static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge, { struct mlxsw_sp_bridge_device *bridge_device; - if (--bridge_port->ref_count != 0) + if (!refcount_dec_and_test(&bridge_port->ref_count)) return; bridge_device = bridge_port->bridge_device; mlxsw_sp_bridge_port_destroy(bridge_port); From 27a90b14b93d3b2e1efd10764e456af7e2a42991 Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Tue, 30 Jan 2024 12:03:43 +0100 Subject: [PATCH 0450/2255] bpf: Build type-punning BPF selftests with -fno-strict-aliasing A few BPF selftests perform type punning and they may break strict aliasing rules, which are exploited by both GCC and clang by default while optimizing. This can lead to broken compiled programs. This patch disables strict aliasing for these particular tests, by mean of the -fno-strict-aliasing command line option. This will make sure these tests are optimized properly even if some strict aliasing rule gets violated. After this patch, GCC is able to build all the selftests without warning about potential strict aliasing issue. bpf@vger discussion on strict aliasing and BPF selftests: https://lore.kernel.org/bpf/bae1205a-b6e5-4e46-8e20-520d7c327f7a@linux.dev/T/#t Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/bae1205a-b6e5-4e46-8e20-520d7c327f7a@linux.dev Link: https://lore.kernel.org/bpf/20240130110343.11217-1-jose.marchesi@oracle.com --- tools/testing/selftests/bpf/Makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 1a3654bcb5dd..79253a376fc8 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -41,6 +41,19 @@ CFLAGS += -g $(OPT_FLAGS) -rdynamic \ LDFLAGS += $(SAN_LDFLAGS) LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread +# The following tests perform type punning and they may break strict +# aliasing rules, which are exploited by both GCC and clang by default +# while optimizing. This can lead to broken programs. +progs/bind4_prog.c-CFLAGS := -fno-strict-aliasing +progs/bind6_prog.c-CFLAGS := -fno-strict-aliasing +progs/dynptr_fail.c-CFLAGS := -fno-strict-aliasing +progs/linked_list_fail.c-CFLAGS := -fno-strict-aliasing +progs/map_kptr_fail.c-CFLAGS := -fno-strict-aliasing +progs/syscall.c-CFLAGS := -fno-strict-aliasing +progs/test_pkt_md_access.c-CFLAGS := -fno-strict-aliasing +progs/test_sk_lookup.c-CFLAGS := -fno-strict-aliasing +progs/timer_crash.c-CFLAGS := -fno-strict-aliasing + ifneq ($(LLVM),) # Silence some warnings when compiled with clang CFLAGS += -Wno-unused-command-line-argument From 24219056805f3988bf93e494499b2329453fc706 Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Tue, 30 Jan 2024 12:36:24 +0100 Subject: [PATCH 0451/2255] bpf: Move -Wno-compare-distinct-pointer-types to BPF_CFLAGS Clang supports enabling/disabling certain conversion diagnostics via the -W[no-]compare-distinct-pointer-types command line options. Disabling this warning is required by some BPF selftests due to -Werror. Until very recently GCC would emit these warnings unconditionally, which was a problem for gcc-bpf, but we added support for the command-line options to GCC upstream [1]. This patch moves the -Wno-cmopare-distinct-pointer-types from CLANG_CFLAGS to BPF_CFLAGS in selftests/bpf/Makefile so the option is also used in gcc-bpf builds, not just in clang builds. Tested in bpf-next master. No regressions. [1] https://gcc.gnu.org/pipermail/gcc-patches/2023-August/627769.html Signed-off-by: Jose E. Marchesi Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20240130113624.24940-1-jose.marchesi@oracle.com --- tools/testing/selftests/bpf/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 79253a376fc8..a38a3001527c 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -404,11 +404,11 @@ endif CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH)) BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \ -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \ - -I$(abspath $(OUTPUT)/../usr/include) + -I$(abspath $(OUTPUT)/../usr/include) \ + -Wno-compare-distinct-pointer-types # TODO: enable me -Wsign-compare -CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \ - -Wno-compare-distinct-pointer-types +CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) $(OUTPUT)/test_l4lb_noinline.o: BPF_CFLAGS += -fno-inline $(OUTPUT)/test_xdp_noinline.o: BPF_CFLAGS += -fno-inline From e2b3c4ff5d183da6d1863c2321413406a2752e7a Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 29 Jan 2024 16:06:45 -0800 Subject: [PATCH 0452/2255] bpf: add __arg_trusted global func arg tag Add support for passing PTR_TO_BTF_ID registers to global subprogs. Currently only PTR_TRUSTED flavor of PTR_TO_BTF_ID is supported. Non-NULL semantics is assumed, so caller will be forced to prove PTR_TO_BTF_ID can't be NULL. Note, we disallow global subprogs to destroy passed in PTR_TO_BTF_ID arguments, even the trusted one. We achieve that by not setting ref_obj_id when validating subprog code. This basically enforces (in Rust terms) borrowing semantics vs move semantics. Borrowing semantics seems to be a better fit for isolated global subprog validation approach. Implementation-wise, we utilize existing logic for matching user-provided BTF type to kernel-side BTF type, used by BPF CO-RE logic and following same matching rules. We enforce a unique match for types. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240130000648.2144827-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 1 + kernel/bpf/btf.c | 99 +++++++++++++++++++++++++++++++----- kernel/bpf/verifier.c | 24 +++++++++ 3 files changed, 111 insertions(+), 13 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 7f5816482a10..0dcde339dc7e 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -610,6 +610,7 @@ struct bpf_subprog_arg_info { enum bpf_arg_type arg_type; union { u32 mem_size; + u32 btf_id; }; }; diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 9ec08cfb2967..ed7a05815984 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6985,9 +6985,77 @@ static bool btf_is_dynptr_ptr(const struct btf *btf, const struct btf_type *t) return false; } +struct bpf_cand_cache { + const char *name; + u32 name_len; + u16 kind; + u16 cnt; + struct { + const struct btf *btf; + u32 id; + } cands[]; +}; + +static DEFINE_MUTEX(cand_cache_mutex); + +static struct bpf_cand_cache * +bpf_core_find_cands(struct bpf_core_ctx *ctx, u32 local_type_id); + +static int btf_get_ptr_to_btf_id(struct bpf_verifier_log *log, int arg_idx, + const struct btf *btf, const struct btf_type *t) +{ + struct bpf_cand_cache *cc; + struct bpf_core_ctx ctx = { + .btf = btf, + .log = log, + }; + u32 kern_type_id, type_id; + int err = 0; + + /* skip PTR and modifiers */ + type_id = t->type; + t = btf_type_by_id(btf, t->type); + while (btf_type_is_modifier(t)) { + type_id = t->type; + t = btf_type_by_id(btf, t->type); + } + + mutex_lock(&cand_cache_mutex); + cc = bpf_core_find_cands(&ctx, type_id); + if (IS_ERR(cc)) { + err = PTR_ERR(cc); + bpf_log(log, "arg#%d reference type('%s %s') candidate matching error: %d\n", + arg_idx, btf_type_str(t), __btf_name_by_offset(btf, t->name_off), + err); + goto cand_cache_unlock; + } + if (cc->cnt != 1) { + bpf_log(log, "arg#%d reference type('%s %s') %s\n", + arg_idx, btf_type_str(t), __btf_name_by_offset(btf, t->name_off), + cc->cnt == 0 ? "has no matches" : "is ambiguous"); + err = cc->cnt == 0 ? -ENOENT : -ESRCH; + goto cand_cache_unlock; + } + if (btf_is_module(cc->cands[0].btf)) { + bpf_log(log, "arg#%d reference type('%s %s') points to kernel module type (unsupported)\n", + arg_idx, btf_type_str(t), __btf_name_by_offset(btf, t->name_off)); + err = -EOPNOTSUPP; + goto cand_cache_unlock; + } + kern_type_id = cc->cands[0].id; + +cand_cache_unlock: + mutex_unlock(&cand_cache_mutex); + if (err) + return err; + + return kern_type_id; +} + enum btf_arg_tag { ARG_TAG_CTX = 0x1, ARG_TAG_NONNULL = 0x2, + ARG_TAG_TRUSTED = 0x4, }; /* Process BTF of a function to produce high-level expectation of function @@ -7089,6 +7157,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) if (strcmp(tag, "ctx") == 0) { tags |= ARG_TAG_CTX; + } else if (strcmp(tag, "trusted") == 0) { + tags |= ARG_TAG_TRUSTED; } else if (strcmp(tag, "nonnull") == 0) { tags |= ARG_TAG_NONNULL; } else { @@ -7127,6 +7197,22 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) sub->args[i].arg_type = ARG_PTR_TO_DYNPTR | MEM_RDONLY; continue; } + if (tags & ARG_TAG_TRUSTED) { + int kern_type_id; + + if (tags & ARG_TAG_NONNULL) { + bpf_log(log, "arg#%d has invalid combination of tags\n", i); + return -EINVAL; + } + + kern_type_id = btf_get_ptr_to_btf_id(log, i, btf, t); + if (kern_type_id < 0) + return kern_type_id; + + sub->args[i].arg_type = ARG_PTR_TO_BTF_ID | PTR_TRUSTED; + sub->args[i].btf_id = kern_type_id; + continue; + } if (is_global) { /* generic user data pointer */ u32 mem_size; @@ -8229,17 +8315,6 @@ size_t bpf_core_essential_name_len(const char *name) return n; } -struct bpf_cand_cache { - const char *name; - u32 name_len; - u16 kind; - u16 cnt; - struct { - const struct btf *btf; - u32 id; - } cands[]; -}; - static void bpf_free_cands(struct bpf_cand_cache *cands) { if (!cands->cnt) @@ -8260,8 +8335,6 @@ static struct bpf_cand_cache *vmlinux_cand_cache[VMLINUX_CAND_CACHE_SIZE]; #define MODULE_CAND_CACHE_SIZE 31 static struct bpf_cand_cache *module_cand_cache[MODULE_CAND_CACHE_SIZE]; -static DEFINE_MUTEX(cand_cache_mutex); - static void __print_cand_cache(struct bpf_verifier_log *log, struct bpf_cand_cache **cache, int cache_size) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c5d68a9d8acc..cd4d780e5400 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9336,6 +9336,18 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog, ret = process_dynptr_func(env, regno, -1, arg->arg_type, 0); if (ret) return ret; + } else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) { + struct bpf_call_arg_meta meta; + int err; + + if (register_is_null(reg) && type_may_be_null(arg->arg_type)) + continue; + + memset(&meta, 0, sizeof(meta)); /* leave func_id as zero */ + err = check_reg_type(env, regno, arg->arg_type, &arg->btf_id, &meta); + err = err ?: check_func_arg_reg_off(env, reg, regno, arg->arg_type); + if (err) + return err; } else { bpf_log(log, "verifier bug: unrecognized arg#%d type %d\n", i, arg->arg_type); @@ -20137,6 +20149,18 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog) mark_reg_known_zero(env, regs, i); reg->mem_size = arg->mem_size; reg->id = ++env->id_gen; + } else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) { + reg->type = PTR_TO_BTF_ID; + if (arg->arg_type & PTR_MAYBE_NULL) + reg->type |= PTR_MAYBE_NULL; + if (arg->arg_type & PTR_UNTRUSTED) + reg->type |= PTR_UNTRUSTED; + if (arg->arg_type & PTR_TRUSTED) + reg->type |= PTR_TRUSTED; + mark_reg_known_zero(env, regs, i); + reg->btf = bpf_get_btf_vmlinux(); /* can't fail at this point */ + reg->btf_id = arg->btf_id; + reg->id = ++env->id_gen; } else { WARN_ONCE(1, "BUG: unhandled arg#%d type %d\n", i - BPF_REG_1, arg->arg_type); From 8f2b44cd9d69ec36c9ce9623993978babb575ee8 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 29 Jan 2024 16:06:46 -0800 Subject: [PATCH 0453/2255] bpf: add arg:nullable tag to be combined with trusted pointers Add ability to mark arg:trusted arguments with optional arg:nullable tag to mark it as PTR_TO_BTF_ID_OR_NULL variant, which will allow callers to pass NULL, and subsequently will force global subprog's code to do NULL check. This allows to have "optional" PTR_TO_BTF_ID values passed into global subprogs. For now arg:nullable cannot be combined with anything else. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240130000648.2144827-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index ed7a05815984..c8c6e6cf18e7 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -7056,6 +7056,7 @@ enum btf_arg_tag { ARG_TAG_CTX = 0x1, ARG_TAG_NONNULL = 0x2, ARG_TAG_TRUSTED = 0x4, + ARG_TAG_NULLABLE = 0x8, }; /* Process BTF of a function to produce high-level expectation of function @@ -7161,6 +7162,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) tags |= ARG_TAG_TRUSTED; } else if (strcmp(tag, "nonnull") == 0) { tags |= ARG_TAG_NONNULL; + } else if (strcmp(tag, "nullable") == 0) { + tags |= ARG_TAG_NULLABLE; } else { bpf_log(log, "arg#%d has unsupported set of tags\n", i); return -EOPNOTSUPP; @@ -7210,12 +7213,19 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) return kern_type_id; sub->args[i].arg_type = ARG_PTR_TO_BTF_ID | PTR_TRUSTED; + if (tags & ARG_TAG_NULLABLE) + sub->args[i].arg_type |= PTR_MAYBE_NULL; sub->args[i].btf_id = kern_type_id; continue; } if (is_global) { /* generic user data pointer */ u32 mem_size; + if (tags & ARG_TAG_NULLABLE) { + bpf_log(log, "arg#%d has invalid combination of tags\n", i); + return -EINVAL; + } + t = btf_type_skip_modifiers(btf, t->type, NULL); ref_t = btf_resolve_size(btf, t, &mem_size); if (IS_ERR(ref_t)) { From d28bb1a86e68a3d523e0acee8281bb904dd7f451 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 29 Jan 2024 16:06:47 -0800 Subject: [PATCH 0454/2255] libbpf: add __arg_trusted and __arg_nullable tag macros Add __arg_trusted to annotate global func args that accept trusted PTR_TO_BTF_ID arguments. Also add __arg_nullable to combine with __arg_trusted (and maybe other tags in the future) to force global subprog itself (i.e., callee) to do NULL checks, as opposed to default non-NULL semantics (and thus caller's responsibility to ensure non-NULL values). Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240130000648.2144827-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/bpf_helpers.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index 2324cc42b017..79eaa581be98 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -190,6 +190,8 @@ enum libbpf_tristate { #define __arg_ctx __attribute__((btf_decl_tag("arg:ctx"))) #define __arg_nonnull __attribute((btf_decl_tag("arg:nonnull"))) +#define __arg_nullable __attribute((btf_decl_tag("arg:nullable"))) +#define __arg_trusted __attribute((btf_decl_tag("arg:trusted"))) #ifndef ___bpf_concat #define ___bpf_concat(a, b) a ## b From c381203eadb76d5601fc04b814317e7608af5f5c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 29 Jan 2024 16:06:48 -0800 Subject: [PATCH 0455/2255] selftests/bpf: add trusted global subprog arg tests Add a bunch of test cases validating behavior of __arg_trusted and its combination with __arg_nullable tag. We also validate CO-RE flavor support by kernel for __arg_trusted args. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240130000648.2144827-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/verifier.c | 2 + .../bpf/progs/verifier_global_ptr_args.c | 156 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index d62c5bf00e71..9c6072a19745 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -28,6 +28,7 @@ #include "verifier_div0.skel.h" #include "verifier_div_overflow.skel.h" #include "verifier_global_subprogs.skel.h" +#include "verifier_global_ptr_args.skel.h" #include "verifier_gotol.skel.h" #include "verifier_helper_access_var_len.skel.h" #include "verifier_helper_packet_access.skel.h" @@ -140,6 +141,7 @@ void test_verifier_direct_stack_access_wraparound(void) { RUN(verifier_direct_st void test_verifier_div0(void) { RUN(verifier_div0); } void test_verifier_div_overflow(void) { RUN(verifier_div_overflow); } void test_verifier_global_subprogs(void) { RUN(verifier_global_subprogs); } +void test_verifier_global_ptr_args(void) { RUN(verifier_global_ptr_args); } void test_verifier_gotol(void) { RUN(verifier_gotol); } void test_verifier_helper_access_var_len(void) { RUN(verifier_helper_access_var_len); } void test_verifier_helper_packet_access(void) { RUN(verifier_helper_packet_access); } diff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c new file mode 100644 index 000000000000..484d6262363f --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include "bpf_misc.h" +#include "xdp_metadata.h" +#include "bpf_kfuncs.h" + +extern struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym __weak; +extern void bpf_task_release(struct task_struct *p) __ksym __weak; + +__weak int subprog_trusted_task_nullable(struct task_struct *task __arg_trusted __arg_nullable) +{ + if (!task) + return 0; + return task->pid + task->tgid; +} + +SEC("?kprobe") +__success __log_level(2) +__msg("Validating subprog_trusted_task_nullable() func#1...") +__msg(": R1=trusted_ptr_or_null_task_struct(") +int trusted_task_arg_nullable(void *ctx) +{ + struct task_struct *t = bpf_get_current_task_btf(); + + return subprog_trusted_task_nullable(t) + subprog_trusted_task_nullable(NULL); +} + +__weak int subprog_trusted_task_nonnull(struct task_struct *task __arg_trusted) +{ + return task->pid + task->tgid; +} + +SEC("?kprobe") +__failure __log_level(2) +__msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_") +__msg("Caller passes invalid args into func#1 ('subprog_trusted_task_nonnull')") +int trusted_task_arg_nonnull_fail1(void *ctx) +{ + return subprog_trusted_task_nonnull(NULL); +} + +SEC("?tp_btf/task_newtask") +__failure __log_level(2) +__msg("R1 type=ptr_or_null_ expected=ptr_, trusted_ptr_, rcu_ptr_") +__msg("Caller passes invalid args into func#1 ('subprog_trusted_task_nonnull')") +int trusted_task_arg_nonnull_fail2(void *ctx) +{ + struct task_struct *t = bpf_get_current_task_btf(); + struct task_struct *nullable; + int res; + + nullable = bpf_task_acquire(t); + + /* should fail, PTR_TO_BTF_ID_OR_NULL */ + res = subprog_trusted_task_nonnull(nullable); + + if (nullable) + bpf_task_release(nullable); + + return res; +} + +SEC("?kprobe") +__success __log_level(2) +__msg("Validating subprog_trusted_task_nonnull() func#1...") +__msg(": R1=trusted_ptr_task_struct(") +int trusted_task_arg_nonnull(void *ctx) +{ + struct task_struct *t = bpf_get_current_task_btf(); + + return subprog_trusted_task_nonnull(t); +} + +struct task_struct___local {} __attribute__((preserve_access_index)); + +__weak int subprog_nullable_task_flavor( + struct task_struct___local *task __arg_trusted __arg_nullable) +{ + char buf[16]; + + if (!task) + return 0; + + return bpf_copy_from_user_task(&buf, sizeof(buf), NULL, (void *)task, 0); +} + +SEC("?uprobe.s") +__success __log_level(2) +__msg("Validating subprog_nullable_task_flavor() func#1...") +__msg(": R1=trusted_ptr_or_null_task_struct(") +int flavor_ptr_nullable(void *ctx) +{ + struct task_struct___local *t = (void *)bpf_get_current_task_btf(); + + return subprog_nullable_task_flavor(t); +} + +__weak int subprog_nonnull_task_flavor(struct task_struct___local *task __arg_trusted) +{ + char buf[16]; + + return bpf_copy_from_user_task(&buf, sizeof(buf), NULL, (void *)task, 0); +} + +SEC("?uprobe.s") +__success __log_level(2) +__msg("Validating subprog_nonnull_task_flavor() func#1...") +__msg(": R1=trusted_ptr_task_struct(") +int flavor_ptr_nonnull(void *ctx) +{ + struct task_struct *t = bpf_get_current_task_btf(); + + return subprog_nonnull_task_flavor((void *)t); +} + +__weak int subprog_trusted_destroy(struct task_struct *task __arg_trusted) +{ + bpf_task_release(task); /* should be rejected */ + + return 0; +} + +SEC("?tp_btf/task_newtask") +__failure __log_level(2) +__msg("release kernel function bpf_task_release expects refcounted PTR_TO_BTF_ID") +int BPF_PROG(trusted_destroy_fail, struct task_struct *task, u64 clone_flags) +{ + return subprog_trusted_destroy(task); +} + +__weak int subprog_trusted_acq_rel(struct task_struct *task __arg_trusted) +{ + struct task_struct *owned; + + owned = bpf_task_acquire(task); + if (!owned) + return 0; + + bpf_task_release(owned); /* this one is OK, we acquired it locally */ + + return 0; +} + +SEC("?tp_btf/task_newtask") +__success __log_level(2) +int BPF_PROG(trusted_acq_rel, struct task_struct *task, u64 clone_flags) +{ + return subprog_trusted_acq_rel(task); +} + +char _license[] SEC("license") = "GPL"; From 20d59ee55172fdf6072abf871fa62b2070d6383f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 30 Jan 2024 13:20:22 -0800 Subject: [PATCH 0456/2255] libbpf: add bpf_core_cast() macro Add bpf_core_cast() macro that wraps bpf_rdonly_cast() kfunc. It's more ergonomic than kfunc, as it automatically extracts btf_id with bpf_core_type_id_kernel(), and works with type names. It also casts result to (T *) pointer. See the definition of the macro, it's self-explanatory. libbpf declares bpf_rdonly_cast() extern as __weak __ksym and should be safe to not conflict with other possible declarations in user code. But we do have a conflict with current BPF selftests that declare their externs with first argument as `void *obj`, while libbpf opts into more permissive `const void *obj`. This causes conflict, so we fix up BPF selftests uses in the same patch. Acked-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240130212023.183765-2-andrii@kernel.org Signed-off-by: Martin KaFai Lau --- tools/lib/bpf/bpf_core_read.h | 13 +++++++++++++ tools/testing/selftests/bpf/bpf_kfuncs.h | 2 +- .../selftests/bpf/progs/sk_storage_omem_uncharge.c | 2 -- tools/testing/selftests/bpf/progs/type_cast.c | 4 +--- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/tools/lib/bpf/bpf_core_read.h b/tools/lib/bpf/bpf_core_read.h index 5aec301e9585..0d3e88bd7d5f 100644 --- a/tools/lib/bpf/bpf_core_read.h +++ b/tools/lib/bpf/bpf_core_read.h @@ -2,6 +2,8 @@ #ifndef __BPF_CORE_READ_H__ #define __BPF_CORE_READ_H__ +#include + /* * enum bpf_field_info_kind is passed as a second argument into * __builtin_preserve_field_info() built-in to get a specific aspect of @@ -292,6 +294,17 @@ enum bpf_enum_value_kind { #define bpf_core_read_user_str(dst, sz, src) \ bpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src)) +extern void *bpf_rdonly_cast(const void *obj, __u32 btf_id) __ksym __weak; + +/* + * Cast provided pointer *ptr* into a pointer to a specified *type* in such + * a way that BPF verifier will become aware of associated kernel-side BTF + * type. This allows to access members of kernel types directly without the + * need to use BPF_CORE_READ() macros. + */ +#define bpf_core_cast(ptr, type) \ + ((typeof(type) *)bpf_rdonly_cast((ptr), bpf_core_type_id_kernel(type))) + #define ___concat(a, b) a ## b #define ___apply(fn, n) ___concat(fn, n) #define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 23c24f852f4f..0cd4111f954c 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -63,7 +63,7 @@ extern int bpf_sk_assign_tcp_reqsk(struct __sk_buff *skb, struct sock *sk, void *bpf_cast_to_kern_ctx(void *) __ksym; -void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym; +extern void *bpf_rdonly_cast(const void *obj, __u32 btf_id) __ksym __weak; extern int bpf_get_file_xattr(struct file *file, const char *name, struct bpf_dynptr *value_ptr) __ksym; diff --git a/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c b/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c index 3e745793b27a..934c4e5ada5b 100644 --- a/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c +++ b/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c @@ -12,8 +12,6 @@ int cookie_found = 0; __u64 cookie = 0; __u32 omem = 0; -void *bpf_rdonly_cast(void *, __u32) __ksym; - struct { __uint(type, BPF_MAP_TYPE_SK_STORAGE); __uint(map_flags, BPF_F_NO_PREALLOC); diff --git a/tools/testing/selftests/bpf/progs/type_cast.c b/tools/testing/selftests/bpf/progs/type_cast.c index a9629ac230fd..98ab35893f51 100644 --- a/tools/testing/selftests/bpf/progs/type_cast.c +++ b/tools/testing/selftests/bpf/progs/type_cast.c @@ -4,6 +4,7 @@ #include #include #include +#include "bpf_kfuncs.h" struct { __uint(type, BPF_MAP_TYPE_TASK_STORAGE); @@ -19,9 +20,6 @@ char name[IFNAMSIZ]; unsigned int inum; unsigned int meta_len, frag0_len, kskb_len, kskb2_len; -void *bpf_cast_to_kern_ctx(void *) __ksym; -void *bpf_rdonly_cast(void *, __u32) __ksym; - SEC("?xdp") int md_xdp(struct xdp_md *ctx) { From ea9d561686fbd0e1ddf05d861d8f2c1ae8291870 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 30 Jan 2024 13:20:23 -0800 Subject: [PATCH 0457/2255] selftests/bpf: convert bpf_rdonly_cast() uses to bpf_core_cast() macro Use more ergonomic bpf_core_cast() macro instead of bpf_rdonly_cast() in selftests code. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240130212023.183765-3-andrii@kernel.org Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/progs/connect_unix_prog.c | 3 +-- .../testing/selftests/bpf/progs/getpeername_unix_prog.c | 3 +-- .../testing/selftests/bpf/progs/getsockname_unix_prog.c | 3 +-- tools/testing/selftests/bpf/progs/recvmsg_unix_prog.c | 3 +-- tools/testing/selftests/bpf/progs/sendmsg_unix_prog.c | 3 +-- .../selftests/bpf/progs/sk_storage_omem_uncharge.c | 2 +- tools/testing/selftests/bpf/progs/sock_iter_batch.c | 4 ++-- tools/testing/selftests/bpf/progs/type_cast.c | 9 ++++----- 8 files changed, 12 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/connect_unix_prog.c b/tools/testing/selftests/bpf/progs/connect_unix_prog.c index ca8aa2f116b3..2ef0e0c46d17 100644 --- a/tools/testing/selftests/bpf/progs/connect_unix_prog.c +++ b/tools/testing/selftests/bpf/progs/connect_unix_prog.c @@ -28,8 +28,7 @@ int connect_unix_prog(struct bpf_sock_addr *ctx) if (sa_kern->uaddrlen != unaddrlen) return 0; - sa_kern_unaddr = bpf_rdonly_cast(sa_kern->uaddr, - bpf_core_type_id_kernel(struct sockaddr_un)); + sa_kern_unaddr = bpf_core_cast(sa_kern->uaddr, struct sockaddr_un); if (memcmp(sa_kern_unaddr->sun_path, SERVUN_REWRITE_ADDRESS, sizeof(SERVUN_REWRITE_ADDRESS) - 1) != 0) return 0; diff --git a/tools/testing/selftests/bpf/progs/getpeername_unix_prog.c b/tools/testing/selftests/bpf/progs/getpeername_unix_prog.c index 9c078f34bbb2..5a76754f846b 100644 --- a/tools/testing/selftests/bpf/progs/getpeername_unix_prog.c +++ b/tools/testing/selftests/bpf/progs/getpeername_unix_prog.c @@ -27,8 +27,7 @@ int getpeername_unix_prog(struct bpf_sock_addr *ctx) if (sa_kern->uaddrlen != unaddrlen) return 1; - sa_kern_unaddr = bpf_rdonly_cast(sa_kern->uaddr, - bpf_core_type_id_kernel(struct sockaddr_un)); + sa_kern_unaddr = bpf_core_cast(sa_kern->uaddr, struct sockaddr_un); if (memcmp(sa_kern_unaddr->sun_path, SERVUN_REWRITE_ADDRESS, sizeof(SERVUN_REWRITE_ADDRESS) - 1) != 0) return 1; diff --git a/tools/testing/selftests/bpf/progs/getsockname_unix_prog.c b/tools/testing/selftests/bpf/progs/getsockname_unix_prog.c index ac7145111497..7867113c696f 100644 --- a/tools/testing/selftests/bpf/progs/getsockname_unix_prog.c +++ b/tools/testing/selftests/bpf/progs/getsockname_unix_prog.c @@ -27,8 +27,7 @@ int getsockname_unix_prog(struct bpf_sock_addr *ctx) if (sa_kern->uaddrlen != unaddrlen) return 1; - sa_kern_unaddr = bpf_rdonly_cast(sa_kern->uaddr, - bpf_core_type_id_kernel(struct sockaddr_un)); + sa_kern_unaddr = bpf_core_cast(sa_kern->uaddr, struct sockaddr_un); if (memcmp(sa_kern_unaddr->sun_path, SERVUN_REWRITE_ADDRESS, sizeof(SERVUN_REWRITE_ADDRESS) - 1) != 0) return 1; diff --git a/tools/testing/selftests/bpf/progs/recvmsg_unix_prog.c b/tools/testing/selftests/bpf/progs/recvmsg_unix_prog.c index 4dfbc8552558..1c7ab44bccfa 100644 --- a/tools/testing/selftests/bpf/progs/recvmsg_unix_prog.c +++ b/tools/testing/selftests/bpf/progs/recvmsg_unix_prog.c @@ -27,8 +27,7 @@ int recvmsg_unix_prog(struct bpf_sock_addr *ctx) if (sa_kern->uaddrlen != unaddrlen) return 1; - sa_kern_unaddr = bpf_rdonly_cast(sa_kern->uaddr, - bpf_core_type_id_kernel(struct sockaddr_un)); + sa_kern_unaddr = bpf_core_cast(sa_kern->uaddr, struct sockaddr_un); if (memcmp(sa_kern_unaddr->sun_path, SERVUN_ADDRESS, sizeof(SERVUN_ADDRESS) - 1) != 0) return 1; diff --git a/tools/testing/selftests/bpf/progs/sendmsg_unix_prog.c b/tools/testing/selftests/bpf/progs/sendmsg_unix_prog.c index 1f67e832666e..d8869b03dda9 100644 --- a/tools/testing/selftests/bpf/progs/sendmsg_unix_prog.c +++ b/tools/testing/selftests/bpf/progs/sendmsg_unix_prog.c @@ -28,8 +28,7 @@ int sendmsg_unix_prog(struct bpf_sock_addr *ctx) if (sa_kern->uaddrlen != unaddrlen) return 0; - sa_kern_unaddr = bpf_rdonly_cast(sa_kern->uaddr, - bpf_core_type_id_kernel(struct sockaddr_un)); + sa_kern_unaddr = bpf_core_cast(sa_kern->uaddr, struct sockaddr_un); if (memcmp(sa_kern_unaddr->sun_path, SERVUN_REWRITE_ADDRESS, sizeof(SERVUN_REWRITE_ADDRESS) - 1) != 0) return 0; diff --git a/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c b/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c index 934c4e5ada5b..46d6eb2a3b17 100644 --- a/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c +++ b/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c @@ -27,7 +27,7 @@ int BPF_PROG(bpf_local_storage_destroy, struct bpf_local_storage *local_storage) if (local_storage_ptr != local_storage) return 0; - sk = bpf_rdonly_cast(sk_ptr, bpf_core_type_id_kernel(struct sock)); + sk = bpf_core_cast(sk_ptr, struct sock); if (sk->sk_cookie.counter != cookie) return 0; diff --git a/tools/testing/selftests/bpf/progs/sock_iter_batch.c b/tools/testing/selftests/bpf/progs/sock_iter_batch.c index ffbbfe1fa1c1..96531b0d9d55 100644 --- a/tools/testing/selftests/bpf/progs/sock_iter_batch.c +++ b/tools/testing/selftests/bpf/progs/sock_iter_batch.c @@ -32,7 +32,7 @@ int iter_tcp_soreuse(struct bpf_iter__tcp *ctx) if (!sk) return 0; - sk = bpf_rdonly_cast(sk, bpf_core_type_id_kernel(struct sock)); + sk = bpf_core_cast(sk, struct sock); if (sk->sk_family != AF_INET6 || sk->sk_state != TCP_LISTEN || !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr)) @@ -68,7 +68,7 @@ int iter_udp_soreuse(struct bpf_iter__udp *ctx) if (!sk) return 0; - sk = bpf_rdonly_cast(sk, bpf_core_type_id_kernel(struct sock)); + sk = bpf_core_cast(sk, struct sock); if (sk->sk_family != AF_INET6 || !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr)) return 0; diff --git a/tools/testing/selftests/bpf/progs/type_cast.c b/tools/testing/selftests/bpf/progs/type_cast.c index 98ab35893f51..9d808b8f4ab0 100644 --- a/tools/testing/selftests/bpf/progs/type_cast.c +++ b/tools/testing/selftests/bpf/progs/type_cast.c @@ -46,13 +46,12 @@ int md_skb(struct __sk_buff *skb) /* Simulate the following kernel macro: * #define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB))) */ - shared_info = bpf_rdonly_cast(kskb->head + kskb->end, - bpf_core_type_id_kernel(struct skb_shared_info)); + shared_info = bpf_core_cast(kskb->head + kskb->end, struct skb_shared_info); meta_len = shared_info->meta_len; frag0_len = shared_info->frag_list->len; /* kskb2 should be equal to kskb */ - kskb2 = bpf_rdonly_cast(kskb, bpf_core_type_id_kernel(struct sk_buff)); + kskb2 = bpf_core_cast(kskb, typeof(*kskb2)); kskb2_len = kskb2->len; return 0; } @@ -63,7 +62,7 @@ int BPF_PROG(untrusted_ptr, struct pt_regs *regs, long id) struct task_struct *task, *task_dup; task = bpf_get_current_task_btf(); - task_dup = bpf_rdonly_cast(task, bpf_core_type_id_kernel(struct task_struct)); + task_dup = bpf_core_cast(task, struct task_struct); (void)bpf_task_storage_get(&enter_id, task_dup, 0, 0); return 0; } @@ -71,7 +70,7 @@ int BPF_PROG(untrusted_ptr, struct pt_regs *regs, long id) SEC("?tracepoint/syscalls/sys_enter_nanosleep") int kctx_u64(void *ctx) { - u64 *kctx = bpf_rdonly_cast(ctx, bpf_core_type_id_kernel(u64)); + u64 *kctx = bpf_core_cast(ctx, u64); (void)kctx; return 0; From 047a7d261be652e0a8c756ac75936cc0dc537fc6 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Wed, 24 Jan 2024 15:58:01 +0800 Subject: [PATCH 0458/2255] net: rds: Simplify the allocation of slab caches in rds_conn_init Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Link: https://lore.kernel.org/r/20240124075801.471330-1-chentao@kylinos.cn Signed-off-by: Jakub Kicinski --- net/rds/connection.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/rds/connection.c b/net/rds/connection.c index b4cc699c5fad..c749c5525b40 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -829,9 +829,7 @@ int rds_conn_init(void) if (ret) return ret; - rds_conn_slab = kmem_cache_create("rds_connection", - sizeof(struct rds_connection), - 0, 0, NULL); + rds_conn_slab = KMEM_CACHE(rds_connection, 0); if (!rds_conn_slab) { rds_loop_net_exit(); return -ENOMEM; From 6a571895116e688b2f54990cc537634337990b08 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 20 Jan 2024 08:02:20 +0100 Subject: [PATCH 0459/2255] xdp: Remove usage of the deprecated ida_simple_xx() API ida_alloc() and ida_free() should be preferred to the deprecated ida_simple_get() and ida_simple_remove(). Note that the upper limit of ida_simple_get() is exclusive, but the one of ida_alloc_range() is inclusive. So a -1 has been added when needed. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/8e889d18a6c881b09db4650d4b30a62d76f4fe77.1705734073.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- net/core/xdp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/xdp.c b/net/core/xdp.c index 4869c1c2d8f3..27b585f3fa81 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -75,7 +75,7 @@ static void __xdp_mem_allocator_rcu_free(struct rcu_head *rcu) xa = container_of(rcu, struct xdp_mem_allocator, rcu); /* Allow this ID to be reused */ - ida_simple_remove(&mem_id_pool, xa->mem.id); + ida_free(&mem_id_pool, xa->mem.id); kfree(xa); } @@ -242,7 +242,7 @@ static int __mem_id_cyclic_get(gfp_t gfp) int id; again: - id = ida_simple_get(&mem_id_pool, mem_id_next, MEM_ID_MAX, gfp); + id = ida_alloc_range(&mem_id_pool, mem_id_next, MEM_ID_MAX - 1, gfp); if (id < 0) { if (id == -ENOSPC) { /* Cyclic allocator, reset next id */ @@ -317,7 +317,7 @@ static struct xdp_mem_allocator *__xdp_reg_mem_model(struct xdp_mem_info *mem, /* Insert allocator into ID lookup table */ ptr = rhashtable_insert_slow(mem_id_ht, &id, &xdp_alloc->node); if (IS_ERR(ptr)) { - ida_simple_remove(&mem_id_pool, mem->id); + ida_free(&mem_id_pool, mem->id); mem->id = 0; errno = PTR_ERR(ptr); goto err; From ccf1445204a1dec2a4807fc7f7062e273bd7cb58 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jan 2024 16:08:18 +0100 Subject: [PATCH 0460/2255] mlxsw: remove I2C_CLASS_HWMON from drivers w/o detect and address_list Class-based I2C probing requires detect() and address_list to be set in the I2C client driver, see checks in i2c_detect(). It's misleading to declare I2C_CLASS_HWMON support if this precondition isn't met. Signed-off-by: Heiner Kallweit Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/77b5ab8e-20f2-4310-bd89-57db99e2f53b@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/minimal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c index 6b98c3287b49..f0ceb196a6ce 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c @@ -708,7 +708,6 @@ static const struct i2c_device_id mlxsw_m_i2c_id[] = { static struct i2c_driver mlxsw_m_i2c_driver = { .driver.name = "mlxsw_minimal", - .class = I2C_CLASS_HWMON, .id_table = mlxsw_m_i2c_id, }; From 53e41b76a8ff27f4969e3816c0ce3a1af8156091 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 26 Jan 2024 21:21:25 +0200 Subject: [PATCH 0461/2255] dt-bindings: net: starfive,jh7110-dwmac: Add JH7100 SoC compatible The Synopsys DesignWare MAC found on StarFive JH7100 SoC is mostly similar to the newer JH7110, but it requires only two interrupts and a single reset line, which is 'ahb' instead of the commonly used 'stmmaceth'. Since the common binding 'snps,dwmac' allows selecting 'ahb' only in conjunction with 'stmmaceth', extend the logic to also permit exclusive usage of the 'ahb' reset name. This ensures the following use cases are supported: JH7110: reset-names = "stmmaceth", "ahb"; JH7100: reset-names = "ahb"; other: reset-names = "stmmaceth"; Also note the need to use a different dwmac fallback, as v5.20 applies to JH7110 only, while JH7100 relies on v3.7x. Additionally, drop the reset description items from top-level binding as they are already provided by the included snps,dwmac schema. Signed-off-by: Cristian Ciocaltea Reviewed-by: Jacob Keller Reviewed-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- .../devicetree/bindings/net/snps,dwmac.yaml | 11 +-- .../bindings/net/starfive,jh7110-dwmac.yaml | 72 +++++++++++++------ 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index 5c2769dc689a..90c4db178c67 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -95,6 +95,7 @@ properties: - snps,dwmac-5.20 - snps,dwxgmac - snps,dwxgmac-2.10 + - starfive,jh7100-dwmac - starfive,jh7110-dwmac reg: @@ -144,10 +145,12 @@ properties: - description: AHB reset reset-names: - minItems: 1 - items: - - const: stmmaceth - - const: ahb + oneOf: + - items: + - enum: [stmmaceth, ahb] + - items: + - const: stmmaceth + - const: ahb power-domains: maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml b/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml index 5e7cfbbebce6..0d1962980f57 100644 --- a/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml @@ -16,16 +16,20 @@ select: compatible: contains: enum: + - starfive,jh7100-dwmac - starfive,jh7110-dwmac required: - compatible properties: compatible: - items: - - enum: - - starfive,jh7110-dwmac - - const: snps,dwmac-5.20 + oneOf: + - items: + - const: starfive,jh7100-dwmac + - const: snps,dwmac + - items: + - const: starfive,jh7110-dwmac + - const: snps,dwmac-5.20 reg: maxItems: 1 @@ -46,24 +50,6 @@ properties: - const: tx - const: gtx - interrupts: - minItems: 3 - maxItems: 3 - - interrupt-names: - minItems: 3 - maxItems: 3 - - resets: - items: - - description: MAC Reset signal. - - description: AHB Reset signal. - - reset-names: - items: - - const: stmmaceth - - const: ahb - starfive,tx-use-rgmii-clk: description: Tx clock is provided by external rgmii clock. @@ -94,6 +80,48 @@ required: allOf: - $ref: snps,dwmac.yaml# + - if: + properties: + compatible: + contains: + const: starfive,jh7100-dwmac + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + + interrupt-names: + minItems: 2 + maxItems: 2 + + resets: + maxItems: 1 + + reset-names: + const: ahb + + - if: + properties: + compatible: + contains: + const: starfive,jh7110-dwmac + then: + properties: + interrupts: + minItems: 3 + maxItems: 3 + + interrupt-names: + minItems: 3 + maxItems: 3 + + resets: + minItems: 2 + + reset-names: + minItems: 2 + unevaluatedProperties: false examples: From 8d4597b871210429bda0f5c3a8816b7d9b6daf7e Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 26 Jan 2024 21:21:26 +0200 Subject: [PATCH 0462/2255] net: stmmac: dwmac-starfive: Add support for JH7100 SoC Add a missing quirk to enable support for the StarFive JH7100 SoC. Additionally, for greater flexibility in operation, allow using the rgmii-rxid and rgmii-txid phy modes. Co-developed-by: Emil Renner Berthing Signed-off-by: Emil Renner Berthing Signed-off-by: Cristian Ciocaltea Reviewed-by: Jacob Keller Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 6 ++-- .../ethernet/stmicro/stmmac/dwmac-starfive.c | 32 ++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 85dcda51df05..4ec61f1ee71a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -165,9 +165,9 @@ config DWMAC_STARFIVE help Support for ethernet controllers on StarFive RISC-V SoCs - This selects the StarFive platform specific glue layer support for - the stmmac device driver. This driver is used for StarFive JH7110 - ethernet controller. + This selects the StarFive platform specific glue layer support + for the stmmac device driver. This driver is used for the + StarFive JH7100 and JH7110 ethernet controllers. config DWMAC_STI tristate "STi GMAC support" diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index 5d630affb4d1..4e1076faee0c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -15,13 +15,20 @@ #include "stmmac_platform.h" -#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 -#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 -#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U +#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 +#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 +#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U + +#define JH7100_SYSMAIN_REGISTER49_DLYCHAIN 0xc8 + +struct starfive_dwmac_data { + unsigned int gtxclk_dlychain; +}; struct starfive_dwmac { struct device *dev; struct clk *clk_tx; + const struct starfive_dwmac_data *data; }; static void starfive_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode) @@ -67,6 +74,8 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: mode = STARFIVE_DWMAC_PHY_INFT_RGMII; break; @@ -89,6 +98,14 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) if (err) return dev_err_probe(dwmac->dev, err, "error setting phy mode\n"); + if (dwmac->data) { + err = regmap_write(regmap, JH7100_SYSMAIN_REGISTER49_DLYCHAIN, + dwmac->data->gtxclk_dlychain); + if (err) + return dev_err_probe(dwmac->dev, err, + "error selecting gtxclk delay chain\n"); + } + return 0; } @@ -114,6 +131,8 @@ static int starfive_dwmac_probe(struct platform_device *pdev) if (!dwmac) return -ENOMEM; + dwmac->data = device_get_match_data(&pdev->dev); + dwmac->clk_tx = devm_clk_get_enabled(&pdev->dev, "tx"); if (IS_ERR(dwmac->clk_tx)) return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->clk_tx), @@ -144,8 +163,13 @@ static int starfive_dwmac_probe(struct platform_device *pdev) return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } +static const struct starfive_dwmac_data jh7100_data = { + .gtxclk_dlychain = 4, +}; + static const struct of_device_id starfive_dwmac_match[] = { - { .compatible = "starfive,jh7110-dwmac" }, + { .compatible = "starfive,jh7100-dwmac", .data = &jh7100_data }, + { .compatible = "starfive,jh7110-dwmac" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, starfive_dwmac_match); From 2a0683be5b4c9829e8335e494a21d1148e832822 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Fri, 26 Jan 2024 18:21:18 -0500 Subject: [PATCH 0463/2255] selftests: Introduce Makefile variable to list shared bash scripts Some tests written in bash source other files in a parent directory. For example, drivers/net/bonding/dev_addr_lists.sh sources net/forwarding/lib.sh. If a subset of tests is exported and run outside the source tree (for example by using `make -C tools/testing/selftests gen_tar TARGETS="drivers/net/bonding"`), these other files must be made available as well. Commit ae108c48b5d2 ("selftests: net: Fix cross-tree inclusion of scripts") addressed this problem by symlinking and copying the sourced files but this only works for direct dependencies. Commit 25ae948b4478 ("selftests/net: add lib.sh") changed net/forwarding/lib.sh to source net/lib.sh. As a result, that latter file must be included as well when the former is exported. This was not handled and was reverted in commit 2114e83381d3 ("selftests: forwarding: Avoid failures to source net/lib.sh"). In order to allow reinstating the inclusion of net/lib.sh from net/forwarding/lib.sh, add a mechanism to list dependent files in a new Makefile variable and export them. This allows sourcing those files using the same expression whether tests are run in-tree or exported. Dependencies are not resolved recursively so transitive dependencies must be listed in TEST_INCLUDES. For example, if net/forwarding/lib.sh sources net/lib.sh; the Makefile related to a test that sources net/forwarding/lib.sh from a parent directory must list: TEST_INCLUDES := \ ../../../net/forwarding/lib.sh \ ../../../net/lib.sh v2: Fix rst syntax in Documentation/dev-tools/kselftest.rst (Jakub Kicinski) v1 (from RFC): * changed TEST_INCLUDES to take relative paths, like other TEST_* variables (Vladimir Oltean) * preserved common "$(MAKE) OUTPUT=... -C ... target" ordering in Makefile (Petr Machata) Signed-off-by: Benjamin Poirier Signed-off-by: David S. Miller --- Documentation/dev-tools/kselftest.rst | 12 ++++++++++++ tools/testing/selftests/Makefile | 7 ++++++- tools/testing/selftests/lib.mk | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst index ab376b316c36..522214c7b43b 100644 --- a/Documentation/dev-tools/kselftest.rst +++ b/Documentation/dev-tools/kselftest.rst @@ -255,9 +255,21 @@ Contributing new tests (details) TEST_PROGS_EXTENDED, TEST_GEN_PROGS_EXTENDED mean it is the executable which is not tested by default. + TEST_FILES, TEST_GEN_FILES mean it is the file which is used by test. + TEST_INCLUDES is similar to TEST_FILES, it lists files which should be + included when exporting or installing the tests, with the following + differences: + + * symlinks to files in other directories are preserved + * the part of paths below tools/testing/selftests/ is preserved when + copying the files to the output directory + + TEST_INCLUDES is meant to list dependencies located in other directories of + the selftests hierarchy. + * First use the headers inside the kernel source and/or git repo, and then the system headers. Headers for the kernel release as opposed to headers installed by the distro on the system should be the primary focus to be able diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 15b6a111c3be..082db6b68060 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -191,6 +191,8 @@ run_tests: all @for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests \ + SRC_PATH=$(shell readlink -e $$(pwd)) \ + OBJ_PATH=$(BUILD) \ O=$(abs_objtree); \ done; @@ -241,7 +243,10 @@ ifdef INSTALL_PATH @ret=1; \ for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install \ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET install \ + INSTALL_PATH=$(INSTALL_PATH)/$$TARGET \ + SRC_PATH=$(shell readlink -e $$(pwd)) \ + OBJ_PATH=$(INSTALL_PATH) \ O=$(abs_objtree) \ $(if $(FORCE_TARGETS),|| exit); \ ret=$$((ret * $$?)); \ diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index aa646e0661f3..087fee22dd53 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -69,11 +69,29 @@ define RUN_TESTS run_many $(1) endef +define INSTALL_INCLUDES + $(if $(TEST_INCLUDES), \ + relative_files=""; \ + for entry in $(TEST_INCLUDES); do \ + entry_dir=$$(readlink -e "$$(dirname "$$entry")"); \ + entry_name=$$(basename "$$entry"); \ + relative_dir=$${entry_dir#"$$SRC_PATH"/}; \ + if [ "$$relative_dir" = "$$entry_dir" ]; then \ + echo "Error: TEST_INCLUDES entry \"$$entry\" not located inside selftests directory ($$SRC_PATH)" >&2; \ + exit 1; \ + fi; \ + relative_files="$$relative_files $$relative_dir/$$entry_name"; \ + done; \ + cd $(SRC_PATH) && rsync -aR $$relative_files $(OBJ_PATH)/ \ + ) +endef + run_tests: all ifdef building_out_of_srctree @if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \ rsync -aq --copy-unsafe-links $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT); \ fi + @$(INSTALL_INCLUDES) @if [ "X$(TEST_PROGS)" != "X" ]; then \ $(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) \ $(addprefix $(OUTPUT)/,$(TEST_PROGS))) ; \ @@ -103,6 +121,7 @@ endef install: all ifdef INSTALL_PATH $(INSTALL_RULE) + $(INSTALL_INCLUDES) else $(error Error: set INSTALL_PATH to use install) endif From 6500780cffa7f221431fa4a2ec1c2f6bc51dcb6b Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Fri, 26 Jan 2024 18:21:19 -0500 Subject: [PATCH 0464/2255] selftests: bonding: Add net/forwarding/lib.sh to TEST_INCLUDES In order to avoid duplicated files when both the bonding and forwarding tests are exported together, add net/forwarding/lib.sh to TEST_INCLUDES and include it via its relative path. Reviewed-by: Petr Machata Tested-by: Petr Machata Reviewed-by: Hangbin Liu Signed-off-by: Benjamin Poirier Reviewed-by: Jay Vosburgh Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/bonding/Makefile | 6 ++++-- .../selftests/drivers/net/bonding/bond-eth-type-change.sh | 2 +- .../testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh | 2 +- .../testing/selftests/drivers/net/bonding/dev_addr_lists.sh | 2 +- .../drivers/net/bonding/mode-1-recovery-updelay.sh | 2 +- .../drivers/net/bonding/mode-2-recovery-updelay.sh | 2 +- .../selftests/drivers/net/bonding/net_forwarding_lib.sh | 1 - 7 files changed, 9 insertions(+), 8 deletions(-) delete mode 120000 tools/testing/selftests/drivers/net/bonding/net_forwarding_lib.sh diff --git a/tools/testing/selftests/drivers/net/bonding/Makefile b/tools/testing/selftests/drivers/net/bonding/Makefile index 8a72bb7de70f..1e10a1f06faf 100644 --- a/tools/testing/selftests/drivers/net/bonding/Makefile +++ b/tools/testing/selftests/drivers/net/bonding/Makefile @@ -15,7 +15,9 @@ TEST_PROGS := \ TEST_FILES := \ lag_lib.sh \ bond_topo_2d1c.sh \ - bond_topo_3d1c.sh \ - net_forwarding_lib.sh + bond_topo_3d1c.sh + +TEST_INCLUDES := \ + ../../../net/forwarding/lib.sh include ../../../lib.mk diff --git a/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh b/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh index 862e947e17c7..8293dbc7c18f 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh @@ -11,7 +11,7 @@ ALL_TESTS=" REQUIRE_MZ=no NUM_NETIFS=0 lib_dir=$(dirname "$0") -source "$lib_dir"/net_forwarding_lib.sh +source "$lib_dir"/../../../net/forwarding/lib.sh bond_check_flags() { diff --git a/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh b/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh index a509ef949dcf..0eb7edfb584c 100644 --- a/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh @@ -28,7 +28,7 @@ REQUIRE_MZ=no NUM_NETIFS=0 lib_dir=$(dirname "$0") -source ${lib_dir}/net_forwarding_lib.sh +source "$lib_dir"/../../../net/forwarding/lib.sh s_ns="s-$(mktemp -u XXXXXX)" c_ns="c-$(mktemp -u XXXXXX)" diff --git a/tools/testing/selftests/drivers/net/bonding/dev_addr_lists.sh b/tools/testing/selftests/drivers/net/bonding/dev_addr_lists.sh index 5cfe7d8ebc25..e6fa24eded5b 100755 --- a/tools/testing/selftests/drivers/net/bonding/dev_addr_lists.sh +++ b/tools/testing/selftests/drivers/net/bonding/dev_addr_lists.sh @@ -14,7 +14,7 @@ ALL_TESTS=" REQUIRE_MZ=no NUM_NETIFS=0 lib_dir=$(dirname "$0") -source "$lib_dir"/net_forwarding_lib.sh +source "$lib_dir"/../../../net/forwarding/lib.sh source "$lib_dir"/lag_lib.sh diff --git a/tools/testing/selftests/drivers/net/bonding/mode-1-recovery-updelay.sh b/tools/testing/selftests/drivers/net/bonding/mode-1-recovery-updelay.sh index b76bf5030952..9d26ab4cad0b 100755 --- a/tools/testing/selftests/drivers/net/bonding/mode-1-recovery-updelay.sh +++ b/tools/testing/selftests/drivers/net/bonding/mode-1-recovery-updelay.sh @@ -23,7 +23,7 @@ REQUIRE_MZ=no REQUIRE_JQ=no NUM_NETIFS=0 lib_dir=$(dirname "$0") -source "$lib_dir"/net_forwarding_lib.sh +source "$lib_dir"/../../../net/forwarding/lib.sh source "$lib_dir"/lag_lib.sh cleanup() diff --git a/tools/testing/selftests/drivers/net/bonding/mode-2-recovery-updelay.sh b/tools/testing/selftests/drivers/net/bonding/mode-2-recovery-updelay.sh index 8c2619002147..2d275b3e47dd 100755 --- a/tools/testing/selftests/drivers/net/bonding/mode-2-recovery-updelay.sh +++ b/tools/testing/selftests/drivers/net/bonding/mode-2-recovery-updelay.sh @@ -23,7 +23,7 @@ REQUIRE_MZ=no REQUIRE_JQ=no NUM_NETIFS=0 lib_dir=$(dirname "$0") -source "$lib_dir"/net_forwarding_lib.sh +source "$lib_dir"/../../../net/forwarding/lib.sh source "$lib_dir"/lag_lib.sh cleanup() diff --git a/tools/testing/selftests/drivers/net/bonding/net_forwarding_lib.sh b/tools/testing/selftests/drivers/net/bonding/net_forwarding_lib.sh deleted file mode 120000 index 39c96828c5ef..000000000000 --- a/tools/testing/selftests/drivers/net/bonding/net_forwarding_lib.sh +++ /dev/null @@ -1 +0,0 @@ -../../../net/forwarding/lib.sh \ No newline at end of file From 975b4a8b68ffbf3583b406758ed1b5d35b764942 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Fri, 26 Jan 2024 18:21:20 -0500 Subject: [PATCH 0465/2255] selftests: team: Add shared library scripts to TEST_INCLUDES In order to avoid duplicated files when both the team and bonding tests are exported together, add lag_lib.sh to TEST_INCLUDES. Do likewise for net/forwarding/lib.sh regarding team and forwarding tests. Reviewed-by: Petr Machata Tested-by: Petr Machata Reviewed-by: Hangbin Liu Signed-off-by: Benjamin Poirier Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/team/Makefile | 6 +++--- tools/testing/selftests/drivers/net/team/dev_addr_lists.sh | 4 ++-- tools/testing/selftests/drivers/net/team/lag_lib.sh | 1 - .../selftests/drivers/net/team/net_forwarding_lib.sh | 1 - 4 files changed, 5 insertions(+), 7 deletions(-) delete mode 120000 tools/testing/selftests/drivers/net/team/lag_lib.sh delete mode 120000 tools/testing/selftests/drivers/net/team/net_forwarding_lib.sh diff --git a/tools/testing/selftests/drivers/net/team/Makefile b/tools/testing/selftests/drivers/net/team/Makefile index 6a86e61e8bfe..708bdfce37f5 100644 --- a/tools/testing/selftests/drivers/net/team/Makefile +++ b/tools/testing/selftests/drivers/net/team/Makefile @@ -3,8 +3,8 @@ TEST_PROGS := dev_addr_lists.sh -TEST_FILES := \ - lag_lib.sh \ - net_forwarding_lib.sh +TEST_INCLUDES := \ + ../bonding/lag_lib.sh \ + ../../../net/forwarding/lib.sh include ../../../lib.mk diff --git a/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh b/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh index 33913112d5ca..b1ec7755b783 100755 --- a/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh +++ b/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh @@ -11,9 +11,9 @@ ALL_TESTS=" REQUIRE_MZ=no NUM_NETIFS=0 lib_dir=$(dirname "$0") -source "$lib_dir"/net_forwarding_lib.sh +source "$lib_dir"/../../../net/forwarding/lib.sh -source "$lib_dir"/lag_lib.sh +source "$lib_dir"/../bonding/lag_lib.sh destroy() diff --git a/tools/testing/selftests/drivers/net/team/lag_lib.sh b/tools/testing/selftests/drivers/net/team/lag_lib.sh deleted file mode 120000 index e1347a10afde..000000000000 --- a/tools/testing/selftests/drivers/net/team/lag_lib.sh +++ /dev/null @@ -1 +0,0 @@ -../bonding/lag_lib.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/team/net_forwarding_lib.sh b/tools/testing/selftests/drivers/net/team/net_forwarding_lib.sh deleted file mode 120000 index 39c96828c5ef..000000000000 --- a/tools/testing/selftests/drivers/net/team/net_forwarding_lib.sh +++ /dev/null @@ -1 +0,0 @@ -../../../net/forwarding/lib.sh \ No newline at end of file From 4a24560ad72f8febfa4e11cad63fbf24ac94c008 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Fri, 26 Jan 2024 18:21:21 -0500 Subject: [PATCH 0466/2255] selftests: dsa: Replace test symlinks by wrapper script The dsa tests which are symlinks of tests from net/forwarding/ (like tc_actions.sh) become regular files after export (because `rsync --copy-unsafe-links` is used) and expect to source lib.sh (net/forwarding/lib.sh) from the same directory. In the last patch of this series, net/forwarding/lib.sh will source lib.sh from its parent directory (ie. net/lib.sh). This would not work for dsa tests because net/lib.sh is not present under drivers/net/. Since the tests in net/forwarding/ are not meant to be copied and run from another directory, as a preparation for that last patch, replace the test symlinks by a wrapper script which runs the original tests under net/forwarding/. Following from that, the links to shared library scripts in dsa/ are no longer used so remove them and add all the original files needed from parent directories to TEST_INCLUDES. Suggested-by: Hangbin Liu Reviewed-by: Petr Machata Tested-by: Petr Machata Reviewed-by: Hangbin Liu Signed-off-by: Benjamin Poirier Signed-off-by: David S. Miller --- .../testing/selftests/drivers/net/dsa/Makefile | 17 +++++++++++++++-- .../drivers/net/dsa/bridge_locked_port.sh | 2 +- .../selftests/drivers/net/dsa/bridge_mdb.sh | 2 +- .../selftests/drivers/net/dsa/bridge_mld.sh | 2 +- .../drivers/net/dsa/bridge_vlan_aware.sh | 2 +- .../drivers/net/dsa/bridge_vlan_mcast.sh | 2 +- .../drivers/net/dsa/bridge_vlan_unaware.sh | 2 +- tools/testing/selftests/drivers/net/dsa/lib.sh | 1 - .../drivers/net/dsa/local_termination.sh | 2 +- .../selftests/drivers/net/dsa/no_forwarding.sh | 2 +- .../drivers/net/dsa/run_net_forwarding_test.sh | 9 +++++++++ .../selftests/drivers/net/dsa/tc_actions.sh | 2 +- .../selftests/drivers/net/dsa/tc_common.sh | 1 - .../drivers/net/dsa/test_bridge_fdb_stress.sh | 2 +- 14 files changed, 34 insertions(+), 14 deletions(-) delete mode 120000 tools/testing/selftests/drivers/net/dsa/lib.sh create mode 100755 tools/testing/selftests/drivers/net/dsa/run_net_forwarding_test.sh delete mode 120000 tools/testing/selftests/drivers/net/dsa/tc_common.sh diff --git a/tools/testing/selftests/drivers/net/dsa/Makefile b/tools/testing/selftests/drivers/net/dsa/Makefile index c393e7b73805..83da1d721017 100644 --- a/tools/testing/selftests/drivers/net/dsa/Makefile +++ b/tools/testing/selftests/drivers/net/dsa/Makefile @@ -11,8 +11,21 @@ TEST_PROGS = bridge_locked_port.sh \ tc_actions.sh \ test_bridge_fdb_stress.sh -TEST_PROGS_EXTENDED := lib.sh tc_common.sh +TEST_FILES := \ + run_net_forwarding_test.sh \ + forwarding.config -TEST_FILES := forwarding.config +TEST_INCLUDES := \ + ../../../net/forwarding/bridge_locked_port.sh \ + ../../../net/forwarding/bridge_mdb.sh \ + ../../../net/forwarding/bridge_mld.sh \ + ../../../net/forwarding/bridge_vlan_aware.sh \ + ../../../net/forwarding/bridge_vlan_mcast.sh \ + ../../../net/forwarding/bridge_vlan_unaware.sh \ + ../../../net/forwarding/lib.sh \ + ../../../net/forwarding/local_termination.sh \ + ../../../net/forwarding/no_forwarding.sh \ + ../../../net/forwarding/tc_actions.sh \ + ../../../net/forwarding/tc_common.sh include ../../../lib.mk diff --git a/tools/testing/selftests/drivers/net/dsa/bridge_locked_port.sh b/tools/testing/selftests/drivers/net/dsa/bridge_locked_port.sh index f5eb940c4c7c..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/bridge_locked_port.sh +++ b/tools/testing/selftests/drivers/net/dsa/bridge_locked_port.sh @@ -1 +1 @@ -../../../net/forwarding/bridge_locked_port.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/bridge_mdb.sh b/tools/testing/selftests/drivers/net/dsa/bridge_mdb.sh index 76492da525f7..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/bridge_mdb.sh +++ b/tools/testing/selftests/drivers/net/dsa/bridge_mdb.sh @@ -1 +1 @@ -../../../net/forwarding/bridge_mdb.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/bridge_mld.sh b/tools/testing/selftests/drivers/net/dsa/bridge_mld.sh index 81a7e0df0474..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/bridge_mld.sh +++ b/tools/testing/selftests/drivers/net/dsa/bridge_mld.sh @@ -1 +1 @@ -../../../net/forwarding/bridge_mld.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/bridge_vlan_aware.sh b/tools/testing/selftests/drivers/net/dsa/bridge_vlan_aware.sh index 9831ed74376a..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/bridge_vlan_aware.sh +++ b/tools/testing/selftests/drivers/net/dsa/bridge_vlan_aware.sh @@ -1 +1 @@ -../../../net/forwarding/bridge_vlan_aware.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/bridge_vlan_mcast.sh b/tools/testing/selftests/drivers/net/dsa/bridge_vlan_mcast.sh index 7f3c3f0bf719..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/bridge_vlan_mcast.sh +++ b/tools/testing/selftests/drivers/net/dsa/bridge_vlan_mcast.sh @@ -1 +1 @@ -../../../net/forwarding/bridge_vlan_mcast.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/bridge_vlan_unaware.sh b/tools/testing/selftests/drivers/net/dsa/bridge_vlan_unaware.sh index bf1a57e6bde1..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/bridge_vlan_unaware.sh +++ b/tools/testing/selftests/drivers/net/dsa/bridge_vlan_unaware.sh @@ -1 +1 @@ -../../../net/forwarding/bridge_vlan_unaware.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/lib.sh b/tools/testing/selftests/drivers/net/dsa/lib.sh deleted file mode 120000 index 39c96828c5ef..000000000000 --- a/tools/testing/selftests/drivers/net/dsa/lib.sh +++ /dev/null @@ -1 +0,0 @@ -../../../net/forwarding/lib.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/local_termination.sh b/tools/testing/selftests/drivers/net/dsa/local_termination.sh index c08166f84501..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/local_termination.sh +++ b/tools/testing/selftests/drivers/net/dsa/local_termination.sh @@ -1 +1 @@ -../../../net/forwarding/local_termination.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/no_forwarding.sh b/tools/testing/selftests/drivers/net/dsa/no_forwarding.sh index b9757466bc97..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/no_forwarding.sh +++ b/tools/testing/selftests/drivers/net/dsa/no_forwarding.sh @@ -1 +1 @@ -../../../net/forwarding/no_forwarding.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/run_net_forwarding_test.sh b/tools/testing/selftests/drivers/net/dsa/run_net_forwarding_test.sh new file mode 100755 index 000000000000..4106c0a102ea --- /dev/null +++ b/tools/testing/selftests/drivers/net/dsa/run_net_forwarding_test.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +libdir=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") +testname=$(basename "${BASH_SOURCE[0]}") + +source "$libdir"/forwarding.config +cd "$libdir"/../../../net/forwarding/ || exit 1 +source "./$testname" "$@" diff --git a/tools/testing/selftests/drivers/net/dsa/tc_actions.sh b/tools/testing/selftests/drivers/net/dsa/tc_actions.sh index 306213d9430e..d16a65e7595d 120000 --- a/tools/testing/selftests/drivers/net/dsa/tc_actions.sh +++ b/tools/testing/selftests/drivers/net/dsa/tc_actions.sh @@ -1 +1 @@ -../../../net/forwarding/tc_actions.sh \ No newline at end of file +run_net_forwarding_test.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/tc_common.sh b/tools/testing/selftests/drivers/net/dsa/tc_common.sh deleted file mode 120000 index bc3465bdc36b..000000000000 --- a/tools/testing/selftests/drivers/net/dsa/tc_common.sh +++ /dev/null @@ -1 +0,0 @@ -../../../net/forwarding/tc_common.sh \ No newline at end of file diff --git a/tools/testing/selftests/drivers/net/dsa/test_bridge_fdb_stress.sh b/tools/testing/selftests/drivers/net/dsa/test_bridge_fdb_stress.sh index 92acab83fbe2..74682151d04d 100755 --- a/tools/testing/selftests/drivers/net/dsa/test_bridge_fdb_stress.sh +++ b/tools/testing/selftests/drivers/net/dsa/test_bridge_fdb_stress.sh @@ -19,7 +19,7 @@ REQUIRE_JQ="no" REQUIRE_MZ="no" NETIF_CREATE="no" lib_dir=$(dirname "$0") -source "$lib_dir"/lib.sh +source "$lib_dir"/../../../net/forwarding/lib.sh cleanup() { echo "Cleaning up" From 9f2af915916b49f2f3a0285cae805a33c2a1dde3 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Fri, 26 Jan 2024 18:21:22 -0500 Subject: [PATCH 0467/2255] selftests: forwarding: Redefine relative_path variable The following code which is part of lib.sh: relative_path="${BASH_SOURCE%/*}" if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then relative_path="." fi reimplements functionality that is part of `dirname`: $ dirname "" . To avoid this duplication, replace "relative_path" by "net_forwarding_dir", a new variable defined using dirname. Furthermore, to avoid the potential confusion about what "relative_path" is about (cwd, test script directory or test library directory), define "net_forwarding_dir" as the absolute path to net/forwarding/. Tested-by: Petr Machata Reviewed-by: Hangbin Liu Signed-off-by: Benjamin Poirier Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 9 +++------ tools/testing/selftests/net/forwarding/mirror_gre_lib.sh | 2 +- .../selftests/net/forwarding/mirror_gre_topo_lib.sh | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 8a61464ab6eb..cf0ba4bfe50d 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -29,13 +29,10 @@ STABLE_MAC_ADDRS=${STABLE_MAC_ADDRS:=no} TCPDUMP_EXTRA_FLAGS=${TCPDUMP_EXTRA_FLAGS:=} TROUTE6=${TROUTE6:=traceroute6} -relative_path="${BASH_SOURCE%/*}" -if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then - relative_path="." -fi +net_forwarding_dir=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") -if [[ -f $relative_path/forwarding.config ]]; then - source "$relative_path/forwarding.config" +if [[ -f $net_forwarding_dir/forwarding.config ]]; then + source "$net_forwarding_dir/forwarding.config" fi # Kselftest framework requirement - SKIP code is 4. diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh b/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh index fac486178ef7..0c36546e131e 100644 --- a/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -source "$relative_path/mirror_lib.sh" +source "$net_forwarding_dir/mirror_lib.sh" quick_test_span_gre_dir_ips() { diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh b/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh index 39c03e2867f4..6e615fffa4ef 100644 --- a/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh @@ -33,7 +33,7 @@ # | | # +-------------------------------------------------------------------------+ -source "$relative_path/mirror_topo_lib.sh" +source "$net_forwarding_dir/mirror_topo_lib.sh" mirror_gre_topo_h3_create() { From 521ed1ce94bb35842357fb71918d8ebed552f941 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 26 Jan 2024 18:21:23 -0500 Subject: [PATCH 0468/2255] selftests: forwarding: Remove duplicated lib.sh content commit 25ae948b4478 ("selftests/net: add lib.sh") added net/lib.sh to contain code shared by tests under net/ and net/forwarding/. However, this caused issues with selftests from directories other than net/forwarding/, in particular those under drivers/net/. Those issues were avoided in a simple way by duplicating some content in commit 2114e83381d3 ("selftests: forwarding: Avoid failures to source net/lib.sh"). In order to remove the duplicated content, restore the inclusion of net/lib.sh from net/forwarding/lib.sh but with the following changes: * net/lib.sh is imported through the net_forwarding_dir path The original expression "source ../lib.sh" would look for lib.sh in the directory above the script file's one, which did not work for tests under drivers/net/. * net/lib.sh is added to TEST_INCLUDES Since net/forwarding/lib.sh now sources net/lib.sh, both of those files must be exported along with tests which source net/forwarding/lib.sh. Suggested-by: Hangbin Liu Reviewed-by: Hangbin Liu Signed-off-by: Petr Machata Signed-off-by: Benjamin Poirier Signed-off-by: David S. Miller --- .../selftests/drivers/net/bonding/Makefile | 3 ++- .../selftests/drivers/net/dsa/Makefile | 3 ++- .../selftests/drivers/net/team/Makefile | 3 ++- .../testing/selftests/net/forwarding/Makefile | 3 +++ tools/testing/selftests/net/forwarding/lib.sh | 26 +------------------ 5 files changed, 10 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/drivers/net/bonding/Makefile b/tools/testing/selftests/drivers/net/bonding/Makefile index 1e10a1f06faf..03a089165d3f 100644 --- a/tools/testing/selftests/drivers/net/bonding/Makefile +++ b/tools/testing/selftests/drivers/net/bonding/Makefile @@ -18,6 +18,7 @@ TEST_FILES := \ bond_topo_3d1c.sh TEST_INCLUDES := \ - ../../../net/forwarding/lib.sh + ../../../net/forwarding/lib.sh \ + ../../../net/lib.sh include ../../../lib.mk diff --git a/tools/testing/selftests/drivers/net/dsa/Makefile b/tools/testing/selftests/drivers/net/dsa/Makefile index 83da1d721017..cd6817fe5be6 100644 --- a/tools/testing/selftests/drivers/net/dsa/Makefile +++ b/tools/testing/selftests/drivers/net/dsa/Makefile @@ -26,6 +26,7 @@ TEST_INCLUDES := \ ../../../net/forwarding/local_termination.sh \ ../../../net/forwarding/no_forwarding.sh \ ../../../net/forwarding/tc_actions.sh \ - ../../../net/forwarding/tc_common.sh + ../../../net/forwarding/tc_common.sh \ + ../../../net/lib.sh include ../../../lib.mk diff --git a/tools/testing/selftests/drivers/net/team/Makefile b/tools/testing/selftests/drivers/net/team/Makefile index 708bdfce37f5..2d5a76d99181 100644 --- a/tools/testing/selftests/drivers/net/team/Makefile +++ b/tools/testing/selftests/drivers/net/team/Makefile @@ -5,6 +5,7 @@ TEST_PROGS := dev_addr_lists.sh TEST_INCLUDES := \ ../bonding/lag_lib.sh \ - ../../../net/forwarding/lib.sh + ../../../net/forwarding/lib.sh \ + ../../../net/lib.sh include ../../../lib.mk diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile index 452693514be4..1fba2717738d 100644 --- a/tools/testing/selftests/net/forwarding/Makefile +++ b/tools/testing/selftests/net/forwarding/Makefile @@ -129,4 +129,7 @@ TEST_PROGS_EXTENDED := devlink_lib.sh \ sch_tbf_etsprio.sh \ tc_common.sh +TEST_INCLUDES := \ + ../lib.sh + include ../../lib.mk diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index cf0ba4bfe50d..a7ecfc8cae98 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -35,31 +35,7 @@ if [[ -f $net_forwarding_dir/forwarding.config ]]; then source "$net_forwarding_dir/forwarding.config" fi -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=4 - -busywait() -{ - local timeout=$1; shift - - local start_time="$(date -u +%s%3N)" - while true - do - local out - out=$("$@") - local ret=$? - if ((!ret)); then - echo -n "$out" - return 0 - fi - - local current_time="$(date -u +%s%3N)" - if ((current_time - start_time > timeout)); then - echo -n "$out" - return 1 - fi - done -} +source "$net_forwarding_dir/../lib.sh" ############################################################################## # Sanity checks From 57bf3dd2fe91aa144d2c8f53b02dc4e65c9b1135 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 26 Jan 2024 21:33:03 -0500 Subject: [PATCH 0469/2255] selftests/net: calibrate fq_band_pktlimit This test validates per-band packet limits in FQ. Packets are dropped rather than enqueued if the limit for their band is reached. This test is timing sensitive. It queues packets in FQ with a future delivery time to fill the qdisc. The test failed in a virtual environment (vng). Increase the delays to make it more tolerant to environments with timing variance. Signed-off-by: Willem de Bruijn Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- tools/testing/selftests/net/fq_band_pktlimit.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/fq_band_pktlimit.sh b/tools/testing/selftests/net/fq_band_pktlimit.sh index 24b77bdf41ff..977070ed42b3 100755 --- a/tools/testing/selftests/net/fq_band_pktlimit.sh +++ b/tools/testing/selftests/net/fq_band_pktlimit.sh @@ -8,7 +8,7 @@ # 3. send 20 pkts on band A: verify that 0 are queued, 20 dropped # 4. send 20 pkts on band B: verify that 10 are queued, 10 dropped # -# Send packets with a 100ms delay to ensure that previously sent +# Send packets with a delay to ensure that previously sent # packets are still queued when later ones are sent. # Use SO_TXTIME for this. @@ -29,19 +29,21 @@ ip -6 addr add fdaa::1/128 dev dummy0 ip -6 route add fdaa::/64 dev dummy0 tc qdisc replace dev dummy0 root handle 1: fq quantum 1514 initial_quantum 1514 limit 10 -./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000 +DELAY=400000 + +./cmsg_sender -6 -p u -d "${DELAY}" -n 20 fdaa::2 8000 OUT1="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" -./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000 +./cmsg_sender -6 -p u -d "${DELAY}" -n 20 fdaa::2 8000 OUT2="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" -./cmsg_sender -6 -p u -d 100000 -n 20 -P 7 fdaa::2 8000 +./cmsg_sender -6 -p u -d "${DELAY}" -n 20 -P 7 fdaa::2 8000 OUT3="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" # Initial stats will report zero sent, as all packets are still -# queued in FQ. Sleep for the delay period (100ms) and see that +# queued in FQ. Sleep for at least the delay period and see that # twenty are now sent. -sleep 0.1 +sleep 0.6 OUT4="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')" # Log the output after the test From c5c3e1bfc9e0ee72af528df8d773980f4855938a Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Sat, 27 Jan 2024 12:04:41 +0800 Subject: [PATCH 0470/2255] net: stmmac: Offload queueMaxSDU from tc-taprio Add support for configuring queueMaxSDU. As DWMAC IPs doesn't support queueMaxSDU table handle this in the SW. The maximum 802.3 frame size that is allowed to be transmitted by any queue is queueMaxSDU + 16 bytes (i.e. 6 bytes SA + 6 bytes DA + 4 bytes FCS). Inspired from intel i225 driver. Signed-off-by: Rohan G Thomas Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 22 ++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 25 +++++++++++++++++++ include/linux/stmmac.h | 1 + 4 files changed, 49 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 721c1f8e892f..d8d2a90fd228 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -202,6 +202,7 @@ struct stmmac_extra_stats { unsigned long mtl_est_hlbf; unsigned long mtl_est_btre; unsigned long mtl_est_btrlm; + unsigned long max_sdu_txq_drop[MTL_MAX_TX_QUEUES]; /* per queue statistics */ struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b334eb16da23..33509237fe60 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2507,6 +2507,13 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) if (!xsk_tx_peek_desc(pool, &xdp_desc)) break; + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + xdp_desc.len > priv->plat->est->max_sdu[queue]) { + priv->xstats.max_sdu_txq_drop[queue]++; + continue; + } + if (likely(priv->extend_desc)) tx_desc = (struct dma_desc *)(tx_q->dma_etx + entry); else if (tx_q->tbs & STMMAC_TBS_AVAIL) @@ -4498,6 +4505,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) return stmmac_tso_xmit(skb, dev); } + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + skb->len > priv->plat->est->max_sdu[queue]){ + priv->xstats.max_sdu_txq_drop[queue]++; + goto max_sdu_err; + } + if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) { if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) { netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, @@ -4715,6 +4729,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dma_map_err: netdev_err(priv->dev, "Tx DMA map failed\n"); +max_sdu_err: dev_kfree_skb(skb); priv->xstats.tx_dropped++; return NETDEV_TX_OK; @@ -4871,6 +4886,13 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, if (stmmac_tx_avail(priv, queue) < STMMAC_TX_THRESH(priv)) return STMMAC_XDP_CONSUMED; + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + xdpf->len > priv->plat->est->max_sdu[queue]) { + priv->xstats.max_sdu_txq_drop[queue]++; + return STMMAC_XDP_CONSUMED; + } + if (likely(priv->extend_desc)) tx_desc = (struct dma_desc *)(tx_q->dma_etx + entry); else if (tx_q->tbs & STMMAC_TBS_AVAIL) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 26fa33e5ec34..07aa3a3089dc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -915,6 +915,28 @@ struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time, return time; } +static void tc_taprio_map_maxsdu_txq(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + struct plat_stmmacenet_data *plat = priv->plat; + u32 num_tc = qopt->mqprio.qopt.num_tc; + u32 offset, count, i, j; + + /* QueueMaxSDU received from the driver corresponds to the Linux traffic + * class. Map queueMaxSDU per Linux traffic class to DWMAC Tx queues. + */ + for (i = 0; i < num_tc; i++) { + if (!qopt->max_sdu[i]) + continue; + + offset = qopt->mqprio.qopt.offset[i]; + count = qopt->mqprio.qopt.count[i]; + + for (j = offset; j < offset + count; j++) + plat->est->max_sdu[j] = qopt->max_sdu[i] + ETH_HLEN - ETH_TLEN; + } +} + static int tc_setup_taprio(struct stmmac_priv *priv, struct tc_taprio_qopt_offload *qopt) { @@ -1045,6 +1067,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv, priv->plat->est->ter = qopt->cycle_time_extension; + tc_taprio_map_maxsdu_txq(priv, qopt); + if (fpe && !priv->dma_cap.fpesel) { mutex_unlock(&priv->plat->est->lock); return -EOPNOTSUPP; @@ -1126,6 +1150,7 @@ static int tc_query_caps(struct stmmac_priv *priv, return -EOPNOTSUPP; caps->gate_mask_per_txq = true; + caps->supports_queue_max_sdu = true; return 0; } diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index dee5ad6e48c5..dfa1828cd756 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -127,6 +127,7 @@ struct stmmac_est { u32 gcl_unaligned[EST_GCL]; u32 gcl[EST_GCL]; u32 gcl_size; + u32 max_sdu[MTL_MAX_TX_QUEUES]; }; struct stmmac_rxq_cfg { From fd5a6a71313e27c4f601526081b69d4e76f03dea Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Sat, 27 Jan 2024 12:04:42 +0800 Subject: [PATCH 0471/2255] net: stmmac: est: Per Tx-queue error count for HLBF Keep per Tx-queue error count on Head-Of-Line Blocking due to frame size(HLBF) error. The MAC raises HLBF error on one or more queues when none of the time Intervals of open-gates in the GCL is greater than or equal to the duration needed for frame transmission and by default drops those packets that causes HLBF error. EST_FRM_SZ_ERR register provides the One Hot encoded Queue numbers that have the Frame Size related error. Signed-off-by: Rohan G Thomas Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_est.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index d8d2a90fd228..70bef7811c91 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -203,6 +203,7 @@ struct stmmac_extra_stats { unsigned long mtl_est_btre; unsigned long mtl_est_btrlm; unsigned long max_sdu_txq_drop[MTL_MAX_TX_QUEUES]; + unsigned long mtl_est_txq_hlbf[MTL_MAX_TX_QUEUES]; /* per queue statistics */ struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c index 4da6ccc17c20..c9693f77e1f6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c @@ -81,6 +81,7 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max; void __iomem *est_addr = priv->estaddr; u32 txqcnt_mask = BIT(txqcnt) - 1; + int i; status = readl(est_addr + EST_STATUS); @@ -125,6 +126,11 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, x->mtl_est_hlbf++; + for (i = 0; i < txqcnt; i++) { + if (feqn & BIT(i)) + x->mtl_est_txq_hlbf[i]++; + } + /* Clear Interrupt */ writel(feqn, est_addr + EST_FRM_SZ_ERR); From 5ca63ffdb94ba2bac4c23c8609aabd7edd03c312 Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Sat, 27 Jan 2024 12:04:43 +0800 Subject: [PATCH 0472/2255] net: stmmac: Report taprio offload status Report taprio offload status. This includes per txq and global counters of window_drops and tx_overruns. Window_drops count include count of frames dropped because of queueMaxSDU setting and HLBF error. Transmission overrun counter inform the user application whether any packets are currently being transmitted on a particular queue during a gate-close event.DWMAC IPs takes care Transmission overrun won't happen hence this is always 0. Signed-off-by: Rohan G Thomas Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 07aa3a3089dc..cce00719937d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -937,8 +937,8 @@ static void tc_taprio_map_maxsdu_txq(struct stmmac_priv *priv, } } -static int tc_setup_taprio(struct stmmac_priv *priv, - struct tc_taprio_qopt_offload *qopt) +static int tc_taprio_configure(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) { u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep; struct plat_stmmacenet_data *plat = priv->plat; @@ -990,8 +990,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv, if (qopt->cmd == TAPRIO_CMD_DESTROY) goto disable; - else if (qopt->cmd != TAPRIO_CMD_REPLACE) - return -EOPNOTSUPP; if (qopt->num_entries >= dep) return -EINVAL; @@ -1102,6 +1100,11 @@ disable: priv->plat->est->enable = false; stmmac_est_configure(priv, priv, priv->plat->est, priv->plat->clk_ptp_rate); + /* Reset taprio status */ + for (i = 0; i < priv->plat->tx_queues_to_use; i++) { + priv->xstats.max_sdu_txq_drop[i] = 0; + priv->xstats.mtl_est_txq_hlbf[i] = 0; + } mutex_unlock(&priv->plat->est->lock); } @@ -1119,6 +1122,57 @@ disable: return ret; } +static void tc_taprio_stats(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + u64 window_drops = 0; + int i = 0; + + for (i = 0; i < priv->plat->tx_queues_to_use; i++) + window_drops += priv->xstats.max_sdu_txq_drop[i] + + priv->xstats.mtl_est_txq_hlbf[i]; + qopt->stats.window_drops = window_drops; + + /* Transmission overrun doesn't happen for stmmac, hence always 0 */ + qopt->stats.tx_overruns = 0; +} + +static void tc_taprio_queue_stats(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + struct tc_taprio_qopt_queue_stats *q_stats = &qopt->queue_stats; + int queue = qopt->queue_stats.queue; + + q_stats->stats.window_drops = priv->xstats.max_sdu_txq_drop[queue] + + priv->xstats.mtl_est_txq_hlbf[queue]; + + /* Transmission overrun doesn't happen for stmmac, hence always 0 */ + q_stats->stats.tx_overruns = 0; +} + +static int tc_setup_taprio(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + int err = 0; + + switch (qopt->cmd) { + case TAPRIO_CMD_REPLACE: + case TAPRIO_CMD_DESTROY: + err = tc_taprio_configure(priv, qopt); + break; + case TAPRIO_CMD_STATS: + tc_taprio_stats(priv, qopt); + break; + case TAPRIO_CMD_QUEUE_STATS: + tc_taprio_queue_stats(priv, qopt); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + static int tc_setup_etf(struct stmmac_priv *priv, struct tc_etf_qopt_offload *qopt) { From d80a52335374e484a4ff2afdc9af843e73273945 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jan 2024 14:25:09 +0100 Subject: [PATCH 0473/2255] ethtool: replace struct ethtool_eee with a new struct ethtool_keee on kernel side In order to pass EEE link modes beyond bit 32 to userspace we have to complement the 32 bit bitmaps in struct ethtool_eee with linkmode bitmaps. Therefore, similar to ethtool_link_settings and ethtool_link_ksettings, add a struct ethtool_keee. In a first step it's an identical copy of ethtool_eee. This patch simply does a s/ethtool_eee/ethtool_keee/g for all users. No functional change intended. Suggested-by: Andrew Lunn Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 10 +++++----- drivers/net/dsa/b53/b53_priv.h | 6 +++--- drivers/net/dsa/bcm_sf2.c | 2 +- drivers/net/dsa/microchip/ksz_common.c | 4 ++-- drivers/net/dsa/mt7530.c | 4 ++-- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- drivers/net/dsa/qca/qca8k-common.c | 4 ++-- drivers/net/dsa/qca/qca8k.h | 4 ++-- .../net/ethernet/aquantia/atlantic/aq_ethtool.c | 4 ++-- drivers/net/ethernet/broadcom/asp2/bcmasp.h | 2 +- .../net/ethernet/broadcom/asp2/bcmasp_ethtool.c | 8 ++++---- .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 4 ++-- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++---- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 +- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 6 +++--- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 8 ++++---- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +- drivers/net/ethernet/broadcom/tg3.c | 10 +++++----- drivers/net/ethernet/broadcom/tg3.h | 2 +- drivers/net/ethernet/engleder/tsnep_main.c | 6 +++--- drivers/net/ethernet/freescale/enetc/enetc.c | 4 ++-- drivers/net/ethernet/freescale/fec.h | 2 +- drivers/net/ethernet/freescale/fec_main.c | 10 +++++----- drivers/net/ethernet/freescale/gianfar.c | 4 ++-- drivers/net/ethernet/intel/e1000e/ethtool.c | 6 +++--- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 6 +++--- drivers/net/ethernet/intel/igb/igb_ethtool.c | 8 ++++---- drivers/net/ethernet/intel/igc/igc.h | 2 +- drivers/net/ethernet/intel/igc/igc_ethtool.c | 8 ++++---- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 10 +++++----- drivers/net/ethernet/marvell/mvneta.c | 4 ++-- drivers/net/ethernet/microchip/lan743x_ethtool.c | 4 ++-- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 4 ++-- drivers/net/ethernet/realtek/r8169_main.c | 4 ++-- .../net/ethernet/samsung/sxgbe/sxgbe_ethtool.c | 4 ++-- .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 4 ++-- drivers/net/ethernet/ti/am65-cpsw-ethtool.c | 4 ++-- drivers/net/ethernet/ti/cpsw_ethtool.c | 4 ++-- drivers/net/ethernet/ti/cpsw_priv.h | 4 ++-- drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 4 ++-- drivers/net/phy/marvell.c | 2 +- drivers/net/phy/phy-c45.c | 8 ++++---- drivers/net/phy/phy.c | 8 ++++---- drivers/net/phy/phylink.c | 8 ++++---- drivers/net/usb/ax88179_178a.c | 10 +++++----- drivers/net/usb/lan78xx.c | 4 ++-- drivers/net/usb/r8152.c | 14 +++++++------- include/linux/ethtool.h | 16 ++++++++++++++-- include/linux/phy.h | 8 ++++---- include/linux/phylink.h | 4 ++-- include/net/dsa.h | 4 ++-- net/dsa/user.c | 4 ++-- net/ethtool/eee.c | 10 +++++----- net/ethtool/ioctl.c | 6 +++--- 54 files changed, 159 insertions(+), 147 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 0d628b35fd5c..adc93abf4551 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1257,7 +1257,7 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phydev) { struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; + struct ethtool_keee *p = &dev->ports[port].eee; u8 rgmii_ctrl = 0, reg = 0, off; bool tx_pause = false; bool rx_pause = false; @@ -2224,10 +2224,10 @@ int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy) } EXPORT_SYMBOL(b53_eee_init); -int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) +int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e) { struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; + struct ethtool_keee *p = &dev->ports[port].eee; u16 reg; if (is5325(dev) || is5365(dev)) @@ -2241,10 +2241,10 @@ int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) } EXPORT_SYMBOL(b53_get_mac_eee); -int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) +int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e) { struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; + struct ethtool_keee *p = &dev->ports[port].eee; if (is5325(dev) || is5365(dev)) return -EOPNOTSUPP; diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index fdcfd5081c28..c26a03755e83 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -95,7 +95,7 @@ struct b53_pcs { struct b53_port { u16 vlan_ctl_mask; - struct ethtool_eee eee; + struct ethtool_keee eee; }; struct b53_vlan { @@ -397,7 +397,7 @@ void b53_disable_port(struct dsa_switch *ds, int port); void b53_brcm_hdr_setup(struct dsa_switch *ds, int port); void b53_eee_enable_set(struct dsa_switch *ds, int port, bool enable); int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy); -int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); -int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); +int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); +int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); #endif diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 4a52ccbe393f..bc77ee9e6d0a 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -835,7 +835,7 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, bool tx_pause, bool rx_pause) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - struct ethtool_eee *p = &priv->dev->ports[port].eee; + struct ethtool_keee *p = &priv->dev->ports[port].eee; u32 reg_rgmii_ctrl = 0; u32 reg, offset; diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 245dfb7a7a31..a7b5ddb8656e 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2852,7 +2852,7 @@ static int ksz_validate_eee(struct dsa_switch *ds, int port) } static int ksz_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { int ret; @@ -2872,7 +2872,7 @@ static int ksz_get_mac_eee(struct dsa_switch *ds, int port, } static int ksz_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { struct ksz_device *dev = ds->priv; int ret; diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 68be38ae66e0..98a73a62f2ee 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -3048,7 +3048,7 @@ mt753x_setup(struct dsa_switch *ds) } static int mt753x_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { struct mt7530_priv *priv = ds->priv; u32 eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port)); @@ -3060,7 +3060,7 @@ static int mt753x_get_mac_eee(struct dsa_switch *ds, int port, } static int mt753x_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { struct mt7530_priv *priv = ds->priv; u32 set, mask = LPI_THRESH_MASK | LPI_MODE_EN; diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 383b3c4d6f59..8b0079b8e0e0 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1451,14 +1451,14 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, } static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { /* Nothing to do on the port's MAC */ return 0; } static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { /* Nothing to do on the port's MAC */ return 0; diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c index 2358cd399c7e..7f80035c5441 100644 --- a/drivers/net/dsa/qca/qca8k-common.c +++ b/drivers/net/dsa/qca/qca8k-common.c @@ -534,7 +534,7 @@ int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) } int qca8k_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); struct qca8k_priv *priv = ds->priv; @@ -558,7 +558,7 @@ exit: } int qca8k_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { /* Nothing to do on the port's MAC */ return 0; diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h index c8785c36c54e..2184d8d2d5a9 100644 --- a/drivers/net/dsa/qca/qca8k.h +++ b/drivers/net/dsa/qca/qca8k.h @@ -518,8 +518,8 @@ void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset); /* Common eee function */ -int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee); -int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); +int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *eee); +int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); /* Common bridge function */ void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 18a6c8d99fa0..be865776de55 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -697,7 +697,7 @@ static u32 eee_mask_to_ethtool_mask(u32 speed) return rate; } -static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) +static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_keee *eee) { struct aq_nic_s *aq_nic = netdev_priv(ndev); u32 rate, supported_rates; @@ -729,7 +729,7 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) return 0; } -static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee) +static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_keee *eee) { struct aq_nic_s *aq_nic = netdev_priv(ndev); u32 rate, supported_rates; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index ec90add6b03e..312bf9b6576e 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -337,7 +337,7 @@ struct bcmasp_intf { int wol_irq; unsigned int wol_irq_enabled:1; - struct ethtool_eee eee; + struct ethtool_keee eee; }; #define NUM_NET_FILTERS 32 diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c index ce6a3d56fb23..2851bed153e6 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c @@ -363,10 +363,10 @@ void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable) intf->eee.eee_active = enable; } -static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmasp_get_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmasp_intf *intf = netdev_priv(dev); - struct ethtool_eee *p = &intf->eee; + struct ethtool_keee *p = &intf->eee; if (!dev->phydev) return -ENODEV; @@ -379,10 +379,10 @@ static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e) return phy_ethtool_get_eee(dev->phydev, e); } -static int bcmasp_set_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmasp_set_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmasp_intf *intf = netdev_priv(dev); - struct ethtool_eee *p = &intf->eee; + struct ethtool_keee *p = &intf->eee; int ret; if (!dev->phydev) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 0bc7690cdee1..12d2785eeb8a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -2108,7 +2108,7 @@ static u32 bnx2x_adv_to_eee(u32 modes, u32 shift) return eee_adv << shift; } -static int bnx2x_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnx2x_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnx2x *bp = netdev_priv(dev); u32 eee_cfg; @@ -2141,7 +2141,7 @@ static int bnx2x_get_eee(struct net_device *dev, struct ethtool_eee *edata) return 0; } -static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnx2x_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnx2x *bp = netdev_priv(dev); u32 eee_cfg; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 39845d556baf..d7626c26f9a9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10621,7 +10621,7 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) bp->phy_flags = resp->flags | (le16_to_cpu(resp->flags2) << 8); if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; u16 fw_speeds = le16_to_cpu(resp->supported_speeds_eee_mode); eee->supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); @@ -10766,7 +10766,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) link_info->module_status = resp->module_status; if (bp->phy_flags & BNXT_PHY_FL_EEE_CAP) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; u16 fw_speeds; eee->eee_active = 0; @@ -10957,7 +10957,7 @@ int bnxt_hwrm_set_pause(struct bnxt *bp) static void bnxt_hwrm_set_eee(struct bnxt *bp, struct hwrm_port_phy_cfg_input *req) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; if (eee->eee_enabled) { u16 eee_speeds; @@ -11322,7 +11322,7 @@ static void bnxt_get_wol_settings(struct bnxt *bp) static bool bnxt_eee_config_ok(struct bnxt *bp) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; struct bnxt_link_info *link_info = &bp->link_info; if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 47338b48ca20..b2cb3e77559d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2442,7 +2442,7 @@ struct bnxt { */ struct mutex link_lock; struct bnxt_link_info link_info; - struct ethtool_eee eee; + struct ethtool_keee eee; u32 lpi_tmr_lo; u32 lpi_tmr_hi; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index dc4ca706b0e2..d6a8577d68af 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3884,10 +3884,10 @@ static int bnxt_set_eeprom(struct net_device *dev, eeprom->len); } -static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnxt_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnxt *bp = netdev_priv(dev); - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; struct bnxt_link_info *link_info = &bp->link_info; u32 advertising; int rc = 0; @@ -3942,7 +3942,7 @@ eee_exit: return rc; } -static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnxt_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnxt *bp = netdev_priv(dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 2d7ae71287b1..051c31fb17c2 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1317,10 +1317,10 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable, priv->eee.tx_lpi_enabled = tx_lpi_enabled; } -static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmgenet_priv *priv = netdev_priv(dev); - struct ethtool_eee *p = &priv->eee; + struct ethtool_keee *p = &priv->eee; if (GENET_IS_V1(priv)) return -EOPNOTSUPP; @@ -1336,10 +1336,10 @@ static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e) return phy_ethtool_get_eee(dev->phydev, e); } -static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmgenet_priv *priv = netdev_priv(dev); - struct ethtool_eee *p = &priv->eee; + struct ethtool_keee *p = &priv->eee; if (GENET_IS_V1(priv)) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 1985c0ec4da2..7523b60b3c1c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -645,7 +645,7 @@ struct bcmgenet_priv { struct bcmgenet_mib_counters mib; - struct ethtool_eee eee; + struct ethtool_keee eee; }; #define GENET_IO_MACRO(name, offset) \ diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 04964bbe08cf..11054177c2ec 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2338,10 +2338,10 @@ static void tg3_phy_apply_otp(struct tg3 *tp) tg3_phy_toggle_auxctl_smdsp(tp, false); } -static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_eee *eee) +static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_keee *eee) { u32 val; - struct ethtool_eee *dest = &tp->eee; + struct ethtool_keee *dest = &tp->eee; if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) return; @@ -4618,7 +4618,7 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp) static bool tg3_phy_eee_config_ok(struct tg3 *tp) { - struct ethtool_eee eee; + struct ethtool_keee eee; if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) return true; @@ -14180,7 +14180,7 @@ static int tg3_set_coalesce(struct net_device *dev, return 0; } -static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int tg3_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct tg3 *tp = netdev_priv(dev); @@ -14217,7 +14217,7 @@ static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata) return 0; } -static int tg3_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int tg3_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct tg3 *tp = netdev_priv(dev); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 5016475e5005..cf1b2b123c7e 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -3419,7 +3419,7 @@ struct tg3 { unsigned int irq_cnt; struct ethtool_coalesce coal; - struct ethtool_eee eee; + struct ethtool_keee eee; /* firmware info */ const char *fw_needed; diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index ae0b8b37b9bf..eb64118f5b18 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -240,7 +240,7 @@ static int tsnep_phy_loopback(struct tsnep_adapter *adapter, bool enable) static int tsnep_phy_open(struct tsnep_adapter *adapter) { struct phy_device *phydev; - struct ethtool_eee ethtool_eee; + struct ethtool_keee ethtool_keee; int retval; retval = phy_connect_direct(adapter->netdev, adapter->phydev, @@ -259,8 +259,8 @@ static int tsnep_phy_open(struct tsnep_adapter *adapter) phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); /* disable EEE autoneg, EEE not supported by TSNEP */ - memset(ðtool_eee, 0, sizeof(ethtool_eee)); - phy_ethtool_set_eee(adapter->phydev, ðtool_eee); + memset(ðtool_keee, 0, sizeof(ethtool_keee)); + phy_ethtool_set_eee(adapter->phydev, ðtool_keee); adapter->phydev->irq = PHY_MAC_INTERRUPT; phy_start(adapter->phydev); diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index bfdbdab443ae..9f07f4947b63 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -2402,7 +2402,7 @@ static void enetc_clear_interrupts(struct enetc_ndev_priv *priv) static int enetc_phylink_connect(struct net_device *ndev) { struct enetc_ndev_priv *priv = netdev_priv(ndev); - struct ethtool_eee edata; + struct ethtool_keee edata; int err; if (!priv->phylink) { @@ -2418,7 +2418,7 @@ static int enetc_phylink_connect(struct net_device *ndev) } /* disable EEE autoneg, until ENETC driver supports it */ - memset(&edata, 0, sizeof(struct ethtool_eee)); + memset(&edata, 0, sizeof(struct ethtool_keee)); phylink_ethtool_set_eee(priv->phylink, &edata); phylink_start(priv->phylink); diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index a8fbcada6b01..a19cb2a786fd 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -672,7 +672,7 @@ struct fec_enet_private { unsigned int itr_clk_rate; /* tx lpi eee mode */ - struct ethtool_eee eee; + struct ethtool_keee eee; unsigned int clk_ref_rate; /* ptp clock period in ns*/ diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 432523b2c789..63707e065141 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3122,7 +3122,7 @@ static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us) static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_eee *p = &fep->eee; + struct ethtool_keee *p = &fep->eee; unsigned int sleep_cycle, wake_cycle; int ret = 0; @@ -3149,10 +3149,10 @@ static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) } static int -fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_eee *p = &fep->eee; + struct ethtool_keee *p = &fep->eee; if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) return -EOPNOTSUPP; @@ -3169,10 +3169,10 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata) } static int -fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_eee *p = &fep->eee; + struct ethtool_keee *p = &fep->eee; int ret = 0; if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index e3dfbd7a4236..a811238c018d 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1649,7 +1649,7 @@ static int init_phy(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); phy_interface_t interface = priv->interface; struct phy_device *phydev; - struct ethtool_eee edata; + struct ethtool_keee edata; linkmode_set_bit_array(phy_10_100_features_array, ARRAY_SIZE(phy_10_100_features_array), @@ -1681,7 +1681,7 @@ static int init_phy(struct net_device *dev) phy_support_asym_pause(phydev); /* disable EEE autoneg, EEE not supported by eTSEC */ - memset(&edata, 0, sizeof(struct ethtool_eee)); + memset(&edata, 0, sizeof(struct ethtool_keee)); phy_ethtool_set_eee(phydev, &edata); return 0; diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index fc0f98ea6133..343f54b2b6ae 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -2186,7 +2186,7 @@ static int e1000_get_rxnfc(struct net_device *netdev, } } -static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int e1000e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; @@ -2262,11 +2262,11 @@ release: return ret_val; } -static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int e1000e_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct ethtool_eee eee_curr; + struct ethtool_keee eee_curr; s32 ret_val; ret_val = e1000e_get_eee(netdev, &eee_curr); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index c841779713f6..9dfda3c48af3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5644,7 +5644,7 @@ static int i40e_get_module_eeprom(struct net_device *netdev, return 0; } -static int i40e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int i40e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_aq_get_phy_abilities_resp phy_cfg; @@ -5682,7 +5682,7 @@ static int i40e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) } static int i40e_is_eee_param_supported(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -5709,7 +5709,7 @@ static int i40e_is_eee_param_supported(struct net_device *netdev, return 0; } -static int i40e_set_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int i40e_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_aq_get_phy_abilities_resp abilities; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index b66199c9bb3a..778d1e6cfc45 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -3027,7 +3027,7 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) return ret; } -static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; @@ -3106,11 +3106,11 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) } static int igb_set_eee(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct ethtool_eee eee_curr; + struct ethtool_keee eee_curr; bool adv1g_eee = true, adv100m_eee = true; s32 ret_val; @@ -3118,7 +3118,7 @@ static int igb_set_eee(struct net_device *netdev, (hw->phy.media_type != e1000_media_type_copper)) return -EOPNOTSUPP; - memset(&eee_curr, 0, sizeof(struct ethtool_eee)); + memset(&eee_curr, 0, sizeof(struct ethtool_keee)); ret_val = igb_get_eee(netdev, &eee_curr); if (ret_val) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 45430e246e9c..75f7c5ba65e0 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -168,7 +168,7 @@ struct igc_ring { struct igc_adapter { struct net_device *netdev; - struct ethtool_eee eee; + struct ethtool_keee eee; u16 eee_advert; unsigned long state; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index b95d2c86e803..f2dcfe920f4f 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1623,7 +1623,7 @@ static int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags) } static int igc_ethtool_get_eee(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct igc_adapter *adapter = netdev_priv(netdev); struct igc_hw *hw = &adapter->hw; @@ -1664,14 +1664,14 @@ static int igc_ethtool_get_eee(struct net_device *netdev, } static int igc_ethtool_set_eee(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct igc_adapter *adapter = netdev_priv(netdev); struct igc_hw *hw = &adapter->hw; - struct ethtool_eee eee_curr; + struct ethtool_keee eee_curr; s32 ret_val; - memset(&eee_curr, 0, sizeof(struct ethtool_eee)); + memset(&eee_curr, 0, sizeof(struct ethtool_keee)); ret_val = igc_ethtool_get_eee(netdev, &eee_curr); if (ret_val) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 9a63457712c7..0aa73519a29d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -3425,7 +3425,7 @@ static const struct { }; static int -ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_eee *edata) +ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata) { u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; struct ixgbe_hw *hw = &adapter->hw; @@ -3462,7 +3462,7 @@ ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_eee *edata) return 0; } -static int ixgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int ixgbe_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -3476,17 +3476,17 @@ static int ixgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata) return -EOPNOTSUPP; } -static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - struct ethtool_eee eee_data; + struct ethtool_keee eee_data; s32 ret_val; if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE)) return -EOPNOTSUPP; - memset(&eee_data, 0, sizeof(struct ethtool_eee)); + memset(&eee_data, 0, sizeof(struct ethtool_keee)); ret_val = ixgbe_get_eee(netdev, &eee_data); if (ret_val) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a641b3534ca3..40a5f1431e4e 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -5097,7 +5097,7 @@ static int mvneta_ethtool_set_wol(struct net_device *dev, } static int mvneta_ethtool_get_eee(struct net_device *dev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct mvneta_port *pp = netdev_priv(dev); u32 lpi_ctl0; @@ -5113,7 +5113,7 @@ static int mvneta_ethtool_get_eee(struct net_device *dev, } static int mvneta_ethtool_set_eee(struct net_device *dev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct mvneta_port *pp = netdev_priv(dev); u32 lpi_ctl0; diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c index a2b3f4433ca8..8a6ae171e375 100644 --- a/drivers/net/ethernet/microchip/lan743x_ethtool.c +++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c @@ -1055,7 +1055,7 @@ static int lan743x_ethtool_get_ts_info(struct net_device *netdev, } static int lan743x_ethtool_get_eee(struct net_device *netdev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct lan743x_adapter *adapter = netdev_priv(netdev); struct phy_device *phydev = netdev->phydev; @@ -1092,7 +1092,7 @@ static int lan743x_ethtool_get_eee(struct net_device *netdev, } static int lan743x_ethtool_set_eee(struct net_device *netdev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct lan743x_adapter *adapter; struct phy_device *phydev; diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 0e240b5ab8d4..77491fb64039 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1776,7 +1776,7 @@ static int qede_get_tunable(struct net_device *dev, return 0; } -static int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int qede_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct qede_dev *edev = netdev_priv(dev); struct qed_link_output current_link; @@ -1810,7 +1810,7 @@ static int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata) return 0; } -static int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int qede_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct qede_dev *edev = netdev_priv(dev); struct qed_link_output current_link; diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index dd73df6b17b0..3d30d4499791 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1974,7 +1974,7 @@ static int rtl_set_coalesce(struct net_device *dev, return 0; } -static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data) +static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); @@ -1984,7 +1984,7 @@ static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data) return phy_ethtool_get_eee(tp->phydev, data); } -static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data) +static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); int ret; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c index 8ba017ec9849..d93b628b7046 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c @@ -133,7 +133,7 @@ static const struct sxgbe_stats sxgbe_gstrings_stats[] = { #define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats) static int sxgbe_get_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct sxgbe_priv_data *priv = netdev_priv(dev); @@ -148,7 +148,7 @@ static int sxgbe_get_eee(struct net_device *dev, } static int sxgbe_set_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct sxgbe_priv_data *priv = netdev_priv(dev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 42d27b97dd1d..bbecb3b89535 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -852,7 +852,7 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } static int stmmac_ethtool_op_get_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct stmmac_priv *priv = netdev_priv(dev); @@ -868,7 +868,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, } static int stmmac_ethtool_op_set_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct stmmac_priv *priv = netdev_priv(dev); int ret; diff --git a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c index 35fceba01ea4..d6ce2c9f0a8d 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c +++ b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c @@ -514,14 +514,14 @@ am65_cpsw_set_link_ksettings(struct net_device *ndev, return phylink_ethtool_ksettings_set(salve->phylink, ecmd); } -static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); return phylink_ethtool_get_eee(salve->phylink, edata); } -static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c index a557a477d039..f7b283353ba2 100644 --- a/drivers/net/ethernet/ti/cpsw_ethtool.c +++ b/drivers/net/ethernet/ti/cpsw_ethtool.c @@ -422,7 +422,7 @@ int cpsw_set_link_ksettings(struct net_device *ndev, return phy_ethtool_ksettings_set(cpsw->slaves[slave_no].phy, ecmd); } -int cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; @@ -434,7 +434,7 @@ int cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) return -EOPNOTSUPP; } -int cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +int cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 0e27c433098d..7efa72502c86 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -496,8 +496,8 @@ int cpsw_get_link_ksettings(struct net_device *ndev, struct ethtool_link_ksettings *ecmd); int cpsw_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *ecmd); -int cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata); -int cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata); +int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata); +int cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata); int cpsw_nway_reset(struct net_device *ndev); void cpsw_get_ringparam(struct net_device *ndev, struct ethtool_ringparam *ering, diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c index a27ec1dcc8d5..9a7dd7efcf69 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c @@ -45,7 +45,7 @@ static int emac_set_link_ksettings(struct net_device *ndev, return phy_ethtool_set_link_ksettings(ndev, ecmd); } -static int emac_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int emac_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { if (!ndev->phydev) return -EOPNOTSUPP; @@ -53,7 +53,7 @@ static int emac_get_eee(struct net_device *ndev, struct ethtool_eee *edata) return phy_ethtool_get_eee(ndev->phydev, edata); } -static int emac_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int emac_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { if (!ndev->phydev) return -EOPNOTSUPP; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index eba652a4c1d8..1faa22f58366 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1461,7 +1461,7 @@ static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs) static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs) { - struct ethtool_eee eee; + struct ethtool_keee eee; int val, ret; if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 747d14bf152c..adee5e712871 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1443,13 +1443,13 @@ EXPORT_SYMBOL(genphy_c45_eee_is_active); /** * genphy_c45_ethtool_get_eee - get EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: it reports the Supported/Advertisement/LP Advertisement * capabilities. */ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, - struct ethtool_eee *data) + struct ethtool_keee *data) { __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {}; __ETHTOOL_DECLARE_LINK_MODE_MASK(lp) = {}; @@ -1481,7 +1481,7 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee); /** * genphy_c45_ethtool_set_eee - set EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: sets the Supported/Advertisement/LP Advertisement * capabilities. If eee_enabled is false, no links modes are @@ -1490,7 +1490,7 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee); * non-destructive way. */ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, - struct ethtool_eee *data) + struct ethtool_keee *data) { int ret; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3376e58e2b88..3b9531143be1 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1632,12 +1632,12 @@ EXPORT_SYMBOL(phy_get_eee_err); /** * phy_ethtool_get_eee - get EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: it reportes the Supported/Advertisement/LP Advertisement * capabilities. */ -int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data) +int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data) { int ret; @@ -1655,11 +1655,11 @@ EXPORT_SYMBOL(phy_ethtool_get_eee); /** * phy_ethtool_set_eee - set EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: it is to program the Advertisement EEE register. */ -int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) +int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data) { int ret; diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ed0b4ccaa6a6..503fd7c40523 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2764,9 +2764,9 @@ EXPORT_SYMBOL_GPL(phylink_init_eee); /** * phylink_ethtool_get_eee() - read the energy efficient ethernet parameters * @pl: a pointer to a &struct phylink returned from phylink_create() - * @eee: a pointer to a &struct ethtool_eee for the read parameters + * @eee: a pointer to a &struct ethtool_keee for the read parameters */ -int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_eee *eee) +int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_keee *eee) { int ret = -EOPNOTSUPP; @@ -2782,9 +2782,9 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee); /** * phylink_ethtool_set_eee() - set the energy efficient ethernet parameters * @pl: a pointer to a &struct phylink returned from phylink_create() - * @eee: a pointer to a &struct ethtool_eee for the desired parameters + * @eee: a pointer to a &struct ethtool_keee for the desired parameters */ -int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_eee *eee) +int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_keee *eee) { int ret = -EOPNOTSUPP; diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index d837c1887416..3922a9afdd1f 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -667,7 +667,7 @@ static int ax88179_set_link_ksettings(struct net_device *net, } static int -ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data) +ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_keee *data) { int val; @@ -696,7 +696,7 @@ ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data) } static int -ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data) +ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_keee *data) { u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised); @@ -807,7 +807,7 @@ static void ax88179_enable_eee(struct usbnet *dev) GMII_PHY_PAGE_SELECT, 2, &tmp16); } -static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata) +static int ax88179_get_eee(struct net_device *net, struct ethtool_keee *edata) { struct usbnet *dev = netdev_priv(net); struct ax88179_data *priv = dev->driver_priv; @@ -818,7 +818,7 @@ static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata) return ax88179_ethtool_get_eee(dev, edata); } -static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata) +static int ax88179_set_eee(struct net_device *net, struct ethtool_keee *edata) { struct usbnet *dev = netdev_priv(net); struct ax88179_data *priv = dev->driver_priv; @@ -1587,7 +1587,7 @@ static int ax88179_reset(struct usbnet *dev) u16 *tmp16; u8 *tmp; struct ax88179_data *ax179_data = dev->driver_priv; - struct ethtool_eee eee_data; + struct ethtool_keee eee_data; tmp16 = (u16 *)buf; tmp = (u8 *)buf; diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index a6d653ff552a..106282612bc2 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1673,7 +1673,7 @@ static int lan78xx_set_wol(struct net_device *netdev, return ret; } -static int lan78xx_get_eee(struct net_device *net, struct ethtool_eee *edata) +static int lan78xx_get_eee(struct net_device *net, struct ethtool_keee *edata) { struct lan78xx_net *dev = netdev_priv(net); struct phy_device *phydev = net->phydev; @@ -1709,7 +1709,7 @@ exit: return ret; } -static int lan78xx_set_eee(struct net_device *net, struct ethtool_eee *edata) +static int lan78xx_set_eee(struct net_device *net, struct ethtool_keee *edata) { struct lan78xx_net *dev = netdev_priv(net); int ret; diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0d0672d2a654..dc163b766a89 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -891,8 +891,8 @@ struct r8152 { void (*up)(struct r8152 *tp); void (*down)(struct r8152 *tp); void (*unload)(struct r8152 *tp); - int (*eee_get)(struct r8152 *tp, struct ethtool_eee *eee); - int (*eee_set)(struct r8152 *tp, struct ethtool_eee *eee); + int (*eee_get)(struct r8152 *tp, struct ethtool_keee *eee); + int (*eee_set)(struct r8152 *tp, struct ethtool_keee *eee); bool (*in_nway)(struct r8152 *tp); void (*hw_phy_cfg)(struct r8152 *tp); void (*autosuspend_en)(struct r8152 *tp, bool enable); @@ -8922,7 +8922,7 @@ static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee) +static int r8152_get_eee(struct r8152 *tp, struct ethtool_keee *eee) { u32 lp, adv, supported = 0; u16 val; @@ -8945,7 +8945,7 @@ static int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee) return 0; } -static int r8152_set_eee(struct r8152 *tp, struct ethtool_eee *eee) +static int r8152_set_eee(struct r8152 *tp, struct ethtool_keee *eee) { u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); @@ -8957,7 +8957,7 @@ static int r8152_set_eee(struct r8152 *tp, struct ethtool_eee *eee) return 0; } -static int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee) +static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee) { u32 lp, adv, supported = 0; u16 val; @@ -8981,7 +8981,7 @@ static int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee) } static int -rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) +rtl_ethtool_get_eee(struct net_device *net, struct ethtool_keee *edata) { struct r8152 *tp = netdev_priv(net); int ret; @@ -9008,7 +9008,7 @@ out: } static int -rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) +rtl_ethtool_set_eee(struct net_device *net, struct ethtool_keee *edata) { struct r8152 *tp = netdev_priv(net); int ret; diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 325e0778e937..a850bab8489f 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -222,6 +222,18 @@ extern int __ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings); +struct ethtool_keee { + u32 cmd; + u32 supported; + u32 advertised; + u32 lp_advertised; + u32 eee_active; + u32 eee_enabled; + u32 tx_lpi_enabled; + u32 tx_lpi_timer; + u32 reserved[2]; +}; + struct kernel_ethtool_coalesce { u8 use_cqe_mode_tx; u8 use_cqe_mode_rx; @@ -892,8 +904,8 @@ struct ethtool_ops { struct ethtool_modinfo *); int (*get_module_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); - int (*get_eee)(struct net_device *, struct ethtool_eee *); - int (*set_eee)(struct net_device *, struct ethtool_eee *); + int (*get_eee)(struct net_device *dev, struct ethtool_keee *eee); + int (*set_eee)(struct net_device *dev, struct ethtool_keee *eee); int (*get_tunable)(struct net_device *, const struct ethtool_tunable *, void *); int (*set_tunable)(struct net_device *, diff --git a/include/linux/phy.h b/include/linux/phy.h index c9994a59ca2e..a66f07d3f5f4 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1908,9 +1908,9 @@ int genphy_c45_plca_get_status(struct phy_device *phydev, int genphy_c45_eee_is_active(struct phy_device *phydev, unsigned long *adv, unsigned long *lp, bool *is_enabled); int genphy_c45_ethtool_get_eee(struct phy_device *phydev, - struct ethtool_eee *data); + struct ethtool_keee *data); int genphy_c45_ethtool_set_eee(struct phy_device *phydev, - struct ethtool_eee *data); + struct ethtool_keee *data); int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv); int genphy_c45_an_config_eee_aneg(struct phy_device *phydev); int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv); @@ -1988,8 +1988,8 @@ int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask); int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable); int phy_get_eee_err(struct phy_device *phydev); -int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data); -int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data); +int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data); +int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data); int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); diff --git a/include/linux/phylink.h b/include/linux/phylink.h index d589f89c612c..6ba411732a0d 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -584,8 +584,8 @@ int phylink_ethtool_set_pauseparam(struct phylink *, struct ethtool_pauseparam *); int phylink_get_eee_err(struct phylink *); int phylink_init_eee(struct phylink *, bool); -int phylink_ethtool_get_eee(struct phylink *, struct ethtool_eee *); -int phylink_ethtool_set_eee(struct phylink *, struct ethtool_eee *); +int phylink_ethtool_get_eee(struct phylink *link, struct ethtool_keee *eee); +int phylink_ethtool_set_eee(struct phylink *link, struct ethtool_keee *eee); int phylink_mii_ioctl(struct phylink *, struct ifreq *, int); int phylink_speed_down(struct phylink *pl, bool sync); int phylink_speed_up(struct phylink *pl); diff --git a/include/net/dsa.h b/include/net/dsa.h index 82135fbdb1e6..7c0da9effe4e 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -991,9 +991,9 @@ struct dsa_switch_ops { * Port's MAC EEE settings */ int (*set_mac_eee)(struct dsa_switch *ds, int port, - struct ethtool_eee *e); + struct ethtool_keee *e); int (*get_mac_eee)(struct dsa_switch *ds, int port, - struct ethtool_eee *e); + struct ethtool_keee *e); /* EEPROM access */ int (*get_eeprom_len)(struct dsa_switch *ds); diff --git a/net/dsa/user.c b/net/dsa/user.c index b15e71cc342c..e03da3a4ac38 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -1222,7 +1222,7 @@ static int dsa_user_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) return ret; } -static int dsa_user_set_eee(struct net_device *dev, struct ethtool_eee *e) +static int dsa_user_set_eee(struct net_device *dev, struct ethtool_keee *e) { struct dsa_port *dp = dsa_user_to_port(dev); struct dsa_switch *ds = dp->ds; @@ -1242,7 +1242,7 @@ static int dsa_user_set_eee(struct net_device *dev, struct ethtool_eee *e) return phylink_ethtool_set_eee(dp->pl, e); } -static int dsa_user_get_eee(struct net_device *dev, struct ethtool_eee *e) +static int dsa_user_get_eee(struct net_device *dev, struct ethtool_keee *e) { struct dsa_port *dp = dsa_user_to_port(dev); struct dsa_switch *ds = dp->ds; diff --git a/net/ethtool/eee.c b/net/ethtool/eee.c index 2853394d06a8..21b0e845a531 100644 --- a/net/ethtool/eee.c +++ b/net/ethtool/eee.c @@ -5,7 +5,7 @@ #include "bitset.h" #define EEE_MODES_COUNT \ - (sizeof_field(struct ethtool_eee, supported) * BITS_PER_BYTE) + (sizeof_field(struct ethtool_keee, supported) * BITS_PER_BYTE) struct eee_req_info { struct ethnl_req_info base; @@ -13,7 +13,7 @@ struct eee_req_info { struct eee_reply_data { struct ethnl_reply_data base; - struct ethtool_eee eee; + struct ethtool_keee eee; }; #define EEE_REPDATA(__reply_base) \ @@ -48,7 +48,7 @@ static int eee_reply_size(const struct ethnl_req_info *req_base, { bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; const struct eee_reply_data *data = EEE_REPDATA(reply_base); - const struct ethtool_eee *eee = &data->eee; + const struct ethtool_keee *eee = &data->eee; int len = 0; int ret; @@ -84,7 +84,7 @@ static int eee_fill_reply(struct sk_buff *skb, { bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; const struct eee_reply_data *data = EEE_REPDATA(reply_base); - const struct ethtool_eee *eee = &data->eee; + const struct ethtool_keee *eee = &data->eee; int ret; ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_OURS, @@ -132,7 +132,7 @@ ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info) { struct net_device *dev = req_info->dev; struct nlattr **tb = info->attrs; - struct ethtool_eee eee = {}; + struct ethtool_keee eee = {}; bool mod = false; int ret; diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 7519b0818b91..b02ca72f438e 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1510,13 +1510,13 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) { - struct ethtool_eee edata; + struct ethtool_keee edata; int rc; if (!dev->ethtool_ops->get_eee) return -EOPNOTSUPP; - memset(&edata, 0, sizeof(struct ethtool_eee)); + memset(&edata, 0, sizeof(struct ethtool_keee)); edata.cmd = ETHTOOL_GEEE; rc = dev->ethtool_ops->get_eee(dev, &edata); @@ -1531,7 +1531,7 @@ static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) static int ethtool_set_eee(struct net_device *dev, char __user *useraddr) { - struct ethtool_eee edata; + struct ethtool_keee edata; int ret; if (!dev->ethtool_ops->set_eee) From 0b3100bc8fa7a05804737dba96075ea8d45316ce Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jan 2024 14:26:06 +0100 Subject: [PATCH 0474/2255] ethtool: switch back from ethtool_keee to ethtool_eee for ioctl In order to later extend struct ethtool_keee, we have to decouple it from the userspace format represented by struct ethtool_eee. Therefore switch back to struct ethtool_eee, representing the userspace format, and add conversion between ethtool_eee and ethtool_keee. Struct ethtool_keee will be changed in follow-up patches, therefore don't do a *keee = *eee here. Member cmd isn't copied, because it's not used, and we'll remove it in the next patch of this series. In addition omit setting cmd to ETHTOOL_GEEE in the ioctl response, userspace ethtool isn't interested in it. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- net/ethtool/ioctl.c | 48 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index b02ca72f438e..46c29b369aeb 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1508,22 +1508,50 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) return 0; } +static void eee_to_keee(struct ethtool_keee *keee, + const struct ethtool_eee *eee) +{ + memset(keee, 0, sizeof(*keee)); + + keee->supported = eee->supported; + keee->advertised = eee->advertised; + keee->lp_advertised = eee->lp_advertised; + keee->eee_active = eee->eee_active; + keee->eee_enabled = eee->eee_enabled; + keee->tx_lpi_enabled = eee->tx_lpi_enabled; + keee->tx_lpi_timer = eee->tx_lpi_timer; +} + +static void keee_to_eee(struct ethtool_eee *eee, + const struct ethtool_keee *keee) +{ + memset(eee, 0, sizeof(*eee)); + + eee->supported = keee->supported; + eee->advertised = keee->advertised; + eee->lp_advertised = keee->lp_advertised; + eee->eee_active = keee->eee_active; + eee->eee_enabled = keee->eee_enabled; + eee->tx_lpi_enabled = keee->tx_lpi_enabled; + eee->tx_lpi_timer = keee->tx_lpi_timer; +} + static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) { - struct ethtool_keee edata; + struct ethtool_keee keee; + struct ethtool_eee eee; int rc; if (!dev->ethtool_ops->get_eee) return -EOPNOTSUPP; - memset(&edata, 0, sizeof(struct ethtool_keee)); - edata.cmd = ETHTOOL_GEEE; - rc = dev->ethtool_ops->get_eee(dev, &edata); - + memset(&keee, 0, sizeof(keee)); + rc = dev->ethtool_ops->get_eee(dev, &keee); if (rc) return rc; - if (copy_to_user(useraddr, &edata, sizeof(edata))) + keee_to_eee(&eee, &keee); + if (copy_to_user(useraddr, &eee, sizeof(eee))) return -EFAULT; return 0; @@ -1531,16 +1559,18 @@ static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) static int ethtool_set_eee(struct net_device *dev, char __user *useraddr) { - struct ethtool_keee edata; + struct ethtool_keee keee; + struct ethtool_eee eee; int ret; if (!dev->ethtool_ops->set_eee) return -EOPNOTSUPP; - if (copy_from_user(&edata, useraddr, sizeof(edata))) + if (copy_from_user(&eee, useraddr, sizeof(eee))) return -EFAULT; - ret = dev->ethtool_ops->set_eee(dev, &edata); + eee_to_keee(&keee, &eee); + ret = dev->ethtool_ops->set_eee(dev, &keee); if (!ret) ethtool_notify(dev, ETHTOOL_MSG_EEE_NTF, NULL); return ret; From 285cc15cc555b4f05ebf2556bc6e85a6d36b790a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jan 2024 14:26:50 +0100 Subject: [PATCH 0475/2255] ethtool: adjust struct ethtool_keee to kernel needs This patch changes the following in struct ethtool_keee - remove member cmd, it's not needed on kernel side - remove reserved fields - switch the semantically boolean members to type bool We don't have to change any user of the boolean members due to the implicit casting from/to bool. A small change is needed where a pointer to bool members is used, in addition remove few now unneeded double negations. Reviewed-by: Andrew Lunn Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- include/linux/ethtool.h | 8 +++----- net/ethtool/eee.c | 12 ++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index a850bab8489f..14549cb9e2b2 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -223,15 +223,13 @@ __ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings); struct ethtool_keee { - u32 cmd; u32 supported; u32 advertised; u32 lp_advertised; - u32 eee_active; - u32 eee_enabled; - u32 tx_lpi_enabled; u32 tx_lpi_timer; - u32 reserved[2]; + bool tx_lpi_enabled; + bool eee_active; + bool eee_enabled; }; struct kernel_ethtool_coalesce { diff --git a/net/ethtool/eee.c b/net/ethtool/eee.c index 21b0e845a531..ac9f694ffe20 100644 --- a/net/ethtool/eee.c +++ b/net/ethtool/eee.c @@ -98,10 +98,10 @@ static int eee_fill_reply(struct sk_buff *skb, if (ret < 0) return ret; - if (nla_put_u8(skb, ETHTOOL_A_EEE_ACTIVE, !!eee->eee_active) || - nla_put_u8(skb, ETHTOOL_A_EEE_ENABLED, !!eee->eee_enabled) || + if (nla_put_u8(skb, ETHTOOL_A_EEE_ACTIVE, eee->eee_active) || + nla_put_u8(skb, ETHTOOL_A_EEE_ENABLED, eee->eee_enabled) || nla_put_u8(skb, ETHTOOL_A_EEE_TX_LPI_ENABLED, - !!eee->tx_lpi_enabled) || + eee->tx_lpi_enabled) || nla_put_u32(skb, ETHTOOL_A_EEE_TX_LPI_TIMER, eee->tx_lpi_timer)) return -EMSGSIZE; @@ -145,9 +145,9 @@ ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info) link_mode_names, info->extack, &mod); if (ret < 0) return ret; - ethnl_update_bool32(&eee.eee_enabled, tb[ETHTOOL_A_EEE_ENABLED], &mod); - ethnl_update_bool32(&eee.tx_lpi_enabled, - tb[ETHTOOL_A_EEE_TX_LPI_ENABLED], &mod); + ethnl_update_bool(&eee.eee_enabled, tb[ETHTOOL_A_EEE_ENABLED], &mod); + ethnl_update_bool(&eee.tx_lpi_enabled, tb[ETHTOOL_A_EEE_TX_LPI_ENABLED], + &mod); ethnl_update_u32(&eee.tx_lpi_timer, tb[ETHTOOL_A_EEE_TX_LPI_TIMER], &mod); if (!mod) From 1d756ff13da6a2222ac4387511f2a0e2e83ce670 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jan 2024 14:28:47 +0100 Subject: [PATCH 0476/2255] ethtool: add suffix _u32 to legacy bitmap members of struct ethtool_keee This is in preparation of using the existing names for linkmode bitmaps. Suggested-by: Andrew Lunn Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../ethernet/aquantia/atlantic/aq_ethtool.c | 8 +++--- .../ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 8 +++--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 12 ++++---- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 14 +++++----- drivers/net/ethernet/broadcom/tg3.c | 22 +++++++-------- drivers/net/ethernet/intel/e1000e/ethtool.c | 10 +++---- .../net/ethernet/intel/i40e/i40e_ethtool.c | 10 +++---- drivers/net/ethernet/intel/igb/igb_ethtool.c | 20 ++++++------- drivers/net/ethernet/intel/igc/igc_ethtool.c | 12 ++++---- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 18 ++++++------ .../net/ethernet/qlogic/qede/qede_ethtool.c | 28 +++++++++---------- drivers/net/phy/phy-c45.c | 12 ++++---- drivers/net/usb/ax88179_178a.c | 10 +++---- drivers/net/usb/r8152.c | 14 +++++----- include/linux/ethtool.h | 6 ++-- net/ethtool/eee.c | 16 +++++------ net/ethtool/ioctl.c | 12 ++++---- 17 files changed, 116 insertions(+), 116 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index be865776de55..0bd1a0a1ae6a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -713,14 +713,14 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_keee *eee) if (err < 0) return err; - eee->supported = eee_mask_to_ethtool_mask(supported_rates); + eee->supported_u32 = eee_mask_to_ethtool_mask(supported_rates); if (aq_nic->aq_nic_cfg.eee_speeds) - eee->advertised = eee->supported; + eee->advertised_u32 = eee->supported_u32; - eee->lp_advertised = eee_mask_to_ethtool_mask(rate); + eee->lp_advertised_u32 = eee_mask_to_ethtool_mask(rate); - eee->eee_enabled = !!eee->advertised; + eee->eee_enabled = !!eee->advertised_u32; eee->tx_lpi_enabled = eee->eee_enabled; if ((supported_rates & rate) & AQ_NIC_RATE_EEE_MSK) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 12d2785eeb8a..5f0e1759d078 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -2120,14 +2120,14 @@ static int bnx2x_get_eee(struct net_device *dev, struct ethtool_keee *edata) eee_cfg = bp->link_vars.eee_status; - edata->supported = + edata->supported_u32 = bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_SUPPORTED_MASK) >> SHMEM_EEE_SUPPORTED_SHIFT); - edata->advertised = + edata->advertised_u32 = bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_ADV_STATUS_MASK) >> SHMEM_EEE_ADV_STATUS_SHIFT); - edata->lp_advertised = + edata->lp_advertised_u32 = bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_LP_ADV_STATUS_MASK) >> SHMEM_EEE_LP_ADV_STATUS_SHIFT); @@ -2162,7 +2162,7 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_keee *edata) return -EOPNOTSUPP; } - advertised = bnx2x_adv_to_eee(edata->advertised, + advertised = bnx2x_adv_to_eee(edata->advertised_u32, SHMEM_EEE_ADV_STATUS_SHIFT); if ((advertised != (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK))) { DP(BNX2X_MSG_ETHTOOL, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d7626c26f9a9..fde32b32fa81 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10624,7 +10624,7 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) struct ethtool_keee *eee = &bp->eee; u16 fw_speeds = le16_to_cpu(resp->supported_speeds_eee_mode); - eee->supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); + eee->supported_u32 = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); bp->lpi_tmr_lo = le32_to_cpu(resp->tx_lpi_timer_low) & PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_LOW_MASK; bp->lpi_tmr_hi = le32_to_cpu(resp->valid_tx_lpi_timer_high) & @@ -10775,7 +10775,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) eee->eee_active = 1; fw_speeds = le16_to_cpu( resp->link_partner_adv_eee_link_speed_mask); - eee->lp_advertised = + eee->lp_advertised_u32 = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); } @@ -10786,7 +10786,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) eee->eee_enabled = 1; fw_speeds = le16_to_cpu(resp->adv_eee_link_speed_mask); - eee->advertised = + eee->advertised_u32 = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); if (resp->eee_config_phy_addr & @@ -10969,7 +10969,7 @@ static void bnxt_hwrm_set_eee(struct bnxt *bp, flags |= PORT_PHY_CFG_REQ_FLAGS_EEE_TX_LPI_DISABLE; req->flags |= cpu_to_le32(flags); - eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised); + eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised_u32); req->eee_link_speed_mask = cpu_to_le16(eee_speeds); req->tx_lpi_timer = cpu_to_le32(eee->tx_lpi_timer); } else { @@ -11336,8 +11336,8 @@ static bool bnxt_eee_config_ok(struct bnxt *bp) eee->eee_enabled = 0; return false; } - if (eee->advertised & ~advertising) { - eee->advertised = advertising & eee->supported; + if (eee->advertised_u32 & ~advertising) { + eee->advertised_u32 = advertising & eee->supported_u32; return false; } } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index d6a8577d68af..481b835a7703 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3919,16 +3919,16 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_keee *edata) edata->tx_lpi_timer = eee->tx_lpi_timer; } } - if (!edata->advertised) { - edata->advertised = advertising & eee->supported; - } else if (edata->advertised & ~advertising) { + if (!edata->advertised_u32) { + edata->advertised_u32 = advertising & eee->supported_u32; + } else if (edata->advertised_u32 & ~advertising) { netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", - edata->advertised, advertising); + edata->advertised_u32, advertising); rc = -EINVAL; goto eee_exit; } - eee->advertised = edata->advertised; + eee->advertised_u32 = edata->advertised_u32; eee->tx_lpi_enabled = edata->tx_lpi_enabled; eee->tx_lpi_timer = edata->tx_lpi_timer; eee_ok: @@ -3954,12 +3954,12 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_keee *edata) /* Preserve tx_lpi_timer so that the last value will be used * by default when it is re-enabled. */ - edata->advertised = 0; + edata->advertised_u32 = 0; edata->tx_lpi_enabled = 0; } if (!bp->eee.eee_active) - edata->lp_advertised = 0; + edata->lp_advertised_u32 = 0; return 0; } diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 11054177c2ec..f644a91317c9 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2362,13 +2362,13 @@ static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_keee *eee) /* Pull lp advertised settings */ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &val)) return; - dest->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); + dest->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); /* Pull advertised and eee_enabled settings */ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val)) return; dest->eee_enabled = !!val; - dest->advertised = mmd_eee_adv_to_ethtool_adv_t(val); + dest->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); /* Pull tx_lpi_enabled */ val = tr32(TG3_CPMU_EEE_MODE); @@ -4364,9 +4364,9 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) if (!tp->eee.eee_enabled) { val = 0; - tp->eee.advertised = 0; + tp->eee.advertised_u32 = 0; } else { - tp->eee.advertised = advertise & + tp->eee.advertised_u32 = advertise & (ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full); } @@ -4626,13 +4626,13 @@ static bool tg3_phy_eee_config_ok(struct tg3 *tp) tg3_eee_pull_config(tp, &eee); if (tp->eee.eee_enabled) { - if (tp->eee.advertised != eee.advertised || + if (tp->eee.advertised_u32 != eee.advertised_u32 || tp->eee.tx_lpi_timer != eee.tx_lpi_timer || tp->eee.tx_lpi_enabled != eee.tx_lpi_enabled) return false; } else { /* EEE is disabled but we're advertising */ - if (eee.advertised) + if (eee.advertised_u32) return false; } @@ -14189,7 +14189,7 @@ static int tg3_set_eee(struct net_device *dev, struct ethtool_keee *edata) return -EOPNOTSUPP; } - if (edata->advertised != tp->eee.advertised) { + if (edata->advertised_u32 != tp->eee.advertised_u32) { netdev_warn(tp->dev, "Direct manipulation of EEE advertisement is not supported\n"); return -EINVAL; @@ -15655,10 +15655,10 @@ static int tg3_phy_probe(struct tg3 *tp) tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0))) { tp->phy_flags |= TG3_PHYFLG_EEE_CAP; - tp->eee.supported = SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full; - tp->eee.advertised = ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full; + tp->eee.supported_u32 = SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full; + tp->eee.advertised_u32 = ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full; tp->eee.eee_enabled = 1; tp->eee.tx_lpi_enabled = 1; tp->eee.tx_lpi_timer = TG3_CPMU_DBTMR1_LNKIDLE_2047US; diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 343f54b2b6ae..ff243ae71b78 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -2223,16 +2223,16 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data); if (ret_val) goto release; - edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data); + edata->supported_u32 = mmd_eee_cap_to_ethtool_sup_t(phy_data); /* EEE Advertised */ - edata->advertised = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); + edata->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); /* EEE Link Partner Advertised */ ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data); if (ret_val) goto release; - edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); + edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); /* EEE PCS Status */ ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data); @@ -2283,12 +2283,12 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_keee *edata) return -EINVAL; } - if (edata->advertised & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) { + if (edata->advertised_u32 & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) { e_err("EEE advertisement supports only 100TX and/or 1000T full-duplex\n"); return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 9dfda3c48af3..1b5473358e1a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5664,16 +5664,16 @@ static int i40e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) if (phy_cfg.eee_capability == 0) return -EOPNOTSUPP; - edata->supported = SUPPORTED_Autoneg; - edata->lp_advertised = edata->supported; + edata->supported_u32 = SUPPORTED_Autoneg; + edata->lp_advertised_u32 = edata->supported_u32; /* Get current configuration */ status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_cfg, NULL); if (status) return -EAGAIN; - edata->advertised = phy_cfg.eee_capability ? SUPPORTED_Autoneg : 0U; - edata->eee_enabled = !!edata->advertised; + edata->advertised_u32 = phy_cfg.eee_capability ? SUPPORTED_Autoneg : 0U; + edata->eee_enabled = !!edata->advertised_u32; edata->tx_lpi_enabled = pf->stats.tx_lpi_status; edata->eee_active = pf->stats.tx_lpi_status && pf->stats.rx_lpi_status; @@ -5691,7 +5691,7 @@ static int i40e_is_eee_param_supported(struct net_device *netdev, u32 value; const char *name; } param[] = { - {edata->advertised & ~SUPPORTED_Autoneg, "advertise"}, + {edata->advertised_u32 & ~SUPPORTED_Autoneg, "advertise"}, {edata->tx_lpi_timer, "tx-timer"}, {edata->tx_lpi_enabled != pf->stats.tx_lpi_status, "tx-lpi"} }; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 778d1e6cfc45..b87b23d2151c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -3038,10 +3038,10 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) (hw->phy.media_type != e1000_media_type_copper)) return -EOPNOTSUPP; - edata->supported = (SUPPORTED_1000baseT_Full | - SUPPORTED_100baseT_Full); + edata->supported_u32 = (SUPPORTED_1000baseT_Full | + SUPPORTED_100baseT_Full); if (!hw->dev_spec._82575.eee_disable) - edata->advertised = + edata->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); /* The IPCNFG and EEER registers are not supported on I354. */ @@ -3068,7 +3068,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) if (ret_val) return -ENODATA; - edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); + edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); break; case e1000_i354: case e1000_i210: @@ -3079,7 +3079,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) if (ret_val) return -ENODATA; - edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); + edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); break; default: @@ -3099,7 +3099,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) edata->eee_enabled = false; edata->eee_active = false; edata->tx_lpi_enabled = false; - edata->advertised &= ~edata->advertised; + edata->advertised_u32 &= ~edata->advertised_u32; } return 0; @@ -3138,14 +3138,14 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } - if (!edata->advertised || (edata->advertised & + if (!edata->advertised_u32 || (edata->advertised_u32 & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) { dev_err(&adapter->pdev->dev, "EEE Advertisement supports only 100Tx and/or 100T full duplex\n"); return -EINVAL; } - adv100m_eee = !!(edata->advertised & ADVERTISE_100_FULL); - adv1g_eee = !!(edata->advertised & ADVERTISE_1000_FULL); + adv100m_eee = !!(edata->advertised_u32 & ADVERTISE_100_FULL); + adv1g_eee = !!(edata->advertised_u32 & ADVERTISE_1000_FULL); } else if (!edata->eee_enabled) { dev_err(&adapter->pdev->dev, @@ -3153,7 +3153,7 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) { hw->dev_spec._82575.eee_disable = !edata->eee_enabled; adapter->flags |= IGB_FLAG_EEE; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index f2dcfe920f4f..7f844e967421 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1630,11 +1630,11 @@ static int igc_ethtool_get_eee(struct net_device *netdev, u32 eeer; if (hw->dev_spec._base.eee_enable) - edata->advertised = + edata->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); *edata = adapter->eee; - edata->supported = SUPPORTED_Autoneg; + edata->supported_u32 = SUPPORTED_Autoneg; eeer = rd32(IGC_EEER); @@ -1647,8 +1647,8 @@ static int igc_ethtool_get_eee(struct net_device *netdev, edata->eee_enabled = hw->dev_spec._base.eee_enable; - edata->advertised = SUPPORTED_Autoneg; - edata->lp_advertised = SUPPORTED_Autoneg; + edata->advertised_u32 = SUPPORTED_Autoneg; + edata->lp_advertised_u32 = SUPPORTED_Autoneg; /* Report correct negotiated EEE status for devices that * wrongly report EEE at half-duplex @@ -1657,7 +1657,7 @@ static int igc_ethtool_get_eee(struct net_device *netdev, edata->eee_enabled = false; edata->eee_active = false; edata->tx_lpi_enabled = false; - edata->advertised &= ~edata->advertised; + edata->advertised_u32 &= ~edata->advertised_u32; } return 0; @@ -1699,7 +1699,7 @@ static int igc_ethtool_set_eee(struct net_device *netdev, return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); if (hw->dev_spec._base.eee_enable != edata->eee_enabled) { hw->dev_spec._base.eee_enable = edata->eee_enabled; adapter->flags |= IGC_FLAG_EEE; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 0aa73519a29d..ca69a8221793 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -3436,27 +3436,27 @@ ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata) if (rc) return rc; - edata->lp_advertised = 0; + edata->lp_advertised_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_lp_map); ++i) { if (info[0] & ixgbe_lp_map[i].lp_advertised) - edata->lp_advertised |= ixgbe_lp_map[i].mac_speed; + edata->lp_advertised_u32 |= ixgbe_lp_map[i].mac_speed; } - edata->supported = 0; + edata->supported_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed) - edata->supported |= ixgbe_ls_map[i].supported; + edata->supported_u32 |= ixgbe_ls_map[i].supported; } - edata->advertised = 0; + edata->advertised_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed) - edata->advertised |= ixgbe_ls_map[i].supported; + edata->advertised_u32 |= ixgbe_ls_map[i].supported; } - edata->eee_enabled = !!edata->advertised; + edata->eee_enabled = !!edata->advertised_u32; edata->tx_lpi_enabled = edata->eee_enabled; - if (edata->advertised & edata->lp_advertised) + if (edata->advertised_u32 & edata->lp_advertised_u32) edata->eee_active = true; return 0; @@ -3504,7 +3504,7 @@ static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_keee *edata) return -EINVAL; } - if (eee_data.advertised != edata->advertised) { + if (eee_data.advertised_u32 != edata->advertised_u32) { e_err(drv, "Setting EEE advertised speeds is not supported\n"); return -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 77491fb64039..dfa15619fd78 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1790,17 +1790,17 @@ static int qede_get_eee(struct net_device *dev, struct ethtool_keee *edata) } if (current_link.eee.adv_caps & QED_EEE_1G_ADV) - edata->advertised = ADVERTISED_1000baseT_Full; + edata->advertised_u32 = ADVERTISED_1000baseT_Full; if (current_link.eee.adv_caps & QED_EEE_10G_ADV) - edata->advertised |= ADVERTISED_10000baseT_Full; + edata->advertised_u32 |= ADVERTISED_10000baseT_Full; if (current_link.sup_caps & QED_EEE_1G_ADV) - edata->supported = ADVERTISED_1000baseT_Full; + edata->supported_u32 = ADVERTISED_1000baseT_Full; if (current_link.sup_caps & QED_EEE_10G_ADV) - edata->supported |= ADVERTISED_10000baseT_Full; + edata->supported_u32 |= ADVERTISED_10000baseT_Full; if (current_link.eee.lp_adv_caps & QED_EEE_1G_ADV) - edata->lp_advertised = ADVERTISED_1000baseT_Full; + edata->lp_advertised_u32 = ADVERTISED_1000baseT_Full; if (current_link.eee.lp_adv_caps & QED_EEE_10G_ADV) - edata->lp_advertised |= ADVERTISED_10000baseT_Full; + edata->lp_advertised_u32 |= ADVERTISED_10000baseT_Full; edata->tx_lpi_timer = current_link.eee.tx_lpi_timer; edata->eee_enabled = current_link.eee.enable; @@ -1832,20 +1832,20 @@ static int qede_set_eee(struct net_device *dev, struct ethtool_keee *edata) memset(¶ms, 0, sizeof(params)); params.override_flags |= QED_LINK_OVERRIDE_EEE_CONFIG; - if (!(edata->advertised & (ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)) || - ((edata->advertised & (ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)) != - edata->advertised)) { + if (!(edata->advertised_u32 & (ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full)) || + ((edata->advertised_u32 & (ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full)) != + edata->advertised_u32)) { DP_VERBOSE(edev, QED_MSG_DEBUG, "Invalid advertised capabilities %d\n", - edata->advertised); + edata->advertised_u32); return -EINVAL; } - if (edata->advertised & ADVERTISED_1000baseT_Full) + if (edata->advertised_u32 & ADVERTISED_1000baseT_Full) params.eee.adv_caps = QED_EEE_1G_ADV; - if (edata->advertised & ADVERTISED_10000baseT_Full) + if (edata->advertised_u32 & ADVERTISED_10000baseT_Full) params.eee.adv_caps |= QED_EEE_10G_ADV; params.eee.enable = edata->eee_enabled; params.eee.tx_lpi_enable = edata->tx_lpi_enabled; diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index adee5e712871..99c84af25746 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1463,12 +1463,12 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, data->eee_enabled = is_enabled; data->eee_active = ret; - if (!ethtool_convert_link_mode_to_legacy_u32(&data->supported, + if (!ethtool_convert_link_mode_to_legacy_u32(&data->supported_u32, phydev->supported_eee)) overflow = true; - if (!ethtool_convert_link_mode_to_legacy_u32(&data->advertised, adv)) + if (!ethtool_convert_link_mode_to_legacy_u32(&data->advertised_u32, adv)) overflow = true; - if (!ethtool_convert_link_mode_to_legacy_u32(&data->lp_advertised, lp)) + if (!ethtool_convert_link_mode_to_legacy_u32(&data->lp_advertised_u32, lp)) overflow = true; if (overflow) @@ -1495,11 +1495,11 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, int ret; if (data->eee_enabled) { - if (data->advertised) { + if (data->advertised_u32) { __ETHTOOL_DECLARE_LINK_MODE_MASK(adv); ethtool_convert_legacy_u32_to_link_mode(adv, - data->advertised); + data->advertised_u32); linkmode_andnot(adv, adv, phydev->supported_eee); if (!linkmode_empty(adv)) { phydev_warn(phydev, "At least some EEE link modes are not supported.\n"); @@ -1507,7 +1507,7 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, } ethtool_convert_legacy_u32_to_link_mode(phydev->advertising_eee, - data->advertised); + data->advertised_u32); } else { linkmode_copy(phydev->advertising_eee, phydev->supported_eee); diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 3922a9afdd1f..d6168eaa286f 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -676,21 +676,21 @@ ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_keee *data) MDIO_MMD_PCS); if (val < 0) return val; - data->supported = mmd_eee_cap_to_ethtool_sup_t(val); + data->supported_u32 = mmd_eee_cap_to_ethtool_sup_t(val); /* Get advertisement EEE */ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV, MDIO_MMD_AN); if (val < 0) return val; - data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); + data->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); /* Get LP advertisement EEE */ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN); if (val < 0) return val; - data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); + data->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); return 0; } @@ -698,7 +698,7 @@ ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_keee *data) static int ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_keee *data) { - u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised); + u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised_u32); return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, tmp16); @@ -1663,7 +1663,7 @@ static int ax88179_reset(struct usbnet *dev) ax88179_disable_eee(dev); ax88179_ethtool_get_eee(dev, &eee_data); - eee_data.advertised = 0; + eee_data.advertised_u32 = 0; ax88179_ethtool_set_eee(dev, &eee_data); /* Restart autoneg */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index dc163b766a89..3d806b3ff425 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -8938,16 +8938,16 @@ static int r8152_get_eee(struct r8152 *tp, struct ethtool_keee *eee) eee->eee_enabled = tp->eee_en; eee->eee_active = !!(supported & adv & lp); - eee->supported = supported; - eee->advertised = tp->eee_adv; - eee->lp_advertised = lp; + eee->supported_u32 = supported; + eee->advertised_u32 = tp->eee_adv; + eee->lp_advertised_u32 = lp; return 0; } static int r8152_set_eee(struct r8152 *tp, struct ethtool_keee *eee) { - u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); + u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised_u32); tp->eee_en = eee->eee_enabled; tp->eee_adv = val; @@ -8973,9 +8973,9 @@ static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee) eee->eee_enabled = tp->eee_en; eee->eee_active = !!(supported & adv & lp); - eee->supported = supported; - eee->advertised = tp->eee_adv; - eee->lp_advertised = lp; + eee->supported_u32 = supported; + eee->advertised_u32 = tp->eee_adv; + eee->lp_advertised_u32 = lp; return 0; } diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 14549cb9e2b2..89807c30f5a7 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -223,9 +223,9 @@ __ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings); struct ethtool_keee { - u32 supported; - u32 advertised; - u32 lp_advertised; + u32 supported_u32; + u32 advertised_u32; + u32 lp_advertised_u32; u32 tx_lpi_timer; bool tx_lpi_enabled; bool eee_active; diff --git a/net/ethtool/eee.c b/net/ethtool/eee.c index ac9f694ffe20..ca56f28173d5 100644 --- a/net/ethtool/eee.c +++ b/net/ethtool/eee.c @@ -5,7 +5,7 @@ #include "bitset.h" #define EEE_MODES_COUNT \ - (sizeof_field(struct ethtool_keee, supported) * BITS_PER_BYTE) + (sizeof_field(struct ethtool_keee, supported_u32) * BITS_PER_BYTE) struct eee_req_info { struct ethnl_req_info base; @@ -52,19 +52,19 @@ static int eee_reply_size(const struct ethnl_req_info *req_base, int len = 0; int ret; - BUILD_BUG_ON(sizeof(eee->advertised) * BITS_PER_BYTE != + BUILD_BUG_ON(sizeof(eee->advertised_u32) * BITS_PER_BYTE != EEE_MODES_COUNT); - BUILD_BUG_ON(sizeof(eee->lp_advertised) * BITS_PER_BYTE != + BUILD_BUG_ON(sizeof(eee->lp_advertised_u32) * BITS_PER_BYTE != EEE_MODES_COUNT); /* MODES_OURS */ - ret = ethnl_bitset32_size(&eee->advertised, &eee->supported, + ret = ethnl_bitset32_size(&eee->advertised_u32, &eee->supported_u32, EEE_MODES_COUNT, link_mode_names, compact); if (ret < 0) return ret; len += ret; /* MODES_PEERS */ - ret = ethnl_bitset32_size(&eee->lp_advertised, NULL, + ret = ethnl_bitset32_size(&eee->lp_advertised_u32, NULL, EEE_MODES_COUNT, link_mode_names, compact); if (ret < 0) return ret; @@ -88,12 +88,12 @@ static int eee_fill_reply(struct sk_buff *skb, int ret; ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_OURS, - &eee->advertised, &eee->supported, + &eee->advertised_u32, &eee->supported_u32, EEE_MODES_COUNT, link_mode_names, compact); if (ret < 0) return ret; ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_PEER, - &eee->lp_advertised, NULL, EEE_MODES_COUNT, + &eee->lp_advertised_u32, NULL, EEE_MODES_COUNT, link_mode_names, compact); if (ret < 0) return ret; @@ -140,7 +140,7 @@ ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info) if (ret < 0) return ret; - ret = ethnl_update_bitset32(&eee.advertised, EEE_MODES_COUNT, + ret = ethnl_update_bitset32(&eee.advertised_u32, EEE_MODES_COUNT, tb[ETHTOOL_A_EEE_MODES_OURS], link_mode_names, info->extack, &mod); if (ret < 0) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 46c29b369aeb..5b2ca72e3203 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1513,9 +1513,9 @@ static void eee_to_keee(struct ethtool_keee *keee, { memset(keee, 0, sizeof(*keee)); - keee->supported = eee->supported; - keee->advertised = eee->advertised; - keee->lp_advertised = eee->lp_advertised; + keee->supported_u32 = eee->supported; + keee->advertised_u32 = eee->advertised; + keee->lp_advertised_u32 = eee->lp_advertised; keee->eee_active = eee->eee_active; keee->eee_enabled = eee->eee_enabled; keee->tx_lpi_enabled = eee->tx_lpi_enabled; @@ -1527,9 +1527,9 @@ static void keee_to_eee(struct ethtool_eee *eee, { memset(eee, 0, sizeof(*eee)); - eee->supported = keee->supported; - eee->advertised = keee->advertised; - eee->lp_advertised = keee->lp_advertised; + eee->supported = keee->supported_u32; + eee->advertised = keee->advertised_u32; + eee->lp_advertised = keee->lp_advertised_u32; eee->eee_active = keee->eee_active; eee->eee_enabled = keee->eee_enabled; eee->tx_lpi_enabled = keee->tx_lpi_enabled; From 1f069de63602e8d39d7d9fd6195f65235316f79a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jan 2024 14:29:33 +0100 Subject: [PATCH 0477/2255] ethtool: add linkmode bitmap support to struct ethtool_keee Add linkmode bitmap members to struct ethtool_keee, but keep the legacy u32 bitmaps for compatibility with existing drivers. Use linkmode "supported" not being empty as indicator that a user wants to use the linkmode bitmap members instead of the legacy bitmaps. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- include/linux/ethtool.h | 3 +++ net/ethtool/common.c | 5 +++++ net/ethtool/common.h | 1 + net/ethtool/eee.c | 49 +++++++++++++++++++++++++++++------------ net/ethtool/ioctl.c | 27 ++++++++++++++++++++--- 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 89807c30f5a7..b90c33607594 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -223,6 +223,9 @@ __ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings); struct ethtool_keee { + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); + __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised); + __ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertised); u32 supported_u32; u32 advertised_u32; u32 lp_advertised_u32; diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 6b2a360dcdf0..ce486cec346c 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -712,3 +712,8 @@ ethtool_forced_speed_maps_init(struct ethtool_forced_speed_map *maps, u32 size) } } EXPORT_SYMBOL_GPL(ethtool_forced_speed_maps_init); + +bool ethtool_eee_use_linkmodes(const struct ethtool_keee *eee) +{ + return !linkmode_empty(eee->supported); +} diff --git a/net/ethtool/common.h b/net/ethtool/common.h index 28b8aaaf9bcb..0f2b5f7eacee 100644 --- a/net/ethtool/common.h +++ b/net/ethtool/common.h @@ -55,5 +55,6 @@ int ethtool_get_module_eeprom_call(struct net_device *dev, struct ethtool_eeprom *ee, u8 *data); bool __ethtool_dev_mm_supported(struct net_device *dev); +bool ethtool_eee_use_linkmodes(const struct ethtool_keee *eee); #endif /* _ETHTOOL_COMMON_H */ diff --git a/net/ethtool/eee.c b/net/ethtool/eee.c index ca56f28173d5..db6faa18fe41 100644 --- a/net/ethtool/eee.c +++ b/net/ethtool/eee.c @@ -30,6 +30,7 @@ static int eee_prepare_data(const struct ethnl_req_info *req_base, { struct eee_reply_data *data = EEE_REPDATA(reply_base); struct net_device *dev = reply_base->dev; + struct ethtool_keee *eee = &data->eee; int ret; if (!dev->ethtool_ops->get_eee) @@ -37,9 +38,18 @@ static int eee_prepare_data(const struct ethnl_req_info *req_base, ret = ethnl_ops_begin(dev); if (ret < 0) return ret; - ret = dev->ethtool_ops->get_eee(dev, &data->eee); + ret = dev->ethtool_ops->get_eee(dev, eee); ethnl_ops_complete(dev); + if (!ret && !ethtool_eee_use_linkmodes(eee)) { + ethtool_convert_legacy_u32_to_link_mode(eee->supported, + eee->supported_u32); + ethtool_convert_legacy_u32_to_link_mode(eee->advertised, + eee->advertised_u32); + ethtool_convert_legacy_u32_to_link_mode(eee->lp_advertised, + eee->lp_advertised_u32); + } + return ret; } @@ -58,14 +68,16 @@ static int eee_reply_size(const struct ethnl_req_info *req_base, EEE_MODES_COUNT); /* MODES_OURS */ - ret = ethnl_bitset32_size(&eee->advertised_u32, &eee->supported_u32, - EEE_MODES_COUNT, link_mode_names, compact); + ret = ethnl_bitset_size(eee->advertised, eee->supported, + __ETHTOOL_LINK_MODE_MASK_NBITS, + link_mode_names, compact); if (ret < 0) return ret; len += ret; /* MODES_PEERS */ - ret = ethnl_bitset32_size(&eee->lp_advertised_u32, NULL, - EEE_MODES_COUNT, link_mode_names, compact); + ret = ethnl_bitset_size(eee->lp_advertised, NULL, + __ETHTOOL_LINK_MODE_MASK_NBITS, + link_mode_names, compact); if (ret < 0) return ret; len += ret; @@ -87,14 +99,16 @@ static int eee_fill_reply(struct sk_buff *skb, const struct ethtool_keee *eee = &data->eee; int ret; - ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_OURS, - &eee->advertised_u32, &eee->supported_u32, - EEE_MODES_COUNT, link_mode_names, compact); + ret = ethnl_put_bitset(skb, ETHTOOL_A_EEE_MODES_OURS, + eee->advertised, eee->supported, + __ETHTOOL_LINK_MODE_MASK_NBITS, + link_mode_names, compact); if (ret < 0) return ret; - ret = ethnl_put_bitset32(skb, ETHTOOL_A_EEE_MODES_PEER, - &eee->lp_advertised_u32, NULL, EEE_MODES_COUNT, - link_mode_names, compact); + ret = ethnl_put_bitset(skb, ETHTOOL_A_EEE_MODES_PEER, + eee->lp_advertised, NULL, + __ETHTOOL_LINK_MODE_MASK_NBITS, + link_mode_names, compact); if (ret < 0) return ret; @@ -140,9 +154,16 @@ ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info) if (ret < 0) return ret; - ret = ethnl_update_bitset32(&eee.advertised_u32, EEE_MODES_COUNT, - tb[ETHTOOL_A_EEE_MODES_OURS], - link_mode_names, info->extack, &mod); + if (ethtool_eee_use_linkmodes(&eee)) { + ret = ethnl_update_bitset(eee.advertised, + __ETHTOOL_LINK_MODE_MASK_NBITS, + tb[ETHTOOL_A_EEE_MODES_OURS], + link_mode_names, info->extack, &mod); + } else { + ret = ethnl_update_bitset32(&eee.advertised_u32, EEE_MODES_COUNT, + tb[ETHTOOL_A_EEE_MODES_OURS], + link_mode_names, info->extack, &mod); + } if (ret < 0) return ret; ethnl_update_bool(&eee.eee_enabled, tb[ETHTOOL_A_EEE_ENABLED], &mod); diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 5b2ca72e3203..1763e8b697e1 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1520,6 +1520,13 @@ static void eee_to_keee(struct ethtool_keee *keee, keee->eee_enabled = eee->eee_enabled; keee->tx_lpi_enabled = eee->tx_lpi_enabled; keee->tx_lpi_timer = eee->tx_lpi_timer; + + ethtool_convert_legacy_u32_to_link_mode(keee->supported, + eee->supported); + ethtool_convert_legacy_u32_to_link_mode(keee->advertised, + eee->advertised); + ethtool_convert_legacy_u32_to_link_mode(keee->lp_advertised, + eee->lp_advertised); } static void keee_to_eee(struct ethtool_eee *eee, @@ -1527,13 +1534,27 @@ static void keee_to_eee(struct ethtool_eee *eee, { memset(eee, 0, sizeof(*eee)); - eee->supported = keee->supported_u32; - eee->advertised = keee->advertised_u32; - eee->lp_advertised = keee->lp_advertised_u32; eee->eee_active = keee->eee_active; eee->eee_enabled = keee->eee_enabled; eee->tx_lpi_enabled = keee->tx_lpi_enabled; eee->tx_lpi_timer = keee->tx_lpi_timer; + + if (ethtool_eee_use_linkmodes(keee)) { + bool overflow; + + overflow = !ethtool_convert_link_mode_to_legacy_u32(&eee->supported, + keee->supported); + ethtool_convert_link_mode_to_legacy_u32(&eee->advertised, + keee->advertised); + ethtool_convert_link_mode_to_legacy_u32(&eee->lp_advertised, + keee->lp_advertised); + if (overflow) + pr_warn("Ethtool ioctl interface doesn't support passing EEE linkmodes beyond bit 32\n"); + } else { + eee->supported = keee->supported_u32; + eee->advertised = keee->advertised_u32; + eee->lp_advertised = keee->lp_advertised_u32; + } } static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) From 2bb0526129592de59c3e2cd3e8ebe426b7b5b07f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Jan 2024 14:30:29 +0100 Subject: [PATCH 0478/2255] net: phy: c45: change genphy_c45_ethtool_[get|set]_eee to use EEE linkmode bitmaps Change genphy_c45_ethtool_[get|set]_eee to use EEE linkmode bitmaps. This is a prerequisite for adding support for EEE modes beyond bit 31. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy-c45.c | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 99c84af25746..46c87a903efd 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1453,7 +1453,7 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, { __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {}; __ETHTOOL_DECLARE_LINK_MODE_MASK(lp) = {}; - bool overflow = false, is_enabled; + bool is_enabled; int ret; ret = genphy_c45_eee_is_active(phydev, adv, lp, &is_enabled); @@ -1462,17 +1462,9 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, data->eee_enabled = is_enabled; data->eee_active = ret; - - if (!ethtool_convert_link_mode_to_legacy_u32(&data->supported_u32, - phydev->supported_eee)) - overflow = true; - if (!ethtool_convert_link_mode_to_legacy_u32(&data->advertised_u32, adv)) - overflow = true; - if (!ethtool_convert_link_mode_to_legacy_u32(&data->lp_advertised_u32, lp)) - overflow = true; - - if (overflow) - phydev_warn(phydev, "Not all supported or advertised EEE link modes were passed to the user space\n"); + linkmode_copy(data->supported, phydev->supported_eee); + linkmode_copy(data->advertised, adv); + linkmode_copy(data->lp_advertised, lp); return 0; } @@ -1495,24 +1487,22 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, int ret; if (data->eee_enabled) { - if (data->advertised_u32) { - __ETHTOOL_DECLARE_LINK_MODE_MASK(adv); + unsigned long *adv = data->advertised; - ethtool_convert_legacy_u32_to_link_mode(adv, - data->advertised_u32); - linkmode_andnot(adv, adv, phydev->supported_eee); - if (!linkmode_empty(adv)) { + if (!linkmode_empty(adv)) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp); + bool unsupp; + + unsupp = linkmode_andnot(tmp, adv, phydev->supported_eee); + if (unsupp) { phydev_warn(phydev, "At least some EEE link modes are not supported.\n"); return -EINVAL; } - - ethtool_convert_legacy_u32_to_link_mode(phydev->advertising_eee, - data->advertised_u32); } else { - linkmode_copy(phydev->advertising_eee, - phydev->supported_eee); + adv = phydev->supported_eee; } + linkmode_copy(phydev->advertising_eee, adv); phydev->eee_enabled = true; } else { phydev->eee_enabled = false; From e746094b1bb09efa2eaacf5e945f78a0e09c9c35 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Sun, 28 Jan 2024 20:51:34 +0100 Subject: [PATCH 0479/2255] net: lan966x: debugfs: Fix showing the port keyset On lan966x, it is possible to use debugfs to print different information about the VCAPs. Information like, if it is enabled, how the ports are configured, print the actual rules. The issue is that when printing how the ports are configured for IS1 lookups, it was parsing the wrong register to get this information. The fix consists in reading the correct register that contains this information. Signed-off-by: Horatiu Vultur Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c index ac525ff1503e..3a01e13bd10b 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c @@ -25,6 +25,8 @@ static void lan966x_vcap_is1_port_keys(struct lan966x_port *port, for (int l = 0; l < admin->lookups; ++l) { out->prf(out->dst, "\n Lookup %d: ", l); + val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, l)); + out->prf(out->dst, "\n other: "); switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) { case VCAP_IS1_PS_OTHER_NORMAL: From c494a01abe01fcfcbbcd849023ce06a573963aed Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:45 +0100 Subject: [PATCH 0480/2255] qca_spi: Add check for kthread_stop We better not rely on that spi_thread points to a running thread. So add an check for this. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 5f3c11fb3fa2..77bab8bf5203 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -730,8 +730,10 @@ qcaspi_netdev_close(struct net_device *dev) qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0, wr_verify); free_irq(qca->spi_dev->irq, qca); - kthread_stop(qca->spi_thread); - qca->spi_thread = NULL; + if (qca->spi_thread) { + kthread_stop(qca->spi_thread); + qca->spi_thread = NULL; + } qcaspi_flush_tx_ring(qca); return 0; From 1a10d67ca426f6f5a76fbb81270d4ad1b44d3950 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:46 +0100 Subject: [PATCH 0481/2255] qca_spi: Improve SPI thread creation Directly storing the result of kthread_run within the private driver data makes it harder to identify if the pointer has a running thread or not. So better use a local variable for the result check and we don't have to care about error pointer in the rest of the code. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 77bab8bf5203..fe50c2dd7cc8 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -687,6 +687,7 @@ static int qcaspi_netdev_open(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); + struct task_struct *thread; int ret = 0; if (!qca) @@ -697,15 +698,17 @@ qcaspi_netdev_open(struct net_device *dev) qca->sync = QCASPI_SYNC_UNKNOWN; qcafrm_fsm_init_spi(&qca->frm_handle); - qca->spi_thread = kthread_run((void *)qcaspi_spi_thread, - qca, "%s", dev->name); + thread = kthread_run((void *)qcaspi_spi_thread, + qca, "%s", dev->name); - if (IS_ERR(qca->spi_thread)) { + if (IS_ERR(thread)) { netdev_err(dev, "%s: unable to start kernel thread.\n", QCASPI_DRV_NAME); - return PTR_ERR(qca->spi_thread); + return PTR_ERR(thread); } + qca->spi_thread = thread; + ret = request_irq(qca->spi_dev->irq, qcaspi_intr_handler, 0, dev->name, qca); if (ret) { From 3c5e48780882d1c2de5efc9667c633ff0ebae2bc Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:47 +0100 Subject: [PATCH 0482/2255] qca_spi: Improve SPI IRQ handling The functions qcaspi_netdev_open/close are responsible of request & free of the SPI interrupt, which wasn't the best choice because allocation problems are discovered not during probe. So let us split IRQ allocation & enabling, so we can take advantage of a device managed IRQ. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index fe50c2dd7cc8..3f7e38a11ba0 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -688,7 +688,6 @@ qcaspi_netdev_open(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); struct task_struct *thread; - int ret = 0; if (!qca) return -EINVAL; @@ -709,14 +708,7 @@ qcaspi_netdev_open(struct net_device *dev) qca->spi_thread = thread; - ret = request_irq(qca->spi_dev->irq, qcaspi_intr_handler, 0, - dev->name, qca); - if (ret) { - netdev_err(dev, "%s: unable to get IRQ %d (irqval=%d).\n", - QCASPI_DRV_NAME, qca->spi_dev->irq, ret); - kthread_stop(qca->spi_thread); - return ret; - } + enable_irq(qca->spi_dev->irq); /* SPI thread takes care of TX queue */ @@ -731,7 +723,7 @@ qcaspi_netdev_close(struct net_device *dev) netif_stop_queue(dev); qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0, wr_verify); - free_irq(qca->spi_dev->irq, qca); + disable_irq(qca->spi_dev->irq); if (qca->spi_thread) { kthread_stop(qca->spi_thread); @@ -989,6 +981,15 @@ qca_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, qcaspi_devs); + ret = devm_request_irq(&spi->dev, spi->irq, qcaspi_intr_handler, + IRQF_NO_AUTOEN, qca->net_dev->name, qca); + if (ret) { + dev_err(&spi->dev, "Unable to get IRQ %d (irqval=%d).\n", + spi->irq, ret); + free_netdev(qcaspi_devs); + return ret; + } + ret = of_get_ethdev_address(spi->dev.of_node, qca->net_dev); if (ret) { eth_hw_addr_random(qca->net_dev); From 56f0b4f55b71f453c2ec6b6f70725c28dc437c32 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:48 +0100 Subject: [PATCH 0483/2255] qca_spi: Avoid skb_copy_expand in TX path The skb spare room needs to be expanded for SPI header, footer and possible padding within the TX path. So announce the necessary space in order to avoid expensive skb_copy_expand calls. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 3f7e38a11ba0..5fabb40cca05 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -878,6 +878,8 @@ qcaspi_netdev_setup(struct net_device *dev) qcaspi_set_ethtool_ops(dev); dev->watchdog_timeo = QCASPI_TX_TIMEOUT; dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->needed_tailroom = ALIGN(QCAFRM_FOOTER_LEN + QCAFRM_MIN_LEN, 4); + dev->needed_headroom = ALIGN(QCAFRM_HEADER_LEN, 4); dev->tx_queue_len = 100; /* MTU range: 46 - 1500 */ From c453884ebe0818885ba54b674a5ee3535f882372 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:49 +0100 Subject: [PATCH 0484/2255] qca_7k_common: Drop unnecessary function description qcafrm_fsm_decode has the almost the same function description in qca_7k_common.c. So drop the comment here. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k_common.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h index 928554f11e35..71bdf5d9f8d7 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.h +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -128,17 +128,6 @@ static inline void qcafrm_fsm_init_uart(struct qcafrm_handle *handle) handle->state = handle->init; } -/* Gather received bytes and try to extract a full Ethernet frame - * by following a simple state machine. - * - * Return: QCAFRM_GATHER No Ethernet frame fully received yet. - * QCAFRM_NOHEAD Header expected but not found. - * QCAFRM_INVLEN QCA7K frame length is invalid - * QCAFRM_NOTAIL Footer expected but not found. - * > 0 Number of byte in the fully received - * Ethernet frame - */ - s32 qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte); #endif /* _QCA_FRAMING_H */ From 22d70f69f96dd0994c717b3f34c90f0a64518887 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:50 +0100 Subject: [PATCH 0485/2255] qca_7k_common: Drop unused len from qcafrm_handle This member is never used. So drop it. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k_common.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h index 71bdf5d9f8d7..088cca7f61db 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.h +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -107,9 +107,6 @@ struct qcafrm_handle { /* Offset in buffer (borrowed for length too) */ u16 offset; - - /* Frame length as kept by this module */ - u16 len; }; u16 qcafrm_create_header(u8 *buf, u16 len); From c7f6250ab2adbce44ce086d190e346be6d7a03fb Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:51 +0100 Subject: [PATCH 0486/2255] qca_spi: Add QCASPI prefix to ring defines All defines in qca_spi.h except of the two ring limit defines have a QCASPI prefix. Since the name is quite generic add the QCASPI prefix to avoid possible name conflicts. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_debug.c | 6 +++--- drivers/net/ethernet/qualcomm/qca_spi.c | 4 ++-- drivers/net/ethernet/qualcomm/qca_spi.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c index 1822f2ad8f0d..857883d0b5ed 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.c +++ b/drivers/net/ethernet/qualcomm/qca_debug.c @@ -255,7 +255,7 @@ qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring, struct qcaspi *qca = netdev_priv(dev); ring->rx_max_pending = QCASPI_RX_MAX_FRAMES; - ring->tx_max_pending = TX_RING_MAX_LEN; + ring->tx_max_pending = QCASPI_TX_RING_MAX_LEN; ring->rx_pending = QCASPI_RX_MAX_FRAMES; ring->tx_pending = qca->txr.count; } @@ -275,8 +275,8 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring, if (qca->spi_thread) kthread_park(qca->spi_thread); - qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN); - qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN); + qca->txr.count = max_t(u32, ring->tx_pending, QCASPI_TX_RING_MIN_LEN); + qca->txr.count = min_t(u16, qca->txr.count, QCASPI_TX_RING_MAX_LEN); if (qca->spi_thread) kthread_unpark(qca->spi_thread); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 5fabb40cca05..f53438c4aea2 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -476,7 +476,7 @@ qcaspi_flush_tx_ring(struct qcaspi *qca) * has been replaced by netif_tx_lock_bh() and so on. */ netif_tx_lock_bh(qca->net_dev); - for (i = 0; i < TX_RING_MAX_LEN; i++) { + for (i = 0; i < QCASPI_TX_RING_MAX_LEN; i++) { if (qca->txr.skb[i]) { dev_kfree_skb(qca->txr.skb[i]); qca->txr.skb[i] = NULL; @@ -890,7 +890,7 @@ qcaspi_netdev_setup(struct net_device *dev) memset(qca, 0, sizeof(struct qcaspi)); memset(&qca->txr, 0, sizeof(qca->txr)); - qca->txr.count = TX_RING_MAX_LEN; + qca->txr.count = QCASPI_TX_RING_MAX_LEN; } static const struct of_device_id qca_spi_of_match[] = { diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index 3067356106f0..dcecb072b8eb 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -39,8 +39,8 @@ #define QCASPI_GOOD_SIGNATURE 0xAA55 -#define TX_RING_MAX_LEN 10 -#define TX_RING_MIN_LEN 2 +#define QCASPI_TX_RING_MAX_LEN 10 +#define QCASPI_TX_RING_MIN_LEN 2 /* sync related constants */ #define QCASPI_SYNC_UNKNOWN 0 @@ -54,7 +54,7 @@ #define QCASPI_EVENT_CPUON 1 struct tx_ring { - struct sk_buff *skb[TX_RING_MAX_LEN]; + struct sk_buff *skb[QCASPI_TX_RING_MAX_LEN]; u16 head; u16 tail; u16 size; From fa5343952f45d478897d5d3db9d64007b13e4abd Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:52 +0100 Subject: [PATCH 0487/2255] qca_spi: Introduce QCASPI_RX_MAX_FRAMES Currently qca_spi reserves enough space for 4 complete Ethernet over SPI frames in the receive buffer. Unfortunately this is hidden under a magic number. So replace it with a more self explaining define. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 2 +- drivers/net/ethernet/qualcomm/qca_spi.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index f53438c4aea2..c0f6bd3d331a 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -829,7 +829,7 @@ qcaspi_netdev_init(struct net_device *dev) qca->burst_len = qcaspi_burst_len; qca->spi_thread = NULL; qca->buffer_size = (dev->mtu + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + - QCAFRM_FOOTER_LEN + 4) * 4; + QCAFRM_FOOTER_LEN + 4) * QCASPI_RX_MAX_FRAMES; memset(&qca->stats, 0, sizeof(struct qcaspi_stats)); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index dcecb072b8eb..f735ad77402f 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -41,6 +41,7 @@ #define QCASPI_TX_RING_MAX_LEN 10 #define QCASPI_TX_RING_MIN_LEN 2 +#define QCASPI_RX_MAX_FRAMES 4 /* sync related constants */ #define QCASPI_SYNC_UNKNOWN 0 From 0a8ef9ed7a16d42fe1c3bf4656312d875a7e1ce5 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:53 +0100 Subject: [PATCH 0488/2255] qca_spi: Improve calculation of RX buffer size There are two points with the calculation of RX buffer size which are not optimal: 1. dev->mtu is a mutual parameter and it's currently initialized with QCAFRM_MAX_MTU. But for RX buffer size calculation we always need the maximum possible MTU. So better use the define directly. 2. This magic number 4 represent the hardware generated frame length which is specific to SPI. We better replace this with the suitable define. There is no functional change. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index c0f6bd3d331a..b35fabcd488b 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -828,8 +828,8 @@ qcaspi_netdev_init(struct net_device *dev) qca->clkspeed = qcaspi_clkspeed; qca->burst_len = qcaspi_burst_len; qca->spi_thread = NULL; - qca->buffer_size = (dev->mtu + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + - QCAFRM_FOOTER_LEN + 4) * QCASPI_RX_MAX_FRAMES; + qca->buffer_size = (QCAFRM_MAX_MTU + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + + QCAFRM_FOOTER_LEN + QCASPI_HW_PKT_LEN) * QCASPI_RX_MAX_FRAMES; memset(&qca->stats, 0, sizeof(struct qcaspi_stats)); From 8f3655d8a515bdef18eeccf4245e3e3c458d7fd3 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:54 +0100 Subject: [PATCH 0489/2255] qca_spi: Log expected signature in error case Most of the users doesn't know the expected signature of the QCA700x. So provide it within the error message. Btw use lowercase for hex as in the rest of the driver. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index b35fabcd488b..d2d68c20b32c 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -1006,8 +1006,8 @@ qca_spi_probe(struct spi_device *spi) qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); if (signature != QCASPI_GOOD_SIGNATURE) { - dev_err(&spi->dev, "Invalid signature (0x%04X)\n", - signature); + dev_err(&spi->dev, "Invalid signature (expected 0x%04x, read 0x%04x)\n", + QCASPI_GOOD_SIGNATURE, signature); free_netdev(qcaspi_devs); return -EFAULT; } From f486c4b57649ed58a2baef66691ce4ac6fcf0fb1 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:55 +0100 Subject: [PATCH 0490/2255] qca_spi: Adjust log of SPI_REG_RDBUF_BYTE_AVA All known SPI registers of the QCA700x are 16 bit long. So adjust the formater width accordingly. Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index d2d68c20b32c..ca8c0596a992 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -359,7 +359,7 @@ qcaspi_receive(struct qcaspi *qca) /* Read the packet size. */ qcaspi_read_register(qca, SPI_REG_RDBUF_BYTE_AVA, &available); - netdev_dbg(net_dev, "qcaspi_receive: SPI_REG_RDBUF_BYTE_AVA: Value: %08x\n", + netdev_dbg(net_dev, "qcaspi_receive: SPI_REG_RDBUF_BYTE_AVA: Value: %04x\n", available); if (available > QCASPI_HW_BUF_LEN + QCASPI_HW_PKT_LEN) { From 060e309a4d12890540d925552337800b38a26778 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:56 +0100 Subject: [PATCH 0491/2255] qca_7k: Replace BSD boilerplate with SPDX According to MODULE_LICENSE the driver is under a dual license. So replace the BSD license text with the proper SPDX tag. Signed-off-by: Stefan Wahren Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k.c | 17 +---------------- drivers/net/ethernet/qualcomm/qca_7k.h | 16 +--------------- drivers/net/ethernet/qualcomm/qca_7k_common.c | 15 +-------------- drivers/net/ethernet/qualcomm/qca_7k_common.h | 15 +-------------- drivers/net/ethernet/qualcomm/qca_debug.c | 15 +-------------- drivers/net/ethernet/qualcomm/qca_debug.h | 15 +-------------- drivers/net/ethernet/qualcomm/qca_spi.c | 15 +-------------- drivers/net/ethernet/qualcomm/qca_spi.h | 15 +-------------- drivers/net/ethernet/qualcomm/qca_uart.c | 15 +-------------- 9 files changed, 9 insertions(+), 129 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c index 4292c89bd35c..6263e4cf47fa 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.c +++ b/drivers/net/ethernet/qualcomm/qca_7k.c @@ -1,22 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* - * * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * */ /* This module implements the Qualcomm Atheros SPI protocol for diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h index 356de8ec5d48..828ee9c27578 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.h +++ b/drivers/net/ethernet/qualcomm/qca_7k.h @@ -1,21 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * */ /* Qualcomm Atheros SPI register definition. diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c index 6b511f05df61..be2f754efd21 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.c +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Atheros ethernet framing. Every Ethernet frame is surrounded diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h index 088cca7f61db..44ed66fdb407 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.h +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Atheros Ethernet framing. Every Ethernet frame is surrounded by an atheros diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c index 857883d0b5ed..ff3b89e9028e 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.c +++ b/drivers/net/ethernet/qualcomm/qca_debug.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This file contains debugging routines for use in the QCA7K driver. diff --git a/drivers/net/ethernet/qualcomm/qca_debug.h b/drivers/net/ethernet/qualcomm/qca_debug.h index 46a785844421..0d98cef3abc4 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.h +++ b/drivers/net/ethernet/qualcomm/qca_debug.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This file contains debugging routines for use in the QCA7K driver. diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index ca8c0596a992..ed6d20be19bb 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This module implements the Qualcomm Atheros SPI protocol for diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index f735ad77402f..d59cb2352cee 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Qualcomm Atheros SPI register definition. diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c index 223321897b96..d0db9d0adad7 100644 --- a/drivers/net/ethernet/qualcomm/qca_uart.c +++ b/drivers/net/ethernet/qualcomm/qca_uart.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2017, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This module implements the Qualcomm Atheros UART protocol for From d7d5f0fceca8cea3ca44e2a281bb9a4c5ca8354c Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:57 +0100 Subject: [PATCH 0492/2255] qca_7k: Replace old mail address The company I2SE has been acquired a long time ago. Switch to my private mail address before the I2SE account is deactivated. Signed-off-by: Stefan Wahren Signed-off-by: Stefan Wahren Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k_common.c | 2 +- drivers/net/ethernet/qualcomm/qca_spi.c | 2 +- drivers/net/ethernet/qualcomm/qca_uart.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c index be2f754efd21..5302da587620 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.c +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c @@ -149,5 +149,5 @@ EXPORT_SYMBOL_GPL(qcafrm_fsm_decode); MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common"); MODULE_AUTHOR("Qualcomm Atheros Communications"); -MODULE_AUTHOR("Stefan Wahren "); +MODULE_AUTHOR("Stefan Wahren "); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index ed6d20be19bb..5799ecc88a87 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -1043,6 +1043,6 @@ module_spi_driver(qca_spi_driver); MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 SPI Driver"); MODULE_AUTHOR("Qualcomm Atheros Communications"); -MODULE_AUTHOR("Stefan Wahren "); +MODULE_AUTHOR("Stefan Wahren "); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(QCASPI_DRV_VERSION); diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c index d0db9d0adad7..321fd8d00730 100644 --- a/drivers/net/ethernet/qualcomm/qca_uart.c +++ b/drivers/net/ethernet/qualcomm/qca_uart.c @@ -397,6 +397,6 @@ module_serdev_device_driver(qca_uart_driver); MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 UART Driver"); MODULE_AUTHOR("Qualcomm Atheros Communications"); -MODULE_AUTHOR("Stefan Wahren "); +MODULE_AUTHOR("Stefan Wahren "); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(QCAUART_DRV_VERSION); From a47996ebbe405b2d89f371d3fc349d390097edfa Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:58 +0100 Subject: [PATCH 0493/2255] mailmap: add entry for Stefan Wahren Add a .mailmap entry because my old i2se.com address will be deactivated in the near future. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 04998f7bda81..95b4fe465cc6 100644 --- a/.mailmap +++ b/.mailmap @@ -568,6 +568,7 @@ Simon Kelley Sricharan Ramabadhran Srinivas Ramana Sriram R +Stefan Wahren Stéphane Witzmann Stephen Hemminger Stephen Hemminger From 23b8a64b6c9fd9c6b959550059ba48fe32ebe6fe Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jan 2024 21:10:59 +0100 Subject: [PATCH 0494/2255] MAINTAINERS: add entry for qca7k driver(s) Since upstreaming i contributed a lot to this driver(s), so add myself as a maintainer. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index cec57b22d937..05899589d74e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18014,6 +18014,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git F: Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml F: drivers/net/wireless/ath/ath9k/ +QUALCOMM ATHEROS QCA7K ETHERNET DRIVER +M: Stefan Wahren +L: netdev@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/net/qca,qca7000.txt +F: drivers/net/ethernet/qualcomm/qca* + QUALCOMM BAM-DMUX WWAN NETWORK DRIVER M: Stephan Gerhold L: netdev@vger.kernel.org From 26f0dc8a705ae182eaa126cef0a9870d1a87a5ac Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 28 Jan 2024 10:30:56 +0100 Subject: [PATCH 0495/2255] 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(-) 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); From 2a71528427c635f0a8bff704b2e62ce81c641d6f Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 28 Jan 2024 10:30:57 +0100 Subject: [PATCH 0496/2255] wifi: brcmfmac: fix copyright year mentioned in platform_data header The driver found its inception a little after the year 201. According git blame output it was added in 2016 so lets go with that. Fixes: 4d7928959832 ("brcmfmac: switch to new platform data") Reported-by: Dmitry Antipov Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240128093057.164791-3-arend.vanspriel@broadcom.com --- include/linux/platform_data/brcmfmac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/platform_data/brcmfmac.h b/include/linux/platform_data/brcmfmac.h index f922a192fe58..ec99b7b73d1d 100644 --- a/include/linux/platform_data/brcmfmac.h +++ b/include/linux/platform_data/brcmfmac.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 201 Broadcom Corporation + * Copyright (c) 2016 Broadcom Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above From 2ef61296d2844c6a4211e07ab70ef2fb412b2c30 Mon Sep 17 00:00:00 2001 From: Manu Bretelle Date: Tue, 30 Jan 2024 21:32:12 -0800 Subject: [PATCH 0497/2255] selftests/bpf: Disable IPv6 for lwt_redirect test After a recent change in the vmtest runner, this test started failing sporadically. Investigation showed that this test was subject to race condition which got exacerbated after the vm runner change. The symptoms being that the logic that waited for an ICMPv4 packet is naive and will break if 5 or more non-ICMPv4 packets make it to tap0. When ICMPv6 is enabled, the kernel will generate traffic such as ICMPv6 router solicitation... On a system with good performance, the expected ICMPv4 packet would very likely make it to the network interface promptly, but on a system with poor performance, those "guarantees" do not hold true anymore. Given that the test is IPv4 only, this change disable IPv6 in the test netns by setting `net.ipv6.conf.all.disable_ipv6` to 1. This essentially leaves "ping" as the sole generator of traffic in the network namespace. If this test was to be made IPv6 compatible, the logic in `wait_for_packet` would need to be modified. In more details... At a high level, the test does: - create a new namespace - in `setup_redirect_target` set up lo, tap0, and link_err interfaces as well as add 2 routes that attaches ingress/egress sections of `test_lwt_redirect.bpf.o` to the xmit path. - in `send_and_capture_test_packets` send an ICMP packet and read off the tap interface (using `wait_for_packet`) to check that a ICMP packet with the right size is read. `wait_for_packet` will try to read `max_retry` (5) times from the tap0 fd looking for an ICMPv4 packet matching some criteria. The problem is that when we set up the `tap0` interface, because IPv6 is enabled by default, traffic such as Router solicitation is sent through tap0, as in: # tcpdump -r /tmp/lwt_redirect.pc reading from file /tmp/lwt_redirect.pcap, link-type EN10MB (Ethernet) 04:46:23.578352 IP6 :: > ff02::1:ffc0:4427: ICMP6, neighbor solicitation, who has fe80::fcba:dff:fec0:4427, length 32 04:46:23.659522 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 04:46:24.389169 IP 10.0.0.1 > 20.0.0.9: ICMP echo request, id 122, seq 1, length 108 04:46:24.618599 IP6 fe80::fcba:dff:fec0:4427 > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 04:46:24.619985 IP6 fe80::fcba:dff:fec0:4427 > ff02::2: ICMP6, router solicitation, length 16 04:46:24.767326 IP6 fe80::fcba:dff:fec0:4427 > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 04:46:28.936402 IP6 fe80::fcba:dff:fec0:4427 > ff02::2: ICMP6, router solicitation, length 16 If `wait_for_packet` sees 5 non-ICMPv4 packets, it will return 0, which is what we see in: 2024-01-31T03:51:25.0336992Z test_lwt_redirect_run:PASS:netns_create 0 nsec 2024-01-31T03:51:25.0341309Z open_netns:PASS:malloc token 0 nsec 2024-01-31T03:51:25.0344844Z open_netns:PASS:open /proc/self/ns/net 0 nsec 2024-01-31T03:51:25.0350071Z open_netns:PASS:open netns fd 0 nsec 2024-01-31T03:51:25.0353516Z open_netns:PASS:setns 0 nsec 2024-01-31T03:51:25.0356560Z test_lwt_redirect_run:PASS:setns 0 nsec 2024-01-31T03:51:25.0360140Z open_tuntap:PASS:open(/dev/net/tun) 0 nsec 2024-01-31T03:51:25.0363822Z open_tuntap:PASS:ioctl(TUNSETIFF) 0 nsec 2024-01-31T03:51:25.0367402Z open_tuntap:PASS:fcntl(O_NONBLOCK) 0 nsec 2024-01-31T03:51:25.0371167Z setup_redirect_target:PASS:open_tuntap 0 nsec 2024-01-31T03:51:25.0375180Z setup_redirect_target:PASS:if_nametoindex 0 nsec 2024-01-31T03:51:25.0379929Z setup_redirect_target:PASS:ip link add link_err type dummy 0 nsec 2024-01-31T03:51:25.0384874Z setup_redirect_target:PASS:ip link set lo up 0 nsec 2024-01-31T03:51:25.0389678Z setup_redirect_target:PASS:ip addr add dev lo 10.0.0.1/32 0 nsec 2024-01-31T03:51:25.0394814Z setup_redirect_target:PASS:ip link set link_err up 0 nsec 2024-01-31T03:51:25.0399874Z setup_redirect_target:PASS:ip link set tap0 up 0 nsec 2024-01-31T03:51:25.0407731Z setup_redirect_target:PASS:ip route add 10.0.0.0/24 dev link_err encap bpf xmit obj test_lwt_redirect.bpf.o sec redir_ingress 0 nsec 2024-01-31T03:51:25.0419105Z setup_redirect_target:PASS:ip route add 20.0.0.0/24 dev link_err encap bpf xmit obj test_lwt_redirect.bpf.o sec redir_egress 0 nsec 2024-01-31T03:51:25.0427209Z test_lwt_redirect_normal:PASS:setup_redirect_target 0 nsec 2024-01-31T03:51:25.0431424Z ping_dev:PASS:if_nametoindex 0 nsec 2024-01-31T03:51:25.0437222Z send_and_capture_test_packets:FAIL:wait_for_epacket unexpected wait_for_epacket: actual 0 != expected 1 2024-01-31T03:51:25.0448298Z (/tmp/work/bpf/bpf/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c:175: errno: Success) test_lwt_redirect_normal egress test fails 2024-01-31T03:51:25.0457124Z close_netns:PASS:setns 0 nsec When running in a VM which potential resource contrains, the odds that calling `ping` is not scheduled very soon after bringing `tap0` up increases, and with this the chances to get our ICMP packet pushed to position 6+ in the network trace. To confirm this indeed solves the issue, I ran the test 100 times in a row with: errors=0 successes=0 for i in `seq 1 100` do ./test_progs -t lwt_redirect/lwt_redirect_normal if [ $? -eq 0 ]; then successes=$((successes+1)) else errors=$((errors+1)) fi done echo "successes: $successes/errors: $errors" While this test would at least fail a couple of time every 10 runs, here it ran 100 times with no error. Fixes: 43a7c3ef8a15 ("selftests/bpf: Add lwt_xmit tests for BPF_REDIRECT") Signed-off-by: Manu Bretelle Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240131053212.2247527-1-chantr4@gmail.com --- tools/testing/selftests/bpf/prog_tests/lwt_redirect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c index beeb3ac1c361..b5b9e74b1044 100644 --- a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c +++ b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c @@ -203,6 +203,7 @@ static int setup_redirect_target(const char *target_dev, bool need_mac) if (!ASSERT_GE(target_index, 0, "if_nametoindex")) goto fail; + SYS(fail, "sysctl -w net.ipv6.conf.all.disable_ipv6=1"); SYS(fail, "ip link add link_err type dummy"); SYS(fail, "ip link set lo up"); SYS(fail, "ip addr add dev lo " LOCAL_SRC "/32"); From 5264ab612e28058536de8069bcf83eb20fd65c29 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 26 Jan 2024 21:31:51 -0500 Subject: [PATCH 0498/2255] selftests/net: calibrate txtimestamp The test sends packets and compares enqueue, transmit and Ack timestamps with expected values. It installs netem delays to increase latency between these points. The test proves flaky in virtual environment (vng). Increase the delays to reduce variance. Scale measurement tolerance accordingly. Time sensitive tests are difficult to calibrate. Increasing delays 10x also increases runtime 10x, for one. And it may still prove flaky at some rate. Signed-off-by: Willem de Bruijn Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240127023212.3746239-1-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/txtimestamp.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/txtimestamp.sh b/tools/testing/selftests/net/txtimestamp.sh index 31637769f59f..25baca4b148e 100755 --- a/tools/testing/selftests/net/txtimestamp.sh +++ b/tools/testing/selftests/net/txtimestamp.sh @@ -8,13 +8,13 @@ set -e setup() { # set 1ms delay on lo egress - tc qdisc add dev lo root netem delay 1ms + tc qdisc add dev lo root netem delay 10ms # set 2ms delay on ifb0 egress modprobe ifb ip link add ifb_netem0 type ifb ip link set dev ifb_netem0 up - tc qdisc add dev ifb_netem0 root netem delay 2ms + tc qdisc add dev ifb_netem0 root netem delay 20ms # redirect lo ingress through ifb0 egress tc qdisc add dev lo handle ffff: ingress @@ -24,9 +24,11 @@ setup() { } run_test_v4v6() { - # SND will be delayed 1000us - # ACK will be delayed 6000us: 1 + 2 ms round-trip - local -r args="$@ -v 1000 -V 6000" + # SND will be delayed 10ms + # ACK will be delayed 60ms: 10 + 20 ms round-trip + # allow +/- tolerance of 8ms + # wait for ACK to be queued + local -r args="$@ -v 10000 -V 60000 -t 8000 -S 80000" ./txtimestamp ${args} -4 -L 127.0.0.1 ./txtimestamp ${args} -6 -L ::1 From 79b47344bbc5a693a92ed6b2b09dac59254bfac8 Mon Sep 17 00:00:00 2001 From: Daniel Xu Date: Sun, 28 Jan 2024 18:24:06 -0700 Subject: [PATCH 0499/2255] bpf: btf: Support flags for BTF_SET8 sets This commit adds support for flags on BTF_SET8s. struct btf_id_set8 already supported 32 bits worth of flags, but was only used for alignment purposes before. We now use these bits to encode flags. The first use case is tagging kfunc sets with a flag so that pahole can recognize which BTF_ID_FLAGS(func, ..) are actual kfuncs. Signed-off-by: Daniel Xu Link: https://lore.kernel.org/r/7bb152ec76d6c2c930daec88e995bf18484a5ebb.1706491398.git.dxu@dxuuu.xyz Signed-off-by: Alexei Starovoitov --- include/linux/btf_ids.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/linux/btf_ids.h b/include/linux/btf_ids.h index a9cb10b0e2e9..dca09b7f21dc 100644 --- a/include/linux/btf_ids.h +++ b/include/linux/btf_ids.h @@ -21,6 +21,7 @@ struct btf_id_set8 { #include /* for __PASTE */ #include /* for __maybe_unused */ +#include /* * Following macros help to define lists of BTF IDs placed @@ -183,17 +184,18 @@ extern struct btf_id_set name; * .word (1 << 3) | (1 << 1) | (1 << 2) * */ -#define __BTF_SET8_START(name, scope) \ +#define __BTF_SET8_START(name, scope, flags) \ +__BTF_ID_LIST(name, local) \ asm( \ ".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \ "." #scope " __BTF_ID__set8__" #name "; \n" \ "__BTF_ID__set8__" #name ":; \n" \ -".zero 8 \n" \ +".zero 4 \n" \ +".long " __stringify(flags) "\n" \ ".popsection; \n"); #define BTF_SET8_START(name) \ -__BTF_ID_LIST(name, local) \ -__BTF_SET8_START(name, local) +__BTF_SET8_START(name, local, 0) #define BTF_SET8_END(name) \ asm( \ From e7f8df0e81bf73ab6dc6ac1dc01273fa06564119 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 30 Jan 2024 16:58:14 +0100 Subject: [PATCH 0500/2255] dpll: move xa_erase() call in to match dpll_pin_alloc() error path order This is cosmetics. Move the call of xa_erase() in dpll_pin_put() so the order of cleanup calls matches the error path of dpll_pin_alloc(). Signed-off-by: Jiri Pirko Reviewed-by: Vadim Fedorenko Link: https://lore.kernel.org/r/20240130155814.268622-1-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- drivers/dpll/dpll_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 5152bd1b0daf..61e5c607a72f 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -560,9 +560,9 @@ void dpll_pin_put(struct dpll_pin *pin) { mutex_lock(&dpll_lock); if (refcount_dec_and_test(&pin->refcount)) { + xa_erase(&dpll_pin_xa, pin->id); xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); - xa_erase(&dpll_pin_xa, pin->id); dpll_pin_prop_free(&pin->prop); kfree(pin); } From 96b93f08357c4cc858ec7543464f07e461e5713a Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sun, 28 Jan 2024 10:18:49 +0000 Subject: [PATCH 0501/2255] ptp: lan743x: Use spin_lock instead of spin_lock_bh lan743x_ptp_request_tx_timestamp uses spin_lock_bh, but it is only called from lan743x_tx_xmit_frame where all IRQs are already disabled. This fixes the "IRQs not enabled as expected" warning. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20240128101849.107298-1-tanure@linux.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan743x_ptp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c index 2f04bc77a118..2801f08bf1c9 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.c +++ b/drivers/net/ethernet/microchip/lan743x_ptp.c @@ -1712,13 +1712,13 @@ bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter) struct lan743x_ptp *ptp = &adapter->ptp; bool result = false; - spin_lock_bh(&ptp->tx_ts_lock); + spin_lock(&ptp->tx_ts_lock); if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { /* request granted */ ptp->pending_tx_timestamps++; result = true; } - spin_unlock_bh(&ptp->tx_ts_lock); + spin_unlock(&ptp->tx_ts_lock); return result; } From 61c81872815f46006982bb80460c0c80a949b35b Mon Sep 17 00:00:00 2001 From: Andre Werner Date: Mon, 29 Jan 2024 14:55:04 +0100 Subject: [PATCH 0502/2255] net: phy: phy_device: Prevent nullptr exceptions on ISR If phydev->irq is set unconditionally, check for valid interrupt handler or fall back to polling mode to prevent nullptr exceptions in interrupt service routine. Signed-off-by: Andre Werner Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240129135734.18975-2-andre.werner@systec-electronic.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy_device.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index dd778c7fde1d..52828d1c64f7 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1413,6 +1413,11 @@ int phy_sfp_probe(struct phy_device *phydev, } EXPORT_SYMBOL(phy_sfp_probe); +static bool phy_drv_supports_irq(struct phy_driver *phydrv) +{ + return phydrv->config_intr && phydrv->handle_interrupt; +} + /** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach @@ -1527,6 +1532,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, if (phydev->dev_flags & PHY_F_NO_IRQ) phydev->irq = PHY_POLL; + if (!phy_drv_supports_irq(phydev->drv) && phy_interrupt_is_valid(phydev)) + phydev->irq = PHY_POLL; + /* Port is set to PORT_TP by default and the actual PHY driver will set * it to different value depending on the PHY configuration. If we have * the generic PHY driver we can't figure it out, thus set the old @@ -2992,11 +3000,6 @@ s32 phy_get_internal_delay(struct phy_device *phydev, struct device *dev, } EXPORT_SYMBOL(phy_get_internal_delay); -static bool phy_drv_supports_irq(struct phy_driver *phydrv) -{ - return phydrv->config_intr && phydrv->handle_interrupt; -} - static int phy_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness value) { From 08b47dfdd6b8db8d1f68748ad7a35ff0aa7040f3 Mon Sep 17 00:00:00 2001 From: Andre Werner Date: Mon, 29 Jan 2024 14:55:05 +0100 Subject: [PATCH 0503/2255] net: phy: adin1100: Add interrupt support for link change An interrupt handler was added to the driver as well as functions to enable interrupts at the phy. There are several interrupts maskable at the phy, but only link change interrupts are handled by the driver yet. Signed-off-by: Andre Werner Link: https://lore.kernel.org/r/20240129135734.18975-3-andre.werner@systec-electronic.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/adin1100.c | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c index 7619d6185801..85f910e2d4fb 100644 --- a/drivers/net/phy/adin1100.c +++ b/drivers/net/phy/adin1100.c @@ -18,6 +18,12 @@ #define PHY_ID_ADIN1110 0x0283bc91 #define PHY_ID_ADIN2111 0x0283bca1 +#define ADIN_PHY_SUBSYS_IRQ_MASK 0x0021 +#define ADIN_LINK_STAT_CHNG_IRQ_EN BIT(1) + +#define ADIN_PHY_SUBSYS_IRQ_STATUS 0x0011 +#define ADIN_LINK_STAT_CHNG BIT(1) + #define ADIN_FORCED_MODE 0x8000 #define ADIN_FORCED_MODE_EN BIT(0) @@ -136,6 +142,53 @@ static int adin_config_aneg(struct phy_device *phydev) return genphy_c45_config_aneg(phydev); } +static int adin_phy_ack_intr(struct phy_device *phydev) +{ + /* Clear pending interrupts */ + int rc = phy_read_mmd(phydev, MDIO_MMD_VEND2, + ADIN_PHY_SUBSYS_IRQ_STATUS); + + return rc < 0 ? rc : 0; +} + +static int adin_config_intr(struct phy_device *phydev) +{ + u16 irq_mask; + int ret; + + ret = adin_phy_ack_intr(phydev); + if (ret) + return ret; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + irq_mask = ADIN_LINK_STAT_CHNG_IRQ_EN; + else + irq_mask = 0; + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, + ADIN_PHY_SUBSYS_IRQ_MASK, + ADIN_LINK_STAT_CHNG_IRQ_EN, irq_mask); +} + +static irqreturn_t adin_phy_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND2, + ADIN_PHY_SUBSYS_IRQ_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & ADIN_LINK_STAT_CHNG)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int adin_set_powerdown_mode(struct phy_device *phydev, bool en) { int ret; @@ -275,6 +328,8 @@ static struct phy_driver adin_driver[] = { .probe = adin_probe, .config_aneg = adin_config_aneg, .read_status = adin_read_status, + .config_intr = adin_config_intr, + .handle_interrupt = adin_phy_handle_interrupt, .set_loopback = adin_set_loopback, .suspend = adin_suspend, .resume = adin_resume, From 9e56ff53b4115875667760445b028357848b4748 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 Jan 2024 15:15:19 +0100 Subject: [PATCH 0504/2255] net: phy: move at803x PHY driver to dedicated directory In preparation for addition of other Qcom PHY and to tidy things up, move the at803x PHY driver to dedicated directory. The same order in the Kconfig selection is saved. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240129141600.2592-2-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 7 +------ drivers/net/phy/Makefile | 2 +- drivers/net/phy/qcom/Kconfig | 7 +++++++ drivers/net/phy/qcom/Makefile | 2 ++ drivers/net/phy/{ => qcom}/at803x.c | 0 5 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 drivers/net/phy/qcom/Kconfig create mode 100644 drivers/net/phy/qcom/Makefile rename drivers/net/phy/{ => qcom}/at803x.c (100%) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 9e2672800f0b..e261e58bf158 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -335,12 +335,7 @@ config NCN26000_PHY Currently supports the NCN26000 10BASE-T1S Industrial PHY with MII interface. -config AT803X_PHY - tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" - depends on REGULATOR - help - Currently supports the AR8030, AR8031, AR8033, AR8035 and internal - QCA8337(Internal qca8k PHY) model +source "drivers/net/phy/qcom/Kconfig" config QSEMI_PHY tristate "Quality Semiconductor PHYs" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 6097afd44392..197acfa0b412 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ -obj-$(CONFIG_AT803X_PHY) += at803x.o ifdef CONFIG_AX88796B_RUST_PHY obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o else @@ -91,6 +90,7 @@ endif obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja.o obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o +obj-y += qcom/ obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_RENESAS_PHY) += uPD60620.o diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig new file mode 100644 index 000000000000..2c274fbbe410 --- /dev/null +++ b/drivers/net/phy/qcom/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +config AT803X_PHY + tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" + depends on REGULATOR + help + Currently supports the AR8030, AR8031, AR8033, AR8035 and internal + QCA8337(Internal qca8k PHY) model diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile new file mode 100644 index 000000000000..6a68da8aaa7b --- /dev/null +++ b/drivers/net/phy/qcom/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_AT803X_PHY) += at803x.o diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/qcom/at803x.c similarity index 100% rename from drivers/net/phy/at803x.c rename to drivers/net/phy/qcom/at803x.c From 6fb760972c49490b03f3db2ad64cf30bdd28c54a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 Jan 2024 15:15:20 +0100 Subject: [PATCH 0505/2255] net: phy: qcom: create and move functions to shared library Create and move functions to shared library in preparation for qca83xx PHY Family to be detached from at803x driver. Only the shared defines are moved to the shared qcom.h header. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240129141600.2592-3-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/qcom/Kconfig | 4 ++ drivers/net/phy/qcom/Makefile | 1 + drivers/net/phy/qcom/at803x.c | 69 +---------------------------- drivers/net/phy/qcom/qcom-phy-lib.c | 53 ++++++++++++++++++++++ drivers/net/phy/qcom/qcom.h | 34 ++++++++++++++ 5 files changed, 94 insertions(+), 67 deletions(-) create mode 100644 drivers/net/phy/qcom/qcom-phy-lib.c create mode 100644 drivers/net/phy/qcom/qcom.h diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig index 2c274fbbe410..fe47cc7c94d2 100644 --- a/drivers/net/phy/qcom/Kconfig +++ b/drivers/net/phy/qcom/Kconfig @@ -1,6 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only +config QCOM_NET_PHYLIB + tristate + config AT803X_PHY tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" + select QCOM_NET_PHYLIB depends on REGULATOR help Currently supports the AR8030, AR8031, AR8033, AR8035 and internal diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile index 6a68da8aaa7b..bfba2ed7db27 100644 --- a/drivers/net/phy/qcom/Makefile +++ b/drivers/net/phy/qcom/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o obj-$(CONFIG_AT803X_PHY) += at803x.o diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 9c07a6cc6e67..8194618c0865 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -22,6 +22,8 @@ #include #include +#include "qcom.h" + #define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 #define AT803X_SFC_ASSERT_CRS BIT(11) #define AT803X_SFC_FORCE_LINK BIT(10) @@ -84,9 +86,6 @@ #define AT803X_REG_CHIP_CONFIG 0x1f #define AT803X_BT_BX_REG_SEL 0x8000 -#define AT803X_DEBUG_ADDR 0x1D -#define AT803X_DEBUG_DATA 0x1E - #define AT803X_MODE_CFG_MASK 0x0F #define AT803X_MODE_CFG_BASET_RGMII 0x00 #define AT803X_MODE_CFG_BASET_SGMII 0x01 @@ -103,19 +102,6 @@ #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 -#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 -#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) -#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) -#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) - -#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 -#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) - -#define AT803X_DEBUG_REG_HIB_CTRL 0x0b -#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) -#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) -#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) - #define AT803X_DEBUG_REG_3C 0x3C #define AT803X_DEBUG_REG_GREEN 0x3D @@ -393,18 +379,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); -enum stat_access_type { - PHY, - MMD -}; - -struct at803x_hw_stat { - const char *string; - u8 reg; - u32 mask; - enum stat_access_type access_type; -}; - static struct at803x_hw_stat qca83xx_hw_stats[] = { { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, @@ -439,45 +413,6 @@ struct at803x_context { u16 led_control; }; -static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) -{ - int ret; - - ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); - if (ret < 0) - return ret; - - return phy_write(phydev, AT803X_DEBUG_DATA, data); -} - -static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) -{ - int ret; - - ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); - if (ret < 0) - return ret; - - return phy_read(phydev, AT803X_DEBUG_DATA); -} - -static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, - u16 clear, u16 set) -{ - u16 val; - int ret; - - ret = at803x_debug_reg_read(phydev, reg); - if (ret < 0) - return ret; - - val = ret & 0xffff; - val &= ~clear; - val |= set; - - return phy_write(phydev, AT803X_DEBUG_DATA, val); -} - static int at803x_write_page(struct phy_device *phydev, int page) { int mask; diff --git a/drivers/net/phy/qcom/qcom-phy-lib.c b/drivers/net/phy/qcom/qcom-phy-lib.c new file mode 100644 index 000000000000..7192184429b7 --- /dev/null +++ b/drivers/net/phy/qcom/qcom-phy-lib.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include "qcom.h" + +MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL"); + +int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) +{ + int ret; + + ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); + if (ret < 0) + return ret; + + return phy_read(phydev, AT803X_DEBUG_DATA); +} +EXPORT_SYMBOL_GPL(at803x_debug_reg_read); + +int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, + u16 clear, u16 set) +{ + u16 val; + int ret; + + ret = at803x_debug_reg_read(phydev, reg); + if (ret < 0) + return ret; + + val = ret & 0xffff; + val &= ~clear; + val |= set; + + return phy_write(phydev, AT803X_DEBUG_DATA, val); +} +EXPORT_SYMBOL_GPL(at803x_debug_reg_mask); + +int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) +{ + int ret; + + ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); + if (ret < 0) + return ret; + + return phy_write(phydev, AT803X_DEBUG_DATA, data); +} +EXPORT_SYMBOL_GPL(at803x_debug_reg_write); diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h new file mode 100644 index 000000000000..8eb476d7c282 --- /dev/null +++ b/drivers/net/phy/qcom/qcom.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#define AT803X_DEBUG_ADDR 0x1D +#define AT803X_DEBUG_DATA 0x1E + +#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 +#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) +#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) +#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) + +#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 +#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) + +#define AT803X_DEBUG_REG_HIB_CTRL 0x0b +#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) +#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) +#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) + +enum stat_access_type { + PHY, + MMD +}; + +struct at803x_hw_stat { + const char *string; + u8 reg; + u32 mask; + enum stat_access_type access_type; +}; + +int at803x_debug_reg_read(struct phy_device *phydev, u16 reg); +int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, + u16 clear, u16 set); +int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data); From 2e45d404d99d43bb7127b74b5dea8818df64996c Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 Jan 2024 15:15:21 +0100 Subject: [PATCH 0506/2255] net: phy: qcom: deatch qca83xx PHY driver from at803x Deatch qca83xx PHY driver from at803x. The QCA83xx PHYs implement specific function and doesn't use generic at803x so it can be detached from the driver and moved to a dedicated one. Probe function and priv struct is reimplemented to allocate and use only the qca83xx specific data. Unused data from at803x PHY driver are dropped from at803x priv struct. This is to make slimmer PHY drivers instead of including lots of bloat that would never be used in specific SoC. A new Kconfig flag QCA83XX_PHY is introduced to compile the new introduced PHY driver. As the Kconfig name starts with Qualcomm the same order is kept. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240129141600.2592-4-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/qcom/Kconfig | 11 +- drivers/net/phy/qcom/Makefile | 1 + drivers/net/phy/qcom/at803x.c | 235 ---------------------------- drivers/net/phy/qcom/qca83xx.c | 275 +++++++++++++++++++++++++++++++++ 4 files changed, 284 insertions(+), 238 deletions(-) create mode 100644 drivers/net/phy/qcom/qca83xx.c diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig index fe47cc7c94d2..ba78bbe31857 100644 --- a/drivers/net/phy/qcom/Kconfig +++ b/drivers/net/phy/qcom/Kconfig @@ -3,9 +3,14 @@ config QCOM_NET_PHYLIB tristate config AT803X_PHY - tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" + tristate "Qualcomm Atheros AR803X PHYs" select QCOM_NET_PHYLIB depends on REGULATOR help - Currently supports the AR8030, AR8031, AR8033, AR8035 and internal - QCA8337(Internal qca8k PHY) model + Currently supports the AR8030, AR8031, AR8033, AR8035 model + +config QCA83XX_PHY + tristate "Qualcomm Atheros QCA833x PHYs" + select QCOM_NET_PHYLIB + help + Currently supports the internal QCA8337(Internal qca8k PHY) model diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile index bfba2ed7db27..3d98e397e063 100644 --- a/drivers/net/phy/qcom/Makefile +++ b/drivers/net/phy/qcom/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o obj-$(CONFIG_AT803X_PHY) += at803x.o +obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 8194618c0865..638babc50df1 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -102,17 +102,10 @@ #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 -#define AT803X_DEBUG_REG_3C 0x3C - -#define AT803X_DEBUG_REG_GREEN 0x3D -#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) - #define AT803X_DEBUG_REG_1F 0x1F #define AT803X_DEBUG_PLL_ON BIT(2) #define AT803X_DEBUG_RGMII_1V8 BIT(3) -#define MDIO_AZ_DEBUG 0x800D - /* AT803x supports either the XTAL input pad, an internal PLL or the * DSP as clock reference for the clock output pad. The XTAL reference * is only used for 25 MHz output, all other frequencies need the PLL. @@ -163,13 +156,7 @@ #define QCA8081_PHY_ID 0x004dd101 -#define QCA8327_A_PHY_ID 0x004dd033 -#define QCA8327_B_PHY_ID 0x004dd034 -#define QCA8337_PHY_ID 0x004dd036 #define QCA9561_PHY_ID 0x004dd042 -#define QCA8K_PHY_ID_MASK 0xffffffff - -#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0) #define AT803X_PAGE_FIBER 0 #define AT803X_PAGE_COPPER 1 @@ -379,12 +366,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); -static struct at803x_hw_stat qca83xx_hw_stats[] = { - { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, - { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, - { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD}, -}; - struct at803x_ss_mask { u16 speed_mask; u8 speed_shift; @@ -400,7 +381,6 @@ struct at803x_priv { bool is_1000basex; struct regulator_dev *vddio_rdev; struct regulator_dev *vddh_rdev; - u64 stats[ARRAY_SIZE(qca83xx_hw_stats)]; int led_polarity_mode; }; @@ -564,53 +544,6 @@ static void at803x_get_wol(struct phy_device *phydev, wol->wolopts |= WAKE_MAGIC; } -static int qca83xx_get_sset_count(struct phy_device *phydev) -{ - return ARRAY_SIZE(qca83xx_hw_stats); -} - -static void qca83xx_get_strings(struct phy_device *phydev, u8 *data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) { - strscpy(data + i * ETH_GSTRING_LEN, - qca83xx_hw_stats[i].string, ETH_GSTRING_LEN); - } -} - -static u64 qca83xx_get_stat(struct phy_device *phydev, int i) -{ - struct at803x_hw_stat stat = qca83xx_hw_stats[i]; - struct at803x_priv *priv = phydev->priv; - int val; - u64 ret; - - if (stat.access_type == MMD) - val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg); - else - val = phy_read(phydev, stat.reg); - - if (val < 0) { - ret = U64_MAX; - } else { - val = val & stat.mask; - priv->stats[i] += val; - ret = priv->stats[i]; - } - - return ret; -} - -static void qca83xx_get_stats(struct phy_device *phydev, - struct ethtool_stats *stats, u64 *data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) - data[i] = qca83xx_get_stat(phydev, i); -} - static int at803x_suspend(struct phy_device *phydev) { int value; @@ -1707,124 +1640,6 @@ static int at8035_probe(struct phy_device *phydev) return at8035_parse_dt(phydev); } -static int qca83xx_config_init(struct phy_device *phydev) -{ - u8 switch_revision; - - switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK; - - switch (switch_revision) { - case 1: - /* For 100M waveform */ - at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); - /* Turn on Gigabit clock */ - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); - break; - - case 2: - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); - fallthrough; - case 4: - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); - at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); - break; - } - - /* Following original QCA sourcecode set port to prefer master */ - phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); - - return 0; -} - -static int qca8327_config_init(struct phy_device *phydev) -{ - /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. - * Disable on init and enable only with 100m speed following - * qca original source code. - */ - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - - return qca83xx_config_init(phydev); -} - -static void qca83xx_link_change_notify(struct phy_device *phydev) -{ - /* Set DAC Amplitude adjustment to +6% for 100m on link running */ - if (phydev->state == PHY_RUNNING) { - if (phydev->speed == SPEED_100) - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, - QCA8327_DEBUG_MANU_CTRL_EN); - } else { - /* Reset DAC Amplitude adjustment */ - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - } -} - -static int qca83xx_resume(struct phy_device *phydev) -{ - int ret, val; - - /* Skip reset if not suspended */ - if (!phydev->suspended) - return 0; - - /* Reinit the port, reset values set by suspend */ - qca83xx_config_init(phydev); - - /* Reset the port on port resume */ - phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); - - /* On resume from suspend the switch execute a reset and - * restart auto-negotiation. Wait for reset to complete. - */ - ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), - 50000, 600000, true); - if (ret) - return ret; - - usleep_range(1000, 2000); - - return 0; -} - -static int qca83xx_suspend(struct phy_device *phydev) -{ - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, - AT803X_DEBUG_GATE_CLK_IN1000, 0); - - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, - AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | - AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); - - return 0; -} - -static int qca8337_suspend(struct phy_device *phydev) -{ - /* Only QCA8337 support actual suspend. */ - genphy_suspend(phydev); - - return qca83xx_suspend(phydev); -} - -static int qca8327_suspend(struct phy_device *phydev) -{ - u16 mask = 0; - - /* QCA8327 cause port unreliability when phy suspend - * is set. - */ - mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); - phy_modify(phydev, MII_BMCR, mask, 0); - - return qca83xx_suspend(phydev); -} - static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) { int ret; @@ -2598,53 +2413,6 @@ static struct phy_driver at803x_driver[] = { .read_status = at803x_read_status, .soft_reset = genphy_soft_reset, .config_aneg = at803x_config_aneg, -}, { - /* QCA8337 */ - .phy_id = QCA8337_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8337 internal PHY", - /* PHY_GBIT_FEATURES */ - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = qca83xx_get_sset_count, - .get_strings = qca83xx_get_strings, - .get_stats = qca83xx_get_stats, - .suspend = qca8337_suspend, - .resume = qca83xx_resume, -}, { - /* QCA8327-A from switch QCA8327-AL1A */ - .phy_id = QCA8327_A_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-A internal PHY", - /* PHY_GBIT_FEATURES */ - .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca8327_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = qca83xx_get_sset_count, - .get_strings = qca83xx_get_strings, - .get_stats = qca83xx_get_stats, - .suspend = qca8327_suspend, - .resume = qca83xx_resume, -}, { - /* QCA8327-B from switch QCA8327-BL1A */ - .phy_id = QCA8327_B_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-B internal PHY", - /* PHY_GBIT_FEATURES */ - .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca8327_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = qca83xx_get_sset_count, - .get_strings = qca83xx_get_strings, - .get_stats = qca83xx_get_stats, - .suspend = qca8327_suspend, - .resume = qca83xx_resume, }, { /* Qualcomm QCA8081 */ PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), @@ -2683,9 +2451,6 @@ static struct mdio_device_id __maybe_unused atheros_tbl[] = { { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) }, { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, { } diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c new file mode 100644 index 000000000000..5d083ef0250e --- /dev/null +++ b/drivers/net/phy/qcom/qca83xx.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include + +#include "qcom.h" + +#define AT803X_DEBUG_REG_3C 0x3C + +#define AT803X_DEBUG_REG_GREEN 0x3D +#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) + +#define MDIO_AZ_DEBUG 0x800D + +#define QCA8327_A_PHY_ID 0x004dd033 +#define QCA8327_B_PHY_ID 0x004dd034 +#define QCA8337_PHY_ID 0x004dd036 +#define QCA8K_PHY_ID_MASK 0xffffffff + +#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0) + +static struct at803x_hw_stat qca83xx_hw_stats[] = { + { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, + { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, + { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD}, +}; + +struct qca83xx_priv { + u64 stats[ARRAY_SIZE(qca83xx_hw_stats)]; +}; + +MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL"); + +static int qca83xx_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(qca83xx_hw_stats); +} + +static void qca83xx_get_strings(struct phy_device *phydev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) { + strscpy(data + i * ETH_GSTRING_LEN, + qca83xx_hw_stats[i].string, ETH_GSTRING_LEN); + } +} + +static u64 qca83xx_get_stat(struct phy_device *phydev, int i) +{ + struct at803x_hw_stat stat = qca83xx_hw_stats[i]; + struct qca83xx_priv *priv = phydev->priv; + int val; + u64 ret; + + if (stat.access_type == MMD) + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg); + else + val = phy_read(phydev, stat.reg); + + if (val < 0) { + ret = U64_MAX; + } else { + val = val & stat.mask; + priv->stats[i] += val; + ret = priv->stats[i]; + } + + return ret; +} + +static void qca83xx_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) + data[i] = qca83xx_get_stat(phydev, i); +} + +static int qca83xx_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct qca83xx_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return 0; +} + +static int qca83xx_config_init(struct phy_device *phydev) +{ + u8 switch_revision; + + switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK; + + switch (switch_revision) { + case 1: + /* For 100M waveform */ + at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); + /* Turn on Gigabit clock */ + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); + break; + + case 2: + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); + fallthrough; + case 4: + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); + at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); + break; + } + + /* Following original QCA sourcecode set port to prefer master */ + phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); + + return 0; +} + +static int qca8327_config_init(struct phy_device *phydev) +{ + /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. + * Disable on init and enable only with 100m speed following + * qca original source code. + */ + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + + return qca83xx_config_init(phydev); +} + +static void qca83xx_link_change_notify(struct phy_device *phydev) +{ + /* Set DAC Amplitude adjustment to +6% for 100m on link running */ + if (phydev->state == PHY_RUNNING) { + if (phydev->speed == SPEED_100) + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, + QCA8327_DEBUG_MANU_CTRL_EN); + } else { + /* Reset DAC Amplitude adjustment */ + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + } +} + +static int qca83xx_resume(struct phy_device *phydev) +{ + int ret, val; + + /* Skip reset if not suspended */ + if (!phydev->suspended) + return 0; + + /* Reinit the port, reset values set by suspend */ + qca83xx_config_init(phydev); + + /* Reset the port on port resume */ + phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); + + /* On resume from suspend the switch execute a reset and + * restart auto-negotiation. Wait for reset to complete. + */ + ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), + 50000, 600000, true); + if (ret) + return ret; + + usleep_range(1000, 2000); + + return 0; +} + +static int qca83xx_suspend(struct phy_device *phydev) +{ + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, + AT803X_DEBUG_GATE_CLK_IN1000, 0); + + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, + AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | + AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); + + return 0; +} + +static int qca8337_suspend(struct phy_device *phydev) +{ + /* Only QCA8337 support actual suspend. */ + genphy_suspend(phydev); + + return qca83xx_suspend(phydev); +} + +static int qca8327_suspend(struct phy_device *phydev) +{ + u16 mask = 0; + + /* QCA8327 cause port unreliability when phy suspend + * is set. + */ + mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); + phy_modify(phydev, MII_BMCR, mask, 0); + + return qca83xx_suspend(phydev); +} + +static struct phy_driver qca83xx_driver[] = { +{ + /* QCA8337 */ + .phy_id = QCA8337_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8337 internal PHY", + /* PHY_GBIT_FEATURES */ + .probe = qca83xx_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = qca83xx_get_sset_count, + .get_strings = qca83xx_get_strings, + .get_stats = qca83xx_get_stats, + .suspend = qca8337_suspend, + .resume = qca83xx_resume, +}, { + /* QCA8327-A from switch QCA8327-AL1A */ + .phy_id = QCA8327_A_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-A internal PHY", + /* PHY_GBIT_FEATURES */ + .link_change_notify = qca83xx_link_change_notify, + .probe = qca83xx_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca8327_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = qca83xx_get_sset_count, + .get_strings = qca83xx_get_strings, + .get_stats = qca83xx_get_stats, + .suspend = qca8327_suspend, + .resume = qca83xx_resume, +}, { + /* QCA8327-B from switch QCA8327-BL1A */ + .phy_id = QCA8327_B_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-B internal PHY", + /* PHY_GBIT_FEATURES */ + .link_change_notify = qca83xx_link_change_notify, + .probe = qca83xx_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca8327_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = qca83xx_get_sset_count, + .get_strings = qca83xx_get_strings, + .get_stats = qca83xx_get_stats, + .suspend = qca8327_suspend, + .resume = qca83xx_resume, +}, }; + +module_phy_driver(qca83xx_driver); + +static struct mdio_device_id __maybe_unused qca83xx_tbl[] = { + { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, qca83xx_tbl); From 249d2b80e4db0e38503ed0ec2af6c7401bc099b9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 Jan 2024 15:15:22 +0100 Subject: [PATCH 0507/2255] net: phy: qcom: move additional functions to shared library Move additional functions to shared library in preparation for qca808x PHY Family to be detached from at803x driver. Only the shared defines are moved to the shared qcom.h header. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240129141600.2592-5-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/qcom/at803x.c | 426 +--------------------------- drivers/net/phy/qcom/qcom-phy-lib.c | 376 ++++++++++++++++++++++++ drivers/net/phy/qcom/qcom.h | 86 ++++++ 3 files changed, 463 insertions(+), 425 deletions(-) diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 638babc50df1..6a753498b994 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -24,65 +24,11 @@ #include "qcom.h" -#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 -#define AT803X_SFC_ASSERT_CRS BIT(11) -#define AT803X_SFC_FORCE_LINK BIT(10) -#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5) -#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3 -#define AT803X_SFC_MANUAL_MDIX 0x1 -#define AT803X_SFC_MANUAL_MDI 0x0 -#define AT803X_SFC_SQE_TEST BIT(2) -#define AT803X_SFC_POLARITY_REVERSAL BIT(1) -#define AT803X_SFC_DISABLE_JABBER BIT(0) - -#define AT803X_SPECIFIC_STATUS 0x11 -#define AT803X_SS_SPEED_MASK GENMASK(15, 14) -#define AT803X_SS_SPEED_1000 2 -#define AT803X_SS_SPEED_100 1 -#define AT803X_SS_SPEED_10 0 -#define AT803X_SS_DUPLEX BIT(13) -#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) -#define AT803X_SS_MDIX BIT(6) - -#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) -#define QCA808X_SS_SPEED_2500 4 - -#define AT803X_INTR_ENABLE 0x12 -#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) -#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) -#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) -#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) -#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) -#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) -#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) -#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) -#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) -#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) -#define AT803X_INTR_ENABLE_WOL BIT(0) - -#define AT803X_INTR_STATUS 0x13 - -#define AT803X_SMART_SPEED 0x14 -#define AT803X_SMART_SPEED_ENABLE BIT(5) -#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) -#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) -#define AT803X_CDT 0x16 -#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) -#define AT803X_CDT_ENABLE_TEST BIT(0) -#define AT803X_CDT_STATUS 0x1c -#define AT803X_CDT_STATUS_STAT_NORMAL 0 -#define AT803X_CDT_STATUS_STAT_SHORT 1 -#define AT803X_CDT_STATUS_STAT_OPEN 2 -#define AT803X_CDT_STATUS_STAT_FAIL 3 -#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) -#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) #define AT803X_LED_CONTROL 0x18 #define AT803X_PHY_MMD3_WOL_CTRL 0x8012 #define AT803X_WOL_EN BIT(5) -#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C -#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B -#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A + #define AT803X_REG_CHIP_CONFIG 0x1f #define AT803X_BT_BX_REG_SEL 0x8000 @@ -138,10 +84,6 @@ #define AT803X_CLK_OUT_STRENGTH_HALF 1 #define AT803X_CLK_OUT_STRENGTH_QUARTER 2 -#define AT803X_DEFAULT_DOWNSHIFT 5 -#define AT803X_MIN_DOWNSHIFT 2 -#define AT803X_MAX_DOWNSHIFT 9 - #define AT803X_MMD3_SMARTEEE_CTL1 0x805b #define AT803X_MMD3_SMARTEEE_CTL2 0x805c #define AT803X_MMD3_SMARTEEE_CTL3 0x805d @@ -366,11 +308,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); -struct at803x_ss_mask { - u16 speed_mask; - u8 speed_shift; -}; - struct at803x_priv { int flags; u16 clk_25m_reg; @@ -470,80 +407,6 @@ static void at803x_context_restore(struct phy_device *phydev, phy_write(phydev, AT803X_LED_CONTROL, context->led_control); } -static int at803x_set_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int ret, irq_enabled; - - if (wol->wolopts & WAKE_MAGIC) { - struct net_device *ndev = phydev->attached_dev; - const u8 *mac; - unsigned int i; - static const unsigned int offsets[] = { - AT803X_LOC_MAC_ADDR_32_47_OFFSET, - AT803X_LOC_MAC_ADDR_16_31_OFFSET, - AT803X_LOC_MAC_ADDR_0_15_OFFSET, - }; - - if (!ndev) - return -ENODEV; - - mac = (const u8 *)ndev->dev_addr; - - if (!is_valid_ether_addr(mac)) - return -EINVAL; - - for (i = 0; i < 3; i++) - phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], - mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); - - /* Enable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); - if (ret) - return ret; - } else { - /* Disable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); - if (ret) - return ret; - } - - /* Clear WOL status */ - ret = phy_read(phydev, AT803X_INTR_STATUS); - if (ret < 0) - return ret; - - /* Check if there are other interrupts except for WOL triggered when PHY is - * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can - * be passed up to the interrupt PIN. - */ - irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (irq_enabled < 0) - return irq_enabled; - - irq_enabled &= ~AT803X_INTR_ENABLE_WOL; - if (ret & irq_enabled && !phy_polling_mode(phydev)) - phy_trigger_machine(phydev); - - return 0; -} - -static void at803x_get_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int value; - - wol->supported = WAKE_MAGIC; - wol->wolopts = 0; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - if (value < 0) - return; - - if (value & AT803X_INTR_ENABLE_WOL) - wol->wolopts |= WAKE_MAGIC; -} - static int at803x_suspend(struct phy_device *phydev) { int value; @@ -816,73 +679,6 @@ static int at803x_config_init(struct phy_device *phydev) return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); } -static int at803x_ack_interrupt(struct phy_device *phydev) -{ - int err; - - err = phy_read(phydev, AT803X_INTR_STATUS); - - return (err < 0) ? err : 0; -} - -static int at803x_config_intr(struct phy_device *phydev) -{ - int err; - int value; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - if (err) - return err; - - value |= AT803X_INTR_ENABLE_AUTONEG_ERR; - value |= AT803X_INTR_ENABLE_SPEED_CHANGED; - value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; - value |= AT803X_INTR_ENABLE_LINK_FAIL; - value |= AT803X_INTR_ENABLE_LINK_SUCCESS; - - err = phy_write(phydev, AT803X_INTR_ENABLE, value); - } else { - err = phy_write(phydev, AT803X_INTR_ENABLE, 0); - if (err) - return err; - - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - } - - return err; -} - -static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) -{ - int irq_status, int_enabled; - - irq_status = phy_read(phydev, AT803X_INTR_STATUS); - if (irq_status < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* Read the current enabled interrupts */ - int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (int_enabled < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* See if this was one of our enabled interrupts */ - if (!(irq_status & int_enabled)) - return IRQ_NONE; - - phy_trigger_machine(phydev); - - return IRQ_HANDLED; -} - static void at803x_link_change_notify(struct phy_device *phydev) { /* @@ -908,69 +704,6 @@ static void at803x_link_change_notify(struct phy_device *phydev) } } -static int at803x_read_specific_status(struct phy_device *phydev, - struct at803x_ss_mask ss_mask) -{ - int ss; - - /* Read the AT8035 PHY-Specific Status register, which indicates the - * speed and duplex that the PHY is actually using, irrespective of - * whether we are in autoneg mode or not. - */ - ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); - if (ss < 0) - return ss; - - if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { - int sfc, speed; - - sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); - if (sfc < 0) - return sfc; - - speed = ss & ss_mask.speed_mask; - speed >>= ss_mask.speed_shift; - - switch (speed) { - case AT803X_SS_SPEED_10: - phydev->speed = SPEED_10; - break; - case AT803X_SS_SPEED_100: - phydev->speed = SPEED_100; - break; - case AT803X_SS_SPEED_1000: - phydev->speed = SPEED_1000; - break; - case QCA808X_SS_SPEED_2500: - phydev->speed = SPEED_2500; - break; - } - if (ss & AT803X_SS_DUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; - - if (ss & AT803X_SS_MDIX) - phydev->mdix = ETH_TP_MDI_X; - else - phydev->mdix = ETH_TP_MDI; - - switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) { - case AT803X_SFC_MANUAL_MDI: - phydev->mdix_ctrl = ETH_TP_MDI; - break; - case AT803X_SFC_MANUAL_MDIX: - phydev->mdix_ctrl = ETH_TP_MDI_X; - break; - case AT803X_SFC_AUTOMATIC_CROSSOVER: - phydev->mdix_ctrl = ETH_TP_MDI_AUTO; - break; - } - } - - return 0; -} - static int at803x_read_status(struct phy_device *phydev) { struct at803x_ss_mask ss_mask = { 0 }; @@ -1006,50 +739,6 @@ static int at803x_read_status(struct phy_device *phydev) return 0; } -static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) -{ - u16 val; - - switch (ctrl) { - case ETH_TP_MDI: - val = AT803X_SFC_MANUAL_MDI; - break; - case ETH_TP_MDI_X: - val = AT803X_SFC_MANUAL_MDIX; - break; - case ETH_TP_MDI_AUTO: - val = AT803X_SFC_AUTOMATIC_CROSSOVER; - break; - default: - return 0; - } - - return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL, - AT803X_SFC_MDI_CROSSOVER_MODE_M, - FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val)); -} - -static int at803x_prepare_config_aneg(struct phy_device *phydev) -{ - int ret; - - ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); - if (ret < 0) - return ret; - - /* Changes of the midx bits are disruptive to the normal operation; - * therefore any changes to these registers must be followed by a - * software reset to take effect. - */ - if (ret == 1) { - ret = genphy_soft_reset(phydev); - if (ret < 0) - return ret; - } - - return 0; -} - static int at803x_config_aneg(struct phy_device *phydev) { struct at803x_priv *priv = phydev->priv; @@ -1065,80 +754,6 @@ static int at803x_config_aneg(struct phy_device *phydev) return genphy_config_aneg(phydev); } -static int at803x_get_downshift(struct phy_device *phydev, u8 *d) -{ - int val; - - val = phy_read(phydev, AT803X_SMART_SPEED); - if (val < 0) - return val; - - if (val & AT803X_SMART_SPEED_ENABLE) - *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; - else - *d = DOWNSHIFT_DEV_DISABLE; - - return 0; -} - -static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) -{ - u16 mask, set; - int ret; - - switch (cnt) { - case DOWNSHIFT_DEV_DEFAULT_COUNT: - cnt = AT803X_DEFAULT_DOWNSHIFT; - fallthrough; - case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: - set = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER | - FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); - mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; - break; - case DOWNSHIFT_DEV_DISABLE: - set = 0; - mask = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER; - break; - default: - return -EINVAL; - } - - ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); - - /* After changing the smart speed settings, we need to perform a - * software reset, use phy_init_hw() to make sure we set the - * reapply any values which might got lost during software reset. - */ - if (ret == 1) - ret = phy_init_hw(phydev); - - return ret; -} - -static int at803x_get_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_get_downshift(phydev, data); - default: - return -EOPNOTSUPP; - } -} - -static int at803x_set_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, const void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_set_downshift(phydev, *(const u8 *)data); - default: - return -EOPNOTSUPP; - } -} - static int at803x_cable_test_result_trans(u16 status) { switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { @@ -1170,45 +785,6 @@ static bool at803x_cdt_fault_length_valid(u16 status) return false; } -static int at803x_cdt_fault_length(int dt) -{ - /* According to the datasheet the distance to the fault is - * DELTA_TIME * 0.824 meters. - * - * The author suspect the correct formula is: - * - * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 - * - * where c is the speed of light, VF is the velocity factor of - * the twisted pair cable, 125MHz the counter frequency and - * we need to divide by 2 because the hardware will measure the - * round trip time to the fault and back to the PHY. - * - * With a VF of 0.69 we get the factor 0.824 mentioned in the - * datasheet. - */ - return (dt * 824) / 10; -} - -static int at803x_cdt_start(struct phy_device *phydev, - u32 cdt_start) -{ - return phy_write(phydev, AT803X_CDT, cdt_start); -} - -static int at803x_cdt_wait_for_completion(struct phy_device *phydev, - u32 cdt_en) -{ - int val, ret; - - /* One test run takes about 25ms */ - ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, - !(val & cdt_en), - 30000, 100000, true); - - return ret < 0 ? ret : 0; -} - static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) { static const int ethtool_pair[] = { diff --git a/drivers/net/phy/qcom/qcom-phy-lib.c b/drivers/net/phy/qcom/qcom-phy-lib.c index 7192184429b7..e0295d4b4a51 100644 --- a/drivers/net/phy/qcom/qcom-phy-lib.c +++ b/drivers/net/phy/qcom/qcom-phy-lib.c @@ -3,6 +3,9 @@ #include #include +#include +#include + #include "qcom.h" MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions"); @@ -51,3 +54,376 @@ int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) return phy_write(phydev, AT803X_DEBUG_DATA, data); } EXPORT_SYMBOL_GPL(at803x_debug_reg_write); + +int at803x_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int ret, irq_enabled; + + if (wol->wolopts & WAKE_MAGIC) { + struct net_device *ndev = phydev->attached_dev; + const u8 *mac; + unsigned int i; + static const unsigned int offsets[] = { + AT803X_LOC_MAC_ADDR_32_47_OFFSET, + AT803X_LOC_MAC_ADDR_16_31_OFFSET, + AT803X_LOC_MAC_ADDR_0_15_OFFSET, + }; + + if (!ndev) + return -ENODEV; + + mac = (const u8 *)ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return -EINVAL; + + for (i = 0; i < 3; i++) + phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], + mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); + + /* Enable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); + if (ret) + return ret; + } else { + /* Disable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); + if (ret) + return ret; + } + + /* Clear WOL status */ + ret = phy_read(phydev, AT803X_INTR_STATUS); + if (ret < 0) + return ret; + + /* Check if there are other interrupts except for WOL triggered when PHY is + * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can + * be passed up to the interrupt PIN. + */ + irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (irq_enabled < 0) + return irq_enabled; + + irq_enabled &= ~AT803X_INTR_ENABLE_WOL; + if (ret & irq_enabled && !phy_polling_mode(phydev)) + phy_trigger_machine(phydev); + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_set_wol); + +void at803x_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int value; + + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + if (value < 0) + return; + + if (value & AT803X_INTR_ENABLE_WOL) + wol->wolopts |= WAKE_MAGIC; +} +EXPORT_SYMBOL_GPL(at803x_get_wol); + +int at803x_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, AT803X_INTR_STATUS); + + return (err < 0) ? err : 0; +} +EXPORT_SYMBOL_GPL(at803x_ack_interrupt); + +int at803x_config_intr(struct phy_device *phydev) +{ + int err; + int value; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + if (err) + return err; + + value |= AT803X_INTR_ENABLE_AUTONEG_ERR; + value |= AT803X_INTR_ENABLE_SPEED_CHANGED; + value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; + value |= AT803X_INTR_ENABLE_LINK_FAIL; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS; + + err = phy_write(phydev, AT803X_INTR_ENABLE, value); + } else { + err = phy_write(phydev, AT803X_INTR_ENABLE, 0); + if (err) + return err; + + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + } + + return err; +} +EXPORT_SYMBOL_GPL(at803x_config_intr); + +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) +{ + int irq_status, int_enabled; + + irq_status = phy_read(phydev, AT803X_INTR_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* Read the current enabled interrupts */ + int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (int_enabled < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* See if this was one of our enabled interrupts */ + if (!(irq_status & int_enabled)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(at803x_handle_interrupt); + +int at803x_read_specific_status(struct phy_device *phydev, + struct at803x_ss_mask ss_mask) +{ + int ss; + + /* Read the AT8035 PHY-Specific Status register, which indicates the + * speed and duplex that the PHY is actually using, irrespective of + * whether we are in autoneg mode or not. + */ + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); + if (ss < 0) + return ss; + + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { + int sfc, speed; + + sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); + if (sfc < 0) + return sfc; + + speed = ss & ss_mask.speed_mask; + speed >>= ss_mask.speed_shift; + + switch (speed) { + case AT803X_SS_SPEED_10: + phydev->speed = SPEED_10; + break; + case AT803X_SS_SPEED_100: + phydev->speed = SPEED_100; + break; + case AT803X_SS_SPEED_1000: + phydev->speed = SPEED_1000; + break; + case QCA808X_SS_SPEED_2500: + phydev->speed = SPEED_2500; + break; + } + if (ss & AT803X_SS_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (ss & AT803X_SS_MDIX) + phydev->mdix = ETH_TP_MDI_X; + else + phydev->mdix = ETH_TP_MDI; + + switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) { + case AT803X_SFC_MANUAL_MDI: + phydev->mdix_ctrl = ETH_TP_MDI; + break; + case AT803X_SFC_MANUAL_MDIX: + phydev->mdix_ctrl = ETH_TP_MDI_X; + break; + case AT803X_SFC_AUTOMATIC_CROSSOVER: + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_read_specific_status); + +int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) +{ + u16 val; + + switch (ctrl) { + case ETH_TP_MDI: + val = AT803X_SFC_MANUAL_MDI; + break; + case ETH_TP_MDI_X: + val = AT803X_SFC_MANUAL_MDIX; + break; + case ETH_TP_MDI_AUTO: + val = AT803X_SFC_AUTOMATIC_CROSSOVER; + break; + default: + return 0; + } + + return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL, + AT803X_SFC_MDI_CROSSOVER_MODE_M, + FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val)); +} +EXPORT_SYMBOL_GPL(at803x_config_mdix); + +int at803x_prepare_config_aneg(struct phy_device *phydev) +{ + int ret; + + ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); + if (ret < 0) + return ret; + + /* Changes of the midx bits are disruptive to the normal operation; + * therefore any changes to these registers must be followed by a + * software reset to take effect. + */ + if (ret == 1) { + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg); + +static int at803x_get_downshift(struct phy_device *phydev, u8 *d) +{ + int val; + + val = phy_read(phydev, AT803X_SMART_SPEED); + if (val < 0) + return val; + + if (val & AT803X_SMART_SPEED_ENABLE) + *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; + else + *d = DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) +{ + u16 mask, set; + int ret; + + switch (cnt) { + case DOWNSHIFT_DEV_DEFAULT_COUNT: + cnt = AT803X_DEFAULT_DOWNSHIFT; + fallthrough; + case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: + set = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER | + FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); + mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; + break; + case DOWNSHIFT_DEV_DISABLE: + set = 0; + mask = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER; + break; + default: + return -EINVAL; + } + + ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); + + /* After changing the smart speed settings, we need to perform a + * software reset, use phy_init_hw() to make sure we set the + * reapply any values which might got lost during software reset. + */ + if (ret == 1) + ret = phy_init_hw(phydev); + + return ret; +} + +int at803x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(at803x_get_tunable); + +int at803x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(at803x_set_tunable); + +int at803x_cdt_fault_length(int dt) +{ + /* According to the datasheet the distance to the fault is + * DELTA_TIME * 0.824 meters. + * + * The author suspect the correct formula is: + * + * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 + * + * where c is the speed of light, VF is the velocity factor of + * the twisted pair cable, 125MHz the counter frequency and + * we need to divide by 2 because the hardware will measure the + * round trip time to the fault and back to the PHY. + * + * With a VF of 0.69 we get the factor 0.824 mentioned in the + * datasheet. + */ + return (dt * 824) / 10; +} +EXPORT_SYMBOL_GPL(at803x_cdt_fault_length); + +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start) +{ + return phy_write(phydev, AT803X_CDT, cdt_start); +} +EXPORT_SYMBOL_GPL(at803x_cdt_start); + +int at803x_cdt_wait_for_completion(struct phy_device *phydev, + u32 cdt_en) +{ + int val, ret; + + /* One test run takes about 25ms */ + ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, + !(val & cdt_en), + 30000, 100000, true); + + return ret < 0 ? ret : 0; +} +EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion); diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h index 8eb476d7c282..c127d8f50f0f 100644 --- a/drivers/net/phy/qcom/qcom.h +++ b/drivers/net/phy/qcom/qcom.h @@ -1,5 +1,63 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 +#define AT803X_SFC_ASSERT_CRS BIT(11) +#define AT803X_SFC_FORCE_LINK BIT(10) +#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5) +#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3 +#define AT803X_SFC_MANUAL_MDIX 0x1 +#define AT803X_SFC_MANUAL_MDI 0x0 +#define AT803X_SFC_SQE_TEST BIT(2) +#define AT803X_SFC_POLARITY_REVERSAL BIT(1) +#define AT803X_SFC_DISABLE_JABBER BIT(0) + +#define AT803X_SPECIFIC_STATUS 0x11 +#define AT803X_SS_SPEED_MASK GENMASK(15, 14) +#define AT803X_SS_SPEED_1000 2 +#define AT803X_SS_SPEED_100 1 +#define AT803X_SS_SPEED_10 0 +#define AT803X_SS_DUPLEX BIT(13) +#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) +#define AT803X_SS_MDIX BIT(6) + +#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) +#define QCA808X_SS_SPEED_2500 4 + +#define AT803X_INTR_ENABLE 0x12 +#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) +#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) +#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) +#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) +#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) +#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) +#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) +#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) +#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) +#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) +#define AT803X_INTR_ENABLE_WOL BIT(0) + +#define AT803X_INTR_STATUS 0x13 + +#define AT803X_SMART_SPEED 0x14 +#define AT803X_SMART_SPEED_ENABLE BIT(5) +#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) +#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) + +#define AT803X_CDT 0x16 +#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) +#define AT803X_CDT_ENABLE_TEST BIT(0) +#define AT803X_CDT_STATUS 0x1c +#define AT803X_CDT_STATUS_STAT_NORMAL 0 +#define AT803X_CDT_STATUS_STAT_SHORT 1 +#define AT803X_CDT_STATUS_STAT_OPEN 2 +#define AT803X_CDT_STATUS_STAT_FAIL 3 +#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) +#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) + +#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C +#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B +#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A + #define AT803X_DEBUG_ADDR 0x1D #define AT803X_DEBUG_DATA 0x1E @@ -16,6 +74,10 @@ #define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) #define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) +#define AT803X_DEFAULT_DOWNSHIFT 5 +#define AT803X_MIN_DOWNSHIFT 2 +#define AT803X_MAX_DOWNSHIFT 9 + enum stat_access_type { PHY, MMD @@ -28,7 +90,31 @@ struct at803x_hw_stat { enum stat_access_type access_type; }; +struct at803x_ss_mask { + u16 speed_mask; + u8 speed_shift; +}; + int at803x_debug_reg_read(struct phy_device *phydev, u16 reg); int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, u16 clear, u16 set); int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data); +int at803x_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol); +void at803x_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol); +int at803x_ack_interrupt(struct phy_device *phydev); +int at803x_config_intr(struct phy_device *phydev); +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev); +int at803x_read_specific_status(struct phy_device *phydev, + struct at803x_ss_mask ss_mask); +int at803x_config_mdix(struct phy_device *phydev, u8 ctrl); +int at803x_prepare_config_aneg(struct phy_device *phydev); +int at803x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data); +int at803x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data); +int at803x_cdt_fault_length(int dt); +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start); +int at803x_cdt_wait_for_completion(struct phy_device *phydev, + u32 cdt_en); From c89414adf2ec7cd9e7080c419aa5847f1db1009c Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 Jan 2024 15:15:23 +0100 Subject: [PATCH 0508/2255] net: phy: qcom: detach qca808x PHY driver from at803x Almost all the QCA8081 PHY driver OPs are specific and only some of them use the generic at803x. To make the at803x code slimmer, move all the specific qca808x regs and functions to a dedicated PHY driver. Probe function and priv struct is reworked to allocate and use only the qca808x specific data. Unused data from at803x PHY driver are dropped from at803x priv struct. Also a new Kconfig is introduced QCA808X_PHY, to compile the newly introduced PHY driver for QCA8081 PHY. As the Kconfig name starts with Qualcomm the same order is kept. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240129141600.2592-6-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/qcom/Kconfig | 6 + drivers/net/phy/qcom/Makefile | 1 + drivers/net/phy/qcom/at803x.c | 897 +------------------------------ drivers/net/phy/qcom/qca808x.c | 934 +++++++++++++++++++++++++++++++++ 4 files changed, 942 insertions(+), 896 deletions(-) create mode 100644 drivers/net/phy/qcom/qca808x.c diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig index ba78bbe31857..80db24deb689 100644 --- a/drivers/net/phy/qcom/Kconfig +++ b/drivers/net/phy/qcom/Kconfig @@ -14,3 +14,9 @@ config QCA83XX_PHY select QCOM_NET_PHYLIB help Currently supports the internal QCA8337(Internal qca8k PHY) model + +config QCA808X_PHY + tristate "Qualcomm QCA808x PHYs" + select QCOM_NET_PHYLIB + help + Currently supports the QCA8081 model diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile index 3d98e397e063..0362d7ed47be 100644 --- a/drivers/net/phy/qcom/Makefile +++ b/drivers/net/phy/qcom/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o obj-$(CONFIG_AT803X_PHY) += at803x.o obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o +obj-$(CONFIG_QCA808X_PHY) += qca808x.o diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 6a753498b994..36b70e88394e 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -96,8 +96,6 @@ #define ATH8035_PHY_ID 0x004dd072 #define AT8030_PHY_ID_MASK 0xffffffef -#define QCA8081_PHY_ID 0x004dd101 - #define QCA9561_PHY_ID 0x004dd042 #define AT803X_PAGE_FIBER 0 @@ -110,201 +108,7 @@ /* disable hibernation mode */ #define AT803X_DISABLE_HIBERNATION_MODE BIT(2) -/* ADC threshold */ -#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80 -#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0) -#define QCA808X_ADC_THRESHOLD_80MV 0 -#define QCA808X_ADC_THRESHOLD_100MV 0xf0 -#define QCA808X_ADC_THRESHOLD_200MV 0x0f -#define QCA808X_ADC_THRESHOLD_300MV 0xff - -/* CLD control */ -#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007 -#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4) -#define QCA808X_8023AZ_AFE_EN 0x90 - -/* AZ control */ -#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008 -#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014 -#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E -#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E -#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020 -#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341 - -#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c -#define QCA808X_TOP_OPTION1_DATA 0x0 - -#define QCA808X_PHY_MMD3_DEBUG_1 0xa100 -#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203 -#define QCA808X_PHY_MMD3_DEBUG_2 0xa101 -#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad -#define QCA808X_PHY_MMD3_DEBUG_3 0xa103 -#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698 -#define QCA808X_PHY_MMD3_DEBUG_4 0xa105 -#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001 -#define QCA808X_PHY_MMD3_DEBUG_5 0xa106 -#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111 -#define QCA808X_PHY_MMD3_DEBUG_6 0xa011 -#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85 - -/* master/slave seed config */ -#define QCA808X_PHY_DEBUG_LOCAL_SEED 9 -#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1) -#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2) -#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32 - -/* Hibernation yields lower power consumpiton in contrast with normal operation mode. - * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s. - */ -#define QCA808X_DBG_AN_TEST 0xb -#define QCA808X_HIBERNATION_EN BIT(15) - -#define QCA808X_CDT_ENABLE_TEST BIT(15) -#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) -#define QCA808X_CDT_STATUS BIT(11) -#define QCA808X_CDT_LENGTH_UNIT BIT(10) - -#define QCA808X_MMD3_CDT_STATUS 0x8064 -#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 -#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 -#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 -#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 -#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) -#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) - -#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) -#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) -#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) -#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) - -#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) -#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) -#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) -#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) -#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) - -#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) -#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) -#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) -#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) - -/* NORMAL are MDI with type set to 0 */ -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI1) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI1) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI2) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI2) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI3) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI3) - -/* Added for reference of existence but should be handled by wait_for_completion already */ -#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) - -#define QCA808X_MMD7_LED_GLOBAL 0x8073 -#define QCA808X_LED_BLINK_1 GENMASK(11, 6) -#define QCA808X_LED_BLINK_2 GENMASK(5, 0) -/* Values are the same for both BLINK_1 and BLINK_2 */ -#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) -#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) -#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) -#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) -#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) -#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) -#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) -#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) -#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) -#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) -#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) -#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) -#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) -#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) -#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) -#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) -#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) -#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) - -#define QCA808X_MMD7_LED2_CTRL 0x8074 -#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075 -#define QCA808X_MMD7_LED1_CTRL 0x8076 -#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077 -#define QCA808X_MMD7_LED0_CTRL 0x8078 -#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2)) - -/* LED hw control pattern is the same for every LED */ -#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) -#define QCA808X_LED_SPEED2500_ON BIT(15) -#define QCA808X_LED_SPEED2500_BLINK BIT(14) -/* Follow blink trigger even if duplex or speed condition doesn't match */ -#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) -#define QCA808X_LED_FULL_DUPLEX_ON BIT(12) -#define QCA808X_LED_HALF_DUPLEX_ON BIT(11) -#define QCA808X_LED_TX_BLINK BIT(10) -#define QCA808X_LED_RX_BLINK BIT(9) -#define QCA808X_LED_TX_ON_10MS BIT(8) -#define QCA808X_LED_RX_ON_10MS BIT(7) -#define QCA808X_LED_SPEED1000_ON BIT(6) -#define QCA808X_LED_SPEED100_ON BIT(5) -#define QCA808X_LED_SPEED10_ON BIT(4) -#define QCA808X_LED_COLLISION_BLINK BIT(3) -#define QCA808X_LED_SPEED1000_BLINK BIT(2) -#define QCA808X_LED_SPEED100_BLINK BIT(1) -#define QCA808X_LED_SPEED10_BLINK BIT(0) - -#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079 -#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2)) - -/* LED force ctrl is the same for every LED - * No documentation exist for this, not even internal one - * with NDA as QCOM gives only info about configuring - * hw control pattern rules and doesn't indicate any way - * to force the LED to specific mode. - * These define comes from reverse and testing and maybe - * lack of some info or some info are not entirely correct. - * For the basic LED control and hw control these finding - * are enough to support LED control in all the required APIs. - * - * On doing some comparison with implementation with qca807x, - * it was found that it's 1:1 equal to it and confirms all the - * reverse done. It was also found further specification with the - * force mode and the blink modes. - */ -#define QCA808X_LED_FORCE_EN BIT(15) -#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) -#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) -#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) -#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) -#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) - -#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a -/* QSDK sets by default 0x46 to this reg that sets BIT 6 for - * LED to active high. It's not clear what BIT 3 and BIT 4 does. - */ -#define QCA808X_LED_ACTIVE_HIGH BIT(6) - -/* QCA808X 1G chip type */ -#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d -#define QCA808X_PHY_CHIP_TYPE_1G BIT(0) - -#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072 -#define QCA8081_PHY_FIFO_RSTN BIT(11) - -MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); +MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); @@ -318,7 +122,6 @@ struct at803x_priv { bool is_1000basex; struct regulator_dev *vddio_rdev; struct regulator_dev *vddh_rdev; - int led_polarity_mode; }; struct at803x_context { @@ -519,9 +322,6 @@ static int at803x_probe(struct phy_device *phydev) if (!priv) return -ENOMEM; - /* Init LED polarity mode to -1 */ - priv->led_polarity_mode = -1; - phydev->priv = priv; ret = at803x_parse_dt(phydev); @@ -1216,672 +1016,6 @@ static int at8035_probe(struct phy_device *phydev) return at8035_parse_dt(phydev); } -static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) -{ - int ret; - - /* Enable fast retrain */ - ret = genphy_c45_fast_retrain(phydev, true); - if (ret) - return ret; - - phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1, - QCA808X_TOP_OPTION1_DATA); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB, - QCA808X_MSE_THRESHOLD_20DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB, - QCA808X_MSE_THRESHOLD_17DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB, - QCA808X_MSE_THRESHOLD_27DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB, - QCA808X_MSE_THRESHOLD_28DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1, - QCA808X_MMD3_DEBUG_1_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4, - QCA808X_MMD3_DEBUG_4_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5, - QCA808X_MMD3_DEBUG_5_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3, - QCA808X_MMD3_DEBUG_3_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6, - QCA808X_MMD3_DEBUG_6_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2, - QCA808X_MMD3_DEBUG_2_VALUE); - - return 0; -} - -static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) -{ - u16 seed_value; - - if (!enable) - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_ENABLE, 0); - - seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE, - FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) | - QCA808X_MASTER_SLAVE_SEED_ENABLE); -} - -static bool qca808x_is_prefer_master(struct phy_device *phydev) -{ - return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) || - (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); -} - -static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) -{ - return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); -} - -static int qca808x_config_init(struct phy_device *phydev) -{ - int ret; - - /* Active adc&vga on 802.3az for the link 1000M and 100M */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, - QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); - if (ret) - return ret; - - /* Adjust the threshold on 802.3az for the link 1000M */ - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, - QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, - QCA808X_MMD3_AZ_TRAINING_VAL); - if (ret) - return ret; - - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { - /* Config the fast retrain for the link 2500M */ - ret = qca808x_phy_fast_retrain_config(phydev); - if (ret) - return ret; - - ret = genphy_read_master_slave(phydev); - if (ret < 0) - return ret; - - if (!qca808x_is_prefer_master(phydev)) { - /* Enable seed and configure lower ramdom seed to make phy - * linked as slave mode. - */ - ret = qca808x_phy_ms_seed_enable(phydev, true); - if (ret) - return ret; - } - } - - /* Configure adc threshold as 100mv for the link 10M */ - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, - QCA808X_ADC_THRESHOLD_MASK, - QCA808X_ADC_THRESHOLD_100MV); -} - -static int qca808x_read_status(struct phy_device *phydev) -{ - struct at803x_ss_mask ss_mask = { 0 }; - int ret; - - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); - if (ret < 0) - return ret; - - linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising, - ret & MDIO_AN_10GBT_STAT_LP2_5G); - - ret = genphy_read_status(phydev); - if (ret) - return ret; - - /* qca8081 takes the different bits for speed value from at803x */ - ss_mask.speed_mask = QCA808X_SS_SPEED_MASK; - ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK); - ret = at803x_read_specific_status(phydev, ss_mask); - if (ret < 0) - return ret; - - if (phydev->link) { - if (phydev->speed == SPEED_2500) - phydev->interface = PHY_INTERFACE_MODE_2500BASEX; - else - phydev->interface = PHY_INTERFACE_MODE_SGMII; - } else { - /* generate seed as a lower random value to make PHY linked as SLAVE easily, - * except for master/slave configuration fault detected or the master mode - * preferred. - * - * the reason for not putting this code into the function link_change_notify is - * the corner case where the link partner is also the qca8081 PHY and the seed - * value is configured as the same value, the link can't be up and no link change - * occurs. - */ - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { - if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || - qca808x_is_prefer_master(phydev)) { - qca808x_phy_ms_seed_enable(phydev, false); - } else { - qca808x_phy_ms_seed_enable(phydev, true); - } - } - } - - return 0; -} - -static int qca808x_soft_reset(struct phy_device *phydev) -{ - int ret; - - ret = genphy_soft_reset(phydev); - if (ret < 0) - return ret; - - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) - ret = qca808x_phy_ms_seed_enable(phydev, true); - - return ret; -} - -static bool qca808x_cdt_fault_length_valid(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: - return true; - default: - return false; - } -} - -static int qca808x_cable_test_result_trans(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_NORMAL: - return ETHTOOL_A_CABLE_RESULT_CODE_OK; - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: - return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; - case QCA808X_CDT_STATUS_STAT_FAIL: - default: - return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; - } -} - -static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, - int result) -{ - int val; - u32 cdt_length_reg = 0; - - switch (pair) { - case ETHTOOL_A_CABLE_PAIR_A: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; - break; - case ETHTOOL_A_CABLE_PAIR_B: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; - break; - case ETHTOOL_A_CABLE_PAIR_C: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; - break; - case ETHTOOL_A_CABLE_PAIR_D: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; - break; - default: - return -EINVAL; - } - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); - if (val < 0) - return val; - - if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); - else - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); - - return at803x_cdt_fault_length(val); -} - -static int qca808x_cable_test_start(struct phy_device *phydev) -{ - int ret; - - /* perform CDT with the following configs: - * 1. disable hibernation. - * 2. force PHY working in MDI mode. - * 3. for PHY working in 1000BaseT. - * 4. configure the threshold. - */ - - ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0); - if (ret < 0) - return ret; - - ret = at803x_config_mdix(phydev, ETH_TP_MDI); - if (ret < 0) - return ret; - - /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */ - phydev->duplex = DUPLEX_FULL; - phydev->speed = SPEED_1000; - ret = genphy_c45_pma_setup_forced(phydev); - if (ret < 0) - return ret; - - ret = genphy_setup_forced(phydev); - if (ret < 0) - return ret; - - /* configure the thresholds for open, short, pair ok test */ - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060); - - return 0; -} - -static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, - u16 status) -{ - int length, result; - u16 pair_code; - - switch (pair) { - case ETHTOOL_A_CABLE_PAIR_A: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); - break; - case ETHTOOL_A_CABLE_PAIR_B: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); - break; - case ETHTOOL_A_CABLE_PAIR_C: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); - break; - case ETHTOOL_A_CABLE_PAIR_D: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); - break; - default: - return -EINVAL; - } - - result = qca808x_cable_test_result_trans(pair_code); - ethnl_cable_test_result(phydev, pair, result); - - if (qca808x_cdt_fault_length_valid(pair_code)) { - length = qca808x_cdt_fault_length(phydev, pair, result); - ethnl_cable_test_fault_length(phydev, pair, length); - } - - return 0; -} - -static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) -{ - int ret, val; - - *finished = false; - - val = QCA808X_CDT_ENABLE_TEST | - QCA808X_CDT_LENGTH_UNIT; - ret = at803x_cdt_start(phydev, val); - if (ret) - return ret; - - ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); - if (ret) - return ret; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); - if (val < 0) - return val; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); - if (ret) - return ret; - - *finished = true; - - return 0; -} - -static int qca808x_get_features(struct phy_device *phydev) -{ - int ret; - - ret = genphy_c45_pma_read_abilities(phydev); - if (ret) - return ret; - - /* The autoneg ability is not existed in bit3 of MMD7.1, - * but it is supported by qca808x PHY, so we add it here - * manually. - */ - linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); - - /* As for the qca8081 1G version chip, the 2500baseT ability is also - * existed in the bit0 of MMD1.21, we need to remove it manually if - * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. - */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); - if (ret < 0) - return ret; - - if (QCA808X_PHY_CHIP_TYPE_1G & ret) - linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); - - return 0; -} - -static int qca808x_config_aneg(struct phy_device *phydev) -{ - int phy_ctrl = 0; - int ret; - - ret = at803x_prepare_config_aneg(phydev); - if (ret) - return ret; - - /* The reg MII_BMCR also needs to be configured for force mode, the - * genphy_config_aneg is also needed. - */ - if (phydev->autoneg == AUTONEG_DISABLE) - genphy_c45_pma_setup_forced(phydev); - - if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) - phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G; - - ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); - if (ret < 0) - return ret; - - return __genphy_config_aneg(phydev, ret); -} - -static void qca808x_link_change_notify(struct phy_device *phydev) -{ - /* Assert interface sgmii fifo on link down, deassert it on link up, - * the interface device address is always phy address added by 1. - */ - mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1, - MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL, - QCA8081_PHY_FIFO_RSTN, - phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); -} - -static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules, - u16 *offload_trigger) -{ - /* Parsing specific to netdev trigger */ - if (test_bit(TRIGGER_NETDEV_TX, &rules)) - *offload_trigger |= QCA808X_LED_TX_BLINK; - if (test_bit(TRIGGER_NETDEV_RX, &rules)) - *offload_trigger |= QCA808X_LED_RX_BLINK; - if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) - *offload_trigger |= QCA808X_LED_SPEED10_ON; - if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) - *offload_trigger |= QCA808X_LED_SPEED100_ON; - if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) - *offload_trigger |= QCA808X_LED_SPEED1000_ON; - if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules)) - *offload_trigger |= QCA808X_LED_SPEED2500_ON; - if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) - *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; - if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) - *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON; - - if (rules && !*offload_trigger) - return -EOPNOTSUPP; - - /* Enable BLINK_CHECK_BYPASS by default to make the LED - * blink even with duplex or speed mode not enabled. - */ - *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS; - - return 0; -} - -static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index) -{ - u16 reg; - - if (index > 2) - return -EINVAL; - - reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_FORCE_EN); -} - -static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index, - unsigned long rules) -{ - u16 offload_trigger = 0; - - if (index > 2) - return -EINVAL; - - return qca808x_led_parse_netdev(phydev, rules, &offload_trigger); -} - -static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index, - unsigned long rules) -{ - u16 reg, offload_trigger = 0; - int ret; - - if (index > 2) - return -EINVAL; - - reg = QCA808X_MMD7_LED_CTRL(index); - - ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger); - if (ret) - return ret; - - ret = qca808x_led_hw_control_enable(phydev, index); - if (ret) - return ret; - - return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_PATTERN_MASK, - offload_trigger); -} - -static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index) -{ - u16 reg; - int val; - - if (index > 2) - return false; - - reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); - - return !(val & QCA808X_LED_FORCE_EN); -} - -static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index, - unsigned long *rules) -{ - u16 reg; - int val; - - if (index > 2) - return -EINVAL; - - /* Check if we have hw control enabled */ - if (qca808x_led_hw_control_status(phydev, index)) - return -EINVAL; - - reg = QCA808X_MMD7_LED_CTRL(index); - - val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); - if (val & QCA808X_LED_TX_BLINK) - set_bit(TRIGGER_NETDEV_TX, rules); - if (val & QCA808X_LED_RX_BLINK) - set_bit(TRIGGER_NETDEV_RX, rules); - if (val & QCA808X_LED_SPEED10_ON) - set_bit(TRIGGER_NETDEV_LINK_10, rules); - if (val & QCA808X_LED_SPEED100_ON) - set_bit(TRIGGER_NETDEV_LINK_100, rules); - if (val & QCA808X_LED_SPEED1000_ON) - set_bit(TRIGGER_NETDEV_LINK_1000, rules); - if (val & QCA808X_LED_SPEED2500_ON) - set_bit(TRIGGER_NETDEV_LINK_2500, rules); - if (val & QCA808X_LED_HALF_DUPLEX_ON) - set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); - if (val & QCA808X_LED_FULL_DUPLEX_ON) - set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); - - return 0; -} - -static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index) -{ - u16 reg; - - if (index > 2) - return -EINVAL; - - reg = QCA808X_MMD7_LED_CTRL(index); - - return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_PATTERN_MASK); -} - -static int qca808x_led_brightness_set(struct phy_device *phydev, - u8 index, enum led_brightness value) -{ - u16 reg; - int ret; - - if (index > 2) - return -EINVAL; - - if (!value) { - ret = qca808x_led_hw_control_reset(phydev, index); - if (ret) - return ret; - } - - reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, - QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON : - QCA808X_LED_FORCE_OFF); -} - -static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, - unsigned long *delay_on, - unsigned long *delay_off) -{ - int ret; - u16 reg; - - if (index > 2) - return -EINVAL; - - reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - /* Set blink to 50% off, 50% on at 4Hz by default */ - ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, - QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, - QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); - if (ret) - return ret; - - /* We use BLINK_1 for normal blinking */ - ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); - if (ret) - return ret; - - /* We set blink to 4Hz, aka 250ms */ - *delay_on = 250 / 2; - *delay_off = 250 / 2; - - return 0; -} - -static int qca808x_led_polarity_set(struct phy_device *phydev, int index, - unsigned long modes) -{ - struct at803x_priv *priv = phydev->priv; - bool active_low = false; - u32 mode; - - for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { - switch (mode) { - case PHY_LED_ACTIVE_LOW: - active_low = true; - break; - default: - return -EINVAL; - } - } - - /* PHY polarity is global and can't be set per LED. - * To detect this, check if last requested polarity mode - * match the new one. - */ - if (priv->led_polarity_mode >= 0 && - priv->led_polarity_mode != active_low) { - phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n"); - return -EINVAL; - } - - /* Save the last PHY polarity mode */ - priv->led_polarity_mode = active_low; - - return phy_modify_mmd(phydev, MDIO_MMD_AN, - QCA808X_MMD7_LED_POLARITY_CTRL, - QCA808X_LED_ACTIVE_HIGH, - active_low ? 0 : QCA808X_LED_ACTIVE_HIGH); -} - static struct phy_driver at803x_driver[] = { { /* Qualcomm Atheros AR8035 */ @@ -1989,34 +1123,6 @@ static struct phy_driver at803x_driver[] = { .read_status = at803x_read_status, .soft_reset = genphy_soft_reset, .config_aneg = at803x_config_aneg, -}, { - /* Qualcomm QCA8081 */ - PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), - .name = "Qualcomm QCA8081", - .flags = PHY_POLL_CABLE_TEST, - .probe = at803x_probe, - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .get_tunable = at803x_get_tunable, - .set_tunable = at803x_set_tunable, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .get_features = qca808x_get_features, - .config_aneg = qca808x_config_aneg, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_status = qca808x_read_status, - .config_init = qca808x_config_init, - .soft_reset = qca808x_soft_reset, - .cable_test_start = qca808x_cable_test_start, - .cable_test_get_status = qca808x_cable_test_get_status, - .link_change_notify = qca808x_link_change_notify, - .led_brightness_set = qca808x_led_brightness_set, - .led_blink_set = qca808x_led_blink_set, - .led_hw_is_supported = qca808x_led_hw_is_supported, - .led_hw_control_set = qca808x_led_hw_control_set, - .led_hw_control_get = qca808x_led_hw_control_get, - .led_polarity_set = qca808x_led_polarity_set, }, }; module_phy_driver(at803x_driver); @@ -2028,7 +1134,6 @@ static struct mdio_device_id __maybe_unused atheros_tbl[] = { { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, { } }; diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c new file mode 100644 index 000000000000..0f549027d899 --- /dev/null +++ b/drivers/net/phy/qcom/qca808x.c @@ -0,0 +1,934 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include + +#include "qcom.h" + +/* ADC threshold */ +#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80 +#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0) +#define QCA808X_ADC_THRESHOLD_80MV 0 +#define QCA808X_ADC_THRESHOLD_100MV 0xf0 +#define QCA808X_ADC_THRESHOLD_200MV 0x0f +#define QCA808X_ADC_THRESHOLD_300MV 0xff + +/* CLD control */ +#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007 +#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4) +#define QCA808X_8023AZ_AFE_EN 0x90 + +/* AZ control */ +#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008 +#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014 +#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E +#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E +#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020 +#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341 + +#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c +#define QCA808X_TOP_OPTION1_DATA 0x0 + +#define QCA808X_PHY_MMD3_DEBUG_1 0xa100 +#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203 +#define QCA808X_PHY_MMD3_DEBUG_2 0xa101 +#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad +#define QCA808X_PHY_MMD3_DEBUG_3 0xa103 +#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698 +#define QCA808X_PHY_MMD3_DEBUG_4 0xa105 +#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001 +#define QCA808X_PHY_MMD3_DEBUG_5 0xa106 +#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111 +#define QCA808X_PHY_MMD3_DEBUG_6 0xa011 +#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85 + +/* master/slave seed config */ +#define QCA808X_PHY_DEBUG_LOCAL_SEED 9 +#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1) +#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2) +#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32 + +/* Hibernation yields lower power consumpiton in contrast with normal operation mode. + * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s. + */ +#define QCA808X_DBG_AN_TEST 0xb +#define QCA808X_HIBERNATION_EN BIT(15) + +#define QCA808X_CDT_ENABLE_TEST BIT(15) +#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) +#define QCA808X_CDT_STATUS BIT(11) +#define QCA808X_CDT_LENGTH_UNIT BIT(10) + +#define QCA808X_MMD3_CDT_STATUS 0x8064 +#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 +#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 +#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 +#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 +#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) +#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) + +#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) +#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) +#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) +#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) + +#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) +#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) +#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) +#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) +#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) + +#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) +#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) +#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) +#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) + +/* NORMAL are MDI with type set to 0 */ +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI3) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI3) + +/* Added for reference of existence but should be handled by wait_for_completion already */ +#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) + +#define QCA808X_MMD7_LED_GLOBAL 0x8073 +#define QCA808X_LED_BLINK_1 GENMASK(11, 6) +#define QCA808X_LED_BLINK_2 GENMASK(5, 0) +/* Values are the same for both BLINK_1 and BLINK_2 */ +#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) +#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) +#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) +#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) +#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) +#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) +#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) +#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) +#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) +#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) +#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) +#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) +#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) +#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) +#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) +#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) +#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) +#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) + +#define QCA808X_MMD7_LED2_CTRL 0x8074 +#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075 +#define QCA808X_MMD7_LED1_CTRL 0x8076 +#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077 +#define QCA808X_MMD7_LED0_CTRL 0x8078 +#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2)) + +/* LED hw control pattern is the same for every LED */ +#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) +#define QCA808X_LED_SPEED2500_ON BIT(15) +#define QCA808X_LED_SPEED2500_BLINK BIT(14) +/* Follow blink trigger even if duplex or speed condition doesn't match */ +#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) +#define QCA808X_LED_FULL_DUPLEX_ON BIT(12) +#define QCA808X_LED_HALF_DUPLEX_ON BIT(11) +#define QCA808X_LED_TX_BLINK BIT(10) +#define QCA808X_LED_RX_BLINK BIT(9) +#define QCA808X_LED_TX_ON_10MS BIT(8) +#define QCA808X_LED_RX_ON_10MS BIT(7) +#define QCA808X_LED_SPEED1000_ON BIT(6) +#define QCA808X_LED_SPEED100_ON BIT(5) +#define QCA808X_LED_SPEED10_ON BIT(4) +#define QCA808X_LED_COLLISION_BLINK BIT(3) +#define QCA808X_LED_SPEED1000_BLINK BIT(2) +#define QCA808X_LED_SPEED100_BLINK BIT(1) +#define QCA808X_LED_SPEED10_BLINK BIT(0) + +#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079 +#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2)) + +/* LED force ctrl is the same for every LED + * No documentation exist for this, not even internal one + * with NDA as QCOM gives only info about configuring + * hw control pattern rules and doesn't indicate any way + * to force the LED to specific mode. + * These define comes from reverse and testing and maybe + * lack of some info or some info are not entirely correct. + * For the basic LED control and hw control these finding + * are enough to support LED control in all the required APIs. + * + * On doing some comparison with implementation with qca807x, + * it was found that it's 1:1 equal to it and confirms all the + * reverse done. It was also found further specification with the + * force mode and the blink modes. + */ +#define QCA808X_LED_FORCE_EN BIT(15) +#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) +#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) +#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) +#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) +#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) + +#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a +/* QSDK sets by default 0x46 to this reg that sets BIT 6 for + * LED to active high. It's not clear what BIT 3 and BIT 4 does. + */ +#define QCA808X_LED_ACTIVE_HIGH BIT(6) + +/* QCA808X 1G chip type */ +#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d +#define QCA808X_PHY_CHIP_TYPE_1G BIT(0) + +#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072 +#define QCA8081_PHY_FIFO_RSTN BIT(11) + +#define QCA8081_PHY_ID 0x004dd101 + +MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_LICENSE("GPL"); + +struct qca808x_priv { + int led_polarity_mode; +}; + +static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) +{ + int ret; + + /* Enable fast retrain */ + ret = genphy_c45_fast_retrain(phydev, true); + if (ret) + return ret; + + phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1, + QCA808X_TOP_OPTION1_DATA); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB, + QCA808X_MSE_THRESHOLD_20DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB, + QCA808X_MSE_THRESHOLD_17DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB, + QCA808X_MSE_THRESHOLD_27DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB, + QCA808X_MSE_THRESHOLD_28DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1, + QCA808X_MMD3_DEBUG_1_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4, + QCA808X_MMD3_DEBUG_4_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5, + QCA808X_MMD3_DEBUG_5_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3, + QCA808X_MMD3_DEBUG_3_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6, + QCA808X_MMD3_DEBUG_6_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2, + QCA808X_MMD3_DEBUG_2_VALUE); + + return 0; +} + +static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) +{ + u16 seed_value; + + if (!enable) + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, + QCA808X_MASTER_SLAVE_SEED_ENABLE, 0); + + seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, + QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE, + FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) | + QCA808X_MASTER_SLAVE_SEED_ENABLE); +} + +static bool qca808x_is_prefer_master(struct phy_device *phydev) +{ + return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) || + (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); +} + +static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) +{ + return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); +} + +static int qca808x_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct qca808x_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Init LED polarity mode to -1 */ + priv->led_polarity_mode = -1; + + phydev->priv = priv; + + return 0; +} + +static int qca808x_config_init(struct phy_device *phydev) +{ + int ret; + + /* Active adc&vga on 802.3az for the link 1000M and 100M */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, + QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); + if (ret) + return ret; + + /* Adjust the threshold on 802.3az for the link 1000M */ + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, + QCA808X_MMD3_AZ_TRAINING_VAL); + if (ret) + return ret; + + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + /* Config the fast retrain for the link 2500M */ + ret = qca808x_phy_fast_retrain_config(phydev); + if (ret) + return ret; + + ret = genphy_read_master_slave(phydev); + if (ret < 0) + return ret; + + if (!qca808x_is_prefer_master(phydev)) { + /* Enable seed and configure lower ramdom seed to make phy + * linked as slave mode. + */ + ret = qca808x_phy_ms_seed_enable(phydev, true); + if (ret) + return ret; + } + } + + /* Configure adc threshold as 100mv for the link 10M */ + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, + QCA808X_ADC_THRESHOLD_MASK, + QCA808X_ADC_THRESHOLD_100MV); +} + +static int qca808x_read_status(struct phy_device *phydev) +{ + struct at803x_ss_mask ss_mask = { 0 }; + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); + if (ret < 0) + return ret; + + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising, + ret & MDIO_AN_10GBT_STAT_LP2_5G); + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + /* qca8081 takes the different bits for speed value from at803x */ + ss_mask.speed_mask = QCA808X_SS_SPEED_MASK; + ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK); + ret = at803x_read_specific_status(phydev, ss_mask); + if (ret < 0) + return ret; + + if (phydev->link) { + if (phydev->speed == SPEED_2500) + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; + else + phydev->interface = PHY_INTERFACE_MODE_SGMII; + } else { + /* generate seed as a lower random value to make PHY linked as SLAVE easily, + * except for master/slave configuration fault detected or the master mode + * preferred. + * + * the reason for not putting this code into the function link_change_notify is + * the corner case where the link partner is also the qca8081 PHY and the seed + * value is configured as the same value, the link can't be up and no link change + * occurs. + */ + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || + qca808x_is_prefer_master(phydev)) { + qca808x_phy_ms_seed_enable(phydev, false); + } else { + qca808x_phy_ms_seed_enable(phydev, true); + } + } + } + + return 0; +} + +static int qca808x_soft_reset(struct phy_device *phydev) +{ + int ret; + + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) + ret = qca808x_phy_ms_seed_enable(phydev, true); + + return ret; +} + +static bool qca808x_cdt_fault_length_valid(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return true; + default: + return false; + } +} + +static int qca808x_cable_test_result_trans(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_NORMAL: + return ETHTOOL_A_CABLE_RESULT_CODE_OK; + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; + case QCA808X_CDT_STATUS_STAT_FAIL: + default: + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } +} + +static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, + int result) +{ + int val; + u32 cdt_length_reg = 0; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; + break; + case ETHTOOL_A_CABLE_PAIR_B: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; + break; + case ETHTOOL_A_CABLE_PAIR_C: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; + break; + case ETHTOOL_A_CABLE_PAIR_D: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; + break; + default: + return -EINVAL; + } + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); + if (val < 0) + return val; + + if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); + else + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); + + return at803x_cdt_fault_length(val); +} + +static int qca808x_cable_test_start(struct phy_device *phydev) +{ + int ret; + + /* perform CDT with the following configs: + * 1. disable hibernation. + * 2. force PHY working in MDI mode. + * 3. for PHY working in 1000BaseT. + * 4. configure the threshold. + */ + + ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0); + if (ret < 0) + return ret; + + ret = at803x_config_mdix(phydev, ETH_TP_MDI); + if (ret < 0) + return ret; + + /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */ + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_1000; + ret = genphy_c45_pma_setup_forced(phydev); + if (ret < 0) + return ret; + + ret = genphy_setup_forced(phydev); + if (ret < 0) + return ret; + + /* configure the thresholds for open, short, pair ok test */ + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060); + + return 0; +} + +static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, + u16 status) +{ + int length, result; + u16 pair_code; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); + break; + case ETHTOOL_A_CABLE_PAIR_B: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); + break; + case ETHTOOL_A_CABLE_PAIR_C: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); + break; + case ETHTOOL_A_CABLE_PAIR_D: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); + break; + default: + return -EINVAL; + } + + result = qca808x_cable_test_result_trans(pair_code); + ethnl_cable_test_result(phydev, pair, result); + + if (qca808x_cdt_fault_length_valid(pair_code)) { + length = qca808x_cdt_fault_length(phydev, pair, result); + ethnl_cable_test_fault_length(phydev, pair, length); + } + + return 0; +} + +static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) +{ + int ret, val; + + *finished = false; + + val = QCA808X_CDT_ENABLE_TEST | + QCA808X_CDT_LENGTH_UNIT; + ret = at803x_cdt_start(phydev, val); + if (ret) + return ret; + + ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); + if (ret) + return ret; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); + if (val < 0) + return val; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); + if (ret) + return ret; + + *finished = true; + + return 0; +} + +static int qca808x_get_features(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_pma_read_abilities(phydev); + if (ret) + return ret; + + /* The autoneg ability is not existed in bit3 of MMD7.1, + * but it is supported by qca808x PHY, so we add it here + * manually. + */ + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + + /* As for the qca8081 1G version chip, the 2500baseT ability is also + * existed in the bit0 of MMD1.21, we need to remove it manually if + * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. + */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); + if (ret < 0) + return ret; + + if (QCA808X_PHY_CHIP_TYPE_1G & ret) + linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); + + return 0; +} + +static int qca808x_config_aneg(struct phy_device *phydev) +{ + int phy_ctrl = 0; + int ret; + + ret = at803x_prepare_config_aneg(phydev); + if (ret) + return ret; + + /* The reg MII_BMCR also needs to be configured for force mode, the + * genphy_config_aneg is also needed. + */ + if (phydev->autoneg == AUTONEG_DISABLE) + genphy_c45_pma_setup_forced(phydev); + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) + phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G; + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); + if (ret < 0) + return ret; + + return __genphy_config_aneg(phydev, ret); +} + +static void qca808x_link_change_notify(struct phy_device *phydev) +{ + /* Assert interface sgmii fifo on link down, deassert it on link up, + * the interface device address is always phy address added by 1. + */ + mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1, + MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL, + QCA8081_PHY_FIFO_RSTN, + phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); +} + +static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules, + u16 *offload_trigger) +{ + /* Parsing specific to netdev trigger */ + if (test_bit(TRIGGER_NETDEV_TX, &rules)) + *offload_trigger |= QCA808X_LED_TX_BLINK; + if (test_bit(TRIGGER_NETDEV_RX, &rules)) + *offload_trigger |= QCA808X_LED_RX_BLINK; + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + *offload_trigger |= QCA808X_LED_SPEED10_ON; + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + *offload_trigger |= QCA808X_LED_SPEED100_ON; + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + *offload_trigger |= QCA808X_LED_SPEED1000_ON; + if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules)) + *offload_trigger |= QCA808X_LED_SPEED2500_ON; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON; + + if (rules && !*offload_trigger) + return -EOPNOTSUPP; + + /* Enable BLINK_CHECK_BYPASS by default to make the LED + * blink even with duplex or speed mode not enabled. + */ + *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS; + + return 0; +} + +static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN); +} + +static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 offload_trigger = 0; + + if (index > 2) + return -EINVAL; + + return qca808x_led_parse_netdev(phydev, rules, &offload_trigger); +} + +static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 reg, offload_trigger = 0; + int ret; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger); + if (ret) + return ret; + + ret = qca808x_led_hw_control_enable(phydev, index); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_PATTERN_MASK, + offload_trigger); +} + +static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index) +{ + u16 reg; + int val; + + if (index > 2) + return false; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + + return !(val & QCA808X_LED_FORCE_EN); +} + +static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + u16 reg; + int val; + + if (index > 2) + return -EINVAL; + + /* Check if we have hw control enabled */ + if (qca808x_led_hw_control_status(phydev, index)) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + if (val & QCA808X_LED_TX_BLINK) + set_bit(TRIGGER_NETDEV_TX, rules); + if (val & QCA808X_LED_RX_BLINK) + set_bit(TRIGGER_NETDEV_RX, rules); + if (val & QCA808X_LED_SPEED10_ON) + set_bit(TRIGGER_NETDEV_LINK_10, rules); + if (val & QCA808X_LED_SPEED100_ON) + set_bit(TRIGGER_NETDEV_LINK_100, rules); + if (val & QCA808X_LED_SPEED1000_ON) + set_bit(TRIGGER_NETDEV_LINK_1000, rules); + if (val & QCA808X_LED_SPEED2500_ON) + set_bit(TRIGGER_NETDEV_LINK_2500, rules); + if (val & QCA808X_LED_HALF_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); + if (val & QCA808X_LED_FULL_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); + + return 0; +} + +static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_PATTERN_MASK); +} + +static int qca808x_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + u16 reg; + int ret; + + if (index > 2) + return -EINVAL; + + if (!value) { + ret = qca808x_led_hw_control_reset(phydev, index); + if (ret) + return ret; + } + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON : + QCA808X_LED_FORCE_OFF); +} + +static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) +{ + int ret; + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + /* Set blink to 50% off, 50% on at 4Hz by default */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, + QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, + QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); + if (ret) + return ret; + + /* We use BLINK_1 for normal blinking */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); + if (ret) + return ret; + + /* We set blink to 4Hz, aka 250ms */ + *delay_on = 250 / 2; + *delay_off = 250 / 2; + + return 0; +} + +static int qca808x_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + struct qca808x_priv *priv = phydev->priv; + bool active_low = false; + u32 mode; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + active_low = true; + break; + default: + return -EINVAL; + } + } + + /* PHY polarity is global and can't be set per LED. + * To detect this, check if last requested polarity mode + * match the new one. + */ + if (priv->led_polarity_mode >= 0 && + priv->led_polarity_mode != active_low) { + phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n"); + return -EINVAL; + } + + /* Save the last PHY polarity mode */ + priv->led_polarity_mode = active_low; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, + QCA808X_MMD7_LED_POLARITY_CTRL, + QCA808X_LED_ACTIVE_HIGH, + active_low ? 0 : QCA808X_LED_ACTIVE_HIGH); +} + +static struct phy_driver qca808x_driver[] = { +{ + /* Qualcomm QCA8081 */ + PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), + .name = "Qualcomm QCA8081", + .flags = PHY_POLL_CABLE_TEST, + .probe = qca808x_probe, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .get_features = qca808x_get_features, + .config_aneg = qca808x_config_aneg, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_status = qca808x_read_status, + .config_init = qca808x_config_init, + .soft_reset = qca808x_soft_reset, + .cable_test_start = qca808x_cable_test_start, + .cable_test_get_status = qca808x_cable_test_get_status, + .link_change_notify = qca808x_link_change_notify, + .led_brightness_set = qca808x_led_brightness_set, + .led_blink_set = qca808x_led_blink_set, + .led_hw_is_supported = qca808x_led_hw_is_supported, + .led_hw_control_set = qca808x_led_hw_control_set, + .led_hw_control_get = qca808x_led_hw_control_get, + .led_polarity_set = qca808x_led_polarity_set, +}, }; + +module_phy_driver(qca808x_driver); + +static struct mdio_device_id __maybe_unused qca808x_tbl[] = { + { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, qca808x_tbl); From 57f2c6350f2d8d835def0a613a3d37c28d146102 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 30 Jan 2024 17:22:55 +0800 Subject: [PATCH 0509/2255] net: ipv4: Simplify the allocation of slab caches in inet_initpeers commit 0a31bd5f2bbb ("KMEM_CACHE(): simplify slab cache creation") introduces a new macro. Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240130092255.73078-1-chentao@kylinos.cn Signed-off-by: Jakub Kicinski --- net/ipv4/inetpeer.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index e9fed83e9b3c..5bd759963451 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -81,10 +81,7 @@ void __init inet_initpeers(void) inet_peer_threshold = clamp_val(nr_entries, 4096, 65536 + 128); - peer_cachep = kmem_cache_create("inet_peer_cache", - sizeof(struct inet_peer), - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, - NULL); + peer_cachep = KMEM_CACHE(inet_peer, SLAB_HWCACHE_ALIGN | SLAB_PANIC); } /* Called with rcu_read_lock() or base->lock held */ From 2dc23b6f852bc7816d7ab421979d95223e894be3 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 30 Jan 2024 17:25:36 +0800 Subject: [PATCH 0510/2255] net: bridge: Use KMEM_CACHE instead of kmem_cache_create commit 0a31bd5f2bbb ("KMEM_CACHE(): simplify slab cache creation") introduces a new macro. Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Acked-by: Nikolay Aleksandrov Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240130092536.73623-1-chentao@kylinos.cn Signed-off-by: Jakub Kicinski --- net/bridge/br_fdb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index c622de5eccd0..c77591e63841 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -35,10 +35,7 @@ static struct kmem_cache *br_fdb_cache __read_mostly; int __init br_fdb_init(void) { - br_fdb_cache = kmem_cache_create("bridge_fdb_cache", - sizeof(struct net_bridge_fdb_entry), - 0, - SLAB_HWCACHE_ALIGN, NULL); + br_fdb_cache = KMEM_CACHE(net_bridge_fdb_entry, SLAB_HWCACHE_ALIGN); if (!br_fdb_cache) return -ENOMEM; From d0f6dc26346863e1f4a23117f5468614e54df064 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 29 Jan 2024 11:04:33 -0800 Subject: [PATCH 0511/2255] af_unix: Replace BUG_ON() with WARN_ON_ONCE(). This is a prep patch for the last patch in this series so that checkpatch will not warn about BUG_ON(). Signed-off-by: Kuniyuki Iwashima Acked-by: Jens Axboe Link: https://lore.kernel.org/r/20240129190435.57228-2-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/unix/garbage.c | 8 ++++---- net/unix/scm.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 4046c606f0e6..af676bb8fb67 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -145,7 +145,7 @@ static void scan_children(struct sock *x, void (*func)(struct unix_sock *), /* An embryo cannot be in-flight, so it's safe * to use the list link. */ - BUG_ON(!list_empty(&u->link)); + WARN_ON_ONCE(!list_empty(&u->link)); list_add_tail(&u->link, &embryos); } spin_unlock(&x->sk_receive_queue.lock); @@ -213,8 +213,8 @@ static void __unix_gc(struct work_struct *work) total_refs = file_count(u->sk.sk_socket->file); - BUG_ON(!u->inflight); - BUG_ON(total_refs < u->inflight); + WARN_ON_ONCE(!u->inflight); + WARN_ON_ONCE(total_refs < u->inflight); if (total_refs == u->inflight) { list_move_tail(&u->link, &gc_candidates); __set_bit(UNIX_GC_CANDIDATE, &u->gc_flags); @@ -294,7 +294,7 @@ static void __unix_gc(struct work_struct *work) list_move_tail(&u->link, &gc_inflight_list); /* All candidates should have been detached by now. */ - BUG_ON(!list_empty(&gc_candidates)); + WARN_ON_ONCE(!list_empty(&gc_candidates)); /* Paired with READ_ONCE() in wait_for_unix_gc(). */ WRITE_ONCE(gc_in_progress, false); diff --git a/net/unix/scm.c b/net/unix/scm.c index b5ae5ab16777..505e56cf02a2 100644 --- a/net/unix/scm.c +++ b/net/unix/scm.c @@ -51,10 +51,10 @@ void unix_inflight(struct user_struct *user, struct file *fp) if (u) { if (!u->inflight) { - BUG_ON(!list_empty(&u->link)); + WARN_ON_ONCE(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); } else { - BUG_ON(list_empty(&u->link)); + WARN_ON_ONCE(list_empty(&u->link)); } u->inflight++; /* Paired with READ_ONCE() in wait_for_unix_gc() */ @@ -71,8 +71,8 @@ void unix_notinflight(struct user_struct *user, struct file *fp) spin_lock(&unix_gc_lock); if (u) { - BUG_ON(!u->inflight); - BUG_ON(list_empty(&u->link)); + WARN_ON_ONCE(!u->inflight); + WARN_ON_ONCE(list_empty(&u->link)); u->inflight--; if (!u->inflight) From 11498715f266a3fb4caabba9dd575636cbcaa8f1 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 29 Jan 2024 11:04:34 -0800 Subject: [PATCH 0512/2255] af_unix: Remove io_uring code for GC. Since commit 705318a99a13 ("io_uring/af_unix: disable sending io_uring over sockets"), io_uring's unix socket cannot be passed via SCM_RIGHTS, so it does not contribute to cyclic reference and no longer be candidate for garbage collection. Also, commit 6e5e6d274956 ("io_uring: drop any code related to SCM_RIGHTS") cleaned up SCM_RIGHTS code in io_uring. Let's do it in AF_UNIX as well by reverting commit 0091bfc81741 ("io_uring/af_unix: defer registered files gc to io_uring release") and commit 10369080454d ("net: reclaim skb->scm_io_uring bit"). Signed-off-by: Kuniyuki Iwashima Acked-by: Jens Axboe Link: https://lore.kernel.org/r/20240129190435.57228-3-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/af_unix.h | 1 - net/unix/garbage.c | 25 ++----------------------- net/unix/scm.c | 6 ------ 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/include/net/af_unix.h b/include/net/af_unix.h index f045bbd9017d..9e39b2ec4524 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -20,7 +20,6 @@ static inline struct unix_sock *unix_get_socket(struct file *filp) void unix_inflight(struct user_struct *user, struct file *fp); void unix_notinflight(struct user_struct *user, struct file *fp); void unix_destruct_scm(struct sk_buff *skb); -void io_uring_destruct_scm(struct sk_buff *skb); void unix_gc(void); void wait_for_unix_gc(struct scm_fp_list *fpl); struct sock *unix_peer_get(struct sock *sk); diff --git a/net/unix/garbage.c b/net/unix/garbage.c index af676bb8fb67..ce5b5f87b16e 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -184,12 +184,10 @@ static bool gc_in_progress; static void __unix_gc(struct work_struct *work) { - struct sk_buff *next_skb, *skb; - struct unix_sock *u; - struct unix_sock *next; struct sk_buff_head hitlist; - struct list_head cursor; + struct unix_sock *u, *next; LIST_HEAD(not_cycle_list); + struct list_head cursor; spin_lock(&unix_gc_lock); @@ -269,30 +267,11 @@ static void __unix_gc(struct work_struct *work) spin_unlock(&unix_gc_lock); - /* We need io_uring to clean its registered files, ignore all io_uring - * originated skbs. It's fine as io_uring doesn't keep references to - * other io_uring instances and so killing all other files in the cycle - * will put all io_uring references forcing it to go through normal - * release.path eventually putting registered files. - */ - skb_queue_walk_safe(&hitlist, skb, next_skb) { - if (skb->destructor == io_uring_destruct_scm) { - __skb_unlink(skb, &hitlist); - skb_queue_tail(&skb->sk->sk_receive_queue, skb); - } - } - /* Here we are. Hitlist is filled. Die. */ __skb_queue_purge(&hitlist); spin_lock(&unix_gc_lock); - /* There could be io_uring registered files, just push them back to - * the inflight list - */ - list_for_each_entry_safe(u, next, &gc_candidates, link) - list_move_tail(&u->link, &gc_inflight_list); - /* All candidates should have been detached by now. */ WARN_ON_ONCE(!list_empty(&gc_candidates)); diff --git a/net/unix/scm.c b/net/unix/scm.c index 505e56cf02a2..db65b0ab5947 100644 --- a/net/unix/scm.c +++ b/net/unix/scm.c @@ -148,9 +148,3 @@ void unix_destruct_scm(struct sk_buff *skb) sock_wfree(skb); } EXPORT_SYMBOL(unix_destruct_scm); - -void io_uring_destruct_scm(struct sk_buff *skb) -{ - unix_destruct_scm(skb); -} -EXPORT_SYMBOL(io_uring_destruct_scm); From 99a7a5b9943ea2d05fb0dee38e4ae2290477ed83 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 29 Jan 2024 11:04:35 -0800 Subject: [PATCH 0513/2255] af_unix: Remove CONFIG_UNIX_SCM. Originally, the code related to garbage collection was all in garbage.c. Commit f4e65870e5ce ("net: split out functions related to registering inflight socket files") moved some functions to scm.c for io_uring and added CONFIG_UNIX_SCM just in case AF_UNIX was built as module. However, since commit 97154bcf4d1b ("af_unix: Kconfig: make CONFIG_UNIX bool"), AF_UNIX is no longer built separately. Also, io_uring does not support SCM_RIGHTS now. Let's move the functions back to garbage.c Signed-off-by: Kuniyuki Iwashima Acked-by: Jens Axboe Link: https://lore.kernel.org/r/20240129190435.57228-4-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/af_unix.h | 7 +- net/Makefile | 2 +- net/unix/Kconfig | 5 -- net/unix/Makefile | 2 - net/unix/af_unix.c | 63 +++++++++++++++++- net/unix/garbage.c | 73 +++++++++++++++++++- net/unix/scm.c | 150 ------------------------------------------ net/unix/scm.h | 10 --- 8 files changed, 137 insertions(+), 175 deletions(-) delete mode 100644 net/unix/scm.c delete mode 100644 net/unix/scm.h diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 9e39b2ec4524..54e346152eb1 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -17,19 +17,20 @@ static inline struct unix_sock *unix_get_socket(struct file *filp) } #endif +extern spinlock_t unix_gc_lock; +extern unsigned int unix_tot_inflight; + void unix_inflight(struct user_struct *user, struct file *fp); void unix_notinflight(struct user_struct *user, struct file *fp); -void unix_destruct_scm(struct sk_buff *skb); void unix_gc(void); void wait_for_unix_gc(struct scm_fp_list *fpl); + struct sock *unix_peer_get(struct sock *sk); #define UNIX_HASH_MOD (256 - 1) #define UNIX_HASH_SIZE (256 * 2) #define UNIX_HASH_BITS 8 -extern unsigned int unix_tot_inflight; - struct unix_address { refcount_t refcnt; int len; diff --git a/net/Makefile b/net/Makefile index b06b5539e7a6..65bb8c72a35e 100644 --- a/net/Makefile +++ b/net/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_INET) += ipv4/ obj-$(CONFIG_TLS) += tls/ obj-$(CONFIG_XFRM) += xfrm/ -obj-$(CONFIG_UNIX_SCM) += unix/ +obj-$(CONFIG_UNIX) += unix/ obj-y += ipv6/ obj-$(CONFIG_PACKET) += packet/ obj-$(CONFIG_NET_KEY) += key/ diff --git a/net/unix/Kconfig b/net/unix/Kconfig index 28b232f281ab..8b5d04210d7c 100644 --- a/net/unix/Kconfig +++ b/net/unix/Kconfig @@ -16,11 +16,6 @@ config UNIX Say Y unless you know what you are doing. -config UNIX_SCM - bool - depends on UNIX - default y - config AF_UNIX_OOB bool depends on UNIX diff --git a/net/unix/Makefile b/net/unix/Makefile index 20491825b4d0..4ddd125c4642 100644 --- a/net/unix/Makefile +++ b/net/unix/Makefile @@ -11,5 +11,3 @@ unix-$(CONFIG_BPF_SYSCALL) += unix_bpf.o obj-$(CONFIG_UNIX_DIAG) += unix_diag.o unix_diag-y := diag.o - -obj-$(CONFIG_UNIX_SCM) += scm.o diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 1720419d93d6..1cfbc586adb4 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -118,8 +118,6 @@ #include #include -#include "scm.h" - static atomic_long_t unix_nr_socks; static struct hlist_head bsd_socket_buckets[UNIX_HASH_SIZE / 2]; static spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2]; @@ -1790,6 +1788,52 @@ out: return err; } +/* The "user->unix_inflight" variable is protected by the garbage + * collection lock, and we just read it locklessly here. If you go + * over the limit, there might be a tiny race in actually noticing + * it across threads. Tough. + */ +static inline bool too_many_unix_fds(struct task_struct *p) +{ + struct user_struct *user = current_user(); + + if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) + return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); + return false; +} + +static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +{ + int i; + + if (too_many_unix_fds(current)) + return -ETOOMANYREFS; + + /* Need to duplicate file references for the sake of garbage + * collection. Otherwise a socket in the fps might become a + * candidate for GC while the skb is not yet queued. + */ + UNIXCB(skb).fp = scm_fp_dup(scm->fp); + if (!UNIXCB(skb).fp) + return -ENOMEM; + + for (i = scm->fp->count - 1; i >= 0; i--) + unix_inflight(scm->fp->user, scm->fp->fp[i]); + + return 0; +} + +static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) +{ + int i; + + scm->fp = UNIXCB(skb).fp; + UNIXCB(skb).fp = NULL; + + for (i = scm->fp->count - 1; i >= 0; i--) + unix_notinflight(scm->fp->user, scm->fp->fp[i]); +} + static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) { scm->fp = scm_fp_dup(UNIXCB(skb).fp); @@ -1837,6 +1881,21 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) spin_unlock(&unix_gc_lock); } +static void unix_destruct_scm(struct sk_buff *skb) +{ + struct scm_cookie scm; + + memset(&scm, 0, sizeof(scm)); + scm.pid = UNIXCB(skb).pid; + if (UNIXCB(skb).fp) + unix_detach_fds(&scm, skb); + + /* Alas, it calls VFS */ + /* So fscking what? fput() had been SMP-safe since the last Summer */ + scm_destroy(&scm); + sock_wfree(skb); +} + static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) { int err = 0; diff --git a/net/unix/garbage.c b/net/unix/garbage.c index ce5b5f87b16e..9b8473dd79a4 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -81,11 +81,80 @@ #include #include -#include "scm.h" +struct unix_sock *unix_get_socket(struct file *filp) +{ + struct inode *inode = file_inode(filp); -/* Internal data structures and random procedures: */ + /* Socket ? */ + if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { + struct socket *sock = SOCKET_I(inode); + const struct proto_ops *ops; + struct sock *sk = sock->sk; + ops = READ_ONCE(sock->ops); + + /* PF_UNIX ? */ + if (sk && ops && ops->family == PF_UNIX) + return unix_sk(sk); + } + + return NULL; +} + +DEFINE_SPINLOCK(unix_gc_lock); +unsigned int unix_tot_inflight; static LIST_HEAD(gc_candidates); +static LIST_HEAD(gc_inflight_list); + +/* Keep the number of times in flight count for the file + * descriptor if it is for an AF_UNIX socket. + */ +void unix_inflight(struct user_struct *user, struct file *filp) +{ + struct unix_sock *u = unix_get_socket(filp); + + spin_lock(&unix_gc_lock); + + if (u) { + if (!u->inflight) { + WARN_ON_ONCE(!list_empty(&u->link)); + list_add_tail(&u->link, &gc_inflight_list); + } else { + WARN_ON_ONCE(list_empty(&u->link)); + } + u->inflight++; + + /* Paired with READ_ONCE() in wait_for_unix_gc() */ + WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1); + } + + WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1); + + spin_unlock(&unix_gc_lock); +} + +void unix_notinflight(struct user_struct *user, struct file *filp) +{ + struct unix_sock *u = unix_get_socket(filp); + + spin_lock(&unix_gc_lock); + + if (u) { + WARN_ON_ONCE(!u->inflight); + WARN_ON_ONCE(list_empty(&u->link)); + + u->inflight--; + if (!u->inflight) + list_del_init(&u->link); + + /* Paired with READ_ONCE() in wait_for_unix_gc() */ + WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1); + } + + WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1); + + spin_unlock(&unix_gc_lock); +} static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) diff --git a/net/unix/scm.c b/net/unix/scm.c deleted file mode 100644 index db65b0ab5947..000000000000 --- a/net/unix/scm.c +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scm.h" - -unsigned int unix_tot_inflight; -EXPORT_SYMBOL(unix_tot_inflight); - -LIST_HEAD(gc_inflight_list); -EXPORT_SYMBOL(gc_inflight_list); - -DEFINE_SPINLOCK(unix_gc_lock); -EXPORT_SYMBOL(unix_gc_lock); - -struct unix_sock *unix_get_socket(struct file *filp) -{ - struct inode *inode = file_inode(filp); - - /* Socket ? */ - if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { - struct socket *sock = SOCKET_I(inode); - const struct proto_ops *ops = READ_ONCE(sock->ops); - struct sock *s = sock->sk; - - /* PF_UNIX ? */ - if (s && ops && ops->family == PF_UNIX) - return unix_sk(s); - } - - return NULL; -} -EXPORT_SYMBOL(unix_get_socket); - -/* Keep the number of times in flight count for the file - * descriptor if it is for an AF_UNIX socket. - */ -void unix_inflight(struct user_struct *user, struct file *fp) -{ - struct unix_sock *u = unix_get_socket(fp); - - spin_lock(&unix_gc_lock); - - if (u) { - if (!u->inflight) { - WARN_ON_ONCE(!list_empty(&u->link)); - list_add_tail(&u->link, &gc_inflight_list); - } else { - WARN_ON_ONCE(list_empty(&u->link)); - } - u->inflight++; - /* Paired with READ_ONCE() in wait_for_unix_gc() */ - WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1); - } - WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1); - spin_unlock(&unix_gc_lock); -} - -void unix_notinflight(struct user_struct *user, struct file *fp) -{ - struct unix_sock *u = unix_get_socket(fp); - - spin_lock(&unix_gc_lock); - - if (u) { - WARN_ON_ONCE(!u->inflight); - WARN_ON_ONCE(list_empty(&u->link)); - - u->inflight--; - if (!u->inflight) - list_del_init(&u->link); - /* Paired with READ_ONCE() in wait_for_unix_gc() */ - WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1); - } - WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1); - spin_unlock(&unix_gc_lock); -} - -/* - * The "user->unix_inflight" variable is protected by the garbage - * collection lock, and we just read it locklessly here. If you go - * over the limit, there might be a tiny race in actually noticing - * it across threads. Tough. - */ -static inline bool too_many_unix_fds(struct task_struct *p) -{ - struct user_struct *user = current_user(); - - if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) - return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); - return false; -} - -int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) -{ - int i; - - if (too_many_unix_fds(current)) - return -ETOOMANYREFS; - - /* - * Need to duplicate file references for the sake of garbage - * collection. Otherwise a socket in the fps might become a - * candidate for GC while the skb is not yet queued. - */ - UNIXCB(skb).fp = scm_fp_dup(scm->fp); - if (!UNIXCB(skb).fp) - return -ENOMEM; - - for (i = scm->fp->count - 1; i >= 0; i--) - unix_inflight(scm->fp->user, scm->fp->fp[i]); - return 0; -} -EXPORT_SYMBOL(unix_attach_fds); - -void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) -{ - int i; - - scm->fp = UNIXCB(skb).fp; - UNIXCB(skb).fp = NULL; - - for (i = scm->fp->count-1; i >= 0; i--) - unix_notinflight(scm->fp->user, scm->fp->fp[i]); -} -EXPORT_SYMBOL(unix_detach_fds); - -void unix_destruct_scm(struct sk_buff *skb) -{ - struct scm_cookie scm; - - memset(&scm, 0, sizeof(scm)); - scm.pid = UNIXCB(skb).pid; - if (UNIXCB(skb).fp) - unix_detach_fds(&scm, skb); - - /* Alas, it calls VFS */ - /* So fscking what? fput() had been SMP-safe since the last Summer */ - scm_destroy(&scm); - sock_wfree(skb); -} -EXPORT_SYMBOL(unix_destruct_scm); diff --git a/net/unix/scm.h b/net/unix/scm.h deleted file mode 100644 index 5a255a477f16..000000000000 --- a/net/unix/scm.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef NET_UNIX_SCM_H -#define NET_UNIX_SCM_H - -extern struct list_head gc_inflight_list; -extern spinlock_t unix_gc_lock; - -int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb); -void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb); - -#endif From a05e90427ef6706f59188b379ad6366b9d298bc5 Mon Sep 17 00:00:00 2001 From: Daniel Xu Date: Sun, 28 Jan 2024 18:24:07 -0700 Subject: [PATCH 0514/2255] bpf: btf: Add BTF_KFUNCS_START/END macro pair This macro pair is functionally equivalent to BTF_SET8_START/END, except with BTF_SET8_KFUNCS flag set in the btf_id_set8 flags field. The next commit will codemod all kfunc set8s to this new variant such that all kfuncs are tagged as such in .BTF_ids section. Signed-off-by: Daniel Xu Link: https://lore.kernel.org/r/d536c57c7c2af428686853cc7396b7a44faa53b7.1706491398.git.dxu@dxuuu.xyz Signed-off-by: Alexei Starovoitov --- include/linux/btf_ids.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/btf_ids.h b/include/linux/btf_ids.h index dca09b7f21dc..e24aabfe8ecc 100644 --- a/include/linux/btf_ids.h +++ b/include/linux/btf_ids.h @@ -8,6 +8,9 @@ struct btf_id_set { u32 ids[]; }; +/* This flag implies BTF_SET8 holds kfunc(s) */ +#define BTF_SET8_KFUNCS (1 << 0) + struct btf_id_set8 { u32 cnt; u32 flags; @@ -204,6 +207,12 @@ asm( \ ".popsection; \n"); \ extern struct btf_id_set8 name; +#define BTF_KFUNCS_START(name) \ +__BTF_SET8_START(name, local, BTF_SET8_KFUNCS) + +#define BTF_KFUNCS_END(name) \ +BTF_SET8_END(name) + #else #define BTF_ID_LIST(name) static u32 __maybe_unused name[64]; @@ -218,6 +227,8 @@ extern struct btf_id_set8 name; #define BTF_SET_END(name) #define BTF_SET8_START(name) static struct btf_id_set8 __maybe_unused name = { 0 }; #define BTF_SET8_END(name) +#define BTF_KFUNCS_START(name) static struct btf_id_set8 __maybe_unused name = { .flags = BTF_SET8_KFUNCS }; +#define BTF_KFUNCS_END(name) #endif /* CONFIG_DEBUG_INFO_BTF */ From 6f3189f38a3e995232e028a4c341164c4aca1b20 Mon Sep 17 00:00:00 2001 From: Daniel Xu Date: Sun, 28 Jan 2024 18:24:08 -0700 Subject: [PATCH 0515/2255] bpf: treewide: Annotate BPF kfuncs in BTF This commit marks kfuncs as such inside the .BTF_ids section. The upshot of these annotations is that we'll be able to automatically generate kfunc prototypes for downstream users. The process is as follows: 1. In source, use BTF_KFUNCS_START/END macro pair to mark kfuncs 2. During build, pahole injects into BTF a "bpf_kfunc" BTF_DECL_TAG for each function inside BTF_KFUNCS sets 3. At runtime, vmlinux or module BTF is made available in sysfs 4. At runtime, bpftool (or similar) can look at provided BTF and generate appropriate prototypes for functions with "bpf_kfunc" tag To ensure future kfunc are similarly tagged, we now also return error inside kfunc registration for untagged kfuncs. For vmlinux kfuncs, we also WARN(), as initcall machinery does not handle errors. Signed-off-by: Daniel Xu Acked-by: Benjamin Tissoires Link: https://lore.kernel.org/r/e55150ceecbf0a5d961e608941165c0bee7bc943.1706491398.git.dxu@dxuuu.xyz Signed-off-by: Alexei Starovoitov --- Documentation/bpf/kfuncs.rst | 8 ++++---- drivers/hid/bpf/hid_bpf_dispatch.c | 8 ++++---- fs/verity/measure.c | 4 ++-- kernel/bpf/btf.c | 8 ++++++++ kernel/bpf/cpumask.c | 4 ++-- kernel/bpf/helpers.c | 8 ++++---- kernel/bpf/map_iter.c | 4 ++-- kernel/cgroup/rstat.c | 4 ++-- kernel/trace/bpf_trace.c | 8 ++++---- net/bpf/test_run.c | 8 ++++---- net/core/filter.c | 20 +++++++++---------- net/core/xdp.c | 4 ++-- net/ipv4/bpf_tcp_ca.c | 4 ++-- net/ipv4/fou_bpf.c | 4 ++-- net/ipv4/tcp_bbr.c | 4 ++-- net/ipv4/tcp_cubic.c | 4 ++-- net/ipv4/tcp_dctcp.c | 4 ++-- net/netfilter/nf_conntrack_bpf.c | 4 ++-- net/netfilter/nf_nat_bpf.c | 4 ++-- net/xfrm/xfrm_interface_bpf.c | 4 ++-- net/xfrm/xfrm_state_bpf.c | 4 ++-- .../selftests/bpf/bpf_testmod/bpf_testmod.c | 8 ++++---- 22 files changed, 70 insertions(+), 62 deletions(-) diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index 7985c6615f3c..a8f5782bd833 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -177,10 +177,10 @@ In addition to kfuncs' arguments, verifier may need more information about the type of kfunc(s) being registered with the BPF subsystem. To do so, we define flags on a set of kfuncs as follows:: - BTF_SET8_START(bpf_task_set) + BTF_KFUNCS_START(bpf_task_set) BTF_ID_FLAGS(func, bpf_get_task_pid, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_put_pid, KF_RELEASE) - BTF_SET8_END(bpf_task_set) + BTF_KFUNCS_END(bpf_task_set) This set encodes the BTF ID of each kfunc listed above, and encodes the flags along with it. Ofcourse, it is also allowed to specify no flags. @@ -347,10 +347,10 @@ Once the kfunc is prepared for use, the final step to making it visible is registering it with the BPF subsystem. Registration is done per BPF program type. An example is shown below:: - BTF_SET8_START(bpf_task_set) + BTF_KFUNCS_START(bpf_task_set) BTF_ID_FLAGS(func, bpf_get_task_pid, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_put_pid, KF_RELEASE) - BTF_SET8_END(bpf_task_set) + BTF_KFUNCS_END(bpf_task_set) static const struct btf_kfunc_id_set bpf_task_kfunc_set = { .owner = THIS_MODULE, diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index d9ef45fcaeab..02c441aaa217 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -172,9 +172,9 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr * The following set contains all functions we agree BPF programs * can use. */ -BTF_SET8_START(hid_bpf_kfunc_ids) +BTF_KFUNCS_START(hid_bpf_kfunc_ids) BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL) -BTF_SET8_END(hid_bpf_kfunc_ids) +BTF_KFUNCS_END(hid_bpf_kfunc_ids) static const struct btf_kfunc_id_set hid_bpf_kfunc_set = { .owner = THIS_MODULE, @@ -440,12 +440,12 @@ static const struct btf_kfunc_id_set hid_bpf_fmodret_set = { }; /* for syscall HID-BPF */ -BTF_SET8_START(hid_bpf_syscall_kfunc_ids) +BTF_KFUNCS_START(hid_bpf_syscall_kfunc_ids) BTF_ID_FLAGS(func, hid_bpf_attach_prog) BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE) BTF_ID_FLAGS(func, hid_bpf_hw_request) -BTF_SET8_END(hid_bpf_syscall_kfunc_ids) +BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids) static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = { .owner = THIS_MODULE, diff --git a/fs/verity/measure.c b/fs/verity/measure.c index bf7a5f4cccaf..3969d54158d1 100644 --- a/fs/verity/measure.c +++ b/fs/verity/measure.c @@ -159,9 +159,9 @@ __bpf_kfunc int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr_ker __bpf_kfunc_end_defs(); -BTF_SET8_START(fsverity_set_ids) +BTF_KFUNCS_START(fsverity_set_ids) BTF_ID_FLAGS(func, bpf_get_fsverity_digest, KF_TRUSTED_ARGS) -BTF_SET8_END(fsverity_set_ids) +BTF_KFUNCS_END(fsverity_set_ids) static int bpf_get_fsverity_digest_filter(const struct bpf_prog *prog, u32 kfunc_id) { diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index c8c6e6cf18e7..ef380e546952 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -8124,6 +8124,14 @@ int register_btf_kfunc_id_set(enum bpf_prog_type prog_type, { enum btf_kfunc_hook hook; + /* All kfuncs need to be tagged as such in BTF. + * WARN() for initcall registrations that do not check errors. + */ + if (!(kset->set->flags & BTF_SET8_KFUNCS)) { + WARN_ON(!kset->owner); + return -EINVAL; + } + hook = bpf_prog_type_to_kfunc_hook(prog_type); return __register_btf_kfunc_id_set(hook, kset); } diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c index 2e73533a3811..dad0fb1c8e87 100644 --- a/kernel/bpf/cpumask.c +++ b/kernel/bpf/cpumask.c @@ -424,7 +424,7 @@ __bpf_kfunc u32 bpf_cpumask_weight(const struct cpumask *cpumask) __bpf_kfunc_end_defs(); -BTF_SET8_START(cpumask_kfunc_btf_ids) +BTF_KFUNCS_START(cpumask_kfunc_btf_ids) BTF_ID_FLAGS(func, bpf_cpumask_create, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_cpumask_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_cpumask_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS) @@ -450,7 +450,7 @@ BTF_ID_FLAGS(func, bpf_cpumask_copy, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_any_distribute, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_any_and_distribute, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_weight, KF_RCU) -BTF_SET8_END(cpumask_kfunc_btf_ids) +BTF_KFUNCS_END(cpumask_kfunc_btf_ids) static const struct btf_kfunc_id_set cpumask_kfunc_set = { .owner = THIS_MODULE, diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index bcb951a2ecf4..4db1c658254c 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2544,7 +2544,7 @@ __bpf_kfunc void bpf_throw(u64 cookie) __bpf_kfunc_end_defs(); -BTF_SET8_START(generic_btf_ids) +BTF_KFUNCS_START(generic_btf_ids) #ifdef CONFIG_KEXEC_CORE BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE) #endif @@ -2573,7 +2573,7 @@ BTF_ID_FLAGS(func, bpf_task_get_cgroup1, KF_ACQUIRE | KF_RCU | KF_RET_NULL) #endif BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_throw) -BTF_SET8_END(generic_btf_ids) +BTF_KFUNCS_END(generic_btf_ids) static const struct btf_kfunc_id_set generic_kfunc_set = { .owner = THIS_MODULE, @@ -2589,7 +2589,7 @@ BTF_ID(struct, cgroup) BTF_ID(func, bpf_cgroup_release_dtor) #endif -BTF_SET8_START(common_btf_ids) +BTF_KFUNCS_START(common_btf_ids) BTF_ID_FLAGS(func, bpf_cast_to_kern_ctx) BTF_ID_FLAGS(func, bpf_rdonly_cast) BTF_ID_FLAGS(func, bpf_rcu_read_lock) @@ -2618,7 +2618,7 @@ BTF_ID_FLAGS(func, bpf_dynptr_is_null) BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly) BTF_ID_FLAGS(func, bpf_dynptr_size) BTF_ID_FLAGS(func, bpf_dynptr_clone) -BTF_SET8_END(common_btf_ids) +BTF_KFUNCS_END(common_btf_ids) static const struct btf_kfunc_id_set common_kfunc_set = { .owner = THIS_MODULE, diff --git a/kernel/bpf/map_iter.c b/kernel/bpf/map_iter.c index 6abd7c5df4b3..9575314f40a6 100644 --- a/kernel/bpf/map_iter.c +++ b/kernel/bpf/map_iter.c @@ -213,9 +213,9 @@ __bpf_kfunc s64 bpf_map_sum_elem_count(const struct bpf_map *map) __bpf_kfunc_end_defs(); -BTF_SET8_START(bpf_map_iter_kfunc_ids) +BTF_KFUNCS_START(bpf_map_iter_kfunc_ids) BTF_ID_FLAGS(func, bpf_map_sum_elem_count, KF_TRUSTED_ARGS) -BTF_SET8_END(bpf_map_iter_kfunc_ids) +BTF_KFUNCS_END(bpf_map_iter_kfunc_ids) static const struct btf_kfunc_id_set bpf_map_iter_kfunc_set = { .owner = THIS_MODULE, diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c index a8350d2d63e6..07e2284bb499 100644 --- a/kernel/cgroup/rstat.c +++ b/kernel/cgroup/rstat.c @@ -562,10 +562,10 @@ void cgroup_base_stat_cputime_show(struct seq_file *seq) } /* Add bpf kfuncs for cgroup_rstat_updated() and cgroup_rstat_flush() */ -BTF_SET8_START(bpf_rstat_kfunc_ids) +BTF_KFUNCS_START(bpf_rstat_kfunc_ids) BTF_ID_FLAGS(func, cgroup_rstat_updated) BTF_ID_FLAGS(func, cgroup_rstat_flush, KF_SLEEPABLE) -BTF_SET8_END(bpf_rstat_kfunc_ids) +BTF_KFUNCS_END(bpf_rstat_kfunc_ids) static const struct btf_kfunc_id_set bpf_rstat_kfunc_set = { .owner = THIS_MODULE, diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 64fdaf79d113..241ddf5e3895 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1412,14 +1412,14 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr, __bpf_kfunc_end_defs(); -BTF_SET8_START(key_sig_kfunc_set) +BTF_KFUNCS_START(key_sig_kfunc_set) BTF_ID_FLAGS(func, bpf_lookup_user_key, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_lookup_system_key, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_key_put, KF_RELEASE) #ifdef CONFIG_SYSTEM_DATA_VERIFICATION BTF_ID_FLAGS(func, bpf_verify_pkcs7_signature, KF_SLEEPABLE) #endif -BTF_SET8_END(key_sig_kfunc_set) +BTF_KFUNCS_END(key_sig_kfunc_set) static const struct btf_kfunc_id_set bpf_key_sig_kfunc_set = { .owner = THIS_MODULE, @@ -1475,9 +1475,9 @@ __bpf_kfunc int bpf_get_file_xattr(struct file *file, const char *name__str, __bpf_kfunc_end_defs(); -BTF_SET8_START(fs_kfunc_set_ids) +BTF_KFUNCS_START(fs_kfunc_set_ids) BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS) -BTF_SET8_END(fs_kfunc_set_ids) +BTF_KFUNCS_END(fs_kfunc_set_ids) static int bpf_get_file_xattr_filter(const struct bpf_prog *prog, u32 kfunc_id) { diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index dfd919374017..5535f9adc658 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -617,21 +617,21 @@ CFI_NOSEAL(bpf_kfunc_call_memb_release_dtor); __bpf_kfunc_end_defs(); -BTF_SET8_START(bpf_test_modify_return_ids) +BTF_KFUNCS_START(bpf_test_modify_return_ids) BTF_ID_FLAGS(func, bpf_modify_return_test) BTF_ID_FLAGS(func, bpf_modify_return_test2) BTF_ID_FLAGS(func, bpf_fentry_test1, KF_SLEEPABLE) -BTF_SET8_END(bpf_test_modify_return_ids) +BTF_KFUNCS_END(bpf_test_modify_return_ids) static const struct btf_kfunc_id_set bpf_test_modify_return_set = { .owner = THIS_MODULE, .set = &bpf_test_modify_return_ids, }; -BTF_SET8_START(test_sk_check_kfunc_ids) +BTF_KFUNCS_START(test_sk_check_kfunc_ids) BTF_ID_FLAGS(func, bpf_kfunc_call_test_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_kfunc_call_memb_release, KF_RELEASE) -BTF_SET8_END(test_sk_check_kfunc_ids) +BTF_KFUNCS_END(test_sk_check_kfunc_ids) static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size, u32 size, u32 headroom, u32 tailroom) diff --git a/net/core/filter.c b/net/core/filter.c index 358870408a51..524adf1fa6d0 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -11982,21 +11982,21 @@ int bpf_dynptr_from_skb_rdonly(struct sk_buff *skb, u64 flags, return 0; } -BTF_SET8_START(bpf_kfunc_check_set_skb) +BTF_KFUNCS_START(bpf_kfunc_check_set_skb) BTF_ID_FLAGS(func, bpf_dynptr_from_skb) -BTF_SET8_END(bpf_kfunc_check_set_skb) +BTF_KFUNCS_END(bpf_kfunc_check_set_skb) -BTF_SET8_START(bpf_kfunc_check_set_xdp) +BTF_KFUNCS_START(bpf_kfunc_check_set_xdp) BTF_ID_FLAGS(func, bpf_dynptr_from_xdp) -BTF_SET8_END(bpf_kfunc_check_set_xdp) +BTF_KFUNCS_END(bpf_kfunc_check_set_xdp) -BTF_SET8_START(bpf_kfunc_check_set_sock_addr) +BTF_KFUNCS_START(bpf_kfunc_check_set_sock_addr) BTF_ID_FLAGS(func, bpf_sock_addr_set_sun_path) -BTF_SET8_END(bpf_kfunc_check_set_sock_addr) +BTF_KFUNCS_END(bpf_kfunc_check_set_sock_addr) -BTF_SET8_START(bpf_kfunc_check_set_tcp_reqsk) +BTF_KFUNCS_START(bpf_kfunc_check_set_tcp_reqsk) BTF_ID_FLAGS(func, bpf_sk_assign_tcp_reqsk, KF_TRUSTED_ARGS) -BTF_SET8_END(bpf_kfunc_check_set_tcp_reqsk) +BTF_KFUNCS_END(bpf_kfunc_check_set_tcp_reqsk) static const struct btf_kfunc_id_set bpf_kfunc_set_skb = { .owner = THIS_MODULE, @@ -12075,9 +12075,9 @@ __bpf_kfunc int bpf_sock_destroy(struct sock_common *sock) __bpf_kfunc_end_defs(); -BTF_SET8_START(bpf_sk_iter_kfunc_ids) +BTF_KFUNCS_START(bpf_sk_iter_kfunc_ids) BTF_ID_FLAGS(func, bpf_sock_destroy, KF_TRUSTED_ARGS) -BTF_SET8_END(bpf_sk_iter_kfunc_ids) +BTF_KFUNCS_END(bpf_sk_iter_kfunc_ids) static int tracing_iter_filter(const struct bpf_prog *prog, u32 kfunc_id) { diff --git a/net/core/xdp.c b/net/core/xdp.c index 4869c1c2d8f3..034fb80f3fbe 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -771,11 +771,11 @@ __bpf_kfunc int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, __bpf_kfunc_end_defs(); -BTF_SET8_START(xdp_metadata_kfunc_ids) +BTF_KFUNCS_START(xdp_metadata_kfunc_ids) #define XDP_METADATA_KFUNC(_, __, name, ___) BTF_ID_FLAGS(func, name, KF_TRUSTED_ARGS) XDP_METADATA_KFUNC_xxx #undef XDP_METADATA_KFUNC -BTF_SET8_END(xdp_metadata_kfunc_ids) +BTF_KFUNCS_END(xdp_metadata_kfunc_ids) static const struct btf_kfunc_id_set xdp_metadata_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c index 834edc18463a..7f518ea5f4ac 100644 --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c @@ -201,13 +201,13 @@ bpf_tcp_ca_get_func_proto(enum bpf_func_id func_id, } } -BTF_SET8_START(bpf_tcp_ca_check_kfunc_ids) +BTF_KFUNCS_START(bpf_tcp_ca_check_kfunc_ids) BTF_ID_FLAGS(func, tcp_reno_ssthresh) BTF_ID_FLAGS(func, tcp_reno_cong_avoid) BTF_ID_FLAGS(func, tcp_reno_undo_cwnd) BTF_ID_FLAGS(func, tcp_slow_start) BTF_ID_FLAGS(func, tcp_cong_avoid_ai) -BTF_SET8_END(bpf_tcp_ca_check_kfunc_ids) +BTF_KFUNCS_END(bpf_tcp_ca_check_kfunc_ids) static const struct btf_kfunc_id_set bpf_tcp_ca_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/ipv4/fou_bpf.c b/net/ipv4/fou_bpf.c index 4da03bf45c9b..06e5572f296f 100644 --- a/net/ipv4/fou_bpf.c +++ b/net/ipv4/fou_bpf.c @@ -100,10 +100,10 @@ __bpf_kfunc int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx, __bpf_kfunc_end_defs(); -BTF_SET8_START(fou_kfunc_set) +BTF_KFUNCS_START(fou_kfunc_set) BTF_ID_FLAGS(func, bpf_skb_set_fou_encap) BTF_ID_FLAGS(func, bpf_skb_get_fou_encap) -BTF_SET8_END(fou_kfunc_set) +BTF_KFUNCS_END(fou_kfunc_set) static const struct btf_kfunc_id_set fou_bpf_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 22358032dd48..05dc2d05bc7c 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -1155,7 +1155,7 @@ static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = { .set_state = bbr_set_state, }; -BTF_SET8_START(tcp_bbr_check_kfunc_ids) +BTF_KFUNCS_START(tcp_bbr_check_kfunc_ids) #ifdef CONFIG_X86 #ifdef CONFIG_DYNAMIC_FTRACE BTF_ID_FLAGS(func, bbr_init) @@ -1168,7 +1168,7 @@ BTF_ID_FLAGS(func, bbr_min_tso_segs) BTF_ID_FLAGS(func, bbr_set_state) #endif #endif -BTF_SET8_END(tcp_bbr_check_kfunc_ids) +BTF_KFUNCS_END(tcp_bbr_check_kfunc_ids) static const struct btf_kfunc_id_set tcp_bbr_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 0fd78ecb67e7..44869ea089e3 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -485,7 +485,7 @@ static struct tcp_congestion_ops cubictcp __read_mostly = { .name = "cubic", }; -BTF_SET8_START(tcp_cubic_check_kfunc_ids) +BTF_KFUNCS_START(tcp_cubic_check_kfunc_ids) #ifdef CONFIG_X86 #ifdef CONFIG_DYNAMIC_FTRACE BTF_ID_FLAGS(func, cubictcp_init) @@ -496,7 +496,7 @@ BTF_ID_FLAGS(func, cubictcp_cwnd_event) BTF_ID_FLAGS(func, cubictcp_acked) #endif #endif -BTF_SET8_END(tcp_cubic_check_kfunc_ids) +BTF_KFUNCS_END(tcp_cubic_check_kfunc_ids) static const struct btf_kfunc_id_set tcp_cubic_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index bb23bb5b387a..e33fbe4933e4 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -260,7 +260,7 @@ static struct tcp_congestion_ops dctcp_reno __read_mostly = { .name = "dctcp-reno", }; -BTF_SET8_START(tcp_dctcp_check_kfunc_ids) +BTF_KFUNCS_START(tcp_dctcp_check_kfunc_ids) #ifdef CONFIG_X86 #ifdef CONFIG_DYNAMIC_FTRACE BTF_ID_FLAGS(func, dctcp_init) @@ -271,7 +271,7 @@ BTF_ID_FLAGS(func, dctcp_cwnd_undo) BTF_ID_FLAGS(func, dctcp_state) #endif #endif -BTF_SET8_END(tcp_dctcp_check_kfunc_ids) +BTF_KFUNCS_END(tcp_dctcp_check_kfunc_ids) static const struct btf_kfunc_id_set tcp_dctcp_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c index 475358ec8212..d2492d050fe6 100644 --- a/net/netfilter/nf_conntrack_bpf.c +++ b/net/netfilter/nf_conntrack_bpf.c @@ -467,7 +467,7 @@ __bpf_kfunc int bpf_ct_change_status(struct nf_conn *nfct, u32 status) __bpf_kfunc_end_defs(); -BTF_SET8_START(nf_ct_kfunc_set) +BTF_KFUNCS_START(nf_ct_kfunc_set) BTF_ID_FLAGS(func, bpf_xdp_ct_alloc, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_xdp_ct_lookup, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_skb_ct_alloc, KF_ACQUIRE | KF_RET_NULL) @@ -478,7 +478,7 @@ BTF_ID_FLAGS(func, bpf_ct_set_timeout, KF_TRUSTED_ARGS) BTF_ID_FLAGS(func, bpf_ct_change_timeout, KF_TRUSTED_ARGS) BTF_ID_FLAGS(func, bpf_ct_set_status, KF_TRUSTED_ARGS) BTF_ID_FLAGS(func, bpf_ct_change_status, KF_TRUSTED_ARGS) -BTF_SET8_END(nf_ct_kfunc_set) +BTF_KFUNCS_END(nf_ct_kfunc_set) static const struct btf_kfunc_id_set nf_conntrack_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/netfilter/nf_nat_bpf.c b/net/netfilter/nf_nat_bpf.c index 6e3b2f58855f..481be15609b1 100644 --- a/net/netfilter/nf_nat_bpf.c +++ b/net/netfilter/nf_nat_bpf.c @@ -54,9 +54,9 @@ __bpf_kfunc int bpf_ct_set_nat_info(struct nf_conn___init *nfct, __bpf_kfunc_end_defs(); -BTF_SET8_START(nf_nat_kfunc_set) +BTF_KFUNCS_START(nf_nat_kfunc_set) BTF_ID_FLAGS(func, bpf_ct_set_nat_info, KF_TRUSTED_ARGS) -BTF_SET8_END(nf_nat_kfunc_set) +BTF_KFUNCS_END(nf_nat_kfunc_set) static const struct btf_kfunc_id_set nf_bpf_nat_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/xfrm/xfrm_interface_bpf.c b/net/xfrm/xfrm_interface_bpf.c index 7d5e920141e9..5ea15037ebd1 100644 --- a/net/xfrm/xfrm_interface_bpf.c +++ b/net/xfrm/xfrm_interface_bpf.c @@ -93,10 +93,10 @@ __bpf_kfunc int bpf_skb_set_xfrm_info(struct __sk_buff *skb_ctx, const struct bp __bpf_kfunc_end_defs(); -BTF_SET8_START(xfrm_ifc_kfunc_set) +BTF_KFUNCS_START(xfrm_ifc_kfunc_set) BTF_ID_FLAGS(func, bpf_skb_get_xfrm_info) BTF_ID_FLAGS(func, bpf_skb_set_xfrm_info) -BTF_SET8_END(xfrm_ifc_kfunc_set) +BTF_KFUNCS_END(xfrm_ifc_kfunc_set) static const struct btf_kfunc_id_set xfrm_interface_kfunc_set = { .owner = THIS_MODULE, diff --git a/net/xfrm/xfrm_state_bpf.c b/net/xfrm/xfrm_state_bpf.c index 9e20d4a377f7..2248eda741f8 100644 --- a/net/xfrm/xfrm_state_bpf.c +++ b/net/xfrm/xfrm_state_bpf.c @@ -117,10 +117,10 @@ __bpf_kfunc void bpf_xdp_xfrm_state_release(struct xfrm_state *x) __bpf_kfunc_end_defs(); -BTF_SET8_START(xfrm_state_kfunc_set) +BTF_KFUNCS_START(xfrm_state_kfunc_set) BTF_ID_FLAGS(func, bpf_xdp_get_xfrm_state, KF_RET_NULL | KF_ACQUIRE) BTF_ID_FLAGS(func, bpf_xdp_xfrm_state_release, KF_RELEASE) -BTF_SET8_END(xfrm_state_kfunc_set) +BTF_KFUNCS_END(xfrm_state_kfunc_set) static const struct btf_kfunc_id_set xfrm_state_xdp_kfunc_set = { .owner = THIS_MODULE, diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 6f163a0f1c94..4754c662b39f 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -343,12 +343,12 @@ static struct bin_attribute bin_attr_bpf_testmod_file __ro_after_init = { .write = bpf_testmod_test_write, }; -BTF_SET8_START(bpf_testmod_common_kfunc_ids) +BTF_KFUNCS_START(bpf_testmod_common_kfunc_ids) BTF_ID_FLAGS(func, bpf_iter_testmod_seq_new, KF_ITER_NEW) BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY) BTF_ID_FLAGS(func, bpf_kfunc_common_test) -BTF_SET8_END(bpf_testmod_common_kfunc_ids) +BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids) static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = { .owner = THIS_MODULE, @@ -494,7 +494,7 @@ __bpf_kfunc static u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused return arg; } -BTF_SET8_START(bpf_testmod_check_kfunc_ids) +BTF_KFUNCS_START(bpf_testmod_check_kfunc_ids) BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc) BTF_ID_FLAGS(func, bpf_kfunc_call_test1) BTF_ID_FLAGS(func, bpf_kfunc_call_test2) @@ -520,7 +520,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_ref, KF_TRUSTED_ARGS | KF_RCU) BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE) BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg) BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset) -BTF_SET8_END(bpf_testmod_check_kfunc_ids) +BTF_KFUNCS_END(bpf_testmod_check_kfunc_ids) static int bpf_testmod_ops_init(struct btf *btf) { From e79027c08302e299571555a9606b751820afa409 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 30 Jan 2024 08:43:27 -0700 Subject: [PATCH 0516/2255] selftests: Declare local variable for pause in fcnal-test.sh Running fcnal-test.sh script with -P argument is causing test failures: $ ./fcnal-test.sh -t ping -P TEST: ping out - ns-B IP [ OK ] hit enter to continue, 'q' to quit fcnal-test.sh: line 106: [: ping: integer expression expected TEST: out, [FAIL] expected rc ping; actual rc 0 hit enter to continue, 'q' to quit The test functions use local variable 'a' for addresses and then log_test is also using 'a' without a local declaration. Fix by declaring a local variable and using 'ans' (for answer) in the read. Signed-off-by: David Ahern Link: https://lore.kernel.org/r/20240130154327.33848-1-dsahern@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/fcnal-test.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index d7cfb7c2b427..386ebd829df5 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -100,6 +100,7 @@ log_test() local rc=$1 local expected=$2 local msg="$3" + local ans [ "${VERBOSE}" = "1" ] && echo @@ -113,16 +114,16 @@ log_test() if [ "${PAUSE_ON_FAIL}" = "yes" ]; then echo echo "hit enter to continue, 'q' to quit" - read a - [ "$a" = "q" ] && exit 1 + read ans + [ "$ans" = "q" ] && exit 1 fi fi if [ "${PAUSE}" = "yes" ]; then echo echo "hit enter to continue, 'q' to quit" - read a - [ "$a" = "q" ] && exit 1 + read ans + [ "$ans" = "q" ] && exit 1 fi kill_procs From e2ece0bc5ab1f7e0bb00f3b81fd4132b774d880d Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:46 +0000 Subject: [PATCH 0517/2255] tools/net/ynl: Add --output-json arg to ynl cli The ynl cli currently emits python pretty printed structures which is hard to consume. Add a new --output-json argument to emit JSON. Signed-off-by: Donald Hunter Reviewed-by: Breno Leitao Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-2-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/cli.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index 2ad9ec0f5545..0f8239979670 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -9,6 +9,15 @@ import time from lib import YnlFamily, Netlink +class YnlEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, bytes): + return bytes.hex(obj) + if isinstance(obj, set): + return list(obj) + return json.JSONEncoder.default(self, obj) + + def main(): parser = argparse.ArgumentParser(description='YNL CLI sample') parser.add_argument('--spec', dest='spec', type=str, required=True) @@ -28,8 +37,15 @@ def main(): parser.add_argument('--append', dest='flags', action='append_const', const=Netlink.NLM_F_APPEND) parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction) + parser.add_argument('--output-json', action='store_true') args = parser.parse_args() + def output(msg): + if args.output_json: + print(json.dumps(msg, cls=YnlEncoder)) + else: + pprint.PrettyPrinter().pprint(msg) + if args.no_schema: args.schema = '' @@ -47,14 +63,14 @@ def main(): if args.do: reply = ynl.do(args.do, attrs, args.flags) - pprint.PrettyPrinter().pprint(reply) + output(reply) if args.dump: reply = ynl.dump(args.dump, attrs) - pprint.PrettyPrinter().pprint(reply) + output(reply) if args.ntf: ynl.check_ntf() - pprint.PrettyPrinter().pprint(ynl.async_msg_queue) + output(ynl.async_msg_queue) if __name__ == "__main__": From bf8b832374fb85931acda478920e3a270f53bf17 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:47 +0000 Subject: [PATCH 0518/2255] tools/net/ynl: Support sub-messages in nested attribute spaces Sub-message selectors could only be resolved using values from the current nest level. Enable value lookup in outer scopes by using collections.ChainMap to implement an ordered lookup from nested to outer scopes. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-3-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 1e10512b2117..f24581759acf 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -405,6 +405,26 @@ class GenlProtocol(NetlinkProtocol): return self.genl_family['mcast'][mcast_name] + +class SpaceAttrs: + SpecValuesPair = namedtuple('SpecValuesPair', ['spec', 'values']) + + def __init__(self, attr_space, attrs, outer = None): + outer_scopes = outer.scopes if outer else [] + inner_scope = self.SpecValuesPair(attr_space, attrs) + self.scopes = [inner_scope] + outer_scopes + + def lookup(self, name): + for scope in self.scopes: + if name in scope.spec: + if name in scope.values: + return scope.values[name] + spec_name = scope.spec.yaml['name'] + raise Exception( + f"No value for '{name}' in attribute space '{spec_name}'") + raise Exception(f"Attribute '{name}' not defined in any attribute-set") + + # # YNL implementation details. # @@ -548,24 +568,22 @@ class YnlFamily(SpecFamily): else: rsp[name] = [decoded] - def _resolve_selector(self, attr_spec, vals): + def _resolve_selector(self, attr_spec, search_attrs): sub_msg = attr_spec.sub_message if sub_msg not in self.sub_msgs: raise Exception(f"No sub-message spec named {sub_msg} for {attr_spec.name}") sub_msg_spec = self.sub_msgs[sub_msg] selector = attr_spec.selector - if selector not in vals: - raise Exception(f"There is no value for {selector} to resolve '{attr_spec.name}'") - value = vals[selector] + value = search_attrs.lookup(selector) if value not in sub_msg_spec.formats: raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'") spec = sub_msg_spec.formats[value] return spec - def _decode_sub_msg(self, attr, attr_spec, rsp): - msg_format = self._resolve_selector(attr_spec, rsp) + def _decode_sub_msg(self, attr, attr_spec, search_attrs): + msg_format = self._resolve_selector(attr_spec, search_attrs) decoded = {} offset = 0 if msg_format.fixed_header: @@ -579,10 +597,12 @@ class YnlFamily(SpecFamily): raise Exception(f"Unknown attribute-set '{attr_space}' when decoding '{attr_spec.name}'") return decoded - def _decode(self, attrs, space): + def _decode(self, attrs, space, outer_attrs = None): if space: attr_space = self.attr_sets[space] rsp = dict() + search_attrs = SpaceAttrs(attr_space, rsp, outer_attrs) + for attr in attrs: try: attr_spec = attr_space.attrs_by_val[attr.type] @@ -594,7 +614,7 @@ class YnlFamily(SpecFamily): continue if attr_spec["type"] == 'nest': - subdict = self._decode(NlAttrs(attr.raw), attr_spec['nested-attributes']) + subdict = self._decode(NlAttrs(attr.raw), attr_spec['nested-attributes'], search_attrs) decoded = subdict elif attr_spec["type"] == 'string': decoded = attr.as_strz() @@ -617,7 +637,7 @@ class YnlFamily(SpecFamily): selector = self._decode_enum(selector, attr_spec) decoded = {"value": value, "selector": selector} elif attr_spec["type"] == 'sub-message': - decoded = self._decode_sub_msg(attr, attr_spec, rsp) + decoded = self._decode_sub_msg(attr, attr_spec, vals) else: if not self.process_unknown: raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') From 78d23416979500c749049d5d20bac457bcca2fb5 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:48 +0000 Subject: [PATCH 0519/2255] doc/netlink: Describe sub-message selector resolution Update the netlink-raw docs to add a description of sub-message selector resolution to explain that selector resolution is constrained by the spec. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-4-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/userspace-api/netlink/netlink-raw.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/userspace-api/netlink/netlink-raw.rst b/Documentation/userspace-api/netlink/netlink-raw.rst index 1e14f5f22b8e..32197f3cb40e 100644 --- a/Documentation/userspace-api/netlink/netlink-raw.rst +++ b/Documentation/userspace-api/netlink/netlink-raw.rst @@ -150,3 +150,11 @@ attributes from an ``attribute-set``. For example the following Note that a selector attribute must appear in a netlink message before any sub-message attributes that depend on it. + +If an attribute such as ``kind`` is defined at more than one nest level, then a +sub-message selector will be resolved using the value 'closest' to the selector. +For example, if the same attribute name is defined in a nested ``attribute-set`` +alongside a sub-message selector and also in a top level ``attribute-set``, then +the selector will be resolved using the value 'closest' to the selector. If the +value is not present in the message at the same level as defined in the spec +then this is an error. From 5f2823c48ad6f63fc033e8ec5e995fcd5cbab409 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:49 +0000 Subject: [PATCH 0520/2255] tools/net/ynl: Refactor fixed header encoding into separate method Refactor the fixed header encoding into a separate _encode_struct method so that it can be reused for fixed headers in sub-messages and for encoding structs. Signed-off-by: Donald Hunter Reviewed-by: Breno Leitao Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-5-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index f24581759acf..b22ddedb801b 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -720,6 +720,20 @@ class YnlFamily(SpecFamily): fixed_header_attrs[m.name] = value return fixed_header_attrs + def _encode_struct(self, name, vals): + members = self.consts[name].members + attr_payload = b'' + for m in members: + value = vals.pop(m.name) if m.name in vals else 0 + if m.type == 'pad': + attr_payload += bytearray(m.len) + elif m.type == 'binary': + attr_payload += bytes.fromhex(value) + else: + format = NlAttr.get_format(m.type, m.byte_order) + attr_payload += format.pack(value) + return attr_payload + def handle_ntf(self, decoded): msg = dict() if self.include_raw: @@ -779,18 +793,8 @@ class YnlFamily(SpecFamily): req_seq = random.randint(1024, 65535) msg = self.nlproto.message(nl_flags, op.req_value, 1, req_seq) - fixed_header_members = [] if op.fixed_header: - fixed_header_members = self.consts[op.fixed_header].members - for m in fixed_header_members: - value = vals.pop(m.name) if m.name in vals else 0 - if m.type == 'pad': - msg += bytearray(m.len) - elif m.type == 'binary': - msg += bytes.fromhex(value) - else: - format = NlAttr.get_format(m.type, m.byte_order) - msg += format.pack(value) + msg += self._encode_struct(op.fixed_header, vals) for name, value in vals.items(): msg += self._add_attr(op.attr_set.name, name, value) msg = _genl_msg_finalize(msg) From ab463c4342d1d14f25357c0f9f1a9744d7417edd Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:50 +0000 Subject: [PATCH 0521/2255] tools/net/ynl: Add support for encoding sub-messages Add sub-message encoding to ynl. This makes it possible to create tc qdiscs and other polymorphic netlink objects. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-6-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index b22ddedb801b..b063094e8a4b 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -469,7 +469,7 @@ class YnlFamily(SpecFamily): self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP, mcast_id) - def _add_attr(self, space, name, value): + def _add_attr(self, space, name, value, search_attrs): try: attr = self.attr_sets[space][name] except KeyError: @@ -478,8 +478,10 @@ class YnlFamily(SpecFamily): if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED attr_payload = b'' + sub_attrs = SpaceAttrs(self.attr_sets[space], value, search_attrs) for subname, subvalue in value.items(): - attr_payload += self._add_attr(attr['nested-attributes'], subname, subvalue) + attr_payload += self._add_attr(attr['nested-attributes'], + subname, subvalue, sub_attrs) elif attr["type"] == 'flag': attr_payload = b'' elif attr["type"] == 'string': @@ -489,6 +491,8 @@ class YnlFamily(SpecFamily): attr_payload = value elif isinstance(value, str): attr_payload = bytes.fromhex(value) + elif isinstance(value, dict) and attr.struct_name: + attr_payload = self._encode_struct(attr.struct_name, value) else: raise Exception(f'Unknown type for binary attribute, value: {value}') elif attr.is_auto_scalar: @@ -501,6 +505,20 @@ class YnlFamily(SpecFamily): attr_payload = format.pack(int(value)) elif attr['type'] in "bitfield32": attr_payload = struct.pack("II", int(value["value"]), int(value["selector"])) + elif attr['type'] == 'sub-message': + msg_format = self._resolve_selector(attr, search_attrs) + attr_payload = b'' + if msg_format.fixed_header: + attr_payload += self._encode_struct(msg_format.fixed_header, value) + if msg_format.attr_set: + if msg_format.attr_set in self.attr_sets: + nl_type |= Netlink.NLA_F_NESTED + sub_attrs = SpaceAttrs(msg_format.attr_set, value, search_attrs) + for subname, subvalue in value.items(): + attr_payload += self._add_attr(msg_format.attr_set, + subname, subvalue, sub_attrs) + else: + raise Exception(f"Unknown attribute-set '{msg_format.attr_set}'") else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') @@ -637,7 +655,7 @@ class YnlFamily(SpecFamily): selector = self._decode_enum(selector, attr_spec) decoded = {"value": value, "selector": selector} elif attr_spec["type"] == 'sub-message': - decoded = self._decode_sub_msg(attr, attr_spec, vals) + decoded = self._decode_sub_msg(attr, attr_spec, search_attrs) else: if not self.process_unknown: raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') @@ -795,8 +813,9 @@ class YnlFamily(SpecFamily): msg = self.nlproto.message(nl_flags, op.req_value, 1, req_seq) if op.fixed_header: msg += self._encode_struct(op.fixed_header, vals) + search_attrs = SpaceAttrs(op.attr_set, vals) for name, value in vals.items(): - msg += self._add_attr(op.attr_set.name, name, value) + msg += self._add_attr(op.attr_set.name, name, value, search_attrs) msg = _genl_msg_finalize(msg) self.sock.send(msg, 0) From a387a921139e07587b0fb93c9c0fec8b6800776d Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:51 +0000 Subject: [PATCH 0522/2255] tools/net/ynl: Encode default values for binary blobs Add support for defaulting binary byte arrays to all zeros as well as defaulting scalar values to 0 when encoding input parameters. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-7-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index b063094e8a4b..d04435f26f89 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -742,12 +742,17 @@ class YnlFamily(SpecFamily): members = self.consts[name].members attr_payload = b'' for m in members: - value = vals.pop(m.name) if m.name in vals else 0 + value = vals.pop(m.name) if m.name in vals else None if m.type == 'pad': attr_payload += bytearray(m.len) elif m.type == 'binary': - attr_payload += bytes.fromhex(value) + if value is None: + attr_payload += bytearray(m.len) + else: + attr_payload += bytes.fromhex(value) else: + if value is None: + value = 0 format = NlAttr.get_format(m.type, m.byte_order) attr_payload += format.pack(value) return attr_payload From e45fee0f49fcbafe9f0f883ef22afb890504a5e6 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:52 +0000 Subject: [PATCH 0523/2255] tools/net/ynl: Combine struct decoding logic in ynl _decode_fixed_header() and NlAttr.as_struct() both implemented struct decoding logic. Deduplicate the code into newly named _decode_struct() method. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-8-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 47 ++++++++++++---------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index d04435f26f89..0e7e9f60ab7e 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -148,23 +148,6 @@ class NlAttr: format = self.get_format(type) return [ x[0] for x in format.iter_unpack(self.raw) ] - def as_struct(self, members): - value = dict() - offset = 0 - for m in members: - # TODO: handle non-scalar members - if m.type == 'binary': - decoded = self.raw[offset : offset + m['len']] - offset += m['len'] - elif m.type in NlAttr.type_formats: - format = self.get_format(m.type, m.byte_order) - [ decoded ] = format.unpack_from(self.raw, offset) - offset += format.size - if m.display_hint: - decoded = self.formatted_string(decoded, m.display_hint) - value[m.name] = decoded - return value - def __repr__(self): return f"[type:{self.type} len:{self._len}] {self.raw}" @@ -541,11 +524,7 @@ class YnlFamily(SpecFamily): def _decode_binary(self, attr, attr_spec): if attr_spec.struct_name: - members = self.consts[attr_spec.struct_name] - decoded = attr.as_struct(members) - for m in members: - if m.enum: - decoded[m.name] = self._decode_enum(decoded[m.name], m) + decoded = self._decode_struct(attr.raw, attr_spec.struct_name) elif attr_spec.sub_type: decoded = attr.as_c_array(attr_spec.sub_type) else: @@ -605,7 +584,7 @@ class YnlFamily(SpecFamily): decoded = {} offset = 0 if msg_format.fixed_header: - decoded.update(self._decode_fixed_header(attr, msg_format.fixed_header)); + decoded.update(self._decode_struct(attr.raw, msg_format.fixed_header)); offset = self._fixed_header_size(msg_format.fixed_header) if msg_format.attr_set: if msg_format.attr_set in self.attr_sets: @@ -717,26 +696,28 @@ class YnlFamily(SpecFamily): else: return 0 - def _decode_fixed_header(self, msg, name): - fixed_header_members = self.consts[name].members - fixed_header_attrs = dict() + def _decode_struct(self, data, name): + members = self.consts[name].members + attrs = dict() offset = 0 - for m in fixed_header_members: + for m in members: value = None if m.type == 'pad': offset += m.len elif m.type == 'binary': - value = msg.raw[offset : offset + m.len] + value = data[offset : offset + m.len] offset += m.len else: format = NlAttr.get_format(m.type, m.byte_order) - [ value ] = format.unpack_from(msg.raw, offset) + [ value ] = format.unpack_from(data, offset) offset += format.size if value is not None: if m.enum: value = self._decode_enum(value, m) - fixed_header_attrs[m.name] = value - return fixed_header_attrs + elif m.display_hint: + value = NlAttr.formatted_string(value, m.display_hint) + attrs[m.name] = value + return attrs def _encode_struct(self, name, vals): members = self.consts[name].members @@ -764,7 +745,7 @@ class YnlFamily(SpecFamily): op = self.rsp_by_value[decoded.cmd()] attrs = self._decode(decoded.raw_attrs, op.attr_set.name) if op.fixed_header: - attrs.update(self._decode_fixed_header(decoded, op.fixed_header)) + attrs.update(self._decode_struct(decoded.raw, op.fixed_header)) msg['name'] = op['name'] msg['msg'] = attrs @@ -856,7 +837,7 @@ class YnlFamily(SpecFamily): rsp_msg = self._decode(decoded.raw_attrs, op.attr_set.name) if op.fixed_header: - rsp_msg.update(self._decode_fixed_header(decoded, op.fixed_header)) + rsp_msg.update(self._decode_struct(decoded.raw, op.fixed_header)) rsp.append(rsp_msg) if not rsp: From 886365cf40b2b53864f1ef0655fe7999c2477418 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:53 +0000 Subject: [PATCH 0524/2255] tools/net/ynl: Rename _fixed_header_size() to _struct_size() Refactor the _fixed_header_size() method to be _struct_size() so that naming is consistent with _encode_struct() and _decode_struct(). Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-9-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 0e7e9f60ab7e..173ef4489e38 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -353,7 +353,7 @@ class NetlinkProtocol: fixed_header_size = 0 if ynl: op = ynl.rsp_by_value[msg.cmd()] - fixed_header_size = ynl._fixed_header_size(op.fixed_header) + fixed_header_size = ynl._struct_size(op.fixed_header) msg.raw_attrs = NlAttrs(msg.raw, fixed_header_size) return msg @@ -585,7 +585,7 @@ class YnlFamily(SpecFamily): offset = 0 if msg_format.fixed_header: decoded.update(self._decode_struct(attr.raw, msg_format.fixed_header)); - offset = self._fixed_header_size(msg_format.fixed_header) + offset = self._struct_size(msg_format.fixed_header) if msg_format.attr_set: if msg_format.attr_set in self.attr_sets: subdict = self._decode(NlAttrs(attr.raw, offset), msg_format.attr_set) @@ -675,18 +675,18 @@ class YnlFamily(SpecFamily): return msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set)) - offset = 20 + self._fixed_header_size(op.fixed_header) + offset = 20 + self._struct_size(op.fixed_header) path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset, extack['bad-attr-offs']) if path: del extack['bad-attr-offs'] extack['bad-attr'] = path - def _fixed_header_size(self, name): + def _struct_size(self, name): if name: - fixed_header_members = self.consts[name].members + members = self.consts[name].members size = 0 - for m in fixed_header_members: + for m in members: if m.type in ['pad', 'binary']: size += m.len else: From 971c3eeaf668ed312d032d12becb106982d2b2bd Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:54 +0000 Subject: [PATCH 0525/2255] tools/net/ynl: Move formatted_string method out of NlAttr The formatted_string() class method was in NlAttr so that it could be accessed by NlAttr.as_struct(). Now that as_struct() has been removed, move formatted_string() to YnlFamily as an internal helper method. Signed-off-by: Donald Hunter Reviewed-by: Breno Leitao Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-10-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 173ef4489e38..2b0ca61deaf8 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -113,20 +113,6 @@ class NlAttr: else format.little return format.native - @classmethod - def formatted_string(cls, raw, display_hint): - if display_hint == 'mac': - formatted = ':'.join('%02x' % b for b in raw) - elif display_hint == 'hex': - formatted = bytes.hex(raw, ' ') - elif display_hint in [ 'ipv4', 'ipv6' ]: - formatted = format(ipaddress.ip_address(raw)) - elif display_hint == 'uuid': - formatted = str(uuid.UUID(bytes=raw)) - else: - formatted = raw - return formatted - def as_scalar(self, attr_type, byte_order=None): format = self.get_format(attr_type, byte_order) return format.unpack(self.raw)[0] @@ -530,7 +516,7 @@ class YnlFamily(SpecFamily): else: decoded = attr.as_bin() if attr_spec.display_hint: - decoded = NlAttr.formatted_string(decoded, attr_spec.display_hint) + decoded = self._formatted_string(decoded, attr_spec.display_hint) return decoded def _decode_array_nest(self, attr, attr_spec): @@ -715,7 +701,7 @@ class YnlFamily(SpecFamily): if m.enum: value = self._decode_enum(value, m) elif m.display_hint: - value = NlAttr.formatted_string(value, m.display_hint) + value = self._formatted_string(value, m.display_hint) attrs[m.name] = value return attrs @@ -738,6 +724,19 @@ class YnlFamily(SpecFamily): attr_payload += format.pack(value) return attr_payload + def _formatted_string(self, raw, display_hint): + if display_hint == 'mac': + formatted = ':'.join('%02x' % b for b in raw) + elif display_hint == 'hex': + formatted = bytes.hex(raw, ' ') + elif display_hint in [ 'ipv4', 'ipv6' ]: + formatted = format(ipaddress.ip_address(raw)) + elif display_hint == 'uuid': + formatted = str(uuid.UUID(bytes=raw)) + else: + formatted = raw + return formatted + def handle_ntf(self, decoded): msg = dict() if self.include_raw: From bf08f32c8cedb12a23efcdc2c9584601d7030e16 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:55 +0000 Subject: [PATCH 0526/2255] tools/net/ynl: Add support for nested structs Make it possible for struct definitions to reference other struct definitions ofr binary members. For example, the tbf qdisc uses this struct definition for its parms attribute: - name: tc-tbf-qopt type: struct members: - name: rate type: binary struct: tc-ratespec - name: peakrate type: binary struct: tc-ratespec - name: limit type: u32 - name: buffer type: u32 - name: mtu type: u32 This adds the necessary schema changes and adds nested struct encoding and decoding to ynl. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-11-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/netlink-raw.yaml | 15 ++++++++++++--- tools/net/ynl/lib/nlspec.py | 2 ++ tools/net/ynl/lib/ynl.py | 26 ++++++++++++++++++++------ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml index 04b92f1a5cd6..ac4e05415f2f 100644 --- a/Documentation/netlink/netlink-raw.yaml +++ b/Documentation/netlink/netlink-raw.yaml @@ -152,14 +152,23 @@ properties: the right formatting mechanism when displaying values of this type. enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + struct: + description: Name of the nested struct type. + type: string if: properties: type: - oneOf: - - const: binary - - const: pad + const: pad then: required: [ len ] + if: + properties: + type: + const: binary + then: + oneOf: + - required: [ len ] + - required: [ struct ] # End genetlink-legacy attribute-sets: diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 44f13e383e8a..5d197a12ab8d 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -248,6 +248,7 @@ class SpecStructMember(SpecElement): len integer, optional byte length of binary types display_hint string, hint to help choose format specifier when displaying the value + struct string, name of nested struct type """ def __init__(self, family, yaml): super().__init__(family, yaml) @@ -256,6 +257,7 @@ class SpecStructMember(SpecElement): self.enum = yaml.get('enum') self.len = yaml.get('len') self.display_hint = yaml.get('display-hint') + self.struct = yaml.get('struct') class SpecStruct(SpecElement): diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 2b0ca61deaf8..0f4193cc2e3b 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -674,7 +674,10 @@ class YnlFamily(SpecFamily): size = 0 for m in members: if m.type in ['pad', 'binary']: - size += m.len + if m.struct: + size += self._struct_size(m.struct) + else: + size += m.len else: format = NlAttr.get_format(m.type, m.byte_order) size += format.size @@ -691,8 +694,14 @@ class YnlFamily(SpecFamily): if m.type == 'pad': offset += m.len elif m.type == 'binary': - value = data[offset : offset + m.len] - offset += m.len + if m.struct: + len = self._struct_size(m.struct) + value = self._decode_struct(data[offset : offset + len], + m.struct) + offset += len + else: + value = data[offset : offset + m.len] + offset += m.len else: format = NlAttr.get_format(m.type, m.byte_order) [ value ] = format.unpack_from(data, offset) @@ -713,10 +722,15 @@ class YnlFamily(SpecFamily): if m.type == 'pad': attr_payload += bytearray(m.len) elif m.type == 'binary': - if value is None: - attr_payload += bytearray(m.len) + if m.struct: + if value is None: + value = dict() + attr_payload += self._encode_struct(m.struct, value) else: - attr_payload += bytes.fromhex(value) + if value is None: + attr_payload += bytearray(m.len) + else: + attr_payload += bytes.fromhex(value) else: if value is None: value = 0 From 9d6429c33976fcce0d46124a9151314137687e0f Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:56 +0000 Subject: [PATCH 0527/2255] doc/netlink: Describe nested structs in netlink raw docs Add a description and example of nested struct definitions to the netlink raw documentation. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-12-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- .../userspace-api/netlink/netlink-raw.rst | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/userspace-api/netlink/netlink-raw.rst b/Documentation/userspace-api/netlink/netlink-raw.rst index 32197f3cb40e..1990eea772d0 100644 --- a/Documentation/userspace-api/netlink/netlink-raw.rst +++ b/Documentation/userspace-api/netlink/netlink-raw.rst @@ -158,3 +158,37 @@ alongside a sub-message selector and also in a top level ``attribute-set``, then the selector will be resolved using the value 'closest' to the selector. If the value is not present in the message at the same level as defined in the spec then this is an error. + +Nested struct definitions +------------------------- + +Many raw netlink families such as :doc:`tc<../../networking/netlink_spec/tc>` +make use of nested struct definitions. The ``netlink-raw`` schema makes it +possible to embed a struct within a struct definition using the ``struct`` +property. For example, the following struct definition embeds the +``tc-ratespec`` struct definition for both the ``rate`` and the ``peakrate`` +members of ``struct tc-tbf-qopt``. + +.. code-block:: yaml + + - + name: tc-tbf-qopt + type: struct + members: + - + name: rate + type: binary + struct: tc-ratespec + - + name: peakrate + type: binary + struct: tc-ratespec + - + name: limit + type: u32 + - + name: buffer + type: u32 + - + name: mtu + type: u32 From fe09ae5fb93be371a72d1b2ac62fb3eead51a728 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:57 +0000 Subject: [PATCH 0528/2255] tools/net/ynl: Add type info to struct members in generated docs Extend the ynl doc generator to include type information for struct members, ignoring the pad type. Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-13-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-rst.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/ynl-gen-rst.py b/tools/net/ynl/ynl-gen-rst.py index 262d88f88696..927407b3efb3 100755 --- a/tools/net/ynl/ynl-gen-rst.py +++ b/tools/net/ynl/ynl-gen-rst.py @@ -189,12 +189,19 @@ def parse_operations(operations: List[Dict[str, Any]]) -> str: def parse_entries(entries: List[Dict[str, Any]], level: int) -> str: """Parse a list of entries""" + ignored = ["pad"] lines = [] for entry in entries: if isinstance(entry, dict): # entries could be a list or a dictionary + field_name = entry.get("name", "") + if field_name in ignored: + continue + type_ = entry.get("type") + if type_: + field_name += f" ({inline(type_)})" lines.append( - rst_fields(entry.get("name", ""), sanitize(entry.get("doc", "")), level) + rst_fields(field_name, sanitize(entry.get("doc", "")), level) ) elif isinstance(entry, list): lines.append(rst_list_inline(entry, level)) From 2267672a6190cfb0349e95a70e09dc6a973007c1 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:58 +0000 Subject: [PATCH 0529/2255] doc/netlink/specs: Update the tc spec Fill in many of the gaps in the tc netlink spec, including stats attrs, classes and actions. Many documentation strings have also been added. This is still a work in progress, albeit fairly complete: - there are still many attributes left as binary blobs. - actions have not had much testing Signed-off-by: Donald Hunter Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-14-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/tc.yaml | 2134 +++++++++++++++++++++++++-- 1 file changed, 2025 insertions(+), 109 deletions(-) diff --git a/Documentation/netlink/specs/tc.yaml b/Documentation/netlink/specs/tc.yaml index 4346fa402fc9..4b21b00dbebe 100644 --- a/Documentation/netlink/specs/tc.yaml +++ b/Documentation/netlink/specs/tc.yaml @@ -48,21 +48,28 @@ definitions: - name: bytes type: u64 + doc: Number of enqueued bytes - name: packets type: u32 + doc: Number of enqueued packets - name: drops type: u32 + doc: Packets dropped because of lack of resources - name: overlimits type: u32 + doc: | + Number of throttle events when this flow goes out of allocated bandwidth - name: bps type: u32 + doc: Current flow byte rate - name: pps type: u32 + doc: Current flow packet rate - name: qlen type: u32 @@ -112,6 +119,7 @@ definitions: - name: limit type: u32 + doc: Queue length; bytes for bfifo, packets for pfifo - name: tc-htb-opt type: struct @@ -119,11 +127,11 @@ definitions: - name: rate type: binary - len: 12 + struct: tc-ratespec - name: ceil type: binary - len: 12 + struct: tc-ratespec - name: buffer type: u32 @@ -149,15 +157,19 @@ definitions: - name: rate2quantum type: u32 + doc: bps->quantum divisor - name: defcls type: u32 + doc: Default class number - name: debug type: u32 + doc: Debug flags - name: direct-pkts type: u32 + doc: Count of non shaped packets - name: tc-gred-qopt type: struct @@ -165,15 +177,19 @@ definitions: - name: limit type: u32 + doc: HARD maximal queue length in bytes - name: qth-min type: u32 + doc: Min average length threshold in bytes - name: qth-max type: u32 + doc: Max average length threshold in bytes - name: DP type: u32 + doc: Up to 2^32 DPs - name: backlog type: u32 @@ -195,15 +211,19 @@ definitions: - name: Wlog type: u8 + doc: log(W) - name: Plog type: u8 + doc: log(P_max / (qth-max - qth-min)) - name: Scell_log type: u8 + doc: cell size for idle damping - name: prio type: u8 + doc: Priority of this VQ - name: packets type: u32 @@ -266,9 +286,11 @@ definitions: - name: bands type: u16 + doc: Number of bands - name: max-bands type: u16 + doc: Maximum number of queues - name: tc-netem-qopt type: struct @@ -276,21 +298,138 @@ definitions: - name: latency type: u32 + doc: Added delay in microseconds - name: limit type: u32 + doc: Fifo limit in packets - name: loss type: u32 + doc: Random packet loss (0=none, ~0=100%) - name: gap type: u32 + doc: Re-ordering gap (0 for none) - name: duplicate type: u32 + doc: Random packet duplication (0=none, ~0=100%) - name: jitter type: u32 + doc: Random jitter latency in microseconds + - + name: tc-netem-gimodel + doc: State transition probabilities for 4 state model + type: struct + members: + - + name: p13 + type: u32 + - + name: p31 + type: u32 + - + name: p32 + type: u32 + - + name: p14 + type: u32 + - + name: p23 + type: u32 + - + name: tc-netem-gemodel + doc: Gilbert-Elliot models + type: struct + members: + - + name: p + type: u32 + - + name: r + type: u32 + - + name: h + type: u32 + - + name: k1 + type: u32 + - + name: tc-netem-corr + type: struct + members: + - + name: delay-corr + type: u32 + doc: Delay correlation + - + name: loss-corr + type: u32 + doc: Packet loss correlation + - + name: dup-corr + type: u32 + doc: Duplicate correlation + - + name: tc-netem-reorder + type: struct + members: + - + name: probability + type: u32 + - + name: correlation + type: u32 + - + name: tc-netem-corrupt + type: struct + members: + - + name: probability + type: u32 + - + name: correlation + type: u32 + - + name: tc-netem-rate + type: struct + members: + - + name: rate + type: u32 + - + name: packet-overhead + type: s32 + - + name: cell-size + type: u32 + - + name: cell-overhead + type: s32 + - + name: tc-netem-slot + type: struct + members: + - + name: min-delay + type: s64 + - + name: max-delay + type: s64 + - + name: max-packets + type: s32 + - + name: max-bytes + type: s32 + - + name: dist-delay + type: s64 + - + name: dist-jitter + type: s64 - name: tc-plug-qopt type: struct @@ -307,11 +446,13 @@ definitions: members: - name: bands - type: u16 + type: u32 + doc: Number of bands - name: priomap type: binary len: 16 + doc: Map of logical priority -> PRIO band - name: tc-red-qopt type: struct @@ -319,21 +460,27 @@ definitions: - name: limit type: u32 + doc: Hard queue length in packets - name: qth-min type: u32 + doc: Min average threshold in packets - name: qth-max type: u32 + doc: Max average threshold in packets - name: Wlog type: u8 + doc: log(W) - name: Plog type: u8 + doc: log(P_max / (qth-max - qth-min)) - name: Scell-log type: u8 + doc: Cell size for idle damping - name: flags type: u8 @@ -369,71 +516,128 @@ definitions: name: penalty-burst type: u32 - - name: tc-sfq-qopt-v1 # TODO nested structs + name: tc-sfq-qopt type: struct members: - name: quantum type: u32 + doc: Bytes per round allocated to flow - name: perturb-period type: s32 + doc: Period of hash perturbation - name: limit type: u32 + doc: Maximal packets in queue - name: divisor type: u32 + doc: Hash divisor - name: flows type: u32 + doc: Maximal number of flows + - + name: tc-sfqred-stats + type: struct + members: + - + name: prob-drop + type: u32 + doc: Early drops, below max threshold + - + name: forced-drop + type: u32 + doc: Early drops, after max threshold + - + name: prob-mark + type: u32 + doc: Marked packets, below max threshold + - + name: forced-mark + type: u32 + doc: Marked packets, after max threshold + - + name: prob-mark-head + type: u32 + doc: Marked packets, below max threshold + - + name: forced-mark-head + type: u32 + doc: Marked packets, after max threshold + - + name: tc-sfq-qopt-v1 + type: struct + members: + - + name: v0 + type: binary + struct: tc-sfq-qopt - name: depth type: u32 + doc: Maximum number of packets per flow - name: headdrop type: u32 - name: limit type: u32 + doc: HARD maximal flow queue length in bytes - name: qth-min type: u32 + doc: Min average length threshold in bytes - - name: qth-mac + name: qth-max type: u32 + doc: Max average length threshold in bytes - name: Wlog type: u8 + doc: log(W) - name: Plog type: u8 + doc: log(P_max / (qth-max - qth-min)) - name: Scell-log type: u8 + doc: Cell size for idle damping - name: flags type: u8 - name: max-P type: u32 + doc: probabilty, high resolution - - name: prob-drop - type: u32 + name: stats + type: binary + struct: tc-sfqred-stats + - + name: tc-ratespec + type: struct + members: - - name: forced-drop - type: u32 + name: cell-log + type: u8 - - name: prob-mark - type: u32 + name: linklayer + type: u8 - - name: forced-mark - type: u32 + name: overhead + type: u8 - - name: prob-mark-head - type: u32 + name: cell-align + type: u8 - - name: forced-mark-head + name: mpu + type: u8 + - + name: rate type: u32 - name: tc-tbf-qopt @@ -441,12 +645,12 @@ definitions: members: - name: rate - type: binary # TODO nested struct tc_ratespec - len: 12 + type: binary + struct: tc-ratespec - name: peakrate - type: binary # TODO nested struct tc_ratespec - len: 12 + type: binary + struct: tc-ratespec - name: limit type: u32 @@ -491,9 +695,663 @@ definitions: - name: interval type: s8 + doc: Sampling period - name: ewma-log type: u8 + doc: The log() of measurement window weight + - + name: tc-choke-xstats + type: struct + members: + - + name: early + type: u32 + doc: Early drops + - + name: pdrop + type: u32 + doc: Drops due to queue limits + - + name: other + type: u32 + doc: Drops due to drop() calls + - + name: marked + type: u32 + doc: Marked packets + - + name: matched + type: u32 + doc: Drops due to flow match + - + name: tc-codel-xstats + type: struct + members: + - + name: maxpacket + type: u32 + doc: Largest packet we've seen so far + - + name: count + type: u32 + doc: How many drops we've done since the last time we entered dropping state + - + name: lastcount + type: u32 + doc: Count at entry to dropping state + - + name: ldelay + type: u32 + doc: in-queue delay seen by most recently dequeued packet + - + name: drop-next + type: s32 + doc: Time to drop next packet + - + name: drop-overlimit + type: u32 + doc: Number of times max qdisc packet limit was hit + - + name: ecn-mark + type: u32 + doc: Number of packets we've ECN marked instead of dropped + - + name: dropping + type: u32 + doc: Are we in a dropping state? + - + name: ce-mark + type: u32 + doc: Number of CE marked packets because of ce-threshold + - + name: tc-fq-codel-xstats + type: struct + members: + - + name: type + type: u32 + - + name: maxpacket + type: u32 + doc: Largest packet we've seen so far + - + name: drop-overlimit + type: u32 + doc: Number of times max qdisc packet limit was hit + - + name: ecn-mark + type: u32 + doc: Number of packets we ECN marked instead of being dropped + - + name: new-flow-count + type: u32 + doc: Number of times packets created a new flow + - + name: new-flows-len + type: u32 + doc: Count of flows in new list + - + name: old-flows-len + type: u32 + doc: Count of flows in old list + - + name: ce-mark + type: u32 + doc: Packets above ce-threshold + - + name: memory-usage + type: u32 + doc: Memory usage in bytes + - + name: drop-overmemory + type: u32 + - + name: tc-fq-pie-xstats + type: struct + members: + - + name: packets-in + type: u32 + doc: Total number of packets enqueued + - + name: dropped + type: u32 + doc: Packets dropped due to fq_pie_action + - + name: overlimit + type: u32 + doc: Dropped due to lack of space in queue + - + name: overmemory + type: u32 + doc: Dropped due to lack of memory in queue + - + name: ecn-mark + type: u32 + doc: Packets marked with ecn + - + name: new-flow-count + type: u32 + doc: Count of new flows created by packets + - + name: new-flows-len + type: u32 + doc: Count of flows in new list + - + name: old-flows-len + type: u32 + doc: Count of flows in old list + - + name: memory-usage + type: u32 + doc: Total memory across all queues + - + name: tc-fq-qd-stats + type: struct + members: + - + name: gc-flows + type: u64 + - + name: highprio-packets + type: u64 + doc: obsolete + - + name: tcp-retrans + type: u64 + doc: obsolete + - + name: throttled + type: u64 + - + name: flows-plimit + type: u64 + - + name: pkts-too-long + type: u64 + - + name: allocation-errors + type: u64 + - + name: time-next-delayed-flow + type: s64 + - + name: flows + type: u32 + - + name: inactive-flows + type: u32 + - + name: throttled-flows + type: u32 + - + name: unthrottle-latency-ns + type: u32 + - + name: ce-mark + type: u64 + doc: Packets above ce-threshold + - + name: horizon-drops + type: u64 + - + name: horizon-caps + type: u64 + - + name: fastpath-packets + type: u64 + - + name: band-drops + type: binary + len: 24 + - + name: band-pkt-count + type: binary + len: 12 + - + name: pad + type: pad + len: 4 + - + name: tc-hhf-xstats + type: struct + members: + - + name: drop-overlimit + type: u32 + doc: Number of times max qdisc packet limit was hit + - + name: hh-overlimit + type: u32 + doc: Number of times max heavy-hitters was hit + - + name: hh-tot-count + type: u32 + doc: Number of captured heavy-hitters so far + - + name: hh-cur-count + type: u32 + doc: Number of current heavy-hitters + - + name: tc-pie-xstats + type: struct + members: + - + name: prob + type: u64 + doc: Current probability + - + name: delay + type: u32 + doc: Current delay in ms + - + name: avg-dq-rate + type: u32 + doc: Current average dq rate in bits/pie-time + - + name: dq-rate-estimating + type: u32 + doc: Is avg-dq-rate being calculated? + - + name: packets-in + type: u32 + doc: Total number of packets enqueued + - + name: dropped + type: u32 + doc: Packets dropped due to pie action + - + name: overlimit + type: u32 + doc: Dropped due to lack of space in queue + - + name: maxq + type: u32 + doc: Maximum queue size + - + name: ecn-mark + type: u32 + doc: Packets marked with ecn + - + name: tc-red-xstats + type: struct + members: + - + name: early + type: u32 + doc: Early drops + - + name: pdrop + type: u32 + doc: Drops due to queue limits + - + name: other + type: u32 + doc: Drops due to drop() calls + - + name: marked + type: u32 + doc: Marked packets + - + name: tc-sfb-xstats + type: struct + members: + - + name: earlydrop + type: u32 + - + name: penaltydrop + type: u32 + - + name: bucketdrop + type: u32 + - + name: queuedrop + type: u32 + - + name: childdrop + type: u32 + doc: drops in child qdisc + - + name: marked + type: u32 + - + name: maxqlen + type: u32 + - + name: maxprob + type: u32 + - + name: avgprob + type: u32 + - + name: tc-sfq-xstats + type: struct + members: + - + name: allot + type: s32 + - + name: gnet-stats-basic + type: struct + members: + - + name: bytes + type: u64 + - + name: packets + type: u32 + - + name: gnet-stats-rate-est + type: struct + members: + - + name: bps + type: u32 + - + name: pps + type: u32 + - + name: gnet-stats-rate-est64 + type: struct + members: + - + name: bps + type: u64 + - + name: pps + type: u64 + - + name: gnet-stats-queue + type: struct + members: + - + name: qlen + type: u32 + - + name: backlog + type: u32 + - + name: drops + type: u32 + - + name: requeues + type: u32 + - + name: overlimits + type: u32 + - + name: tc-u32-key + type: struct + members: + - + name: mask + type: u32 + byte-order: big-endian + - + name: val + type: u32 + byte-order: big-endian + - + name: "off" + type: s32 + - + name: offmask + type: s32 + - + name: tc-u32-sel + type: struct + members: + - + name: flags + type: u8 + - + name: offshift + type: u8 + - + name: nkeys + type: u8 + - + name: offmask + type: u16 + byte-order: big-endian + - + name: "off" + type: u16 + - + name: offoff + type: s16 + - + name: hoff + type: s16 + - + name: hmask + type: u32 + byte-order: big-endian + - + name: keys + type: binary + struct: tc-u32-key # TODO: array + - + name: tc-u32-pcnt + type: struct + members: + - + name: rcnt + type: u64 + - + name: rhit + type: u64 + - + name: kcnts + type: u64 # TODO: array + - + name: tcf-t + type: struct + members: + - + name: install + type: u64 + - + name: lastuse + type: u64 + - + name: expires + type: u64 + - + name: firstuse + type: u64 + - + name: tc-gen + type: struct + members: + - + name: index + type: u32 + - + name: capab + type: u32 + - + name: action + type: s32 + - + name: refcnt + type: s32 + - + name: bindcnt + type: s32 + - + name: tc-gact-p + type: struct + members: + - + name: ptype + type: u16 + - + name: pval + type: u16 + - + name: paction + type: s32 + - + name: tcf-ematch-tree-hdr + type: struct + members: + - + name: nmatches + type: u16 + - + name: progid + type: u16 + - + name: tc-basic-pcnt + type: struct + members: + - + name: rcnt + type: u64 + - + name: rhit + type: u64 + - + name: tc-matchall-pcnt + type: struct + members: + - + name: rhit + type: u64 + - + name: tc-mpls + type: struct + members: + - + name: index + type: u32 + - + name: capab + type: u32 + - + name: action + type: s32 + - + name: refcnt + type: s32 + - + name: bindcnt + type: s32 + - + name: m-action + type: s32 + - + name: tc-police + type: struct + members: + - + name: index + type: u32 + - + name: action + type: s32 + - + name: limit + type: u32 + - + name: burst + type: u32 + - + name: mtu + type: u32 + - + name: rate + type: binary + struct: tc-ratespec + - + name: peakrate + type: binary + struct: tc-ratespec + - + name: refcnt + type: s32 + - + name: bindcnt + type: s32 + - + name: capab + type: u32 + - + name: tc-pedit-sel + type: struct + members: + - + name: index + type: u32 + - + name: capab + type: u32 + - + name: action + type: s32 + - + name: refcnt + type: s32 + - + name: bindcnt + type: s32 + - + name: nkeys + type: u8 + - + name: flags + type: u8 + - + name: keys + type: binary + struct: tc-pedit-key # TODO: array + - + name: tc-pedit-key + type: struct + members: + - + name: mask + type: u32 + - + name: val + type: u32 + - + name: "off" + type: u32 + - + name: at + type: u32 + - + name: offmask + type: u32 + - + name: shift + type: u32 + - + name: tc-vlan + type: struct + members: + - + name: index + type: u32 + - + name: capab + type: u32 + - + name: action + type: s32 + - + name: refcnt + type: s32 + - + name: bindcnt + type: s32 + - + name: v-action + type: s32 attribute-sets: - name: tc-attrs @@ -512,7 +1370,9 @@ attribute-sets: struct: tc-stats - name: xstats - type: binary + type: sub-message + sub-message: tca-stats-app-msg + selector: kind - name: rate type: binary @@ -552,6 +1412,582 @@ attribute-sets: - name: ext-warn-msg type: string + - + name: tc-act-attrs + attributes: + - + name: kind + type: string + - + name: options + type: sub-message + sub-message: tc-act-options-msg + selector: kind + - + name: index + type: u32 + - + name: stats + type: nest + nested-attributes: tc-act-stats-attrs + - + name: pad + type: pad + - + name: cookie + type: binary + - + name: flags + type: bitfield32 + - + name: hw-stats + type: bitfield32 + - + name: used-hw-stats + type: bitfield32 + - + name: in-hw-count + type: u32 + - + name: tc-act-stats-attrs + attributes: + - + name: basic + type: binary + struct: gnet-stats-basic + - + name: rate-est + type: binary + struct: gnet-stats-rate-est + - + name: queue + type: binary + struct: gnet-stats-queue + - + name: app + type: binary + - + name: rate-est64 + type: binary + struct: gnet-stats-rate-est64 + - + name: pad + type: pad + - + name: basic-hw + type: binary + struct: gnet-stats-basic + - + name: pkt64 + type: u64 + - + name: tc-act-bpf-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + - + name: ops-len + type: u16 + - + name: ops + type: binary + - + name: fd + type: u32 + - + name: name + type: string + - + name: pad + type: pad + - + name: tag + type: binary + - + name: id + type: binary + - + name: tc-act-connmark-attrs + attributes: + - + name: parms + type: binary + - + name: tm + type: binary + struct: tcf-t + - + name: pad + type: pad + - + name: tc-act-csum-attrs + attributes: + - + name: parms + type: binary + - + name: tm + type: binary + struct: tcf-t + - + name: pad + type: pad + - + name: tc-act-ct-attrs + attributes: + - + name: parms + type: binary + - + name: tm + type: binary + struct: tcf-t + - + name: action + type: u16 + - + name: zone + type: u16 + - + name: mark + type: u32 + - + name: mark-mask + type: u32 + - + name: labels + type: binary + - + name: labels-mask + type: binary + - + name: nat-ipv4-min + type: u32 + byte-order: big-endian + - + name: nat-ipv4-max + type: u32 + byte-order: big-endian + - + name: nat-ipv6-min + type: binary + - + name: nat-ipv6-max + type: binary + - + name: nat-port-min + type: u16 + byte-order: big-endian + - + name: nat-port-max + type: u16 + byte-order: big-endian + - + name: pad + type: pad + - + name: helper-name + type: string + - + name: helper-family + type: u8 + - + name: helper-proto + type: u8 + - + name: tc-act-ctinfo-attrs + attributes: + - + name: pad + type: pad + - + name: tm + type: binary + struct: tcf-t + - + name: act + type: binary + - + name: zone + type: u16 + - + name: parms-dscp-mask + type: u32 + - + name: parms-dscp-statemask + type: u32 + - + name: parms-cpmark-mask + type: u32 + - + name: stats-dscp-set + type: u64 + - + name: stats-dscp-error + type: u64 + - + name: stats-cpmark-set + type: u64 + - + name: tc-act-gate-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + - + name: pad + type: pad + - + name: priority + type: s32 + - + name: entry-list + type: binary + - + name: base-time + type: u64 + - + name: cycle-time + type: u64 + - + name: cycle-time-ext + type: u64 + - + name: flags + type: u32 + - + name: clockid + type: s32 + - + name: tc-act-ife-attrs + attributes: + - + name: parms + type: binary + - + name: tm + type: binary + struct: tcf-t + - + name: dmac + type: binary + - + name: smac + type: binary + - + name: type + type: u16 + - + name: metalst + type: binary + - + name: pad + type: pad + - + name: tc-act-mirred-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + - + name: pad + type: pad + - + name: blockid + type: binary + - + name: tc-act-mpls-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + struct: tc-mpls + - + name: pad + type: pad + - + name: proto + type: u16 + byte-order: big-endian + - + name: label + type: u32 + - + name: tc + type: u8 + - + name: ttl + type: u8 + - + name: bos + type: u8 + - + name: tc-act-nat-attrs + attributes: + - + name: parms + type: binary + - + name: tm + type: binary + struct: tcf-t + - + name: pad + type: pad + - + name: tc-act-pedit-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + struct: tc-pedit-sel + - + name: pad + type: pad + - + name: parms-ex + type: binary + - + name: keys-ex + type: binary + - + name: key-ex + type: binary + - + name: tc-act-simple-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + - + name: data + type: binary + - + name: pad + type: pad + - + name: tc-act-skbedit-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + - + name: priority + type: u32 + - + name: queue-mapping + type: u16 + - + name: mark + type: u32 + - + name: pad + type: pad + - + name: ptype + type: u16 + - + name: mask + type: u32 + - + name: flags + type: u64 + - + name: queue-mapping-max + type: u16 + - + name: tc-act-skbmod-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + - + name: dmac + type: binary + - + name: smac + type: binary + - + name: etype + type: binary + - + name: pad + type: pad + - + name: tc-act-tunnel-key-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + - + name: enc-ipv4-src + type: u32 + byte-order: big-endian + - + name: enc-ipv4-dst + type: u32 + byte-order: big-endian + - + name: enc-ipv6-src + type: binary + - + name: enc-ipv6-dst + type: binary + - + name: enc-key-id + type: u64 + byte-order: big-endian + - + name: pad + type: pad + - + name: enc-dst-port + type: u16 + byte-order: big-endian + - + name: no-csum + type: u8 + - + name: enc-opts + type: binary + - + name: enc-tos + type: u8 + - + name: enc-ttl + type: u8 + - + name: no-frag + type: flag + - + name: tc-act-vlan-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + struct: tc-vlan + - + name: push-vlan-id + type: u16 + - + name: push-vlan-protocol + type: u16 + - + name: pad + type: pad + - + name: push-vlan-priority + type: u8 + - + name: push-eth-dst + type: binary + - + name: push-eth-src + type: binary + - + name: tc-basic-attrs + attributes: + - + name: classid + type: u32 + - + name: ematches + type: nest + nested-attributes: tc-ematch-attrs + - + name: act + type: array-nest + nested-attributes: tc-act-attrs + - + name: police + type: nest + nested-attributes: tc-police-attrs + - + name: pcnt + type: binary + struct: tc-basic-pcnt + - + name: pad + type: pad + - + name: tc-bpf-attrs + attributes: + - + name: act + type: nest + nested-attributes: tc-act-attrs + - + name: police + type: nest + nested-attributes: tc-police-attrs + - + name: classid + type: u32 + - + name: ops-len + type: u16 + - + name: ops + type: binary + - + name: fd + type: u32 + - + name: name + type: string + - + name: flags + type: u32 + - + name: flags-gen + type: u32 + - + name: tag + type: binary + - + name: id + type: u32 - name: tc-cake-attrs attributes: @@ -641,7 +2077,8 @@ attribute-sets: type: u32 - name: tin-stats - type: binary + type: array-nest + nested-attributes: tc-cake-tin-stats-attrs - name: deficit type: s32 @@ -660,6 +2097,84 @@ attribute-sets: - name: blue-timer-us type: s32 + - + name: tc-cake-tin-stats-attrs + attributes: + - + name: pad + type: pad + - + name: sent-packets + type: u32 + - + name: sent-bytes64 + type: u64 + - + name: dropped-packets + type: u32 + - + name: dropped-bytes64 + type: u64 + - + name: acks-dropped-packets + type: u32 + - + name: acks-dropped-bytes64 + type: u64 + - + name: ecn-marked-packets + type: u32 + - + name: ecn-marked-bytes64 + type: u64 + - + name: backlog-packets + type: u32 + - + name: backlog-bytes + type: u32 + - + name: threshold-rate64 + type: u64 + - + name: target-us + type: u32 + - + name: interval-us + type: u32 + - + name: way-indirect-hits + type: u32 + - + name: way-misses + type: u32 + - + name: way-collisions + type: u32 + - + name: peak-delay-us + type: u32 + - + name: avg-delay-us + type: u32 + - + name: base-delay-us + type: u32 + - + name: sparse-flows + type: u32 + - + name: bulk-flows + type: u32 + - + name: unresponsive-flows + type: u32 + - + name: max-skblen + type: u32 + - + name: flow-quantum + type: u32 - name: tc-cbs-attrs attributes: @@ -667,6 +2182,20 @@ attribute-sets: name: parms type: binary struct: tc-cbs-qopt + - + name: tc-cgroup-attrs + attributes: + - + name: act + type: nest + nested-attributes: tc-act-attrs + - + name: police + type: nest + nested-attributes: tc-police-attrs + - + name: ematches + type: binary - name: tc-choke-attrs attributes: @@ -677,6 +2206,9 @@ attribute-sets: - name: stab type: binary + checks: + min-len: 256 + max-len: 256 - name: max-p type: u32 @@ -704,6 +2236,56 @@ attribute-sets: - name: quantum type: u32 + - + name: tc-ematch-attrs + attributes: + - + name: tree-hdr + type: binary + struct: tcf-ematch-tree-hdr + - + name: tree-list + type: binary + - + name: tc-flow-attrs + attributes: + - + name: keys + type: u32 + - + name: mode + type: u32 + - + name: baseclass + type: u32 + - + name: rshift + type: u32 + - + name: addend + type: u32 + - + name: mask + type: u32 + - + name: xor + type: u32 + - + name: divisor + type: u32 + - + name: act + type: binary + - + name: police + type: nest + nested-attributes: tc-police-attrs + - + name: ematches + type: binary + - + name: perturb + type: u32 - name: tc-flower-attrs attributes: @@ -953,15 +2535,19 @@ attribute-sets: - name: key-arp-sha type: binary + display-hint: mac - name: key-arp-sha-mask type: binary + display-hint: mac - name: key-arp-tha type: binary + display-hint: mac - name: key-arp-tha-mask type: binary + display-hint: mac - name: key-mpls-ttl type: u8 @@ -1020,10 +2606,12 @@ attribute-sets: type: u8 - name: key-enc-opts - type: binary + type: nest + nested-attributes: tc-flower-key-enc-opts-attrs - name: key-enc-opts-mask - type: binary + type: nest + nested-attributes: tc-flower-key-enc-opts-attrs - name: in-hw-count type: u32 @@ -1069,7 +2657,8 @@ attribute-sets: type: binary - name: key-mpls-opts - type: binary + type: nest + nested-attributes: tc-flower-key-mpls-opt-attrs - name: key-hash type: u32 @@ -1091,6 +2680,129 @@ attribute-sets: name: key-l2-tpv3-sid type: u32 byte-order: big-endian + - + name: l2-miss + type: u8 + - + name: key-cfm + type: nest + nested-attributes: tc-flower-key-cfm-attrs + - + name: key-spi + type: u32 + byte-order: big-endian + - + name: key-spi-mask + type: u32 + byte-order: big-endian + - + name: tc-flower-key-enc-opts-attrs + attributes: + - + name: geneve + type: nest + nested-attributes: tc-flower-key-enc-opt-geneve-attrs + - + name: vxlan + type: nest + nested-attributes: tc-flower-key-enc-opt-vxlan-attrs + - + name: erspan + type: nest + nested-attributes: tc-flower-key-enc-opt-erspan-attrs + - + name: gtp + type: nest + nested-attributes: tc-flower-key-enc-opt-gtp-attrs + - + name: tc-flower-key-enc-opt-geneve-attrs + attributes: + - + name: class + type: u16 + - + name: type + type: u8 + - + name: data + type: binary + - + name: tc-flower-key-enc-opt-vxlan-attrs + attributes: + - + name: gbp + type: u32 + - + name: tc-flower-key-enc-opt-erspan-attrs + attributes: + - + name: ver + type: u8 + - + name: index + type: u32 + - + name: dir + type: u8 + - + name: hwid + type: u8 + - + name: tc-flower-key-enc-opt-gtp-attrs + attributes: + - + name: pdu-type + type: u8 + - + name: qfi + type: u8 + - + name: tc-flower-key-mpls-opt-attrs + attributes: + - + name: lse-depth + type: u8 + - + name: lse-ttl + type: u8 + - + name: lse-bos + type: u8 + - + name: lse-tc + type: u8 + - + name: lse-label + type: u32 + - + name: tc-flower-key-cfm-attrs + attributes: + - + name: md-level + type: u8 + - + name: opcode + type: u8 + - + name: tc-fw-attrs + attributes: + - + name: classid + type: u32 + - + name: police + type: nest + nested-attributes: tc-police-attrs + - + name: indev + type: string + - + name: act + type: array-nest + nested-attributes: tc-act-attrs + - + name: mask + type: u32 - name: tc-gred-attrs attributes: @@ -1135,7 +2847,7 @@ attribute-sets: type: u32 - name: stat-bytes - type: u32 + type: u64 - name: stat-packets type: u32 @@ -1232,40 +2944,25 @@ attribute-sets: name: offload type: flag - - name: tc-act-attrs + name: tc-matchall-attrs attributes: - - name: kind - type: string - - - name: options - type: sub-message - sub-message: tc-act-options-msg - selector: kind - - - name: index + name: classid type: u32 - - name: stats + name: act + type: array-nest + nested-attributes: tc-act-attrs + - + name: flags + type: u32 + - + name: pcnt type: binary + struct: tc-matchall-pcnt - name: pad type: pad - - - name: cookie - type: binary - - - name: flags - type: bitfield32 - - - name: hw-stats - type: bitfield32 - - - name: used-hw-stats - type: bitfield32 - - - name: in-hw-count - type: u32 - name: tc-etf-attrs attributes: @@ -1304,48 +3001,71 @@ attribute-sets: - name: plimit type: u32 + doc: Limit of total number of packets in queue - name: flow-plimit type: u32 + doc: Limit of packets per flow - name: quantum type: u32 + doc: RR quantum - name: initial-quantum type: u32 + doc: RR quantum for new flow - name: rate-enable type: u32 + doc: Enable / disable rate limiting - name: flow-default-rate type: u32 + doc: Obsolete, do not use - name: flow-max-rate type: u32 + doc: Per flow max rate - name: buckets-log type: u32 + doc: log2(number of buckets) - name: flow-refill-delay type: u32 + doc: Flow credit refill delay in usec - name: orphan-mask type: u32 + doc: Mask applied to orphaned skb hashes - name: low-rate-threshold type: u32 + doc: Per packet delay under this rate - name: ce-threshold type: u32 + doc: DCTCP-like CE marking threshold - name: timer-slack type: u32 - name: horizon type: u32 + doc: Time horizon in usec - name: horizon-drop type: u8 + doc: Drop packets beyond horizon, or cap their EDT + - + name: priomap + type: binary + struct: tc-prio-qopt + - + name: weights + type: binary + sub-type: s32 + doc: Weights for each band - name: tc-fq-codel-attrs attributes: @@ -1427,6 +3147,7 @@ attribute-sets: - name: corr type: binary + struct: tc-netem-corr - name: delay-dist type: binary @@ -1434,15 +3155,19 @@ attribute-sets: - name: reorder type: binary + struct: tc-netem-reorder - name: corrupt type: binary + struct: tc-netem-corrupt - name: loss - type: binary + type: nest + nested-attributes: tc-netem-loss-attrs - name: rate type: binary + struct: tc-netem-rate - name: ecn type: u32 @@ -1461,10 +3186,27 @@ attribute-sets: - name: slot type: binary + struct: tc-netem-slot - name: slot-dist type: binary sub-type: s16 + - + name: prng-seed + type: u64 + - + name: tc-netem-loss-attrs + attributes: + - + name: gi + type: binary + doc: General Intuitive - 4 state model + struct: tc-netem-gimodel + - + name: ge + type: binary + doc: Gilbert Elliot models + struct: tc-netem-gemodel - name: tc-pie-attrs attributes: @@ -1492,6 +3234,44 @@ attribute-sets: - name: dq-rate-estimator type: u32 + - + name: tc-police-attrs + attributes: + - + name: tbf + type: binary + struct: tc-police + - + name: rate + type: binary + - + name: peakrate + type: binary + - + name: avrate + type: u32 + - + name: result + type: u32 + - + name: tm + type: binary + struct: tcf-t + - + name: pad + type: pad + - + name: rate64 + type: u64 + - + name: peakrate64 + type: u64 + - + name: pktrate64 + type: u64 + - + name: pktburst64 + type: u64 - name: tc-qfq-attrs attributes: @@ -1516,13 +3296,36 @@ attribute-sets: type: u32 - name: flags - type: binary + type: bitfield32 - name: early-drop-block type: u32 - name: mark-block type: u32 + - + name: tc-route-attrs + attributes: + - + name: classid + type: u32 + - + name: to + type: u32 + - + name: from + type: u32 + - + name: iif + type: u32 + - + name: police + type: nest + nested-attributes: tc-police-attrs + - + name: act + type: array-nest + nested-attributes: tc-act-attrs - name: tc-taprio-attrs attributes: @@ -1629,17 +3432,43 @@ attribute-sets: name: pad type: pad - - name: tca-gact-attrs + name: tc-act-sample-attrs attributes: - name: tm type: binary + struct: tcf-t - name: parms type: binary + struct: tc-gen + - + name: rate + type: u32 + - + name: trunc-size + type: u32 + - + name: psample-group + type: u32 + - + name: pad + type: pad + - + name: tc-act-gact-attrs + attributes: + - + name: tm + type: binary + struct: tcf-t + - + name: parms + type: binary + struct: tc-gen - name: prob type: binary + struct: tc-gact-p - name: pad type: pad @@ -1659,34 +3488,89 @@ attribute-sets: - name: basic type: binary + struct: gnet-stats-basic - name: rate-est type: binary + struct: gnet-stats-rate-est - name: queue type: binary + struct: gnet-stats-queue - name: app - type: binary # TODO sub-message needs 2+ level deep lookup + type: sub-message sub-message: tca-stats-app-msg selector: kind - name: rate-est64 type: binary + struct: gnet-stats-rate-est64 - name: pad type: pad - name: basic-hw type: binary + struct: gnet-stats-basic - name: pkt64 + type: u64 + - + name: tc-u32-attrs + attributes: + - + name: classid + type: u32 + - + name: hash + type: u32 + - + name: link + type: u32 + - + name: divisor + type: u32 + - + name: sel type: binary + struct: tc-u32-sel + - + name: police + type: nest + nested-attributes: tc-police-attrs + - + name: act + type: array-nest + nested-attributes: tc-act-attrs + - + name: indev + type: string + - + name: pcnt + type: binary + struct: tc-u32-pcnt + - + name: mark + type: binary + struct: tc-u32-mark + - + name: flags + type: u32 + - + name: pad + type: pad sub-messages: - name: tc-options-msg formats: + - + value: basic + attribute-set: tc-basic-attrs + - + value: bpf + attribute-set: tc-bpf-attrs - value: bfifo fixed-header: tc-fifo-qopt @@ -1696,6 +3580,9 @@ sub-messages: - value: cbs attribute-set: tc-cbs-attrs + - + value: cgroup + attribute-set: tc-cgroup-attrs - value: choke attribute-set: tc-choke-attrs @@ -1713,6 +3600,12 @@ sub-messages: - value: ets attribute-set: tc-ets-attrs + - + value: flow + attribute-set: tc-flow-attrs + - + value: flower + attribute-set: tc-flower-attrs - value: fq attribute-set: tc-fq-attrs @@ -1723,8 +3616,8 @@ sub-messages: value: fq_pie attribute-set: tc-fq-pie-attrs - - value: flower - attribute-set: tc-flower-attrs + value: fw + attribute-set: tc-fw-attrs - value: gred attribute-set: tc-gred-attrs @@ -1739,6 +3632,9 @@ sub-messages: attribute-set: tc-htb-attrs - value: ingress # no content + - + value: matchall + attribute-set: tc-matchall-attrs - value: mq # no content - @@ -1775,6 +3671,9 @@ sub-messages: - value: red attribute-set: tc-red-attrs + - + value: route + attribute-set: tc-route-attrs - value: sfb fixed-header: tc-sfb-qopt @@ -1787,88 +3686,105 @@ sub-messages: - value: tbf attribute-set: tc-tbf-attrs + - + value: u32 + attribute-set: tc-u32-attrs - name: tc-act-options-msg formats: + - + value: bpf + attribute-set: tc-act-bpf-attrs + - + value: connmark + attribute-set: tc-act-connmark-attrs + - + value: csum + attribute-set: tc-act-csum-attrs + - + value: ct + attribute-set: tc-act-ct-attrs + - + value: ctinfo + attribute-set: tc-act-ctinfo-attrs - value: gact - attribute-set: tca-gact-attrs + attribute-set: tc-act-gact-attrs + - + value: gate + attribute-set: tc-act-gate-attrs + - + value: ife + attribute-set: tc-act-ife-attrs + - + value: mirred + attribute-set: tc-act-mirred-attrs + - + value: mpls + attribute-set: tc-act-mpls-attrs + - + value: nat + attribute-set: tc-act-nat-attrs + - + value: pedit + attribute-set: tc-act-pedit-attrs + - + value: police + attribute-set: tc-act-police-attrs + - + value: sample + attribute-set: tc-act-sample-attrs + - + value: simple + attribute-set: tc-act-simple-attrs + - + value: skbedit + attribute-set: tc-act-skbedit-attrs + - + value: skbmod + attribute-set: tc-act-skbmod-attrs + - + value: tunnel_key + attribute-set: tc-act-tunnel-key-attrs + - + value: vlan + attribute-set: tc-act-vlan-attrs - name: tca-stats-app-msg formats: - - - value: bfifo - - - value: blackhole - value: cake attribute-set: tc-cake-stats-attrs - - - value: cbs - value: choke - - - value: clsact + fixed-header: tc-choke-xstats - value: codel - - - value: drr - - - value: etf - - - value: ets + fixed-header: tc-codel-xstats - value: fq + fixed-header: tc-fq-qd-stats - value: fq_codel + fixed-header: tc-fq-codel-xstats - value: fq_pie - - - value: flower - - - value: gred - - - value: hfsc + fixed-header: tc-fq-pie-xstats - value: hhf - - - value: htb - - - value: ingress - - - value: mq - - - value: mqprio - - - value: multiq - - - value: netem - - - value: noqueue - - - value: pfifo - - - value: pfifo_fast - - - value: pfifo_head_drop + fixed-header: tc-hhf-xstats - value: pie - - - value: plug - - - value: prio - - - value: qfq + fixed-header: tc-pie-xstats - value: red + fixed-header: tc-red-xstats - value: sfb + fixed-header: tc-sfb-xstats - value: sfq - - - value: taprio - - - value: tbf + fixed-header: tc-sfq-xstats operations: enum-model: directional From b2005bb756e1d0ef400a79f3e1bce4f3870415a9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 29 Jan 2024 15:21:21 +0100 Subject: [PATCH 0530/2255] dt-bindings: net: qcom,ipa: do not override firmware-name $ref dtschema package defines firmware-name as string-array, so individual bindings should not make it a string but instead just narrow the number of expected firmware file names. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Acked-by: Alex Elder Link: https://lore.kernel.org/r/20240129142121.102450-1-krzysztof.kozlowski@linaro.org Signed-off-by: Paolo Abeni --- Documentation/devicetree/bindings/net/qcom,ipa.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml index c30218684cfe..53cae71d9957 100644 --- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml @@ -159,7 +159,7 @@ properties: when the AP (not the modem) performs early initialization. firmware-name: - $ref: /schemas/types.yaml#/definitions/string + maxItems: 1 description: If present, name (or relative path) of the file within the firmware search path containing the firmware image used when From 8263b3382d8c1af0fffa27095a9f1db6f2dad899 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Wed, 31 Jan 2024 23:26:15 +0200 Subject: [PATCH 0531/2255] libbpf: Remove unnecessary null check in kernel_supports() After recent changes, Coverity complained about inconsistent null checks in kernel_supports() function: kernel_supports(const struct bpf_object *obj, ...) [...] // var_compare_op: Comparing obj to null implies that obj might be null if (obj && obj->gen_loader) return true; // var_deref_op: Dereferencing null pointer obj if (obj->token_fd) return feat_supported(obj->feat_cache, feat_id); [...] - The original null check was introduced by commit [0], which introduced a call `kernel_supports(NULL, ...)` in function bump_rlimit_memlock(); - This call was refactored to use `feat_supported(NULL, ...)` in commit [1]. Looking at all places where kernel_supports() is called: - There is either `obj->...` access before the call; - Or `obj` comes from `prog->obj` expression, where `prog` comes from enumeration of programs in `obj`; - Or `obj` comes from `prog->obj`, where `prog` is a parameter to one of the API functions: - bpf_program__attach_kprobe_opts; - bpf_program__attach_kprobe; - bpf_program__attach_ksyscall. Assuming correct API usage, it appears that `obj` can never be null when passed to kernel_supports(). Silence the Coverity warning by removing redundant null check. [0] e542f2c4cd16 ("libbpf: Auto-bump RLIMIT_MEMLOCK if kernel needs it for BPF") [1] d6dd1d49367a ("libbpf: Further decouple feature checking logic from bpf_object") Signed-off-by: Eduard Zingerman Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20240131212615.20112-1-eddyz87@gmail.com --- tools/lib/bpf/libbpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index db65ea59a05a..f6953d7faff1 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4661,7 +4661,7 @@ bpf_object__probe_loading(struct bpf_object *obj) bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) { - if (obj && obj->gen_loader) + if (obj->gen_loader) /* To generate loader program assume the latest kernel * to avoid doing extra prog_load, map_create syscalls. */ From 57b9426952c46f8d0aa7fad27fe55403fb28974f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 21 Jan 2024 15:18:23 +0800 Subject: [PATCH 0532/2255] 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(+) 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) From 26cdaee43dc5f9c9d0c5429b365b8f094afad717 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Sun, 21 Jan 2024 15:18:24 +0800 Subject: [PATCH 0533/2255] 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(-) 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) From 0bc7d1d4e63cf31ff1b4396b0e2f0e3c76828d26 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 21 Jan 2024 15:18:25 +0800 Subject: [PATCH 0534/2255] 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 +- .../net/wireless/realtek/rtw89/rtw8851be.c | 2 + .../net/wireless/realtek/rtw89/rtw8852ae.c | 1 + .../net/wireless/realtek/rtw89/rtw8852be.c | 1 + .../net/wireless/realtek/rtw89/rtw8852ce.c | 1 + .../net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 7 files changed, 63 insertions(+), 7 deletions(-) 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, From c108b4a50dd7650941d4f4ec5c161655a73711db Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 21 Jan 2024 15:18:26 +0800 Subject: [PATCH 0535/2255] 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(-) 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 From 5f8066d4578241a2d9d63428e6a604807c2ab226 Mon Sep 17 00:00:00 2001 From: Philippe Schenker Date: Tue, 30 Jan 2024 09:34:18 +0100 Subject: [PATCH 0536/2255] dt-bindings: net: dsa: Add KSZ8567 switch support This commit adds the dt-binding for KSZ8567, a robust 7-port Ethernet switch. The KSZ8567 features two RGMII/MII/RMII interfaces, each capable of gigabit speeds, complemented by five 10/100 Mbps MAC/PHYs. This binding is necessary to set specific capabilities for this switch chip that are necessary due to the ksz dsa driver only accepting specific chip ids. The KSZ8567 is very similar to KSZ9567 however only containing 100 Mbps phys on its downstream ports. Signed-off-by: Philippe Schenker Acked-by: Conor Dooley Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20240130083419.135763-1-dev@pschenker.ch Signed-off-by: Paolo Abeni --- Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml index c963dc09e8e1..52acc15ebcbf 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml @@ -31,6 +31,7 @@ properties: - microchip,ksz9893 - microchip,ksz9563 - microchip,ksz8563 + - microchip,ksz8567 reset-gpios: description: From 3723b56d6f73f7c8c3b521a80556f129830f6fb9 Mon Sep 17 00:00:00 2001 From: Philippe Schenker Date: Tue, 30 Jan 2024 09:34:19 +0100 Subject: [PATCH 0537/2255] net: dsa: Add KSZ8567 switch support This commit introduces support for the KSZ8567, a robust 7-port Ethernet switch. The KSZ8567 features two RGMII/MII/RMII interfaces, each capable of gigabit speeds, complemented by five 10/100 Mbps MAC/PHYs. Signed-off-by: Philippe Schenker Acked-by: Arun Ramadoss Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20240130083419.135763-2-dev@pschenker.ch Signed-off-by: Paolo Abeni --- drivers/net/dsa/microchip/ksz9477_i2c.c | 4 ++ drivers/net/dsa/microchip/ksz_common.c | 43 ++++++++++++++++++++- drivers/net/dsa/microchip/ksz_common.h | 1 + drivers/net/dsa/microchip/ksz_spi.c | 5 +++ include/linux/platform_data/microchip-ksz.h | 1 + 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index cac4a607e54a..82bebee4615c 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -103,6 +103,10 @@ static const struct of_device_id ksz9477_dt_ids[] = { .compatible = "microchip,ksz8563", .data = &ksz_switch_chips[KSZ8563] }, + { + .compatible = "microchip,ksz8567", + .data = &ksz_switch_chips[KSZ8567] + }, { .compatible = "microchip,ksz9567", .data = &ksz_switch_chips[KSZ9567] diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index a7b5ddb8656e..9ff5132f3ac6 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1476,6 +1476,39 @@ const struct ksz_chip_data ksz_switch_chips[] = { .gbit_capable = {true, true, true}, }, + [KSZ8567] = { + .chip_id = KSZ8567_CHIP_ID, + .dev_name = "KSZ8567", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x7F, /* can be configured as cpu port */ + .port_cnt = 7, /* total port count */ + .port_nirqs = 3, + .num_tx_queues = 4, + .tc_cbs_supported = true, + .tc_ets_supported = true, + .ops = &ksz9477_dev_ops, + .mib_names = ksz9477_mib_names, + .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), + .reg_mib_cnt = MIB_COUNTER_NUM, + .regs = ksz9477_regs, + .masks = ksz9477_masks, + .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, + .supports_mii = {false, false, false, false, + false, true, true}, + .supports_rmii = {false, false, false, false, + false, true, true}, + .supports_rgmii = {false, false, false, false, + false, true, true}, + .internal_phy = {true, true, true, true, + true, false, false}, + .gbit_capable = {false, false, false, false, false, + true, true}, + }, + [KSZ9567] = { .chip_id = KSZ9567_CHIP_ID, .dev_name = "KSZ9567", @@ -2649,6 +2682,7 @@ static void ksz_port_teardown(struct dsa_switch *ds, int port) switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -2705,7 +2739,8 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, dev->chip_id == KSZ9563_CHIP_ID) proto = DSA_TAG_PROTO_KSZ9893; - if (dev->chip_id == KSZ9477_CHIP_ID || + if (dev->chip_id == KSZ8567_CHIP_ID || + dev->chip_id == KSZ9477_CHIP_ID || dev->chip_id == KSZ9896_CHIP_ID || dev->chip_id == KSZ9897_CHIP_ID || dev->chip_id == KSZ9567_CHIP_ID) @@ -2813,6 +2848,7 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port) case KSZ8830_CHIP_ID: return KSZ8863_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -2839,6 +2875,7 @@ static int ksz_validate_eee(struct dsa_switch *ds, int port) switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -3183,6 +3220,7 @@ static int ksz_switch_detect(struct ksz_device *dev) case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: case KSZ9567_CHIP_ID: + case KSZ8567_CHIP_ID: case LAN9370_CHIP_ID: case LAN9371_CHIP_ID: case LAN9372_CHIP_ID: @@ -3220,6 +3258,7 @@ static int ksz_cls_flower_add(struct dsa_switch *ds, int port, switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -3239,6 +3278,7 @@ static int ksz_cls_flower_del(struct dsa_switch *ds, int port, switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -4142,6 +4182,7 @@ static int ksz_parse_drive_strength(struct ksz_device *dev) case KSZ8794_CHIP_ID: case KSZ8765_CHIP_ID: case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 15612101a155..060c5de9aa05 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -187,6 +187,7 @@ struct ksz_device { /* List of supported models */ enum ksz_model { KSZ8563, + KSZ8567, KSZ8795, KSZ8794, KSZ8765, diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 6f6d878e742c..c8166fb440ab 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -164,6 +164,10 @@ static const struct of_device_id ksz_dt_ids[] = { .compatible = "microchip,ksz8563", .data = &ksz_switch_chips[KSZ8563] }, + { + .compatible = "microchip,ksz8567", + .data = &ksz_switch_chips[KSZ8567] + }, { .compatible = "microchip,ksz9567", .data = &ksz_switch_chips[KSZ9567] @@ -204,6 +208,7 @@ static const struct spi_device_id ksz_spi_ids[] = { { "ksz9893" }, { "ksz9563" }, { "ksz8563" }, + { "ksz8567" }, { "ksz9567" }, { "lan9370" }, { "lan9371" }, diff --git a/include/linux/platform_data/microchip-ksz.h b/include/linux/platform_data/microchip-ksz.h index f177416635a2..8c659db4da6b 100644 --- a/include/linux/platform_data/microchip-ksz.h +++ b/include/linux/platform_data/microchip-ksz.h @@ -33,6 +33,7 @@ enum ksz_chip_id { KSZ9897_CHIP_ID = 0x00989700, KSZ9893_CHIP_ID = 0x00989300, KSZ9563_CHIP_ID = 0x00956300, + KSZ8567_CHIP_ID = 0x00856700, KSZ9567_CHIP_ID = 0x00956700, LAN9370_CHIP_ID = 0x00937000, LAN9371_CHIP_ID = 0x00937100, From f8a7840e98a440f466954c0b9eed99a9f064a564 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:32 +0800 Subject: [PATCH 0538/2255] 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(+) 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, From b16daa62125e3f841a135c37dfd996cdf7e7960d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:33 +0800 Subject: [PATCH 0539/2255] 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(-) 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, From 1ba63a8a752a76ebe4b26d80c6d25bd04484a9eb Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:34 +0800 Subject: [PATCH 0540/2255] 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 ++++++++++++++++++ .../net/wireless/realtek/rtw89/rtw8922a_rfk.c | 33 +++ .../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 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 From 88d1f9b22fab815dd8c27ccb06f30d4814eaa11a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:35 +0800 Subject: [PATCH 0541/2255] 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(+) 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, From 1de97cd362c4080aab595b84bf0bff3ebc702446 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:38:02 +0800 Subject: [PATCH 0542/2255] 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(+) 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, From a6c759c8962b11fdc62ced6f70a3f6ed0a50e033 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:38:13 +0800 Subject: [PATCH 0543/2255] 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(+) 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, From b5d7020134d91ccb9ae763f738aaa466e37ac25a Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:50 +0800 Subject: [PATCH 0544/2255] 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(-) 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, From ac54faf507e5d2776a7dca2c13665745d4490cd5 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:51 +0800 Subject: [PATCH 0545/2255] 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(-) 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 { From a412920b70199c07504ea9e937b00f07916a541a Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:52 +0800 Subject: [PATCH 0546/2255] 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(-) 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); From 4ba24331c973eb1df0d3b67b0e3f8b7cde7765a7 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:53 +0800 Subject: [PATCH 0547/2255] 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(-) 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); From e58e3117019cfa732706211c151fd94d8fb08ce3 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 26 Jan 2024 14:33:54 +0800 Subject: [PATCH 0548/2255] 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(-) 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); } From f651300cd8849a3703892fe5efd397c7a44a7f60 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 26 Jan 2024 14:33:55 +0800 Subject: [PATCH 0549/2255] 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(-) 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) From f1abee76dba829ada6e30ac640443e81bde2f878 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:56 +0800 Subject: [PATCH 0550/2255] 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(+) 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) From 17903a283593c1dbf9da041f836004163ca30f7b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 31 Jan 2024 10:10:07 +0300 Subject: [PATCH 0551/2255] 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(-) 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; } From 088a464ed53feeab9632c6748b9f25354639e2bd Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Tue, 30 Jan 2024 19:37:59 -0800 Subject: [PATCH 0552/2255] bpf, docs: Clarify which legacy packet instructions existed As discussed on the BPF IETF mailing list (see link), this patch updates the "Legacy BPF Packet access instructions" section to clarify which instructions are deprecated (vs which were never defined and so are not deprecated). Signed-off-by: Dave Thaler Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Acked-by: David Vernet Link: https://mailarchive.ietf.org/arch/msg/bpf/5LnnKm093cGpOmDI9TnLQLBXyys Link: https://lore.kernel.org/bpf/20240131033759.3634-1-dthaler1968@gmail.com --- Documentation/bpf/standardization/instruction-set.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index fceacca46299..dcbc9193c66f 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -630,7 +630,9 @@ Legacy BPF Packet access instructions ------------------------------------- BPF previously introduced special instructions for access to packet data that were -carried over from classic BPF. However, these instructions are +carried over from classic BPF. These instructions used an instruction +class of BPF_LD, a size modifier of BPF_W, BPF_H, or BPF_B, and a +mode modifier of BPF_ABS or BPF_IND. However, these instructions are deprecated and should no longer be used. All legacy packet access instructions belong to the "legacy" conformance group instead of the "basic" conformance group. From 69065aa11ca680d76a6c6bc088aa0f0abe24afdb Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Tue, 30 Jan 2024 12:46:58 +0000 Subject: [PATCH 0553/2255] riscv, bpf: Enable inline bpf_kptr_xchg() for RV64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RV64 JIT supports 64-bit BPF_XCHG atomic instructions. At the same time, the underlying implementation of xchg() and atomic64_xchg() in RV64 both are raw_xchg() that supported 64-bit. Therefore inline bpf_kptr_xchg() will have equivalent semantics. Let's inline it for better performance. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20240130124659.670321-2-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit_comp64.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index fda6b4f6a4c1..869e4282a2c4 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1806,3 +1806,8 @@ bool bpf_jit_supports_kfunc_call(void) { return true; } + +bool bpf_jit_supports_ptr_xchg(void) +{ + return true; +} From 994ff2f7973982af286608da10c295383650fc28 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Tue, 30 Jan 2024 12:46:59 +0000 Subject: [PATCH 0554/2255] selftests/bpf: Enable inline bpf_kptr_xchg() test for RV64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable inline bpf_kptr_xchg() test for RV64, and the test have passed as show below: Summary: 1/0 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20240130124659.670321-3-pulehui@huaweicloud.com --- tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c b/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c index 15144943e88b..7def158da9eb 100644 --- a/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c +++ b/tools/testing/selftests/bpf/prog_tests/kptr_xchg_inline.c @@ -13,7 +13,8 @@ void test_kptr_xchg_inline(void) unsigned int cnt; int err; -#if !(defined(__x86_64__) || defined(__aarch64__)) +#if !(defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__riscv) && __riscv_xlen == 64)) test__skip(); return; #endif From c1f5204efcbcced83f67f12fa8f1a7f5f244fb87 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sun, 28 Jan 2024 22:21:04 -0800 Subject: [PATCH 0555/2255] cpumask: add cpumask_weight_andnot() Similarly to cpumask_weight_and(), cpumask_weight_andnot() is a handy helper that may help to avoid creating an intermediate mask just to calculate number of bits that set in a 1st given mask, and clear in 2nd one. Signed-off-by: Yury Norov Reviewed-by: Jacob Keller Signed-off-by: Paolo Abeni --- include/linux/bitmap.h | 12 ++++++++++++ include/linux/cpumask.h | 13 +++++++++++++ lib/bitmap.c | 7 +++++++ 3 files changed, 32 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 99451431e4d6..5814e9ee40ba 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -54,6 +54,7 @@ struct device; * bitmap_full(src, nbits) Are all bits set in *src? * bitmap_weight(src, nbits) Hamming Weight: number set bits * bitmap_weight_and(src1, src2, nbits) Hamming Weight of and'ed bitmap + * bitmap_weight_andnot(src1, src2, nbits) Hamming Weight of andnot'ed bitmap * bitmap_set(dst, pos, nbits) Set specified bit area * bitmap_clear(dst, pos, nbits) Clear specified bit area * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area @@ -169,6 +170,8 @@ bool __bitmap_subset(const unsigned long *bitmap1, unsigned int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits); unsigned int __bitmap_weight_and(const unsigned long *bitmap1, const unsigned long *bitmap2, unsigned int nbits); +unsigned int __bitmap_weight_andnot(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); void __bitmap_set(unsigned long *map, unsigned int start, int len); void __bitmap_clear(unsigned long *map, unsigned int start, int len); @@ -425,6 +428,15 @@ unsigned long bitmap_weight_and(const unsigned long *src1, return __bitmap_weight_and(src1, src2, nbits); } +static __always_inline +unsigned long bitmap_weight_andnot(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + return hweight_long(*src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)); + return __bitmap_weight_andnot(src1, src2, nbits); +} + static __always_inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits) { diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index cfb545841a2c..228c23eb36d2 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -719,6 +719,19 @@ static inline unsigned int cpumask_weight_and(const struct cpumask *srcp1, return bitmap_weight_and(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits); } +/** + * cpumask_weight_andnot - Count of bits in (*srcp1 & ~*srcp2) + * @srcp1: the cpumask to count bits (< nr_cpu_ids) in. + * @srcp2: the cpumask to count bits (< nr_cpu_ids) in. + * + * Return: count of bits set in both *srcp1 and *srcp2 + */ +static inline unsigned int cpumask_weight_andnot(const struct cpumask *srcp1, + const struct cpumask *srcp2) +{ + return bitmap_weight_andnot(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits); +} + /** * cpumask_shift_right - *dstp = *srcp >> n * @dstp: the cpumask result diff --git a/lib/bitmap.c b/lib/bitmap.c index 09522af227f1..b97692854966 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -348,6 +348,13 @@ unsigned int __bitmap_weight_and(const unsigned long *bitmap1, } EXPORT_SYMBOL(__bitmap_weight_and); +unsigned int __bitmap_weight_andnot(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) +{ + return BITMAP_WEIGHT(bitmap1[idx] & ~bitmap2[idx], bits); +} +EXPORT_SYMBOL(__bitmap_weight_andnot); + void __bitmap_set(unsigned long *map, unsigned int start, int len) { unsigned long *p = map + BIT_WORD(start); From dcee228078c34b63089c4b589d4bddf08019d0f6 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sun, 28 Jan 2024 22:21:05 -0800 Subject: [PATCH 0556/2255] cpumask: define cleanup function for cpumasks Now we can simplify code that allocates cpumasks for local needs. Signed-off-by: Yury Norov Signed-off-by: Paolo Abeni --- include/linux/cpumask.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 228c23eb36d2..1c29947db848 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -7,6 +7,7 @@ * set of CPUs in a system, one bit position per CPU number. In general, * only nr_cpu_ids (<= NR_CPUS) bits are valid. */ +#include #include #include #include @@ -990,6 +991,8 @@ static inline bool cpumask_available(cpumask_var_t mask) } #endif /* CONFIG_CPUMASK_OFFSTACK */ +DEFINE_FREE(free_cpumask_var, struct cpumask *, if (_T) free_cpumask_var(_T)); + /* It's common to want to use cpu_all_mask in struct member initializers, * so it has to refer to an address rather than a pointer. */ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); From 91bfe210e196780667c94c2795103ca6013233fc Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sun, 28 Jan 2024 22:21:06 -0800 Subject: [PATCH 0557/2255] net: mana: add a function to spread IRQs per CPUs Souradeep investigated that the driver performs faster if IRQs are spread on CPUs with the following heuristics: 1. No more than one IRQ per CPU, if possible; 2. NUMA locality is the second priority; 3. Sibling dislocality is the last priority. Let's consider this topology: Node 0 1 Core 0 1 2 3 CPU 0 1 2 3 4 5 6 7 The most performant IRQ distribution based on the above topology and heuristics may look like this: IRQ Nodes Cores CPUs 0 1 0 0-1 1 1 1 2-3 2 1 0 0-1 3 1 1 2-3 4 2 2 4-5 5 2 3 6-7 6 2 2 4-5 7 2 3 6-7 The irq_setup() routine introduced in this patch leverages the for_each_numa_hop_mask() iterator and assigns IRQs to sibling groups as described above. According to [1], for NUMA-aware but sibling-ignorant IRQ distribution based on cpumask_local_spread() performance test results look like this: ./ntttcp -r -m 16 NTTTCP for Linux 1.4.0 --------------------------------------------------------- 08:05:20 INFO: 17 threads created 08:05:28 INFO: Network activity progressing... 08:06:28 INFO: Test run completed. 08:06:28 INFO: Test cycle finished. 08:06:28 INFO: ##### Totals: ##### 08:06:28 INFO: test duration :60.00 seconds 08:06:28 INFO: total bytes :630292053310 08:06:28 INFO: throughput :84.04Gbps 08:06:28 INFO: retrans segs :4 08:06:28 INFO: cpu cores :192 08:06:28 INFO: cpu speed :3799.725MHz 08:06:28 INFO: user :0.05% 08:06:28 INFO: system :1.60% 08:06:28 INFO: idle :96.41% 08:06:28 INFO: iowait :0.00% 08:06:28 INFO: softirq :1.94% 08:06:28 INFO: cycles/byte :2.50 08:06:28 INFO: cpu busy (all) :534.41% For NUMA- and sibling-aware IRQ distribution, the same test works 15% faster: ./ntttcp -r -m 16 NTTTCP for Linux 1.4.0 --------------------------------------------------------- 08:08:51 INFO: 17 threads created 08:08:56 INFO: Network activity progressing... 08:09:56 INFO: Test run completed. 08:09:56 INFO: Test cycle finished. 08:09:56 INFO: ##### Totals: ##### 08:09:56 INFO: test duration :60.00 seconds 08:09:56 INFO: total bytes :741966608384 08:09:56 INFO: throughput :98.93Gbps 08:09:56 INFO: retrans segs :6 08:09:56 INFO: cpu cores :192 08:09:56 INFO: cpu speed :3799.791MHz 08:09:56 INFO: user :0.06% 08:09:56 INFO: system :1.81% 08:09:56 INFO: idle :96.18% 08:09:56 INFO: iowait :0.00% 08:09:56 INFO: softirq :1.95% 08:09:56 INFO: cycles/byte :2.25 08:09:56 INFO: cpu busy (all) :569.22% [1] https://lore.kernel.org/all/20231211063726.GA4977@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net/ Signed-off-by: Yury Norov Co-developed-by: Souradeep Chakrabarti Signed-off-by: Paolo Abeni --- .../net/ethernet/microsoft/mana/gdma_main.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index d33b27214539..05a0ac054823 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -1249,6 +1249,35 @@ void mana_gd_free_res_map(struct gdma_resource *r) r->size = 0; } +static __maybe_unused int irq_setup(unsigned int *irqs, unsigned int len, int node) +{ + const struct cpumask *next, *prev = cpu_none_mask; + cpumask_var_t cpus __free(free_cpumask_var); + int cpu, weight; + + if (!alloc_cpumask_var(&cpus, GFP_KERNEL)) + return -ENOMEM; + + rcu_read_lock(); + for_each_numa_hop_mask(next, node) { + weight = cpumask_weight_andnot(next, prev); + while (weight > 0) { + cpumask_andnot(cpus, next, prev); + for_each_cpu(cpu, cpus) { + if (len-- == 0) + goto done; + irq_set_affinity_and_hint(*irqs++, topology_sibling_cpumask(cpu)); + cpumask_andnot(cpus, cpus, topology_sibling_cpumask(cpu)); + --weight; + } + } + prev = next; + } +done: + rcu_read_unlock(); + return 0; +} + static int mana_gd_setup_irqs(struct pci_dev *pdev) { unsigned int max_queues_per_port = num_online_cpus(); From 8afefc361209b726aa5886833384d048412b159e Mon Sep 17 00:00:00 2001 From: Souradeep Chakrabarti Date: Sun, 28 Jan 2024 22:21:07 -0800 Subject: [PATCH 0558/2255] net: mana: Assigning IRQ affinity on HT cores Existing MANA design assigns IRQ to every CPU, including sibling hyper-threads. This may cause multiple IRQs to be active simultaneously in the same core and may reduce the network performance. Improve the performance by assigning IRQ to non sibling CPUs in local NUMA node. The performance improvement we are getting using ntttcp with following patch is around 15 percent against existing design and approximately 11 percent, when trying to assign one IRQ in each core across NUMA nodes, if enough cores are present. The change will improve the performance for the system with high number of CPU, where number of CPUs in a node is more than 64 CPUs. Nodes with 64 CPUs or less than 64 CPUs will not be affected by this change. The performance study was done using ntttcp tool in Azure. The node had 2 nodes with 32 cores each, total 128 vCPU and number of channels were 32 for 32 RX rings. The below table shows a comparison between existing design and new design: IRQ node-num core-num CPU performance(%) 1 0 | 0 0 | 0 0 | 0-1 0 2 0 | 0 0 | 1 1 | 2-3 3 3 0 | 0 1 | 2 2 | 4-5 10 4 0 | 0 1 | 3 3 | 6-7 15 5 0 | 0 2 | 4 4 | 8-9 15 ... ... 25 0 | 0 12| 24 24| 48-49 12 ... 32 0 | 0 15| 31 31| 62-63 12 33 0 | 0 16| 0 32| 0-1 10 ... 64 0 | 0 31| 31 63| 62-63 0 Signed-off-by: Souradeep Chakrabarti Signed-off-by: Paolo Abeni --- .../net/ethernet/microsoft/mana/gdma_main.c | 59 +++++++++++++++---- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index 05a0ac054823..1332db9a08eb 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -1249,7 +1249,7 @@ void mana_gd_free_res_map(struct gdma_resource *r) r->size = 0; } -static __maybe_unused int irq_setup(unsigned int *irqs, unsigned int len, int node) +static int irq_setup(unsigned int *irqs, unsigned int len, int node) { const struct cpumask *next, *prev = cpu_none_mask; cpumask_var_t cpus __free(free_cpumask_var); @@ -1280,13 +1280,16 @@ done: static int mana_gd_setup_irqs(struct pci_dev *pdev) { - unsigned int max_queues_per_port = num_online_cpus(); struct gdma_context *gc = pci_get_drvdata(pdev); + unsigned int max_queues_per_port; struct gdma_irq_context *gic; unsigned int max_irqs, cpu; - int nvec, irq; + int start_irq_index = 1; + int nvec, *irqs, irq; int err, i = 0, j; + cpus_read_lock(); + max_queues_per_port = num_online_cpus(); if (max_queues_per_port > MANA_MAX_NUM_QUEUES) max_queues_per_port = MANA_MAX_NUM_QUEUES; @@ -1294,8 +1297,18 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) max_irqs = max_queues_per_port + 1; nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX); - if (nvec < 0) + if (nvec < 0) { + cpus_read_unlock(); return nvec; + } + if (nvec <= num_online_cpus()) + start_irq_index = 0; + + irqs = kmalloc_array((nvec - start_irq_index), sizeof(int), GFP_KERNEL); + if (!irqs) { + err = -ENOMEM; + goto free_irq_vector; + } gc->irq_contexts = kcalloc(nvec, sizeof(struct gdma_irq_context), GFP_KERNEL); @@ -1323,17 +1336,41 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) goto free_irq; } - err = request_irq(irq, mana_gd_intr, 0, gic->name, gic); - if (err) - goto free_irq; + if (!i) { + err = request_irq(irq, mana_gd_intr, 0, gic->name, gic); + if (err) + goto free_irq; - cpu = cpumask_local_spread(i, gc->numa_node); - irq_set_affinity_and_hint(irq, cpumask_of(cpu)); + /* If number of IRQ is one extra than number of online CPUs, + * then we need to assign IRQ0 (hwc irq) and IRQ1 to + * same CPU. + * Else we will use different CPUs for IRQ0 and IRQ1. + * Also we are using cpumask_local_spread instead of + * cpumask_first for the node, because the node can be + * mem only. + */ + if (start_irq_index) { + cpu = cpumask_local_spread(i, gc->numa_node); + irq_set_affinity_and_hint(irq, cpumask_of(cpu)); + } else { + irqs[start_irq_index] = irq; + } + } else { + irqs[i - start_irq_index] = irq; + err = request_irq(irqs[i - start_irq_index], mana_gd_intr, 0, + gic->name, gic); + if (err) + goto free_irq; + } } + err = irq_setup(irqs, (nvec - start_irq_index), gc->numa_node); + if (err) + goto free_irq; + gc->max_num_msix = nvec; gc->num_msix_usable = nvec; - + cpus_read_unlock(); return 0; free_irq: @@ -1346,8 +1383,10 @@ free_irq: } kfree(gc->irq_contexts); + kfree(irqs); gc->irq_contexts = NULL; free_irq_vector: + cpus_read_unlock(); pci_free_irq_vectors(pdev); return err; } From 0def8a15dae7964a32d43bf598e289b19334040a Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:43 +0000 Subject: [PATCH 0559/2255] net: ena: Remove an unused field Remove io_sq->header_addr field because it is no longer in use. LLQ was updated to support a bounce buffer so there is no need in saving the header address of the sq. Signed-off-by: Nati Koler Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_com.c | 3 --- drivers/net/ethernet/amazon/ena/ena_com.h | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 633b321d7fdd..9a8a43b78967 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -1284,9 +1284,6 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, (uintptr_t)cmd_completion.sq_doorbell_offset); if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { - io_sq->header_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar - + cmd_completion.llq_headers_offset); - io_sq->desc_addr.pbuf_dev_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar + cmd_completion.llq_descriptors_offset); diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 3c5081d9d25d..f3176fc63d70 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -158,7 +158,6 @@ struct ena_com_io_sq { struct ena_com_io_desc_addr desc_addr; u32 __iomem *db_addr; - u8 __iomem *header_addr; enum queue_direction direction; enum ena_admin_placement_policy_type mem_queue_type; From bd765cc910127ee8ed6cd83dae0f0bfbca69d71e Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:44 +0000 Subject: [PATCH 0560/2255] net: ena: Add more documentation for RX copybreak This patch contains more details about the functionality of RX copybreak. Signed-off-by: Shay Agroskin Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- .../networking/device_drivers/ethernet/amazon/ena.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst index b842bcb14255..a4c7d0c65fd7 100644 --- a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst +++ b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst @@ -211,10 +211,16 @@ Documentation/networking/net_dim.rst RX copybreak ============ + The rx_copybreak is initialized by default to ENA_DEFAULT_RX_COPYBREAK and can be configured by the ETHTOOL_STUNABLE command of the SIOCETHTOOL ioctl. +This option controls the maximum packet length for which the RX +descriptor it was received on would be recycled. When a packet smaller +than RX copybreak bytes is received, it is copied into a new memory +buffer and the RX descriptor is returned to HW. + Statistics ========== From 243f36eef5c72f69d67a0474402bb77a56beff4f Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:45 +0000 Subject: [PATCH 0561/2255] net: ena: Minor cosmetic changes A few changes for better readability and style 1. Adding / Removing newlines 2. Removing an unnecessary and confusing comment 3. Using an existing variable rather than re-checking a field Signed-off-by: Shay Agroskin Signed-off-by: Arthur Kiyanovski Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 1c0a7828d397..d68d08147f03 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2197,8 +2197,6 @@ void ena_down(struct ena_adapter *adapter) /* After this point the napi handler won't enable the tx queue */ ena_napi_disable_in_range(adapter, 0, io_queue_count); - /* After destroy the queue there won't be any new interrupts */ - if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) { int rc; @@ -3226,7 +3224,7 @@ static void ena_destroy_device(struct ena_adapter *adapter, bool graceful) if (!graceful) ena_com_set_admin_running_state(ena_dev, false); - if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags)) + if (dev_up) ena_down(adapter); /* Stop the device from sending AENQ events (in case reset flag is set @@ -4040,8 +4038,8 @@ static void __ena_shutoff(struct pci_dev *pdev, bool shutdown) free_irq_cpu_rmap(netdev->rx_cpu_rmap); netdev->rx_cpu_rmap = NULL; } -#endif /* CONFIG_RFS_ACCEL */ +#endif /* CONFIG_RFS_ACCEL */ /* Make sure timer and reset routine won't be called after * freeing device resources. */ From 50d7a2660579889fba28b7e4543d4ce85aa2311b Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:46 +0000 Subject: [PATCH 0562/2255] net: ena: Enable DIM by default Dynamic Interrupt Moderation (DIM) is a technique designed to balance the need for timely data processing with the desire to minimize CPU overhead. Instead of generating an interrupt for every received packet, the system can dynamically adjust the rate at which interrupts are generated based on the incoming traffic patterns. Enabling DIM by default to improve the user experience. DIM can be turned on/off through ethtool: `ethtool -C adaptive-rx ` Signed-off-by: Arthur Kiyanovski Signed-off-by: Osama Abboud Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index d68d08147f03..0b7f94f6c631 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2134,6 +2134,12 @@ int ena_up(struct ena_adapter *adapter) */ ena_init_napi_in_range(adapter, 0, io_queue_count); + /* Enabling DIM needs to happen before enabling IRQs since DIM + * is run from napi routine + */ + if (ena_com_interrupt_moderation_supported(adapter->ena_dev)) + ena_com_enable_adaptive_moderation(adapter->ena_dev); + rc = ena_request_io_irq(adapter); if (rc) goto err_req_irq; From 06a96fe6f9f02f1205774b60c2f42f09a6832f31 Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:47 +0000 Subject: [PATCH 0563/2255] net: ena: Remove CQ tail pointer update The functionality was added to allow the drivers to create an SQ and CQ of different sizes. When the RX/TX SQ and CQ have the same size, such update isn't necessary as the device can safely assume it doesn't override unprocessed completions. However, if the SQ is larger than the CQ, the device might "have" more completions it wants to update about than there's room in the CQ. There's no support for different SQ and CQ sizes, therefore, removing the API and its usage. '____cacheline_aligned' compiler attribute was added to 'struct ena_com_io_cq' to ensure that the removal of the 'cq_head_db_reg' field doesn't change the cache-line layout of this struct. Signed-off-by: Shay Agroskin Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_com.c | 5 ---- drivers/net/ethernet/amazon/ena/ena_com.h | 6 +---- drivers/net/ethernet/amazon/ena/ena_eth_com.h | 24 ------------------- drivers/net/ethernet/amazon/ena/ena_netdev.c | 5 +--- drivers/net/ethernet/amazon/ena/ena_xdp.c | 1 - 5 files changed, 2 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 9a8a43b78967..675ee728fe52 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -1427,11 +1427,6 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, io_cq->unmask_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + cmd_completion.cq_interrupt_unmask_register_offset); - if (cmd_completion.cq_head_db_register_offset) - io_cq->cq_head_db_reg = - (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + - cmd_completion.cq_head_db_register_offset); - if (cmd_completion.numa_node_register_offset) io_cq->numa_node_cfg_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index f3176fc63d70..fea57eb8e58b 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -109,16 +109,13 @@ struct ena_com_io_cq { /* Interrupt unmask register */ u32 __iomem *unmask_reg; - /* The completion queue head doorbell register */ - u32 __iomem *cq_head_db_reg; - /* numa configuration register (for TPH) */ u32 __iomem *numa_node_cfg_reg; /* The value to write to the above register to unmask * the interrupt of this queue */ - u32 msix_vector; + u32 msix_vector ____cacheline_aligned; enum queue_direction direction; @@ -134,7 +131,6 @@ struct ena_com_io_cq { /* Device queue index */ u16 idx; u16 head; - u16 last_head_update; u8 phase; u8 cdesc_entry_size_in_bytes; diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h index 372b259279ec..4d65d820a95e 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h @@ -8,8 +8,6 @@ #include "ena_com.h" -/* head update threshold in units of (queue size / ENA_COMP_HEAD_THRESH) */ -#define ENA_COMP_HEAD_THRESH 4 /* we allow 2 DMA descriptors per LLQ entry */ #define ENA_LLQ_ENTRY_DESC_CHUNK_SIZE (2 * sizeof(struct ena_eth_io_tx_desc)) #define ENA_LLQ_HEADER (128UL - ENA_LLQ_ENTRY_DESC_CHUNK_SIZE) @@ -172,28 +170,6 @@ static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq) return 0; } -static inline int ena_com_update_dev_comp_head(struct ena_com_io_cq *io_cq) -{ - u16 unreported_comp, head; - bool need_update; - - if (unlikely(io_cq->cq_head_db_reg)) { - head = io_cq->head; - unreported_comp = head - io_cq->last_head_update; - need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH); - - if (unlikely(need_update)) { - netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Write completion queue doorbell for queue %d: head: %d\n", - io_cq->qid, head); - writel(head, io_cq->cq_head_db_reg); - io_cq->last_head_update = head; - } - } - - return 0; -} - static inline void ena_com_update_numa_node(struct ena_com_io_cq *io_cq, u8 numa_node) { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 0b7f94f6c631..cd75e5a7a52e 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -856,7 +856,6 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) tx_ring->next_to_clean = next_to_clean; ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done); - ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq); netdev_tx_completed_queue(txq, tx_pkts, tx_bytes); @@ -1303,10 +1302,8 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, ENA_RX_REFILL_THRESH_PACKET); /* Optimization, try to batch new rx buffers */ - if (refill_required > refill_threshold) { - ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq); + if (refill_required > refill_threshold) ena_refill_rx_bufs(rx_ring, refill_required); - } if (xdp_flags & ENA_XDP_REDIRECT) xdp_do_flush(); diff --git a/drivers/net/ethernet/amazon/ena/ena_xdp.c b/drivers/net/ethernet/amazon/ena/ena_xdp.c index fc1c4ef73ba3..337c435d3ce9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_xdp.c +++ b/drivers/net/ethernet/amazon/ena/ena_xdp.c @@ -412,7 +412,6 @@ static int ena_clean_xdp_irq(struct ena_ring *tx_ring, u32 budget) tx_ring->next_to_clean = next_to_clean; ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done); - ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq); netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev, "tx_poll: q %d done. total pkts: %d\n", From ae82209293297c423c0c40575cae7b464248866c Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:48 +0000 Subject: [PATCH 0564/2255] net: ena: Change error print during ena_device_init() The print was re-worded to a more informative one. Signed-off-by: Shahar Itzko Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index cd75e5a7a52e..18acb764e446 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3071,6 +3071,7 @@ static int ena_device_init(struct ena_adapter *adapter, struct pci_dev *pdev, bool *wd_state) { struct ena_com_dev *ena_dev = adapter->ena_dev; + struct net_device *netdev = adapter->netdev; struct ena_llq_configurations llq_config; struct device *dev = &pdev->dev; bool readless_supported; @@ -3160,7 +3161,7 @@ static int ena_device_init(struct ena_adapter *adapter, struct pci_dev *pdev, rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx->llq, &llq_config); if (rc) { - dev_err(dev, "ENA device init failed\n"); + netdev_err(netdev, "Cannot set queues placement policy rc= %d\n", rc); goto err_admin_init; } From 071271f39ce833a3534d1fbd47174d1bed6d9326 Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:49 +0000 Subject: [PATCH 0565/2255] net: ena: Add more information on TX timeouts The function responsible for polling TX completions might not receive the CPU resources it needs due to higher priority tasks running on the requested core. The driver might not be able to recognize such cases, but it can use its state to suspect that they happened. If both conditions are met: - napi hasn't been executed more than the TX completion timeout value - napi is scheduled (meaning that we've received an interrupt) Then it's more likely that the napi handler isn't scheduled because of an overloaded CPU. It was decided that for this case, the driver would wait twice as long as the regular timeout before scheduling a reset. The driver uses ENA_REGS_RESET_SUSPECTED_POLL_STARVATION reset reason to indicate this case to the device. This patch also adds more information to the ena_tx_timeout() callback. This function is called by the kernel when it detects that a specific TX queue has been closed for too long. Signed-off-by: Shay Agroskin Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 77 +++++++++++++++---- .../net/ethernet/amazon/ena/ena_regs_defs.h | 1 + 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 18acb764e446..ae9291b61be2 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -47,19 +47,44 @@ static int ena_restore_device(struct ena_adapter *adapter); static void ena_tx_timeout(struct net_device *dev, unsigned int txqueue) { + enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_OS_NETDEV_WD; struct ena_adapter *adapter = netdev_priv(dev); + unsigned int time_since_last_napi, threshold; + struct ena_ring *tx_ring; + int napi_scheduled; + if (txqueue >= adapter->num_io_queues) { + netdev_err(dev, "TX timeout on invalid queue %u\n", txqueue); + goto schedule_reset; + } + + threshold = jiffies_to_usecs(dev->watchdog_timeo); + tx_ring = &adapter->tx_ring[txqueue]; + + time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies); + napi_scheduled = !!(tx_ring->napi->state & NAPIF_STATE_SCHED); + + netdev_err(dev, + "TX q %d is paused for too long (threshold %u). Time since last napi %u usec. napi scheduled: %d\n", + txqueue, + threshold, + time_since_last_napi, + napi_scheduled); + + if (threshold < time_since_last_napi && napi_scheduled) { + netdev_err(dev, + "napi handler hasn't been called for a long time but is scheduled\n"); + reset_reason = ENA_REGS_RESET_SUSPECTED_POLL_STARVATION; + } +schedule_reset: /* Change the state of the device to trigger reset * Check that we are not in the middle or a trigger already */ - if (test_and_set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) return; - ena_reset_device(adapter, ENA_REGS_RESET_OS_NETDEV_WD); + ena_reset_device(adapter, reset_reason); ena_increase_stat(&adapter->dev_stats.tx_timeout, 1, &adapter->syncp); - - netif_err(adapter, tx_err, dev, "Transmit time out\n"); } static void update_rx_ring_mtu(struct ena_adapter *adapter, int mtu) @@ -3374,14 +3399,18 @@ static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter, struct ena_ring *tx_ring) { struct ena_napi *ena_napi = container_of(tx_ring->napi, struct ena_napi, napi); + enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_MISS_TX_CMPL; unsigned int time_since_last_napi; unsigned int missing_tx_comp_to; bool is_tx_comp_time_expired; struct ena_tx_buffer *tx_buf; unsigned long last_jiffies; + int napi_scheduled; u32 missed_tx = 0; int i, rc = 0; + missing_tx_comp_to = jiffies_to_msecs(adapter->missing_tx_completion_to); + for (i = 0; i < tx_ring->ring_size; i++) { tx_buf = &tx_ring->tx_buffer_info[i]; last_jiffies = tx_buf->last_jiffies; @@ -3408,25 +3437,45 @@ static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter, adapter->missing_tx_completion_to); if (unlikely(is_tx_comp_time_expired)) { - if (!tx_buf->print_once) { - time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies); - missing_tx_comp_to = jiffies_to_msecs(adapter->missing_tx_completion_to); - netif_notice(adapter, tx_err, adapter->netdev, - "Found a Tx that wasn't completed on time, qid %d, index %d. %u usecs have passed since last napi execution. Missing Tx timeout value %u msecs\n", - tx_ring->qid, i, time_since_last_napi, missing_tx_comp_to); + time_since_last_napi = + jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies); + napi_scheduled = !!(ena_napi->napi.state & NAPIF_STATE_SCHED); + + if (missing_tx_comp_to < time_since_last_napi && napi_scheduled) { + /* We suspect napi isn't called because the + * bottom half is not run. Require a bigger + * timeout for these cases + */ + if (!time_is_before_jiffies(last_jiffies + + 2 * adapter->missing_tx_completion_to)) + continue; + + reset_reason = ENA_REGS_RESET_SUSPECTED_POLL_STARVATION; } - tx_buf->print_once = 1; missed_tx++; + + if (tx_buf->print_once) + continue; + + netif_notice(adapter, tx_err, adapter->netdev, + "TX hasn't completed, qid %d, index %d. %u usecs from last napi execution, napi scheduled: %d\n", + tx_ring->qid, i, time_since_last_napi, napi_scheduled); + + tx_buf->print_once = 1; } } if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) { netif_err(adapter, tx_err, adapter->netdev, - "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n", + "Lost TX completions are above the threshold (%d > %d). Completion transmission timeout: %u.\n", missed_tx, - adapter->missing_tx_completion_threshold); - ena_reset_device(adapter, ENA_REGS_RESET_MISS_TX_CMPL); + adapter->missing_tx_completion_threshold, + missing_tx_comp_to); + netif_err(adapter, tx_err, adapter->netdev, + "Resetting the device\n"); + + ena_reset_device(adapter, reset_reason); rc = -EIO; } diff --git a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h index 1e007a41a525..2c3d6a77ea79 100644 --- a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h @@ -21,6 +21,7 @@ enum ena_regs_reset_reason_types { ENA_REGS_RESET_USER_TRIGGER = 12, ENA_REGS_RESET_GENERIC = 13, ENA_REGS_RESET_MISS_INTERRUPT = 14, + ENA_REGS_RESET_SUSPECTED_POLL_STARVATION = 15, }; /* ena_registers offsets */ From 70c9360390ea9c1e5a86109f34b9f0ae0c60be82 Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:50 +0000 Subject: [PATCH 0566/2255] net: ena: Relocate skb_tx_timestamp() to improve time stamping accuracy Move skb_tx_timestamp() closer to the actual time the driver sends the packets to the device. Signed-off-by: Osama Abboud Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index ae9291b61be2..d4ca406c65ee 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2614,8 +2614,6 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(rc)) goto error_drop_packet; - skb_tx_timestamp(skb); - next_to_use = tx_ring->next_to_use; req_id = tx_ring->free_ids[next_to_use]; tx_info = &tx_ring->tx_buffer_info[req_id]; @@ -2679,6 +2677,8 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) } } + skb_tx_timestamp(skb); + if (netif_xmit_stopped(txq) || !netdev_xmit_more()) /* trigger the dma engine. ena_ring_tx_doorbell() * calls a memory barrier inside it. From 716bdaeceaeea93be4028218ebe42d19cdd48625 Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:51 +0000 Subject: [PATCH 0567/2255] net: ena: Change default print level for netif_ prints The netif_* functions are used by the driver to log events into the kernel ring (dmesg) similar to the netdev_* ones. Unlike the latter, the netif_* function family allow the user to choose what events get logged using ethtool: sudo ethtool -s [interface] msglvl [msg_type] on By default the events which get logged are slow-path related and aren't printed often (e.g. interface up related prints). This patch removes the NETIF_MSG_TX_DONE type (called every TX completion polling) from the defaults and adds NETIF_MSG_IFDOWN instead as it makes more sensible defaults. This patch also transforms ena_down() print from netif_info into netif_dbg (same as the analogue print in ena_up()) as it suits it better. Signed-off-by: Shay Agroskin Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index d4ca406c65ee..8d999045ef71 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -32,7 +32,7 @@ MODULE_LICENSE("GPL"); #define ENA_MAX_RINGS min_t(unsigned int, ENA_MAX_NUM_IO_QUEUES, num_possible_cpus()) #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | \ - NETIF_MSG_TX_DONE | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR) + NETIF_MSG_IFDOWN | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR) static struct ena_aenq_handlers aenq_handlers; @@ -2212,7 +2212,7 @@ void ena_down(struct ena_adapter *adapter) { int io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues; - netif_info(adapter, ifdown, adapter->netdev, "%s\n", __func__); + netif_dbg(adapter, ifdown, adapter->netdev, "%s\n", __func__); clear_bit(ENA_FLAG_DEV_UP, &adapter->flags); From 4b4012da28cf240d0208833297c4435a11de0039 Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:52 +0000 Subject: [PATCH 0568/2255] net: ena: handle ena_calc_io_queue_size() possible errors Fail queue size calculation when the device returns maximum TX/RX queue sizes that are smaller than the allowed minimum. Signed-off-by: Osama Abboud Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 24 +++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 8d999045ef71..965a01c5e245 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2899,8 +2899,8 @@ static const struct net_device_ops ena_netdev_ops = { .ndo_xdp_xmit = ena_xdp_xmit, }; -static void ena_calc_io_queue_size(struct ena_adapter *adapter, - struct ena_com_dev_get_features_ctx *get_feat_ctx) +static int ena_calc_io_queue_size(struct ena_adapter *adapter, + struct ena_com_dev_get_features_ctx *get_feat_ctx) { struct ena_admin_feature_llq_desc *llq = &get_feat_ctx->llq; struct ena_com_dev *ena_dev = adapter->ena_dev; @@ -2959,6 +2959,18 @@ static void ena_calc_io_queue_size(struct ena_adapter *adapter, max_tx_queue_size = rounddown_pow_of_two(max_tx_queue_size); max_rx_queue_size = rounddown_pow_of_two(max_rx_queue_size); + if (max_tx_queue_size < ENA_MIN_RING_SIZE) { + netdev_err(adapter->netdev, "Device max TX queue size: %d < minimum: %d\n", + max_tx_queue_size, ENA_MIN_RING_SIZE); + return -EINVAL; + } + + if (max_rx_queue_size < ENA_MIN_RING_SIZE) { + netdev_err(adapter->netdev, "Device max RX queue size: %d < minimum: %d\n", + max_rx_queue_size, ENA_MIN_RING_SIZE); + return -EINVAL; + } + /* When forcing large headers, we multiply the entry size by 2, and therefore divide * the queue size by 2, leaving the amount of memory used by the queues unchanged. */ @@ -2989,6 +3001,8 @@ static void ena_calc_io_queue_size(struct ena_adapter *adapter, adapter->max_rx_ring_size = max_rx_queue_size; adapter->requested_tx_ring_size = tx_queue_size; adapter->requested_rx_ring_size = rx_queue_size; + + return 0; } static int ena_device_validate_params(struct ena_adapter *adapter, @@ -3190,11 +3204,15 @@ static int ena_device_init(struct ena_adapter *adapter, struct pci_dev *pdev, goto err_admin_init; } - ena_calc_io_queue_size(adapter, get_feat_ctx); + rc = ena_calc_io_queue_size(adapter, get_feat_ctx); + if (unlikely(rc)) + goto err_admin_init; return 0; err_admin_init: + ena_com_abort_admin_commands(ena_dev); + ena_com_wait_for_abort_completion(ena_dev); ena_com_delete_host_info(ena_dev); ena_com_admin_destroy(ena_dev); err_mmio_read_less: From 50613650c3d6255cef13a129ccaa919ca73a6743 Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 30 Jan 2024 09:53:53 +0000 Subject: [PATCH 0569/2255] net: ena: Reduce lines with longer column width boundary This patch reduces some of the lines by removing newlines where more variables or print strings can be pushed back to the previous line while still adhering to the styling guidelines. Signed-off-by: David Arinzon Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_com.c | 315 +++++++----------- drivers/net/ethernet/amazon/ena/ena_eth_com.c | 49 ++- drivers/net/ethernet/amazon/ena/ena_eth_com.h | 15 +- drivers/net/ethernet/amazon/ena/ena_netdev.c | 32 +- 4 files changed, 151 insertions(+), 260 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 675ee728fe52..9e9e4a03f1a8 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -90,8 +90,7 @@ static int ena_com_admin_init_sq(struct ena_com_admin_queue *admin_queue) struct ena_com_admin_sq *sq = &admin_queue->sq; u16 size = ADMIN_SQ_SIZE(admin_queue->q_depth); - sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, - &sq->dma_addr, GFP_KERNEL); + sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &sq->dma_addr, GFP_KERNEL); if (!sq->entries) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); @@ -113,8 +112,7 @@ static int ena_com_admin_init_cq(struct ena_com_admin_queue *admin_queue) struct ena_com_admin_cq *cq = &admin_queue->cq; u16 size = ADMIN_CQ_SIZE(admin_queue->q_depth); - cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, - &cq->dma_addr, GFP_KERNEL); + cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &cq->dma_addr, GFP_KERNEL); if (!cq->entries) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); @@ -136,8 +134,7 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev, ena_dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH; size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH); - aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, - &aenq->dma_addr, GFP_KERNEL); + aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, &aenq->dma_addr, GFP_KERNEL); if (!aenq->entries) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); @@ -155,14 +152,13 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev, aenq_caps = 0; aenq_caps |= ena_dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK; - aenq_caps |= (sizeof(struct ena_admin_aenq_entry) - << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & - ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; + aenq_caps |= + (sizeof(struct ena_admin_aenq_entry) << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & + ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; writel(aenq_caps, ena_dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF); if (unlikely(!aenq_handlers)) { - netdev_err(ena_dev->net_device, - "AENQ handlers pointer is NULL\n"); + netdev_err(ena_dev->net_device, "AENQ handlers pointer is NULL\n"); return -EINVAL; } @@ -189,14 +185,12 @@ static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *admin_queu } if (unlikely(!admin_queue->comp_ctx)) { - netdev_err(admin_queue->ena_dev->net_device, - "Completion context is NULL\n"); + netdev_err(admin_queue->ena_dev->net_device, "Completion context is NULL\n"); return NULL; } if (unlikely(admin_queue->comp_ctx[command_id].occupied && capture)) { - netdev_err(admin_queue->ena_dev->net_device, - "Completion context is occupied\n"); + netdev_err(admin_queue->ena_dev->net_device, "Completion context is occupied\n"); return NULL; } @@ -226,8 +220,7 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu /* In case of queue FULL */ cnt = (u16)atomic_read(&admin_queue->outstanding_cmds); if (cnt >= admin_queue->q_depth) { - netdev_dbg(admin_queue->ena_dev->net_device, - "Admin queue is full.\n"); + netdev_dbg(admin_queue->ena_dev->net_device, "Admin queue is full.\n"); admin_queue->stats.out_of_space++; return ERR_PTR(-ENOSPC); } @@ -274,8 +267,7 @@ static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *admin_queue) struct ena_comp_ctx *comp_ctx; u16 i; - admin_queue->comp_ctx = - devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL); + admin_queue->comp_ctx = devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL); if (unlikely(!admin_queue->comp_ctx)) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); return -ENOMEM; @@ -336,20 +328,17 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, dev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); io_sq->desc_addr.virt_addr = - dma_alloc_coherent(ena_dev->dmadev, size, - &io_sq->desc_addr.phys_addr, + dma_alloc_coherent(ena_dev->dmadev, size, &io_sq->desc_addr.phys_addr, GFP_KERNEL); set_dev_node(ena_dev->dmadev, dev_node); if (!io_sq->desc_addr.virt_addr) { io_sq->desc_addr.virt_addr = dma_alloc_coherent(ena_dev->dmadev, size, - &io_sq->desc_addr.phys_addr, - GFP_KERNEL); + &io_sq->desc_addr.phys_addr, GFP_KERNEL); } if (!io_sq->desc_addr.virt_addr) { - netdev_err(ena_dev->net_device, - "Memory allocation failed\n"); + netdev_err(ena_dev->net_device, "Memory allocation failed\n"); return -ENOMEM; } } @@ -367,16 +356,14 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, dev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); - io_sq->bounce_buf_ctrl.base_buffer = - devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); + io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); set_dev_node(ena_dev->dmadev, dev_node); if (!io_sq->bounce_buf_ctrl.base_buffer) io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); if (!io_sq->bounce_buf_ctrl.base_buffer) { - netdev_err(ena_dev->net_device, - "Bounce buffer memory allocation failed\n"); + netdev_err(ena_dev->net_device, "Bounce buffer memory allocation failed\n"); return -ENOMEM; } @@ -425,13 +412,11 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev, prev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); io_cq->cdesc_addr.virt_addr = - dma_alloc_coherent(ena_dev->dmadev, size, - &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); set_dev_node(ena_dev->dmadev, prev_node); if (!io_cq->cdesc_addr.virt_addr) { io_cq->cdesc_addr.virt_addr = - dma_alloc_coherent(ena_dev->dmadev, size, - &io_cq->cdesc_addr.phys_addr, + dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); } @@ -514,8 +499,8 @@ static int ena_com_comp_status_to_errno(struct ena_com_admin_queue *admin_queue, u8 comp_status) { if (unlikely(comp_status != 0)) - netdev_err(admin_queue->ena_dev->net_device, - "Admin command failed[%u]\n", comp_status); + netdev_err(admin_queue->ena_dev->net_device, "Admin command failed[%u]\n", + comp_status); switch (comp_status) { case ENA_ADMIN_SUCCESS: @@ -580,8 +565,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c } if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) { - netdev_err(admin_queue->ena_dev->net_device, - "Command was aborted\n"); + netdev_err(admin_queue->ena_dev->net_device, "Command was aborted\n"); spin_lock_irqsave(&admin_queue->q_lock, flags); admin_queue->stats.aborted_cmd++; spin_unlock_irqrestore(&admin_queue->q_lock, flags); @@ -589,8 +573,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c goto err; } - WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", - comp_ctx->status); + WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", comp_ctx->status); ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status); err: @@ -634,8 +617,7 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set LLQ configurations: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set LLQ configurations: %d\n", ret); return ret; } @@ -658,8 +640,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, llq_default_cfg->llq_header_location; } else { netdev_err(ena_dev->net_device, - "Invalid header location control, supported: 0x%x\n", - supported_feat); + "Invalid header location control, supported: 0x%x\n", supported_feat); return -EINVAL; } @@ -681,8 +662,8 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, netdev_err(ena_dev->net_device, "Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", - llq_default_cfg->llq_stride_ctrl, - supported_feat, llq_info->desc_stride_ctrl); + llq_default_cfg->llq_stride_ctrl, supported_feat, + llq_info->desc_stride_ctrl); } } else { llq_info->desc_stride_ctrl = 0; @@ -704,8 +685,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, llq_info->desc_list_entry_size = 256; } else { netdev_err(ena_dev->net_device, - "Invalid entry_size_ctrl, supported: 0x%x\n", - supported_feat); + "Invalid entry_size_ctrl, supported: 0x%x\n", supported_feat); return -EINVAL; } @@ -750,8 +730,8 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, netdev_err(ena_dev->net_device, "Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", - llq_default_cfg->llq_num_decs_before_header, - supported_feat, llq_info->descs_num_before_header); + llq_default_cfg->llq_num_decs_before_header, supported_feat, + llq_info->descs_num_before_header); } /* Check for accelerated queue supported */ llq_accel_mode_get = llq_features->accel_mode.u.get; @@ -767,8 +747,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, rc = ena_com_set_llq(ena_dev); if (rc) - netdev_err(ena_dev->net_device, - "Cannot set LLQ configuration: %d\n", rc); + netdev_err(ena_dev->net_device, "Cannot set LLQ configuration: %d\n", rc); return rc; } @@ -780,8 +759,7 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com int ret; wait_for_completion_timeout(&comp_ctx->wait_event, - usecs_to_jiffies( - admin_queue->completion_timeout)); + usecs_to_jiffies(admin_queue->completion_timeout)); /* In case the command wasn't completed find out the root cause. * There might be 2 kinds of errors @@ -797,8 +775,7 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com if (comp_ctx->status == ENA_CMD_COMPLETED) { netdev_err(admin_queue->ena_dev->net_device, "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n", - comp_ctx->cmd_opcode, - admin_queue->auto_polling ? "ON" : "OFF"); + comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF"); /* Check if fallback to polling is enabled */ if (admin_queue->auto_polling) admin_queue->polling = true; @@ -867,15 +844,13 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) if (unlikely(i == timeout)) { netdev_err(ena_dev->net_device, "Reading reg failed for timeout. expected: req id[%u] offset[%u] actual: req id[%u] offset[%u]\n", - mmio_read->seq_num, offset, read_resp->req_id, - read_resp->reg_off); + mmio_read->seq_num, offset, read_resp->req_id, read_resp->reg_off); ret = ENA_MMIO_READ_TIMEOUT; goto err; } if (read_resp->reg_off != offset) { - netdev_err(ena_dev->net_device, - "Read failure: wrong offset provided\n"); + netdev_err(ena_dev->net_device, "Read failure: wrong offset provided\n"); ret = ENA_MMIO_READ_TIMEOUT; } else { ret = read_resp->reg_val; @@ -934,8 +909,7 @@ static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev, sizeof(destroy_resp)); if (unlikely(ret && (ret != -ENODEV))) - netdev_err(ena_dev->net_device, - "Failed to destroy io sq error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to destroy io sq error: %d\n", ret); return ret; } @@ -949,8 +923,7 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, if (io_cq->cdesc_addr.virt_addr) { size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; - dma_free_coherent(ena_dev->dmadev, size, - io_cq->cdesc_addr.virt_addr, + dma_free_coherent(ena_dev->dmadev, size, io_cq->cdesc_addr.virt_addr, io_cq->cdesc_addr.phys_addr); io_cq->cdesc_addr.virt_addr = NULL; @@ -959,8 +932,7 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, if (io_sq->desc_addr.virt_addr) { size = io_sq->desc_entry_size * io_sq->q_depth; - dma_free_coherent(ena_dev->dmadev, size, - io_sq->desc_addr.virt_addr, + dma_free_coherent(ena_dev->dmadev, size, io_sq->desc_addr.virt_addr, io_sq->desc_addr.phys_addr); io_sq->desc_addr.virt_addr = NULL; @@ -985,8 +957,7 @@ static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) { - netdev_err(ena_dev->net_device, - "Reg read timeout occurred\n"); + netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); return -ETIME; } @@ -1026,8 +997,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, int ret; if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) { - netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", - feature_id); + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", feature_id); return -EOPNOTSUPP; } @@ -1064,8 +1034,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, if (unlikely(ret)) netdev_err(ena_dev->net_device, - "Failed to submit get_feature command %d error: %d\n", - feature_id, ret); + "Failed to submit get_feature command %d error: %d\n", feature_id, ret); return ret; } @@ -1104,13 +1073,11 @@ static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) { struct ena_rss *rss = &ena_dev->rss; - if (!ena_com_check_supported_feature_id(ena_dev, - ENA_ADMIN_RSS_HASH_FUNCTION)) + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION)) return -EOPNOTSUPP; - rss->hash_key = - dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), - &rss->hash_key_dma_addr, GFP_KERNEL); + rss->hash_key = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), + &rss->hash_key_dma_addr, GFP_KERNEL); if (unlikely(!rss->hash_key)) return -ENOMEM; @@ -1123,8 +1090,8 @@ static void ena_com_hash_key_destroy(struct ena_com_dev *ena_dev) struct ena_rss *rss = &ena_dev->rss; if (rss->hash_key) - dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), - rss->hash_key, rss->hash_key_dma_addr); + dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), rss->hash_key, + rss->hash_key_dma_addr); rss->hash_key = NULL; } @@ -1132,9 +1099,8 @@ static int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev) { struct ena_rss *rss = &ena_dev->rss; - rss->hash_ctrl = - dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), - &rss->hash_ctrl_dma_addr, GFP_KERNEL); + rss->hash_ctrl = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), + &rss->hash_ctrl_dma_addr, GFP_KERNEL); if (unlikely(!rss->hash_ctrl)) return -ENOMEM; @@ -1147,8 +1113,8 @@ static void ena_com_hash_ctrl_destroy(struct ena_com_dev *ena_dev) struct ena_rss *rss = &ena_dev->rss; if (rss->hash_ctrl) - dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), - rss->hash_ctrl, rss->hash_ctrl_dma_addr); + dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), rss->hash_ctrl, + rss->hash_ctrl_dma_addr); rss->hash_ctrl = NULL; } @@ -1177,15 +1143,13 @@ static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev, tbl_size = (1ULL << log_size) * sizeof(struct ena_admin_rss_ind_table_entry); - rss->rss_ind_tbl = - dma_alloc_coherent(ena_dev->dmadev, tbl_size, - &rss->rss_ind_tbl_dma_addr, GFP_KERNEL); + rss->rss_ind_tbl = dma_alloc_coherent(ena_dev->dmadev, tbl_size, &rss->rss_ind_tbl_dma_addr, + GFP_KERNEL); if (unlikely(!rss->rss_ind_tbl)) goto mem_err1; tbl_size = (1ULL << log_size) * sizeof(u16); - rss->host_rss_ind_tbl = - devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL); + rss->host_rss_ind_tbl = devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL); if (unlikely(!rss->host_rss_ind_tbl)) goto mem_err2; @@ -1197,8 +1161,7 @@ mem_err2: tbl_size = (1ULL << log_size) * sizeof(struct ena_admin_rss_ind_table_entry); - dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, - rss->rss_ind_tbl_dma_addr); + dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, rss->rss_ind_tbl_dma_addr); rss->rss_ind_tbl = NULL; mem_err1: rss->tbl_log_size = 0; @@ -1261,8 +1224,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, &create_cmd.sq_ba, io_sq->desc_addr.phys_addr); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Memory address set failed\n"); + netdev_err(ena_dev->net_device, "Memory address set failed\n"); return ret; } } @@ -1273,8 +1235,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, (struct ena_admin_acq_entry *)&cmd_completion, sizeof(cmd_completion)); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to create IO SQ. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to create IO SQ. error: %d\n", ret); return ret; } @@ -1289,8 +1250,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, cmd_completion.llq_descriptors_offset); } - netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", - io_sq->idx, io_sq->q_depth); + netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth); return ret; } @@ -1417,8 +1377,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, (struct ena_admin_acq_entry *)&cmd_completion, sizeof(cmd_completion)); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to create IO CQ. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to create IO CQ. error: %d\n", ret); return ret; } @@ -1432,8 +1391,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + cmd_completion.numa_node_register_offset); - netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", - io_cq->idx, io_cq->q_depth); + netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth); return ret; } @@ -1443,8 +1401,7 @@ int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid, struct ena_com_io_cq **io_cq) { if (qid >= ENA_TOTAL_NUM_QUEUES) { - netdev_err(ena_dev->net_device, - "Invalid queue number %d but the max is %d\n", qid, + netdev_err(ena_dev->net_device, "Invalid queue number %d but the max is %d\n", qid, ENA_TOTAL_NUM_QUEUES); return -EINVAL; } @@ -1484,8 +1441,7 @@ void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev) spin_lock_irqsave(&admin_queue->q_lock, flags); while (atomic_read(&admin_queue->outstanding_cmds) != 0) { spin_unlock_irqrestore(&admin_queue->q_lock, flags); - ena_delay_exponential_backoff_us(exp++, - ena_dev->ena_min_poll_delay_us); + ena_delay_exponential_backoff_us(exp++, ena_dev->ena_min_poll_delay_us); spin_lock_irqsave(&admin_queue->q_lock, flags); } spin_unlock_irqrestore(&admin_queue->q_lock, flags); @@ -1511,8 +1467,7 @@ int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev, sizeof(destroy_resp)); if (unlikely(ret && (ret != -ENODEV))) - netdev_err(ena_dev->net_device, - "Failed to destroy IO CQ. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to destroy IO CQ. error: %d\n", ret); return ret; } @@ -1580,8 +1535,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to config AENQ ret: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to config AENQ ret: %d\n", ret); return ret; } @@ -1602,8 +1556,7 @@ int ena_com_get_dma_width(struct ena_com_dev *ena_dev) netdev_dbg(ena_dev->net_device, "ENA dma width: %d\n", width); if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) { - netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", - width); + netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", width); return -EINVAL; } @@ -1625,19 +1578,16 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev) ctrl_ver = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CONTROLLER_VERSION_OFF); - if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || - (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { + if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); return -ETIME; } dev_info(ena_dev->dmadev, "ENA device version: %d.%d\n", - (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> - ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, + (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, ver & ENA_REGS_VERSION_MINOR_VERSION_MASK); - dev_info(ena_dev->dmadev, - "ENA controller version: %d.%d.%d implementation version %d\n", + dev_info(ena_dev->dmadev, "ENA controller version: %d.%d.%d implementation version %d\n", (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >> ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT, (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) >> @@ -1686,20 +1636,17 @@ void ena_com_admin_destroy(struct ena_com_dev *ena_dev) size = ADMIN_SQ_SIZE(admin_queue->q_depth); if (sq->entries) - dma_free_coherent(ena_dev->dmadev, size, sq->entries, - sq->dma_addr); + dma_free_coherent(ena_dev->dmadev, size, sq->entries, sq->dma_addr); sq->entries = NULL; size = ADMIN_CQ_SIZE(admin_queue->q_depth); if (cq->entries) - dma_free_coherent(ena_dev->dmadev, size, cq->entries, - cq->dma_addr); + dma_free_coherent(ena_dev->dmadev, size, cq->entries, cq->dma_addr); cq->entries = NULL; size = ADMIN_AENQ_SIZE(aenq->q_depth); if (ena_dev->aenq.entries) - dma_free_coherent(ena_dev->dmadev, size, aenq->entries, - aenq->dma_addr); + dma_free_coherent(ena_dev->dmadev, size, aenq->entries, aenq->dma_addr); aenq->entries = NULL; } @@ -1725,10 +1672,8 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; spin_lock_init(&mmio_read->lock); - mmio_read->read_resp = - dma_alloc_coherent(ena_dev->dmadev, - sizeof(*mmio_read->read_resp), - &mmio_read->read_resp_dma_addr, GFP_KERNEL); + mmio_read->read_resp = dma_alloc_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), + &mmio_read->read_resp_dma_addr, GFP_KERNEL); if (unlikely(!mmio_read->read_resp)) goto err; @@ -1759,8 +1704,8 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev) writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF); writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF); - dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), - mmio_read->read_resp, mmio_read->read_resp_dma_addr); + dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), mmio_read->read_resp, + mmio_read->read_resp_dma_addr); mmio_read->read_resp = NULL; } @@ -1792,8 +1737,7 @@ int ena_com_admin_init(struct ena_com_dev *ena_dev, } if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) { - netdev_err(ena_dev->net_device, - "Device isn't ready, abort com init\n"); + netdev_err(ena_dev->net_device, "Device isn't ready, abort com init\n"); return -ENODEV; } @@ -1870,8 +1814,7 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev, int ret; if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) { - netdev_err(ena_dev->net_device, - "Qid (%d) is bigger than max num of queues (%d)\n", + netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n", ctx->qid, ENA_TOTAL_NUM_QUEUES); return -EINVAL; } @@ -1897,8 +1840,7 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev, if (ctx->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) /* header length is limited to 8 bits */ - io_sq->tx_max_header_size = - min_t(u32, ena_dev->tx_max_header_size, SZ_256); + io_sq->tx_max_header_size = min_t(u32, ena_dev->tx_max_header_size, SZ_256); ret = ena_com_init_io_sq(ena_dev, ctx, io_sq); if (ret) @@ -1930,8 +1872,7 @@ void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid) struct ena_com_io_cq *io_cq; if (qid >= ENA_TOTAL_NUM_QUEUES) { - netdev_err(ena_dev->net_device, - "Qid (%d) is bigger than max num of queues (%d)\n", + netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n", qid, ENA_TOTAL_NUM_QUEUES); return; } @@ -1975,8 +1916,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, if (rc) return rc; - if (get_resp.u.max_queue_ext.version != - ENA_FEATURE_MAX_QUEUE_EXT_VER) + if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER) return -EINVAL; memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext, @@ -2017,18 +1957,15 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS, 0); if (!rc) - memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, - sizeof(get_resp.u.hw_hints)); + memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, sizeof(get_resp.u.hw_hints)); else if (rc == -EOPNOTSUPP) - memset(&get_feat_ctx->hw_hints, 0x0, - sizeof(get_feat_ctx->hw_hints)); + memset(&get_feat_ctx->hw_hints, 0x0, sizeof(get_feat_ctx->hw_hints)); else return rc; rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0); if (!rc) - memcpy(&get_feat_ctx->llq, &get_resp.u.llq, - sizeof(get_resp.u.llq)); + memcpy(&get_feat_ctx->llq, &get_resp.u.llq, sizeof(get_resp.u.llq)); else if (rc == -EOPNOTSUPP) memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq)); else @@ -2076,8 +2013,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) aenq_common = &aenq_e->aenq_common_desc; /* Go over all the events */ - while ((READ_ONCE(aenq_common->flags) & - ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { + while ((READ_ONCE(aenq_common->flags) & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { /* Make sure the phase bit (ownership) is as expected before * reading the rest of the descriptor. */ @@ -2086,8 +2022,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) timestamp = (u64)aenq_common->timestamp_low | ((u64)aenq_common->timestamp_high << 32); - netdev_dbg(ena_dev->net_device, - "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n", + netdev_dbg(ena_dev->net_device, "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n", aenq_common->group, aenq_common->syndrome, timestamp); /* Handle specific event*/ @@ -2116,8 +2051,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) /* write the aenq doorbell after all AENQ descriptors were read */ mb(); - writel_relaxed((u32)aenq->head, - ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); + writel_relaxed((u32)aenq->head, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); } int ena_com_dev_reset(struct ena_com_dev *ena_dev, @@ -2129,15 +2063,13 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, stat = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); cap = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF); - if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || - (cap == ENA_MMIO_READ_TIMEOUT))) { + if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || (cap == ENA_MMIO_READ_TIMEOUT))) { netdev_err(ena_dev->net_device, "Reg read32 timeout occurred\n"); return -ETIME; } if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) { - netdev_err(ena_dev->net_device, - "Device isn't ready, can't reset device\n"); + netdev_err(ena_dev->net_device, "Device isn't ready, can't reset device\n"); return -EINVAL; } @@ -2160,8 +2092,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, rc = wait_for_reset_state(ena_dev, timeout, ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK); if (rc != 0) { - netdev_err(ena_dev->net_device, - "Reset indication didn't turn on\n"); + netdev_err(ena_dev->net_device, "Reset indication didn't turn on\n"); return rc; } @@ -2169,8 +2100,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, writel(0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); rc = wait_for_reset_state(ena_dev, timeout, 0); if (rc != 0) { - netdev_err(ena_dev->net_device, - "Reset indication didn't turn off\n"); + netdev_err(ena_dev->net_device, "Reset indication didn't turn off\n"); return rc; } @@ -2207,8 +2137,7 @@ static int ena_get_dev_stats(struct ena_com_dev *ena_dev, sizeof(*get_resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to get stats. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to get stats. error: %d\n", ret); return ret; } @@ -2220,8 +2149,7 @@ int ena_com_get_eni_stats(struct ena_com_dev *ena_dev, int ret; if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) { - netdev_err(ena_dev->net_device, - "Capability %d isn't supported\n", + netdev_err(ena_dev->net_device, "Capability %d isn't supported\n", ENA_ADMIN_ENI_STATS); return -EOPNOTSUPP; } @@ -2258,8 +2186,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) int ret; if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) { - netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", - ENA_ADMIN_MTU); + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_MTU); return -EOPNOTSUPP; } @@ -2278,8 +2205,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set mtu %d. error: %d\n", mtu, ret); + netdev_err(ena_dev->net_device, "Failed to set mtu %d. error: %d\n", mtu, ret); return ret; } @@ -2293,8 +2219,7 @@ int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, ret = ena_com_get_feature(ena_dev, &resp, ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to get offload capabilities %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to get offload capabilities %d\n", ret); return ret; } @@ -2312,8 +2237,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) struct ena_admin_get_feat_resp get_resp; int ret; - if (!ena_com_check_supported_feature_id(ena_dev, - ENA_ADMIN_RSS_HASH_FUNCTION)) { + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION)) { netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_RSS_HASH_FUNCTION); return -EOPNOTSUPP; @@ -2326,8 +2250,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) return ret; if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) { - netdev_err(ena_dev->net_device, - "Func hash %d isn't supported by device, abort\n", + netdev_err(ena_dev->net_device, "Func hash %d isn't supported by device, abort\n", rss->hash_func); return -EOPNOTSUPP; } @@ -2357,8 +2280,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) (struct ena_admin_acq_entry *)&resp, sizeof(resp)); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to set hash function %d. error: %d\n", + netdev_err(ena_dev->net_device, "Failed to set hash function %d. error: %d\n", rss->hash_func, ret); return -EINVAL; } @@ -2390,16 +2312,15 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, return rc; if (!(BIT(func) & get_resp.u.flow_hash_func.supported_func)) { - netdev_err(ena_dev->net_device, - "Flow hash function %d isn't supported\n", func); + netdev_err(ena_dev->net_device, "Flow hash function %d isn't supported\n", func); return -EOPNOTSUPP; } if ((func == ENA_ADMIN_TOEPLITZ) && key) { if (key_len != sizeof(hash_key->key)) { netdev_err(ena_dev->net_device, - "key len (%u) doesn't equal the supported size (%zu)\n", - key_len, sizeof(hash_key->key)); + "key len (%u) doesn't equal the supported size (%zu)\n", key_len, + sizeof(hash_key->key)); return -EINVAL; } memcpy(hash_key->key, key, key_len); @@ -2487,8 +2408,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) struct ena_admin_set_feat_resp resp; int ret; - if (!ena_com_check_supported_feature_id(ena_dev, - ENA_ADMIN_RSS_HASH_INPUT)) { + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_INPUT)) { netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_RSS_HASH_INPUT); return -EOPNOTSUPP; @@ -2519,8 +2439,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) (struct ena_admin_acq_entry *)&resp, sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set hash input. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set hash input. error: %d\n", ret); return ret; } @@ -2597,8 +2516,7 @@ int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev, int rc; if (proto >= ENA_ADMIN_RSS_PROTO_NUM) { - netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", - proto); + netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", proto); return -EINVAL; } @@ -2650,8 +2568,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) struct ena_admin_set_feat_resp resp; int ret; - if (!ena_com_check_supported_feature_id( - ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) { + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) { netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG); return -EOPNOTSUPP; @@ -2691,8 +2608,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set indirect table. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set indirect table. error: %d\n", ret); return ret; } @@ -2771,9 +2687,8 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev) { struct ena_host_attribute *host_attr = &ena_dev->host_attr; - host_attr->host_info = - dma_alloc_coherent(ena_dev->dmadev, SZ_4K, - &host_attr->host_info_dma_addr, GFP_KERNEL); + host_attr->host_info = dma_alloc_coherent(ena_dev->dmadev, SZ_4K, + &host_attr->host_info_dma_addr, GFP_KERNEL); if (unlikely(!host_attr->host_info)) return -ENOMEM; @@ -2819,8 +2734,7 @@ void ena_com_delete_debug_area(struct ena_com_dev *ena_dev) if (host_attr->debug_area_virt_addr) { dma_free_coherent(ena_dev->dmadev, host_attr->debug_area_size, - host_attr->debug_area_virt_addr, - host_attr->debug_area_dma_addr); + host_attr->debug_area_virt_addr, host_attr->debug_area_dma_addr); host_attr->debug_area_virt_addr = NULL; } } @@ -2869,8 +2783,7 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set host attributes: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set host attributes: %d\n", ret); return ret; } @@ -2888,8 +2801,7 @@ static int ena_com_update_nonadaptive_moderation_interval(struct ena_com_dev *en u32 *intr_moder_interval) { if (!intr_delay_resolution) { - netdev_err(ena_dev->net_device, - "Illegal interrupt delay granularity value\n"); + netdev_err(ena_dev->net_device, "Illegal interrupt delay granularity value\n"); return -EFAULT; } @@ -2927,14 +2839,12 @@ int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev) if (rc) { if (rc == -EOPNOTSUPP) { - netdev_dbg(ena_dev->net_device, - "Feature %d isn't supported\n", + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_INTERRUPT_MODERATION); rc = 0; } else { netdev_err(ena_dev->net_device, - "Failed to get interrupt moderation admin cmd. rc: %d\n", - rc); + "Failed to get interrupt moderation admin cmd. rc: %d\n", rc); } /* no moderation supported, disable adaptive support */ @@ -2982,8 +2892,7 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev, (llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc)); if (unlikely(ena_dev->tx_max_header_size == 0)) { - netdev_err(ena_dev->net_device, - "The size of the LLQ entry is smaller than needed\n"); + netdev_err(ena_dev->net_device, "The size of the LLQ entry is smaller than needed\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c index f9f886289b97..933e619b3a31 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c @@ -18,8 +18,7 @@ static struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc( cdesc = (struct ena_eth_io_rx_cdesc_base *)(io_cq->cdesc_addr.virt_addr + (head_masked * io_cq->cdesc_entry_size_in_bytes)); - desc_phase = (READ_ONCE(cdesc->status) & - ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> + desc_phase = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT; if (desc_phase != expected_phase) @@ -65,8 +64,8 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq, io_sq->entries_in_tx_burst_left--; netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Decreasing entries_in_tx_burst_left of queue %d to %d\n", - io_sq->qid, io_sq->entries_in_tx_burst_left); + "Decreasing entries_in_tx_burst_left of queue %d to %d\n", io_sq->qid, + io_sq->entries_in_tx_burst_left); } /* Make sure everything was written into the bounce buffer before @@ -75,8 +74,8 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq, wmb(); /* The line is completed. Copy it to dev */ - __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, - bounce_buffer, (llq_info->desc_list_entry_size) / 8); + __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, bounce_buffer, + (llq_info->desc_list_entry_size) / 8); io_sq->tail++; @@ -102,16 +101,14 @@ static int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq, header_offset = llq_info->descs_num_before_header * io_sq->desc_entry_size; - if (unlikely((header_offset + header_len) > - llq_info->desc_list_entry_size)) { + if (unlikely((header_offset + header_len) > llq_info->desc_list_entry_size)) { netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Trying to write header larger than llq entry can accommodate\n"); return -EFAULT; } if (unlikely(!bounce_buffer)) { - netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Bounce buffer is NULL\n"); + netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n"); return -EFAULT; } @@ -129,8 +126,7 @@ static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq) bounce_buffer = pkt_ctrl->curr_bounce_buf; if (unlikely(!bounce_buffer)) { - netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Bounce buffer is NULL\n"); + netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n"); return NULL; } @@ -247,8 +243,7 @@ static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq, ena_com_cq_inc_head(io_cq); count++; - last = (READ_ONCE(cdesc->status) & - ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> + last = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT; } while (!last); @@ -369,9 +364,8 @@ static void ena_com_rx_set_flags(struct ena_com_io_cq *io_cq, netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, "l3_proto %d l4_proto %d l3_csum_err %d l4_csum_err %d hash %d frag %d cdesc_status %x\n", - ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto, - ena_rx_ctx->l3_csum_err, ena_rx_ctx->l4_csum_err, - ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status); + ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto, ena_rx_ctx->l3_csum_err, + ena_rx_ctx->l4_csum_err, ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status); } /*****************************************************************************/ @@ -403,13 +397,12 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, if (unlikely(header_len > io_sq->tx_max_header_size)) { netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Header size is too large %d max header: %d\n", - header_len, io_sq->tx_max_header_size); + "Header size is too large %d max header: %d\n", header_len, + io_sq->tx_max_header_size); return -EINVAL; } - if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && - !buffer_to_push)) { + if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && !buffer_to_push)) { netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Push header wasn't provided in LLQ mode\n"); return -EINVAL; @@ -556,13 +549,11 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, } netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Fetch rx packet: queue %d completed desc: %d\n", io_cq->qid, - nb_hw_desc); + "Fetch rx packet: queue %d completed desc: %d\n", io_cq->qid, nb_hw_desc); if (unlikely(nb_hw_desc > ena_rx_ctx->max_bufs)) { netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc, - ena_rx_ctx->max_bufs); + "Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc, ena_rx_ctx->max_bufs); return -ENOSPC; } @@ -586,8 +577,8 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, io_sq->next_to_comp += nb_hw_desc; netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "[%s][QID#%d] Updating SQ head to: %d\n", __func__, - io_sq->qid, io_sq->next_to_comp); + "[%s][QID#%d] Updating SQ head to: %d\n", __func__, io_sq->qid, + io_sq->next_to_comp); /* Get rx flags from the last pkt */ ena_com_rx_set_flags(io_cq, ena_rx_ctx, cdesc); @@ -624,8 +615,8 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, desc->req_id = req_id; netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "[%s] Adding single RX desc, Queue: %u, req_id: %u\n", - __func__, io_sq->qid, req_id); + "[%s] Adding single RX desc, Queue: %u, req_id: %u\n", __func__, io_sq->qid, + req_id); desc->buff_addr_lo = (u32)ena_buf->paddr; desc->buff_addr_hi = diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h index 4d65d820a95e..72b019758caa 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h @@ -143,8 +143,8 @@ static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq, } netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Queue: %d num_descs: %d num_entries_needed: %d\n", - io_sq->qid, num_descs, num_entries_needed); + "Queue: %d num_descs: %d num_entries_needed: %d\n", io_sq->qid, num_descs, + num_entries_needed); return num_entries_needed > io_sq->entries_in_tx_burst_left; } @@ -155,15 +155,14 @@ static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq) u16 tail = io_sq->tail; netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Write submission queue doorbell for queue: %d tail: %d\n", - io_sq->qid, tail); + "Write submission queue doorbell for queue: %d tail: %d\n", io_sq->qid, tail); writel(tail, io_sq->db_addr); if (is_llq_max_tx_burst_exists(io_sq)) { netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Reset available entries in tx burst for queue %d to %d\n", - io_sq->qid, max_entries_in_tx_burst); + "Reset available entries in tx burst for queue %d to %d\n", io_sq->qid, + max_entries_in_tx_burst); io_sq->entries_in_tx_burst_left = max_entries_in_tx_burst; } @@ -224,8 +223,8 @@ static inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, *req_id = READ_ONCE(cdesc->req_id); if (unlikely(*req_id >= io_cq->q_depth)) { - netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Invalid req id %d\n", cdesc->req_id); + netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, "Invalid req id %d\n", + cdesc->req_id); return -EINVAL; } diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 965a01c5e245..03be2c008c4d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -141,11 +141,9 @@ int ena_xmit_common(struct ena_adapter *adapter, if (unlikely(rc)) { netif_err(adapter, tx_queued, adapter->netdev, "Failed to prepare tx bufs\n"); - ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, - &ring->syncp); + ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, &ring->syncp); if (rc != -ENOMEM) - ena_reset_device(adapter, - ENA_REGS_RESET_DRIVER_INVALID_STATE); + ena_reset_device(adapter, ENA_REGS_RESET_DRIVER_INVALID_STATE); return rc; } @@ -510,8 +508,7 @@ static struct page *ena_alloc_map_page(struct ena_ring *rx_ring, */ page = dev_alloc_page(); if (!page) { - ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, - &rx_ring->syncp); + ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, &rx_ring->syncp); return ERR_PTR(-ENOSPC); } @@ -570,8 +567,8 @@ static void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info, unsigned long attrs) { - dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, - DMA_BIDIRECTIONAL, attrs); + dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, DMA_BIDIRECTIONAL, + attrs); } static void ena_free_rx_page(struct ena_ring *rx_ring, @@ -844,8 +841,7 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) &req_id); if (rc) { if (unlikely(rc == -EINVAL)) - handle_invalid_req_id(tx_ring, req_id, NULL, - false); + handle_invalid_req_id(tx_ring, req_id, NULL, false); break; } @@ -1070,8 +1066,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, DMA_FROM_DEVICE); if (!reuse_rx_buf_page) - ena_unmap_rx_buff_attrs(rx_ring, rx_info, - DMA_ATTR_SKIP_CPU_SYNC); + ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page, page_offset + buf_offset, len, buf_len); @@ -1342,8 +1337,7 @@ error: adapter = netdev_priv(rx_ring->netdev); if (rc == -ENOSPC) { - ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, - &rx_ring->syncp); + ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, &rx_ring->syncp); ena_reset_device(adapter, ENA_REGS_RESET_TOO_MANY_RX_DESCS); } else { ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1, @@ -1833,8 +1827,7 @@ static int ena_rss_configure(struct ena_adapter *adapter) if (!ena_dev->rss.tbl_log_size) { rc = ena_rss_init_default(adapter); if (rc && (rc != -EOPNOTSUPP)) { - netif_err(adapter, ifup, adapter->netdev, - "Failed to init RSS rc: %d\n", rc); + netif_err(adapter, ifup, adapter->netdev, "Failed to init RSS rc: %d\n", rc); return rc; } } @@ -2790,8 +2783,7 @@ static void ena_config_debug_area(struct ena_adapter *adapter) rc = ena_com_set_host_attributes(adapter->ena_dev); if (rc) { if (rc == -EOPNOTSUPP) - netif_warn(adapter, drv, adapter->netdev, - "Cannot set host attributes\n"); + netif_warn(adapter, drv, adapter->netdev, "Cannot set host attributes\n"); else netif_err(adapter, drv, adapter->netdev, "Cannot set host attributes\n"); @@ -3831,8 +3823,8 @@ static int ena_rss_init_default(struct ena_adapter *adapter) } } - rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL, - ENA_HASH_KEY_SIZE, 0xFFFFFFFF); + rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL, ENA_HASH_KEY_SIZE, + 0xFFFFFFFF); if (unlikely(rc && (rc != -EOPNOTSUPP))) { dev_err(dev, "Cannot fill hash function\n"); goto err_fill_indir; From cf4f0f1e1c465da7c1f6bc89c3ff50bf42f0ab02 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 30 Jan 2024 13:08:29 +0100 Subject: [PATCH 0570/2255] dpll: extend uapi by lock status error attribute If the dpll devices goes to state "unlocked" or "holdover", it may be caused by an error. In that case, allow user to see what the error was. Introduce a new attribute and values it can carry. Signed-off-by: Jiri Pirko Acked-by: Vadim Fedorenko Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- Documentation/netlink/specs/dpll.yaml | 39 +++++++++++++++++++++++++++ include/uapi/linux/dpll.h | 30 +++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index b14aed18065f..1755066d8308 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -51,6 +51,40 @@ definitions: if dpll lock-state was not DPLL_LOCK_STATUS_LOCKED_HO_ACQ, the dpll's lock-state shall remain DPLL_LOCK_STATUS_UNLOCKED) render-max: true + - + type: enum + name: lock-status-error + doc: | + if previous status change was done due to a failure, this provides + information of dpll device lock status error. + Valid values for DPLL_A_LOCK_STATUS_ERROR attribute + entries: + - + name: none + doc: | + dpll device lock status was changed without any error + value: 1 + - + name: undefined + doc: | + dpll device lock status was changed due to undefined error. + Driver fills this value up in case it is not able + to obtain suitable exact error type. + - + name: media-down + doc: | + dpll device lock status was changed because of associated + media got down. + This may happen for example if dpll device was previously + locked on an input pin of type PIN_TYPE_SYNCE_ETH_PORT. + - + name: fractional-frequency-offset-too-high + doc: | + the FFO (Fractional Frequency Offset) between the RX and TX + symbol rate on the media got too high. + This may happen for example if dpll device was previously + locked on an input pin of type PIN_TYPE_SYNCE_ETH_PORT. + render-max: true - type: const name: temp-divider @@ -214,6 +248,10 @@ attribute-sets: name: type type: u32 enum: type + - + name: lock-status-error + type: u32 + enum: lock-status-error - name: pin enum-name: dpll_a_pin @@ -379,6 +417,7 @@ operations: - mode - mode-supported - lock-status + - lock-status-error - temp - clock-id - type diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index b4e947f9bfbc..0c13d7f1a1bc 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -50,6 +50,35 @@ enum dpll_lock_status { DPLL_LOCK_STATUS_MAX = (__DPLL_LOCK_STATUS_MAX - 1) }; +/** + * enum dpll_lock_status_error - if previous status change was done due to a + * failure, this provides information of dpll device lock status error. Valid + * values for DPLL_A_LOCK_STATUS_ERROR attribute + * @DPLL_LOCK_STATUS_ERROR_NONE: dpll device lock status was changed without + * any error + * @DPLL_LOCK_STATUS_ERROR_UNDEFINED: dpll device lock status was changed due + * to undefined error. Driver fills this value up in case it is not able to + * obtain suitable exact error type. + * @DPLL_LOCK_STATUS_ERROR_MEDIA_DOWN: dpll device lock status was changed + * because of associated media got down. This may happen for example if dpll + * device was previously locked on an input pin of type + * PIN_TYPE_SYNCE_ETH_PORT. + * @DPLL_LOCK_STATUS_ERROR_FRACTIONAL_FREQUENCY_OFFSET_TOO_HIGH: the FFO + * (Fractional Frequency Offset) between the RX and TX symbol rate on the + * media got too high. This may happen for example if dpll device was + * previously locked on an input pin of type PIN_TYPE_SYNCE_ETH_PORT. + */ +enum dpll_lock_status_error { + DPLL_LOCK_STATUS_ERROR_NONE = 1, + DPLL_LOCK_STATUS_ERROR_UNDEFINED, + DPLL_LOCK_STATUS_ERROR_MEDIA_DOWN, + DPLL_LOCK_STATUS_ERROR_FRACTIONAL_FREQUENCY_OFFSET_TOO_HIGH, + + /* private: */ + __DPLL_LOCK_STATUS_ERROR_MAX, + DPLL_LOCK_STATUS_ERROR_MAX = (__DPLL_LOCK_STATUS_ERROR_MAX - 1) +}; + #define DPLL_TEMP_DIVIDER 1000 /** @@ -150,6 +179,7 @@ enum dpll_a { DPLL_A_LOCK_STATUS, DPLL_A_TEMP, DPLL_A_TYPE, + DPLL_A_LOCK_STATUS_ERROR, __DPLL_A_MAX, DPLL_A_MAX = (__DPLL_A_MAX - 1) From e2ca9e75849e63eab6544549b6888595997e8153 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 30 Jan 2024 13:08:30 +0100 Subject: [PATCH 0571/2255] dpll: extend lock_status_get() op by status error and expose to user Pass additional argunent status_error over lock_status_get() so drivers can fill it up. In case they do, expose the value over previously introduced attribute to user. Do it only in case the current lock_status is either "unlocked" or "holdover". Signed-off-by: Jiri Pirko Acked-by: Vadim Fedorenko Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- drivers/dpll/dpll_netlink.c | 9 ++++++++- drivers/net/ethernet/intel/ice/ice_dpll.c | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/dpll.c | 9 +++++---- drivers/ptp/ptp_ocp.c | 9 +++++---- include/linux/dpll.h | 1 + 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 314bb3775465..cf3313517ae1 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -121,14 +121,21 @@ dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll, struct netlink_ext_ack *extack) { const struct dpll_device_ops *ops = dpll_device_ops(dpll); + enum dpll_lock_status_error status_error = 0; enum dpll_lock_status status; int ret; - ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, extack); + ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, + &status_error, extack); if (ret) return ret; if (nla_put_u32(msg, DPLL_A_LOCK_STATUS, status)) return -EMSGSIZE; + if (status_error && + (status == DPLL_LOCK_STATUS_UNLOCKED || + status == DPLL_LOCK_STATUS_HOLDOVER) && + nla_put_u32(msg, DPLL_A_LOCK_STATUS_ERROR, status_error)) + return -EMSGSIZE; return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index b9c5eced6326..c0256564e998 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -488,6 +488,7 @@ ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, * @dpll: registered dpll pointer * @dpll_priv: private data pointer passed on dpll registration * @status: on success holds dpll's lock status + * @status_error: status error value * @extack: error reporting * * Dpll subsystem callback, provides dpll's lock status. @@ -500,6 +501,7 @@ ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, static int ice_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, struct netlink_ext_ack *extack) { struct ice_dpll *d = dpll_priv; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 18fed2b34fb1..07f43d5c90c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -118,10 +118,11 @@ mlx5_dpll_pin_ffo_get(struct mlx5_dpll_synce_status *synce_status, return 0; } -static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, - void *priv, - enum dpll_lock_status *status, - struct netlink_ext_ack *extack) +static int +mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, void *priv, + enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, + struct netlink_ext_ack *extack) { struct mlx5_dpll_synce_status synce_status; struct mlx5_dpll *mdpll = priv; diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 5f858e426bbd..9507681e0d12 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -4209,10 +4209,11 @@ ptp_ocp_detach(struct ptp_ocp *bp) device_unregister(&bp->dev); } -static int ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll, - void *priv, - enum dpll_lock_status *status, - struct netlink_ext_ack *extack) +static int +ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll, void *priv, + enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, + struct netlink_ext_ack *extack) { struct ptp_ocp *bp = priv; diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 9cf896ea1d41..9cb02ad73d51 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -19,6 +19,7 @@ struct dpll_device_ops { enum dpll_mode *mode, struct netlink_ext_ack *extack); int (*lock_status_get)(const struct dpll_device *dpll, void *dpll_priv, enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, struct netlink_ext_ack *extack); int (*temp_get)(const struct dpll_device *dpll, void *dpll_priv, s32 *temp, struct netlink_ext_ack *extack); From 2c54a4d71246379f4ffb9beb6a780f9a49fdfc24 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 30 Jan 2024 13:08:31 +0100 Subject: [PATCH 0572/2255] net/mlx5: DPLL, Implement lock status error value Fill-up the lock status error value properly. Signed-off-by: Jiri Pirko Acked-by: Vadim Fedorenko Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlx5/core/dpll.c | 23 +++++++++++++++++++ include/linux/mlx5/mlx5_ifc.h | 8 +++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 07f43d5c90c6..4ad3d2d3d4c8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -41,6 +41,7 @@ struct mlx5_dpll_synce_status { enum mlx5_msees_oper_status oper_status; bool ho_acq; bool oper_freq_measure; + enum mlx5_msees_failure_reason failure_reason; s32 frequency_diff; }; @@ -60,6 +61,7 @@ mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev, synce_status->oper_status = MLX5_GET(msees_reg, out, oper_status); synce_status->ho_acq = MLX5_GET(msees_reg, out, ho_acq); synce_status->oper_freq_measure = MLX5_GET(msees_reg, out, oper_freq_measure); + synce_status->failure_reason = MLX5_GET(msees_reg, out, failure_reason); synce_status->frequency_diff = MLX5_GET(msees_reg, out, frequency_diff); return 0; } @@ -99,6 +101,26 @@ mlx5_dpll_lock_status_get(struct mlx5_dpll_synce_status *synce_status) } } +static enum dpll_lock_status_error +mlx5_dpll_lock_status_error_get(struct mlx5_dpll_synce_status *synce_status) +{ + switch (synce_status->oper_status) { + case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER: + fallthrough; + case MLX5_MSEES_OPER_STATUS_FAIL_FREE_RUNNING: + switch (synce_status->failure_reason) { + case MLX5_MSEES_FAILURE_REASON_PORT_DOWN: + return DPLL_LOCK_STATUS_ERROR_MEDIA_DOWN; + case MLX5_MSEES_FAILURE_REASON_TOO_HIGH_FREQUENCY_DIFF: + return DPLL_LOCK_STATUS_ERROR_FRACTIONAL_FREQUENCY_OFFSET_TOO_HIGH; + default: + return DPLL_LOCK_STATUS_ERROR_UNDEFINED; + } + default: + return DPLL_LOCK_STATUS_ERROR_NONE; + } +} + static enum dpll_pin_state mlx5_dpll_pin_state_get(struct mlx5_dpll_synce_status *synce_status) { @@ -132,6 +154,7 @@ mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, void *priv, if (err) return err; *status = mlx5_dpll_lock_status_get(&synce_status); + *status_error = mlx5_dpll_lock_status_error_get(&synce_status); return 0; } diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index c726f90ab752..6c44f107b8ba 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -12705,6 +12705,14 @@ enum mlx5_msees_oper_status { MLX5_MSEES_OPER_STATUS_FAIL_FREE_RUNNING = 0x5, }; +enum mlx5_msees_failure_reason { + MLX5_MSEES_FAILURE_REASON_UNDEFINED_ERROR = 0x0, + MLX5_MSEES_FAILURE_REASON_PORT_DOWN = 0x1, + MLX5_MSEES_FAILURE_REASON_TOO_HIGH_FREQUENCY_DIFF = 0x2, + MLX5_MSEES_FAILURE_REASON_NET_SYNCHRONIZER_DEVICE_ERROR = 0x3, + MLX5_MSEES_FAILURE_REASON_LACK_OF_RESOURCES = 0x4, +}; + struct mlx5_ifc_msees_reg_bits { u8 reserved_at_0[0x8]; u8 local_port[0x8]; From 1581e5118e485e82cfb5d04d636a79aaefb6f266 Mon Sep 17 00:00:00 2001 From: Matt Bobrowski Date: Thu, 1 Feb 2024 10:43:40 +0000 Subject: [PATCH 0573/2255] bpf: Minor clean-up to sleepable_lsm_hooks BTF set There's already one main CONFIG_SECURITY_NETWORK ifdef block within the sleepable_lsm_hooks BTF set. Consolidate this duplicated ifdef block as there's no need for it and all things guarded by it should remain in one place in this specific context. Signed-off-by: Matt Bobrowski Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/Zbt1smz43GDMbVU3@google.com --- kernel/bpf/bpf_lsm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 63b4dc495125..68240c3c6e7d 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -282,10 +282,6 @@ BTF_ID(func, bpf_lsm_file_lock) BTF_ID(func, bpf_lsm_file_open) BTF_ID(func, bpf_lsm_file_receive) -#ifdef CONFIG_SECURITY_NETWORK -BTF_ID(func, bpf_lsm_inet_conn_established) -#endif /* CONFIG_SECURITY_NETWORK */ - BTF_ID(func, bpf_lsm_inode_create) BTF_ID(func, bpf_lsm_inode_free_security) BTF_ID(func, bpf_lsm_inode_getattr) @@ -336,6 +332,8 @@ BTF_ID(func, bpf_lsm_sb_umount) BTF_ID(func, bpf_lsm_settime) #ifdef CONFIG_SECURITY_NETWORK +BTF_ID(func, bpf_lsm_inet_conn_established) + BTF_ID(func, bpf_lsm_socket_accept) BTF_ID(func, bpf_lsm_socket_bind) BTF_ID(func, bpf_lsm_socket_connect) From 9fa5e1a180aa639fb156a16e453ab820b7e7860b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 1 Feb 2024 09:20:23 -0800 Subject: [PATCH 0574/2255] libbpf: Call memfd_create() syscall directly Some versions of Android do not implement memfd_create() wrapper in their libc implementation, leading to build failures ([0]). On the other hand, memfd_create() is available as a syscall on quite old kernels (3.17+, while bpf() syscall itself is available since 3.18+), so it is ok to assume that syscall availability and call into it with syscall() helper to avoid Android-specific workarounds. Validated in libbpf-bootstrap's CI ([1]). [0] https://github.com/libbpf/libbpf-bootstrap/actions/runs/7701003207/job/20986080319#step:5:83 [1] https://github.com/libbpf/libbpf-bootstrap/actions/runs/7715988887/job/21031767212?pr=253 Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240201172027.604869-2-andrii@kernel.org --- tools/lib/bpf/libbpf.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index f6953d7faff1..6932f2c4ddfd 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1525,11 +1525,20 @@ static Elf64_Sym *find_elf_var_sym(const struct bpf_object *obj, const char *nam return ERR_PTR(-ENOENT); } +/* Some versions of Android don't provide memfd_create() in their libc + * implementation, so avoid complications and just go straight to Linux + * syscall. + */ +static int sys_memfd_create(const char *name, unsigned flags) +{ + return syscall(__NR_memfd_create, name, flags); +} + static int create_placeholder_fd(void) { int fd; - fd = ensure_good_fd(memfd_create("libbpf-placeholder-fd", MFD_CLOEXEC)); + fd = ensure_good_fd(sys_memfd_create("libbpf-placeholder-fd", MFD_CLOEXEC)); if (fd < 0) return -errno; return fd; From 93ee1eb85e28d1e35bb059c1f5965d65d5fc83c2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 1 Feb 2024 09:20:24 -0800 Subject: [PATCH 0575/2255] libbpf: Add missing LIBBPF_API annotation to libbpf_set_memlock_rlim API LIBBPF_API annotation seems missing on libbpf_set_memlock_rlim API, so add it to make this API callable from libbpf's shared library version. Fixes: e542f2c4cd16 ("libbpf: Auto-bump RLIMIT_MEMLOCK if kernel needs it for BPF") Fixes: ab9a5a05dc48 ("libbpf: fix up few libbpf.map problems") Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240201172027.604869-3-andrii@kernel.org --- tools/lib/bpf/bpf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 1441f642c563..f866e98b2436 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -35,7 +35,7 @@ extern "C" { #endif -int libbpf_set_memlock_rlim(size_t memlock_bytes); +LIBBPF_API int libbpf_set_memlock_rlim(size_t memlock_bytes); struct bpf_map_create_opts { size_t sz; /* size of this struct for forward/backward compatibility */ From c81a8ab196b5083d5109a51585fcc24fa2055a77 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 1 Feb 2024 09:20:25 -0800 Subject: [PATCH 0576/2255] libbpf: Add btf__new_split() API that was declared but not implemented Seems like original commit adding split BTF support intended to add btf__new_split() API, and even declared it in libbpf.map, but never added (trivial) implementation. Fix this. Fixes: ba451366bf44 ("libbpf: Implement basic split BTF support") Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240201172027.604869-4-andrii@kernel.org --- tools/lib/bpf/btf.c | 5 +++++ tools/lib/bpf/libbpf.map | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 95db88b36cf3..845034d15420 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1079,6 +1079,11 @@ struct btf *btf__new(const void *data, __u32 size) return libbpf_ptr(btf_new(data, size, NULL)); } +struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf) +{ + return libbpf_ptr(btf_new(data, size, base_btf)); +} + static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, struct btf_ext **btf_ext) { diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index d9e1f57534fa..386964f572a8 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -245,7 +245,6 @@ LIBBPF_0.3.0 { btf__parse_raw_split; btf__parse_split; btf__new_empty_split; - btf__new_split; ring_buffer__epoll_fd; } LIBBPF_0.2.0; @@ -411,5 +410,7 @@ LIBBPF_1.3.0 { } LIBBPF_1.2.0; LIBBPF_1.4.0 { + global: bpf_token_create; + btf__new_split; } LIBBPF_1.3.0; From b9551da8cf3ade01a50316df8a618fd945723ee0 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 1 Feb 2024 09:20:26 -0800 Subject: [PATCH 0577/2255] libbpf: Add missed btf_ext__raw_data() API Another API that was declared in libbpf.map but actual implementation was missing. btf_ext__get_raw_data() was intended as a discouraged alias to consistently-named btf_ext__raw_data(), so make this an actuality. Fixes: 20eccf29e297 ("libbpf: hide and discourage inconsistently named getters") Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240201172027.604869-5-andrii@kernel.org --- tools/lib/bpf/btf.c | 6 +++++- tools/lib/bpf/libbpf.map | 2 +- tools/lib/bpf/linker.c | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 845034d15420..a17b4c9c4213 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -3050,12 +3050,16 @@ done: return btf_ext; } -const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size) +const void *btf_ext__raw_data(const struct btf_ext *btf_ext, __u32 *size) { *size = btf_ext->data_size; return btf_ext->data; } +__attribute__((alias("btf_ext__raw_data"))) +const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size); + + struct btf_dedup; static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts); diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 386964f572a8..86804fd90dd1 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -325,7 +325,6 @@ LIBBPF_0.7.0 { bpf_xdp_detach; bpf_xdp_query; bpf_xdp_query_id; - btf_ext__raw_data; libbpf_probe_bpf_helper; libbpf_probe_bpf_map_type; libbpf_probe_bpf_prog_type; @@ -413,4 +412,5 @@ LIBBPF_1.4.0 { global: bpf_token_create; btf__new_split; + btf_ext__raw_data; } LIBBPF_1.3.0; diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c index 16bca56002ab..0d4be829551b 100644 --- a/tools/lib/bpf/linker.c +++ b/tools/lib/bpf/linker.c @@ -2732,7 +2732,7 @@ static int finalize_btf(struct bpf_linker *linker) /* Emit .BTF.ext section */ if (linker->btf_ext) { - raw_data = btf_ext__get_raw_data(linker->btf_ext, &raw_sz); + raw_data = btf_ext__raw_data(linker->btf_ext, &raw_sz); if (!raw_data) return -ENOMEM; From 943b043aeecce9accb6d367af47791c633e95e4d Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 1 Feb 2024 09:20:27 -0800 Subject: [PATCH 0578/2255] selftests/bpf: Fix bench runner SIGSEGV Some benchmarks don't have either "consumer" or "producer" sides. For example, trig-tp and other BPF triggering benchmarks don't have consumers, as they only do "producing" by calling into syscall or predefined uproes. As such it's valid for some benchmarks to have zero consumers or producers. So allows to specify `-c0` explicitly. This triggers another problem. If benchmark doesn't support either consumer or producer side, consumer_thread/producer_thread callback will be NULL, but benchmark runner will attempt to use those NULL callback to create threads anyways. So instead of crashing with SIGSEGV in case of misconfigured benchmark, detect the condition and report error. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240201172027.604869-6-andrii@kernel.org --- tools/testing/selftests/bpf/bench.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index 73ce11b0547d..1724d50ba942 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -323,14 +323,14 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) break; case 'p': env.producer_cnt = strtol(arg, NULL, 10); - if (env.producer_cnt <= 0) { + if (env.producer_cnt < 0) { fprintf(stderr, "Invalid producer count: %s\n", arg); argp_usage(state); } break; case 'c': env.consumer_cnt = strtol(arg, NULL, 10); - if (env.consumer_cnt <= 0) { + if (env.consumer_cnt < 0) { fprintf(stderr, "Invalid consumer count: %s\n", arg); argp_usage(state); } @@ -607,6 +607,10 @@ static void setup_benchmark(void) bench->setup(); for (i = 0; i < env.consumer_cnt; i++) { + if (!bench->consumer_thread) { + fprintf(stderr, "benchmark doesn't support consumers!\n"); + exit(1); + } err = pthread_create(&state.consumers[i], NULL, bench->consumer_thread, (void *)(long)i); if (err) { @@ -626,6 +630,10 @@ static void setup_benchmark(void) env.prod_cpus.next_cpu = env.cons_cpus.next_cpu; for (i = 0; i < env.producer_cnt; i++) { + if (!bench->producer_thread) { + fprintf(stderr, "benchmark doesn't support producers!\n"); + exit(1); + } err = pthread_create(&state.producers[i], NULL, bench->producer_thread, (void *)(long)i); if (err) { From 102c28b83ddf021c9902dc59e6436278a0975916 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Jan 2024 13:22:58 -0600 Subject: [PATCH 0579/2255] net: ipa: stash modem TX and RX endpoints Rather than repeatedly looking up the endpoints in the name map, save the modem TX and RX endpoint pointers in the netdev private area. Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20240130192305.250915-2-elder@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_modem.c | 49 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c index 423422a2a445..a6f6cd149c1b 100644 --- a/drivers/net/ipa/ipa_modem.c +++ b/drivers/net/ipa/ipa_modem.c @@ -39,10 +39,14 @@ enum ipa_modem_state { /** * struct ipa_priv - IPA network device private data * @ipa: IPA pointer + * @tx: Transmit endpoint pointer + * @rx: Receive endpoint pointer * @work: Work structure used to wake the modem netdev TX queue */ struct ipa_priv { struct ipa *ipa; + struct ipa_endpoint *tx; + struct ipa_endpoint *rx; struct work_struct work; }; @@ -59,11 +63,11 @@ static int ipa_open(struct net_device *netdev) if (ret < 0) goto err_power_put; - ret = ipa_endpoint_enable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]); + ret = ipa_endpoint_enable_one(priv->tx); if (ret) goto err_power_put; - ret = ipa_endpoint_enable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]); + ret = ipa_endpoint_enable_one(priv->rx); if (ret) goto err_disable_tx; @@ -75,7 +79,7 @@ static int ipa_open(struct net_device *netdev) return 0; err_disable_tx: - ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]); + ipa_endpoint_disable_one(priv->tx); err_power_put: pm_runtime_put_noidle(dev); @@ -97,8 +101,8 @@ static int ipa_stop(struct net_device *netdev) netif_stop_queue(netdev); - ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]); - ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]); + ipa_endpoint_disable_one(priv->rx); + ipa_endpoint_disable_one(priv->tx); out_power_put: pm_runtime_mark_last_busy(dev); (void)pm_runtime_put_autosuspend(dev); @@ -233,14 +237,14 @@ static void ipa_modem_netdev_setup(struct net_device *netdev) */ void ipa_modem_suspend(struct net_device *netdev) { - struct ipa_priv *priv = netdev_priv(netdev); - struct ipa *ipa = priv->ipa; + struct ipa_priv *priv; if (!(netdev->flags & IFF_UP)) return; - ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]); - ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]); + priv = netdev_priv(netdev); + ipa_endpoint_suspend_one(priv->rx); + ipa_endpoint_suspend_one(priv->tx); } /** @@ -268,14 +272,14 @@ static void ipa_modem_wake_queue_work(struct work_struct *work) */ void ipa_modem_resume(struct net_device *netdev) { - struct ipa_priv *priv = netdev_priv(netdev); - struct ipa *ipa = priv->ipa; + struct ipa_priv *priv; if (!(netdev->flags & IFF_UP)) return; - ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]); - ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]); + priv = netdev_priv(netdev); + ipa_endpoint_resume_one(priv->tx); + ipa_endpoint_resume_one(priv->rx); /* Arrange for the TX queue to be restarted */ (void)queue_pm_work(&priv->work); @@ -306,16 +310,21 @@ int ipa_modem_start(struct ipa *ipa) SET_NETDEV_DEV(netdev, &ipa->pdev->dev); priv = netdev_priv(netdev); priv->ipa = ipa; + priv->tx = ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]; + priv->rx = ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]; INIT_WORK(&priv->work, ipa_modem_wake_queue_work); - ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]->netdev = netdev; - ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]->netdev = netdev; + + priv->tx->netdev = netdev; + priv->rx->netdev = netdev; + ipa->modem_netdev = netdev; ret = register_netdev(netdev); if (ret) { ipa->modem_netdev = NULL; - ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]->netdev = NULL; - ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]->netdev = NULL; + priv->rx->netdev = NULL; + priv->tx->netdev = NULL; + free_netdev(netdev); } @@ -355,9 +364,11 @@ int ipa_modem_stop(struct ipa *ipa) if (netdev->flags & IFF_UP) (void)ipa_stop(netdev); unregister_netdev(netdev); + ipa->modem_netdev = NULL; - ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]->netdev = NULL; - ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]->netdev = NULL; + priv->rx->netdev = NULL; + priv->tx->netdev = NULL; + free_netdev(netdev); } From 844ecc4aa78e2f291071025cf76a98287b38856a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Jan 2024 13:22:59 -0600 Subject: [PATCH 0580/2255] net: ipa: begin simplifying TX queue stop There are a number of flags used in the IPA driver to attempt to manage race conditions that can occur between runtime resume and netdev transmit. If we disable TX before requesting power, we can avoid these races entirely, simplifying things considerably. This patch implements the main change, disabling transmit always in the net_device->ndo_start_xmit() callback, then re-enabling it again whenever we find power is active (or when we drop the skb). The patches that follow will refactor the "old" code to the point that most of it can be eliminated. Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20240130192305.250915-3-elder@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_modem.c | 41 +++++++++++++++++++++++----------- drivers/net/ipa/ipa_power.c | 44 ++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 31 deletions(-) diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c index a6f6cd149c1b..c7a0b167c432 100644 --- a/drivers/net/ipa/ipa_modem.c +++ b/drivers/net/ipa/ipa_modem.c @@ -110,13 +110,16 @@ out_power_put: return 0; } -/** ipa_start_xmit() - Transmits an skb. - * @skb: skb to be transmitted - * @dev: network device +/** ipa_start_xmit() - Transmit an skb + * @skb: Socket buffer to be transmitted + * @netdev: Network device * - * Return codes: - * NETDEV_TX_OK: Success - * NETDEV_TX_BUSY: Error while transmitting the skb. Try again later + * Return: NETDEV_TX_OK if successful (or dropped), NETDEV_TX_BUSY otherwise + + * Normally NETDEV_TX_OK indicates the buffer was successfully transmitted. + * If the buffer has an unexpected protocol or its size is out of range it + * is quietly dropped, returning NETDEV_TX_OK. NETDEV_TX_BUSY indicates + * the buffer cannot be sent at this time and should retried later. */ static netdev_tx_t ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev) @@ -136,7 +139,25 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (endpoint->config.qmap && skb->protocol != htons(ETH_P_MAP)) goto err_drop_skb; - /* The hardware must be powered for us to transmit */ + /* The hardware must be powered for us to transmit, so if we're not + * ready we want the network stack to stop queueing until power is + * ACTIVE. Once runtime resume has completed, we inform the network + * stack it's OK to try transmitting again. + * + * We learn from pm_runtime_get() whether the hardware is powered. + * If it was not, powering up is either started or already underway. + * And in that case we want to disable queueing, expecting it to be + * re-enabled once power is ACTIVE. But runtime PM and network + * transmit run concurrently, and if we're not careful the requests + * to stop and start queueing could occur in the wrong order. + * + * For that reason we *always* stop queueing here, *before* the call + * to pm_runtime_get(). If we determine here that power is ACTIVE, + * we restart queueing before transmitting the SKB. Otherwise + * queueing will eventually be enabled after resume completes. + */ + ipa_power_modem_queue_stop(ipa); + dev = &ipa->pdev->dev; ret = pm_runtime_get(dev); if (ret < 1) { @@ -147,12 +168,6 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev) goto err_drop_skb; } - /* No power (yet). Stop the network stack from transmitting - * until we're resumed; ipa_modem_resume() arranges for the - * TX queue to be started again. - */ - ipa_power_modem_queue_stop(ipa); - pm_runtime_put_noidle(dev); return NETDEV_TX_BUSY; diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index e223886123ce..f1802448ff44 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -233,28 +233,32 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) ipa_interrupt_suspend_clear_all(ipa->interrupt); } -/* The next few functions coordinate stopping and starting the modem +/* The next few functions are used when stopping and starting the modem * network device transmit queue. * - * Transmit can be running concurrent with power resume, and there's a - * chance the resume completes before the transmit path stops the queue, - * leaving the queue in a stopped state. The next two functions are used - * to avoid this: ipa_power_modem_queue_stop() is used by ipa_start_xmit() - * to conditionally stop the TX queue; and ipa_power_modem_queue_start() - * is used by ipa_runtime_resume() to conditionally restart it. + * Transmit can run concurrent with power resume. When transmitting, + * we disable further transmits until we can determine whether power + * is ACTIVE. If it is, future transmits are re-enabled and the buffer + * gets sent (or dropped). If power is not ACTIVE, it will eventually + * be, and transmits stay disabled until after it is. * - * Two flags and a spinlock are used. If the queue is stopped, the STOPPED - * power flag is set. And if the queue is started, the STARTED flag is set. - * The queue is only started on resume if the STOPPED flag is set. And the - * queue is only started in ipa_start_xmit() if the STARTED flag is *not* - * set. As a result, the queue remains operational if the two activites - * happen concurrently regardless of the order they complete. The spinlock - * ensures the flag and TX queue operations are done atomically. + * Two flags and a spinlock are used when managing this. If the queue + * is stopped, the STOPPED power flag is set. And if the queue is + * started, the STARTED flag is set. * * The first function stops the modem netdev transmit queue, but only if - * the STARTED flag is *not* set. That flag is cleared if it was set. - * If the queue is stopped, the STOPPED flag is set. This is called only - * from the power ->runtime_resume operation. + * the STARTED flag is *not* set. This previously avoided a race where + * the TX path stops further transmits after power has become ACTIVE. + * The STARTED flag is cleared by this function. + * + * The second function starts the transmit queue, but only if the + * STOPPED flag is set. This avoids enabling transmits repeatedly + * immediately after power has become ACTIVE (not really a big deal). + * If the STOPPED flag was set, it is cleared and the STARTED flag + * is set by this function. + * + * The third function enables transmits again and clears the STARTED + * flag in case it was set, to return it to initial state. */ void ipa_power_modem_queue_stop(struct ipa *ipa) { @@ -291,9 +295,13 @@ void ipa_power_modem_queue_wake(struct ipa *ipa) spin_unlock_irqrestore(&power->spinlock, flags); } -/* This function clears the STARTED flag once the TX queue is operating */ +/* This function is run after power has become ACTIVE. It enables transmits + * again clears the STARTED flag to indicate the TX queue is operating and + * can be stopped again if necessary. + */ void ipa_power_modem_queue_active(struct ipa *ipa) { + netif_wake_queue(ipa->modem_netdev); clear_bit(IPA_POWER_FLAG_STARTED, ipa->power->flags); } From 688de12f080f10dff8f3ddc80103e432ad8deb0b Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Jan 2024 13:23:00 -0600 Subject: [PATCH 0581/2255] net: ipa: kill the STARTED IPA power flag A transmit on the modem netdev can only complete if the IPA hardware is powered. Currently, if a transmit request arrives when the hardware was not powered, further transmits are be stopped to allow power-up to complete. Once power-up completes, transmits are once again enabled. Runtime resume can complete at the same time a transmit request is being handled, and previously there was a race between stopping and restarting transmits. The STARTED flag was used to ensure the stop request in the transmit path was skipped if the start request in the runtime resume path had already occurred. Now, the queue is *always* stopped in the transmit path, *before* determining whether power is ACTIVE. If power is found to already be active (or if the socket buffer is gets dropped), transmit is re-enabled. Otherwise it will (always) be enabled after runtime resume completes. The race between transmit and runtime resume no longer exists, so there is no longer any need to maintain the STARTED flag. Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20240130192305.250915-4-elder@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_power.c | 47 +++++++++++-------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index f1802448ff44..509c9bfa648e 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -39,14 +39,12 @@ * @IPA_POWER_FLAG_RESUMED: Whether resume from suspend has been signaled * @IPA_POWER_FLAG_SYSTEM: Hardware is system (not runtime) suspended * @IPA_POWER_FLAG_STOPPED: Modem TX is disabled by ipa_start_xmit() - * @IPA_POWER_FLAG_STARTED: Modem TX was enabled by ipa_runtime_resume() * @IPA_POWER_FLAG_COUNT: Number of defined power flags */ enum ipa_power_flag { IPA_POWER_FLAG_RESUMED, IPA_POWER_FLAG_SYSTEM, IPA_POWER_FLAG_STOPPED, - IPA_POWER_FLAG_STARTED, IPA_POWER_FLAG_COUNT, /* Last; not a flag */ }; @@ -64,7 +62,7 @@ struct ipa_power { struct device *dev; struct clk *core; struct qmp *qmp; - spinlock_t spinlock; /* used with STOPPED/STARTED power flags */ + spinlock_t spinlock; /* used with STOPPED power flag */ DECLARE_BITMAP(flags, IPA_POWER_FLAG_COUNT); u32 interconnect_count; struct icc_bulk_data interconnect[] __counted_by(interconnect_count); @@ -242,23 +240,16 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) * gets sent (or dropped). If power is not ACTIVE, it will eventually * be, and transmits stay disabled until after it is. * - * Two flags and a spinlock are used when managing this. If the queue - * is stopped, the STOPPED power flag is set. And if the queue is - * started, the STARTED flag is set. + * A flag and a spinlock are used when managing this. If the queue gets + * stopped, the STOPPED power flag is set. * - * The first function stops the modem netdev transmit queue, but only if - * the STARTED flag is *not* set. This previously avoided a race where - * the TX path stops further transmits after power has become ACTIVE. - * The STARTED flag is cleared by this function. + * The first function stops the modem netdev transmit queue. The second + * function starts the transmit queue, but only if the STOPPED flag is + * set. This avoids enabling transmits repeatedly immediately after + * power has become ACTIVE (not really a big deal). If the STOPPED flag + * was set, it is cleared by this function. * - * The second function starts the transmit queue, but only if the - * STOPPED flag is set. This avoids enabling transmits repeatedly - * immediately after power has become ACTIVE (not really a big deal). - * If the STOPPED flag was set, it is cleared and the STARTED flag - * is set by this function. - * - * The third function enables transmits again and clears the STARTED - * flag in case it was set, to return it to initial state. + * The third function just enables transmits again. */ void ipa_power_modem_queue_stop(struct ipa *ipa) { @@ -267,18 +258,14 @@ void ipa_power_modem_queue_stop(struct ipa *ipa) spin_lock_irqsave(&power->spinlock, flags); - if (!__test_and_clear_bit(IPA_POWER_FLAG_STARTED, power->flags)) { - netif_stop_queue(ipa->modem_netdev); - __set_bit(IPA_POWER_FLAG_STOPPED, power->flags); - } + netif_stop_queue(ipa->modem_netdev); + __set_bit(IPA_POWER_FLAG_STOPPED, power->flags); spin_unlock_irqrestore(&power->spinlock, flags); } /* This function starts the modem netdev transmit queue, but only if the - * STOPPED flag is set. That flag is cleared if it was set. If the queue - * was restarted, the STARTED flag is set; this allows ipa_start_xmit() - * to skip stopping the queue in the event of a race. + * STOPPED flag is set. That flag is cleared if it was set. */ void ipa_power_modem_queue_wake(struct ipa *ipa) { @@ -287,22 +274,16 @@ void ipa_power_modem_queue_wake(struct ipa *ipa) spin_lock_irqsave(&power->spinlock, flags); - if (__test_and_clear_bit(IPA_POWER_FLAG_STOPPED, power->flags)) { - __set_bit(IPA_POWER_FLAG_STARTED, power->flags); + if (__test_and_clear_bit(IPA_POWER_FLAG_STOPPED, power->flags)) netif_wake_queue(ipa->modem_netdev); - } spin_unlock_irqrestore(&power->spinlock, flags); } -/* This function is run after power has become ACTIVE. It enables transmits - * again clears the STARTED flag to indicate the TX queue is operating and - * can be stopped again if necessary. - */ +/* This function enables transmits again after power has become ACTIVE. */ void ipa_power_modem_queue_active(struct ipa *ipa) { netif_wake_queue(ipa->modem_netdev); - clear_bit(IPA_POWER_FLAG_STARTED, ipa->power->flags); } static int ipa_power_retention_init(struct ipa_power *power) From 86c9a4929258299498480a542871a4604cc3766c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Jan 2024 13:23:01 -0600 Subject: [PATCH 0582/2255] net: ipa: kill the IPA power STOPPED flag Currently the STOPPED IPA power flag is used to indicate that the transmit queue has been stopped. Previously this was used to avoid setting the STARTED flag unless the queue had already been stopped. It meant transmit queuing would be enabled on resume if it was stopped by the transmit path--and if so, it ensured it only got enabled once. We only stop the transmit queue in the transmit path. The STARTED flag has been removed, and it causes no real harm to enable transmits when they're already enabled. So we can get rid of the STOPPED flag and call netif_wake_queue() unconditionally. This makes the IPA power spinlock unnecessary, so it can be removed as well. Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20240130192305.250915-5-elder@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_power.c | 40 +++++-------------------------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index 509c9bfa648e..e615473d2380 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -38,13 +38,11 @@ * enum ipa_power_flag - IPA power flags * @IPA_POWER_FLAG_RESUMED: Whether resume from suspend has been signaled * @IPA_POWER_FLAG_SYSTEM: Hardware is system (not runtime) suspended - * @IPA_POWER_FLAG_STOPPED: Modem TX is disabled by ipa_start_xmit() * @IPA_POWER_FLAG_COUNT: Number of defined power flags */ enum ipa_power_flag { IPA_POWER_FLAG_RESUMED, IPA_POWER_FLAG_SYSTEM, - IPA_POWER_FLAG_STOPPED, IPA_POWER_FLAG_COUNT, /* Last; not a flag */ }; @@ -53,7 +51,6 @@ enum ipa_power_flag { * @dev: IPA device pointer * @core: IPA core clock * @qmp: QMP handle for AOSS communication - * @spinlock: Protects modem TX queue enable/disable * @flags: Boolean state flags * @interconnect_count: Number of elements in interconnect[] * @interconnect: Interconnect array @@ -62,7 +59,6 @@ struct ipa_power { struct device *dev; struct clk *core; struct qmp *qmp; - spinlock_t spinlock; /* used with STOPPED power flag */ DECLARE_BITMAP(flags, IPA_POWER_FLAG_COUNT); u32 interconnect_count; struct icc_bulk_data interconnect[] __counted_by(interconnect_count); @@ -240,47 +236,22 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) * gets sent (or dropped). If power is not ACTIVE, it will eventually * be, and transmits stay disabled until after it is. * - * A flag and a spinlock are used when managing this. If the queue gets - * stopped, the STOPPED power flag is set. - * * The first function stops the modem netdev transmit queue. The second - * function starts the transmit queue, but only if the STOPPED flag is - * set. This avoids enabling transmits repeatedly immediately after - * power has become ACTIVE (not really a big deal). If the STOPPED flag - * was set, it is cleared by this function. - * - * The third function just enables transmits again. + * function starts the transmit queue and is used in the power resume + * path after power has become ACTIVE. The third function also enables + * transmits again, and is used by ipa_start_xmit() once it knows power + * is active. */ void ipa_power_modem_queue_stop(struct ipa *ipa) { - struct ipa_power *power = ipa->power; - unsigned long flags; - - spin_lock_irqsave(&power->spinlock, flags); - netif_stop_queue(ipa->modem_netdev); - __set_bit(IPA_POWER_FLAG_STOPPED, power->flags); - - spin_unlock_irqrestore(&power->spinlock, flags); } -/* This function starts the modem netdev transmit queue, but only if the - * STOPPED flag is set. That flag is cleared if it was set. - */ void ipa_power_modem_queue_wake(struct ipa *ipa) { - struct ipa_power *power = ipa->power; - unsigned long flags; - - spin_lock_irqsave(&power->spinlock, flags); - - if (__test_and_clear_bit(IPA_POWER_FLAG_STOPPED, power->flags)) - netif_wake_queue(ipa->modem_netdev); - - spin_unlock_irqrestore(&power->spinlock, flags); + netif_wake_queue(ipa->modem_netdev); } -/* This function enables transmits again after power has become ACTIVE. */ void ipa_power_modem_queue_active(struct ipa *ipa) { netif_wake_queue(ipa->modem_netdev); @@ -374,7 +345,6 @@ ipa_power_init(struct device *dev, const struct ipa_power_data *data) } power->dev = dev; power->core = clk; - spin_lock_init(&power->spinlock); power->interconnect_count = data->interconnect_count; ret = ipa_interconnect_init(power, data->interconnect_data); From 30cdaea236009c6f626f0660ac4ca08558a2166f Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Jan 2024 13:23:02 -0600 Subject: [PATCH 0583/2255] net: ipa: kill ipa_power_modem_queue_stop() All ipa_power_modem_queue_stop() does now is call netif_stop_queue(). Just call netif_stop_queue() in the one place it's needed, and get rid of ipa_power_modem_queue_stop(). Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20240130192305.250915-6-elder@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_modem.c | 2 +- drivers/net/ipa/ipa_power.c | 16 +++++----------- drivers/net/ipa/ipa_power.h | 6 ------ 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c index c7a0b167c432..08e1202f1286 100644 --- a/drivers/net/ipa/ipa_modem.c +++ b/drivers/net/ipa/ipa_modem.c @@ -156,7 +156,7 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev) * we restart queueing before transmitting the SKB. Otherwise * queueing will eventually be enabled after resume completes. */ - ipa_power_modem_queue_stop(ipa); + netif_stop_queue(netdev); dev = &ipa->pdev->dev; ret = pm_runtime_get(dev); diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index e615473d2380..812359c7977d 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -227,7 +227,7 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) ipa_interrupt_suspend_clear_all(ipa->interrupt); } -/* The next few functions are used when stopping and starting the modem +/* The next two functions are used when stopping and starting the modem * network device transmit queue. * * Transmit can run concurrent with power resume. When transmitting, @@ -236,17 +236,11 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) * gets sent (or dropped). If power is not ACTIVE, it will eventually * be, and transmits stay disabled until after it is. * - * The first function stops the modem netdev transmit queue. The second - * function starts the transmit queue and is used in the power resume - * path after power has become ACTIVE. The third function also enables - * transmits again, and is used by ipa_start_xmit() once it knows power - * is active. + * The first function starts the transmit queue and is used in the power + * resume path after power has become ACTIVE. The second function also + * enables transmits again, and is used by ipa_start_xmit() once it + * knows power is active. */ -void ipa_power_modem_queue_stop(struct ipa *ipa) -{ - netif_stop_queue(ipa->modem_netdev); -} - void ipa_power_modem_queue_wake(struct ipa *ipa) { netif_wake_queue(ipa->modem_netdev); diff --git a/drivers/net/ipa/ipa_power.h b/drivers/net/ipa/ipa_power.h index 3a4c59ea1222..f51653399a07 100644 --- a/drivers/net/ipa/ipa_power.h +++ b/drivers/net/ipa/ipa_power.h @@ -23,12 +23,6 @@ extern const struct dev_pm_ops ipa_pm_ops; */ u32 ipa_core_clock_rate(struct ipa *ipa); -/** - * ipa_power_modem_queue_stop() - Possibly stop the modem netdev TX queue - * @ipa: IPA pointer - */ -void ipa_power_modem_queue_stop(struct ipa *ipa); - /** * ipa_power_modem_queue_wake() - Possibly wake the modem netdev TX queue * @ipa: IPA pointer From 2acf5fc8dabaf9a5b14a678cd039f974dc749768 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Jan 2024 13:23:03 -0600 Subject: [PATCH 0584/2255] net: ipa: kill ipa_power_modem_queue_active() All ipa_power_modem_queue_active() does now is call netif_wake_queue(). Just call netif_wake_queue() in the two places it's needed, and get rid of ipa_power_modem_queue_active(). Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20240130192305.250915-7-elder@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_modem.c | 4 ++-- drivers/net/ipa/ipa_power.c | 19 ++++--------------- drivers/net/ipa/ipa_power.h | 6 ------ 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c index 08e1202f1286..0c298060468e 100644 --- a/drivers/net/ipa/ipa_modem.c +++ b/drivers/net/ipa/ipa_modem.c @@ -163,7 +163,7 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (ret < 1) { /* If a resume won't happen, just drop the packet */ if (ret < 0 && ret != -EINPROGRESS) { - ipa_power_modem_queue_active(ipa); + netif_wake_queue(netdev); pm_runtime_put_noidle(dev); goto err_drop_skb; } @@ -173,7 +173,7 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - ipa_power_modem_queue_active(ipa); + netif_wake_queue(netdev); ret = ipa_endpoint_skb_tx(endpoint, skb); diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index 812359c7977d..fd2abce043fa 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -227,30 +227,19 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) ipa_interrupt_suspend_clear_all(ipa->interrupt); } -/* The next two functions are used when stopping and starting the modem - * network device transmit queue. - * - * Transmit can run concurrent with power resume. When transmitting, +/* Transmit can run concurrent with power resume. When transmitting, * we disable further transmits until we can determine whether power * is ACTIVE. If it is, future transmits are re-enabled and the buffer * gets sent (or dropped). If power is not ACTIVE, it will eventually - * be, and transmits stay disabled until after it is. - * - * The first function starts the transmit queue and is used in the power - * resume path after power has become ACTIVE. The second function also - * enables transmits again, and is used by ipa_start_xmit() once it - * knows power is active. + * be, and transmits stay disabled until after it is. This function + * starts the transmit queue and is used in the power resume path after + * power has become ACTIVE. */ void ipa_power_modem_queue_wake(struct ipa *ipa) { netif_wake_queue(ipa->modem_netdev); } -void ipa_power_modem_queue_active(struct ipa *ipa) -{ - netif_wake_queue(ipa->modem_netdev); -} - static int ipa_power_retention_init(struct ipa_power *power) { struct qmp *qmp = qmp_get(power->dev); diff --git a/drivers/net/ipa/ipa_power.h b/drivers/net/ipa/ipa_power.h index f51653399a07..dcd36a6a718f 100644 --- a/drivers/net/ipa/ipa_power.h +++ b/drivers/net/ipa/ipa_power.h @@ -29,12 +29,6 @@ u32 ipa_core_clock_rate(struct ipa *ipa); */ void ipa_power_modem_queue_wake(struct ipa *ipa); -/** - * ipa_power_modem_queue_active() - Report modem netdev TX queue active - * @ipa: IPA pointer - */ -void ipa_power_modem_queue_active(struct ipa *ipa); - /** * ipa_power_retention() - Control register retention on power collapse * @ipa: IPA pointer From e01bbdc9f8513395a8554aeeeef8f45dd26dfe15 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Jan 2024 13:23:04 -0600 Subject: [PATCH 0585/2255] net: ipa: kill ipa_power_modem_queue_wake() All ipa_power_modem_queue_wake() does is call netif_wake_queue() on the modem netdev. There is no need to wrap that call in a trivial function (and certainly not one defined in "ipa_power.c"). So get rid of ipa_power_modem_queue_wake(), and replace its one caller with a direct call to netif_wake_queue(). Determine the netdev pointer to use from the private TX endpoint's netdev pointer. Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20240130192305.250915-8-elder@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_modem.c | 2 +- drivers/net/ipa/ipa_power.c | 13 ------------- drivers/net/ipa/ipa_power.h | 6 ------ 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c index 0c298060468e..1d1be92fbebc 100644 --- a/drivers/net/ipa/ipa_modem.c +++ b/drivers/net/ipa/ipa_modem.c @@ -277,7 +277,7 @@ static void ipa_modem_wake_queue_work(struct work_struct *work) { struct ipa_priv *priv = container_of(work, struct ipa_priv, work); - ipa_power_modem_queue_wake(priv->ipa); + netif_wake_queue(priv->tx->netdev); } /** ipa_modem_resume() - resume callback for runtime_pm diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index fd2abce043fa..128a816f6523 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -227,19 +227,6 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) ipa_interrupt_suspend_clear_all(ipa->interrupt); } -/* Transmit can run concurrent with power resume. When transmitting, - * we disable further transmits until we can determine whether power - * is ACTIVE. If it is, future transmits are re-enabled and the buffer - * gets sent (or dropped). If power is not ACTIVE, it will eventually - * be, and transmits stay disabled until after it is. This function - * starts the transmit queue and is used in the power resume path after - * power has become ACTIVE. - */ -void ipa_power_modem_queue_wake(struct ipa *ipa) -{ - netif_wake_queue(ipa->modem_netdev); -} - static int ipa_power_retention_init(struct ipa_power *power) { struct qmp *qmp = qmp_get(power->dev); diff --git a/drivers/net/ipa/ipa_power.h b/drivers/net/ipa/ipa_power.h index dcd36a6a718f..718aacf5e2b2 100644 --- a/drivers/net/ipa/ipa_power.h +++ b/drivers/net/ipa/ipa_power.h @@ -23,12 +23,6 @@ extern const struct dev_pm_ops ipa_pm_ops; */ u32 ipa_core_clock_rate(struct ipa *ipa); -/** - * ipa_power_modem_queue_wake() - Possibly wake the modem netdev TX queue - * @ipa: IPA pointer - */ -void ipa_power_modem_queue_wake(struct ipa *ipa); - /** * ipa_power_retention() - Control register retention on power collapse * @ipa: IPA pointer From 9484b9555de04ed16952dda6518b324f61a6fd6a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 31 Jan 2024 03:26:03 +0100 Subject: [PATCH 0586/2255] dt-bindings: net: ipq4019-mdio: document now supported clock-frequency Document support for clock-frequency and add details on why this property is needed and what values are supported. From internal documentation, while other values are supported, the correct function of the MDIO bus is not assured hence add only the suggested supported values to the property enum. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../bindings/net/qcom,ipq4019-mdio.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/net/qcom,ipq4019-mdio.yaml b/Documentation/devicetree/bindings/net/qcom,ipq4019-mdio.yaml index 3407e909e8a7..0029e197a825 100644 --- a/Documentation/devicetree/bindings/net/qcom,ipq4019-mdio.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ipq4019-mdio.yaml @@ -44,6 +44,21 @@ properties: items: - const: gcc_mdio_ahb_clk + clock-frequency: + description: + The MDIO bus clock that must be output by the MDIO bus hardware, if + absent, the default hardware values are used. + + MDC rate is feed by an external clock (fixed 100MHz) and is divider + internally. The default divider is /256 resulting in the default rate + applied of 390KHz. + + To follow 802.3 standard that instruct up to 2.5MHz by default, if + this property is not declared and the divider is set to /256, by + default 1.5625Mhz is select. + enum: [ 390625, 781250, 1562500, 3125000, 6250000, 12500000 ] + default: 1562500 + required: - compatible - reg From bdce82e960d1205d118662f575cec39379984e34 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 31 Jan 2024 03:26:04 +0100 Subject: [PATCH 0587/2255] net: mdio: ipq4019: add support for clock-frequency property The IPQ4019 MDIO internally divide the clock feed by AHB based on the MDIO_MODE reg. On reset or power up, the default value for the divider is 0xff that reflect the divider set to /256. This makes the MDC run at a very low rate, that is, considering AHB is always fixed to 100Mhz, a value of 390KHz. This hasn't have been a problem as MDIO wasn't used for time sensitive operation, it is now that on IPQ807x is usually mounted with PHY that requires MDIO to load their firmware (example Aquantia PHY). To handle this problem and permit to set the correct designed MDC frequency for the SoC add support for the standard "clock-frequency" property for the MDIO node. The divider supports value from /1 to /256 and the common value are to set it to /16 to reflect 6.25Mhz or to /8 on newer platform to reflect 12.5Mhz. To scan if the requested rate is supported by the divider, loop with each supported divider and stop when the requested rate match the final rate with the current divider. An error is returned if the rate doesn't match any value. On MDIO reset, the divider is restored to the requested value to prevent any kind of downclocking caused by the divider reverting to a default value. To follow 802.3 spec of 2.5MHz of default value, if divider is set at /256 and "clock-frequency" is not set in DT, assume nobody set the divider and try to find the closest MDC rate to 2.5MHz. (in the case of AHB set to 100MHz, it's 1.5625MHz) While at is also document other bits of the MDIO_MODE reg to have a clear idea of what is actually applied there. Documentation of some BITs is skipped as they are marked as reserved and their usage is not clear (RES 11:9 GENPHY 16:13 RES1 19:17) Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/mdio/mdio-ipq4019.c | 109 ++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/drivers/net/mdio/mdio-ipq4019.c b/drivers/net/mdio/mdio-ipq4019.c index abd8b508ec16..9d8f43b28aac 100644 --- a/drivers/net/mdio/mdio-ipq4019.c +++ b/drivers/net/mdio/mdio-ipq4019.c @@ -14,6 +14,20 @@ #include #define MDIO_MODE_REG 0x40 +#define MDIO_MODE_MDC_MODE BIT(12) +/* 0 = Clause 22, 1 = Clause 45 */ +#define MDIO_MODE_C45 BIT(8) +#define MDIO_MODE_DIV_MASK GENMASK(7, 0) +#define MDIO_MODE_DIV(x) FIELD_PREP(MDIO_MODE_DIV_MASK, (x) - 1) +#define MDIO_MODE_DIV_1 0x0 +#define MDIO_MODE_DIV_2 0x1 +#define MDIO_MODE_DIV_4 0x3 +#define MDIO_MODE_DIV_8 0x7 +#define MDIO_MODE_DIV_16 0xf +#define MDIO_MODE_DIV_32 0x1f +#define MDIO_MODE_DIV_64 0x3f +#define MDIO_MODE_DIV_128 0x7f +#define MDIO_MODE_DIV_256 0xff #define MDIO_ADDR_REG 0x44 #define MDIO_DATA_WRITE_REG 0x48 #define MDIO_DATA_READ_REG 0x4c @@ -26,9 +40,6 @@ #define MDIO_CMD_ACCESS_CODE_C45_WRITE 1 #define MDIO_CMD_ACCESS_CODE_C45_READ 2 -/* 0 = Clause 22, 1 = Clause 45 */ -#define MDIO_MODE_C45 BIT(8) - #define IPQ4019_MDIO_TIMEOUT 10000 #define IPQ4019_MDIO_SLEEP 10 @@ -41,6 +52,7 @@ struct ipq4019_mdio_data { void __iomem *membase; void __iomem *eth_ldo_rdy; struct clk *mdio_clk; + unsigned int mdc_rate; }; static int ipq4019_mdio_wait_busy(struct mii_bus *bus) @@ -203,6 +215,38 @@ static int ipq4019_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum, return 0; } +static int ipq4019_mdio_set_div(struct ipq4019_mdio_data *priv) +{ + unsigned long ahb_rate; + int div; + u32 val; + + /* If we don't have a clock for AHB use the fixed value */ + ahb_rate = IPQ_MDIO_CLK_RATE; + if (priv->mdio_clk) + ahb_rate = clk_get_rate(priv->mdio_clk); + + /* MDC rate is ahb_rate/(MDIO_MODE_DIV + 1) + * While supported, internal documentation doesn't + * assure correct functionality of the MDIO bus + * with divider of 1, 2 or 4. + */ + for (div = 8; div <= 256; div *= 2) { + /* The requested rate is supported by the div */ + if (priv->mdc_rate == DIV_ROUND_UP(ahb_rate, div)) { + val = readl(priv->membase + MDIO_MODE_REG); + val &= ~MDIO_MODE_DIV_MASK; + val |= MDIO_MODE_DIV(div); + writel(val, priv->membase + MDIO_MODE_REG); + + return 0; + } + } + + /* The requested rate is not supported */ + return -EINVAL; +} + static int ipq_mdio_reset(struct mii_bus *bus) { struct ipq4019_mdio_data *priv = bus->priv; @@ -225,10 +269,58 @@ static int ipq_mdio_reset(struct mii_bus *bus) return ret; ret = clk_prepare_enable(priv->mdio_clk); - if (ret == 0) - mdelay(10); + if (ret) + return ret; - return ret; + mdelay(10); + + /* Restore MDC rate */ + return ipq4019_mdio_set_div(priv); +} + +static void ipq4019_mdio_select_mdc_rate(struct platform_device *pdev, + struct ipq4019_mdio_data *priv) +{ + unsigned long ahb_rate; + int div; + u32 val; + + /* MDC rate defined in DT, we don't have to decide a default value */ + if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &priv->mdc_rate)) + return; + + /* If we don't have a clock for AHB use the fixed value */ + ahb_rate = IPQ_MDIO_CLK_RATE; + if (priv->mdio_clk) + ahb_rate = clk_get_rate(priv->mdio_clk); + + /* Check what is the current div set */ + val = readl(priv->membase + MDIO_MODE_REG); + div = FIELD_GET(MDIO_MODE_DIV_MASK, val); + + /* div is not set to the default value of /256 + * Probably someone changed that (bootloader, other drivers) + * Keep this and don't overwrite it. + */ + if (div != MDIO_MODE_DIV_256) { + priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div + 1); + return; + } + + /* If div is /256 assume nobody have set this value and + * try to find one MDC rate that is close the 802.3 spec of + * 2.5MHz + */ + for (div = 256; div >= 8; div /= 2) { + /* Stop as soon as we found a divider that + * reached the closest value to 2.5MHz + */ + if (DIV_ROUND_UP(ahb_rate, div) > 2500000) + break; + + priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div); + } } static int ipq4019_mdio_probe(struct platform_device *pdev) @@ -252,6 +344,11 @@ static int ipq4019_mdio_probe(struct platform_device *pdev) if (IS_ERR(priv->mdio_clk)) return PTR_ERR(priv->mdio_clk); + ipq4019_mdio_select_mdc_rate(pdev, priv); + ret = ipq4019_mdio_set_div(priv); + if (ret) + return ret; + /* The platform resource is provided on the chipset IPQ5018 */ /* This resource is optional */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); From 447b80a9330ef2d9a94fc5a9bf35b6eac061f38b Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 31 Jan 2024 08:50:48 +0100 Subject: [PATCH 0588/2255] net: phy: dp83867: Add support for active-low LEDs Add the led_polarity_set callback for setting LED polarity. Signed-off-by: Alexander Stein Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/dp83867.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 5f08f9d38bd7..4120385c5a79 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -158,6 +158,7 @@ /* LED_DRV bits */ #define DP83867_LED_DRV_EN(x) BIT((x) * 4) #define DP83867_LED_DRV_VAL(x) BIT((x) * 4 + 1) +#define DP83867_LED_POLARITY(x) BIT((x) * 4 + 2) #define DP83867_LED_FN(idx, val) (((val) & 0xf) << ((idx) * 4)) #define DP83867_LED_FN_MASK(idx) (0xf << ((idx) * 4)) @@ -1152,6 +1153,26 @@ static int dp83867_led_hw_control_get(struct phy_device *phydev, u8 index, return 0; } +static int dp83867_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + /* Default active high */ + u16 polarity = DP83867_LED_POLARITY(index); + u32 mode; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + polarity = 0; + break; + default: + return -EINVAL; + } + } + return phy_modify(phydev, DP83867_LEDCR2, + DP83867_LED_POLARITY(index), polarity); +} + static struct phy_driver dp83867_driver[] = { { .phy_id = DP83867_PHY_ID, @@ -1184,6 +1205,7 @@ static struct phy_driver dp83867_driver[] = { .led_hw_is_supported = dp83867_led_hw_is_supported, .led_hw_control_set = dp83867_led_hw_control_set, .led_hw_control_get = dp83867_led_hw_control_get, + .led_polarity_set = dp83867_led_polarity_set, }, }; module_phy_driver(dp83867_driver); From 094bdd48afb8dde4ac71a6a672b096108ded9f49 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Wed, 31 Jan 2024 17:08:22 +1300 Subject: [PATCH 0589/2255] selftests: openvswitch: Test ICMP related matches work with SNAT Add a test case for regression in openvswitch nat that was fixed by commit e6345d2824a3 ("netfilter: nf_nat: fix action not being set for all ct states"). Link: https://lore.kernel.org/netdev/20231221224311.130319-1-brad@faucet.nz/ Link: https://mail.openvswitch.org/pipermail/ovs-dev/2024-January/410476.html Suggested-by: Aaron Conole Signed-off-by: Brad Cowie Tested-by: Aaron Conole Acked-by: Aaron Conole Signed-off-by: David S. Miller --- .../selftests/net/openvswitch/openvswitch.sh | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh index f8499d4c87f3..87b80bee6df4 100755 --- a/tools/testing/selftests/net/openvswitch/openvswitch.sh +++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh @@ -17,6 +17,7 @@ tests=" ct_connect_v4 ip4-ct-xon: Basic ipv4 tcp connection using ct connect_v4 ip4-xon: Basic ipv4 ping between two NS nat_connect_v4 ip4-nat-xon: Basic ipv4 tcp connection via NAT + nat_related_v4 ip4-nat-related: ICMP related matches work with SNAT netlink_checks ovsnl: validate netlink attrs and settings upcall_interfaces ovs: test the upcall interfaces drop_reason drop: test drop reasons are emitted" @@ -473,6 +474,67 @@ test_nat_connect_v4 () { return 0 } +# nat_related_v4 test +# - client->server ip packets go via SNAT +# - client solicits ICMP destination unreachable packet from server +# - undo NAT for ICMP reply and test dst ip has been updated +test_nat_related_v4 () { + which nc >/dev/null 2>/dev/null || return $ksft_skip + + sbx_add "test_nat_related_v4" || return $? + + ovs_add_dp "test_nat_related_v4" natrelated4 || return 1 + info "create namespaces" + for ns in client server; do + ovs_add_netns_and_veths "test_nat_related_v4" "natrelated4" "$ns" \ + "${ns:0:1}0" "${ns:0:1}1" || return 1 + done + + ip netns exec client ip addr add 172.31.110.10/24 dev c1 + ip netns exec client ip link set c1 up + ip netns exec server ip addr add 172.31.110.20/24 dev s1 + ip netns exec server ip link set s1 up + + ip netns exec server ip route add 192.168.0.20/32 via 172.31.110.10 + + # Allow ARP + ovs_add_flow "test_nat_related_v4" natrelated4 \ + "in_port(1),eth(),eth_type(0x0806),arp()" "2" || return 1 + ovs_add_flow "test_nat_related_v4" natrelated4 \ + "in_port(2),eth(),eth_type(0x0806),arp()" "1" || return 1 + + # Allow IP traffic from client->server, rewrite source IP with SNAT to 192.168.0.20 + ovs_add_flow "test_nat_related_v4" natrelated4 \ + "ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=172.31.110.20)" \ + "ct(commit,nat(src=192.168.0.20)),recirc(0x1)" || return 1 + ovs_add_flow "test_nat_related_v4" natrelated4 \ + "recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" \ + "2" || return 1 + + # Allow related ICMP responses back from server and undo NAT to restore original IP + # Drop any ICMP related packets where dst ip hasn't been restored back to original IP + ovs_add_flow "test_nat_related_v4" natrelated4 \ + "ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \ + "ct(commit,nat),recirc(0x2)" || return 1 + ovs_add_flow "test_nat_related_v4" natrelated4 \ + "recirc_id(0x2),ct_state(+rel+trk),in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20,dst=172.31.110.10,proto=1),icmp()" \ + "1" || return 1 + ovs_add_flow "test_nat_related_v4" natrelated4 \ + "recirc_id(0x2),ct_state(+rel+trk),in_port(2),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20,proto=1),icmp()" \ + "drop" || return 1 + + # Solicit destination unreachable response from server + ovs_sbx "test_nat_related_v4" ip netns exec client \ + bash -c "echo a | nc -u -w 1 172.31.110.20 10000" + + # Check to make sure no packets matched the drop rule with incorrect dst ip + python3 "$ovs_base/ovs-dpctl.py" dump-flows natrelated4 \ + | grep "drop" | grep "packets:0" >/dev/null || return 1 + + info "done..." + return 0 +} + # netlink_validation # - Create a dp # - check no warning with "old version" simulation From 08d82175bfbbbf7fc2bfca391877abed320b5e29 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Jan 2024 15:54:52 +0000 Subject: [PATCH 0590/2255] wifi: ath9k: remove redundant assignment to variable ret MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The variable ret is being assigned a value but it isn't being read afterwards. The assignment is redundant and so ret can be removed. Cleans up clang scan build warning: warning: Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret' [deadcode.DeadStores] Signed-off-by: Colin Ian King Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20240116155452.2315351-1-colin.i.king@gmail.com --- drivers/net/wireless/ath/ath9k/xmit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f15684379b03..d519b676a109 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -369,12 +369,11 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct list_head bf_head; struct ath_tx_status ts; struct ath_frame_info *fi; - int ret; memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); - while ((ret = ath_tid_dequeue(tid, &skb)) == 0) { + while (ath_tid_dequeue(tid, &skb) == 0) { fi = get_frame_info(skb); bf = fi->bf; From 24355fcb0d4cbcb6ddda262596558e8cfba70f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Fri, 26 Jan 2024 15:02:17 +0100 Subject: [PATCH 0591/2255] wifi: ath9k: delay all of ath9k_wmi_event_tasklet() until init is complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ath9k_wmi_event_tasklet() used in ath9k_htc assumes that all the data structures have been fully initialised by the time it runs. However, because of the order in which things are initialised, this is not guaranteed to be the case, because the device is exposed to the USB subsystem before the ath9k driver initialisation is completed. We already committed a partial fix for this in commit: 8b3046abc99e ("ath9k_htc: fix NULL pointer dereference at ath9k_htc_tx_get_packet()") However, that commit only aborted the WMI_TXSTATUS_EVENTID command in the event tasklet, pairing it with an "initialisation complete" bit in the TX struct. It seems syzbot managed to trigger the race for one of the other commands as well, so let's just move the existing synchronisation bit to cover the whole tasklet (setting it at the end of ath9k_htc_probe_device() instead of inside ath9k_tx_init()). Link: https://lore.kernel.org/r/ed1d2c66-1193-4c81-9542-d514c29ba8b8.bugreport@ubisectech.com Fixes: 8b3046abc99e ("ath9k_htc: fix NULL pointer dereference at ath9k_htc_tx_get_packet()") Reported-by: Ubisectech Sirius Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20240126140218.1033443-1-toke@toke.dk --- drivers/net/wireless/ath/ath9k/htc.h | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 4 ++++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 4 ---- drivers/net/wireless/ath/ath9k/wmi.c | 10 ++++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 237f4ec2cffd..6c33e898b300 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -306,7 +306,6 @@ struct ath9k_htc_tx { DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); struct timer_list cleanup_timer; spinlock_t tx_lock; - bool initialized; }; struct ath9k_htc_tx_ctl { @@ -515,6 +514,7 @@ struct ath9k_htc_priv { unsigned long ps_usecount; bool ps_enabled; bool ps_idle; + bool initialized; #ifdef CONFIG_MAC80211_LEDS enum led_brightness brightness; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 0aa5bdeb44a1..3633f9eb2c55 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -966,6 +966,10 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, htc_handle->drv_priv = priv; + /* Allow ath9k_wmi_event_tasklet() to operate. */ + smp_wmb(); + priv->initialized = true; + return 0; err_init: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index efcaeccb055a..ce9c04e418b8 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -815,10 +815,6 @@ int ath9k_tx_init(struct ath9k_htc_priv *priv) skb_queue_head_init(&priv->tx.data_vo_queue); skb_queue_head_init(&priv->tx.tx_failed); - /* Allow ath9k_wmi_event_tasklet(WMI_TXSTATUS_EVENTID) to operate. */ - smp_wmb(); - priv->tx.initialized = true; - return 0; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 1476b42b52a9..805ad31edba2 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -155,6 +155,12 @@ void ath9k_wmi_event_tasklet(struct tasklet_struct *t) } spin_unlock_irqrestore(&wmi->wmi_lock, flags); + /* Check if ath9k_htc_probe_device() completed. */ + if (!data_race(priv->initialized)) { + kfree_skb(skb); + continue; + } + hdr = (struct wmi_cmd_hdr *) skb->data; cmd_id = be16_to_cpu(hdr->command_id); wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); @@ -169,10 +175,6 @@ void ath9k_wmi_event_tasklet(struct tasklet_struct *t) &wmi->drv_priv->fatal_work); break; case WMI_TXSTATUS_EVENTID: - /* Check if ath9k_tx_init() completed. */ - if (!data_race(priv->tx.initialized)) - break; - spin_lock_bh(&priv->tx.tx_lock); if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { spin_unlock_bh(&priv->tx.tx_lock); From 413e20e82ee78f142cb5194fd317db514f012602 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Wed, 31 Jan 2024 10:18:32 +0800 Subject: [PATCH 0592/2255] wifi: ath11k: change to move WMI_VDEV_PARAM_SET_HEMU_MODE before WMI_PEER_ASSOC_CMDID Currently when connecting to an AP with 11AX-HE phy mode, host sends WMI_VDEV_PARAM_SET_HEMU_MODE parameter to firmware after WMI_PEER_ASSOC_CMDID command. This results in TXBF not working, because firmware calculates TXBF values while handling WMI_PEER_ASSOC_CMDID, however at that time WMI_VDEV_PARAM_SET_HEMU_MODE has not been sent yet. See below log: AP sends "VHT/HE/EHT NDP Announcement" to station, and station sends "Action no Ack" of category code HE to AP, the "Nc Index" and "Codebook Information" are wrong: Issued action: IEEE 802.11 Action No Ack, Flags: ........ IEEE 802.11 wireless LAN Fixed parameters Category code: HE (30) HE Action: HE Compressed Beamforming And CQI (0) Total length: 152 HE MIMO Control: 0x0004008018 .... .... .... .... .... .... .... .... .... .000 = Nc Index: 1 Column (0) .... .... .... .... .... .... .... ..0. .... .... = Codebook Information: 0 Change to send WMI_VDEV_PARAM_SET_HEMU_MODE before WMI_PEER_ASSOC_CMDID, then firmware will calculate the TXBF values with valid parameters instead of empty values. TXBF works well and throughput performance is improved from 80 Mbps to 130 Mbps with this patch. Good action after this patch: IEEE 802.11 Action No Ack, Flags: ........ IEEE 802.11 wireless LAN Fixed parameters Category code: HE (30) HE Action: HE Compressed Beamforming And CQI (0) Total length: 409 HE MIMO Control: 0x0004008219 .... .... .... .... .... .... .... .... .... .001 = Nc Index: 2 Columns (1) .... .... .... .... .... .... .... ..1. .... .... = Codebook Information: 1 This change applies to all chipsets. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 38dfe775d0ab ("wifi: ath11k: push MU-MIMO params from hostapd to hardware") Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240131021832.17298-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index bbf4d1f4d310..df1b1ee71881 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3023,7 +3023,14 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, rcu_read_unlock(); + if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { + ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", + arvif->vdev_id, bss_conf->bssid); + return; + } + peer_arg.is_assoc = true; + ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); if (ret) { ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", @@ -3046,12 +3053,6 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, return; } - if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { - ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", - arvif->vdev_id, bss_conf->bssid); - return; - } - WARN_ON(arvif->is_up); arvif->aid = vif->cfg.aid; From 12f491cd6d812559e2d986b7836e9062d2efde96 Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Tue, 23 Jan 2024 17:58:12 +0530 Subject: [PATCH 0593/2255] wifi: ath12k: add firmware-2.bin support Firmware IE containers can dynamically provide various information what firmware supports. Also it can embed more than one image so updating firmware is easy, user just needs to update one file in /lib/firmware/. The firmware API 2 or higher will use the IE container format, the current API 1 will not use the new format but it still is supported for some time. Firmware API 2 files are named as firmware-2.bin (which contains both amss.bin and m3.bin images) and API 1 files are amss.bin and m3.bin. Currently ath12k PCI driver provides firmware binary (amss.bin) path to MHI driver, MHI driver reads firmware from filesystem and boots it. Add provision to read firmware files from ath12k driver and provide the amss.bin firmware data and size to MHI using a pointer. Currently enum ath12k_fw_features is empty, the patches adding features will add the flags. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123122812.3811251-1-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/Makefile | 3 +- drivers/net/wireless/ath/ath12k/core.c | 4 + drivers/net/wireless/ath/ath12k/core.h | 14 ++ drivers/net/wireless/ath/ath12k/fw.c | 164 +++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/fw.h | 27 ++++ drivers/net/wireless/ath/ath12k/mhi.c | 20 ++- drivers/net/wireless/ath/ath12k/qmi.c | 49 ++++--- 7 files changed, 259 insertions(+), 22 deletions(-) create mode 100644 drivers/net/wireless/ath/ath12k/fw.c create mode 100644 drivers/net/wireless/ath/ath12k/fw.h diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 62c52e733b5e..0d723e85cf6b 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -19,7 +19,8 @@ ath12k-y += core.o \ hw.o \ mhi.o \ pci.o \ - dp_mon.o + dp_mon.o \ + fw.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 1baad3302157..634a9ddc2fe5 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -14,6 +14,7 @@ #include "dp_rx.h" #include "debug.h" #include "hif.h" +#include "fw.h" unsigned int ath12k_debug_mask; module_param_named(debug_mask, ath12k_debug_mask, uint, 0644); @@ -1109,6 +1110,8 @@ int ath12k_core_pre_init(struct ath12k_base *ab) return ret; } + ath12k_fw_map(ab); + return 0; } @@ -1137,6 +1140,7 @@ void ath12k_core_deinit(struct ath12k_base *ab) ath12k_hif_power_down(ab); ath12k_mac_destroy(ab); ath12k_core_soc_destroy(ab); + ath12k_fw_unmap(ab); } void ath12k_core_free(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 5c6c1e2eddb6..fc906d7acd42 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "qmi.h" #include "htc.h" #include "wmi.h" @@ -24,6 +25,7 @@ #include "hal_rx.h" #include "reg.h" #include "dbring.h" +#include "fw.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -824,6 +826,18 @@ struct ath12k_base { u32 subsystem_device; } id; + struct { + u32 api_version; + + const struct firmware *fw; + const u8 *amss_data; + size_t amss_len; + const u8 *m3_data; + size_t m3_len; + + DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT); + } fw; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/fw.c b/drivers/net/wireless/ath/ath12k/fw.c new file mode 100644 index 000000000000..fbcf40c97792 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/fw.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" + +#include "debug.h" + +static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab, + const char *name) +{ + size_t magic_len, len, ie_len; + int ie_id, i, index, bit, ret; + struct ath12k_fw_ie *hdr; + const u8 *data; + __le32 *timestamp; + + ab->fw.fw = ath12k_core_firmware_request(ab, name); + if (IS_ERR(ab->fw.fw)) { + ret = PTR_ERR(ab->fw.fw); + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to load %s: %d\n", name, ret); + ab->fw.fw = NULL; + return ret; + } + + data = ab->fw.fw->data; + len = ab->fw.fw->size; + + /* magic also includes the null byte, check that as well */ + magic_len = strlen(ATH12K_FIRMWARE_MAGIC) + 1; + + if (len < magic_len) { + ath12k_err(ab, "firmware image too small to contain magic: %zu\n", + len); + ret = -EINVAL; + goto err; + } + + if (memcmp(data, ATH12K_FIRMWARE_MAGIC, magic_len) != 0) { + ath12k_err(ab, "Invalid firmware magic\n"); + ret = -EINVAL; + goto err; + } + + /* jump over the padding */ + magic_len = ALIGN(magic_len, 4); + + /* make sure there's space for padding */ + if (magic_len > len) { + ath12k_err(ab, "No space for padding after magic\n"); + ret = -EINVAL; + goto err; + } + + len -= magic_len; + data += magic_len; + + /* loop elements */ + while (len > sizeof(struct ath12k_fw_ie)) { + hdr = (struct ath12k_fw_ie *)data; + + ie_id = le32_to_cpu(hdr->id); + ie_len = le32_to_cpu(hdr->len); + + len -= sizeof(*hdr); + data += sizeof(*hdr); + + if (len < ie_len) { + ath12k_err(ab, "Invalid length for FW IE %d (%zu < %zu)\n", + ie_id, len, ie_len); + ret = -EINVAL; + goto err; + } + + switch (ie_id) { + case ATH12K_FW_IE_TIMESTAMP: + if (ie_len != sizeof(u32)) + break; + + timestamp = (__le32 *)data; + + ath12k_dbg(ab, ATH12K_DBG_BOOT, "found fw timestamp %d\n", + le32_to_cpup(timestamp)); + break; + case ATH12K_FW_IE_FEATURES: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found firmware features ie (%zd B)\n", + ie_len); + + for (i = 0; i < ATH12K_FW_FEATURE_COUNT; i++) { + index = i / 8; + bit = i % 8; + + if (index == ie_len) + break; + + if (data[index] & (1 << bit)) + __set_bit(i, ab->fw.fw_features); + } + + ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "features", "", + ab->fw.fw_features, + sizeof(ab->fw.fw_features)); + break; + case ATH12K_FW_IE_AMSS_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found fw image ie (%zd B)\n", + ie_len); + + ab->fw.amss_data = data; + ab->fw.amss_len = ie_len; + break; + case ATH12K_FW_IE_M3_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found m3 image ie (%zd B)\n", + ie_len); + + ab->fw.m3_data = data; + ab->fw.m3_len = ie_len; + break; + default: + ath12k_warn(ab, "Unknown FW IE: %u\n", ie_id); + break; + } + + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + + /* make sure there's space for padding */ + if (ie_len > len) + break; + + len -= ie_len; + data += ie_len; + } + + return 0; + +err: + release_firmware(ab->fw.fw); + ab->fw.fw = NULL; + return ret; +} + +void ath12k_fw_map(struct ath12k_base *ab) +{ + int ret; + + ret = ath12k_fw_request_firmware_api_n(ab, ATH12K_FW_API2_FILE); + if (ret == 0) + ab->fw.api_version = 2; + else + ab->fw.api_version = 1; + + ath12k_dbg(ab, ATH12K_DBG_BOOT, "using fw api %d\n", + ab->fw.api_version); +} + +void ath12k_fw_unmap(struct ath12k_base *ab) +{ + release_firmware(ab->fw.fw); + memset(&ab->fw, 0, sizeof(ab->fw)); +} diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h new file mode 100644 index 000000000000..d91d95fc5740 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef ATH12K_FW_H +#define ATH12K_FW_H + +#define ATH12K_FW_API2_FILE "firmware-2.bin" +#define ATH12K_FIRMWARE_MAGIC "QCOM-ATH12K-FW" + +enum ath12k_fw_ie_type { + ATH12K_FW_IE_TIMESTAMP = 0, + ATH12K_FW_IE_FEATURES = 1, + ATH12K_FW_IE_AMSS_IMAGE = 2, + ATH12K_FW_IE_M3_IMAGE = 3, +}; + +enum ath12k_fw_features { + /* keep last */ + ATH12K_FW_FEATURE_COUNT, +}; + +void ath12k_fw_map(struct ath12k_base *ab); +void ath12k_fw_unmap(struct ath12k_base *ab); + +#endif /* ATH12K_FW_H */ diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index d5441ddb374b..b7b31978a434 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020-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 +#include #include "core.h" #include "debug.h" @@ -364,17 +365,24 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) if (!mhi_ctrl) return -ENOMEM; - ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, - ab_pci->amss_path, - sizeof(ab_pci->amss_path)); - ab_pci->mhi_ctrl = mhi_ctrl; mhi_ctrl->cntrl_dev = ab->dev; - mhi_ctrl->fw_image = ab_pci->amss_path; mhi_ctrl->regs = ab->mem; mhi_ctrl->reg_len = ab->mem_len; mhi_ctrl->rddm_size = ab->hw_params->rddm_size; + if (ab->fw.amss_data && ab->fw.amss_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_data; + mhi_ctrl->fw_sz = ab->fw.amss_len; + } else { + /* use the old separate mhi.bin MHI firmware file */ + ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, + ab_pci->amss_path, + sizeof(ab_pci->amss_path)); + mhi_ctrl->fw_image = ab_pci->amss_path; + } + ret = ath12k_mhi_get_msi(ab_pci); if (ret) { ath12k_err(ab, "failed to get msi for mhi\n"); diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 69f56400367c..0f0eaadc8418 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2666,37 +2666,56 @@ out: static int ath12k_qmi_m3_load(struct ath12k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; - const struct firmware *fw; + const struct firmware *fw = NULL; + const void *m3_data; char path[100]; + size_t m3_len; int ret; - if (m3_mem->vaddr || m3_mem->size) + if (m3_mem->vaddr) + /* m3 firmware buffer is already available in the DMA buffer */ return 0; - fw = ath12k_core_firmware_request(ab, ATH12K_M3_FILE); - if (IS_ERR(fw)) { - ret = PTR_ERR(fw); - ath12k_core_create_firmware_path(ab, ATH12K_M3_FILE, - path, sizeof(path)); - ath12k_err(ab, "failed to load %s: %d\n", path, ret); - return ret; + if (ab->fw.m3_data && ab->fw.m3_len > 0) { + /* firmware-N.bin had a m3 firmware file so use that */ + m3_data = ab->fw.m3_data; + m3_len = ab->fw.m3_len; + } else { + /* No m3 file in firmware-N.bin so try to request old + * separate m3.bin. + */ + fw = ath12k_core_firmware_request(ab, ATH12K_M3_FILE); + if (IS_ERR(fw)) { + ret = PTR_ERR(fw); + ath12k_core_create_firmware_path(ab, ATH12K_M3_FILE, + path, sizeof(path)); + ath12k_err(ab, "failed to load %s: %d\n", path, ret); + return ret; + } + + m3_data = fw->data; + m3_len = fw->size; } m3_mem->vaddr = dma_alloc_coherent(ab->dev, - fw->size, &m3_mem->paddr, + m3_len, &m3_mem->paddr, GFP_KERNEL); if (!m3_mem->vaddr) { ath12k_err(ab, "failed to allocate memory for M3 with size %zu\n", fw->size); - release_firmware(fw); - return -ENOMEM; + ret = -ENOMEM; + goto out; } - memcpy(m3_mem->vaddr, fw->data, fw->size); - m3_mem->size = fw->size; + memcpy(m3_mem->vaddr, m3_data, m3_len); + m3_mem->size = m3_len; + + ret = 0; + +out: release_firmware(fw); - return 0; + return ret; } static void ath12k_qmi_m3_free(struct ath12k_base *ab) From d6212d2e41a0cb1ff6b059db79c70752cdafc95e Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Wed, 31 Jan 2024 13:24:40 +0530 Subject: [PATCH 0594/2255] octeontx2-af: Create BPIDs free pool In current driver 64 BPIDs are reserved for LBK interfaces. These bpids are 1-to-1 mapped to LBK interface channel numbers. In some usecases one LBK interface required more than one bpids and in some case they may not require at all. These usescase can't be address with the current implementation as it always reserves only one bpid per LBK channel. This patch addresses this issue by creating free bpid pool from these 64 bpids instead of 1-to-1 mapping to the lbk channel. Now based on usecase LBK interface can request a bpid using (bp_enable()). This patch also reduces the number of bpids for cgx interfaces to 8 and adds proper error code Signed-off-by: Geetha sowjanya Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 2 + .../net/ethernet/marvell/octeontx2/af/rvu.c | 3 + .../net/ethernet/marvell/octeontx2/af/rvu.h | 12 ++ .../ethernet/marvell/octeontx2/af/rvu_nix.c | 165 ++++++++++++++---- .../ethernet/marvell/octeontx2/af/rvu_reg.h | 3 + 5 files changed, 150 insertions(+), 35 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index bb8d60e7bab1..d5c4f810da61 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -837,6 +837,8 @@ enum nix_af_status { NIX_AF_ERR_CQ_CTX_WRITE_ERR = -429, NIX_AF_ERR_AQ_CTX_RETRY_WRITE = -430, NIX_AF_ERR_LINK_CREDITS = -431, + NIX_AF_ERR_INVALID_BPID = -434, + NIX_AF_ERR_INVALID_BPID_REQ = -435, NIX_AF_ERR_INVALID_MCAST_GRP = -436, NIX_AF_ERR_INVALID_MCAST_DEL_REQ = -437, NIX_AF_ERR_NON_CONTIG_MCE_LIST = -438, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 5c1d04a3c559..7048167707d1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -2618,6 +2618,9 @@ static void __rvu_flr_handler(struct rvu *rvu, u16 pcifunc) * 3. Cleanup pools (NPA) */ + /* Free allocated BPIDs */ + rvu_nix_flr_free_bpids(rvu, pcifunc); + /* Free multicast/mirror node associated with the 'pcifunc' */ rvu_nix_mcast_flr_free_entries(rvu, pcifunc); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 43be37dd1f32..6971f441c22b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -288,6 +288,16 @@ enum rvu_pfvf_flags { #define RVU_CLEAR_VF_PERM ~GENMASK(PF_SET_VF_TRUSTED, PF_SET_VF_MAC) +struct nix_bp { + struct rsrc_bmap bpids; /* free bpids bitmap */ + u16 cgx_bpid_cnt; + u16 sdp_bpid_cnt; + u16 free_pool_base; + u16 *fn_map; /* pcifunc mapping */ + u8 *intf_map; /* interface type map */ + u8 *ref_cnt; +}; + struct nix_txsch { struct rsrc_bmap schq; u8 lvl; @@ -363,6 +373,7 @@ struct nix_hw { struct nix_lso lso; struct nix_txvlan txvlan; struct nix_ipolicer *ipolicer; + struct nix_bp bp; u64 *tx_credits; u8 cc_mcs_cnt; }; @@ -873,6 +884,7 @@ int rvu_nix_mcast_get_mce_index(struct rvu *rvu, u16 pcifunc, u32 mcast_grp_idx); int rvu_nix_mcast_update_mcam_entry(struct rvu *rvu, u16 pcifunc, u32 mcast_grp_idx, u16 mcam_index); +void rvu_nix_flr_free_bpids(struct rvu *rvu, u16 pcifunc); /* NPC APIs */ void rvu_npc_freemem(struct rvu *rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index febd00c63bf6..09e7d84f8025 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -499,14 +499,84 @@ static void nix_interface_deinit(struct rvu *rvu, u16 pcifunc, u8 nixlf) rvu_cgx_disable_dmac_entries(rvu, pcifunc); } +#define NIX_BPIDS_PER_LMAC 8 +#define NIX_BPIDS_PER_CPT 1 +static int nix_setup_bpids(struct rvu *rvu, struct nix_hw *hw, int blkaddr) +{ + struct nix_bp *bp = &hw->bp; + int err, max_bpids; + u64 cfg; + + cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST1); + max_bpids = FIELD_GET(NIX_CONST_MAX_BPIDS, cfg); + + /* Reserve the BPIds for CGX and SDP */ + bp->cgx_bpid_cnt = rvu->hw->cgx_links * NIX_BPIDS_PER_LMAC; + bp->sdp_bpid_cnt = rvu->hw->sdp_links * FIELD_GET(NIX_CONST_SDP_CHANS, cfg); + bp->free_pool_base = bp->cgx_bpid_cnt + bp->sdp_bpid_cnt + + NIX_BPIDS_PER_CPT; + bp->bpids.max = max_bpids - bp->free_pool_base; + + err = rvu_alloc_bitmap(&bp->bpids); + if (err) + return err; + + bp->fn_map = devm_kcalloc(rvu->dev, bp->bpids.max, + sizeof(u16), GFP_KERNEL); + if (!bp->fn_map) + return -ENOMEM; + + bp->intf_map = devm_kcalloc(rvu->dev, bp->bpids.max, + sizeof(u8), GFP_KERNEL); + if (!bp->intf_map) + return -ENOMEM; + + bp->ref_cnt = devm_kcalloc(rvu->dev, bp->bpids.max, + sizeof(u8), GFP_KERNEL); + if (!bp->ref_cnt) + return -ENOMEM; + + return 0; +} + +void rvu_nix_flr_free_bpids(struct rvu *rvu, u16 pcifunc) +{ + int blkaddr, bpid, err; + struct nix_hw *nix_hw; + struct nix_bp *bp; + + if (!is_afvf(pcifunc)) + return; + + err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr); + if (err) + return; + + bp = &nix_hw->bp; + + mutex_lock(&rvu->rsrc_lock); + for (bpid = 0; bpid < bp->bpids.max; bpid++) { + if (bp->fn_map[bpid] == pcifunc) { + bp->ref_cnt[bpid]--; + if (bp->ref_cnt[bpid]) + continue; + rvu_free_rsrc(&bp->bpids, bpid); + bp->fn_map[bpid] = 0; + } + } + mutex_unlock(&rvu->rsrc_lock); +} + int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, struct nix_bp_cfg_req *req, struct msg_rsp *rsp) { u16 pcifunc = req->hdr.pcifunc; + int blkaddr, pf, type, err; + u16 chan_base, chan, bpid; struct rvu_pfvf *pfvf; - int blkaddr, pf, type; - u16 chan_base, chan; + struct nix_hw *nix_hw; + struct nix_bp *bp; u64 cfg; pf = rvu_get_pf(pcifunc); @@ -515,13 +585,29 @@ int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, return 0; pfvf = rvu_get_pfvf(rvu, pcifunc); - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr); + if (err) + return err; + bp = &nix_hw->bp; chan_base = pfvf->rx_chan_base + req->chan_base; for (chan = chan_base; chan < (chan_base + req->chan_cnt); chan++) { cfg = rvu_read64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(chan)); rvu_write64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(chan), cfg & ~BIT_ULL(16)); + + if (type == NIX_INTF_TYPE_LBK) { + bpid = cfg & GENMASK(8, 0); + mutex_lock(&rvu->rsrc_lock); + rvu_free_rsrc(&bp->bpids, bpid - bp->free_pool_base); + for (bpid = 0; bpid < bp->bpids.max; bpid++) { + if (bp->fn_map[bpid] == pcifunc) { + bp->fn_map[bpid] = 0; + bp->ref_cnt[bpid] = 0; + } + } + mutex_unlock(&rvu->rsrc_lock); + } } return 0; } @@ -529,26 +615,21 @@ int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req, int type, int chan_id) { - int bpid, blkaddr, lmac_chan_cnt, sdp_chan_cnt; - u16 cgx_bpid_cnt, lbk_bpid_cnt, sdp_bpid_cnt; + int bpid, blkaddr, sdp_chan_base, err; struct rvu_hwinfo *hw = rvu->hw; struct rvu_pfvf *pfvf; + struct nix_hw *nix_hw; u8 cgx_id, lmac_id; - u64 cfg; - - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, req->hdr.pcifunc); - cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST); - lmac_chan_cnt = cfg & 0xFF; - - cgx_bpid_cnt = hw->cgx_links * lmac_chan_cnt; - lbk_bpid_cnt = hw->lbk_links * ((cfg >> 16) & 0xFF); - - cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST1); - sdp_chan_cnt = cfg & 0xFFF; - sdp_bpid_cnt = hw->sdp_links * sdp_chan_cnt; + struct nix_bp *bp; pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc); + err = nix_get_struct_ptrs(rvu, req->hdr.pcifunc, &nix_hw, &blkaddr); + if (err) + return err; + + bp = &nix_hw->bp; + /* Backpressure IDs range division * CGX channles are mapped to (0 - 191) BPIDs * LBK channles are mapped to (192 - 255) BPIDs @@ -561,38 +642,48 @@ static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req, */ switch (type) { case NIX_INTF_TYPE_CGX: - if ((req->chan_base + req->chan_cnt) > 16) - return -EINVAL; + if ((req->chan_base + req->chan_cnt) > NIX_BPIDS_PER_LMAC) + return NIX_AF_ERR_INVALID_BPID_REQ; rvu_get_cgx_lmac_id(pfvf->cgx_lmac, &cgx_id, &lmac_id); /* Assign bpid based on cgx, lmac and chan id */ - bpid = (cgx_id * hw->lmac_per_cgx * lmac_chan_cnt) + - (lmac_id * lmac_chan_cnt) + req->chan_base; + bpid = (cgx_id * hw->lmac_per_cgx * NIX_BPIDS_PER_LMAC) + + (lmac_id * NIX_BPIDS_PER_LMAC) + req->chan_base; if (req->bpid_per_chan) bpid += chan_id; - if (bpid > cgx_bpid_cnt) - return -EINVAL; + if (bpid > bp->cgx_bpid_cnt) + return NIX_AF_ERR_INVALID_BPID; break; case NIX_INTF_TYPE_LBK: - if ((req->chan_base + req->chan_cnt) > 63) - return -EINVAL; - bpid = cgx_bpid_cnt + req->chan_base; - if (req->bpid_per_chan) - bpid += chan_id; - if (bpid > (cgx_bpid_cnt + lbk_bpid_cnt)) - return -EINVAL; + /* Alloc bpid from the free pool */ + mutex_lock(&rvu->rsrc_lock); + bpid = rvu_alloc_rsrc(&bp->bpids); + if (bpid < 0) { + mutex_unlock(&rvu->rsrc_lock); + return NIX_AF_ERR_INVALID_BPID; + } + bp->fn_map[bpid] = req->hdr.pcifunc; + bp->ref_cnt[bpid]++; + bpid += bp->free_pool_base; + mutex_unlock(&rvu->rsrc_lock); break; case NIX_INTF_TYPE_SDP: - if ((req->chan_base + req->chan_cnt) > 255) - return -EINVAL; + if ((req->chan_base + req->chan_cnt) > bp->sdp_bpid_cnt) + return NIX_AF_ERR_INVALID_BPID_REQ; - bpid = sdp_bpid_cnt + req->chan_base; + /* Handle usecase of 2 SDP blocks */ + if (!hw->cap.programmable_chans) + sdp_chan_base = pfvf->rx_chan_base - NIX_CHAN_SDP_CH_START; + else + sdp_chan_base = pfvf->rx_chan_base - hw->sdp_chan_base; + + bpid = bp->cgx_bpid_cnt + req->chan_base + sdp_chan_base; if (req->bpid_per_chan) bpid += chan_id; - if (bpid > (cgx_bpid_cnt + lbk_bpid_cnt + sdp_bpid_cnt)) - return -EINVAL; + if (bpid > (bp->cgx_bpid_cnt + bp->sdp_bpid_cnt)) + return NIX_AF_ERR_INVALID_BPID; break; default: return -EINVAL; @@ -4791,6 +4882,10 @@ static int rvu_nix_block_init(struct rvu *rvu, struct nix_hw *nix_hw) if (err) return err; + err = nix_setup_bpids(rvu, nix_hw, blkaddr); + if (err) + return err; + /* Configure segmentation offload formats */ nix_setup_lso(rvu, nix_hw, blkaddr); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index 6f73ad9807f0..086f05c0376f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -439,6 +439,9 @@ #define NIX_AF_LINKX_RANGE_MASK GENMASK_ULL(19, 16) #define NIX_AF_LINKX_MCS_CNT_MASK GENMASK_ULL(33, 32) +#define NIX_CONST_MAX_BPIDS GENMASK_ULL(23, 12) +#define NIX_CONST_SDP_CHANS GENMASK_ULL(11, 0) + /* SSO */ #define SSO_AF_CONST (0x1000) #define SSO_AF_CONST1 (0x1008) From ae703539f49d20cafc888f5d2e8fe5851d5da6cd Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Wed, 31 Jan 2024 13:24:41 +0530 Subject: [PATCH 0595/2255] octeontx2-af: Cleanup loopback device checks PCI device IDs of RVU device IDs are configurable and RVU PF0's (ie AF's) are currently assumed as VFs that identify loopback functionality ie LBKVFs. But in some cases these VFs can be setup for different functionality. Hence remove assumptions that AF's VFs are always LBK VFs by renaming 'is_afvf' as 'is_lbkvf' explicitly and also identify LBK VF using PCI dev ID. Similar change is done for other VF types. Signed-off-by: Geetha sowjanya Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++-- .../net/ethernet/marvell/octeontx2/af/rvu.h | 9 ++++++--- .../ethernet/marvell/octeontx2/af/rvu_nix.c | 18 +++++++++--------- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 8 ++++---- .../ethernet/marvell/octeontx2/af/rvu_sdp.c | 6 +++++- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 7048167707d1..edd12d09dc89 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1484,7 +1484,7 @@ int rvu_get_nix_blkaddr(struct rvu *rvu, u16 pcifunc) /* All CGX mapped PFs are set with assigned NIX block during init */ if (is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc))) { blkaddr = pf->nix_blkaddr; - } else if (is_afvf(pcifunc)) { + } else if (is_lbk_vf(rvu, pcifunc)) { vf = pcifunc - 1; /* Assign NIX based on VF number. All even numbered VFs get * NIX0 and odd numbered gets NIX1 @@ -2034,7 +2034,7 @@ int rvu_mbox_handler_set_vf_perm(struct rvu *rvu, struct set_vf_perm *req, u16 target; /* Only PF can add VF permissions */ - if ((pcifunc & RVU_PFVF_FUNC_MASK) || is_afvf(pcifunc)) + if ((pcifunc & RVU_PFVF_FUNC_MASK) || is_lbk_vf(rvu, pcifunc)) return -EOPNOTSUPP; target = (pcifunc & ~RVU_PFVF_FUNC_MASK) | (req->vf + 1); @@ -3154,6 +3154,7 @@ static int rvu_enable_sriov(struct rvu *rvu) { struct pci_dev *pdev = rvu->pdev; int err, chans, vfs; + int pos = 0; if (!rvu_afvf_msix_vectors_num_ok(rvu)) { dev_warn(&pdev->dev, @@ -3161,6 +3162,12 @@ static int rvu_enable_sriov(struct rvu *rvu) return 0; } + /* Get RVU VFs device id */ + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); + if (!pos) + return 0; + pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &rvu->vf_devid); + chans = rvu_get_num_lbk_chans(); if (chans < 0) return chans; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 6971f441c22b..a1d5fc65b92d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -514,6 +514,7 @@ struct rvu { struct mutex rsrc_lock; /* Serialize resource alloc/free */ struct mutex alias_lock; /* Serialize bar2 alias access */ int vfs; /* Number of VFs attached to RVU */ + u16 vf_devid; /* VF devices id */ int nix_blkaddr[MAX_NIX_BLKS]; /* Mbox */ @@ -743,9 +744,11 @@ static inline bool is_rvu_supports_nix1(struct rvu *rvu) /* Function Prototypes * RVU */ -static inline bool is_afvf(u16 pcifunc) +#define RVU_LBK_VF_DEVID 0xA0F8 +static inline bool is_lbk_vf(struct rvu *rvu, u16 pcifunc) { - return !(pcifunc & ~RVU_PFVF_FUNC_MASK); + return (!(pcifunc & ~RVU_PFVF_FUNC_MASK) && + (rvu->vf_devid == RVU_LBK_VF_DEVID)); } static inline bool is_vf(u16 pcifunc) @@ -805,7 +808,7 @@ void rvu_aq_free(struct rvu *rvu, struct admin_queue *aq); int rvu_sdp_init(struct rvu *rvu); bool is_sdp_pfvf(u16 pcifunc); bool is_sdp_pf(u16 pcifunc); -bool is_sdp_vf(u16 pcifunc); +bool is_sdp_vf(struct rvu *rvu, u16 pcifunc); /* CGX APIs */ static inline bool is_pf_cgxmapped(struct rvu *rvu, u8 pf) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 09e7d84f8025..d39001cdc707 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -545,7 +545,7 @@ void rvu_nix_flr_free_bpids(struct rvu *rvu, u16 pcifunc) struct nix_hw *nix_hw; struct nix_bp *bp; - if (!is_afvf(pcifunc)) + if (!is_lbk_vf(rvu, pcifunc)) return; err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr); @@ -580,7 +580,7 @@ int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, u64 cfg; pf = rvu_get_pf(pcifunc); - type = is_afvf(pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; + type = is_lbk_vf(rvu, pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; if (!is_pf_cgxmapped(rvu, pf) && type != NIX_INTF_TYPE_LBK) return 0; @@ -703,7 +703,7 @@ int rvu_mbox_handler_nix_bp_enable(struct rvu *rvu, u64 cfg; pf = rvu_get_pf(pcifunc); - type = is_afvf(pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; + type = is_lbk_vf(rvu, pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; if (is_sdp_pfvf(pcifunc)) type = NIX_INTF_TYPE_SDP; @@ -1614,7 +1614,7 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, cfg = NPC_TX_DEF_PKIND; rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg); - intf = is_afvf(pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; + intf = is_lbk_vf(rvu, pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; if (is_sdp_pfvf(pcifunc)) intf = NIX_INTF_TYPE_SDP; @@ -1990,7 +1990,7 @@ static int nix_get_tx_link(struct rvu *rvu, u16 pcifunc) int pf = rvu_get_pf(pcifunc); u8 cgx_id = 0, lmac_id = 0; - if (is_afvf(pcifunc)) {/* LBK links */ + if (is_lbk_vf(rvu, pcifunc)) {/* LBK links */ return hw->cgx_links; } else if (is_pf_cgxmapped(rvu, pf)) { rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); @@ -2007,7 +2007,7 @@ static void nix_get_txschq_range(struct rvu *rvu, u16 pcifunc, struct rvu_hwinfo *hw = rvu->hw; int pf = rvu_get_pf(pcifunc); - if (is_afvf(pcifunc)) { /* LBK links */ + if (is_lbk_vf(rvu, pcifunc)) { /* LBK links */ *start = hw->cap.nix_txsch_per_cgx_lmac * link; *end = *start + hw->cap.nix_txsch_per_lbk_lmac; } else if (is_pf_cgxmapped(rvu, pf)) { /* CGX links */ @@ -3447,7 +3447,7 @@ static int nix_update_mce_rule(struct rvu *rvu, u16 pcifunc, int pf; /* skip multicast pkt replication for AF's VFs & SDP links */ - if (is_afvf(pcifunc) || is_sdp_pfvf(pcifunc)) + if (is_lbk_vf(rvu, pcifunc) || is_sdp_pfvf(pcifunc)) return 0; if (!hw->cap.nix_rx_multicast) @@ -3794,7 +3794,7 @@ int rvu_mbox_handler_nix_get_hw_info(struct rvu *rvu, struct msg_req *req, if (blkaddr < 0) return NIX_AF_ERR_AF_LF_INVALID; - if (is_afvf(pcifunc)) + if (is_lbk_vf(rvu, pcifunc)) rvu_get_lbk_link_max_frs(rvu, &rsp->max_mtu); else rvu_get_lmac_link_max_frs(rvu, &rsp->max_mtu); @@ -4518,7 +4518,7 @@ int rvu_mbox_handler_nix_set_hw_frs(struct rvu *rvu, struct nix_frs_cfg *req, if (!nix_hw) return NIX_AF_ERR_INVALID_NIXBLK; - if (is_afvf(pcifunc)) + if (is_lbk_vf(rvu, pcifunc)) rvu_get_lbk_link_max_frs(rvu, &max_mtu); else rvu_get_lmac_link_max_frs(rvu, &max_mtu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index 167145bdcb75..da3573b0dfc2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -417,7 +417,7 @@ static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam, owner = mcam->entry2pfvf_map[index]; target_func = (entry->action >> 4) & 0xffff; /* do nothing when target is LBK/PF or owner is not PF */ - if (is_pffunc_af(owner) || is_afvf(target_func) || + if (is_pffunc_af(owner) || is_lbk_vf(rvu, target_func) || (owner & RVU_PFVF_FUNC_MASK) || !(target_func & RVU_PFVF_FUNC_MASK)) return; @@ -626,7 +626,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, int blkaddr, index; /* AF's and SDP VFs work in promiscuous mode */ - if (is_afvf(pcifunc) || is_sdp_vf(pcifunc)) + if (is_lbk_vf(rvu, pcifunc) || is_sdp_vf(rvu, pcifunc)) return; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); @@ -791,7 +791,7 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc, return; /* Skip LBK VFs */ - if (is_afvf(pcifunc)) + if (is_lbk_vf(rvu, pcifunc)) return; /* If pkt replication is not supported, @@ -871,7 +871,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf, u16 vf_func; /* Only CGX PF/VF can add allmulticast entry */ - if (is_afvf(pcifunc) && is_sdp_vf(pcifunc)) + if (is_lbk_vf(rvu, pcifunc) && is_sdp_vf(rvu, pcifunc)) return; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c index ae50d56258ec..1edfda0ae3e8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c @@ -40,8 +40,12 @@ bool is_sdp_pf(u16 pcifunc) !(pcifunc & RVU_PFVF_FUNC_MASK)); } -bool is_sdp_vf(u16 pcifunc) +#define RVU_SDP_VF_DEVID 0xA0F7 +bool is_sdp_vf(struct rvu *rvu, u16 pcifunc) { + if (!(pcifunc & ~RVU_PFVF_FUNC_MASK)) + return (rvu->vf_devid == RVU_SDP_VF_DEVID); + return (is_sdp_pfvf(pcifunc) && !!(pcifunc & RVU_PFVF_FUNC_MASK)); } From fa33b35f86b8010938e474643ef4f88b62a9b262 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Wed, 31 Jan 2024 16:45:49 +0800 Subject: [PATCH 0596/2255] sctp: Simplify the allocation of slab caches commit 0a31bd5f2bbb ("KMEM_CACHE(): simplify slab cache creation") introduces a new macro. Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Reviewed-by: Jiri Pirko Acked-by: Xin Long Signed-off-by: David S. Miller --- net/sctp/protocol.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 94c6dd53cd62..e849f368ed91 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1495,17 +1495,11 @@ static __init int sctp_init(void) /* Allocate bind_bucket and chunk caches. */ status = -ENOBUFS; - sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket", - sizeof(struct sctp_bind_bucket), - 0, SLAB_HWCACHE_ALIGN, - NULL); + sctp_bucket_cachep = KMEM_CACHE(sctp_bind_bucket, SLAB_HWCACHE_ALIGN); if (!sctp_bucket_cachep) goto out; - sctp_chunk_cachep = kmem_cache_create("sctp_chunk", - sizeof(struct sctp_chunk), - 0, SLAB_HWCACHE_ALIGN, - NULL); + sctp_chunk_cachep = KMEM_CACHE(sctp_chunk, SLAB_HWCACHE_ALIGN); if (!sctp_chunk_cachep) goto err_chunk_cachep; From 84f90efd5076525a581e3f923f6c86579f41e713 Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Wed, 31 Jan 2024 14:23:51 +0530 Subject: [PATCH 0597/2255] dt-bindings: net: ti: Update maintainers list Update the list with the current maintainers of TI's CPSW ethernet peripheral. Signed-off-by: Ravi Gunasekaran Acked-by: Roger Quadros Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml | 5 +++-- .../devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml | 5 +++-- Documentation/devicetree/bindings/net/ti,k3-am654-cpts.yaml | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml b/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml index f07ae3173b03..d5bd93ee4dbb 100644 --- a/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml +++ b/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml @@ -7,8 +7,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: TI SoC Ethernet Switch Controller (CPSW) maintainers: - - Grygorii Strashko - - Sekhar Nori + - Siddharth Vadapalli + - Ravi Gunasekaran + - Roger Quadros description: The 3-port switch gigabit ethernet subsystem provides ethernet packet diff --git a/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml b/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml index c9c25132d154..73ed5951d296 100644 --- a/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml +++ b/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml @@ -7,8 +7,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: The TI AM654x/J721E/AM642x SoC Gigabit Ethernet MAC (Media Access Controller) maintainers: - - Grygorii Strashko - - Sekhar Nori + - Siddharth Vadapalli + - Ravi Gunasekaran + - Roger Quadros description: The TI AM654x/J721E SoC Gigabit Ethernet MAC (CPSW2G NUSS) has two ports diff --git a/Documentation/devicetree/bindings/net/ti,k3-am654-cpts.yaml b/Documentation/devicetree/bindings/net/ti,k3-am654-cpts.yaml index 3e910d3b24a0..b1c875325776 100644 --- a/Documentation/devicetree/bindings/net/ti,k3-am654-cpts.yaml +++ b/Documentation/devicetree/bindings/net/ti,k3-am654-cpts.yaml @@ -7,8 +7,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: The TI AM654x/J721E Common Platform Time Sync (CPTS) module maintainers: - - Grygorii Strashko - - Sekhar Nori + - Siddharth Vadapalli + - Ravi Gunasekaran + - Roger Quadros description: |+ The TI AM654x/J721E CPTS module is used to facilitate host control of time From 20ea9327c2fd545d6b96e998727bcd724290694d Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Wed, 31 Jan 2024 17:08:51 +0800 Subject: [PATCH 0598/2255] net: dccp: Simplify the allocation of slab caches in dccp_ackvec_init Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/dccp/ackvec.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index c4bbac99740d..1cba001bb4c8 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -376,15 +376,11 @@ EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_cleanup); int __init dccp_ackvec_init(void) { - dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", - sizeof(struct dccp_ackvec), 0, - SLAB_HWCACHE_ALIGN, NULL); + dccp_ackvec_slab = KMEM_CACHE(dccp_ackvec, SLAB_HWCACHE_ALIGN); if (dccp_ackvec_slab == NULL) goto out_err; - dccp_ackvec_record_slab = kmem_cache_create("dccp_ackvec_record", - sizeof(struct dccp_ackvec_record), - 0, SLAB_HWCACHE_ALIGN, NULL); + dccp_ackvec_record_slab = KMEM_CACHE(dccp_ackvec_record, SLAB_HWCACHE_ALIGN); if (dccp_ackvec_record_slab == NULL) goto out_destroy_slab; From 6925eba532e1e9a30ae0f6807dba07f596ba0cd6 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Mon, 29 Jan 2024 12:27:12 +0530 Subject: [PATCH 0599/2255] wifi: ath12k: indicate NON MBSSID vdev by default during vdev start When any VDEV is started, MBSSID flags are passed to firmware to indicate if its a MBSSID/EMA AP vdev. If the interface is not an AP or if the AP doesn't support MBSSID, the vdev needs to be brought up as a non MBSSID vdev. Set these flags as a non MBSSID AP by default which can be updated as and when MBSSID support is added in ath12k. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Sriram R Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-2-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 5 +++++ drivers/net/wireless/ath/ath12k/wmi.c | 1 + drivers/net/wireless/ath/ath12k/wmi.h | 8 ++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a27480a69b27..672c9d347097 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6153,6 +6153,11 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; + /* Fill the MBSSID flags to indicate AP is non MBSSID by default + * Corresponding flags would be updated with MBSSID support. + */ + arg.mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP; + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; arg.ssid_len = arvif->u.ap.ssid_len; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 2fa724e5851a..5f1cce16589f 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1024,6 +1024,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, cmd->regdomain = cpu_to_le32(arg->regdomain); cmd->he_ops = cpu_to_le32(arg->he_ops); cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); + cmd->mbssid_flags = cpu_to_le32(arg->mbssid_flags); if (!restart) { if (arg->ssid) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 06e5b9b4049b..d8481c710021 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.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_WMI_H @@ -2764,6 +2764,10 @@ struct ath12k_wmi_ssid_params { #define ATH12K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) +enum wmi_vdev_mbssid_flags { + WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP = BIT(0), +}; + struct wmi_vdev_start_request_cmd { __le32 tlv_header; __le32 vdev_id; @@ -2782,7 +2786,7 @@ struct wmi_vdev_start_request_cmd { __le32 cac_duration_ms; __le32 regdomain; __le32 min_data_rate; - __le32 mbssid_flags; + __le32 mbssid_flags; /* uses enum wmi_vdev_mbssid_flags */ __le32 mbssid_tx_vdev_id; __le32 eht_ops; __le32 punct_bitmap; From 9f06911998cac015e333f519243f1601ca687f47 Mon Sep 17 00:00:00 2001 From: Sowmiya Sree Elavalagan Date: Mon, 29 Jan 2024 12:27:13 +0530 Subject: [PATCH 0600/2255] wifi: ath12k: fetch correct pdev id from WMI_SERVICE_READY_EXT_EVENTID Currently while fetching for pdev id from WMI_SERVICE_READY_EXT_EVENTID we consider 32 bit pdev_id in ath12k_wmi_caps_ext_params structure. But Firmware sends lower 16 bit for pdev id along with higher 16 bit for hw_link_id. Due to this wrong pdev id is fetched. This wrong pdev id when used for WMI commands leads to Firmware crash. Hence fetch the correct pdev id considering only the lower 16 bits. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Sowmiya Sree Elavalagan Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-3-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 9 +++--- drivers/net/wireless/ath/ath12k/wmi.h | 44 ++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 5f1cce16589f..487ca82bd17d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -493,13 +493,13 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, mac_caps = wmi_mac_phy_caps + phy_idx; - pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id); + pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); fw_pdev = &ab->fw_pdev[ab->fw_pdev_count]; fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands); - fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id); + fw_pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id); ab->fw_pdev_count++; @@ -4215,7 +4215,7 @@ ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, for (i = 0; i < ab->fw_pdev_count; i++) { struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i]; - if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) && + if (fw_pdev->pdev_id == ath12k_wmi_caps_ext_get_pdev_id(caps) && fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) { bands = fw_pdev->supported_bands; break; @@ -4272,7 +4272,8 @@ static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, return 0; } else { for (i = 0; i < ab->num_radios; i++) { - if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id)) + if (ab->pdevs[i].pdev_id == + ath12k_wmi_caps_ext_get_pdev_id(caps)) break; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index d8481c710021..06b931222321 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2542,9 +2542,17 @@ struct ath12k_wmi_hw_mode_cap_params { #define WMI_MAX_HECAP_PHY_SIZE (3) +/* pdev_id is present in lower 16 bits of pdev_and_hw_link_ids in + * ath12k_wmi_mac_phy_caps_params & ath12k_wmi_caps_ext_params. + * + * hw_link_id is present in higher 16 bits of pdev_and_hw_link_ids. + */ +#define WMI_CAPS_PARAMS_PDEV_ID GENMASK(15, 0) +#define WMI_CAPS_PARAMS_HW_LINK_ID GENMASK(31, 16) + struct ath12k_wmi_mac_phy_caps_params { __le32 hw_mode_id; - __le32 pdev_id; + __le32 pdev_and_hw_link_ids; __le32 phy_id; __le32 supported_flags; __le32 supported_bands; @@ -2636,13 +2644,7 @@ struct wmi_service_ready_ext2_event { struct ath12k_wmi_caps_ext_params { __le32 hw_mode_id; - union { - struct { - __le16 pdev_id; - __le16 hw_link_id; - } __packed ath12k_wmi_pdev_to_link_map; - __le32 pdev_id; - }; + __le32 pdev_and_hw_link_ids; __le32 phy_id; __le32 wireless_modes_ext; __le32 eht_cap_mac_info_2ghz[WMI_MAX_EHTCAP_MAC_SIZE]; @@ -4921,4 +4923,30 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id, int ath12k_wmi_set_hw_mode(struct ath12k_base *ab, enum wmi_host_hw_mode_config_type mode); +static inline u32 +ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, WMI_CAPS_PARAMS_PDEV_ID); +} + +static inline u32 +ath12k_wmi_caps_ext_get_hw_link_id(const struct ath12k_wmi_caps_ext_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, WMI_CAPS_PARAMS_HW_LINK_ID); +} + +static inline u32 +ath12k_wmi_mac_phy_get_pdev_id(const struct ath12k_wmi_mac_phy_caps_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, + WMI_CAPS_PARAMS_PDEV_ID); +} + +static inline u32 +ath12k_wmi_mac_phy_get_hw_link_id(const struct ath12k_wmi_mac_phy_caps_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, + WMI_CAPS_PARAMS_HW_LINK_ID); +} + #endif From 28703381099022e18df1de7c2c665d72f92c7819 Mon Sep 17 00:00:00 2001 From: Harshitha Prem Date: Mon, 29 Jan 2024 12:27:14 +0530 Subject: [PATCH 0601/2255] wifi: ath12k: add support for peer meta data version Add support to process WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT service bit. If this service bit is set by firmware, then it expects host to set rx_peer_meta_data_ver in wmi_resource_config's flags2 with value 3 for QCN9274 to indicate as V1B meta version. If this is not set firmware crash is seen during peer addition. Hence, if WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT service bit is set by firmware, set correct peer metadata version to avoid firmware crash. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Harshitha Prem Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-4-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.h | 4 +++- drivers/net/wireless/ath/ath12k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath12k/wmi.h | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 0c3b416ae150..44ba3a50e075 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.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_HW_H @@ -66,6 +66,8 @@ #define TARGET_NUM_WDS_ENTRIES 32 #define TARGET_DMA_BURST_SIZE 1 #define TARGET_RX_BATCHMODE 1 +#define TARGET_RX_PEER_METADATA_VER_V1A 2 +#define TARGET_RX_PEER_METADATA_VER_V1B 3 #define ATH12K_HW_MAX_QUEUES 4 #define ATH12K_QUEUE_LEN 4096 diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 487ca82bd17d..276351d68efb 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -228,6 +228,9 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, config->peer_map_unmap_version = 0x32; config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; + + if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) + config->dp_peer_meta_data_ver = TARGET_RX_PEER_METADATA_VER_V1B; } void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -3266,6 +3269,9 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); + wmi_cfg->flags2 = le32_encode_bits(tg_cfg->dp_peer_meta_data_ver, + WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); + wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 06b931222321..7443831d62d8 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2163,6 +2163,8 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_11BE = 289, + WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, + WMI_MAX_EXT2_SERVICE, }; @@ -2350,6 +2352,7 @@ struct ath12k_wmi_resource_config_arg { u32 twt_ap_pdev_count; u32 twt_ap_sta_count; bool is_reg_cc_ext_event_supported; + u8 dp_peer_meta_data_ver; }; struct ath12k_wmi_init_cmd_arg { @@ -2402,6 +2405,7 @@ struct wmi_init_cmd { } __packed; #define WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT 4 +#define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) struct ath12k_wmi_resource_config_params { __le32 tlv_header; From 902700d55d4a4522bb3eb4ef94f752a19c42230a Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:15 +0530 Subject: [PATCH 0602/2255] wifi: ath12k: fix fetching MCBC flag for QCN9274 In QCN9274, RX packet's multicast and broadcast(MCBC) flag is fetched from RX descriptor's msdu_end info5 member but it is not correct for QCN9274. Due to this with encryption, ARP request packet is wrongly marked as MCBC packet and it is sent to mac80211 without setting RX_FLAG_PN_VALIDATED & RX_FLAG_DECRYPTED flag. This results in packet getting dropped in mac80211. Hence ping initiated from station to AP fails. Fix this by fetching correct MCBC flag in case of QCN9274. For QC9274 MCBC flag should be fetched from RX descriptor's mpdu_start info6 member. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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 Fixes: 8f04852e90cb ("wifi: ath12k: Use msdu_end to check MCBC") Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-5-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/hal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index a489369d8068..1bdab8604db9 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.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 "hal_tx.h" @@ -449,8 +449,8 @@ static u8 *ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) static bool ath12k_hw_qcn9274_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) { - return __le16_to_cpu(desc->u.qcn9274.msdu_end.info5) & - RX_MSDU_END_INFO5_DA_IS_MCBC; + return __le32_to_cpu(desc->u.qcn9274.mpdu_start.info6) & + RX_MPDU_START_INFO6_MCAST_BCAST; } static void ath12k_hw_qcn9274_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, From 94e8235c679db3e3b130a91d4c1d8f5023a5bb01 Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Mon, 29 Jan 2024 12:27:16 +0530 Subject: [PATCH 0603/2255] wifi: ath12k: Add logic to write QRTR node id to scratch Currently only one MHI device is registered successfully on platform having two or more identical MHI devices. This is beacuse QMI service runs with identical QRTR node ID. And, qrtr-lookup cannot register more than one QMI service with identical node ID. Hence, generate a unique QRTR instance ID from PCIe domain number and bus number. QMI allows node id to be written on scratch register. Add logic to write QRTR node id to the register. It is available for firmware to uniquely identify an instance. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: P Praneesh Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-6-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/fw.h | 5 ++++ drivers/net/wireless/ath/ath12k/pci.c | 39 ++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/pci.h | 3 ++- drivers/net/wireless/ath/ath12k/qmi.h | 1 - 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h index d91d95fc5740..28dc1423df70 100644 --- a/drivers/net/wireless/ath/ath12k/fw.h +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -17,6 +17,11 @@ enum ath12k_fw_ie_type { }; enum ath12k_fw_features { + /* The firmware supports setting the QRTR id via register + * PCIE_LOCAL_REG_QRTR_NODE_ID + */ + ATH12K_FW_FEATURE_MULTI_QRTR_ID = 0, + /* keep last */ ATH12K_FW_FEATURE_COUNT, }; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 76438b3afd55..7a0ed7c9f5a2 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.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 @@ -39,6 +39,10 @@ #define QCN9274_DEVICE_ID 0x1109 #define WCN7850_DEVICE_ID 0x1107 +#define PCIE_LOCAL_REG_QRTR_NODE_ID 0x1E03164 +#define DOMAIN_NUMBER_MASK GENMASK(7, 4) +#define BUS_NUMBER_MASK GENMASK(3, 0) + static const struct pci_device_id ath12k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) }, @@ -682,12 +686,22 @@ static void ath12k_pci_init_qmi_ce_config(struct ath12k_base *ab) { struct ath12k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + struct pci_bus *bus = ab_pci->pdev->bus; + cfg->tgt_ce = ab->hw_params->target_ce_config; cfg->tgt_ce_len = ab->hw_params->target_ce_count; cfg->svc_to_ce_map = ab->hw_params->svc_to_ce_map; cfg->svc_to_ce_map_len = ab->hw_params->svc_to_ce_map_len; ab->qmi.service_ins_id = ab->hw_params->qmi_service_ins_id; + + if (test_bit(ATH12K_FW_FEATURE_MULTI_QRTR_ID, ab->fw.fw_features)) { + ab_pci->qmi_instance = + u32_encode_bits(pci_domain_nr(bus), DOMAIN_NUMBER_MASK) | + u32_encode_bits(bus->number, BUS_NUMBER_MASK); + ab->qmi.service_ins_id += ab_pci->qmi_instance; + } } static void ath12k_pci_ce_irqs_enable(struct ath12k_base *ab) @@ -901,6 +915,26 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci) set_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags); } +static void ath12k_pci_update_qrtr_node_id(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + u32 reg; + + /* On platforms with two or more identical mhi devices, qmi service run + * with identical qrtr-node-id. Because of this identical ID qrtr-lookup + * cannot register more than one qmi service with identical node ID. + * + * This generates a unique instance ID from PCIe domain number and bus number, + * writes to the given register, it is available for firmware when the QMI service + * is spawned. + */ + reg = PCIE_LOCAL_REG_QRTR_NODE_ID & WINDOW_RANGE_MASK; + ath12k_pci_write32(ab, reg, ab_pci->qmi_instance); + + ath12k_dbg(ab, ATH12K_DBG_PCI, "pci reg 0x%x instance 0x%x read val 0x%x\n", + reg, ab_pci->qmi_instance, ath12k_pci_read32(ab, reg)); +} + static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci) { if (test_and_clear_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags)) @@ -1219,6 +1253,9 @@ int ath12k_pci_power_up(struct ath12k_base *ab) ath12k_pci_msi_enable(ab_pci); + if (test_bit(ATH12K_FW_FEATURE_MULTI_QRTR_ID, ab->fw.fw_features)) + ath12k_pci_update_qrtr_node_id(ab); + ret = ath12k_mhi_start(ab_pci); if (ret) { ath12k_err(ab, "failed to start mhi: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index b2edf32ada20..023616928f03 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_PCI_H #define ATH12K_PCI_H @@ -111,6 +111,7 @@ struct ath12k_pci { u16 link_ctl; unsigned long irq_flags; const struct ath12k_pci_ops *pci_ops; + u32 qmi_instance; }; static inline struct ath12k_pci *ath12k_pci_priv(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 828ab2bf037d..6ee33c9851c6 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -15,7 +15,6 @@ #define ATH12K_QMI_MAX_BDF_FILE_NAME_SIZE 64 #define ATH12K_QMI_CALDB_ADDRESS 0x4BA00000 #define ATH12K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 -#define ATH12K_QMI_WLFW_NODE_ID_BASE 0x07 #define ATH12K_QMI_WLFW_SERVICE_ID_V01 0x45 #define ATH12K_QMI_WLFW_SERVICE_VERS_V01 0x01 #define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01 0x02 From 664a1c96b297965c443446e61ccb02ebc961ddc3 Mon Sep 17 00:00:00 2001 From: Aaradhana Sahu Date: Mon, 29 Jan 2024 12:27:17 +0530 Subject: [PATCH 0604/2255] wifi: ath12k: fix firmware assert during insmod in memory segment mode In segment memory mode, firmware allocates memory segments of size 2 MB. This 2 MB memory is used by firmware for the number of peers. This number of peer is sent from host to firmware during WMI init command. For single-phy the number of peers sent is TARGET_NUM_PEERS_SINGLE = 529 (512 + 17). While for split-phy number of peers sent to firmware is TARGET_NUM_PEERS_DBS = 2 *(512 + 17) = 1058. With this 1058 number of peers firmware is unable to allocate memory in 2 MB segment and firmware crash is observed. Hence, fix this firmware crash by reducing the number of stations TARGET_NUM_STATIONS for split-phy. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Aaradhana Sahu Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-7-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 27 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/core.h | 3 +++ drivers/net/wireless/ath/ath12k/hw.h | 23 ++++++++++++++++------ drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- drivers/net/wireless/ath/ath12k/wmi.c | 15 +++----------- 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 634a9ddc2fe5..7f0b395f1296 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -510,6 +510,33 @@ exit: return ret; } +u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab) +{ + if (ab->num_radios == 2) + return TARGET_NUM_STATIONS_DBS; + else if (ab->num_radios == 3) + return TARGET_NUM_PEERS_PDEV_DBS_SBS; + return TARGET_NUM_STATIONS_SINGLE; +} + +u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab) +{ + if (ab->num_radios == 2) + return TARGET_NUM_PEERS_PDEV_DBS; + else if (ab->num_radios == 3) + return TARGET_NUM_PEERS_PDEV_DBS_SBS; + return TARGET_NUM_PEERS_PDEV_SINGLE; +} + +u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab) +{ + if (ab->num_radios == 2) + return TARGET_NUM_TIDS(DBS); + else if (ab->num_radios == 3) + return TARGET_NUM_TIDS(DBS_SBS); + return TARGET_NUM_TIDS(SINGLE); +} + 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 fc906d7acd42..68b4031ac484 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -869,6 +869,9 @@ int ath12k_core_suspend(struct ath12k_base *ab); const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, const char *filename); +u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab); +u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab); +u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab); static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state) { diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 44ba3a50e075..efa3411dc63d 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -17,19 +17,30 @@ /* Num VDEVS per radio */ #define TARGET_NUM_VDEVS (16 + 1) -#define TARGET_NUM_PEERS_PDEV (512 + TARGET_NUM_VDEVS) +#define TARGET_NUM_PEERS_PDEV_SINGLE (TARGET_NUM_STATIONS_SINGLE + \ + TARGET_NUM_VDEVS) +#define TARGET_NUM_PEERS_PDEV_DBS (TARGET_NUM_STATIONS_DBS + \ + TARGET_NUM_VDEVS) +#define TARGET_NUM_PEERS_PDEV_DBS_SBS (TARGET_NUM_STATIONS_DBS_SBS + \ + TARGET_NUM_VDEVS) /* Num of peers for Single Radio mode */ -#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV_SINGLE) /* Num of peers for DBS */ -#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV_DBS) /* Num of peers for DBS_SBS */ -#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV_DBS_SBS) -/* Max num of stations (per radio) */ -#define TARGET_NUM_STATIONS 512 +/* Max num of stations for Single Radio mode */ +#define TARGET_NUM_STATIONS_SINGLE 512 + +/* Max num of stations for DBS */ +#define TARGET_NUM_STATIONS_DBS 128 + +/* Max num of stations for DBS_SBS */ +#define TARGET_NUM_STATIONS_DBS_SBS 128 #define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x #define TARGET_NUM_PEER_KEYS 2 diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 672c9d347097..046bb466a391 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7624,8 +7624,8 @@ static int ath12k_mac_setup_register(struct ath12k *ar, 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; + ar->max_num_stations = ath12k_core_get_max_station_per_radio(ar->ab); + ar->max_num_peers = ath12k_core_get_max_peers_per_radio(ar->ab); return 0; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 276351d68efb..7fc269eb4a0c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -179,18 +179,9 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config) { config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; - - if (ab->num_radios == 2) { - config->num_peers = TARGET_NUM_PEERS(DBS); - config->num_tids = TARGET_NUM_TIDS(DBS); - } else if (ab->num_radios == 3) { - config->num_peers = TARGET_NUM_PEERS(DBS_SBS); - config->num_tids = TARGET_NUM_TIDS(DBS_SBS); - } else { - /* Control should not reach here */ - config->num_peers = TARGET_NUM_PEERS(SINGLE); - config->num_tids = TARGET_NUM_TIDS(SINGLE); - } + config->num_peers = ab->num_radios * + ath12k_core_get_max_peers_per_radio(ab); + config->num_tids = ath12k_core_get_max_num_tids(ab); config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; config->num_peer_keys = TARGET_NUM_PEER_KEYS; From f7019c2fcdf68a0df3a30735c91bb4fb8e2b810d Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:18 +0530 Subject: [PATCH 0605/2255] wifi: ath12k: split hal_ops to support RX TLVs word mask compaction With word mask subscription support, the rx_desc structure will change. The fields in this structure rx_desc will be reduced to only the required fields. To make word mask subscription changes compatible with the older firmware version (firmware that does not support word mask subscription), two different structures of rx_desc will be required for the same hardware. Most of the hal_ops are directly related to rx_desc. Hence, split hal_ops into operations that are independent of rx_desc (hal_ops) and the operations that are directly dependent on rx_desc (hal_rx_ops). These hal_rx_ops depend on both hardware and firmware hence move them out of hw_params. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-8-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 + drivers/net/wireless/ath/ath12k/dp_mon.c | 3 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 72 ++++++++++++------------ drivers/net/wireless/ath/ath12k/hal.c | 18 ++++-- drivers/net/wireless/ath/ath12k/hal.h | 12 +++- drivers/net/wireless/ath/ath12k/pci.c | 2 + 6 files changed, 63 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 68b4031ac484..67bf8d840b00 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -838,6 +838,8 @@ struct ath12k_base { DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT); } fw; + const struct hal_rx_ops *hal_rx_ops; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 2432ab605c85..7aa55cf64e8b 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -917,7 +917,8 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, u8 qos_pkt = 0; rx_desc = (struct hal_rx_desc *)head_msdu->data; - hdr_desc = ab->hw_params->hal_ops->rx_desc_get_msdu_payload(rx_desc); + hdr_desc = + ab->hal_rx_ops->rx_desc_get_msdu_payload(rx_desc); /* Base size */ wh = (struct ieee80211_hdr_3addr *)hdr_desc; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index a31c24b54851..d8816b38ccaa 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -23,34 +23,34 @@ static enum hal_encrypt_type ath12k_dp_rx_h_enctype(struct ath12k_base *ab, struct hal_rx_desc *desc) { - if (!ab->hw_params->hal_ops->rx_desc_encrypt_valid(desc)) + if (!ab->hal_rx_ops->rx_desc_encrypt_valid(desc)) return HAL_ENCRYPT_TYPE_OPEN; - return ab->hw_params->hal_ops->rx_desc_get_encrypt_type(desc); + return ab->hal_rx_ops->rx_desc_get_encrypt_type(desc); } u8 ath12k_dp_rx_h_decap_type(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_decap_type(desc); + return ab->hal_rx_ops->rx_desc_get_decap_type(desc); } static u8 ath12k_dp_rx_h_mesh_ctl_present(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mesh_ctl(desc); + return ab->hal_rx_ops->rx_desc_get_mesh_ctl(desc); } static bool ath12k_dp_rx_h_seq_ctrl_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); } static bool ath12k_dp_rx_h_fc_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_fc_valid(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_fc_valid(desc); } static bool ath12k_dp_rx_h_more_frags(struct ath12k_base *ab, @@ -74,149 +74,149 @@ static u16 ath12k_dp_rx_h_frag_no(struct ath12k_base *ab, static u16 ath12k_dp_rx_h_seq_no(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_start_seq_no(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_start_seq_no(desc); } static bool ath12k_dp_rx_h_msdu_done(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_msdu_done(desc); + return ab->hal_rx_ops->dp_rx_h_msdu_done(desc); } static bool ath12k_dp_rx_h_l4_cksum_fail(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_l4_cksum_fail(desc); + return ab->hal_rx_ops->dp_rx_h_l4_cksum_fail(desc); } static bool ath12k_dp_rx_h_ip_cksum_fail(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_ip_cksum_fail(desc); + return ab->hal_rx_ops->dp_rx_h_ip_cksum_fail(desc); } static bool ath12k_dp_rx_h_is_decrypted(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_is_decrypted(desc); + return ab->hal_rx_ops->dp_rx_h_is_decrypted(desc); } u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_mpdu_err(desc); + return ab->hal_rx_ops->dp_rx_h_mpdu_err(desc); } static u16 ath12k_dp_rx_h_msdu_len(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_len(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_len(desc); } static u8 ath12k_dp_rx_h_sgi(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_sgi(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_sgi(desc); } static u8 ath12k_dp_rx_h_rate_mcs(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_rate_mcs(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_rate_mcs(desc); } static u8 ath12k_dp_rx_h_rx_bw(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_rx_bw(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_rx_bw(desc); } static u32 ath12k_dp_rx_h_freq(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_freq(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_freq(desc); } static u8 ath12k_dp_rx_h_pkt_type(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_pkt_type(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_pkt_type(desc); } static u8 ath12k_dp_rx_h_nss(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return hweight8(ab->hw_params->hal_ops->rx_desc_get_msdu_nss(desc)); + return hweight8(ab->hal_rx_ops->rx_desc_get_msdu_nss(desc)); } static u8 ath12k_dp_rx_h_tid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_tid(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_tid(desc); } static u16 ath12k_dp_rx_h_peer_id(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_peer_id(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_peer_id(desc); } u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_l3_pad_bytes(desc); + return ab->hal_rx_ops->rx_desc_get_l3_pad_bytes(desc); } static bool ath12k_dp_rx_h_first_msdu(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_first_msdu(desc); + return ab->hal_rx_ops->rx_desc_get_first_msdu(desc); } static bool ath12k_dp_rx_h_last_msdu(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_last_msdu(desc); + return ab->hal_rx_ops->rx_desc_get_last_msdu(desc); } static void ath12k_dp_rx_desc_end_tlv_copy(struct ath12k_base *ab, struct hal_rx_desc *fdesc, struct hal_rx_desc *ldesc) { - ab->hw_params->hal_ops->rx_desc_copy_end_tlv(fdesc, ldesc); + ab->hal_rx_ops->rx_desc_copy_end_tlv(fdesc, ldesc); } static void ath12k_dp_rxdesc_set_msdu_len(struct ath12k_base *ab, struct hal_rx_desc *desc, u16 len) { - ab->hw_params->hal_ops->rx_desc_set_msdu_len(desc, len); + ab->hal_rx_ops->rx_desc_set_msdu_len(desc, len); } static bool ath12k_dp_rx_h_is_da_mcbc(struct ath12k_base *ab, struct hal_rx_desc *desc) { return (ath12k_dp_rx_h_first_msdu(ab, desc) && - ab->hw_params->hal_ops->rx_desc_is_da_mcbc(desc)); + ab->hal_rx_ops->rx_desc_is_da_mcbc(desc)); } static bool ath12k_dp_rxdesc_mac_addr2_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_mac_addr2_valid(desc); + return ab->hal_rx_ops->rx_desc_mac_addr2_valid(desc); } static u8 *ath12k_dp_rxdesc_get_mpdu_start_addr2(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_mpdu_start_addr2(desc); + return ab->hal_rx_ops->rx_desc_mpdu_start_addr2(desc); } static void ath12k_dp_rx_desc_get_dot11_hdr(struct ath12k_base *ab, struct hal_rx_desc *desc, struct ieee80211_hdr *hdr) { - ab->hw_params->hal_ops->rx_desc_get_dot11_hdr(desc, hdr); + ab->hal_rx_ops->rx_desc_get_dot11_hdr(desc, hdr); } static void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_base *ab, @@ -224,13 +224,13 @@ static void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_base *ab, u8 *crypto_hdr, enum hal_encrypt_type enctype) { - ab->hw_params->hal_ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype); + ab->hal_rx_ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype); } static u16 ath12k_dp_rxdesc_get_mpdu_frame_ctrl(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_frame_ctl(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_frame_ctl(desc); } static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) @@ -3935,9 +3935,9 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) tlv_filter.rx_packet_offset = hal_rx_desc_sz; tlv_filter.rx_mpdu_start_offset = - ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); + ab->hal_rx_ops->rx_desc_get_mpdu_start_offset(); tlv_filter.rx_msdu_end_offset = - ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); + ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); /* TODO: Selectively subscribe to required qwords within msdu_end * and mpdu_start and setup the mask in below msg @@ -3973,9 +3973,9 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) tlv_filter.rx_header_offset = offsetof(struct hal_rx_desc_wcn7850, pkt_hdr_tlv); tlv_filter.rx_mpdu_start_offset = - ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); + ab->hal_rx_ops->rx_desc_get_mpdu_start_offset(); tlv_filter.rx_msdu_end_offset = - ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); + ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); /* TODO: Selectively subscribe to required qwords within msdu_end * and mpdu_start and setup the mask in below msg diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 1bdab8604db9..b6b8298a2bdc 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -680,7 +680,7 @@ static u32 ath12k_hw_qcn9274_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } -const struct hal_ops hal_qcn9274_ops = { +const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_rx_desc_get_last_msdu, .rx_desc_get_l3_pad_bytes = ath12k_hw_qcn9274_rx_desc_get_l3_pad_bytes, @@ -712,8 +712,6 @@ const struct hal_ops hal_qcn9274_ops = { .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_qcn9274_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_qcn9274_rx_desc_get_mpdu_frame_ctl, - .create_srng_config = ath12k_hal_srng_create_config_qcn9274, - .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, .dp_rx_h_msdu_done = ath12k_hw_qcn9274_dp_rx_h_msdu_done, .dp_rx_h_l4_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_l4_cksum_fail, .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_ip_cksum_fail, @@ -721,6 +719,11 @@ const struct hal_ops hal_qcn9274_ops = { .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_dp_rx_h_mpdu_err, }; +const struct hal_ops hal_qcn9274_ops = { + .create_srng_config = ath12k_hal_srng_create_config_qcn9274, + .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, +}; + static bool ath12k_hw_wcn7850_rx_desc_get_first_msdu(struct hal_rx_desc *desc) { return !!le16_get_bits(desc->u.wcn7850.msdu_end.info5, @@ -1134,7 +1137,7 @@ static u32 ath12k_hw_wcn7850_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } -const struct hal_ops hal_wcn7850_ops = { +const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, .rx_desc_get_l3_pad_bytes = ath12k_hw_wcn7850_rx_desc_get_l3_pad_bytes, @@ -1167,8 +1170,6 @@ const struct hal_ops hal_wcn7850_ops = { .rx_desc_get_dot11_hdr = ath12k_hw_wcn7850_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_wcn7850_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_wcn7850_rx_desc_get_mpdu_frame_ctl, - .create_srng_config = ath12k_hal_srng_create_config_wcn7850, - .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, .dp_rx_h_msdu_done = ath12k_hw_wcn7850_dp_rx_h_msdu_done, .dp_rx_h_l4_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_l4_cksum_fail, .dp_rx_h_ip_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_ip_cksum_fail, @@ -1176,6 +1177,11 @@ const struct hal_ops hal_wcn7850_ops = { .dp_rx_h_mpdu_err = ath12k_hw_wcn7850_dp_rx_h_mpdu_err, }; +const struct hal_ops hal_wcn7850_ops = { + .create_srng_config = ath12k_hal_srng_create_config_wcn7850, + .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, +}; + static int ath12k_hal_alloc_cont_rdp(struct ath12k_base *ab) { struct ath12k_hal *hal = &ab->hal; diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index fc47e7e6b498..33dedfbb3964 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.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_HAL_H @@ -1031,7 +1031,7 @@ struct ath12k_hal_tcl_to_wbm_rbm_map { u8 rbm_id; }; -struct hal_ops { +struct hal_rx_ops { bool (*rx_desc_get_first_msdu)(struct hal_rx_desc *desc); bool (*rx_desc_get_last_msdu)(struct hal_rx_desc *desc); u8 (*rx_desc_get_l3_pad_bytes)(struct hal_rx_desc *desc); @@ -1070,18 +1070,24 @@ struct hal_ops { void (*rx_desc_get_crypto_header)(struct hal_rx_desc *desc, u8 *crypto_hdr, enum hal_encrypt_type enctype); - int (*create_srng_config)(struct ath12k_base *ab); bool (*dp_rx_h_msdu_done)(struct hal_rx_desc *desc); bool (*dp_rx_h_l4_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_ip_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_is_decrypted)(struct hal_rx_desc *desc); u32 (*dp_rx_h_mpdu_err)(struct hal_rx_desc *desc); +}; + +struct hal_ops { + int (*create_srng_config)(struct ath12k_base *ab); const struct ath12k_hal_tcl_to_wbm_rbm_map *tcl_to_wbm_rbm_map; }; extern const struct hal_ops hal_qcn9274_ops; extern const struct hal_ops hal_wcn7850_ops; +extern const struct hal_rx_ops hal_rx_qcn9274_ops; +extern const struct hal_rx_ops hal_rx_wcn7850_ops; + u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, int tid, u32 ba_window_size, diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 7a0ed7c9f5a2..d334f41f9658 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1361,6 +1361,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = true; ab_pci->pci_ops = &ath12k_pci_ops_qcn9274; + ab->hal_rx_ops = &hal_rx_qcn9274_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { @@ -1383,6 +1384,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; + ab->hal_rx_ops = &hal_rx_wcn7850_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { From 3cf1a9f7a1b2823af5a57e277bbb7c730c8d737b Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:19 +0530 Subject: [PATCH 0606/2255] wifi: ath12k: remove hal_desc_sz from hw params With word mask subscription support, the rx_desc structure will change. The fields in this structure rx_desc will be reduced to only the required fields. To make word mask subscription changes compatible with the older firmware version (firmware that does not support word mask subscription), two different structures of rx_desc will be required for the same hardware. The hardware param hal_desc_sz value cannot be constant for the same hardware. It depends on the size of rx_desc structure which may change based on firmware capability to support word mask subscription. Hence, remove hal_desc_sz from hardware param and add hal_rx_ops to get the size of rx_desc in run time. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-9-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 2 ++ drivers/net/wireless/ath/ath12k/dp.c | 8 ++++++- drivers/net/wireless/ath/ath12k/dp.h | 3 ++- drivers/net/wireless/ath/ath12k/dp_mon.c | 2 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 30 ++++++++++++------------ drivers/net/wireless/ath/ath12k/hal.c | 12 ++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 3 +++ drivers/net/wireless/ath/ath12k/hw.c | 5 +--- drivers/net/wireless/ath/ath12k/hw.h | 1 - 9 files changed, 43 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 7f0b395f1296..ca3777c684b3 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -748,6 +748,8 @@ static int ath12k_core_start(struct ath12k_base *ab, goto err_mac_destroy; } + ath12k_dp_hal_rx_desc_init(ab); + ret = ath12k_wmi_cmd_init(ab); if (ret) { ath12k_err(ab, "failed to send wmi init cmd: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index a6f81f2f97ef..af800d60f3a2 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.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 @@ -997,6 +997,12 @@ void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab) } } +void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab) +{ + ab->hal.hal_desc_sz = + ab->hal_rx_ops->rx_desc_get_desc_size(); +} + static void ath12k_dp_service_mon_ring(struct timer_list *t) { struct ath12k_base *ab = from_timer(ab, t, mon_reap_timer); diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 0a10cd362356..226b95bd5ab0 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.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_DP_H @@ -1821,4 +1821,5 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie); struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, u32 desc_id); +void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 7aa55cf64e8b..2d56913a75d0 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -864,7 +864,7 @@ static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, struct sk_buff { u32 rx_pkt_offset, l2_hdr_offset; - rx_pkt_offset = ar->ab->hw_params->hal_desc_sz; + rx_pkt_offset = ar->ab->hal.hal_desc_sz; l2_hdr_offset = ath12k_dp_rx_h_l3pad(ar->ab, (struct hal_rx_desc *)msdu->data); skb_pull(msdu, rx_pkt_offset + l2_hdr_offset); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index d8816b38ccaa..10ea33fafff4 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -58,7 +58,7 @@ static bool ath12k_dp_rx_h_more_frags(struct ath12k_base *ab, { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); + hdr = (struct ieee80211_hdr *)(skb->data + ab->hal.hal_desc_sz); return ieee80211_has_morefrags(hdr->frame_control); } @@ -67,7 +67,7 @@ static u16 ath12k_dp_rx_h_frag_no(struct ath12k_base *ab, { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); + hdr = (struct ieee80211_hdr *)(skb->data + ab->hal.hal_desc_sz); return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; } @@ -1761,7 +1761,7 @@ static int ath12k_dp_rx_msdu_coalesce(struct ath12k *ar, int buf_first_hdr_len, buf_first_len; struct hal_rx_desc *ldesc; int space_extra, rem_len, buf_len; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; /* As the msdu is spread across multiple rx buffers, * find the offset to the start of msdu for computing @@ -2473,7 +2473,7 @@ static int ath12k_dp_rx_process_msdu(struct ath12k *ar, u8 l3_pad_bytes; u16 msdu_len; int ret; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; last_buf = ath12k_dp_rx_get_msdu_last_buf(msdu_list, msdu); if (!last_buf) { @@ -2804,7 +2804,7 @@ static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer u8 mic[IEEE80211_CCMP_MIC_LEN]; int head_len, tail_len, ret; size_t data_len; - u32 hdr_len, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hdr_len, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; u8 *key, *data; u8 key_idx; @@ -2854,7 +2854,7 @@ static void ath12k_dp_rx_h_undecap_frag(struct ath12k *ar, struct sk_buff *msdu, struct ieee80211_hdr *hdr; size_t hdr_len; size_t crypto_len; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; if (!flags) return; @@ -2892,7 +2892,7 @@ static int ath12k_dp_rx_h_defrag(struct ath12k *ar, bool is_decrypted = false; int msdu_len = 0; int extra_space; - u32 flags, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 flags, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; first_frag = skb_peek(&rx_tid->rx_frags); last_frag = skb_peek_tail(&rx_tid->rx_frags); @@ -2968,7 +2968,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, struct ath12k_rx_desc_info *desc_info; u8 dst_ind; - hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + hal_rx_desc_sz = ab->hal.hal_desc_sz; link_desc_banks = dp->link_desc_banks; reo_dest_ring = rx_tid->dst_ring_desc; @@ -3122,7 +3122,7 @@ static u64 ath12k_dp_rx_h_get_pn(struct ath12k *ar, struct sk_buff *skb) struct ieee80211_hdr *hdr; u64 pn = 0; u8 *ehdr; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz); ehdr = skb->data + hal_rx_desc_sz + ieee80211_hdrlen(hdr->frame_control); @@ -3305,7 +3305,7 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, struct ath12k_skb_rxcb *rxcb; struct hal_rx_desc *rx_desc; u16 msdu_len; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; struct ath12k_rx_desc_info *desc_info; u64 desc_va; @@ -3486,7 +3486,7 @@ static void ath12k_dp_rx_null_q_desc_sg_drop(struct ath12k *ar, int n_buffs; n_buffs = DIV_ROUND_UP(msdu_len, - (DP_RX_BUFFER_SIZE - ar->ab->hw_params->hal_desc_sz)); + (DP_RX_BUFFER_SIZE - ar->ab->hal.hal_desc_sz)); skb_queue_walk_safe(msdu_list, skb, tmp) { rxcb = ATH12K_SKB_RXCB(skb); @@ -3510,7 +3510,7 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu, struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; u8 l3pad_bytes; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); @@ -3607,7 +3607,7 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; u8 l3pad_bytes; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, desc); rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, desc); @@ -3922,7 +3922,7 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 ring_id; int ret; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; @@ -3957,7 +3957,7 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 ring_id; int ret; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; int i; ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index b6b8298a2bdc..fa1bfb5256d0 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -680,6 +680,11 @@ static u32 ath12k_hw_qcn9274_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } +static u32 ath12k_hw_qcn9274_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_qcn9274); +} + const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_rx_desc_get_last_msdu, @@ -717,6 +722,7 @@ const struct hal_rx_ops hal_rx_qcn9274_ops = { .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_ip_cksum_fail, .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_qcn9274_get_rx_desc_size, }; const struct hal_ops hal_qcn9274_ops = { @@ -1137,6 +1143,11 @@ static u32 ath12k_hw_wcn7850_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } +static u32 ath12k_hw_wcn7850_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_wcn7850); +} + const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, @@ -1175,6 +1186,7 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { .dp_rx_h_ip_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_ip_cksum_fail, .dp_rx_h_is_decrypted = ath12k_hw_wcn7850_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_wcn7850_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_wcn7850_get_rx_desc_size, }; const struct hal_ops hal_wcn7850_ops = { diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 33dedfbb3964..82517991510b 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1023,6 +1023,8 @@ struct ath12k_hal { /* shadow register configuration */ u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS]; int num_shadow_reg_configured; + + u32 hal_desc_sz; }; /* Maps WBM ring number and Return Buffer Manager Id per TCL ring */ @@ -1075,6 +1077,7 @@ struct hal_rx_ops { bool (*dp_rx_h_ip_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_is_decrypted)(struct hal_rx_desc *desc); u32 (*dp_rx_h_mpdu_err)(struct hal_rx_desc *desc); + u32 (*rx_desc_get_desc_size)(void); }; struct hal_ops { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index cbb6e2b6d826..f399511746a8 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.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 @@ -897,7 +897,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = false, - .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274), .num_tcl_banks = 48, .max_tx_ring = 4, @@ -963,7 +962,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = true, - .hal_desc_sz = sizeof(struct hal_rx_desc_wcn7850), .num_tcl_banks = 7, .max_tx_ring = 3, @@ -1029,7 +1027,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = false, - .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274), .num_tcl_banks = 48, .max_tx_ring = 4, diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index efa3411dc63d..987188f56b29 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -187,7 +187,6 @@ struct ath12k_hw_params { bool reoq_lut_support:1; bool supports_shadow_regs:1; - u32 hal_desc_sz; u32 num_tcl_banks; u32 max_tx_ring; From 419927ec8438e336f9dea183de9153da4e65dafc Mon Sep 17 00:00:00 2001 From: Karthikeyan Kathirvel Date: Mon, 29 Jan 2024 12:27:20 +0530 Subject: [PATCH 0607/2255] wifi: ath12k: subscribe required word mask from rx tlv Most of the RX descriptors fields are currently not used in the ath12k driver. Hence add support to selectively subscribe to the required quad words (64 bits) within msdu_end and mpdu_start of rx_desc. Add compact rx_desc structures and configure the bit mask for Rx TLVs (msdu_end, mpdu_start, mpdu_end) via registers. With these registers SW can configure to DMA the partial TLV struct to Rx buffer. Each TLV type has its own register to configure the mask value. The mask value configured in register will indicate if a particular QWORD has to be written to rx buffer or not i.e., if Nth bit is enabled in the mask Nth QWORD will be written and it will not be written if the bit is disabled in mask. While 0th bit indicates whether TLV tag will be written or not. Advantages of Qword subscription of TLVs - Avoid multiple cache-line misses as the all the required fields of the TLV are within 128 bytes. - Memory optimization as TLVs + DATA + SHINFO can fit in 2k buffer even for 64 bit kernel. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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 Kathirvel Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-10-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 17 + drivers/net/wireless/ath/ath12k/dp.h | 14 + drivers/net/wireless/ath/ath12k/dp_rx.c | 14 +- drivers/net/wireless/ath/ath12k/dp_tx.c | 20 ++ drivers/net/wireless/ath/ath12k/hal.c | 359 ++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 4 + drivers/net/wireless/ath/ath12k/rx_desc.h | 114 ++++++- drivers/net/wireless/ath/ath12k/wmi.h | 2 + 8 files changed, 535 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index af800d60f3a2..c8e1b244b69e 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -997,8 +997,25 @@ void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab) } } +bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab) +{ + if (test_bit(WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS, ab->wmi_ab.svc_map) && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end && + ab->hw_params->hal_ops->get_hal_rx_compact_ops) { + return true; + } + return false; +} + void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab) { + if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) { + /* RX TLVS compaction is supported, hence change the hal_rx_ops + * to compact hal_rx_ops. + */ + ab->hal_rx_ops = ab->hw_params->hal_ops->get_hal_rx_compact_ops(); + } ab->hal.hal_desc_sz = ab->hal_rx_ops->rx_desc_get_desc_size(); } diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 226b95bd5ab0..eb2dd408e081 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -766,6 +766,11 @@ enum htt_stats_internal_ppdu_frametype { #define HTT_RX_RING_SELECTION_CFG_RX_MSDU_START_OFFSET GENMASK(31, 16) #define HTT_RX_RING_SELECTION_CFG_RX_ATTENTION_OFFSET GENMASK(15, 0) +#define HTT_RX_RING_SELECTION_CFG_WORD_MASK_COMPACT_SET BIT(23) +#define HTT_RX_RING_SELECTION_CFG_RX_MPDU_START_MASK GENMASK(15, 0) +#define HTT_RX_RING_SELECTION_CFG_RX_MPDU_END_MASK GENMASK(18, 16) +#define HTT_RX_RING_SELECTION_CFG_RX_MSDU_END_MASK GENMASK(16, 0) + enum htt_rx_filter_tlv_flags { HTT_RX_FILTER_TLV_FLAGS_MPDU_START = BIT(0), HTT_RX_FILTER_TLV_FLAGS_MSDU_START = BIT(1), @@ -1089,6 +1094,11 @@ struct htt_rx_ring_selection_cfg_cmd { __le32 rx_mpdu_offset; __le32 rx_msdu_offset; __le32 rx_attn_offset; + __le32 info2; + __le32 reserved[2]; + __le32 rx_mpdu_start_end_mask; + __le32 rx_msdu_end_word_mask; + __le32 info3; } __packed; struct htt_rx_ring_tlv_filter { @@ -1105,6 +1115,9 @@ struct htt_rx_ring_tlv_filter { u16 rx_msdu_end_offset; u16 rx_msdu_start_offset; u16 rx_attn_offset; + u16 rx_mpdu_start_wmask; + u16 rx_mpdu_end_wmask; + u32 rx_msdu_end_wmask; }; #define HTT_STATS_FRAME_CTRL_TYPE_MGMT 0x0 @@ -1821,5 +1834,6 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie); struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, u32 desc_id); +bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab); void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 10ea33fafff4..5c2316e40019 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3939,10 +3939,16 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) tlv_filter.rx_msdu_end_offset = ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); - /* TODO: Selectively subscribe to required qwords within msdu_end - * and mpdu_start and setup the mask in below msg - * and modify the rx_desc struct - */ + if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) { + tlv_filter.rx_mpdu_start_wmask = + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start(); + tlv_filter.rx_msdu_end_wmask = + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end(); + ath12k_dbg(ab, ATH12K_DBG_DATA, + "Configuring compact tlv masks rx_mpdu_start_wmask 0x%x rx_msdu_end_wmask 0x%x\n", + tlv_filter.rx_mpdu_start_wmask, tlv_filter.rx_msdu_end_wmask); + } + ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, 0, HAL_RXDMA_BUF, DP_RXDMA_REFILL_RING_SIZE, diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index d4db94112deb..572b87153647 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -964,6 +964,26 @@ int ath12k_dp_tx_htt_rx_filter_setup(struct ath12k_base *ab, u32 ring_id, HTT_RX_RING_SELECTION_CFG_RX_ATTENTION_OFFSET); } + if (tlv_filter->rx_mpdu_start_wmask > 0 && + tlv_filter->rx_msdu_end_wmask > 0) { + cmd->info2 |= + le32_encode_bits(true, + HTT_RX_RING_SELECTION_CFG_WORD_MASK_COMPACT_SET); + cmd->rx_mpdu_start_end_mask = + le32_encode_bits(tlv_filter->rx_mpdu_start_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MPDU_START_MASK); + /* mpdu_end is not used for any hardwares so far + * please assign it in future if any chip is + * using through hal ops + */ + cmd->rx_mpdu_start_end_mask |= + le32_encode_bits(tlv_filter->rx_mpdu_end_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MPDU_END_MASK); + cmd->rx_msdu_end_word_mask = + le32_encode_bits(tlv_filter->rx_msdu_end_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MSDU_END_MASK); + } + ret = ath12k_htc_send(&ab->htc, ab->dp.eid, skb); if (ret) goto err_free; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index fa1bfb5256d0..cb540251acf8 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -626,6 +626,21 @@ static int ath12k_hal_srng_create_config_qcn9274(struct ath12k_base *ab) return 0; } +static u16 ath12k_hal_qcn9274_rx_mpdu_start_wmask_get(void) +{ + return QCN9274_MPDU_START_WMASK; +} + +static u32 ath12k_hal_qcn9274_rx_msdu_end_wmask_get(void) +{ + return QCN9274_MSDU_END_WMASK; +} + +static const struct hal_rx_ops *ath12k_hal_qcn9274_get_hal_rx_compact_ops(void) +{ + return &hal_rx_qcn9274_compact_ops; +} + static bool ath12k_hw_qcn9274_dp_rx_h_msdu_done(struct hal_rx_desc *desc) { return !!le32_get_bits(desc->u.qcn9274.msdu_end.info14, @@ -725,9 +740,350 @@ const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_desc_size = ath12k_hw_qcn9274_get_rx_desc_size, }; +static bool ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_FIRST_MSDU); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_LAST_MSDU); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_L3_HDR_PADDING); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_encrypt_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_ENCRYPT_INFO_VALID); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_encrypt_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info2, + RX_MPDU_START_INFO2_ENC_TYPE); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_decap_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info11, + RX_MSDU_END_INFO11_DECAP_FORMAT); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274.msdu_end.info11, + RX_MSDU_END_INFO11_MESH_CTRL_PRESENT); +} + +static bool +ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_CTRL_VALID); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_FCTRL_VALID); +} + +static u16 +ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_NUM); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_len(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info10, + RX_MSDU_END_INFO10_MSDU_LENGTH); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_SGI); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_RATE_MCS); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_RECV_BW); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_freq(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.phy_meta_data); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_PKT_TYPE); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_QCN9274_INFO5_TID); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.sw_peer_id); +} + +static void ath12k_hw_qcn9274_compact_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc, + struct hal_rx_desc *ldesc) +{ + fdesc->u.qcn9274_compact.msdu_end = ldesc->u.qcn9274_compact.msdu_end; +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.phy_ppdu_id); +} + +static void +ath12k_hw_qcn9274_compact_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len) +{ + u32 info = __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.info10); + + info = u32_replace_bits(info, len, RX_MSDU_END_INFO10_MSDU_LENGTH); + desc->u.qcn9274_compact.msdu_end.info10 = __cpu_to_le32(info); +} + +static u8 *ath12k_hw_qcn9274_compact_rx_desc_get_msdu_payload(struct hal_rx_desc *desc) +{ + return &desc->u.qcn9274_compact.msdu_payload[0]; +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_offset(void) +{ + return offsetof(struct hal_rx_desc_qcn9274_compact, mpdu_start); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_end_offset(void) +{ + return offsetof(struct hal_rx_desc_qcn9274_compact, msdu_end); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR2_VALID; +} + +static u8 *ath12k_hw_qcn9274_compact_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) +{ + return desc->u.qcn9274_compact.mpdu_start.addr2; +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info6) & + RX_MPDU_START_INFO6_MCAST_BCAST; +} + +static void ath12k_hw_qcn9274_compact_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, + struct ieee80211_hdr *hdr) +{ + hdr->frame_control = desc->u.qcn9274_compact.mpdu_start.frame_ctrl; + hdr->duration_id = desc->u.qcn9274_compact.mpdu_start.duration; + ether_addr_copy(hdr->addr1, desc->u.qcn9274_compact.mpdu_start.addr1); + ether_addr_copy(hdr->addr2, desc->u.qcn9274_compact.mpdu_start.addr2); + ether_addr_copy(hdr->addr3, desc->u.qcn9274_compact.mpdu_start.addr3); + if (__le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR4_VALID) { + ether_addr_copy(hdr->addr4, desc->u.qcn9274_compact.mpdu_start.addr4); + } + hdr->seq_ctrl = desc->u.qcn9274_compact.mpdu_start.seq_ctrl; +} + +static void +ath12k_hw_qcn9274_compact_rx_desc_get_crypto_hdr(struct hal_rx_desc *desc, + u8 *crypto_hdr, + enum hal_encrypt_type enctype) +{ + unsigned int key_id; + + switch (enctype) { + case HAL_ENCRYPT_TYPE_OPEN: + return; + case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: + case HAL_ENCRYPT_TYPE_TKIP_MIC: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[1] = 0; + crypto_hdr[2] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[0]); + break; + case HAL_ENCRYPT_TYPE_CCMP_128: + case HAL_ENCRYPT_TYPE_CCMP_256: + case HAL_ENCRYPT_TYPE_GCMP_128: + case HAL_ENCRYPT_TYPE_AES_GCMP_256: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[1] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[2] = 0; + break; + case HAL_ENCRYPT_TYPE_WEP_40: + case HAL_ENCRYPT_TYPE_WEP_104: + case HAL_ENCRYPT_TYPE_WEP_128: + case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: + case HAL_ENCRYPT_TYPE_WAPI: + return; + } + key_id = le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info5, + RX_MPDU_START_INFO5_KEY_ID); + crypto_hdr[3] = 0x20 | (key_id << 6); + crypto_hdr[4] = + HAL_RX_MPDU_INFO_PN_GET_BYTE3(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[5] = + HAL_RX_MPDU_INFO_PN_GET_BYTE4(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[6] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[1]); + crypto_hdr[7] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[1]); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_frame_ctl(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.frame_ctrl); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_msdu_done(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info14, + RX_MSDU_END_INFO14_MSDU_DONE); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_l4_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info13, + RX_MSDU_END_INFO13_TCP_UDP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_ip_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info13, + RX_MSDU_END_INFO13_IP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted(struct hal_rx_desc *desc) +{ + return (le32_get_bits(desc->u.qcn9274_compact.msdu_end.info14, + RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE) == + RX_DESC_DECRYPT_STATUS_CODE_OK); +} + +static u32 ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) +{ + u32 info = __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.info13); + u32 errmap = 0; + + if (info & RX_MSDU_END_INFO13_FCS_ERR) + errmap |= HAL_RX_MPDU_ERR_FCS; + + if (info & RX_MSDU_END_INFO13_DECRYPT_ERR) + errmap |= HAL_RX_MPDU_ERR_DECRYPT; + + if (info & RX_MSDU_END_INFO13_TKIP_MIC_ERR) + errmap |= HAL_RX_MPDU_ERR_TKIP_MIC; + + if (info & RX_MSDU_END_INFO13_A_MSDU_ERROR) + errmap |= HAL_RX_MPDU_ERR_AMSDU_ERR; + + if (info & RX_MSDU_END_INFO13_OVERFLOW_ERR) + errmap |= HAL_RX_MPDU_ERR_OVERFLOW; + + if (info & RX_MSDU_END_INFO13_MSDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MSDU_LEN; + + if (info & RX_MSDU_END_INFO13_MPDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MPDU_LEN; + + return errmap; +} + +static u32 ath12k_hw_qcn9274_compact_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_qcn9274_compact); +} + +const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { + .rx_desc_get_first_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu, + .rx_desc_get_last_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu, + .rx_desc_get_l3_pad_bytes = ath12k_hw_qcn9274_compact_rx_desc_get_l3_pad_bytes, + .rx_desc_encrypt_valid = ath12k_hw_qcn9274_compact_rx_desc_encrypt_valid, + .rx_desc_get_encrypt_type = ath12k_hw_qcn9274_compact_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath12k_hw_qcn9274_compact_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath12k_hw_qcn9274_compact_rx_desc_get_mesh_ctl, + .rx_desc_get_mpdu_seq_ctl_vld = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_seq_no, + .rx_desc_get_msdu_len = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_len, + .rx_desc_get_msdu_sgi = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_sgi, + .rx_desc_get_msdu_rate_mcs = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rate_mcs, + .rx_desc_get_msdu_rx_bw = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rx_bw, + .rx_desc_get_msdu_freq = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_freq, + .rx_desc_get_msdu_pkt_type = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type, + .rx_desc_get_msdu_nss = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss, + .rx_desc_get_mpdu_tid = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid, + .rx_desc_get_mpdu_peer_id = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id, + .rx_desc_copy_end_tlv = ath12k_hw_qcn9274_compact_rx_desc_copy_end_tlv, + .rx_desc_get_mpdu_ppdu_id = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_ppdu_id, + .rx_desc_set_msdu_len = ath12k_hw_qcn9274_compact_rx_desc_set_msdu_len, + .rx_desc_get_msdu_payload = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_payload, + .rx_desc_get_mpdu_start_offset = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_offset, + .rx_desc_get_msdu_end_offset = + ath12k_hw_qcn9274_compact_rx_desc_get_msdu_end_offset, + .rx_desc_mac_addr2_valid = ath12k_hw_qcn9274_compact_rx_desc_mac_addr2_valid, + .rx_desc_mpdu_start_addr2 = ath12k_hw_qcn9274_compact_rx_desc_mpdu_start_addr2, + .rx_desc_is_da_mcbc = ath12k_hw_qcn9274_compact_rx_desc_is_da_mcbc, + .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_compact_rx_desc_get_dot11_hdr, + .rx_desc_get_crypto_header = ath12k_hw_qcn9274_compact_rx_desc_get_crypto_hdr, + .rx_desc_get_mpdu_frame_ctl = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_frame_ctl, + .dp_rx_h_msdu_done = ath12k_hw_qcn9274_compact_dp_rx_h_msdu_done, + .dp_rx_h_l4_cksum_fail = ath12k_hw_qcn9274_compact_dp_rx_h_l4_cksum_fail, + .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_compact_dp_rx_h_ip_cksum_fail, + .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted, + .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_qcn9274_compact_get_rx_desc_size, +}; + const struct hal_ops hal_qcn9274_ops = { .create_srng_config = ath12k_hal_srng_create_config_qcn9274, .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, + .rxdma_ring_wmask_rx_mpdu_start = ath12k_hal_qcn9274_rx_mpdu_start_wmask_get, + .rxdma_ring_wmask_rx_msdu_end = ath12k_hal_qcn9274_rx_msdu_end_wmask_get, + .get_hal_rx_compact_ops = ath12k_hal_qcn9274_get_hal_rx_compact_ops, }; static bool ath12k_hw_wcn7850_rx_desc_get_first_msdu(struct hal_rx_desc *desc) @@ -1192,6 +1548,9 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { const struct hal_ops hal_wcn7850_ops = { .create_srng_config = ath12k_hal_srng_create_config_wcn7850, .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, + .rxdma_ring_wmask_rx_mpdu_start = NULL, + .rxdma_ring_wmask_rx_msdu_end = NULL, + .get_hal_rx_compact_ops = NULL, }; static int ath12k_hal_alloc_cont_rdp(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 82517991510b..b7d78ba2b801 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1082,6 +1082,9 @@ struct hal_rx_ops { struct hal_ops { int (*create_srng_config)(struct ath12k_base *ab); + u16 (*rxdma_ring_wmask_rx_mpdu_start)(void); + u32 (*rxdma_ring_wmask_rx_msdu_end)(void); + const struct hal_rx_ops *(*get_hal_rx_compact_ops)(void); const struct ath12k_hal_tcl_to_wbm_rbm_map *tcl_to_wbm_rbm_map; }; @@ -1089,6 +1092,7 @@ extern const struct hal_ops hal_qcn9274_ops; extern const struct hal_ops hal_wcn7850_ops; extern const struct hal_rx_ops hal_rx_qcn9274_ops; +extern const struct hal_rx_ops hal_rx_qcn9274_compact_ops; extern const struct hal_rx_ops hal_rx_wcn7850_ops; u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index 55f20c446ca9..d5fd3a3b6b4d 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.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_RX_DESC_H #define ATH12K_RX_DESC_H @@ -147,6 +147,61 @@ struct rx_mpdu_start_qcn9274 { __le32 res1; } __packed; +#define QCN9274_MPDU_START_SELECT_MPDU_START_TAG BIT(0) +#define QCN9274_MPDU_START_SELECT_INFO0_REO_QUEUE_DESC_LO BIT(1) +#define QCN9274_MPDU_START_SELECT_INFO1_PN_31_0 BIT(2) +#define QCN9274_MPDU_START_SELECT_PN_95_32 BIT(3) +#define QCN9274_MPDU_START_SELECT_PN_127_96_INFO2 BIT(4) +#define QCN9274_MPDU_START_SELECT_PEER_MDATA_INFO3_PHY_PPDU_ID BIT(5) +#define QCN9274_MPDU_START_SELECT_AST_IDX_SW_PEER_ID_INFO4 BIT(6) +#define QCN9274_MPDU_START_SELECT_INFO5_INFO6 BIT(7) +#define QCN9274_MPDU_START_SELECT_FRAME_CTRL_DURATION_ADDR1_31_0 BIT(8) +#define QCN9274_MPDU_START_SELECT_ADDR2_47_0_ADDR1_47_32 BIT(9) +#define QCN9274_MPDU_START_SELECT_ADDR3_47_0_SEQ_CTRL BIT(10) +#define QCN9274_MPDU_START_SELECT_ADDR4_47_0_QOS_CTRL BIT(11) +#define QCN9274_MPDU_START_SELECT_HT_CTRL_INFO7 BIT(12) +#define QCN9274_MPDU_START_SELECT_ML_ADDR1_47_0_ML_ADDR2_15_0 BIT(13) +#define QCN9274_MPDU_START_SELECT_ML_ADDR2_47_16_INFO8 BIT(14) +#define QCN9274_MPDU_START_SELECT_RES_0_RES_1 BIT(15) + +#define QCN9274_MPDU_START_WMASK (QCN9274_MPDU_START_SELECT_INFO1_PN_31_0 | \ + QCN9274_MPDU_START_SELECT_PN_95_32 | \ + QCN9274_MPDU_START_SELECT_PN_127_96_INFO2 | \ + QCN9274_MPDU_START_SELECT_PEER_MDATA_INFO3_PHY_PPDU_ID | \ + QCN9274_MPDU_START_SELECT_AST_IDX_SW_PEER_ID_INFO4 | \ + QCN9274_MPDU_START_SELECT_INFO5_INFO6 | \ + QCN9274_MPDU_START_SELECT_FRAME_CTRL_DURATION_ADDR1_31_0 | \ + QCN9274_MPDU_START_SELECT_ADDR2_47_0_ADDR1_47_32 | \ + QCN9274_MPDU_START_SELECT_ADDR3_47_0_SEQ_CTRL | \ + QCN9274_MPDU_START_SELECT_ADDR4_47_0_QOS_CTRL) + +/* The below rx_mpdu_start_qcn9274_compact structure is tied with the mask + * value QCN9274_MPDU_START_WMASK. If the mask value changes the structure + * will also change. + */ + +struct rx_mpdu_start_qcn9274_compact { + __le32 info1; + __le32 pn[4]; + __le32 info2; + __le32 peer_meta_data; + __le16 info3; + __le16 phy_ppdu_id; + __le16 ast_index; + __le16 sw_peer_id; + __le32 info4; + __le32 info5; + __le32 info6; + __le16 frame_ctrl; + __le16 duration; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctrl; + u8 addr4[ETH_ALEN]; + __le16 qos_ctrl; +} __packed; + /* rx_mpdu_start * * reo_destination_indication @@ -786,6 +841,52 @@ struct rx_msdu_end_qcn9274 { __le32 info14; } __packed; +#define QCN9274_MSDU_END_SELECT_MSDU_END_TAG BIT(0) +#define QCN9274_MSDU_END_SELECT_INFO0_PHY_PPDUID_IP_HDR_CSUM_INFO1 BIT(1) +#define QCN9274_MSDU_END_SELECT_INFO2_CUMULATIVE_CSUM_RULE_IND_0 BIT(2) +#define QCN9274_MSDU_END_SELECT_IPV6_OP_CRC_INFO3_TYPE13 BIT(3) +#define QCN9274_MSDU_END_SELECT_RULE_IND_1_TCP_SEQ_NUM BIT(4) +#define QCN9274_MSDU_END_SELECT_TCP_ACK_NUM_INFO4_WINDOW_SIZE BIT(5) +#define QCN9274_MSDU_END_SELECT_SA_SW_PER_ID_INFO5_SA_DA_ID BIT(6) +#define QCN9274_MSDU_END_SELECT_INFO6_FSE_METADATA BIT(7) +#define QCN9274_MSDU_END_SELECT_CCE_MDATA_TCP_UDP_CSUM_INFO7_IP_LEN BIT(8) +#define QCN9274_MSDU_END_SELECT_INFO8_INFO9 BIT(9) +#define QCN9274_MSDU_END_SELECT_INFO10_INFO11 BIT(10) +#define QCN9274_MSDU_END_SELECT_VLAN_CTAG_STAG_CI_PEER_MDATA BIT(11) +#define QCN9274_MSDU_END_SELECT_INFO12_AND_FLOW_ID_TOEPLITZ BIT(12) +#define QCN9274_MSDU_END_SELECT_PPDU_START_TS_63_32_PHY_MDATA BIT(13) +#define QCN9274_MSDU_END_SELECT_PPDU_START_TS_31_0_TOEPLITZ_HASH_2_4 BIT(14) +#define QCN9274_MSDU_END_SELECT_RES0_SA_47_0 BIT(15) +#define QCN9274_MSDU_END_SELECT_INFO13_INFO14 BIT(16) + +#define QCN9274_MSDU_END_WMASK (QCN9274_MSDU_END_SELECT_MSDU_END_TAG | \ + QCN9274_MSDU_END_SELECT_SA_SW_PER_ID_INFO5_SA_DA_ID | \ + QCN9274_MSDU_END_SELECT_INFO10_INFO11 | \ + QCN9274_MSDU_END_SELECT_INFO12_AND_FLOW_ID_TOEPLITZ | \ + QCN9274_MSDU_END_SELECT_PPDU_START_TS_63_32_PHY_MDATA | \ + QCN9274_MSDU_END_SELECT_INFO13_INFO14) + +/* The below rx_msdu_end_qcn9274_compact structure is tied with the mask value + * QCN9274_MSDU_END_WMASK. If the mask value changes the structure will also + * change. + */ + +struct rx_msdu_end_qcn9274_compact { + __le64 msdu_end_tag; + __le16 sa_sw_peer_id; + __le16 info5; + __le16 sa_idx; + __le16 da_idx_or_sw_peer_id; + __le32 info10; + __le32 info11; + __le32 info12; + __le32 flow_id_toeplitz; + __le32 ppdu_start_timestamp_63_32; + __le32 phy_meta_data; + __le32 info13; + __le32 info14; +} __packed; + /* These macro definitions are only used for WCN7850 */ #define RX_MSDU_END_WCN7850_INFO2_KEY_ID BIT(7, 0) @@ -1450,16 +1551,18 @@ struct rx_msdu_end_wcn7850 { * */ -/* TODO: Move to compact TLV approach - * By default these tlv's are not aligned to 128b boundary - * Need to remove unused qwords and make them compact/aligned - */ struct hal_rx_desc_qcn9274 { struct rx_msdu_end_qcn9274 msdu_end; struct rx_mpdu_start_qcn9274 mpdu_start; u8 msdu_payload[]; } __packed; +struct hal_rx_desc_qcn9274_compact { + struct rx_msdu_end_qcn9274_compact msdu_end; + struct rx_mpdu_start_qcn9274_compact mpdu_start; + u8 msdu_payload[]; +} __packed; + #define RX_BE_PADDING0_BYTES 8 #define RX_BE_PADDING1_BYTES 8 @@ -1484,6 +1587,7 @@ struct hal_rx_desc_wcn7850 { struct hal_rx_desc { union { struct hal_rx_desc_qcn9274 qcn9274; + struct hal_rx_desc_qcn9274_compact qcn9274_compact; struct hal_rx_desc_wcn7850 wcn7850; } u; } __packed; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 7443831d62d8..d740701809c2 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2163,6 +2163,8 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_11BE = 289, + WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361, + WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, WMI_MAX_EXT2_SERVICE, From 57c8b5c332e587cceec5d6bde57146edc2f4af87 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 29 Jan 2024 12:27:21 +0530 Subject: [PATCH 0608/2255] wifi: ath12k: add MAC id support in WBM error path When more than one pdev is supported in the chip/SoC, the packet belonging to second pdev is given to first pdev due to not identifying the MAC id in the WBM error path. So ping fails. In WBM error path, src link id information not available in the descriptor. So get this information from the msdu_end 64bit tag. It is necessary to get the src link id to identify the MAC id in the given chip. Then only we can pass the skb to the corresponding pdev. The msdu_end 64bit tag is available only if compact Rx TLVs descriptors are used. Thus, src link id is fetched correctly in WBM error path when compact descriptors are in use. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-11-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 42 ++++++++++++----------- drivers/net/wireless/ath/ath12k/hal.c | 20 +++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 1 + drivers/net/wireless/ath/ath12k/rx_desc.h | 2 ++ 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 5c2316e40019..ca76c018dd0c 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -233,6 +233,12 @@ static u16 ath12k_dp_rxdesc_get_mpdu_frame_ctrl(struct ath12k_base *ab, return ab->hal_rx_ops->rx_desc_get_mpdu_frame_ctl(desc); } +static inline u8 ath12k_dp_rx_get_msdu_src_link(struct ath12k_base *ab, + struct hal_rx_desc *desc) +{ + return ab->hal_rx_ops->rx_desc_get_msdu_src_link_id(desc); +} + static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) { int i, reaped = 0; @@ -3695,16 +3701,15 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, struct hal_rx_wbm_rel_info err_info; struct hal_srng *srng; struct sk_buff *msdu; - struct sk_buff_head msdu_list[MAX_RADIOS]; + struct sk_buff_head msdu_list; struct ath12k_skb_rxcb *rxcb; void *rx_desc; - int mac_id; + u8 mac_id; int num_buffs_reaped = 0; struct ath12k_rx_desc_info *desc_info; - int ret, i; + int ret, pdev_id; - for (i = 0; i < ab->num_radios; i++) - __skb_queue_head_init(&msdu_list[i]); + __skb_queue_head_init(&msdu_list); srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; rx_ring = &dp->rx_refill_buf_ring; @@ -3737,11 +3742,6 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, } } - /* FIXME: Extract mac id correctly. Since descs are not tied - * to mac, we can extract from vdev id in ring desc. - */ - mac_id = 0; - if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) ath12k_warn(ab, "WBM RX err, Check HW CC implementation"); @@ -3771,7 +3771,8 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, rxcb->err_rel_src = err_info.err_rel_src; rxcb->err_code = err_info.err_code; rxcb->rx_desc = (struct hal_rx_desc *)msdu->data; - __skb_queue_tail(&msdu_list[mac_id], msdu); + + __skb_queue_tail(&msdu_list, msdu); rxcb->is_first_msdu = err_info.first_msdu; rxcb->is_last_msdu = err_info.last_msdu; @@ -3788,21 +3789,22 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); rcu_read_lock(); - for (i = 0; i < ab->num_radios; i++) { - if (!rcu_dereference(ab->pdevs_active[i])) { - __skb_queue_purge(&msdu_list[i]); + while ((msdu = __skb_dequeue(&msdu_list))) { + mac_id = ath12k_dp_rx_get_msdu_src_link(ab, + (struct hal_rx_desc *)msdu->data); + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + ar = ab->pdevs[pdev_id].ar; + + if (!ar || !rcu_dereference(ar->ab->pdevs_active[mac_id])) { + dev_kfree_skb_any(msdu); continue; } - ar = ab->pdevs[i].ar; - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { - __skb_queue_purge(&msdu_list[i]); + dev_kfree_skb_any(msdu); continue; } - - while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL) - ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]); + ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list); } rcu_read_unlock(); done: diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index cb540251acf8..78310da8cfe8 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -700,6 +700,11 @@ static u32 ath12k_hw_qcn9274_get_rx_desc_size(void) return sizeof(struct hal_rx_desc_qcn9274); } +static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return 0; +} + const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_rx_desc_get_last_msdu, @@ -738,6 +743,7 @@ const struct hal_rx_ops hal_rx_qcn9274_ops = { .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_dp_rx_h_mpdu_err, .rx_desc_get_desc_size = ath12k_hw_qcn9274_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = ath12k_hw_qcn9274_rx_desc_get_msdu_src_link, }; static bool ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu(struct hal_rx_desc *desc) @@ -1033,6 +1039,12 @@ static u32 ath12k_hw_qcn9274_compact_get_rx_desc_size(void) return sizeof(struct hal_rx_desc_qcn9274_compact); } +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return le64_get_bits(desc->u.qcn9274_compact.msdu_end.msdu_end_tag, + RX_MSDU_END_64_TLV_SRC_LINK_ID); +} + const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu, @@ -1076,6 +1088,8 @@ const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err, .rx_desc_get_desc_size = ath12k_hw_qcn9274_compact_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = + ath12k_hw_qcn9274_compact_rx_desc_get_msdu_src_link, }; const struct hal_ops hal_qcn9274_ops = { @@ -1504,6 +1518,11 @@ static u32 ath12k_hw_wcn7850_get_rx_desc_size(void) return sizeof(struct hal_rx_desc_wcn7850); } +static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return 0; +} + const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, @@ -1543,6 +1562,7 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { .dp_rx_h_is_decrypted = ath12k_hw_wcn7850_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_wcn7850_dp_rx_h_mpdu_err, .rx_desc_get_desc_size = ath12k_hw_wcn7850_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = ath12k_hw_wcn7850_rx_desc_get_msdu_src_link, }; const struct hal_ops hal_wcn7850_ops = { diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index b7d78ba2b801..107927d64bbb 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1078,6 +1078,7 @@ struct hal_rx_ops { bool (*dp_rx_h_is_decrypted)(struct hal_rx_desc *desc); u32 (*dp_rx_h_mpdu_err)(struct hal_rx_desc *desc); u32 (*rx_desc_get_desc_size)(void); + u8 (*rx_desc_get_msdu_src_link_id)(struct hal_rx_desc *desc); }; struct hal_ops { diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index d5fd3a3b6b4d..a0db6702a189 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.h @@ -663,6 +663,8 @@ enum rx_msdu_start_reception_type { RX_MSDU_START_RECEPTION_TYPE_UL_MU_OFDMA_MIMO, }; +#define RX_MSDU_END_64_TLV_SRC_LINK_ID GENMASK(24, 22) + #define RX_MSDU_END_INFO0_RXPCU_MPDU_FITLER GENMASK(1, 0) #define RX_MSDU_END_INFO0_SW_FRAME_GRP_ID GENMASK(8, 2) From afeee629e72eeed719eb3f2918d7c8f3ae33497f Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Mon, 29 Jan 2024 12:27:22 +0530 Subject: [PATCH 0609/2255] wifi: ath12k: fix PCI read and write Currently, PCI read is failing for the registers belonging to SECURITY_CONTROL_WLAN registers. These registers read is required to read the board-id to identify the dual-mac QCN9274 hardware. The failure is because, for these registers (SECURITY_CONTROL_WLAN) offset, ath12k_pci_get_window_start() returns window_start as 0. Due to this PCI read is done without PCI select window and with window_start offset as 0. Hence, fix PCI read and write by doing PCI select window and by using the correct window_start offset - WINDOW_START for SECURITY_CONTROL_WLAN registers. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: P Praneesh Co-developed-by: Karthikeyan Periyasamy Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-12-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 43 ++++++++++++++------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index d334f41f9658..14954bc05144 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -205,18 +205,17 @@ static u32 ath12k_pci_get_window_start(struct ath12k_base *ab, /* If offset lies within CE register range, use 2nd window */ else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) window_start = 2 * WINDOW_START; - /* If offset lies within PCI_BAR_WINDOW0_BASE and within PCI_SOC_PCI_REG_BASE - * use 0th window - */ - else if (((offset ^ PCI_BAR_WINDOW0_BASE) < WINDOW_RANGE_MASK) && - !((offset ^ PCI_SOC_PCI_REG_BASE) < PCI_SOC_RANGE_MASK)) - window_start = 0; else window_start = WINDOW_START; return window_start; } +static inline bool ath12k_pci_is_offset_within_mhi_region(u32 offset) +{ + return (offset >= PCI_MHIREGLEN_REG && offset <= PCI_MHI_REGION_END); +} + static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) { u32 val, delay; @@ -1172,15 +1171,17 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset) if (window_start == WINDOW_START) { spin_lock_bh(&ab_pci->window_lock); ath12k_pci_select_window(ab_pci, offset); - val = ioread32(ab->mem + window_start + - (offset & WINDOW_RANGE_MASK)); + + if (ath12k_pci_is_offset_within_mhi_region(offset)) { + offset = offset - PCI_MHIREGLEN_REG; + val = ioread32(ab->mem + + (offset & WINDOW_RANGE_MASK)); + } else { + val = ioread32(ab->mem + window_start + + (offset & WINDOW_RANGE_MASK)); + } spin_unlock_bh(&ab_pci->window_lock); } else { - if ((!window_start) && - (offset >= PCI_MHIREGLEN_REG && - offset <= PCI_MHI_REGION_END)) - offset = offset - PCI_MHIREGLEN_REG; - val = ioread32(ab->mem + window_start + (offset & WINDOW_RANGE_MASK)); } @@ -1217,15 +1218,17 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value) if (window_start == WINDOW_START) { spin_lock_bh(&ab_pci->window_lock); ath12k_pci_select_window(ab_pci, offset); - iowrite32(value, ab->mem + window_start + - (offset & WINDOW_RANGE_MASK)); + + if (ath12k_pci_is_offset_within_mhi_region(offset)) { + offset = offset - PCI_MHIREGLEN_REG; + iowrite32(value, ab->mem + + (offset & WINDOW_RANGE_MASK)); + } else { + iowrite32(value, ab->mem + window_start + + (offset & WINDOW_RANGE_MASK)); + } spin_unlock_bh(&ab_pci->window_lock); } else { - if ((!window_start) && - (offset >= PCI_MHIREGLEN_REG && - offset <= PCI_MHI_REGION_END)) - offset = offset - PCI_MHIREGLEN_REG; - iowrite32(value, ab->mem + window_start + (offset & WINDOW_RANGE_MASK)); } From af9bc78d14fbe77db6e7526efaced162060f27bc Mon Sep 17 00:00:00 2001 From: Ganesh Babu Jothiram Date: Mon, 29 Jan 2024 12:27:23 +0530 Subject: [PATCH 0610/2255] wifi: ath12k: Read board id to support split-PHY QCN9274 QCN9274 can support single-PHY or split-PHY architecture. Currently, only the single-PHY architecture is supported in ath12k. The split-PHY QCN9274 requires different AMSS firmware binary "amss_dualmac.bin". Hence, add support to read board id from OTP. Based on board id decide whether single-mac / dual-mac firmware needs to be downloaded to the target. Also, update HW param max_radios to support split-PHY in QCN9274. Also, add new Firmware IE for firmware_N.bin "ATH11K_FW_IE_AMSS_DUALMAC_IMAGE" to support dualmac QCN9274. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 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: Ganesh Babu Jothiram Co-developed-by: Raj Kumar Bhagat Signed-off-by: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-13-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 ++ drivers/net/wireless/ath/ath12k/fw.c | 7 ++++ drivers/net/wireless/ath/ath12k/fw.h | 1 + drivers/net/wireless/ath/ath12k/hw.c | 8 ++++- drivers/net/wireless/ath/ath12k/hw.h | 2 ++ drivers/net/wireless/ath/ath12k/mac.c | 3 +- drivers/net/wireless/ath/ath12k/mhi.c | 49 +++++++++++++++++++++----- drivers/net/wireless/ath/ath12k/pci.h | 3 ++ 8 files changed, 64 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 67bf8d840b00..f0a319ea57c1 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -832,6 +832,8 @@ struct ath12k_base { const struct firmware *fw; const u8 *amss_data; size_t amss_len; + const u8 *amss_dualmac_data; + size_t amss_dualmac_len; const u8 *m3_data; size_t m3_len; diff --git a/drivers/net/wireless/ath/ath12k/fw.c b/drivers/net/wireless/ath/ath12k/fw.c index fbcf40c97792..5be4b2d4a19d 100644 --- a/drivers/net/wireless/ath/ath12k/fw.c +++ b/drivers/net/wireless/ath/ath12k/fw.c @@ -119,6 +119,13 @@ static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab, ab->fw.m3_data = data; ab->fw.m3_len = ie_len; break; + case ATH12K_FW_IE_AMSS_DUALMAC_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found dualmac fw image ie (%zd B)\n", + ie_len); + ab->fw.amss_dualmac_data = data; + ab->fw.amss_dualmac_len = ie_len; + break; default: ath12k_warn(ab, "Unknown FW IE: %u\n", ie_id); break; diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h index 28dc1423df70..3ff041f15fa0 100644 --- a/drivers/net/wireless/ath/ath12k/fw.h +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -14,6 +14,7 @@ enum ath12k_fw_ie_type { ATH12K_FW_IE_FEATURES = 1, ATH12K_FW_IE_AMSS_IMAGE = 2, ATH12K_FW_IE_M3_IMAGE = 3, + ATH12K_FW_IE_AMSS_DUALMAC_IMAGE = 4, }; enum ath12k_fw_features { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index f399511746a8..a9adb547c83d 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -916,6 +916,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .def_num_link = 0, .max_mlo_peer = 256, + + .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, }, { .name = "wcn7850 hw2.0", @@ -982,6 +984,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .def_num_link = 2, .max_mlo_peer = 32, + + .otp_board_id_register = 0, }, { .name = "qcn9274 hw2.0", @@ -991,7 +995,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, }, - .max_radios = 1, + .max_radios = 2, .single_pdev_only = false, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9274, .internal_sleep_clock = false, @@ -1046,6 +1050,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .def_num_link = 0, .max_mlo_peer = 256, + + .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 987188f56b29..2e9c3b05d75a 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -207,6 +207,8 @@ struct ath12k_hw_params { u8 def_num_link; u16 max_mlo_peer; + + u32 otp_board_id_register; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 046bb466a391..6ef55876e7df 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -563,7 +563,8 @@ struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, for (i = 0; i < ab->num_radios; i++) { pdev = rcu_dereference(ab->pdevs_active[i]); - if (pdev && pdev->ar) { + if (pdev && pdev->ar && + (pdev->ar->allocated_vdev_map & (1LL << vdev_id))) { arvif = ath12k_mac_get_arvif(pdev->ar, vdev_id); if (arvif) return arvif; diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index b7b31978a434..50b9e44504f7 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -14,6 +14,8 @@ #include "pci.h" #define MHI_TIMEOUT_DEFAULT_MS 90000 +#define OTP_INVALID_BOARD_ID 0xFFFF +#define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000 static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = { { @@ -359,7 +361,9 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) { struct ath12k_base *ab = ab_pci->ab; struct mhi_controller *mhi_ctrl; + unsigned int board_id; int ret; + bool dualmac = false; mhi_ctrl = mhi_alloc_controller(); if (!mhi_ctrl) @@ -371,16 +375,43 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) mhi_ctrl->reg_len = ab->mem_len; mhi_ctrl->rddm_size = ab->hw_params->rddm_size; - if (ab->fw.amss_data && ab->fw.amss_len > 0) { - /* use MHI firmware file from firmware-N.bin */ - mhi_ctrl->fw_data = ab->fw.amss_data; - mhi_ctrl->fw_sz = ab->fw.amss_len; + if (ab->hw_params->otp_board_id_register) { + board_id = + ath12k_pci_read32(ab, ab->hw_params->otp_board_id_register); + board_id = u32_get_bits(board_id, OTP_BOARD_ID_MASK); + + if (!board_id || (board_id == OTP_INVALID_BOARD_ID)) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to read board id\n"); + } else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) { + dualmac = true; + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "dualmac fw selected for board id: %x\n", board_id); + } + } + + if (dualmac) { + if (ab->fw.amss_dualmac_data && ab->fw.amss_dualmac_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_dualmac_data; + mhi_ctrl->fw_sz = ab->fw.amss_dualmac_len; + } else { + ath12k_warn(ab, "dualmac firmware IE not present in firmware-N.bin\n"); + ret = -ENOENT; + goto free_controller; + } } else { - /* use the old separate mhi.bin MHI firmware file */ - ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, - ab_pci->amss_path, - sizeof(ab_pci->amss_path)); - mhi_ctrl->fw_image = ab_pci->amss_path; + if (ab->fw.amss_data && ab->fw.amss_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_data; + mhi_ctrl->fw_sz = ab->fw.amss_len; + } else { + /* use the old separate mhi.bin MHI firmware file */ + ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, + ab_pci->amss_path, + sizeof(ab_pci->amss_path)); + mhi_ctrl->fw_image = ab_pci->amss_path; + } } ret = ath12k_mhi_get_msi(ab_pci); diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 023616928f03..ca93693ba4e9 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -53,6 +53,9 @@ #define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c #define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 +#define QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB 0x1E20338 +#define OTP_BOARD_ID_MASK GENMASK(15, 0) + #define PCI_BAR_WINDOW0_BASE 0x1E00000 #define PCI_BAR_WINDOW0_END 0x1E7FFFC #define PCI_SOC_RANGE_MASK 0x3FFF From 2d3a7384b9c8ea0b640747176cc01af64cf722ec Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Mon, 29 Jan 2024 12:27:24 +0530 Subject: [PATCH 0611/2255] wifi: ath12k: disable QMI PHY capability learn in split-phy QCN9274 QMI PHY capability learn is used to get PHY count information to support single/multi link operation (SLO/MLO) configuration. The QCN9274 dualmac firmware currently do not support SLO/MLO, if two PHYs are within the same chip. Due to this firmware crashes in split-phy QCN9274, while bringing up AP with MLO parameter enabled in QMI host capability request message. The QMI PHY capability learn is not required for split-phy QCN9274, if SLO/MLO is not supported within the same chip. Hence, disable QMI PHY capability learn support in split-phy QCN9274. 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: Raj Kumar Bhagat Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240129065724.2310207-14-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/core.h | 5 +++++ drivers/net/wireless/ath/ath12k/mhi.c | 1 + drivers/net/wireless/ath/ath12k/qmi.c | 3 +++ 4 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index ca3777c684b3..0d4640ff8d6f 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1218,6 +1218,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; + ab->slo_capable = true; return ab; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index f0a319ea57c1..a984171e4a08 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -842,6 +842,11 @@ struct ath12k_base { const struct hal_rx_ops *hal_rx_ops; + /* slo_capable denotes if the single/multi link operation + * is supported within the same chip (SoC). + */ + bool slo_capable; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index 50b9e44504f7..adb8c3ec1950 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -385,6 +385,7 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) "failed to read board id\n"); } else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) { dualmac = true; + ab->slo_capable = false; ath12k_dbg(ab, ATH12K_DBG_BOOT, "dualmac fw selected for board id: %x\n", board_id); } diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 0f0eaadc8418..92845ffff44a 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2124,6 +2124,9 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab) struct qmi_txn txn; int ret; + if (!ab->slo_capable) + goto out; + ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_phy_cap_resp_msg_v01_ei, &resp); if (ret < 0) From 2f92b22beef74a4051ee04dba390b59080ad85e2 Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Mon, 22 Jan 2024 03:53:35 -0500 Subject: [PATCH 0612/2255] wifi: ath12k: add processing for TWT enable event When ath12k send TWT enable command to firmware, firmware will return a TWT enable event to ath12k. Through the analysis of TWT enable event status, we can easily obtain the status of TWT enable command. It can be more convenient to debug TWT. This patch works with 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: Lingbo Kong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240122085336.3985-2-quic_lingbok@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 35 ++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 5 ++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7fc269eb4a0c..7d65dff7ab1e 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -162,6 +162,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, + [WMI_TAG_TWT_ENABLE_COMPLETE_EVENT] = { + .min_len = sizeof(struct wmi_twt_enable_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -6669,6 +6671,35 @@ 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_twt_enable_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_twt_enable_event *ev; + int ret; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse wmi twt enable status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_TWT_ENABLE_COMPLETE_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch twt enable wmi event\n"); + goto exit; + } + + ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt enable event pdev id %u status %u\n", + le32_to_cpu(ev->pdev_id), + le32_to_cpu(ev->status)); + +exit: + kfree(tb); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -6764,10 +6795,12 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_RFKILL_STATE_CHANGE_EVENTID: ath12k_rfkill_state_change_event(ab, skb); break; + case WMI_TWT_ENABLE_EVENTID: + ath12k_wmi_twt_enable_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: - case WMI_TWT_ENABLE_EVENTID: case WMI_TWT_DISABLE_EVENTID: case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ath12k_dbg(ab, ATH12K_DBG_WMI, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index d740701809c2..0819f16b09f6 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4809,6 +4809,11 @@ struct wmi_rfkill_state_change_event { __le32 radio_state; } __packed; +struct wmi_twt_enable_event { + __le32 pdev_id; + __le32 status; +} __packed; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, From ad2b29ad94c3ed9e39f2eae50915c0f34af4f6fc Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Mon, 22 Jan 2024 03:53:36 -0500 Subject: [PATCH 0613/2255] wifi: ath12k: add processing for TWT disable event When ath12k send TWT disable command to firmware, firmware will return a TWT disable event to ath12k. Through the analysis of TWT disable event status, we can easily obtain the status of TWT disable command. It can be more convenient to debug TWT. This patch works with 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: Lingbo Kong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240122085336.3985-3-quic_lingbok@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 35 ++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 5 ++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7d65dff7ab1e..5acbed4f64f2 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -164,6 +164,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, [WMI_TAG_TWT_ENABLE_COMPLETE_EVENT] = { .min_len = sizeof(struct wmi_twt_enable_event) }, + [WMI_TAG_TWT_DISABLE_COMPLETE_EVENT] = { + .min_len = sizeof(struct wmi_twt_disable_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -6700,6 +6702,35 @@ exit: kfree(tb); } +static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_twt_disable_event *ev; + int ret; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse wmi twt disable status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_TWT_DISABLE_COMPLETE_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch twt disable wmi event\n"); + goto exit; + } + + ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt disable event pdev id %d status %u\n", + le32_to_cpu(ev->pdev_id), + le32_to_cpu(ev->status)); + +exit: + kfree(tb); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -6798,10 +6829,12 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_TWT_ENABLE_EVENTID: ath12k_wmi_twt_enable_event(ab, skb); break; + case WMI_TWT_DISABLE_EVENTID: + ath12k_wmi_twt_disable_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: - case WMI_TWT_DISABLE_EVENTID: case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ath12k_dbg(ab, ATH12K_DBG_WMI, "ignoring unsupported event 0x%x\n", id); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 0819f16b09f6..dceb55ca153a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4814,6 +4814,11 @@ struct wmi_twt_enable_event { __le32 status; } __packed; +struct wmi_twt_disable_event { + __le32 pdev_id; + __le32 status; +} __packed; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, From e7c7fbb582bc7936cf7ee744f62b82bd46a7d4a8 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 25 Jan 2024 21:15:55 +0530 Subject: [PATCH 0614/2255] wifi: ath12k: refactor the rfkill worker Currently, the rfkill worker handler access mac80211 HW from the radio/link structure. This is will be incorrect for single wiphy model, as they will hold multiple link/radio structures. To fix this, access mac80211 HW based on the number of hardware in the SoC/chip. This approach makes the rfkill worker handler compatible with both multi wiphy and single wiphy models. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240125154555.3169706-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 0d4640ff8d6f..b82550b35149 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -909,21 +909,29 @@ 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 ath12k_hw *ah; struct ieee80211_hw *hw; bool rfkill_radio_on; - int i; + int i, j; spin_lock_bh(&ab->base_lock); rfkill_radio_on = ab->rfkill_radio_on; spin_unlock_bh(&ab->base_lock); - for (i = 0; i < ab->num_radios; i++) { - ar = ab->pdevs[i].ar; - if (!ar) + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; + if (!ah) continue; - hw = ath12k_ar_to_hw(ar); - ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); + for (j = 0; j < ah->num_radio; j++) { + ar = &ah->radio[j]; + if (!ar) + continue; + + ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); + } + + hw = ah->hw; wiphy_rfkill_set_hw_state(hw->wiphy, !rfkill_radio_on); } } From 10159a45666bf127afe8d7c654351d542e7fcb42 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 22:56:32 +0200 Subject: [PATCH 0615/2255] 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 --- .../net/wireless/intel/iwlwifi/fw/api/coex.h | 14 +- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 124 ++++++++++++++++++ .../wireless/intel/iwlwifi/mvm/constants.h | 3 + .../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(-) 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; - return hweight16(desired_links) <= iwl_mvm_max_active_links(mvm, vif); + if (n_links <= 1) + return true; + + 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 */ From 619a900f279800876e425ce4ef41c4e493bdf7d4 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 31 Jan 2024 23:08:16 +0200 Subject: [PATCH 0616/2255] 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 --- .../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(-) 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); From 91380f768d7f6e3d003755defa792e9a00a1444a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:48 +0200 Subject: [PATCH 0617/2255] 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(-) 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; } From 7255263962ae6a41c73e44fb3520072ef74492a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:49 +0200 Subject: [PATCH 0618/2255] 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(-) 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) From 8a41c017409198dd4de5a4c522cd5ae4810a5911 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:50 +0200 Subject: [PATCH 0619/2255] 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 +++++++++------ .../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(-) 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) { From 2f72c759fdd413bbfd8888af8e31312b34d2be33 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:51 +0200 Subject: [PATCH 0620/2255] 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 --- .../net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) 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; + + new_trig->occurrences = cpu_to_le32(-1); } - ret = iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list); - kfree(dup); - - 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); From 1722c83f8fbba56c03e0ac597a242c8b0ef4d62c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:52 +0200 Subject: [PATCH 0621/2255] 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(-) 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; From ea1d166fae14e05d49ffb0ea9fcd4658f8d3dcea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:53 +0200 Subject: [PATCH 0622/2255] 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(+) 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); From ec06e9b95944563964170d9e30278361bb26fd3a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:54 +0200 Subject: [PATCH 0623/2255] 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(-) 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++; From 296f3e926716ded8dc29e349d2b042b362f96515 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:55 +0200 Subject: [PATCH 0624/2255] 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(-) 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 From e50a88e5cb8792cc416866496288c5f4d1eb4b1f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 28 Jan 2024 08:53:56 +0200 Subject: [PATCH 0625/2255] 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(-) 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); + } } } From d3b2c6c65bfd3b9616084e91bd0d402964ea7cef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:58 +0200 Subject: [PATCH 0626/2255] 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(+) 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; } From ebe8f41319fabee020736220942d79c1644bea85 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 28 Jan 2024 08:53:59 +0200 Subject: [PATCH 0627/2255] 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 ++++++- .../net/wireless/intel/iwlwifi/fw/runtime.h | 4 +++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 ++ 4 files changed, 53 insertions(+), 1 deletion(-) 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) { From a6dfe1e74403082e43b1f5ed49c0044eeb93da6c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 28 Jan 2024 08:54:00 +0200 Subject: [PATCH 0628/2255] 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(-) 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)); + data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_STEP_NAME, + "STEP", sizeof(*data), NULL); + if (IS_ERR(data)) return; - } - - if (package_size < sizeof(*data)) { - IWL_DEBUG_FW(trans, - "Invalid STEP table UEFI variable len (%lu)\n", - package_size); - kfree(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) { From c8d8f3911135921ace8e939ea0956b55f74bf8a0 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 29 Jan 2024 21:21:49 +0200 Subject: [PATCH 0629/2255] 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(-) 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; } From 8001849921028775eafb5263feadf49e821e9ecf Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Mon, 29 Jan 2024 21:21:50 +0200 Subject: [PATCH 0630/2255] 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 --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 +++++ .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) 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, }; From 0c769cb6b9f364423c255f117774c9ecd5bf23ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:51 +0200 Subject: [PATCH 0631/2255] 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(-) 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, From 64a06679e680d163d91b4642227244184c29ca02 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 29 Jan 2024 21:21:52 +0200 Subject: [PATCH 0632/2255] 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(-) 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; From bc197d3c400f48ce7d9402c968ceeb5680e5b639 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:53 +0200 Subject: [PATCH 0633/2255] 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(-) 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, From f639602a58e7564dd091c7c0793f61042bad9bb6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:54 +0200 Subject: [PATCH 0634/2255] 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(-) 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, From 137d33ac476489645e4a67d66d3abf930cecb419 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 29 Jan 2024 21:21:55 +0200 Subject: [PATCH 0635/2255] 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(-) 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); } From 51eb17b8d5597250fea513050c26a53f2ff183b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:57 +0200 Subject: [PATCH 0636/2255] 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(-) 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. From 3d869feacb74309e4f1cb69572df16ec9862012c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:58 +0200 Subject: [PATCH 0637/2255] 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(-) 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, From 0fcdf55fced7121c43fa576433986f1c04115b73 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 29 Jan 2024 21:21:59 +0200 Subject: [PATCH 0638/2255] 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(-) 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; } From 6770eee75148ba10c0c051885379714773e00b48 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Mon, 29 Jan 2024 21:22:00 +0200 Subject: [PATCH 0639/2255] 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(+) 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)}, From c289f5cd6978af1bd14c1b7c230aaa011e1b3b5d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:22:01 +0200 Subject: [PATCH 0640/2255] 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(-) 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); From 65d3333e4d4f35853aa2991324206e1cb17b81d7 Mon Sep 17 00:00:00 2001 From: Daniel Gabay Date: Mon, 29 Jan 2024 21:22:02 +0200 Subject: [PATCH 0641/2255] 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(-) 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; From ce1fa3adc007ce3fd6beb8f4d733e00daa64c6c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:22:03 +0200 Subject: [PATCH 0642/2255] 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(-) 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__ */ From 45d43937a44c806b8649323b8f5d9f42ae838b0e Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 29 Jan 2024 22:09:19 +0100 Subject: [PATCH 0643/2255] wifi: cfg80211: add a kunit test for 6 GHz colocated AP parsing Test a few things around parsing of 6 GHz colocated APs to e.g. ensure that we are not going to scan for a disabled (affiliated) AP. Signed-off-by: Benjamin Berg Link: https://msgid.link/20240129220918.079dc50ab43b.Ide898d9f1d4c26d7e774d6fd0ec57766967d6572@changeid Signed-off-by: Johannes Berg --- net/wireless/core.h | 44 ++++++++++ net/wireless/scan.c | 49 ++--------- net/wireless/tests/scan.c | 179 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 42 deletions(-) diff --git a/net/wireless/core.h b/net/wireless/core.h index 30434551b377..debf63e6c61f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -550,9 +550,53 @@ int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); void cfg80211_wdev_release_link_bsses(struct wireless_dev *wdev, u16 link_mask); +/** + * struct cfg80211_colocated_ap - colocated AP information + * + * @list: linked list to all colocated APs + * @bssid: BSSID of the reported AP + * @ssid: SSID of the reported AP + * @ssid_len: length of the ssid + * @center_freq: frequency the reported AP is on + * @unsolicited_probe: the reported AP is part of an ESS, where all the APs + * that operate in the same channel as the reported AP and that might be + * detected by a STA receiving this frame, are transmitting unsolicited + * Probe Response frames every 20 TUs + * @oct_recommended: OCT is recommended to exchange MMPDUs with the reported AP + * @same_ssid: the reported AP has the same SSID as the reporting AP + * @multi_bss: the reported AP is part of a multiple BSSID set + * @transmitted_bssid: the reported AP is the transmitting BSSID + * @colocated_ess: all the APs that share the same ESS as the reported AP are + * colocated and can be discovered via legacy bands. + * @short_ssid_valid: short_ssid is valid and can be used + * @short_ssid: the short SSID for this SSID + * @psd_20: The 20MHz PSD EIRP of the primary 20MHz channel for the reported AP + */ +struct cfg80211_colocated_ap { + struct list_head list; + u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + size_t ssid_len; + u32 short_ssid; + u32 center_freq; + u8 unsolicited_probe:1, + oct_recommended:1, + same_ssid:1, + multi_bss:1, + transmitted_bssid:1, + colocated_ess:1, + short_ssid_valid:1; + s8 psd_20; +}; + #if IS_ENABLED(CONFIG_CFG80211_KUNIT_TEST) #define EXPORT_SYMBOL_IF_CFG80211_KUNIT(sym) EXPORT_SYMBOL_IF_KUNIT(sym) #define VISIBLE_IF_CFG80211_KUNIT +void cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list); + +int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, + struct list_head *list); + size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, const u8 *subie, size_t subie_len, u8 *new_ie, size_t new_ie_len); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 01618c4059f4..c78b10e1a167 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -77,45 +77,6 @@ MODULE_PARM_DESC(bss_entries_limit, #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) -/** - * struct cfg80211_colocated_ap - colocated AP information - * - * @list: linked list to all colocated aPS - * @bssid: BSSID of the reported AP - * @ssid: SSID of the reported AP - * @ssid_len: length of the ssid - * @center_freq: frequency the reported AP is on - * @unsolicited_probe: the reported AP is part of an ESS, where all the APs - * that operate in the same channel as the reported AP and that might be - * detected by a STA receiving this frame, are transmitting unsolicited - * Probe Response frames every 20 TUs - * @oct_recommended: OCT is recommended to exchange MMPDUs with the reported AP - * @same_ssid: the reported AP has the same SSID as the reporting AP - * @multi_bss: the reported AP is part of a multiple BSSID set - * @transmitted_bssid: the reported AP is the transmitting BSSID - * @colocated_ess: all the APs that share the same ESS as the reported AP are - * colocated and can be discovered via legacy bands. - * @short_ssid_valid: short_ssid is valid and can be used - * @short_ssid: the short SSID for this SSID - * @psd_20: The 20MHz PSD EIRP of the primary 20MHz channel for the reported AP - */ -struct cfg80211_colocated_ap { - struct list_head list; - u8 bssid[ETH_ALEN]; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; - u32 short_ssid; - u32 center_freq; - u8 unsolicited_probe:1, - oct_recommended:1, - same_ssid:1, - multi_bss:1, - transmitted_bssid:1, - colocated_ess:1, - short_ssid_valid:1; - s8 psd_20; -}; - static void bss_free(struct cfg80211_internal_bss *bss) { struct cfg80211_bss_ies *ies; @@ -566,7 +527,8 @@ static int cfg80211_calc_short_ssid(const struct cfg80211_bss_ies *ies, return 0; } -static void cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list) +VISIBLE_IF_CFG80211_KUNIT void +cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list) { struct cfg80211_colocated_ap *ap, *tmp_ap; @@ -575,6 +537,7 @@ static void cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list) kfree(ap); } } +EXPORT_SYMBOL_IF_KUNIT(cfg80211_free_coloc_ap_list); static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, const u8 *pos, u8 length, @@ -648,8 +611,9 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, return 0; } -static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, - struct list_head *list) +VISIBLE_IF_CFG80211_KUNIT int +cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, + struct list_head *list) { struct ieee80211_neighbor_ap_info *ap_info; const struct element *elem, *ssid_elem; @@ -746,6 +710,7 @@ error: list_splice_tail(&ap_list, list); return n_coloc; } +EXPORT_SYMBOL_IF_KUNIT(cfg80211_parse_colocated_ap); static void cfg80211_scan_req_add_chan(struct cfg80211_scan_request *request, struct ieee80211_channel *chan, diff --git a/net/wireless/tests/scan.c b/net/wireless/tests/scan.c index f9ea44aee995..b40a0c06a6bb 100644 --- a/net/wireless/tests/scan.c +++ b/net/wireless/tests/scan.c @@ -628,6 +628,172 @@ static void test_inform_bss_ml_sta(struct kunit *test) cfg80211_put_bss(wiphy, link_bss); } +static struct cfg80211_parse_colocated_ap_case { + const char *desc; + u8 op_class; + u8 channel; + struct ieee80211_neighbor_ap_info info; + union { + struct ieee80211_tbtt_info_ge_11 tbtt_long; + struct ieee80211_tbtt_info_7_8_9 tbtt_short; + }; + bool add_junk; + bool same_ssid; + bool valid; +} cfg80211_parse_colocated_ap_cases[] = { + { + .desc = "wrong_band", + .info.op_class = 81, + .info.channel = 11, + .tbtt_long = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP, + }, + .valid = false, + }, + { + .desc = "wrong_type", + /* IEEE80211_AP_INFO_TBTT_HDR_TYPE is in the least significant bits */ + .info.tbtt_info_hdr = IEEE80211_TBTT_INFO_TYPE_MLD, + .tbtt_long = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP, + }, + .valid = false, + }, + { + .desc = "colocated_invalid_len_short", + .info.tbtt_info_len = 6, + .tbtt_short = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP | + IEEE80211_RNR_TBTT_PARAMS_SAME_SSID, + }, + .valid = false, + }, + { + .desc = "colocated_invalid_len_short_mld", + .info.tbtt_info_len = 10, + .tbtt_long = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP, + }, + .valid = false, + }, + { + .desc = "colocated_non_mld", + .info.tbtt_info_len = sizeof(struct ieee80211_tbtt_info_7_8_9), + .tbtt_short = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP | + IEEE80211_RNR_TBTT_PARAMS_SAME_SSID, + }, + .same_ssid = true, + .valid = true, + }, + { + .desc = "colocated_non_mld_invalid_bssid", + .info.tbtt_info_len = sizeof(struct ieee80211_tbtt_info_7_8_9), + .tbtt_short = { + .bssid = { 0xff, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP | + IEEE80211_RNR_TBTT_PARAMS_SAME_SSID, + }, + .same_ssid = true, + .valid = false, + }, + { + .desc = "colocated_mld", + .tbtt_long = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP, + }, + .valid = true, + }, + { + .desc = "colocated_mld", + .tbtt_long = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP, + }, + .add_junk = true, + .valid = false, + }, + { + .desc = "colocated_disabled_mld", + .tbtt_long = { + .bssid = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, + .bss_params = IEEE80211_RNR_TBTT_PARAMS_COLOC_AP, + .mld_params.params = cpu_to_le16(IEEE80211_RNR_MLD_PARAMS_DISABLED_LINK), + }, + .valid = false, + }, +}; +KUNIT_ARRAY_PARAM_DESC(cfg80211_parse_colocated_ap, cfg80211_parse_colocated_ap_cases, desc) + +static void test_cfg80211_parse_colocated_ap(struct kunit *test) +{ + const struct cfg80211_parse_colocated_ap_case *params = test->param_value; + struct sk_buff *input = kunit_zalloc_skb(test, 1024, GFP_KERNEL); + struct cfg80211_bss_ies *ies; + struct ieee80211_neighbor_ap_info info; + LIST_HEAD(coloc_ap_list); + int count; + + KUNIT_ASSERT_NOT_NULL(test, input); + + info = params->info; + + /* Reasonable values for a colocated AP */ + if (!info.tbtt_info_len) + info.tbtt_info_len = sizeof(params->tbtt_long); + if (!info.op_class) + info.op_class = 131; + if (!info.channel) + info.channel = 33; + /* Zero is the correct default for .btt_info_hdr (one entry, TBTT type) */ + + skb_put_u8(input, WLAN_EID_SSID); + skb_put_u8(input, 4); + skb_put_data(input, "TEST", 4); + + skb_put_u8(input, WLAN_EID_REDUCED_NEIGHBOR_REPORT); + skb_put_u8(input, sizeof(info) + info.tbtt_info_len + (params->add_junk ? 3 : 0)); + skb_put_data(input, &info, sizeof(info)); + skb_put_data(input, ¶ms->tbtt_long, info.tbtt_info_len); + + if (params->add_junk) + skb_put_data(input, "123", 3); + + ies = kunit_kzalloc(test, struct_size(ies, data, input->len), GFP_KERNEL); + ies->len = input->len; + memcpy(ies->data, input->data, input->len); + + count = cfg80211_parse_colocated_ap(ies, &coloc_ap_list); + + KUNIT_EXPECT_EQ(test, count, params->valid); + KUNIT_EXPECT_EQ(test, list_count_nodes(&coloc_ap_list), params->valid); + + if (params->valid && !list_empty(&coloc_ap_list)) { + struct cfg80211_colocated_ap *ap; + + ap = list_first_entry(&coloc_ap_list, typeof(*ap), list); + if (info.tbtt_info_len <= sizeof(params->tbtt_short)) + KUNIT_EXPECT_MEMEQ(test, ap->bssid, params->tbtt_short.bssid, ETH_ALEN); + else + KUNIT_EXPECT_MEMEQ(test, ap->bssid, params->tbtt_long.bssid, ETH_ALEN); + + if (params->same_ssid) { + KUNIT_EXPECT_EQ(test, ap->ssid_len, 4); + KUNIT_EXPECT_MEMEQ(test, ap->ssid, "TEST", 4); + } else { + KUNIT_EXPECT_EQ(test, ap->ssid_len, 0); + } + } + + cfg80211_free_coloc_ap_list(&coloc_ap_list); +} + static struct kunit_case gen_new_ie_test_cases[] = { KUNIT_CASE_PARAM(test_gen_new_ie, gen_new_ie_gen_params), KUNIT_CASE(test_gen_new_ie_malformed), @@ -653,3 +819,16 @@ static struct kunit_suite inform_bss = { }; kunit_test_suite(inform_bss); + +static struct kunit_case scan_6ghz_cases[] = { + KUNIT_CASE_PARAM(test_cfg80211_parse_colocated_ap, + cfg80211_parse_colocated_ap_gen_params), + {} +}; + +static struct kunit_suite scan_6ghz = { + .name = "cfg80211-scan-6ghz", + .test_cases = scan_6ghz_cases, +}; + +kunit_test_suite(scan_6ghz); From cfbb2add482ab86a9d183dbb9ac00d18c1389cc7 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 29 Jan 2024 22:09:20 +0100 Subject: [PATCH 0644/2255] wifi: cfg80211: tests: verify BSS use flags of NSTR links Extend the test to pass an RNR appropriate for an NSTR and verify that use_for as well as cannot_use_reasons are set correctly. Signed-off-by: Benjamin Berg Link: https://msgid.link/20240129220918.b00aee4c4c9f.I942fddf51cabaab761de3865b4e06cce831a46ef@changeid Signed-off-by: Johannes Berg --- net/wireless/tests/scan.c | 68 ++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/net/wireless/tests/scan.c b/net/wireless/tests/scan.c index b40a0c06a6bb..9f458be71659 100644 --- a/net/wireless/tests/scan.c +++ b/net/wireless/tests/scan.c @@ -407,6 +407,7 @@ static struct inform_bss_ml_sta_case { int mld_id; bool sta_prof_vendor_elems; bool include_oper_class; + bool nstr; } inform_bss_ml_sta_cases[] = { { .desc = "zero_mld_id", @@ -426,6 +427,10 @@ static struct inform_bss_ml_sta_case { .mld_id = 1, .sta_prof_vendor_elems = true, .include_oper_class = true, + }, { + .desc = "nstr", + .mld_id = 0, + .nstr = true, }, }; KUNIT_ARRAY_PARAM_DESC(inform_bss_ml_sta, inform_bss_ml_sta_cases, desc) @@ -458,7 +463,7 @@ static void test_inform_bss_ml_sta(struct kunit *test) struct { struct ieee80211_neighbor_ap_info info; struct ieee80211_tbtt_info_ge_11 ap; - } __packed rnr = { + } __packed rnr_normal = { .info = { .tbtt_info_hdr = u8_encode_bits(0, IEEE80211_AP_INFO_TBTT_HDR_COUNT), .tbtt_info_len = sizeof(struct ieee80211_tbtt_info_ge_11), @@ -477,6 +482,28 @@ static void test_inform_bss_ml_sta(struct kunit *test) IEEE80211_RNR_MLD_PARAMS_LINK_ID), } }; + struct { + struct ieee80211_neighbor_ap_info info; + struct ieee80211_rnr_mld_params mld_params; + } __packed rnr_nstr = { + .info = { + .tbtt_info_hdr = + u8_encode_bits(0, IEEE80211_AP_INFO_TBTT_HDR_COUNT) | + u8_encode_bits(IEEE80211_TBTT_INFO_TYPE_MLD, + IEEE80211_AP_INFO_TBTT_HDR_TYPE), + .tbtt_info_len = sizeof(struct ieee80211_rnr_mld_params), + .op_class = 81, + .channel = 11, + }, + .mld_params = { + .mld_id = params->mld_id, + .params = + le16_encode_bits(link_id, + IEEE80211_RNR_MLD_PARAMS_LINK_ID), + } + }; + size_t rnr_len = params->nstr ? sizeof(rnr_nstr) : sizeof(rnr_normal); + void *rnr = params->nstr ? (void *)&rnr_nstr : (void *)&rnr_normal; struct { __le16 control; u8 var_len; @@ -516,7 +543,7 @@ static void test_inform_bss_ml_sta(struct kunit *test) u16_encode_bits(link_id, IEEE80211_MLE_STA_CONTROL_LINK_ID)), .var_len = sizeof(sta_prof) - 2 - 2, - .bssid = { *rnr.ap.bssid }, + .bssid = { *rnr_normal.ap.bssid }, .beacon_int = cpu_to_le16(101), .tsf_offset = cpu_to_le64(-123ll), .capabilities = cpu_to_le16(0xdead), @@ -540,8 +567,8 @@ static void test_inform_bss_ml_sta(struct kunit *test) } skb_put_u8(input, WLAN_EID_REDUCED_NEIGHBOR_REPORT); - skb_put_u8(input, sizeof(rnr)); - skb_put_data(input, &rnr, sizeof(rnr)); + skb_put_u8(input, rnr_len); + skb_put_data(input, rnr, rnr_len); /* build a multi-link element */ skb_put_u8(input, WLAN_EID_EXTENSION); @@ -587,9 +614,10 @@ static void test_inform_bss_ml_sta(struct kunit *test) KUNIT_EXPECT_EQ(test, ctx.inform_bss_count, 2); /* Check link_bss *****************************************************/ - link_bss = cfg80211_get_bss(wiphy, NULL, sta_prof.bssid, NULL, 0, - IEEE80211_BSS_TYPE_ANY, - IEEE80211_PRIVACY_ANY); + link_bss = __cfg80211_get_bss(wiphy, NULL, sta_prof.bssid, NULL, 0, + IEEE80211_BSS_TYPE_ANY, + IEEE80211_PRIVACY_ANY, + 0); KUNIT_ASSERT_NOT_NULL(test, link_bss); KUNIT_EXPECT_EQ(test, link_bss->signal, 0); KUNIT_EXPECT_EQ(test, link_bss->beacon_interval, @@ -600,6 +628,22 @@ static void test_inform_bss_ml_sta(struct kunit *test) KUNIT_EXPECT_PTR_EQ(test, link_bss->channel, ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(2462))); + /* Test wiphy does not set WIPHY_FLAG_SUPPORTS_NSTR_NONPRIMARY */ + if (params->nstr) { + KUNIT_EXPECT_EQ(test, link_bss->use_for, 0); + KUNIT_EXPECT_EQ(test, link_bss->cannot_use_reasons, + NL80211_BSS_CANNOT_USE_NSTR_NONPRIMARY); + KUNIT_EXPECT_NULL(test, + cfg80211_get_bss(wiphy, NULL, sta_prof.bssid, + NULL, 0, + IEEE80211_BSS_TYPE_ANY, + IEEE80211_PRIVACY_ANY)); + } else { + KUNIT_EXPECT_EQ(test, link_bss->use_for, + NL80211_BSS_USE_FOR_ALL); + KUNIT_EXPECT_EQ(test, link_bss->cannot_use_reasons, 0); + } + rcu_read_lock(); ies = rcu_dereference(link_bss->ies); KUNIT_EXPECT_NOT_NULL(test, ies); @@ -607,20 +651,20 @@ static void test_inform_bss_ml_sta(struct kunit *test) /* Resulting length should be: * SSID (inherited) + RNR (inherited) + vendor element(s) + * operating class (if requested) + - * generated RNR (if MLD ID == 0) + + * generated RNR (if MLD ID == 0 and not NSTR) + * MLE common info + MLE header and control */ if (params->sta_prof_vendor_elems) KUNIT_EXPECT_EQ(test, ies->len, - 6 + 2 + sizeof(rnr) + 2 + 160 + 2 + 165 + + 6 + 2 + rnr_len + 2 + 160 + 2 + 165 + (params->include_oper_class ? 3 : 0) + - (!params->mld_id ? 22 : 0) + + (!params->mld_id && !params->nstr ? 22 : 0) + mle_basic_common_info.var_len + 5); else KUNIT_EXPECT_EQ(test, ies->len, - 6 + 2 + sizeof(rnr) + 2 + 155 + + 6 + 2 + rnr_len + 2 + 155 + (params->include_oper_class ? 3 : 0) + - (!params->mld_id ? 22 : 0) + + (!params->mld_id && !params->nstr ? 22 : 0) + mle_basic_common_info.var_len + 5); rcu_read_unlock(); From c868a189ecfe8cc0b3173c2eaa7f0b659326c151 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:34 +0200 Subject: [PATCH 0645/2255] 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(-) 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; From 8c9bef26e98b71b18afe8de6212b750c4e9f9ecf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 10:24:35 +0200 Subject: [PATCH 0646/2255] 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(-) 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); } From 760cfa5bbd3bdd5ca2b36ca447d69788651ab17b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 10:24:36 +0200 Subject: [PATCH 0647/2255] 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(+) 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); From 2594e4d9e1a2d79bf7bb262974abaf5ef153e371 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:37 +0200 Subject: [PATCH 0648/2255] 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 +----- .../wireless/intel/iwlwifi/fw/regulatory.c | 132 ++++++++++++++ .../wireless/intel/iwlwifi/fw/regulatory.h | 90 ++++++++++ .../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 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_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt); -int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt); -int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt); - -int iwl_sar_get_wgds_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) +static inline int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } -static inline int iwl_sar_get_wrds_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_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", From c0a3dfc1ce955732ae8cd301a052f2277aa55436 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:38 +0200 Subject: [PATCH 0649/2255] 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(-) 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); } From 427661e4c48887ea2a226cd972e574ae7686fb95 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:39 +0200 Subject: [PATCH 0650/2255] 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 + .../wireless/intel/iwlwifi/fw/regulatory.c | 17 +++ .../wireless/intel/iwlwifi/fw/regulatory.h | 6 + .../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 | 137 ++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 10 files changed, 275 insertions(+), 86 deletions(-) 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,80 +1387,8 @@ 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) -{ - int ret; - - iwl_acpi_get_guid_lock_status(&mvm->fwrt); - - /* read PPAG table */ - ret = iwl_acpi_get_ppag_table(&mvm->fwrt); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "PPAG BIOS table invalid or unavailable. (%d)\n", - ret); - } - - /* read SAR tables */ - ret = iwl_acpi_get_wrds_table(&mvm->fwrt); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "WRDS SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* - * If not available, don't fail and don't bother with EWRD and - * WGDS */ - - 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 - * available, issue an error, because we can't use SAR - * Geo without basic SAR. - */ - IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); - } - - } else { - 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) - IWL_DEBUG_RADIO(mvm, - "EWRD SAR BIOS table invalid or unavailable. (%d)\n", - ret); - - /* read geo SAR table */ - if (iwl_sar_geo_support(&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", - ret); - /* we don't fail if the table is not available */ - } - } - - 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; @@ -1487,12 +1417,65 @@ 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 */ +void iwl_mvm_get_bios_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) { + IWL_DEBUG_RADIO(mvm, + "PPAG BIOS table invalid or unavailable. (%d)\n", + ret); + } + + /* read SAR tables */ + ret = iwl_bios_get_wrds_table(&mvm->fwrt); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "WRDS SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* + * If not available, don't fail and don't bother with EWRD and + * WGDS */ + + 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 + * available, issue an error, because we can't use SAR + * Geo without basic SAR. + */ + IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); + } + + } else { + 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) + IWL_DEBUG_RADIO(mvm, + "EWRD SAR BIOS table invalid or unavailable. (%d)\n", + ret); + + /* read geo SAR table */ + if (iwl_sar_geo_support(&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", + ret); + /* we don't fail if the table is not available */ + } + } + + iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters); +} + 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); From be3a8cbb1ca7d6737bfff9ea9ca260958f4bf6f0 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:40 +0200 Subject: [PATCH 0651/2255] 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(-) 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; From 09059c6764a8870ff7515c2d78ecbea7fbcffc23 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:41 +0200 Subject: [PATCH 0652/2255] 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 ---- .../wireless/intel/iwlwifi/fw/regulatory.c | 161 ++++++++++++++++ .../wireless/intel/iwlwifi/fw/regulatory.h | 20 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 5 files changed, 187 insertions(+), 203 deletions(-) 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); From 8408e83e16bb4d1d8f0ccf6937cae0357478ec50 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:42 +0200 Subject: [PATCH 0653/2255] 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 ---------------- .../wireless/intel/iwlwifi/fw/regulatory.c | 32 +++++++++++++++++-- .../net/wireless/intel/iwlwifi/fw/runtime.h | 1 - 3 files changed, 29 insertions(+), 32 deletions(-) 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; From bc8d0a4528f167742ecb511ba663795235e9d15c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:43 +0200 Subject: [PATCH 0654/2255] 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 - .../wireless/intel/iwlwifi/fw/regulatory.c | 1 + .../wireless/intel/iwlwifi/fw/regulatory.h | 1 + .../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(-) 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", From e1c54d6377348fa2f7e216f53426f1b5fb9a59b1 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:44 +0200 Subject: [PATCH 0655/2255] 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(-) 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; From ad5a85d8fdd346ecc34217e3bd713bf0b519912d Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:45 +0200 Subject: [PATCH 0656/2255] 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 +-- .../wireless/intel/iwlwifi/fw/api/nvm-reg.h | 8 +- .../wireless/intel/iwlwifi/fw/regulatory.c | 91 +++++++++++++++++++ .../wireless/intel/iwlwifi/fw/regulatory.h | 15 ++- .../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(-) 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, From 3bc67e7c18cd69e88b801336cfe2a4dc7b4981a4 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:46 +0200 Subject: [PATCH 0657/2255] 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 +- .../wireless/intel/iwlwifi/fw/api/nvm-reg.h | 24 ++++------ .../wireless/intel/iwlwifi/fw/regulatory.c | 19 ++------ .../wireless/intel/iwlwifi/fw/regulatory.h | 12 +++-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 47 ++++++++++++------- 6 files changed, 62 insertions(+), 53 deletions(-) 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) From 084e0452a42b1d4ccde601cc1873a4ee9d8a4cbb Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:47 +0200 Subject: [PATCH 0658/2255] 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 ++-- .../wireless/intel/iwlwifi/fw/regulatory.c | 32 ++++++++----- .../wireless/intel/iwlwifi/fw/regulatory.h | 4 ++ .../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(-) 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) { } From 7d366663b7d84ecdb52ba141c1cafd4f3c73e0ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:00:02 +0100 Subject: [PATCH 0659/2255] 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(-) 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, \ From f455f5ad500a993b65ae1c4c59639eff558e1688 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:54:35 +0100 Subject: [PATCH 0660/2255] wifi: mac80211: trace SMPS requests from driver Even if there are a lot of possible ways drivers might call this, at least knowing when they do and with what settings can be useful. Add tracing for it. Link: https://msgid.link/20240129195435.b20d2ead2013.I8213e65c274451d523a3397519ac578c3ed2df4d@changeid [removed link-id contortions as suggested by Jeff] Signed-off-by: Johannes Berg --- net/mac80211/ht.c | 4 +++- net/mac80211/trace.h | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 749f4ecab990..bccc99a00383 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -9,7 +9,7 @@ * Copyright 2007, Michael Wu * Copyright 2007-2010, Intel Corporation * Copyright 2017 Intel Deutschland GmbH - * Copyright(c) 2020-2023 Intel Corporation + * Copyright(c) 2020-2024 Intel Corporation */ #include @@ -603,6 +603,8 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, if (WARN_ON(!link)) goto out; + trace_api_request_smps(sdata->local, sdata, link, smps_mode); + if (link->u.mgd.driver_smps_mode == smps_mode) goto out; diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 1c0c46b11c6d..e2dde3e77c30 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2,7 +2,7 @@ /* * Portions of this file * Copyright(c) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2023 Intel Corporation + * Copyright (C) 2018 - 2024 Intel Corporation */ #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) @@ -3035,6 +3035,34 @@ TRACE_EVENT(api_radar_detected, ) ); +TRACE_EVENT(api_request_smps, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, + enum ieee80211_smps_mode smps_mode), + + TP_ARGS(local, sdata, link, smps_mode), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(int, link_id) + __field(u32, smps_mode) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->link_id = link->link_id, + __entry->smps_mode = smps_mode; + ), + + TP_printk( + LOCAL_PR_FMT " " VIF_PR_FMT " link:%d, smps_mode:%d", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, __entry->smps_mode + ) +); + /* * Tracing for internal functions * (which may also be called in response to driver calls) From 392d3dfdfd68f4be6964d4fc8f3979a7a859e6f2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:57:39 +0100 Subject: [PATCH 0661/2255] wifi: mac80211: clean up FILS discovery change flags handling It doesn't make sense to return BSS change flags in an int, as they're a bigger type. For this particular function it still works OK, but clean it up to avoid future errors (or copying this code in a broken way.) Reviewed-by: Jeff Johnson Link: https://msgid.link/20240129195739.e340a7d5e7c6.I1dfcca32d43dce903494a2c474844491682671b4@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index dd237081dbe3..2830ddac45b2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -953,7 +953,8 @@ ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata, struct cfg80211_fils_discovery *params, struct ieee80211_link_data *link, - struct ieee80211_bss_conf *link_conf) + struct ieee80211_bss_conf *link_conf, + u64 *changed) { struct fils_discovery_data *new, *old = NULL; struct ieee80211_fils_discovery *fd; @@ -980,7 +981,8 @@ static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata, RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL); } - return BSS_CHANGED_FILS_DISCOVERY; + *changed |= BSS_CHANGED_FILS_DISCOVERY; + return 0; } static int @@ -1443,10 +1445,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, goto error; err = ieee80211_set_fils_discovery(sdata, ¶ms->fils_discovery, - link, link_conf); + link, link_conf, &changed); if (err < 0) goto error; - changed |= err; err = ieee80211_set_unsol_bcast_probe_resp(sdata, ¶ms->unsol_bcast_probe_resp, @@ -1518,10 +1519,9 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, return err; err = ieee80211_set_fils_discovery(sdata, ¶ms->fils_discovery, - link, link_conf); + link, link_conf, &changed); if (err < 0) return err; - changed |= err; err = ieee80211_set_unsol_bcast_probe_resp(sdata, ¶ms->unsol_bcast_probe_resp, From 57d1b4632e03e5f938972055c45b0f2e475e6929 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:54:21 +0100 Subject: [PATCH 0662/2255] wifi: nl80211: move WPA version validation to policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a contiguous mask (starting with bit 0) of allowed values in a bitmap, it's equivalent to check "!(val & ~mask)" and "val ∈ [0, mask]". Use that to move the WPA versions check to the policy, for better error reporting. Reviewed-by: Jeff Johnson Link: https://msgid.link/20240129195421.e8cae9866ccb.I2539b395e3476307d702c6867e51a937e52e57a0@changeid Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e4f41f86e295..68c20409eca6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5,7 +5,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include @@ -581,7 +581,11 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_STATUS_CODE] = { .type = NLA_U16 }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, - [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, + [NL80211_ATTR_WPA_VERSIONS] = + NLA_POLICY_RANGE(NLA_U32, 0, + NL80211_WPA_VERSION_1 | + NL80211_WPA_VERSION_2 | + NL80211_WPA_VERSION_3), [NL80211_ATTR_PID] = { .type = NLA_U32 }, [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, [NL80211_ATTR_PMKID] = NLA_POLICY_EXACT_LEN_WARN(WLAN_PMKID_LEN), @@ -10604,13 +10608,6 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) return res; } -static bool nl80211_valid_wpa_versions(u32 wpa_versions) -{ - return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | - NL80211_WPA_VERSION_2 | - NL80211_WPA_VERSION_3)); -} - static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -10836,12 +10833,9 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, return -EINVAL; } - if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) { + if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) settings->wpa_versions = nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]); - if (!nl80211_valid_wpa_versions(settings->wpa_versions)) - return -EINVAL; - } if (info->attrs[NL80211_ATTR_AKM_SUITES]) { void *data; From 358ddc7bfa980888b69b406a7c4ce0a5b0ac5c30 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 29 Jan 2024 20:00:52 +0100 Subject: [PATCH 0663/2255] 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(-) 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)); From b341590e77d89d8812051fdd2354ff04e12f211b Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 29 Jan 2024 20:00:53 +0100 Subject: [PATCH 0664/2255] wifi: mac80211: don't allow deactivation of all links The set_active_links API is intended for link switching, so switching to no links at all is not supported. Add a warning to check that. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129200054.e3c113f94508.Ia35f927f914bf98dd8f9350dd4f78b1d901b1c1d@changeid Signed-off-by: Johannes Berg --- net/mac80211/link.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/mac80211/link.c b/net/mac80211/link.c index d4f86955afa6..c0d05efcf6f8 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -444,6 +444,9 @@ int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links) lockdep_assert_wiphy(local->hw.wiphy); + if (WARN_ON(!active_links)) + return -EINVAL; + if (!drv_can_activate_links(local, sdata, active_links)) return -EINVAL; @@ -472,6 +475,9 @@ void ieee80211_set_active_links_async(struct ieee80211_vif *vif, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + if (WARN_ON(!active_links)) + return; + if (!ieee80211_sdata_running(sdata)) return; From d10fb5ecc82211691264156bbf8b8a988d57944e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 31 Jan 2024 21:38:16 +0100 Subject: [PATCH 0665/2255] 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(-) 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 */ From 3ec064e0a2cb667eceea7410d2ce7945a186beb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 22:00:39 +0100 Subject: [PATCH 0666/2255] 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(-) 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) From f74f397afe2b7a1e2f8a0a3384006e36fb940f87 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 22:02:27 +0100 Subject: [PATCH 0667/2255] 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(-) 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 { From a51d1cf5ad64a17230cf90e1770d363c5cbc0d5c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:25 +0200 Subject: [PATCH 0668/2255] 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(-) 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) From 18f523654d4943c87da3ec512dad74828be764e4 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:26 +0200 Subject: [PATCH 0669/2255] 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 - .../wireless/intel/iwlwifi/fw/regulatory.c | 2 ++ .../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(-) 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) From 61ff84440c402ad3e0c3989b3bef99f0db5e6766 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 1 Feb 2024 16:17:27 +0200 Subject: [PATCH 0670/2255] 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(-) 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); From dd273e8a22f9302c499ae4248c95a212fccd6811 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Thu, 1 Feb 2024 16:17:28 +0200 Subject: [PATCH 0671/2255] 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(-) 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; } From 4dde4ff0eadd6cde43aa5f39fbea36355f9f6e44 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 1 Feb 2024 16:17:29 +0200 Subject: [PATCH 0672/2255] 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 --- .../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(-) 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)) From 669761e897a4fc87ae0e4625590f2a396a87a3d1 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:31 +0200 Subject: [PATCH 0673/2255] 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 ++-- .../wireless/intel/iwlwifi/fw/regulatory.c | 1 + .../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(-) 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); From 20935f3e646e687f32f044d9d75a4a8637c086db Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:32 +0200 Subject: [PATCH 0674/2255] 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 ++--- .../wireless/intel/iwlwifi/fw/regulatory.c | 1 + .../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(-) 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; From dc2b94a111e0fb3779a86dd8d303ad842880f869 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:33 +0200 Subject: [PATCH 0675/2255] 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 | 45 ++++++++++++-------- 3 files changed, 33 insertions(+), 31 deletions(-) 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); - - } 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) { - IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to enable\n"); - return DSM_VALUE_RFI_ENABLE; + return bios_enable_rfi; } - IWL_DEBUG_RADIO(mvm, "DSM RFI is disabled\n"); + 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"); + 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); + } - /* 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); } From b97ada404c4eecb90c79fd884cdc09022d549d20 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:34 +0200 Subject: [PATCH 0676/2255] 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(-) 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; From 091d89428f18ac8e67b4032dfa305e957040bdd9 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:35 +0200 Subject: [PATCH 0677/2255] 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 | 95 ++++++++++--------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 33 +++---- .../net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 32 +++---- 4 files changed, 76 insertions(+), 88 deletions(-) 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) + if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size))) + return -EINVAL; + + expected_size = acpi_dsm_size[func]; + + /* Currently all ACPI DSMs are either 8-bit or 32-bit */ + if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) + return -EOPNOTSUPP; + + 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 u8 */ - *value = (u8)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_u8); - -/* - * 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)); - - if (ret < 0) - return ret; - - /* cast val (u64) to be u32 */ - *value = (u32)val; - 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); From dc4fe7500e7a1a1ab56a7708ac9be4c90fd12174 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:36 +0200 Subject: [PATCH 0678/2255] 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 +-------------- .../wireless/intel/iwlwifi/fw/regulatory.c | 49 +++++++++++++++ .../wireless/intel/iwlwifi/fw/regulatory.h | 44 ++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 5 files changed, 97 insertions(+), 106 deletions(-) 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) From fc7214c3c986142758ae9d2cd456c98e48547b5e Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:37 +0200 Subject: [PATCH 0679/2255] 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 - .../wireless/intel/iwlwifi/fw/regulatory.c | 13 ++++++-- .../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 ++++++++++++ .../net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 14 ++++---- 7 files changed, 75 insertions(+), 12 deletions(-) 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); From c1b393a7dc237505088129945a85b570af8742da Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 1 Feb 2024 16:17:38 +0200 Subject: [PATCH 0680/2255] 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(+) 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) { From 12e1a6a5b038bcf2c58fd356758710180222e5bc Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:40 +0200 Subject: [PATCH 0681/2255] 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(-) 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 From 5932ad87828b267649d750869c89c0f1a3873477 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 1 Feb 2024 16:17:41 +0200 Subject: [PATCH 0682/2255] 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 --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 80 ------------------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 ++ .../wireless/intel/iwlwifi/mvm/time-event.c | 80 +++++++++++++++++++ 3 files changed, 88 insertions(+), 80 deletions(-) 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, From 3e5fb691faee1d43ee13d4ce2666b0a05e1555b3 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Tue, 23 Jan 2024 12:58:45 +0100 Subject: [PATCH 0683/2255] ice: make ice_vsi_cfg_rxq() static Currently, XSK control path in ice driver calls directly ice_vsi_cfg_rxq() whereas we have ice_vsi_cfg_single_rxq() for that purpose. Use the latter from XSK side and make ice_vsi_cfg_rxq() static. ice_vsi_cfg_rxq() resides in ice_base.c and is rather big, so to reduce the code churn let us move two callers of it from ice_lib.c to ice_base.c. Signed-off-by: Maciej Fijalkowski Acked-by: Magnus Karlsson Reviewed-by: Simon Horman Tested-by: Chandan Kumar Rout (A Contingent Worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_base.c | 58 ++++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_base.h | 3 +- drivers/net/ethernet/intel/ice/ice_lib.c | 56 ---------------------- drivers/net/ethernet/intel/ice/ice_lib.h | 4 -- drivers/net/ethernet/intel/ice/ice_xsk.c | 2 +- 5 files changed, 60 insertions(+), 63 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 7ac847718882..f49cf6a26753 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -538,7 +538,7 @@ static void ice_xsk_pool_fill_cb(struct ice_rx_ring *ring) * * Return 0 on success and a negative value on error. */ -int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) +static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) { struct device *dev = ice_pf_to_dev(ring->vsi->back); u32 num_bufs = ICE_RX_DESC_UNUSED(ring); @@ -633,6 +633,62 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) return 0; } +int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx) +{ + if (q_idx >= vsi->num_rxq) + return -EINVAL; + + return ice_vsi_cfg_rxq(vsi->rx_rings[q_idx]); +} + +/** + * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length + * @vsi: VSI + */ +static void ice_vsi_cfg_frame_size(struct ice_vsi *vsi) +{ + if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) { + vsi->max_frame = ICE_MAX_FRAME_LEGACY_RX; + vsi->rx_buf_len = ICE_RXBUF_1664; +#if (PAGE_SIZE < 8192) + } else if (!ICE_2K_TOO_SMALL_WITH_PADDING && + (vsi->netdev->mtu <= ETH_DATA_LEN)) { + vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; + vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; +#endif + } else { + vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; + vsi->rx_buf_len = ICE_RXBUF_3072; + } +} + +/** + * ice_vsi_cfg_rxqs - Configure the VSI for Rx + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + * Configure the Rx VSI for operation. + */ +int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) +{ + u16 i; + + if (vsi->type == ICE_VSI_VF) + goto setup_rings; + + ice_vsi_cfg_frame_size(vsi); +setup_rings: + /* set up individual rings */ + ice_for_each_rxq(vsi, i) { + int err = ice_vsi_cfg_rxq(vsi->rx_rings[i]); + + if (err) + return err; + } + + return 0; +} + /** * __ice_vsi_get_qs - helper function for assigning queues from PF to VSI * @qs_cfg: gathered variables needed for pf->vsi queues assignment diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h index 17321ba75602..85e607644560 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.h +++ b/drivers/net/ethernet/intel/ice/ice_base.h @@ -6,7 +6,8 @@ #include "ice.h" -int ice_vsi_cfg_rxq(struct ice_rx_ring *ring); +int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx); +int ice_vsi_cfg_rxqs(struct ice_vsi *vsi); int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg); int ice_vsi_ctrl_one_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx, bool wait); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 9be724291ef8..a2d3e5e9fed8 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1671,27 +1671,6 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi) } } -/** - * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length - * @vsi: VSI - */ -static void ice_vsi_cfg_frame_size(struct ice_vsi *vsi) -{ - if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) { - vsi->max_frame = ICE_MAX_FRAME_LEGACY_RX; - vsi->rx_buf_len = ICE_RXBUF_1664; -#if (PAGE_SIZE < 8192) - } else if (!ICE_2K_TOO_SMALL_WITH_PADDING && - (vsi->netdev->mtu <= ETH_DATA_LEN)) { - vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; - vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; -#endif - } else { - vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; - vsi->rx_buf_len = ICE_RXBUF_3072; - } -} - /** * ice_pf_state_is_nominal - checks the PF for nominal state * @pf: pointer to PF to check @@ -1795,14 +1774,6 @@ ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio, wr32(hw, QRXFLXP_CNTXT(pf_q), regval); } -int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx) -{ - if (q_idx >= vsi->num_rxq) - return -EINVAL; - - return ice_vsi_cfg_rxq(vsi->rx_rings[q_idx]); -} - int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, u16 q_idx) { DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1); @@ -1815,33 +1786,6 @@ int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, u return ice_vsi_cfg_txq(vsi, tx_rings[q_idx], qg_buf); } -/** - * ice_vsi_cfg_rxqs - Configure the VSI for Rx - * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error - * Configure the Rx VSI for operation. - */ -int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) -{ - u16 i; - - if (vsi->type == ICE_VSI_VF) - goto setup_rings; - - ice_vsi_cfg_frame_size(vsi); -setup_rings: - /* set up individual rings */ - ice_for_each_rxq(vsi, i) { - int err = ice_vsi_cfg_rxq(vsi->rx_rings[i]); - - if (err) - return err; - } - - return 0; -} - /** * ice_vsi_cfg_txqs - Configure the VSI for Tx * @vsi: the VSI being configured diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 71bd27244941..6ffe4b0603bd 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -54,12 +54,8 @@ bool ice_pf_state_is_nominal(struct ice_pf *pf); void ice_update_eth_stats(struct ice_vsi *vsi); -int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx); - int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, u16 q_idx); -int ice_vsi_cfg_rxqs(struct ice_vsi *vsi); - int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi); void ice_vsi_cfg_msix(struct ice_vsi *vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index 8b81a1677045..617e4d14d46e 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -249,7 +249,7 @@ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx) ice_tx_xsk_pool(vsi, q_idx); } - err = ice_vsi_cfg_rxq(rx_ring); + err = ice_vsi_cfg_single_rxq(vsi, q_idx); if (err) return err; From a292ba981324ec790eb671df1c64fae5c98c4b3d Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Tue, 23 Jan 2024 12:58:46 +0100 Subject: [PATCH 0684/2255] ice: make ice_vsi_cfg_txq() static Currently, XSK control path in ice driver calls directly ice_vsi_cfg_txq() whereas we have ice_vsi_cfg_single_txq() for that purpose. Use the latter from XSK side and make ice_vsi_cfg_txq() static. ice_vsi_cfg_txq() resides in ice_base.c and is rather big, so to reduce the code churn let us move the callers of it from ice_lib.c to ice_base.c. This change puts ice_qp_ena() on nice diet due to the checks and operations that ice_vsi_cfg_single_{r,t}xq() do internally. add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-182 (-182) Function old new delta ice_xsk_pool_setup 2165 1983 -182 Total: Before=472597, After=472415, chg -0.04% Signed-off-by: Maciej Fijalkowski Acked-by: Magnus Karlsson Reviewed-by: Simon Horman Tested-by: Chandan Kumar Rout (A Contingent Worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_base.c | 76 ++++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_base.h | 7 ++- drivers/net/ethernet/intel/ice/ice_lib.c | 73 ---------------------- drivers/net/ethernet/intel/ice/ice_lib.h | 6 -- drivers/net/ethernet/intel/ice/ice_xsk.c | 20 +----- 5 files changed, 82 insertions(+), 100 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index f49cf6a26753..ad953208f582 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -884,7 +884,7 @@ void ice_vsi_free_q_vectors(struct ice_vsi *vsi) * @ring: Tx ring to be configured * @qg_buf: queue group buffer */ -int +static int ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring, struct ice_aqc_add_tx_qgrp *qg_buf) { @@ -955,6 +955,80 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring, return 0; } +int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, + u16 q_idx) +{ + DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1); + + if (q_idx >= vsi->alloc_txq || !tx_rings || !tx_rings[q_idx]) + return -EINVAL; + + qg_buf->num_txqs = 1; + + return ice_vsi_cfg_txq(vsi, tx_rings[q_idx], qg_buf); +} + +/** + * ice_vsi_cfg_txqs - Configure the VSI for Tx + * @vsi: the VSI being configured + * @rings: Tx ring array to be configured + * @count: number of Tx ring array elements + * + * Return 0 on success and a negative value on error + * Configure the Tx VSI for operation. + */ +static int +ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_tx_ring **rings, u16 count) +{ + DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1); + int err = 0; + u16 q_idx; + + qg_buf->num_txqs = 1; + + for (q_idx = 0; q_idx < count; q_idx++) { + err = ice_vsi_cfg_txq(vsi, rings[q_idx], qg_buf); + if (err) + break; + } + + return err; +} + +/** + * ice_vsi_cfg_lan_txqs - Configure the VSI for Tx + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + * Configure the Tx VSI for operation. + */ +int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) +{ + return ice_vsi_cfg_txqs(vsi, vsi->tx_rings, vsi->num_txq); +} + +/** + * ice_vsi_cfg_xdp_txqs - Configure Tx queues dedicated for XDP in given VSI + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + * Configure the Tx queues dedicated for XDP in given VSI for operation. + */ +int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi) +{ + int ret; + int i; + + ret = ice_vsi_cfg_txqs(vsi, vsi->xdp_rings, vsi->num_xdp_txq); + if (ret) + return ret; + + ice_for_each_rxq(vsi, i) + ice_tx_xsk_pool(vsi, i); + + return 0; +} + /** * ice_cfg_itr - configure the initial interrupt throttle values * @hw: pointer to the HW structure diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h index 85e607644560..b711bc921928 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.h +++ b/drivers/net/ethernet/intel/ice/ice_base.h @@ -15,9 +15,10 @@ int ice_vsi_wait_one_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx); int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi); void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); void ice_vsi_free_q_vectors(struct ice_vsi *vsi); -int -ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring, - struct ice_aqc_add_tx_qgrp *qg_buf); +int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, + u16 q_idx); +int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi); +int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi); void ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector); void ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index a2d3e5e9fed8..60e0d824195e 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1774,79 +1774,6 @@ ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio, wr32(hw, QRXFLXP_CNTXT(pf_q), regval); } -int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, u16 q_idx) -{ - DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1); - - if (q_idx >= vsi->alloc_txq || !tx_rings || !tx_rings[q_idx]) - return -EINVAL; - - qg_buf->num_txqs = 1; - - return ice_vsi_cfg_txq(vsi, tx_rings[q_idx], qg_buf); -} - -/** - * ice_vsi_cfg_txqs - Configure the VSI for Tx - * @vsi: the VSI being configured - * @rings: Tx ring array to be configured - * @count: number of Tx ring array elements - * - * Return 0 on success and a negative value on error - * Configure the Tx VSI for operation. - */ -static int -ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_tx_ring **rings, u16 count) -{ - DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1); - int err = 0; - u16 q_idx; - - qg_buf->num_txqs = 1; - - for (q_idx = 0; q_idx < count; q_idx++) { - err = ice_vsi_cfg_txq(vsi, rings[q_idx], qg_buf); - if (err) - break; - } - - return err; -} - -/** - * ice_vsi_cfg_lan_txqs - Configure the VSI for Tx - * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error - * Configure the Tx VSI for operation. - */ -int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) -{ - return ice_vsi_cfg_txqs(vsi, vsi->tx_rings, vsi->num_txq); -} - -/** - * ice_vsi_cfg_xdp_txqs - Configure Tx queues dedicated for XDP in given VSI - * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error - * Configure the Tx queues dedicated for XDP in given VSI for operation. - */ -int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi) -{ - int ret; - int i; - - ret = ice_vsi_cfg_txqs(vsi, vsi->xdp_rings, vsi->num_xdp_txq); - if (ret) - return ret; - - ice_for_each_rxq(vsi, i) - ice_tx_xsk_pool(vsi, i); - - return 0; -} - /** * ice_intrl_usec_to_reg - convert interrupt rate limit to register value * @intrl: interrupt rate limit in usecs diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 6ffe4b0603bd..0c77d581416a 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -54,10 +54,6 @@ bool ice_pf_state_is_nominal(struct ice_pf *pf); void ice_update_eth_stats(struct ice_vsi *vsi); -int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, u16 q_idx); - -int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi); - void ice_vsi_cfg_msix(struct ice_vsi *vsi); int ice_vsi_start_all_rx_rings(struct ice_vsi *vsi); @@ -68,8 +64,6 @@ int ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, u16 rel_vmvf_num); -int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi); - int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi); void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create); diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index 617e4d14d46e..8a051420fa19 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -217,32 +217,17 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx) */ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx) { - DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1); - u16 size = __struct_size(qg_buf); struct ice_q_vector *q_vector; - struct ice_tx_ring *tx_ring; - struct ice_rx_ring *rx_ring; int err; - if (q_idx >= vsi->num_rxq || q_idx >= vsi->num_txq) - return -EINVAL; - - qg_buf->num_txqs = 1; - - tx_ring = vsi->tx_rings[q_idx]; - rx_ring = vsi->rx_rings[q_idx]; - q_vector = rx_ring->q_vector; - - err = ice_vsi_cfg_txq(vsi, tx_ring, qg_buf); + err = ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx); if (err) return err; if (ice_is_xdp_ena_vsi(vsi)) { struct ice_tx_ring *xdp_ring = vsi->xdp_rings[q_idx]; - memset(qg_buf, 0, size); - qg_buf->num_txqs = 1; - err = ice_vsi_cfg_txq(vsi, xdp_ring, qg_buf); + err = ice_vsi_cfg_single_txq(vsi, vsi->xdp_rings, q_idx); if (err) return err; ice_set_ring_xdp(xdp_ring); @@ -253,6 +238,7 @@ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx) if (err) return err; + q_vector = vsi->rx_rings[q_idx]->q_vector; ice_qvec_cfg_msix(vsi, q_vector); err = ice_vsi_ctrl_one_rx_ring(vsi, true, q_idx, true); From 0ca6755f3cc203bdd357602d9aa29dfb0f62682d Mon Sep 17 00:00:00 2001 From: Aniruddha Paul Date: Wed, 3 Jan 2024 15:11:15 +0100 Subject: [PATCH 0685/2255] ice: Add a new counter for Rx EIPE errors HW incorrectly reports EIPE errors on encapsulated packets with L2 padding inside inner packet. HW shows outer UDP/IPV4 packet checksum errors as part of the EIPE flags of the Rx descriptor. These are reported only if checksum offload is enabled and L3/L4 parsed flag is valid in Rx descriptor. When that error is reported by HW, we don't act on it instead of incrementing main Rx errors statistic as it would normally happen. Add a new statistic to count these errors since we still want to print them. Signed-off-by: Aniruddha Paul Reviewed-by: Przemek Kitszel Reviewed-by: Jan Glaza Signed-off-by: Jan Sokolowski Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 1 + drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 8 ++++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 97c2a5fb5dbf..a4ba60e17d0b 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -605,6 +605,7 @@ struct ice_pf { wait_queue_head_t reset_wait_queue; u32 hw_csum_rx_error; + u32 hw_rx_eipe_error; u32 oicr_err_reg; struct msi_map oicr_irq; /* Other interrupt cause MSIX vector */ struct msi_map ll_ts_irq; /* LL_TS interrupt MSIX vector */ diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 55fcf17d503e..3cc364a4d682 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -129,6 +129,7 @@ static const struct ice_stats ice_gstrings_pf_stats[] = { ICE_PF_STAT("rx_oversize.nic", stats.rx_oversize), ICE_PF_STAT("rx_jabber.nic", stats.rx_jabber), ICE_PF_STAT("rx_csum_bad.nic", hw_csum_rx_error), + ICE_PF_STAT("rx_eipe_error.nic", hw_rx_eipe_error), ICE_PF_STAT("rx_dropped.nic", stats.eth.rx_discards), ICE_PF_STAT("rx_crc_errors.nic", stats.crc_errors), ICE_PF_STAT("illegal_bytes.nic", stats.illegal_bytes), diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c index 839e5da24ad5..f8f1d2bdc1be 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c @@ -143,8 +143,12 @@ ice_rx_csum(struct ice_rx_ring *ring, struct sk_buff *skb, ipv6 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) && (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV6); - if (ipv4 && (rx_status0 & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S) | - BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S)))) + if (ipv4 && (rx_status0 & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S)))) { + ring->vsi->back->hw_rx_eipe_error++; + return; + } + + if (ipv4 && (rx_status0 & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S)))) goto checksum_fail; if (ipv6 && (rx_status0 & (BIT(ICE_RX_FLEX_DESC_STATUS0_IPV6EXADD_S)))) From 53875f05c9970c5cad725519cd2b28d6d4a57666 Mon Sep 17 00:00:00 2001 From: Paul M Stillwell Jr Date: Mon, 22 Jan 2024 10:24:17 -0800 Subject: [PATCH 0686/2255] ice: remove incorrect comment Copy paste issue left a comment for this structure that has nothing to do with FW alignment; remove the comment. Reviewed-by: Przemek Kitszel Signed-off-by: Paul M Stillwell Jr Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_debugfs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_debugfs.c b/drivers/net/ethernet/intel/ice/ice_debugfs.c index c2bfba6b9ead..85aa31dd86b1 100644 --- a/drivers/net/ethernet/intel/ice/ice_debugfs.c +++ b/drivers/net/ethernet/intel/ice/ice_debugfs.c @@ -64,9 +64,6 @@ static const char * const ice_fwlog_level_string[] = { "verbose", }; -/* the order in this array is important. it matches the ordering of the - * values in the FW so the index is the same value as in ice_fwlog_level - */ static const char * const ice_fwlog_log_size[] = { "128K", "256K", From b26577001af49a20f09770fd6e6cfd10d5daac93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Thu, 1 Feb 2024 14:09:40 +0100 Subject: [PATCH 0687/2255] net/sched: Add helper macros with module names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macros are preparation for adding module aliases en mass in a separate commit. Although it would be tempting to create aliases like cls-foo for name cls_foo, this could not be used because modprobe utilities treat '-' and '_' interchangeably. In the end, the naming follows pattern of proto modules in linux/net.h. Signed-off-by: Michal Koutný Acked-by: Jamal Hadi Salim Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240201130943.19536-2-mkoutny@suse.com Signed-off-by: Jakub Kicinski --- include/net/act_api.h | 2 ++ include/net/pkt_cls.h | 2 ++ include/net/pkt_sched.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/include/net/act_api.h b/include/net/act_api.h index e1e5e72b901e..77ee0c657e2c 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -201,6 +201,8 @@ int tcf_idr_release(struct tc_action *a, bool bind); int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops); int tcf_unregister_action(struct tc_action_ops *a, struct pernet_operations *ops); +#define NET_ACT_ALIAS_PREFIX "net-act-" +#define MODULE_ALIAS_NET_ACT(kind) MODULE_ALIAS(NET_ACT_ALIAS_PREFIX kind) int tcf_action_destroy(struct tc_action *actions[], int bind); int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, int nr_actions, struct tcf_result *res); diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index f308e8268651..a4ee43f493bb 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -24,6 +24,8 @@ struct tcf_walker { int register_tcf_proto_ops(struct tcf_proto_ops *ops); void unregister_tcf_proto_ops(struct tcf_proto_ops *ops); +#define NET_CLS_ALIAS_PREFIX "net-cls-" +#define MODULE_ALIAS_NET_CLS(kind) MODULE_ALIAS(NET_CLS_ALIAS_PREFIX kind) struct tcf_block_ext_info { enum flow_block_binder_type binder_type; diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 1e200d9a066d..d7b7b6cd4aa1 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -100,6 +100,8 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, int register_qdisc(struct Qdisc_ops *qops); void unregister_qdisc(struct Qdisc_ops *qops); +#define NET_SCH_ALIAS_PREFIX "net-sch-" +#define MODULE_ALIAS_NET_SCH(id) MODULE_ALIAS(NET_SCH_ALIAS_PREFIX id) void qdisc_get_default(char *id, size_t len); int qdisc_set_default(const char *id); From 241a94abcf465ba9363d93168da5ddd47002930f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Thu, 1 Feb 2024 14:09:41 +0100 Subject: [PATCH 0688/2255] net/sched: Add module aliases for cls_,sch_,act_ modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change intended, aliases will be used in followup commits. Note for backporters: you may need to add aliases also for modules that are already removed in mainline kernel but still in your version. Patches were generated with the help of Coccinelle scripts like: cat >scripts/coccinelle/misc/tcf_alias.cocci </dev/null | \ sed 's/char module_alias = "\([^"]*\)";/MODULE_ALIAS_NET_CLS("\1");/' And analogously for: static struct tc_action_ops ops = { .kind = K, static struct Qdisc_ops ops = { .id = K, (Someone familiar would be able to fit those into one .cocci file without sed post processing.) Signed-off-by: Michal Koutný Acked-by: Jamal Hadi Salim Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240201130943.19536-3-mkoutny@suse.com Signed-off-by: Jakub Kicinski --- net/sched/act_bpf.c | 1 + net/sched/act_connmark.c | 1 + net/sched/act_csum.c | 1 + net/sched/act_ct.c | 1 + net/sched/act_ctinfo.c | 1 + net/sched/act_gact.c | 1 + net/sched/act_gate.c | 1 + net/sched/act_ife.c | 1 + net/sched/act_mirred.c | 1 + net/sched/act_mpls.c | 1 + net/sched/act_nat.c | 1 + net/sched/act_pedit.c | 1 + net/sched/act_police.c | 1 + net/sched/act_sample.c | 1 + net/sched/act_simple.c | 1 + net/sched/act_skbedit.c | 1 + net/sched/act_skbmod.c | 1 + net/sched/act_tunnel_key.c | 1 + net/sched/act_vlan.c | 1 + net/sched/cls_basic.c | 1 + net/sched/cls_bpf.c | 1 + net/sched/cls_cgroup.c | 1 + net/sched/cls_flow.c | 1 + net/sched/cls_flower.c | 1 + net/sched/cls_fw.c | 1 + net/sched/cls_matchall.c | 1 + net/sched/cls_route.c | 1 + net/sched/cls_u32.c | 1 + net/sched/sch_cake.c | 1 + net/sched/sch_cbs.c | 1 + net/sched/sch_choke.c | 1 + net/sched/sch_codel.c | 1 + net/sched/sch_drr.c | 1 + net/sched/sch_etf.c | 1 + net/sched/sch_ets.c | 1 + net/sched/sch_fq.c | 1 + net/sched/sch_fq_codel.c | 1 + net/sched/sch_gred.c | 1 + net/sched/sch_hfsc.c | 1 + net/sched/sch_hhf.c | 1 + net/sched/sch_htb.c | 1 + net/sched/sch_ingress.c | 2 ++ net/sched/sch_mqprio.c | 1 + net/sched/sch_multiq.c | 1 + net/sched/sch_netem.c | 1 + net/sched/sch_pie.c | 1 + net/sched/sch_plug.c | 1 + net/sched/sch_prio.c | 1 + net/sched/sch_qfq.c | 1 + net/sched/sch_red.c | 1 + net/sched/sch_sfb.c | 1 + net/sched/sch_sfq.c | 1 + net/sched/sch_skbprio.c | 1 + net/sched/sch_taprio.c | 1 + net/sched/sch_tbf.c | 1 + 55 files changed, 56 insertions(+) diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 6cfee6658103..0e3cf11ae5fc 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -401,6 +401,7 @@ static struct tc_action_ops act_bpf_ops __read_mostly = { .init = tcf_bpf_init, .size = sizeof(struct tcf_bpf), }; +MODULE_ALIAS_NET_ACT("bpf"); static __net_init int bpf_init_net(struct net *net) { diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c index f8762756657d..0fce631e7c91 100644 --- a/net/sched/act_connmark.c +++ b/net/sched/act_connmark.c @@ -242,6 +242,7 @@ static struct tc_action_ops act_connmark_ops = { .cleanup = tcf_connmark_cleanup, .size = sizeof(struct tcf_connmark_info), }; +MODULE_ALIAS_NET_ACT("connmark"); static __net_init int connmark_init_net(struct net *net) { diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 7f8b1f2f2ed9..5cc8e407e791 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -709,6 +709,7 @@ static struct tc_action_ops act_csum_ops = { .offload_act_setup = tcf_csum_offload_act_setup, .size = sizeof(struct tcf_csum), }; +MODULE_ALIAS_NET_ACT("csum"); static __net_init int csum_init_net(struct net *net) { diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index 6124d8b128d1..baac083fd8f1 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -1600,6 +1600,7 @@ static struct tc_action_ops act_ct_ops = { .offload_act_setup = tcf_ct_offload_act_setup, .size = sizeof(struct tcf_ct), }; +MODULE_ALIAS_NET_ACT("ct"); static __net_init int ct_init_net(struct net *net) { diff --git a/net/sched/act_ctinfo.c b/net/sched/act_ctinfo.c index e620f9a84afe..5dd41a012110 100644 --- a/net/sched/act_ctinfo.c +++ b/net/sched/act_ctinfo.c @@ -363,6 +363,7 @@ static struct tc_action_ops act_ctinfo_ops = { .cleanup= tcf_ctinfo_cleanup, .size = sizeof(struct tcf_ctinfo), }; +MODULE_ALIAS_NET_ACT("ctinfo"); static __net_init int ctinfo_init_net(struct net *net) { diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 4af3b7ec249f..e949280eb800 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -296,6 +296,7 @@ static struct tc_action_ops act_gact_ops = { .offload_act_setup = tcf_gact_offload_act_setup, .size = sizeof(struct tcf_gact), }; +MODULE_ALIAS_NET_ACT("gact"); static __net_init int gact_init_net(struct net *net) { diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index c681cd011afd..1dd74125398a 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -645,6 +645,7 @@ static struct tc_action_ops act_gate_ops = { .offload_act_setup = tcf_gate_offload_act_setup, .size = sizeof(struct tcf_gate), }; +MODULE_ALIAS_NET_ACT("gate"); static __net_init int gate_init_net(struct net *net) { diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index 0e867d13beb5..107c6d83dc5c 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -889,6 +889,7 @@ static struct tc_action_ops act_ife_ops = { .init = tcf_ife_init, .size = sizeof(struct tcf_ife_info), }; +MODULE_ALIAS_NET_ACT("ife"); static __net_init int ife_init_net(struct net *net) { diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 12386f590b0f..93a96e9d8d90 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -643,6 +643,7 @@ static struct tc_action_ops act_mirred_ops = { .size = sizeof(struct tcf_mirred), .get_dev = tcf_mirred_get_dev, }; +MODULE_ALIAS_NET_ACT("mirred"); static __net_init int mirred_init_net(struct net *net) { diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c index 34b8edb6cc77..44a37a71ae92 100644 --- a/net/sched/act_mpls.c +++ b/net/sched/act_mpls.c @@ -452,6 +452,7 @@ static struct tc_action_ops act_mpls_ops = { .offload_act_setup = tcf_mpls_offload_act_setup, .size = sizeof(struct tcf_mpls), }; +MODULE_ALIAS_NET_ACT("mpls"); static __net_init int mpls_init_net(struct net *net) { diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index a180e724634e..d541f553805f 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -324,6 +324,7 @@ static struct tc_action_ops act_nat_ops = { .cleanup = tcf_nat_cleanup, .size = sizeof(struct tcf_nat), }; +MODULE_ALIAS_NET_ACT("nat"); static __net_init int nat_init_net(struct net *net) { diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 2ef22969f274..df5a02d5f919 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -620,6 +620,7 @@ static struct tc_action_ops act_pedit_ops = { .offload_act_setup = tcf_pedit_offload_act_setup, .size = sizeof(struct tcf_pedit), }; +MODULE_ALIAS_NET_ACT("pedit"); static __net_init int pedit_init_net(struct net *net) { diff --git a/net/sched/act_police.c b/net/sched/act_police.c index e119b4a3db9f..8555125ed34d 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -502,6 +502,7 @@ static struct tc_action_ops act_police_ops = { .offload_act_setup = tcf_police_offload_act_setup, .size = sizeof(struct tcf_police), }; +MODULE_ALIAS_NET_ACT("police"); static __net_init int police_init_net(struct net *net) { diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index c5c61efe6db4..a69b53d54039 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -316,6 +316,7 @@ static struct tc_action_ops act_sample_ops = { .offload_act_setup = tcf_sample_offload_act_setup, .size = sizeof(struct tcf_sample), }; +MODULE_ALIAS_NET_ACT("sample"); static __net_init int sample_init_net(struct net *net) { diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 0a3e92888295..f3abe0545989 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -209,6 +209,7 @@ static struct tc_action_ops act_simp_ops = { .init = tcf_simp_init, .size = sizeof(struct tcf_defact), }; +MODULE_ALIAS_NET_ACT("simple"); static __net_init int simp_init_net(struct net *net) { diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 754f78b35bb8..1f1d9ce3e968 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -426,6 +426,7 @@ static struct tc_action_ops act_skbedit_ops = { .offload_act_setup = tcf_skbedit_offload_act_setup, .size = sizeof(struct tcf_skbedit), }; +MODULE_ALIAS_NET_ACT("skbedit"); static __net_init int skbedit_init_net(struct net *net) { diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index bcb673ab0008..39945b139c48 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -287,6 +287,7 @@ static struct tc_action_ops act_skbmod_ops = { .cleanup = tcf_skbmod_cleanup, .size = sizeof(struct tcf_skbmod), }; +MODULE_ALIAS_NET_ACT("skbmod"); static __net_init int skbmod_init_net(struct net *net) { diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index 300b08aa8283..1536f8b16f1b 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -842,6 +842,7 @@ static struct tc_action_ops act_tunnel_key_ops = { .offload_act_setup = tcf_tunnel_key_offload_act_setup, .size = sizeof(struct tcf_tunnel_key), }; +MODULE_ALIAS_NET_ACT("tunnel_key"); static __net_init int tunnel_key_init_net(struct net *net) { diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index 836183011a7c..22f4b1e8ade9 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -427,6 +427,7 @@ static struct tc_action_ops act_vlan_ops = { .offload_act_setup = tcf_vlan_offload_act_setup, .size = sizeof(struct tcf_vlan), }; +MODULE_ALIAS_NET_ACT("vlan"); static __net_init int vlan_init_net(struct net *net) { diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index a1f56931330c..ecfaa4f9a04e 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c @@ -328,6 +328,7 @@ static struct tcf_proto_ops cls_basic_ops __read_mostly = { .bind_class = basic_bind_class, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_CLS("basic"); static int __init init_basic(void) { diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 382c7a71f81f..5e83e890f6a4 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -693,6 +693,7 @@ static struct tcf_proto_ops cls_bpf_ops __read_mostly = { .dump = cls_bpf_dump, .bind_class = cls_bpf_bind_class, }; +MODULE_ALIAS_NET_CLS("bpf"); static int __init cls_bpf_init_mod(void) { diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 7ee8dbf49ed0..424252982d6a 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -209,6 +209,7 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { .dump = cls_cgroup_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_CLS("cgroup"); static int __init init_cgroup_cls(void) { diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 6ab317b48d6c..5502998aace7 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -702,6 +702,7 @@ static struct tcf_proto_ops cls_flow_ops __read_mostly = { .walk = flow_walk, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_CLS("flow"); static int __init cls_flow_init(void) { diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index efb9d2811b73..bfedc3d4423d 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -3656,6 +3656,7 @@ static struct tcf_proto_ops cls_fl_ops __read_mostly = { .owner = THIS_MODULE, .flags = TCF_PROTO_OPS_DOIT_UNLOCKED, }; +MODULE_ALIAS_NET_CLS("flower"); static int __init cls_fl_init(void) { diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index afc534ee0a18..cdddc8695228 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -433,6 +433,7 @@ static struct tcf_proto_ops cls_fw_ops __read_mostly = { .bind_class = fw_bind_class, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_CLS("fw"); static int __init init_fw(void) { diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c index c4ed11df6254..9f1e62ca508d 100644 --- a/net/sched/cls_matchall.c +++ b/net/sched/cls_matchall.c @@ -398,6 +398,7 @@ static struct tcf_proto_ops cls_mall_ops __read_mostly = { .bind_class = mall_bind_class, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_CLS("matchall"); static int __init cls_mall_init(void) { diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 12a505db4183..b9c58c040c30 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -671,6 +671,7 @@ static struct tcf_proto_ops cls_route4_ops __read_mostly = { .bind_class = route4_bind_class, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_CLS("route"); static int __init init_route4(void) { diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 289e1755c26b..9412d88a99bc 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -1453,6 +1453,7 @@ static struct tcf_proto_ops cls_u32_ops __read_mostly = { .bind_class = u32_bind_class, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_CLS("u32"); static int __init init_u32(void) { diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 9cff99558694..edee926ccde8 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -3103,6 +3103,7 @@ static struct Qdisc_ops cake_qdisc_ops __read_mostly = { .dump_stats = cake_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("cake"); static int __init cake_module_init(void) { diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index beece8e82c23..69001eff0315 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -546,6 +546,7 @@ static struct Qdisc_ops cbs_qdisc_ops __read_mostly = { .dump = cbs_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("cbs"); static struct notifier_block cbs_device_notifier = { .notifier_call = cbs_dev_notifier, diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index ae1da08e268f..ea108030c6b4 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -498,6 +498,7 @@ static struct Qdisc_ops choke_qdisc_ops __read_mostly = { .dump_stats = choke_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("choke"); static int __init choke_module_init(void) { diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index d7a4874543de..61904d3a593b 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -287,6 +287,7 @@ static struct Qdisc_ops codel_qdisc_ops __read_mostly = { .dump_stats = codel_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("codel"); static int __init codel_module_init(void) { diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 097740a9afea..c69b999fae17 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -481,6 +481,7 @@ static struct Qdisc_ops drr_qdisc_ops __read_mostly = { .destroy = drr_destroy_qdisc, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("drr"); static int __init drr_init(void) { diff --git a/net/sched/sch_etf.c b/net/sched/sch_etf.c index 4808159a5466..2e4bef713b6a 100644 --- a/net/sched/sch_etf.c +++ b/net/sched/sch_etf.c @@ -500,6 +500,7 @@ static struct Qdisc_ops etf_qdisc_ops __read_mostly = { .dump = etf_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("etf"); static int __init etf_module_init(void) { diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c index f7c88495946b..835b4460b448 100644 --- a/net/sched/sch_ets.c +++ b/net/sched/sch_ets.c @@ -812,6 +812,7 @@ static struct Qdisc_ops ets_qdisc_ops __read_mostly = { .dump = ets_qdisc_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("ets"); static int __init ets_init(void) { diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 3a31c47fea9b..cdf23ff16f40 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -1264,6 +1264,7 @@ static struct Qdisc_ops fq_qdisc_ops __read_mostly = { .dump_stats = fq_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("fq"); static int __init fq_module_init(void) { diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 8c4fee063436..79f9d6de6c85 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -717,6 +717,7 @@ static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { .dump_stats = fq_codel_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("fq_codel"); static int __init fq_codel_module_init(void) { diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index 8c61eb3dc943..79ba9dc70254 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -930,6 +930,7 @@ static struct Qdisc_ops gred_qdisc_ops __read_mostly = { .dump = gred_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("gred"); static int __init gred_module_init(void) { diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 16c45da4036a..4e626df742d7 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1679,6 +1679,7 @@ static struct Qdisc_ops hfsc_qdisc_ops __read_mostly = { .priv_size = sizeof(struct hfsc_sched), .owner = THIS_MODULE }; +MODULE_ALIAS_NET_SCH("hfsc"); static int __init hfsc_init(void) diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index d26cd436cbe3..3f906df1435b 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -702,6 +702,7 @@ static struct Qdisc_ops hhf_qdisc_ops __read_mostly = { .dump_stats = hhf_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("hhf"); static int __init hhf_module_init(void) { diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 7349233eaa9b..93e6fb56f3b5 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -2166,6 +2166,7 @@ static struct Qdisc_ops htb_qdisc_ops __read_mostly = { .dump = htb_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("htb"); static int __init htb_module_init(void) { diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 5fa9eaa79bfc..48a800131e99 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -168,6 +168,7 @@ static struct Qdisc_ops ingress_qdisc_ops __read_mostly = { .ingress_block_get = ingress_ingress_block_get, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("ingress"); struct clsact_sched_data { struct tcf_block *ingress_block; @@ -344,6 +345,7 @@ static struct Qdisc_ops clsact_qdisc_ops __read_mostly = { .egress_block_get = clsact_egress_block_get, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("clsact"); static int __init ingress_module_init(void) { diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index 43e53ee00a56..225353fbb3f1 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -774,6 +774,7 @@ static struct Qdisc_ops mqprio_qdisc_ops __read_mostly = { .dump = mqprio_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("mqprio"); static int __init mqprio_module_init(void) { diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index d66d5f0ec080..79e93a19d5fa 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -395,6 +395,7 @@ static struct Qdisc_ops multiq_qdisc_ops __read_mostly = { .dump = multiq_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("multiq"); static int __init multiq_module_init(void) { diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index fa678eb88528..edc72962ae63 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -1293,6 +1293,7 @@ static struct Qdisc_ops netem_qdisc_ops __read_mostly = { .dump = netem_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("netem"); static int __init netem_module_init(void) diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index 2da6250ec346..1764059b0635 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -556,6 +556,7 @@ static struct Qdisc_ops pie_qdisc_ops __read_mostly = { .dump_stats = pie_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("pie"); static int __init pie_module_init(void) { diff --git a/net/sched/sch_plug.c b/net/sched/sch_plug.c index 992f0c8d7988..cefb65201e17 100644 --- a/net/sched/sch_plug.c +++ b/net/sched/sch_plug.c @@ -213,6 +213,7 @@ static struct Qdisc_ops plug_qdisc_ops __read_mostly = { .reset = qdisc_reset_queue, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("plug"); static int __init plug_module_init(void) { diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 8ecdd3ef6f8e..cc30f7a32f1a 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -418,6 +418,7 @@ static struct Qdisc_ops prio_qdisc_ops __read_mostly = { .dump = prio_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("prio"); static int __init prio_module_init(void) { diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 48a604c320c7..d584c0c25899 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1521,6 +1521,7 @@ static struct Qdisc_ops qfq_qdisc_ops __read_mostly = { .destroy = qfq_destroy_qdisc, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("qfq"); static int __init qfq_init(void) { diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 607b6c8b3a9b..b5f096588fae 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -548,6 +548,7 @@ static struct Qdisc_ops red_qdisc_ops __read_mostly = { .dump_stats = red_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("red"); static int __init red_module_init(void) { diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 1871a1c0224d..b717e15a3a17 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -709,6 +709,7 @@ static struct Qdisc_ops sfb_qdisc_ops __read_mostly = { .dump_stats = sfb_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("sfb"); static int __init sfb_module_init(void) { diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index eb77558fa367..e66f4afb920d 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -925,6 +925,7 @@ static struct Qdisc_ops sfq_qdisc_ops __read_mostly = { .dump = sfq_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("sfq"); static int __init sfq_module_init(void) { diff --git a/net/sched/sch_skbprio.c b/net/sched/sch_skbprio.c index 28beb11762d8..b4dd626c309c 100644 --- a/net/sched/sch_skbprio.c +++ b/net/sched/sch_skbprio.c @@ -292,6 +292,7 @@ static struct Qdisc_ops skbprio_qdisc_ops __read_mostly = { .destroy = skbprio_destroy, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("skbprio"); static int __init skbprio_module_init(void) { diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 827cb683efbf..c5de70efdc86 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -2528,6 +2528,7 @@ static struct Qdisc_ops taprio_qdisc_ops __read_mostly = { .dump_stats = taprio_dump_stats, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("taprio"); static struct notifier_block taprio_device_notifier = { .notifier_call = taprio_dev_notifier, diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index dd6b1a723bf7..f1d09183ae63 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -608,6 +608,7 @@ static struct Qdisc_ops tbf_qdisc_ops __read_mostly = { .dump = tbf_dump, .owner = THIS_MODULE, }; +MODULE_ALIAS_NET_SCH("tbf"); static int __init tbf_module_init(void) { From 2c15a5aee2f32e341d1585fa1867eece76a1edb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Thu, 1 Feb 2024 14:09:42 +0100 Subject: [PATCH 0689/2255] net/sched: Load modules via their alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cls_,sch_,act_ modules may be loaded lazily during network configuration but without user's awareness and control. Switch the lazy loading from canonical module names to a module alias. This allows finer control over lazy loading, the precedent from commit 7f78e0351394 ("fs: Limit sys_mount to only request filesystem modules.") explains it already: Using aliases means user space can control the policy of which filesystem^W net/sched modules are auto-loaded by editing /etc/modprobe.d/*.conf with blacklist and alias directives. Allowing simple, safe, well understood work-arounds to known problematic software. By default, nothing changes. However, if a specific module is blacklisted (its canonical name), it won't be modprobe'd when requested under its alias (i.e. kernel auto-loading). It would appear as if the given module was unknown. The module can still be loaded under its canonical name, which is an explicit (privileged) user action. Signed-off-by: Michal Koutný Acked-by: Jamal Hadi Salim Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240201130943.19536-4-mkoutny@suse.com Signed-off-by: Jakub Kicinski --- net/sched/act_api.c | 2 +- net/sched/cls_api.c | 2 +- net/sched/sch_api.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 3e30d7260493..9ee622fb1160 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1363,7 +1363,7 @@ struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, u32 flags, if (rtnl_held) rtnl_unlock(); - request_module("act_%s", act_name); + request_module(NET_ACT_ALIAS_PREFIX "%s", act_name); if (rtnl_held) rtnl_lock(); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index ff3d396a65aa..ca5676b2668e 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -257,7 +257,7 @@ tcf_proto_lookup_ops(const char *kind, bool rtnl_held, #ifdef CONFIG_MODULES if (rtnl_held) rtnl_unlock(); - request_module("cls_%s", kind); + request_module(NET_CLS_ALIAS_PREFIX "%s", kind); if (rtnl_held) rtnl_lock(); ops = __tcf_proto_lookup_ops(kind); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 36b025cc4fd2..9d928f6a473a 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -228,7 +228,7 @@ int qdisc_set_default(const char *name) if (!ops) { /* Not found, drop lock and try to load module */ write_unlock(&qdisc_mod_lock); - request_module("sch_%s", name); + request_module(NET_SCH_ALIAS_PREFIX "%s", name); write_lock(&qdisc_mod_lock); ops = qdisc_lookup_default(name); @@ -1275,7 +1275,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, * go away in the mean time. */ rtnl_unlock(); - request_module("sch_%s", name); + request_module(NET_SCH_ALIAS_PREFIX "%s", name); rtnl_lock(); ops = qdisc_lookup_ops(kind); if (ops != NULL) { From 6cff015817890a97311a10d3482906cfb67f14bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Thu, 1 Feb 2024 14:09:43 +0100 Subject: [PATCH 0690/2255] net/sched: Remove alias of sch_clsact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The module sch_ingress stands out among net/sched modules because it provides multiple act/sch functionalities in a single .ko. They have aliases to make autoloading work for any of the provided functionalities. Since the autoloading was changed to uniformly request any functionality under its alias, the non-systemic aliases can be removed now (i.e. assuming the alias were only used to ensure autoloading). Signed-off-by: Michal Koutný Acked-by: Jamal Hadi Salim Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240201130943.19536-5-mkoutny@suse.com Signed-off-by: Jakub Kicinski --- net/sched/sch_ingress.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 48a800131e99..c2ef9dcf91d2 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -370,6 +370,5 @@ static void __exit ingress_module_exit(void) module_init(ingress_module_init); module_exit(ingress_module_exit); -MODULE_ALIAS("sch_clsact"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Ingress and clsact based ingress and egress qdiscs"); From e67ddd9b1cff7872d43ead73a1403c4e532003d9 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Sat, 27 Jan 2024 19:52:32 +0200 Subject: [PATCH 0691/2255] bpf: Track spilled unbounded scalars Support the pattern where an unbounded scalar is spilled to the stack, then boundary checks are performed on the src register, after which the stack frame slot is refilled into a register. Before this commit, the verifier didn't treat the src register and the stack slot as related if the src register was an unbounded scalar. The register state wasn't copied, the id wasn't preserved, and the stack slot was marked as STACK_MISC. Subsequent boundary checks on the src register wouldn't result in updating the boundaries of the spilled variable on the stack. After this commit, the verifier will preserve the bond between src and dst even if src is unbounded, which permits to do boundary checks on src and refill dst later, still remembering its boundaries. Such a pattern is sometimes generated by clang when compiling complex long functions. One test is adjusted to reflect that now unbounded scalars are tracked. Signed-off-by: Maxim Mikityanskiy Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240127175237.526726-2-maxtram95@gmail.com --- kernel/bpf/verifier.c | 16 +--------------- .../selftests/bpf/progs/verifier_spill_fill.c | 6 +++--- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index cd4d780e5400..28f62f24da7e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4380,20 +4380,6 @@ static u64 reg_const_value(struct bpf_reg_state *reg, bool subreg32) return subreg32 ? tnum_subreg(reg->var_off).value : reg->var_off.value; } -static bool __is_scalar_unbounded(struct bpf_reg_state *reg) -{ - return tnum_is_unknown(reg->var_off) && - reg->smin_value == S64_MIN && reg->smax_value == S64_MAX && - reg->umin_value == 0 && reg->umax_value == U64_MAX && - reg->s32_min_value == S32_MIN && reg->s32_max_value == S32_MAX && - reg->u32_min_value == 0 && reg->u32_max_value == U32_MAX; -} - -static bool register_is_bounded(struct bpf_reg_state *reg) -{ - return reg->type == SCALAR_VALUE && !__is_scalar_unbounded(reg); -} - static bool __is_pointer_value(bool allow_ptr_leaks, const struct bpf_reg_state *reg) { @@ -4504,7 +4490,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, return err; mark_stack_slot_scratched(env, spi); - if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && env->bpf_capable) { + if (reg && !(off % BPF_REG_SIZE) && reg->type == SCALAR_VALUE && env->bpf_capable) { bool reg_value_fits; reg_value_fits = get_reg_width(reg) <= BITS_PER_BYTE * size; diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 7013a9694163..317806451762 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -452,9 +452,9 @@ l0_%=: r1 >>= 16; \ SEC("raw_tp") __log_level(2) __success -__msg("fp-8=0m??mmmm") -__msg("fp-16=00mm??mm") -__msg("fp-24=00mm???m") +__msg("fp-8=0m??scalar()") +__msg("fp-16=00mm??scalar()") +__msg("fp-24=00mm???scalar()") __naked void spill_subregs_preserve_stack_zero(void) { asm volatile ( From 6be503cec6c9bccd64f72c03697011d2e2b96fc3 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Sat, 27 Jan 2024 19:52:33 +0200 Subject: [PATCH 0692/2255] selftests/bpf: Test tracking spilled unbounded scalars The previous commit added tracking for unbounded scalars on spill. Add the test case to check the new functionality. Signed-off-by: Maxim Mikityanskiy Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240127175237.526726-3-maxtram95@gmail.com --- .../selftests/bpf/progs/verifier_spill_fill.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 317806451762..f9803005e1c0 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -940,4 +940,31 @@ l0_%=: r0 = 0; \ : __clobber_all); } +SEC("xdp") +__description("spill unbounded reg, then range check src") +__success __retval(0) +__naked void spill_unbounded(void) +{ + asm volatile (" \ + /* Produce an unbounded scalar. */ \ + call %[bpf_get_prandom_u32]; \ + /* Spill r0 to stack. */ \ + *(u64*)(r10 - 8) = r0; \ + /* Boundary check on r0. */ \ + if r0 > 16 goto l0_%=; \ + /* Fill r0 from stack. */ \ + r0 = *(u64*)(r10 - 8); \ + /* Boundary check on r0 with predetermined result. */\ + if r0 <= 16 goto l0_%=; \ + /* Dead branch: the verifier should prune it. Do an invalid memory\ + * access if the verifier follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; From c1e6148cb4f83cec841db1f066e8db4a86c1f118 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Sat, 27 Jan 2024 19:52:34 +0200 Subject: [PATCH 0693/2255] bpf: Preserve boundaries and track scalars on narrowing fill When the width of a fill is smaller than the width of the preceding spill, the information about scalar boundaries can still be preserved, as long as it's coerced to the right width (done by coerce_reg_to_size). Even further, if the actual value fits into the fill width, the ID can be preserved as well for further tracking of equal scalars. Implement the above improvements, which makes narrowing fills behave the same as narrowing spills and MOVs between registers. Two tests are adjusted to accommodate for endianness differences and to take into account that it's now allowed to do a narrowing fill from the least significant bits. reg_bounds_sync is added to coerce_reg_to_size to correctly adjust umin/umax boundaries after the var_off truncation, for example, a 64-bit value 0xXXXXXXXX00000000, when read as a 32-bit, gets umin = 0, umax = 0xFFFFFFFF, var_off = (0x0; 0xffffffff00000000), which needs to be synced down to umax = 0, otherwise reg_bounds_sanity_check doesn't pass. Signed-off-by: Maxim Mikityanskiy Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240127175237.526726-4-maxtram95@gmail.com --- include/linux/bpf_verifier.h | 9 +++++++ kernel/bpf/verifier.c | 15 ++++++++--- .../selftests/bpf/progs/verifier_spill_fill.c | 26 ++++++++++++++----- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 0dcde339dc7e..84365e6dd85d 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -919,6 +919,15 @@ static inline void mark_verifier_state_scratched(struct bpf_verifier_env *env) env->scratched_stack_slots = ~0ULL; } +static inline bool bpf_stack_narrow_access_ok(int off, int fill_size, int spill_size) +{ +#ifdef __BIG_ENDIAN + off -= spill_size - fill_size; +#endif + + return !(off % BPF_REG_SIZE); +} + const char *reg_type_str(struct bpf_verifier_env *env, enum bpf_reg_type type); const char *dynptr_type_str(enum bpf_dynptr_type type); const char *iter_type_str(const struct btf *btf, u32 btf_id); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 28f62f24da7e..82af971926ac 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4778,7 +4778,8 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, if (dst_regno < 0) return 0; - if (!(off % BPF_REG_SIZE) && size == spill_size) { + if (size <= spill_size && + bpf_stack_narrow_access_ok(off, size, spill_size)) { /* The earlier check_reg_arg() has decided the * subreg_def for this insn. Save it first. */ @@ -4786,6 +4787,12 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, copy_register_state(&state->regs[dst_regno], reg); state->regs[dst_regno].subreg_def = subreg_def; + + /* Break the relation on a narrowing fill. + * coerce_reg_to_size will adjust the boundaries. + */ + if (get_reg_width(reg) > size * BITS_PER_BYTE) + state->regs[dst_regno].id = 0; } else { int spill_cnt = 0, zero_cnt = 0; @@ -6061,10 +6068,10 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) * values are also truncated so we push 64-bit bounds into * 32-bit bounds. Above were truncated < 32-bits already. */ - if (size < 4) { + if (size < 4) __mark_reg32_unbounded(reg); - reg_bounds_sync(reg); - } + + reg_bounds_sync(reg); } static void set_sext64_default_val(struct bpf_reg_state *reg, int size) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index f9803005e1c0..3e5d063ea7e8 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -217,7 +217,7 @@ __naked void uninit_u32_from_the_stack(void) SEC("tc") __description("Spill a u32 const scalar. Refill as u16. Offset to skb->data") -__failure __msg("invalid access to packet") +__success __retval(0) __naked void u16_offset_to_skb_data(void) { asm volatile (" \ @@ -225,13 +225,19 @@ __naked void u16_offset_to_skb_data(void) r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ w4 = 20; \ *(u32*)(r10 - 8) = r4; \ - r4 = *(u16*)(r10 - 8); \ + " +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + "r4 = *(u16*)(r10 - 8);" +#else + "r4 = *(u16*)(r10 - 6);" +#endif + " \ r0 = r2; \ - /* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=umax=65535 */\ + /* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=20 */\ r0 += r4; \ - /* if (r0 > r3) R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=umax=65535 */\ + /* if (r0 > r3) R0=pkt,off=20 R2=pkt R3=pkt_end R4=20 */\ if r0 > r3 goto l0_%=; \ - /* r0 = *(u32 *)r2 R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=20 */\ + /* r0 = *(u32 *)r2 R0=pkt,off=20 R2=pkt R3=pkt_end R4=20 */\ r0 = *(u32*)(r2 + 0); \ l0_%=: r0 = 0; \ exit; \ @@ -268,7 +274,7 @@ l0_%=: r0 = 0; \ } SEC("tc") -__description("Spill a u32 const scalar. Refill as u16 from fp-6. Offset to skb->data") +__description("Spill a u32 const scalar. Refill as u16 from MSB. Offset to skb->data") __failure __msg("invalid access to packet") __naked void _6_offset_to_skb_data(void) { @@ -277,7 +283,13 @@ __naked void _6_offset_to_skb_data(void) r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ w4 = 20; \ *(u32*)(r10 - 8) = r4; \ - r4 = *(u16*)(r10 - 6); \ + " +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + "r4 = *(u16*)(r10 - 6);" +#else + "r4 = *(u16*)(r10 - 8);" +#endif + " \ r0 = r2; \ /* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=umax=65535 */\ r0 += r4; \ From 067313a85c6f213932518f12f628810f0092492b Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Sat, 27 Jan 2024 19:52:35 +0200 Subject: [PATCH 0694/2255] selftests/bpf: Add test cases for narrowing fill The previous commit allowed to preserve boundaries and track IDs of scalars on narrowing fills. Add test cases for that pattern. Signed-off-by: Maxim Mikityanskiy Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240127175237.526726-5-maxtram95@gmail.com --- .../selftests/bpf/progs/verifier_spill_fill.c | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 3e5d063ea7e8..7f3b1319bd99 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -979,4 +979,115 @@ l0_%=: r0 = 0; \ : __clobber_all); } +SEC("xdp") +__description("32-bit fill after 64-bit spill") +__success __retval(0) +__naked void fill_32bit_after_spill_64bit(void) +{ + asm volatile(" \ + /* Randomize the upper 32 bits. */ \ + call %[bpf_get_prandom_u32]; \ + r0 <<= 32; \ + /* 64-bit spill r0 to stack. */ \ + *(u64*)(r10 - 8) = r0; \ + /* 32-bit fill r0 from stack. */ \ + " +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + "r0 = *(u32*)(r10 - 8);" +#else + "r0 = *(u32*)(r10 - 4);" +#endif + " \ + /* Boundary check on r0 with predetermined result. */\ + if r0 == 0 goto l0_%=; \ + /* Dead branch: the verifier should prune it. Do an invalid memory\ + * access if the verifier follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ +l0_%=: exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +SEC("xdp") +__description("32-bit fill after 64-bit spill of 32-bit value should preserve ID") +__success __retval(0) +__naked void fill_32bit_after_spill_64bit_preserve_id(void) +{ + asm volatile (" \ + /* Randomize the lower 32 bits. */ \ + call %[bpf_get_prandom_u32]; \ + w0 &= 0xffffffff; \ + /* 64-bit spill r0 to stack - should assign an ID. */\ + *(u64*)(r10 - 8) = r0; \ + /* 32-bit fill r1 from stack - should preserve the ID. */\ + " +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + "r1 = *(u32*)(r10 - 8);" +#else + "r1 = *(u32*)(r10 - 4);" +#endif + " \ + /* Compare r1 with another register to trigger find_equal_scalars. */\ + r2 = 0; \ + if r1 != r2 goto l0_%=; \ + /* The result of this comparison is predefined. */\ + if r0 == r2 goto l0_%=; \ + /* Dead branch: the verifier should prune it. Do an invalid memory\ + * access if the verifier follows it. \ + */ \ + r0 = *(u64*)(r9 + 0); \ + exit; \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +SEC("xdp") +__description("32-bit fill after 64-bit spill should clear ID") +__failure __msg("math between ctx pointer and 4294967295 is not allowed") +__naked void fill_32bit_after_spill_64bit_clear_id(void) +{ + asm volatile (" \ + r6 = r1; \ + /* Roll one bit to force the verifier to track both branches. */\ + call %[bpf_get_prandom_u32]; \ + r0 &= 0x8; \ + /* Put a large number into r1. */ \ + r1 = 0xffffffff; \ + r1 <<= 32; \ + r1 += r0; \ + /* 64-bit spill r1 to stack - should assign an ID. */\ + *(u64*)(r10 - 8) = r1; \ + /* 32-bit fill r2 from stack - should clear the ID. */\ + " +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + "r2 = *(u32*)(r10 - 8);" +#else + "r2 = *(u32*)(r10 - 4);" +#endif + " \ + /* Compare r2 with another register to trigger find_equal_scalars.\ + * Having one random bit is important here, otherwise the verifier cuts\ + * the corners. If the ID was mistakenly preserved on fill, this would\ + * cause the verifier to think that r1 is also equal to zero in one of\ + * the branches, and equal to eight on the other branch.\ + */ \ + r3 = 0; \ + if r2 != r3 goto l0_%=; \ +l0_%=: r1 >>= 32; \ + /* The verifier shouldn't propagate r2's range to r1, so it should\ + * still remember r1 = 0xffffffff and reject the below.\ + */ \ + r6 += r1; \ + r0 = *(u32*)(r6 + 0); \ + exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; From 6efbde200bf3cf2dbf6e7181893fed13a79c789b Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Sat, 27 Jan 2024 19:52:36 +0200 Subject: [PATCH 0695/2255] bpf: Handle scalar spill vs all MISC in stacksafe() When check_stack_read_fixed_off() reads value from an spi all stack slots of which are set to STACK_{MISC,INVALID}, the destination register is set to unbound SCALAR_VALUE. Exploit this fact by allowing stacksafe() to use a fake unbound scalar register to compare 'mmmm mmmm' stack value in old state vs spilled 64-bit scalar in current state and vice versa. Veristat results after this patch show some gains: ./veristat -C -e file,prog,states -f 'states_pct>10' not-opt after File Program States (DIFF) ----------------------- --------------------- --------------- bpf_overlay.o tail_rev_nodeport_lb4 -45 (-15.85%) bpf_xdp.o tail_lb_ipv4 -541 (-19.57%) pyperf100.bpf.o on_event -680 (-10.42%) pyperf180.bpf.o on_event -2164 (-19.62%) pyperf600.bpf.o on_event -9799 (-24.84%) strobemeta.bpf.o on_event -9157 (-65.28%) xdp_synproxy_kern.bpf.o syncookie_tc -54 (-19.29%) xdp_synproxy_kern.bpf.o syncookie_xdp -74 (-24.50%) Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240127175237.526726-6-maxtram95@gmail.com --- kernel/bpf/verifier.c | 72 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 82af971926ac..a0b8e400b3df 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1155,6 +1155,12 @@ static bool is_spilled_scalar_reg(const struct bpf_stack_state *stack) stack->spilled_ptr.type == SCALAR_VALUE; } +static bool is_spilled_scalar_reg64(const struct bpf_stack_state *stack) +{ + return stack->slot_type[0] == STACK_SPILL && + stack->spilled_ptr.type == SCALAR_VALUE; +} + /* Mark stack slot as STACK_MISC, unless it is already STACK_INVALID, in which * case they are equivalent, or it's STACK_ZERO, in which case we preserve * more precise STACK_ZERO. @@ -2264,8 +2270,7 @@ static void __reg_assign_32_into_64(struct bpf_reg_state *reg) } /* Mark a register as having a completely unknown (scalar) value. */ -static void __mark_reg_unknown(const struct bpf_verifier_env *env, - struct bpf_reg_state *reg) +static void __mark_reg_unknown_imprecise(struct bpf_reg_state *reg) { /* * Clear type, off, and union(map_ptr, range) and @@ -2277,10 +2282,20 @@ static void __mark_reg_unknown(const struct bpf_verifier_env *env, reg->ref_obj_id = 0; reg->var_off = tnum_unknown; reg->frameno = 0; - reg->precise = !env->bpf_capable; + reg->precise = false; __mark_reg_unbounded(reg); } +/* Mark a register as having a completely unknown (scalar) value, + * initialize .precise as true when not bpf capable. + */ +static void __mark_reg_unknown(const struct bpf_verifier_env *env, + struct bpf_reg_state *reg) +{ + __mark_reg_unknown_imprecise(reg); + reg->precise = !env->bpf_capable; +} + static void mark_reg_unknown(struct bpf_verifier_env *env, struct bpf_reg_state *regs, u32 regno) { @@ -16486,6 +16501,43 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, } } +static struct bpf_reg_state unbound_reg; + +static __init int unbound_reg_init(void) +{ + __mark_reg_unknown_imprecise(&unbound_reg); + unbound_reg.live |= REG_LIVE_READ; + return 0; +} +late_initcall(unbound_reg_init); + +static bool is_stack_all_misc(struct bpf_verifier_env *env, + struct bpf_stack_state *stack) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(stack->slot_type); ++i) { + if ((stack->slot_type[i] == STACK_MISC) || + (stack->slot_type[i] == STACK_INVALID && env->allow_uninit_stack)) + continue; + return false; + } + + return true; +} + +static struct bpf_reg_state *scalar_reg_for_stack(struct bpf_verifier_env *env, + struct bpf_stack_state *stack) +{ + if (is_spilled_scalar_reg64(stack)) + return &stack->spilled_ptr; + + if (is_stack_all_misc(env, stack)) + return &unbound_reg; + + return NULL; +} + static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, struct bpf_func_state *cur, struct bpf_idmap *idmap, bool exact) { @@ -16524,6 +16576,20 @@ static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, if (i >= cur->allocated_stack) return false; + /* 64-bit scalar spill vs all slots MISC and vice versa. + * Load from all slots MISC produces unbound scalar. + * Construct a fake register for such stack and call + * regsafe() to ensure scalar ids are compared. + */ + old_reg = scalar_reg_for_stack(env, &old->stack[spi]); + cur_reg = scalar_reg_for_stack(env, &cur->stack[spi]); + if (old_reg && cur_reg) { + if (!regsafe(env, old_reg, cur_reg, idmap, exact)) + return false; + i += BPF_REG_SIZE - 1; + continue; + } + /* if old state was safe with misc data in the stack * it will be safe with zero-initialized stack. * The opposite is not true From 73a28d9d000e8d20b4b3c516b74ee92afe3ae4be Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Sat, 27 Jan 2024 19:52:37 +0200 Subject: [PATCH 0696/2255] selftests/bpf: States pruning checks for scalar vs STACK_MISC Check that stacksafe() compares spilled scalars with STACK_MISC. The following combinations are explored: - old spill of imprecise scalar is equivalent to cur STACK_{MISC,INVALID} (plus error in unpriv mode); - old spill of precise scalar is not equivalent to cur STACK_MISC; - old STACK_MISC is equivalent to cur scalar; - old STACK_MISC is not equivalent to cur non-scalar. Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240127175237.526726-7-maxtram95@gmail.com --- .../selftests/bpf/progs/verifier_spill_fill.c | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 7f3b1319bd99..85e48069c9e6 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -1090,4 +1090,158 @@ l0_%=: r1 >>= 32; \ : __clobber_all); } +/* stacksafe(): check if stack spill of an imprecise scalar in old state + * is considered equivalent to STACK_{MISC,INVALID} in cur state. + */ +SEC("socket") +__success __log_level(2) +__msg("8: (79) r1 = *(u64 *)(r10 -8)") +__msg("8: safe") +__msg("processed 11 insns") +/* STACK_INVALID should prevent verifier in unpriv mode from + * considering states equivalent and force an error on second + * verification path (entry - label 1 - label 2). + */ +__failure_unpriv +__msg_unpriv("8: (79) r1 = *(u64 *)(r10 -8)") +__msg_unpriv("9: (95) exit") +__msg_unpriv("8: (79) r1 = *(u64 *)(r10 -8)") +__msg_unpriv("invalid read from stack off -8+2 size 8") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void old_imprecise_scalar_vs_cur_stack_misc(void) +{ + asm volatile( + /* get a random value for branching */ + "call %[bpf_ktime_get_ns];" + "if r0 == 0 goto 1f;" + /* conjure scalar at fp-8 */ + "r0 = 42;" + "*(u64*)(r10 - 8) = r0;" + "goto 2f;" +"1:" + /* conjure STACK_{MISC,INVALID} at fp-8 */ + "call %[bpf_ktime_get_ns];" + "*(u16*)(r10 - 8) = r0;" + "*(u16*)(r10 - 4) = r0;" +"2:" + /* read fp-8, should be considered safe on second visit */ + "r1 = *(u64*)(r10 - 8);" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* stacksafe(): check that stack spill of a precise scalar in old state + * is not considered equivalent to STACK_MISC in cur state. + */ +SEC("socket") +__success __log_level(2) +/* verifier should visit 'if r1 == 0x2a ...' two times: + * - once for path entry - label 2; + * - once for path entry - label 1 - label 2. + */ +__msg("if r1 == 0x2a goto pc+0") +__msg("if r1 == 0x2a goto pc+0") +__msg("processed 15 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void old_precise_scalar_vs_cur_stack_misc(void) +{ + asm volatile( + /* get a random value for branching */ + "call %[bpf_ktime_get_ns];" + "if r0 == 0 goto 1f;" + /* conjure scalar at fp-8 */ + "r0 = 42;" + "*(u64*)(r10 - 8) = r0;" + "goto 2f;" +"1:" + /* conjure STACK_MISC at fp-8 */ + "call %[bpf_ktime_get_ns];" + "*(u64*)(r10 - 8) = r0;" + "*(u32*)(r10 - 4) = r0;" +"2:" + /* read fp-8, should not be considered safe on second visit */ + "r1 = *(u64*)(r10 - 8);" + /* use r1 in precise context */ + "if r1 == 42 goto +0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* stacksafe(): check if STACK_MISC in old state is considered + * equivalent to stack spill of a scalar in cur state. + */ +SEC("socket") +__success __log_level(2) +__msg("8: (79) r0 = *(u64 *)(r10 -8)") +__msg("8: safe") +__msg("processed 11 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void old_stack_misc_vs_cur_scalar(void) +{ + asm volatile( + /* get a random value for branching */ + "call %[bpf_ktime_get_ns];" + "if r0 == 0 goto 1f;" + /* conjure STACK_{MISC,INVALID} at fp-8 */ + "call %[bpf_ktime_get_ns];" + "*(u16*)(r10 - 8) = r0;" + "*(u16*)(r10 - 4) = r0;" + "goto 2f;" +"1:" + /* conjure scalar at fp-8 */ + "r0 = 42;" + "*(u64*)(r10 - 8) = r0;" +"2:" + /* read fp-8, should be considered safe on second visit */ + "r0 = *(u64*)(r10 - 8);" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* stacksafe(): check that STACK_MISC in old state is not considered + * equivalent to stack spill of a non-scalar in cur state. + */ +SEC("socket") +__success __log_level(2) +/* verifier should process exit instructions twice: + * - once for path entry - label 2; + * - once for path entry - label 1 - label 2. + */ +__msg("r1 = *(u64 *)(r10 -8)") +__msg("exit") +__msg("r1 = *(u64 *)(r10 -8)") +__msg("exit") +__msg("processed 11 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void old_stack_misc_vs_cur_ctx_ptr(void) +{ + asm volatile( + /* remember context pointer in r9 */ + "r9 = r1;" + /* get a random value for branching */ + "call %[bpf_ktime_get_ns];" + "if r0 == 0 goto 1f;" + /* conjure STACK_MISC at fp-8 */ + "call %[bpf_ktime_get_ns];" + "*(u64*)(r10 - 8) = r0;" + "*(u32*)(r10 - 4) = r0;" + "goto 2f;" +"1:" + /* conjure context pointer in fp-8 */ + "*(u64*)(r10 - 8) = r9;" +"2:" + /* read fp-8, should not be considered safe on second visit */ + "r1 = *(u64*)(r10 - 8);" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; From a68b50f47bec8bd6a33b07b7e1562db2553981a7 Mon Sep 17 00:00:00 2001 From: Shung-Hsi Yu Date: Fri, 2 Feb 2024 17:55:58 +0800 Subject: [PATCH 0697/2255] selftests/bpf: trace_helpers.c: do not use poisoned type After commit c698eaebdf47 ("selftests/bpf: trace_helpers.c: Optimize kallsyms cache") trace_helpers.c now includes libbpf_internal.h, and thus can no longer use the u32 type (among others) since they are poison in libbpf_internal.h. Replace u32 with __u32 to fix the following error when building trace_helpers.c on powerpc: error: attempt to use poisoned "u32" Fixes: c698eaebdf47 ("selftests/bpf: trace_helpers.c: Optimize kallsyms cache") Signed-off-by: Shung-Hsi Yu Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/20240202095559.12900-1-shung-hsi.yu@suse.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/trace_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c index 4faa898ff7fc..27fd7ed3e4b0 100644 --- a/tools/testing/selftests/bpf/trace_helpers.c +++ b/tools/testing/selftests/bpf/trace_helpers.c @@ -271,7 +271,7 @@ ssize_t get_uprobe_offset(const void *addr) * addi r2,r2,XXXX */ { - const u32 *insn = (const u32 *)(uintptr_t)addr; + const __u32 *insn = (const __u32 *)(uintptr_t)addr; if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || ((*insn & OP_RT_RA_MASK) == LIS_R2)) && From 8f13c34087d3eb64329529b8517e5a6251653176 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 2 Feb 2024 11:05:27 -0800 Subject: [PATCH 0698/2255] bpf: handle trusted PTR_TO_BTF_ID_OR_NULL in argument check logic Add PTR_TRUSTED | PTR_MAYBE_NULL modifiers for PTR_TO_BTF_ID to check_reg_type() to support passing trusted nullable PTR_TO_BTF_ID registers into global functions accepting `__arg_trusted __arg_nullable` arguments. This hasn't been caught earlier because tests were either passing known non-NULL PTR_TO_BTF_ID registers or known NULL (SCALAR) registers. When utilizing this functionality in complicated real-world BPF application that passes around PTR_TO_BTF_ID_OR_NULL, it became apparent that verifier rejects valid case because check_reg_type() doesn't handle this case explicitly. Existing check_reg_type() logic is already anticipating this combination, so we just need to explicitly list this combo in the switch statement. Fixes: e2b3c4ff5d18 ("bpf: add __arg_trusted global func arg tag") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240202190529.2374377-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a0b8e400b3df..64fa188d00ad 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8242,6 +8242,7 @@ found: switch ((int)reg->type) { case PTR_TO_BTF_ID: case PTR_TO_BTF_ID | PTR_TRUSTED: + case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL: case PTR_TO_BTF_ID | MEM_RCU: case PTR_TO_BTF_ID | PTR_MAYBE_NULL: case PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU: From e2e70535dd76c6f17bdc9009ffca3d26cfd35ea4 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 2 Feb 2024 11:05:28 -0800 Subject: [PATCH 0699/2255] selftests/bpf: add more cases for __arg_trusted __arg_nullable args Add extra layer of global functions to ensure that passing around (trusted) PTR_TO_BTF_ID_OR_NULL registers works as expected. We also extend trusted_task_arg_nullable subtest to check three possible valid argumements: known NULL, known non-NULL, and maybe NULL cases. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240202190529.2374377-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../bpf/progs/verifier_global_ptr_args.c | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c index 484d6262363f..4ab0ef18d7eb 100644 --- a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c +++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c @@ -19,15 +19,41 @@ __weak int subprog_trusted_task_nullable(struct task_struct *task __arg_trusted return task->pid + task->tgid; } -SEC("?kprobe") +__weak int subprog_trusted_task_nullable_extra_layer(struct task_struct *task __arg_trusted __arg_nullable) +{ + return subprog_trusted_task_nullable(task) + subprog_trusted_task_nullable(NULL); +} + +SEC("?tp_btf/task_newtask") __success __log_level(2) __msg("Validating subprog_trusted_task_nullable() func#1...") __msg(": R1=trusted_ptr_or_null_task_struct(") int trusted_task_arg_nullable(void *ctx) { - struct task_struct *t = bpf_get_current_task_btf(); + struct task_struct *t1 = bpf_get_current_task_btf(); + struct task_struct *t2 = bpf_task_acquire(t1); + int res = 0; - return subprog_trusted_task_nullable(t) + subprog_trusted_task_nullable(NULL); + /* known NULL */ + res += subprog_trusted_task_nullable(NULL); + + /* known non-NULL */ + res += subprog_trusted_task_nullable(t1); + res += subprog_trusted_task_nullable_extra_layer(t1); + + /* unknown if NULL or not */ + res += subprog_trusted_task_nullable(t2); + res += subprog_trusted_task_nullable_extra_layer(t2); + + if (t2) { + /* known non-NULL after explicit NULL check, just in case */ + res += subprog_trusted_task_nullable(t2); + res += subprog_trusted_task_nullable_extra_layer(t2); + + bpf_task_release(t2); + } + + return res; } __weak int subprog_trusted_task_nonnull(struct task_struct *task __arg_trusted) From 1eb986746a67952df86eb2c50a36450ef103d01b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 2 Feb 2024 11:05:29 -0800 Subject: [PATCH 0700/2255] bpf: don't emit warnings intended for global subprogs for static subprogs When btf_prepare_func_args() was generalized to handle both static and global subprogs, a few warnings/errors that are meant only for global subprog cases started to be emitted for static subprogs, where they are sort of expected and irrelavant. Stop polutting verifier logs with irrelevant scary-looking messages. Fixes: e26080d0da87 ("bpf: prepare btf_prepare_func_args() for handling static subprogs") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240202190529.2374377-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index ef380e546952..f7725cb6e564 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -7122,6 +7122,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) args = (const struct btf_param *)(t + 1); nargs = btf_type_vlen(t); if (nargs > MAX_BPF_FUNC_REG_ARGS) { + if (!is_global) + return -EINVAL; bpf_log(log, "Global function %s() with %d > %d args. Buggy compiler.\n", tname, nargs, MAX_BPF_FUNC_REG_ARGS); return -EINVAL; @@ -7131,6 +7133,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); if (!btf_type_is_int(t) && !btf_is_any_enum(t)) { + if (!is_global) + return -EINVAL; bpf_log(log, "Global function %s() doesn't return scalar. Only those are supported.\n", tname); @@ -7251,6 +7255,8 @@ skip_pointer: sub->args[i].arg_type = ARG_ANYTHING; continue; } + if (!is_global) + return -EINVAL; bpf_log(log, "Arg#%d type %s in %s() is not supported yet.\n", i, btf_type_str(t), tname); return -EINVAL; From 5befa3728b855e9f75b29bb0069a1ca7f5bab2f7 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 31 Jan 2024 21:24:29 +0100 Subject: [PATCH 0701/2255] net: phy: realtek: add support for RTL8126A-integrated 5Gbps PHY A user reported that first consumer mainboards show up with a RTL8126A 5Gbps MAC/PHY. This adds support for the integrated PHY, which is also available stand-alone. From a PHY driver perspective it's treated the same as the 2.5Gbps PHY's, we just have to support the new PHY ID. Reported-by: Joe Salmeri Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Tested-by: Joe Salmeri Link: https://lore.kernel.org/r/0c8e67ea-6505-43d1-bd51-94e7ecd6e222@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 894172a3e15f..132784321e44 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -1047,6 +1047,16 @@ static struct phy_driver realtek_drvs[] = { .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, + }, { + PHY_ID_MATCH_EXACT(0x001cc862), + .name = "RTL8251B 5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, }, { PHY_ID_MATCH_EXACT(0x001cc961), .name = "RTL8366RB Gigabit Ethernet", From f5d59230ec26aa5e8b59e9f4a4d288703a737479 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 31 Jan 2024 21:31:01 +0100 Subject: [PATCH 0702/2255] r8169: simplify EEE handling We don't have to store the EEE modes to be advertised in the driver, phylib does this for us and stores it in phydev->advertising_eee. phylib also takes care of properly handling the EEE advertisement. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/27c336a8-ea47-483d-815b-02c45ae41da2@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 32 +++-------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 3d30d4499791..e0abdbcfadee 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -629,7 +629,6 @@ struct rtl8169_private { struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; u32 saved_wolopts; - int eee_adv; const char *fw_name; struct rtl_fw *rtl_fw; @@ -1987,17 +1986,11 @@ static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data) static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); - int ret; if (!rtl_supports_eee(tp)) return -EOPNOTSUPP; - ret = phy_ethtool_set_eee(tp->phydev, data); - - if (!ret) - tp->eee_adv = phy_read_mmd(dev->phydev, MDIO_MMD_AN, - MDIO_AN_EEE_ADV); - return ret; + return phy_ethtool_set_eee(tp->phydev, data); } static void rtl8169_get_ringparam(struct net_device *dev, @@ -2062,21 +2055,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .set_pauseparam = rtl8169_set_pauseparam, }; -static void rtl_enable_eee(struct rtl8169_private *tp) -{ - struct phy_device *phydev = tp->phydev; - int adv; - - /* respect EEE advertisement the user may have set */ - if (tp->eee_adv >= 0) - adv = tp->eee_adv; - else - adv = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); - - if (adv >= 0) - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv); -} - static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) { /* @@ -2313,9 +2291,6 @@ static void rtl8169_init_phy(struct rtl8169_private *tp) /* We may have called phy_speed_down before */ phy_speed_up(tp->phydev); - if (rtl_supports_eee(tp)) - rtl_enable_eee(tp); - genphy_soft_reset(tp->phydev); } @@ -5058,7 +5033,9 @@ static int r8169_mdio_register(struct rtl8169_private *tp) } tp->phydev->mac_managed_pm = true; - + if (rtl_supports_eee(tp)) + linkmode_copy(tp->phydev->advertising_eee, + tp->phydev->supported_eee); phy_support_asym_pause(tp->phydev); /* PHY will be woken up in rtl_open() */ @@ -5193,7 +5170,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->dev = dev; tp->pci_dev = pdev; tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; - tp->eee_adv = -1; tp->ocp_base = OCP_STD_PHY_BASE; raw_spin_lock_init(&tp->cfg9346_usage_lock); From dfd2ee086a63c730022cb095576a8b3a5a752109 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 1 Feb 2024 17:30:31 +0000 Subject: [PATCH 0703/2255] ipv6: make addrconf_wq single threaded Both addrconf_verify_work() and addrconf_dad_work() acquire rtnl, there is no point trying to have one thread per cpu. Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20240201173031.3654257-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/addrconf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 733ace18806c..d63f5d063f07 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -7349,7 +7349,8 @@ int __init addrconf_init(void) if (err < 0) goto out_addrlabel; - addrconf_wq = create_workqueue("ipv6_addrconf"); + /* All works using addrconf_wq need to lock rtnl. */ + addrconf_wq = create_singlethread_workqueue("ipv6_addrconf"); if (!addrconf_wq) { err = -ENOMEM; goto out_nowq; From 8f109e91b852f159b917f5c565bcf43c26d974e2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Feb 2024 16:49:24 -0800 Subject: [PATCH 0704/2255] tools: ynl: include dpll and mptcp_pm in C codegen The DPLL and mptcp_pm families are pretty clean, and YNL C codegen supports them fully with no changes. Add them to user space codegen so that C samples can be written, and we know immediately if changes to these families require YNL codegen work. Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240202004926.447803-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/Makefile.deps | 2 ++ tools/net/ynl/generated/Makefile | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps index 3110f84dd029..e6154a1255f8 100644 --- a/tools/net/ynl/Makefile.deps +++ b/tools/net/ynl/Makefile.deps @@ -15,7 +15,9 @@ UAPI_PATH:=../../../../include/uapi/ get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2) CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h) +CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H_,dpll.h) CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h) +CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H_,mptcp_pm.h) CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h) CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_NETLINK_H,nfsd_netlink.h) diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 84cbabdd02a8..0d826fd008ed 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -14,7 +14,7 @@ YNL_GEN_ARG_ethtool:=--user-header linux/ethtool_netlink.h \ TOOL:=../ynl-gen-c.py -GENS:=ethtool devlink handshake fou netdev nfsd +GENS:=ethtool devlink dpll handshake fou mptcp_pm netdev nfsd SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) From 7c59c9c8f2025358cacf08b8e5a626a08112cffc Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Feb 2024 16:49:25 -0800 Subject: [PATCH 0705/2255] tools: ynl: generate code for ovs families Add ovs_flow, ovs_vport and ovs_datapath to the families supported in C. ovs-flow has some circular nesting which is fun to deal with, but the necessary support has been added already in the previous release cycle. Add a sample that proves that dealing with fixed headers does actually work correctly. Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240202004926.447803-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/Makefile | 2 +- tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/ovs.c | 60 ++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tools/net/ynl/samples/ovs.c diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 0d826fd008ed..3b9f738c61b8 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -14,7 +14,7 @@ YNL_GEN_ARG_ethtool:=--user-header linux/ethtool_netlink.h \ TOOL:=../ynl-gen-c.py -GENS:=ethtool devlink dpll handshake fou mptcp_pm netdev nfsd +GENS:=ethtool devlink dpll handshake fou mptcp_pm netdev nfsd ovs_datapath ovs_vport ovs_flow SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index 49637b26c482..dda6686257a7 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -1,4 +1,5 @@ ethtool devlink netdev +ovs page-pool \ No newline at end of file diff --git a/tools/net/ynl/samples/ovs.c b/tools/net/ynl/samples/ovs.c new file mode 100644 index 000000000000..3e975c003d77 --- /dev/null +++ b/tools/net/ynl/samples/ovs.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include + +#include "ovs_datapath-user.h" + +int main(int argc, char **argv) +{ + struct ynl_sock *ys; + int err; + + ys = ynl_sock_create(&ynl_ovs_datapath_family, NULL); + if (!ys) + return 1; + + if (argc > 1) { + struct ovs_datapath_new_req *req; + + req = ovs_datapath_new_req_alloc(); + if (!req) + goto err_close; + + ovs_datapath_new_req_set_upcall_pid(req, 1); + ovs_datapath_new_req_set_name(req, argv[1]); + + err = ovs_datapath_new(ys, req); + ovs_datapath_new_req_free(req); + if (err) + goto err_close; + } else { + struct ovs_datapath_get_req_dump *req; + struct ovs_datapath_get_list *dps; + + printf("Dump:\n"); + req = ovs_datapath_get_req_dump_alloc(); + + dps = ovs_datapath_get_dump(ys, req); + ovs_datapath_get_req_dump_free(req); + if (!dps) + goto err_close; + + ynl_dump_foreach(dps, dp) { + printf(" %s(%d): pid:%u cache:%u\n", + dp->name, dp->_hdr.dp_ifindex, + dp->upcall_pid, dp->masks_cache_size); + } + ovs_datapath_get_list_free(dps); + } + + ynl_sock_destroy(ys); + + return 0; + +err_close: + fprintf(stderr, "YNL (%d): %s\n", ys->err.code, ys->err.msg); + ynl_sock_destroy(ys); + return 2; +} From d2866539df7b7fd491c7f2bfea79e5eaa7f46310 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Feb 2024 16:49:26 -0800 Subject: [PATCH 0706/2255] tools: ynl: auto-gen for all genetlink families Instead of listing the genetlink families that we want to codegen for, always codegen for everyone. We can add an opt-out later but it seems like most families are not causing any issues, and yet folks forget to add them to the Makefile. Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240202004926.447803-4-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 3b9f738c61b8..7135028cb449 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -14,7 +14,10 @@ YNL_GEN_ARG_ethtool:=--user-header linux/ethtool_netlink.h \ TOOL:=../ynl-gen-c.py -GENS:=ethtool devlink dpll handshake fou mptcp_pm netdev nfsd ovs_datapath ovs_vport ovs_flow +GENS_PATHS=$(shell grep -nrI --files-without-match \ + 'protocol: netlink' \ + ../../../../Documentation/netlink/specs/) +GENS=$(patsubst ../../../../Documentation/netlink/specs/%.yaml,%,${GENS_PATHS}) SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) From f2ec98566775dd4341ec1dcf93aa5859c60de826 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 1 Feb 2024 14:46:00 +0100 Subject: [PATCH 0707/2255] net: phy: qcom: qca808x: fix logic error in LED brightness set In switching to using phy_modify_mmd and a more short version of the LED ON/OFF condition in later revision, it was made a logic error where value ? QCA808X_LED_FORCE_ON : QCA808X_LED_FORCE_OFF is always true as value is always OR with QCA808X_LED_FORCE_EN due to missing () resulting in the testing condition being QCA808X_LED_FORCE_EN | value. Add the () to apply the correct condition and restore correct functionality of the brightness ON/OFF. Fixes: 7196062b64ee ("net: phy: at803x: add LED support for qca808x") Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/net/phy/qcom/qca808x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 0f549027d899..00db4b274264 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -820,8 +820,8 @@ static int qca808x_led_brightness_set(struct phy_device *phydev, return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, - QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON : - QCA808X_LED_FORCE_OFF); + QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON : + QCA808X_LED_FORCE_OFF)); } static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, From f203c8c77c7616c099647636f4c67d59a45fe8a2 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 1 Feb 2024 14:46:01 +0100 Subject: [PATCH 0708/2255] net: phy: qcom: qca808x: default to LED active High if not set qca808x PHY provide support for the led_polarity_set OP to configure and apply the active-low property but on PHY reset, the Active High bit is not set resulting in the LED driven as active-low. To fix this, check if active-low is not set in DT and enable Active High polarity by default to restore correct funcionality of the LED. Fixes: 7196062b64ee ("net: phy: at803x: add LED support for qca808x") Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/net/phy/qcom/qca808x.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 00db4b274264..d88e04278fc4 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -290,8 +290,18 @@ static int qca808x_probe(struct phy_device *phydev) static int qca808x_config_init(struct phy_device *phydev) { + struct qca808x_priv *priv = phydev->priv; int ret; + /* Default to LED Active High if active-low not in DT */ + if (priv->led_polarity_mode == -1) { + ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN, + QCA808X_MMD7_LED_POLARITY_CTRL, + QCA808X_LED_ACTIVE_HIGH); + if (ret) + return ret; + } + /* Active adc&vga on 802.3az for the link 1000M and 100M */ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); From 5f9c1f8f9adaf32e4e39fcf260d4fc20dbfb77c9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Feb 2024 10:48:18 +0100 Subject: [PATCH 0709/2255] 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(-) 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) { From 4c60c8054dd8a36091aab585569c8d12a0085bd9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Feb 2024 10:53:18 +0100 Subject: [PATCH 0710/2255] 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(-) 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; From 6256760f37baa2e4bf34dcbef69d7450460df9bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Feb 2024 10:56:27 +0100 Subject: [PATCH 0711/2255] 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(-) 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, From 679dd27b4ef33d4f596cbf450a3b2742fc54962a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Feb 2024 11:03:39 +0100 Subject: [PATCH 0712/2255] wifi: cfg80211: fix kunit exports These can only be exported if cfg80211's kunit is enabled, since they're otherwise static. kunit itself can be enabled even if cfg80211's kunit isn't. Fix that by using the right macro. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202402040534.6AEKtZ7Y-lkp@intel.com/ Fixes: 45d43937a44c ("wifi: cfg80211: add a kunit test for 6 GHz colocated AP parsing") Signed-off-by: Johannes Berg --- net/wireless/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index c78b10e1a167..6dd9df347771 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -537,7 +537,7 @@ cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list) kfree(ap); } } -EXPORT_SYMBOL_IF_KUNIT(cfg80211_free_coloc_ap_list); +EXPORT_SYMBOL_IF_CFG80211_KUNIT(cfg80211_free_coloc_ap_list); static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, const u8 *pos, u8 length, @@ -710,7 +710,7 @@ error: list_splice_tail(&ap_list, list); return n_coloc; } -EXPORT_SYMBOL_IF_KUNIT(cfg80211_parse_colocated_ap); +EXPORT_SYMBOL_IF_CFG80211_KUNIT(cfg80211_parse_colocated_ap); static void cfg80211_scan_req_add_chan(struct cfg80211_scan_request *request, struct ieee80211_channel *chan, From 7d7bf30f031b8e2474eefe64230609b45030bd3d Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Thu, 1 Feb 2024 21:42:03 +0100 Subject: [PATCH 0713/2255] net: micrel: Fix the frequency adjustments By default lan8841's 1588 clock frequency is 125MHz. But when adjusting the frequency, it is using the 1PPM format of the lan8814. Which is the wrong format as lan8814 has a 1588 clock frequency of 250MHz. So then for each 1PPM adjustment would adjust less than expected. Therefore fix this by using the correct 1PPM format for lan8841. Signed-off-by: Horatiu Vultur Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 40bea9293ddd..9b6973581989 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -120,6 +120,12 @@ */ #define LAN8814_1PPM_FORMAT 17179 +/* Represents 1ppm adjustment in 2^32 format with + * each nsec contains 8 clock cycles. + * The value is calculated as following: (1/1000000)/((2^-32)/8) + */ +#define LAN8841_1PPM_FORMAT 34360 + #define PTP_RX_VERSION 0x0248 #define PTP_TX_VERSION 0x0288 #define PTP_MAX_VERSION(x) (((x) & GENMASK(7, 0)) << 8) @@ -4115,8 +4121,8 @@ static int lan8841_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) faster = false; } - rate = LAN8814_1PPM_FORMAT * (upper_16_bits(scaled_ppm)); - rate += (LAN8814_1PPM_FORMAT * (lower_16_bits(scaled_ppm))) >> 16; + rate = LAN8841_1PPM_FORMAT * (upper_16_bits(scaled_ppm)); + rate += (LAN8841_1PPM_FORMAT * (lower_16_bits(scaled_ppm))) >> 16; mutex_lock(&ptp_priv->ptp_lock); phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_RATE_ADJ_HI, From e35ba5811714b7e5a73f98100ab8112a8176f84c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Feb 2024 16:11:54 -0800 Subject: [PATCH 0714/2255] selftests: netdevsim: stop using ifconfig Paolo points out that ifconfig is legacy and we should not use it. Signed-off-by: Jakub Kicinski Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- .../drivers/net/netdevsim/udp_tunnel_nic.sh | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/drivers/net/netdevsim/udp_tunnel_nic.sh b/tools/testing/selftests/drivers/net/netdevsim/udp_tunnel_nic.sh index f98435c502f6..384cfa3d38a6 100755 --- a/tools/testing/selftests/drivers/net/netdevsim/udp_tunnel_nic.sh +++ b/tools/testing/selftests/drivers/net/netdevsim/udp_tunnel_nic.sh @@ -270,7 +270,7 @@ for port in 0 1; do echo 1 > $NSIM_DEV_SYS/new_port fi NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up msg="new NIC device created" exp0=( 0 0 0 0 ) @@ -284,8 +284,8 @@ for port in 0 1; do msg="VxLAN v4 devices go down" exp0=( 0 0 0 0 ) - ifconfig vxlan1 down - ifconfig vxlan0 down + ip link set dev vxlan1 down + ip link set dev vxlan0 down check_tables msg="VxLAN v6 devices" @@ -293,7 +293,7 @@ for port in 0 1; do new_vxlan vxlanA 4789 $NSIM_NETDEV 6 for ifc in vxlan0 vxlan1; do - ifconfig $ifc up + ip link set dev $ifc up done new_vxlan vxlanB 4789 $NSIM_NETDEV 6 @@ -307,14 +307,14 @@ for port in 0 1; do new_geneve gnv0 6081 msg="NIC device goes down" - ifconfig $NSIM_NETDEV down + ip link set dev $NSIM_NETDEV down if [ $port -eq 1 ]; then exp0=( 0 0 0 0 ) exp1=( 0 0 0 0 ) fi check_tables msg="NIC device goes up again" - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up exp0=( `mke 4789 1` `mke 4790 1` 0 0 ) exp1=( `mke 6081 2` 0 0 0 ) check_tables @@ -433,7 +433,7 @@ for port in 0 1; do echo $port > $NSIM_DEV_SYS/new_port NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up overflow_table0 "overflow NIC table" overflow_table1 "overflow NIC table" @@ -491,7 +491,7 @@ for port in 0 1; do echo $port > $NSIM_DEV_SYS/new_port NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up overflow_table0 "overflow NIC table" overflow_table1 "overflow NIC table" @@ -548,7 +548,7 @@ for port in 0 1; do echo $port > $NSIM_DEV_SYS/new_port NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up overflow_table0 "destroy NIC" overflow_table1 "destroy NIC" @@ -578,7 +578,7 @@ for port in 0 1; do echo $port > $NSIM_DEV_SYS/new_port NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up msg="create VxLANs v6" new_vxlan vxlanA0 10000 $NSIM_NETDEV 6 @@ -639,7 +639,7 @@ for port in 0 1; do echo $port > $NSIM_DEV_SYS/new_port NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up echo 110 > $NSIM_DEV_DFS/ports/$port/udp_ports_inject_error @@ -695,7 +695,7 @@ for port in 0 1; do echo $port > $NSIM_DEV_SYS/new_port NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up msg="create VxLANs v6" exp0=( `mke 10000 1` 0 0 0 ) @@ -755,7 +755,7 @@ for port in 0 1; do echo $port > $NSIM_DEV_SYS/new_port NSIM_NETDEV=`get_netdev_name old_netdevs` - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up msg="create VxLANs v6" exp0=( `mke 10000 1` 0 0 0 ) @@ -768,7 +768,7 @@ for port in 0 1; do check_tables msg="NIC device goes down" - ifconfig $NSIM_NETDEV down + ip link set dev $NSIM_NETDEV down if [ $port -eq 1 ]; then exp0=( 0 0 0 0 ) exp1=( 0 0 0 0 ) @@ -779,7 +779,7 @@ for port in 0 1; do check_tables msg="NIC device goes up again" - ifconfig $NSIM_NETDEV up + ip link set dev $NSIM_NETDEV up exp0=( `mke 10000 1` 0 0 0 ) check_tables @@ -827,12 +827,12 @@ new_vxlan vxlan1 4789 $NSIM_NETDEV2 msg="VxLAN v4 devices go down" exp0=( 0 0 0 0 ) -ifconfig vxlan1 down -ifconfig vxlan0 down +ip link set dev vxlan1 down +ip link set dev vxlan0 down check_tables for ifc in vxlan0 vxlan1; do - ifconfig $ifc up + ip link set dev $ifc up done msg="VxLAN v6 device" @@ -844,11 +844,11 @@ exp1=( `mke 6081 2` 0 0 0 ) new_geneve gnv0 6081 msg="NIC device goes down" -ifconfig $NSIM_NETDEV down +ip link set dev $NSIM_NETDEV down check_tables msg="NIC device goes up again" -ifconfig $NSIM_NETDEV up +ip link set dev $NSIM_NETDEV up check_tables for i in `seq 2`; do From 3907f1ffc0ecf466d5c04aadc44c4b9203f3ec9a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 1 Feb 2024 22:38:01 +0100 Subject: [PATCH 0715/2255] r8169: add support for RTL8126A This adds support for the RTL8126A found on Asus z790 Maximus Formula. It was successfully tested w/o the firmware at 1000Mbps. Firmware file has been provided by Realtek and submitted to linux-firmware. 2.5G and 5G modes are untested. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.h | 1 + drivers/net/ethernet/realtek/r8169_main.c | 105 ++++++++++++++---- .../net/ethernet/realtek/r8169_phy_config.c | 7 ++ 3 files changed, 89 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 81567fcf3957..c921456edeb9 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -68,6 +68,7 @@ enum mac_version { /* support for RTL_GIGA_MAC_VER_60 has been removed */ RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_65, RTL_GIGA_MAC_NONE }; diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index e0abdbcfadee..c7086953974e 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -55,6 +55,7 @@ #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw" #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" +#define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ @@ -136,6 +137,7 @@ static const struct { [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, /* reserve 62 for CFG_METHOD_4 in the vendor driver */ [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2}, }; static const struct pci_device_id rtl8169_pci_tbl[] = { @@ -158,6 +160,7 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 }, { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 }, { PCI_VDEVICE(REALTEK, 0x8125) }, + { PCI_VDEVICE(REALTEK, 0x8126) }, { PCI_VDEVICE(REALTEK, 0x3000) }, {} }; @@ -327,8 +330,12 @@ enum rtl8168_registers { }; enum rtl8125_registers { + INT_CFG0_8125 = 0x34, +#define INT_CFG0_ENABLE_8125 BIT(0) +#define INT_CFG0_CLKREQEN BIT(3) IntrMask_8125 = 0x38, IntrStatus_8125 = 0x3c, + INT_CFG1_8125 = 0x7a, TxPoll_8125 = 0x90, MAC0_BKP = 0x19e0, EEE_TXIDLE_TIMER_8125 = 0x6048, @@ -1139,7 +1146,7 @@ static void rtl_writephy(struct rtl8169_private *tp, int location, int val) case RTL_GIGA_MAC_VER_31: r8168dp_2_mdio_write(tp, location, val); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: r8168g_mdio_write(tp, location, val); break; default: @@ -1154,7 +1161,7 @@ static int rtl_readphy(struct rtl8169_private *tp, int location) case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: return r8168dp_2_mdio_read(tp, location); - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: return r8168g_mdio_read(tp, location); default: return r8169_mdio_read(tp, location); @@ -1340,7 +1347,7 @@ static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable) case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65: if (enable) RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN); else @@ -1507,7 +1514,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) break; case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65: if (wolopts) rtl_mod_config2(tp, 0, PME_SIGNAL); else @@ -2073,6 +2080,9 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) u16 val; enum mac_version ver; } mac_info[] = { + /* 8126A family. */ + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 }, + /* 8125B family. */ { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, @@ -2343,6 +2353,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); break; case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_65: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | RX_PAUSE_SLOT_ON); break; @@ -2529,7 +2540,7 @@ static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); break; - case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_65: RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); @@ -2772,7 +2783,7 @@ static void rtl_enable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: rtl_eri_set_bits(tp, 0xd4, 0x0c00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); break; default: @@ -2786,7 +2797,7 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: rtl_eri_clear_bits(tp, 0xd4, 0x1f00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); break; default: @@ -2796,6 +2807,8 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) { + u8 val8; + if (tp->mac_version < RTL_GIGA_MAC_VER_32) return; @@ -2809,11 +2822,19 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) return; rtl_mod_config5(tp, 0, ASPM_en); - rtl_mod_config2(tp, 0, ClkReqEn); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_65: + val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; + default: + rtl_mod_config2(tp, 0, ClkReqEn); + break; + } switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: /* reset ephy tx/rx disable timer */ r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); /* chip can trigger L1.2 */ @@ -2825,14 +2846,22 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) } else { switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); break; default: break; } - rtl_mod_config2(tp, ClkReqEn, 0); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_65: + val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; + default: + rtl_mod_config2(tp, ClkReqEn, 0); + break; + } rtl_mod_config5(tp, ASPM_en, 0); } } @@ -3545,10 +3574,15 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) /* disable new tx descriptor format */ r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); - if (tp->mac_version == RTL_GIGA_MAC_VER_63) + if (tp->mac_version == RTL_GIGA_MAC_VER_65) + RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); + + if (tp->mac_version == RTL_GIGA_MAC_VER_65) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + else if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); else - r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0300); if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0000); @@ -3561,6 +3595,10 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); + if (tp->mac_version == RTL_GIGA_MAC_VER_65) + r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); + else + r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); r8168_mac_ocp_modify(tp, 0xe0c0, 0x4f0f, 0x4403); r8168_mac_ocp_modify(tp, 0xe052, 0x0080, 0x0068); r8168_mac_ocp_modify(tp, 0xd430, 0x0fff, 0x047f); @@ -3575,10 +3613,10 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_mac_ocp_e00e_cond, 1000, 10); - if (tp->mac_version == RTL_GIGA_MAC_VER_63) - rtl8125b_config_eee_mac(tp); - else + if (tp->mac_version == RTL_GIGA_MAC_VER_61) rtl8125a_config_eee_mac(tp); + else + rtl8125b_config_eee_mac(tp); rtl_disable_rxdvgate(tp); } @@ -3622,6 +3660,12 @@ static void rtl_hw_start_8125b(struct rtl8169_private *tp) rtl_hw_start_8125_common(tp); } +static void rtl_hw_start_8126a(struct rtl8169_private *tp) +{ + rtl_set_def_aspm_entry_latency(tp); + rtl_hw_start_8125_common(tp); +} + static void rtl_hw_config(struct rtl8169_private *tp) { static const rtl_generic_fct hw_configs[] = { @@ -3664,6 +3708,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117, [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a, }; if (hw_configs[tp->mac_version]) @@ -3674,9 +3719,23 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) { int i; + RTL_W8(tp, INT_CFG0_8125, 0x00); + /* disable interrupt coalescing */ - for (i = 0xa00; i < 0xb00; i += 4) - RTL_W32(tp, i, 0); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); + break; + case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_65: + for (i = 0xa00; i < 0xa80; i += 4) + RTL_W32(tp, i, 0); + RTL_W16(tp, INT_CFG1_8125, 0x0000); + break; + default: + break; + } rtl_hw_config(tp); } @@ -3754,8 +3813,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) rtl_jumbo_config(tp); switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_61: - case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: rtl8125_set_eee_txidle_timer(tp); break; default: @@ -3904,7 +3962,7 @@ static void rtl8169_cleanup(struct rtl8169_private *tp) RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: rtl_enable_rxdvgate(tp); fsleep(2000); break; @@ -4055,8 +4113,7 @@ static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, switch (tp->mac_version) { case RTL_GIGA_MAC_VER_34: - case RTL_GIGA_MAC_VER_61: - case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: padto = max_t(unsigned int, padto, ETH_ZLEN); break; default: @@ -5085,7 +5142,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: rtl_hw_init_8168g(tp); break; - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: rtl_hw_init_8125(tp); break; default: diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index b50f16786c24..1f74317beb88 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1102,6 +1102,12 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, rtl8125b_config_eee_phy(phydev); } +static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); +} + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, enum mac_version ver) { @@ -1152,6 +1158,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config, [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config, }; if (phy_configs[ver]) From bd8a8d5ec5048ef74002d9f3db5cae971e68712c Mon Sep 17 00:00:00 2001 From: Yunjian Wang Date: Fri, 2 Feb 2024 15:25:55 +0800 Subject: [PATCH 0716/2255] tun: Fix code style issues in This fixes the following code style problem: - WARNING: please, no spaces at the start of a line - CHECK: Please use a blank line after function/struct/union/enum declarations Signed-off-by: Yunjian Wang Reviewed-by: Jiri Pirko Reviewed-by: Willem de Bruijn Acked-by: Jason Wang Signed-off-by: David S. Miller --- include/linux/if_tun.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 2a7660843444..043d442994b0 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -27,44 +27,54 @@ struct tun_xdp_hdr { #if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) struct socket *tun_get_socket(struct file *); struct ptr_ring *tun_get_tx_ring(struct file *file); + static inline bool tun_is_xdp_frame(void *ptr) { - return (unsigned long)ptr & TUN_XDP_FLAG; + return (unsigned long)ptr & TUN_XDP_FLAG; } + static inline void *tun_xdp_to_ptr(struct xdp_frame *xdp) { - return (void *)((unsigned long)xdp | TUN_XDP_FLAG); + return (void *)((unsigned long)xdp | TUN_XDP_FLAG); } + static inline struct xdp_frame *tun_ptr_to_xdp(void *ptr) { - return (void *)((unsigned long)ptr & ~TUN_XDP_FLAG); + return (void *)((unsigned long)ptr & ~TUN_XDP_FLAG); } + void tun_ptr_free(void *ptr); #else #include #include struct file; struct socket; + static inline struct socket *tun_get_socket(struct file *f) { return ERR_PTR(-EINVAL); } + static inline struct ptr_ring *tun_get_tx_ring(struct file *f) { return ERR_PTR(-EINVAL); } + static inline bool tun_is_xdp_frame(void *ptr) { return false; } + static inline void *tun_xdp_to_ptr(struct xdp_frame *xdp) { return NULL; } + static inline struct xdp_frame *tun_ptr_to_xdp(void *ptr) { return NULL; } + static inline void tun_ptr_free(void *ptr) { } From 45a96c407eb1cd44aa0179db8d600015616bcced Mon Sep 17 00:00:00 2001 From: Yunjian Wang Date: Fri, 2 Feb 2024 15:53:20 +0800 Subject: [PATCH 0717/2255] tun: Implement ethtool's get_channels() callback Implement the tun .get_channels functionality. This feature is necessary for some tools, such as libxdp, which need to retrieve the queue count. Signed-off-by: Yunjian Wang Reviewed-by: Jiri Pirko Reviewed-by: Willem de Bruijn Acked-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e335ece47dec..b472f2c972d8 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -3643,12 +3643,22 @@ static int tun_set_coalesce(struct net_device *dev, return 0; } +static void tun_get_channels(struct net_device *dev, + struct ethtool_channels *channels) +{ + struct tun_struct *tun = netdev_priv(dev); + + channels->combined_count = tun->numqueues; + channels->max_combined = tun->flags & IFF_MULTI_QUEUE ? MAX_TAP_QUEUES : 1; +} + static const struct ethtool_ops tun_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_MAX_FRAMES, .get_drvinfo = tun_get_drvinfo, .get_msglevel = tun_get_msglevel, .set_msglevel = tun_set_msglevel, .get_link = ethtool_op_get_link, + .get_channels = tun_get_channels, .get_ts_info = ethtool_op_get_ts_info, .get_coalesce = tun_get_coalesce, .set_coalesce = tun_set_coalesce, From ffabe98cb576097b77d404d39e8b3df03caa986a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 2 Feb 2024 10:11:06 +0000 Subject: [PATCH 0718/2255] net: make dev_unreg_count global We can use a global dev_unreg_count counter instead of a per netns one. As a bonus we can factorize the changes done on it for bulk device removals. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 1 + include/net/net_namespace.h | 2 -- net/core/dev.c | 12 +++++++++--- net/core/rtnetlink.c | 11 +---------- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 410529fca18b..21780608cf47 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -47,6 +47,7 @@ extern int rtnl_lock_killable(void); extern bool refcount_dec_and_rtnl_lock(refcount_t *r); extern wait_queue_head_t netdev_unregistering_wq; +extern atomic_t dev_unreg_count; extern struct rw_semaphore pernet_ops_rwsem; extern struct rw_semaphore net_rwsem; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 13b3a4e29fdb..cd0c2eedbb5e 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -67,8 +67,6 @@ struct net { */ spinlock_t rules_mod_lock; - atomic_t dev_unreg_count; - unsigned int dev_base_seq; /* protected by rtnl_mutex */ u32 ifindex; diff --git a/net/core/dev.c b/net/core/dev.c index b53b9c94de40..27ba057d06c4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -9698,11 +9698,11 @@ static void dev_index_release(struct net *net, int ifindex) /* Delayed registration/unregisteration */ LIST_HEAD(net_todo_list); DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq); +atomic_t dev_unreg_count = ATOMIC_INIT(0); static void net_set_todo(struct net_device *dev) { list_add_tail(&dev->todo_list, &net_todo_list); - atomic_inc(&dev_net(dev)->dev_unreg_count); } static netdev_features_t netdev_sync_upper_features(struct net_device *lower, @@ -10529,6 +10529,7 @@ void netdev_run_todo(void) { struct net_device *dev, *tmp; struct list_head list; + int cnt; #ifdef CONFIG_LOCKDEP struct list_head unlink_list; @@ -10565,6 +10566,7 @@ void netdev_run_todo(void) linkwatch_sync_dev(dev); } + cnt = 0; while (!list_empty(&list)) { dev = netdev_wait_allrefs_any(&list); list_del(&dev->todo_list); @@ -10582,12 +10584,13 @@ void netdev_run_todo(void) if (dev->needs_free_netdev) free_netdev(dev); - if (atomic_dec_and_test(&dev_net(dev)->dev_unreg_count)) - wake_up(&netdev_unregistering_wq); + cnt++; /* Free network device */ kobject_put(&dev->dev.kobj); } + if (cnt && atomic_sub_and_test(cnt, &dev_unreg_count)) + wake_up(&netdev_unregistering_wq); } /* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has @@ -11034,6 +11037,7 @@ void unregister_netdevice_many_notify(struct list_head *head, { struct net_device *dev, *tmp; LIST_HEAD(close_head); + int cnt = 0; BUG_ON(dev_boot_phase); ASSERT_RTNL(); @@ -11130,7 +11134,9 @@ void unregister_netdevice_many_notify(struct list_head *head, list_for_each_entry(dev, head, unreg_list) { netdev_put(dev, &dev->dev_registered_tracker); net_set_todo(dev); + cnt++; } + atomic_add(cnt, &dev_unreg_count); list_del(head); } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index f6f29eb03ec2..31f433950c8d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -483,24 +483,15 @@ EXPORT_SYMBOL_GPL(__rtnl_link_unregister); */ static void rtnl_lock_unregistering_all(void) { - struct net *net; - bool unregistering; DEFINE_WAIT_FUNC(wait, woken_wake_function); add_wait_queue(&netdev_unregistering_wq, &wait); for (;;) { - unregistering = false; rtnl_lock(); /* We held write locked pernet_ops_rwsem, and parallel * setup_net() and cleanup_net() are not possible. */ - for_each_net(net) { - if (atomic_read(&net->dev_unreg_count) > 0) { - unregistering = true; - break; - } - } - if (!unregistering) + if (!atomic_read(&dev_unreg_count)) break; __rtnl_unlock(); From 89304f91bf8efe832557b00f034493420f16dbdb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 2 Feb 2024 10:14:03 +0000 Subject: [PATCH 0719/2255] sctp: preserve const qualifier in sctp_sk() We can change sctp_sk() to propagate its argument const qualifier, thanks to container_of_const(). Signed-off-by: Eric Dumazet Cc: Marcelo Ricardo Leitner Cc: Xin Long Acked-by: Xin Long Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 5a24d6d8522a..f24a1bbcb3ef 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -242,10 +242,7 @@ struct sctp_sock { int do_auto_asconf; }; -static inline struct sctp_sock *sctp_sk(const struct sock *sk) -{ - return (struct sctp_sock *)sk; -} +#define sctp_sk(ptr) container_of_const(ptr, struct sctp_sock, inet.sk) static inline struct sock *sctp_opt2sk(const struct sctp_sock *sp) { From 1e08223272c7bd5b26196389fab3892ba9942be3 Mon Sep 17 00:00:00 2001 From: Gerhard Engleder Date: Wed, 31 Jan 2024 21:54:34 +0100 Subject: [PATCH 0720/2255] tsnep: Add helper for RX XDP_RING_NEED_WAKEUP flag Similar chunk of code is used in tsnep_rx_poll_zc() and tsnep_rx_reopen_xsk() to maintain the RX XDP_RING_NEED_WAKEUP flag. Consolidate the code to common helper function. Suggested-by: Paolo Abeni Signed-off-by: Gerhard Engleder Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/engleder/tsnep_main.c | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index eb64118f5b18..6cb3817d2877 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -1260,6 +1260,14 @@ static int tsnep_rx_refill_zc(struct tsnep_rx *rx, int count, bool reuse) return desc_refilled; } +static void tsnep_xsk_rx_need_wakeup(struct tsnep_rx *rx, int desc_available) +{ + if (desc_available) + xsk_set_rx_need_wakeup(rx->xsk_pool); + else + xsk_clear_rx_need_wakeup(rx->xsk_pool); +} + static bool tsnep_xdp_run_prog(struct tsnep_rx *rx, struct bpf_prog *prog, struct xdp_buff *xdp, int *status, struct netdev_queue *tx_nq, struct tsnep_tx *tx) @@ -1621,10 +1629,7 @@ static int tsnep_rx_poll_zc(struct tsnep_rx *rx, struct napi_struct *napi, desc_available -= tsnep_rx_refill_zc(rx, desc_available, false); if (xsk_uses_need_wakeup(rx->xsk_pool)) { - if (desc_available) - xsk_set_rx_need_wakeup(rx->xsk_pool); - else - xsk_clear_rx_need_wakeup(rx->xsk_pool); + tsnep_xsk_rx_need_wakeup(rx, desc_available); return done; } @@ -1769,14 +1774,8 @@ static void tsnep_rx_reopen_xsk(struct tsnep_rx *rx) * first polling would be too late as need wakeup signalisation would * be delayed for an indefinite time */ - if (xsk_uses_need_wakeup(rx->xsk_pool)) { - int desc_available = tsnep_rx_desc_available(rx); - - if (desc_available) - xsk_set_rx_need_wakeup(rx->xsk_pool); - else - xsk_clear_rx_need_wakeup(rx->xsk_pool); - } + if (xsk_uses_need_wakeup(rx->xsk_pool)) + tsnep_xsk_rx_need_wakeup(rx, tsnep_rx_desc_available(rx)); } static bool tsnep_pending(struct tsnep_queue *queue) From 1c09d7cbb57abcea66148923cef717cc7ab35704 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 2 Feb 2024 12:40:07 +0100 Subject: [PATCH 0721/2255] mptcp: annotate access for msk keys Both the local and the remote key follow the same locking schema, put in place the proper ONCE accessors. Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/options.c | 12 ++++++------ net/mptcp/protocol.c | 2 +- net/mptcp/protocol.h | 6 ++++-- net/mptcp/subflow.c | 10 ++++++---- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index d2527d189a79..5e2b130d8680 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -689,8 +689,8 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff * opts->suboptions |= OPTION_MPTCP_ADD_ADDR; if (!echo) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRTX); - opts->ahmac = add_addr_generate_hmac(msk->local_key, - msk->remote_key, + opts->ahmac = add_addr_generate_hmac(READ_ONCE(msk->local_key), + READ_ONCE(msk->remote_key), &opts->addr); } else { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADDTX); @@ -792,7 +792,7 @@ static bool mptcp_established_options_fastclose(struct sock *sk, *size = TCPOLEN_MPTCP_FASTCLOSE; opts->suboptions |= OPTION_MPTCP_FASTCLOSE; - opts->rcvr_key = msk->remote_key; + opts->rcvr_key = READ_ONCE(msk->remote_key); pr_debug("FASTCLOSE key=%llu", opts->rcvr_key); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSETX); @@ -1099,8 +1099,8 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk, if (mp_opt->echo) return true; - hmac = add_addr_generate_hmac(msk->remote_key, - msk->local_key, + hmac = add_addr_generate_hmac(READ_ONCE(msk->remote_key), + READ_ONCE(msk->local_key), &mp_opt->addr); pr_debug("msk=%p, ahmac=%llu, mp_opt->ahmac=%llu\n", @@ -1147,7 +1147,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) if (unlikely(mp_opt.suboptions != OPTION_MPTCP_DSS)) { if ((mp_opt.suboptions & OPTION_MPTCP_FASTCLOSE) && - msk->local_key == mp_opt.rcvr_key) { + READ_ONCE(msk->local_key) == mp_opt.rcvr_key) { WRITE_ONCE(msk->rcv_fastclose, true); mptcp_schedule_work((struct sock *)msk); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSERX); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 028e8b473626..874f019c5093 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3193,7 +3193,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, __mptcp_init_sock(nsk); msk = mptcp_sk(nsk); - msk->local_key = subflow_req->local_key; + WRITE_ONCE(msk->local_key, subflow_req->local_key); msk->token = subflow_req->token; msk->in_accept_queue = 1; WRITE_ONCE(msk->fully_established, false); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 3517f2d24a22..13b8cf8ec704 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -260,8 +260,10 @@ struct mptcp_data_frag { struct mptcp_sock { /* inet_connection_sock must be the first member */ struct inet_connection_sock sk; - u64 local_key; - u64 remote_key; + u64 local_key; /* protected by the first subflow socket lock + * lockless access read + */ + u64 remote_key; /* same as above */ u64 write_seq; u64 bytes_sent; u64 snd_nxt; diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 0dcb721c89d1..d60b83511302 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -75,7 +75,8 @@ static void subflow_req_create_thmac(struct mptcp_subflow_request_sock *subflow_ get_random_bytes(&subflow_req->local_nonce, sizeof(u32)); - subflow_generate_hmac(msk->local_key, msk->remote_key, + subflow_generate_hmac(READ_ONCE(msk->local_key), + READ_ONCE(msk->remote_key), subflow_req->local_nonce, subflow_req->remote_nonce, hmac); @@ -694,7 +695,8 @@ static bool subflow_hmac_valid(const struct request_sock *req, if (!msk) return false; - subflow_generate_hmac(msk->remote_key, msk->local_key, + subflow_generate_hmac(READ_ONCE(msk->remote_key), + READ_ONCE(msk->local_key), subflow_req->remote_nonce, subflow_req->local_nonce, hmac); @@ -1530,8 +1532,8 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc, mptcp_pm_get_flags_and_ifindex_by_id(msk, local_id, &flags, &ifindex); subflow->remote_key_valid = 1; - subflow->remote_key = msk->remote_key; - subflow->local_key = msk->local_key; + subflow->remote_key = READ_ONCE(msk->remote_key); + subflow->local_key = READ_ONCE(msk->local_key); subflow->token = msk->token; mptcp_info2sockaddr(loc, &addr, ssk->sk_family); From d440a4e27acdede686b974b62a6b2b2bd7914437 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 2 Feb 2024 12:40:08 +0100 Subject: [PATCH 0722/2255] mptcp: annotate lockless access for the tx path The mptcp-level TX path info (write_seq, bytes_sent, snd_nxt) are under the msk socket lock protection, and are accessed lockless in a few spots. Always mark the write operations with WRITE_ONCE, read operations outside the lock with READ_ONCE and drop the annotation for read under such lock. To simplify the annotations move mptcp_pending_data_fin_ack() from __mptcp_data_acked() to __mptcp_clean_una(), under the msk socket lock, where such call would belong. Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/options.c | 2 +- net/mptcp/protocol.c | 15 +++++++-------- net/mptcp/protocol.h | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 5e2b130d8680..9b31a0a06265 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1060,7 +1060,7 @@ static void ack_update_msk(struct mptcp_sock *msk, msk->wnd_end = new_wnd_end; /* this assumes mptcp_incoming_options() is invoked after tcp_ack() */ - if (after64(msk->wnd_end, READ_ONCE(msk->snd_nxt))) + if (after64(msk->wnd_end, snd_nxt)) __mptcp_check_push(sk, ssk); if (after64(new_snd_una, old_snd_una)) { diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 874f019c5093..b1c24ac3630f 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1033,13 +1033,15 @@ static void __mptcp_clean_una(struct sock *sk) msk->recovery = false; out: - if (snd_una == READ_ONCE(msk->snd_nxt) && - snd_una == READ_ONCE(msk->write_seq)) { + if (snd_una == msk->snd_nxt && snd_una == msk->write_seq) { if (mptcp_rtx_timer_pending(sk) && !mptcp_data_fin_enabled(msk)) mptcp_stop_rtx_timer(sk); } else { mptcp_reset_rtx_timer(sk); } + + if (mptcp_pending_data_fin_ack(sk)) + mptcp_schedule_work(sk); } static void __mptcp_clean_una_wakeup(struct sock *sk) @@ -1499,7 +1501,7 @@ static void mptcp_update_post_push(struct mptcp_sock *msk, */ if (likely(after64(snd_nxt_new, msk->snd_nxt))) { msk->bytes_sent += snd_nxt_new - msk->snd_nxt; - msk->snd_nxt = snd_nxt_new; + WRITE_ONCE(msk->snd_nxt, snd_nxt_new); } } @@ -3200,8 +3202,8 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, if (mp_opt->suboptions & OPTION_MPTCP_CSUMREQD) WRITE_ONCE(msk->csum_enabled, true); - msk->write_seq = subflow_req->idsn + 1; - msk->snd_nxt = msk->write_seq; + WRITE_ONCE(msk->write_seq, subflow_req->idsn + 1); + WRITE_ONCE(msk->snd_nxt, msk->write_seq); msk->snd_una = msk->write_seq; msk->wnd_end = msk->snd_nxt + req->rsk_rcv_wnd; msk->setsockopt_seq = mptcp_sk(sk)->setsockopt_seq; @@ -3303,9 +3305,6 @@ void __mptcp_data_acked(struct sock *sk) __mptcp_clean_una(sk); else __set_bit(MPTCP_CLEAN_UNA, &mptcp_sk(sk)->cb_flags); - - if (mptcp_pending_data_fin_ack(sk)) - mptcp_schedule_work(sk); } void __mptcp_check_push(struct sock *sk, struct sock *ssk) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 13b8cf8ec704..421dede93e2b 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -402,7 +402,7 @@ static inline struct mptcp_data_frag *mptcp_rtx_head(struct sock *sk) { struct mptcp_sock *msk = mptcp_sk(sk); - if (msk->snd_una == READ_ONCE(msk->snd_nxt)) + if (msk->snd_una == msk->snd_nxt) return NULL; return list_first_entry_or_null(&msk->rtx_queue, struct mptcp_data_frag, list); From 9426ce476a705d13eb086d4be7c817856417816f Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 2 Feb 2024 12:40:09 +0100 Subject: [PATCH 0723/2255] mptcp: annotate lockless access for RX path fields The following fields: - ack_seq - snd_una - wnd_end - rmem_fwd_alloc are protected by the data lock end accessed lockless in a few spots. Ensure ONCE annotation for write (under such lock) and for lockless read. Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/options.c | 6 +++--- net/mptcp/protocol.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 9b31a0a06265..801a3525230d 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1030,7 +1030,7 @@ u64 __mptcp_expand_seq(u64 old_seq, u64 cur_seq) static void __mptcp_snd_una_update(struct mptcp_sock *msk, u64 new_snd_una) { msk->bytes_acked += new_snd_una - msk->snd_una; - msk->snd_una = new_snd_una; + WRITE_ONCE(msk->snd_una, new_snd_una); } static void ack_update_msk(struct mptcp_sock *msk, @@ -1057,7 +1057,7 @@ static void ack_update_msk(struct mptcp_sock *msk, new_wnd_end = new_snd_una + tcp_sk(ssk)->snd_wnd; if (after64(new_wnd_end, msk->wnd_end)) - msk->wnd_end = new_wnd_end; + WRITE_ONCE(msk->wnd_end, new_wnd_end); /* this assumes mptcp_incoming_options() is invoked after tcp_ack() */ if (after64(msk->wnd_end, snd_nxt)) @@ -1071,7 +1071,7 @@ static void ack_update_msk(struct mptcp_sock *msk, trace_ack_update_msk(mp_opt->data_ack, old_snd_una, new_snd_una, - new_wnd_end, msk->wnd_end); + new_wnd_end, READ_ONCE(msk->wnd_end)); } bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index b1c24ac3630f..90804e7fb7f6 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -410,6 +410,7 @@ static void mptcp_close_wake_up(struct sock *sk) sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); } +/* called under the msk socket lock */ static bool mptcp_pending_data_fin_ack(struct sock *sk) { struct mptcp_sock *msk = mptcp_sk(sk); @@ -441,16 +442,17 @@ static void mptcp_check_data_fin_ack(struct sock *sk) } } +/* can be called with no lock acquired */ static bool mptcp_pending_data_fin(struct sock *sk, u64 *seq) { struct mptcp_sock *msk = mptcp_sk(sk); if (READ_ONCE(msk->rcv_data_fin) && - ((1 << sk->sk_state) & + ((1 << inet_sk_state_load(sk)) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2))) { u64 rcv_data_fin_seq = READ_ONCE(msk->rcv_data_fin_seq); - if (msk->ack_seq == rcv_data_fin_seq) { + if (READ_ONCE(msk->ack_seq) == rcv_data_fin_seq) { if (seq) *seq = rcv_data_fin_seq; @@ -748,7 +750,7 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) __skb_queue_tail(&sk->sk_receive_queue, skb); } msk->bytes_received += end_seq - msk->ack_seq; - msk->ack_seq = end_seq; + WRITE_ONCE(msk->ack_seq, end_seq); moved = true; } return moved; @@ -985,6 +987,7 @@ static void dfrag_clear(struct sock *sk, struct mptcp_data_frag *dfrag) put_page(dfrag->page); } +/* called under both the msk socket lock and the data lock */ static void __mptcp_clean_una(struct sock *sk) { struct mptcp_sock *msk = mptcp_sk(sk); @@ -2110,7 +2113,7 @@ static unsigned int mptcp_inq_hint(const struct sock *sk) skb = skb_peek(&msk->receive_queue); if (skb) { - u64 hint_val = msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + u64 hint_val = READ_ONCE(msk->ack_seq) - MPTCP_SKB_CB(skb)->map_seq; if (hint_val >= INT_MAX) return INT_MAX; @@ -2754,7 +2757,7 @@ static void __mptcp_init_sock(struct sock *sk) __skb_queue_head_init(&msk->receive_queue); msk->out_of_order_queue = RB_ROOT; msk->first_pending = NULL; - msk->rmem_fwd_alloc = 0; + WRITE_ONCE(msk->rmem_fwd_alloc, 0); WRITE_ONCE(msk->rmem_released, 0); msk->timer_ival = TCP_RTO_MIN; msk->scaling_ratio = TCP_DEFAULT_SCALING_RATIO; @@ -2970,7 +2973,7 @@ static void __mptcp_destroy_sock(struct sock *sk) sk->sk_prot->destroy(sk); - WARN_ON_ONCE(msk->rmem_fwd_alloc); + WARN_ON_ONCE(READ_ONCE(msk->rmem_fwd_alloc)); WARN_ON_ONCE(msk->rmem_released); sk_stream_kill_queues(sk); xfrm_sk_free_policy(sk); @@ -3204,8 +3207,8 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, WRITE_ONCE(msk->write_seq, subflow_req->idsn + 1); WRITE_ONCE(msk->snd_nxt, msk->write_seq); - msk->snd_una = msk->write_seq; - msk->wnd_end = msk->snd_nxt + req->rsk_rcv_wnd; + WRITE_ONCE(msk->snd_una, msk->write_seq); + WRITE_ONCE(msk->wnd_end, msk->snd_nxt + req->rsk_rcv_wnd); msk->setsockopt_seq = mptcp_sk(sk)->setsockopt_seq; mptcp_init_sched(msk, mptcp_sk(sk)->sched); From b9f4554356f60c6ab33ef6604d1aa94475449b1f Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 2 Feb 2024 12:40:10 +0100 Subject: [PATCH 0724/2255] mptcp: annotate lockless access for token The token field is manipulated under the msk socket lock and accessed lockless in a few spots, add proper ONCE annotation Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm.c | 2 +- net/mptcp/pm_netlink.c | 10 +++++----- net/mptcp/protocol.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 4ae19113b8eb..53e0b08b1123 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -77,7 +77,7 @@ void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int { struct mptcp_pm_data *pm = &msk->pm; - pr_debug("msk=%p, token=%u side=%d", msk, msk->token, server_side); + pr_debug("msk=%p, token=%u side=%d", msk, READ_ONCE(msk->token), server_side); WRITE_ONCE(pm->server_side, server_side); mptcp_event(MPTCP_EVENT_CREATED, msk, ssk, GFP_ATOMIC); diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 287a60381eae..d9ad45959219 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -1997,7 +1997,7 @@ static int mptcp_event_put_token_and_ssk(struct sk_buff *skb, const struct mptcp_subflow_context *sf; u8 sk_err; - if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, msk->token)) + if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token))) return -EMSGSIZE; if (mptcp_event_add_subflow(skb, ssk)) @@ -2055,7 +2055,7 @@ static int mptcp_event_created(struct sk_buff *skb, const struct mptcp_sock *msk, const struct sock *ssk) { - int err = nla_put_u32(skb, MPTCP_ATTR_TOKEN, msk->token); + int err = nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)); if (err) return err; @@ -2083,7 +2083,7 @@ void mptcp_event_addr_removed(const struct mptcp_sock *msk, uint8_t id) if (!nlh) goto nla_put_failure; - if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, msk->token)) + if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token))) goto nla_put_failure; if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, id)) @@ -2118,7 +2118,7 @@ void mptcp_event_addr_announced(const struct sock *ssk, if (!nlh) goto nla_put_failure; - if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, msk->token)) + if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token))) goto nla_put_failure; if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, info->id)) @@ -2234,7 +2234,7 @@ void mptcp_event(enum mptcp_event_type type, const struct mptcp_sock *msk, goto nla_put_failure; break; case MPTCP_EVENT_CLOSED: - if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, msk->token) < 0) + if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)) < 0) goto nla_put_failure; break; case MPTCP_EVENT_ANNOUNCED: diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 90804e7fb7f6..4478ddd3b5fa 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3199,7 +3199,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, msk = mptcp_sk(nsk); WRITE_ONCE(msk->local_key, subflow_req->local_key); - msk->token = subflow_req->token; + WRITE_ONCE(msk->token, subflow_req->token); msk->in_accept_queue = 1; WRITE_ONCE(msk->fully_established, false); if (mp_opt->suboptions & OPTION_MPTCP_CSUMREQD) From 28e5c138050670e813017102c1ac842a6a0aa297 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 2 Feb 2024 12:40:11 +0100 Subject: [PATCH 0725/2255] mptcp: annotate lockless accesses around read-mostly fields The following MPTCP socket fields: - can_ack - fully_established - rcv_data_fin - snd_data_fin_enable - rcv_fastclose - use_64bit_ack are accessed without any lock, add the appropriate annotation. The schema is safe as each field can change its value at most once in the whole mptcp socket life cycle. Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/protocol.c | 14 +++++++------- net/mptcp/sockopt.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 4478ddd3b5fa..ad39f54b3a81 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3149,16 +3149,16 @@ static int mptcp_disconnect(struct sock *sk, int flags) msk->cb_flags = 0; msk->push_pending = 0; msk->recovery = false; - msk->can_ack = false; - msk->fully_established = false; - msk->rcv_data_fin = false; - msk->snd_data_fin_enable = false; - msk->rcv_fastclose = false; - msk->use_64bit_ack = false; - msk->bytes_consumed = 0; + WRITE_ONCE(msk->can_ack, false); + WRITE_ONCE(msk->fully_established, false); + WRITE_ONCE(msk->rcv_data_fin, false); + WRITE_ONCE(msk->snd_data_fin_enable, false); + WRITE_ONCE(msk->rcv_fastclose, false); + WRITE_ONCE(msk->use_64bit_ack, false); WRITE_ONCE(msk->csum_enabled, mptcp_is_checksum_enabled(sock_net(sk))); mptcp_pm_data_reset(msk); mptcp_ca_reset(sk); + msk->bytes_consumed = 0; msk->bytes_acked = 0; msk->bytes_received = 0; msk->bytes_sent = 0; diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index c40f1428e602..da37e4541a5d 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -942,7 +942,7 @@ void mptcp_diag_fill_info(struct mptcp_sock *msk, struct mptcp_info *info) mptcp_data_unlock(sk); slow = lock_sock_fast(sk); - info->mptcpi_csum_enabled = msk->csum_enabled; + info->mptcpi_csum_enabled = READ_ONCE(msk->csum_enabled); info->mptcpi_token = msk->token; info->mptcpi_write_seq = msk->write_seq; info->mptcpi_retransmits = inet_csk(sk)->icsk_retransmits; From 843a8851e89e2e85db04caaf88d8554818319047 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 2 Feb 2024 07:13:29 -0800 Subject: [PATCH 0726/2255] net: blackhole_dev: fix build warning for ethh set but not used lib/test_blackhole_dev.c sets a variable that is never read, causing this following building warning: lib/test_blackhole_dev.c:32:17: warning: variable 'ethh' set but not used [-Wunused-but-set-variable] Remove the variable struct ethhdr *ethh, which is unused. Fixes: 509e56b37cc3 ("blackhole_dev: add a selftest") Signed-off-by: Breno Leitao Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- lib/test_blackhole_dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/test_blackhole_dev.c b/lib/test_blackhole_dev.c index 4c40580a99a3..f247089d63c0 100644 --- a/lib/test_blackhole_dev.c +++ b/lib/test_blackhole_dev.c @@ -29,7 +29,6 @@ static int __init test_blackholedev_init(void) { struct ipv6hdr *ip6h; struct sk_buff *skb; - struct ethhdr *ethh; struct udphdr *uh; int data_len; int ret; @@ -61,7 +60,7 @@ static int __init test_blackholedev_init(void) ip6h->saddr = in6addr_loopback; ip6h->daddr = in6addr_loopback; /* Ether */ - ethh = (struct ethhdr *)skb_push(skb, sizeof(struct ethhdr)); + skb_push(skb, sizeof(struct ethhdr)); skb_set_mac_header(skb, 0); skb->protocol = htons(ETH_P_IPV6); From 1c7bbea992c8051b6b53c230d3ad30bcbc5309c9 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 2 Feb 2024 08:05:37 -0800 Subject: [PATCH 0727/2255] net: ocelot: update the MODULE_DESCRIPTION() commit 1c870c63d7d2 ("net: fill in MODULE_DESCRIPTION()s for ocelot") got a suggestion from Vladimir Oltean after it had landed in net-next. Rewrite the module description according to Vladimir's suggestion. Fixes: 1c870c63d7d2 ("net: fill in MODULE_DESCRIPTION()s for ocelot") Suggested-by: Vladimir Oltean Signed-off-by: Breno Leitao Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 2194f2a7ab27..ed2fb44500b0 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -3078,5 +3078,5 @@ void ocelot_deinit_port(struct ocelot *ocelot, int port) } EXPORT_SYMBOL(ocelot_deinit_port); -MODULE_DESCRIPTION("Microsemi Ocelot (VSC7514) Switch driver"); +MODULE_DESCRIPTION("Microsemi Ocelot switch family library"); MODULE_LICENSE("Dual MIT/GPL"); From 0cd216d769fbd161c06f5a702bf7a951f276f558 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 2 Feb 2024 18:20:41 +0200 Subject: [PATCH 0728/2255] net: dsa: reindent arguments of dsa_user_vlan_for_each() These got misaligned after commit 6ca80638b90c ("net: dsa: Use conduit and user terms"). Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/user.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/dsa/user.c b/net/dsa/user.c index e03da3a4ac38..ba2e53b5e16a 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -210,7 +210,7 @@ static int dsa_user_sync_uc(struct net_device *dev, return 0; return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, - &ctx); + &ctx); } static int dsa_user_unsync_uc(struct net_device *dev, @@ -230,7 +230,7 @@ static int dsa_user_unsync_uc(struct net_device *dev, return 0; return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, - &ctx); + &ctx); } static int dsa_user_sync_mc(struct net_device *dev, @@ -250,7 +250,7 @@ static int dsa_user_sync_mc(struct net_device *dev, return 0; return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, - &ctx); + &ctx); } static int dsa_user_unsync_mc(struct net_device *dev, @@ -270,7 +270,7 @@ static int dsa_user_unsync_mc(struct net_device *dev, return 0; return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, - &ctx); + &ctx); } void dsa_user_sync_ha(struct net_device *dev) From 08932323ccf7f8c4c85db9cb12a791ed81264f66 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 2 Feb 2024 18:36:25 +0200 Subject: [PATCH 0729/2255] net: dsa: qca8k: put MDIO controller OF node if unavailable It was pointed out during the review [1] of commit e66bf63a7f67 ("net: dsa: qca8k: skip MDIO bus creation if its OF node has status = "disabled"") that we now leak a reference to the "mdio" OF node if it is disabled. This is only a concern when using dynamic OF as far as I can tell (like probing on an overlay), since OF nodes are never freed in the regular case. Additionally, I'm unaware of any actual device trees (in production or elsewhere) which have status = "disabled" for the MDIO OF node. So handling this as a simple enhancement. [1] https://lore.kernel.org/netdev/CAJq09z4--Ug+3FAmp=EimQ8HTQYOWOuVon-PUMGB5a1N=RPv4g@mail.gmail.com/ Suggested-by: Luiz Angelo Daros de Luca Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/qca/qca8k-8xxx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 7a864329cb72..95d78b3181d1 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -954,7 +954,7 @@ qca8k_mdio_register(struct qca8k_priv *priv) mdio = of_get_child_by_name(dev->of_node, "mdio"); if (mdio && !of_device_is_available(mdio)) - goto out; + goto out_put_node; bus = devm_mdiobus_alloc(dev); if (!bus) { @@ -988,7 +988,6 @@ qca8k_mdio_register(struct qca8k_priv *priv) out_put_node: of_node_put(mdio); -out: return err; } From 709776ea85625fb668ced6b97b005cf53612996e Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 2 Feb 2024 18:36:26 +0200 Subject: [PATCH 0730/2255] net: dsa: qca8k: consistently use "ret" rather than "err" for error codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was pointed out during the review [1] of commit 68e1010cda79 ("net: dsa: qca8k: put MDIO bus OF node on qca8k_mdio_register() failure") that the rest of the qca8k driver uses "int ret" rather than "int err". Make everything consistent in that regard, not only qca8k_mdio_register(), but also qca8k_setup_mdio_bus(). [1] https://lore.kernel.org/netdev/qyl2w3ownx5q7363kqxib52j5htar4y6pkn7gen27rj45xr4on@pvy5agi6o2te/ Suggested-by: Alvin Šipraga Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Reviewed-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/net/dsa/qca/qca8k-8xxx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 95d78b3181d1..dab66c0c6f64 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -950,7 +950,7 @@ qca8k_mdio_register(struct qca8k_priv *priv) struct device *dev = ds->dev; struct device_node *mdio; struct mii_bus *bus; - int err = 0; + int ret = 0; mdio = of_get_child_by_name(dev->of_node, "mdio"); if (mdio && !of_device_is_available(mdio)) @@ -958,7 +958,7 @@ qca8k_mdio_register(struct qca8k_priv *priv) bus = devm_mdiobus_alloc(dev); if (!bus) { - err = -ENOMEM; + ret = -ENOMEM; goto out_put_node; } @@ -984,11 +984,11 @@ qca8k_mdio_register(struct qca8k_priv *priv) bus->write = qca8k_legacy_mdio_write; } - err = devm_of_mdiobus_register(dev, bus, mdio); + ret = devm_of_mdiobus_register(dev, bus, mdio); out_put_node: of_node_put(mdio); - return err; + return ret; } static int @@ -997,7 +997,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv) u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; struct device_node *ports, *port; phy_interface_t mode; - int err; + int ret; ports = of_get_child_by_name(priv->dev->of_node, "ports"); if (!ports) @@ -1007,11 +1007,11 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv) return -EINVAL; for_each_available_child_of_node(ports, port) { - err = of_property_read_u32(port, "reg", ®); - if (err) { + ret = of_property_read_u32(port, "reg", ®); + if (ret) { of_node_put(port); of_node_put(ports); - return err; + return ret; } if (!dsa_is_user_port(priv->ds, reg)) From 8ff25dac88f616ebebb30830e3a20f079d7a30c9 Mon Sep 17 00:00:00 2001 From: David Wei Date: Tue, 30 Jan 2024 13:46:20 -0800 Subject: [PATCH 0731/2255] netdevsim: add Makefile for selftests Add a Makefile for netdevsim selftests and add selftests path to MAINTAINERS Signed-off-by: David Wei Link: https://lore.kernel.org/r/20240130214620.3722189-5-dw@davidwei.uk Signed-off-by: Jakub Kicinski --- MAINTAINERS | 1 + .../selftests/drivers/net/netdevsim/Makefile | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tools/testing/selftests/drivers/net/netdevsim/Makefile diff --git a/MAINTAINERS b/MAINTAINERS index f70c15292707..3f465fd778b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15087,6 +15087,7 @@ NETDEVSIM M: Jakub Kicinski S: Maintained F: drivers/net/netdevsim/* +F: tools/testing/selftests/drivers/net/netdevsim/* NETEM NETWORK EMULATOR M: Stephen Hemminger diff --git a/tools/testing/selftests/drivers/net/netdevsim/Makefile b/tools/testing/selftests/drivers/net/netdevsim/Makefile new file mode 100644 index 000000000000..7a29a05bea8b --- /dev/null +++ b/tools/testing/selftests/drivers/net/netdevsim/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0+ OR MIT + +TEST_PROGS = devlink.sh \ + devlink_in_netns.sh \ + devlink_trap.sh \ + ethtool-coalesce.sh \ + ethtool-fec.sh \ + ethtool-pause.sh \ + ethtool-ring.sh \ + fib.sh \ + hw_stats_l3.sh \ + nexthop.sh \ + psample.sh \ + tc-mq-visibility.sh \ + udp_tunnel_nic.sh \ + +include ../../../lib.mk From 54ca3308a23c5fc0cd5c53d86918217834626c44 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 1 Feb 2024 11:58:30 +0800 Subject: [PATCH 0732/2255] wifi: ath12k: enable 802.11 power save mode in station mode To reduce power consumption enable 802.11 power save mode in station mode. This allows both radio and CPU to sleep more. Only enable the mode on WCN7850, other chips don't support it for now. To test that power save mode is running, run below command and check there is no NULL Data frame seen by a sniffer: iw dev set power_save off And run below command, then check there is a NULL Data frame in sniffer: iw dev set power_save on 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/20240201035830.2534-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/hw.c | 6 +++ drivers/net/wireless/ath/ath12k/hw.h | 2 + drivers/net/wireless/ath/ath12k/mac.c | 54 ++++++++++++++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index a984171e4a08..97e5a0ccd233 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -266,6 +266,7 @@ struct ath12k_vif { u8 tx_encap_type; u8 vdev_stats_id; u32 punct_bitmap; + bool ps; }; struct ath12k_vif_iter { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index a9adb547c83d..6e2242a79a2f 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -918,6 +918,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .max_mlo_peer = 256, .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, + + .supports_sta_ps = false, }, { .name = "wcn7850 hw2.0", @@ -986,6 +988,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .max_mlo_peer = 32, .otp_board_id_register = 0, + + .supports_sta_ps = true, }, { .name = "qcn9274 hw2.0", @@ -1052,6 +1056,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .max_mlo_peer = 256, .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, + + .supports_sta_ps = false, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 2e9c3b05d75a..87965980b938 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -209,6 +209,8 @@ struct ath12k_hw_params { u16 max_mlo_peer; u32 otp_board_id_register; + + bool supports_sta_ps; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 6ef55876e7df..fb5bf500ed87 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2510,12 +2510,60 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, return ret; } +static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf; + enum wmi_sta_powersave_param param; + enum wmi_sta_ps_mode psmode; + int ret; + int timeout; + bool enable_ps; + + lockdep_assert_held(&ar->conf_mutex); + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + enable_ps = arvif->ps; + if (enable_ps) { + psmode = WMI_STA_PS_MODE_ENABLED; + param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + + timeout = conf->dynamic_ps_timeout; + if (timeout == 0) { + /* firmware doesn't like 0 */ + timeout = ieee80211_tu_to_usec(vif->bss_conf.beacon_int) / 1000; + } + + ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, + timeout); + if (ret) { + ath12k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n", + arvif->vdev_id, ret); + return; + } + } else { + psmode = WMI_STA_PS_MODE_DISABLED; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d psmode %s\n", + arvif->vdev_id, psmode ? "enable" : "disable"); + + ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); + if (ret) + ath12k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n", + psmode, arvif->vdev_id, ret); +} + static void ath12k_mac_bss_info_changed(struct ath12k *ar, struct ath12k_vif *arvif, struct ieee80211_bss_conf *info, u64 changed) { struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif_cfg *vif_cfg = &vif->cfg; struct cfg80211_chan_def def; u32 param_id, param_value; enum nl80211_band band; @@ -2788,6 +2836,12 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, if (changed & BSS_CHANGED_EHT_PUNCTURING) arvif->punct_bitmap = info->eht_puncturing; + + if (changed & BSS_CHANGED_PS && + ar->ab->hw_params->supports_sta_ps) { + arvif->ps = vif_cfg->ps; + ath12k_mac_vif_setup_ps(arvif); + } } static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, From b802e7b7e771dee3377d071418281f8b64d2d832 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 2 Feb 2024 10:35:47 +0800 Subject: [PATCH 0733/2255] wifi: ath11k: initialize rx_mcs_80 and rx_mcs_160 before use Currently in ath11k_peer_assoc_h_he() rx_mcs_80 and rx_mcs_160 are used to calculate max_nss, see if (support_160) max_nss = min(rx_mcs_80, rx_mcs_160); else max_nss = rx_mcs_80; Kernel test robot complains on uninitialized symbols: drivers/net/wireless/ath/ath11k/mac.c:2321 ath11k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_80'. drivers/net/wireless/ath/ath11k/mac.c:2321 ath11k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_160'. drivers/net/wireless/ath/ath11k/mac.c:2323 ath11k_peer_assoc_h_he() error: uninitialized symbol 'rx_mcs_80'. This is because there are some code paths that never set them, so the assignment of max_nss can come from uninitialized variables. This could result in some unknown issues since a wrong peer_nss might be passed to firmware. Change to initialize them to an invalid value at the beginning. This makes sense because even max_nss gets an invalid value, due to either or both of them being invalid, we can get an valid peer_nss with following guard: arg->peer_nss = min(sta->deflink.rx_nss, max_nss) Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 3db26ecf7114 ("ath11k: calculate the correct NSS of peer for HE capabilities") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401311243.NyXwWZxP-lkp@intel.com/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240202023547.11141-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index df1b1ee71881..10cfb60e14a0 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2294,6 +2294,8 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); + /* Initialize rx_mcs_160 to 9 which is an invalid value */ + rx_mcs_160 = 9; if (support_160) { for (i = 7; i >= 0; i--) { u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; @@ -2305,6 +2307,8 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, } } + /* Initialize rx_mcs_80 to 9 which is an invalid value */ + rx_mcs_80 = 9; for (i = 7; i >= 0; i--) { u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; From b82fb7ef690bd929b88d9aab1d191ff502ed9029 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 2 Feb 2024 10:40:11 +0800 Subject: [PATCH 0734/2255] wifi: ath11k: initialize eirp_power before use Currently, at the end of ath11k_mac_fill_reg_tpc_info(), the reg_tpc_info struct is populated, including the following: reg_tpc_info->is_psd_power = is_psd_power; reg_tpc_info->eirp_power = eirp_power; Kernel test robot complains on uninitialized symbol: drivers/net/wireless/ath/ath11k/mac.c:7949 ath11k_mac_fill_reg_tpc_info() error: uninitialized symbol 'eirp_power'. This is because there are some code paths that never set eirp_power, so the assignment of reg_tpc_info->eirp_power can come from an uninitialized variable. Functionally this is OK since the eirp_power only has meaning when is_psd_power is true, and all code paths which set is_psd_power to true also set eirp_power. However, to keep the robot happy, always initialize eirp_power before use. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 92425f788fee ("wifi: ath11k: fill parameters for vdev set tpc power WMI command") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401311243.NyXwWZxP-lkp@intel.com/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240202024011.11341-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 10cfb60e14a0..dc2bf13f00c1 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7597,7 +7597,8 @@ void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, 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; + psd_power, tx_power; + s8 eirp_power = 0; u16 start_freq, center_freq; chan = ctx->def.chan; From 5f0e4aede01cb01fa633171f0533affd25328c3a Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 26 Jan 2024 15:53:34 +0800 Subject: [PATCH 0735/2255] 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(-) 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; } From 1209f487d452ff7e822dec30661fd6b5163fb8cf Mon Sep 17 00:00:00 2001 From: Chun Qiu Date: Mon, 29 Jan 2024 13:30:30 +0800 Subject: [PATCH 0736/2255] 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(-) 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), From 2b59c9c30b9cbbb9807abcb2eca0a45ce40611df Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 30 Jan 2024 17:15:53 +0200 Subject: [PATCH 0737/2255] 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(-) 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) From 0583e5acaf43644c4d4f476979c18bf1a034639f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 30 Jan 2024 17:15:54 +0200 Subject: [PATCH 0738/2255] 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(-) 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); From 7ceade653429c1c6af387d4039199eeae3b685c1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 30 Jan 2024 17:15:55 +0200 Subject: [PATCH 0739/2255] 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(-) 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 */ From 04e9c8af8b2d9b51febb522c1f2dae7521dbc154 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:21 +0100 Subject: [PATCH 0740/2255] 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(-) 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 From b303de763b638f4a8703651944e7a724739dba74 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:22 +0100 Subject: [PATCH 0741/2255] 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(-) 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 From 163857d995312a7b5fe3039ce0145b84cc7673b1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:23 +0100 Subject: [PATCH 0742/2255] 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(-) 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 From d8da5a213812cb0092854f586aa26735b59be85b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:24 +0100 Subject: [PATCH 0743/2255] 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(-) 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 From 2719a9e7156c4b3983b43db467c1ff96801bda99 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:25 +0100 Subject: [PATCH 0744/2255] 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 | 73 +++++++++++--------- include/linux/platform_data/net-cw1200.h | 4 -- 3 files changed, 66 insertions(+), 53 deletions(-) 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,22 +371,35 @@ 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)) { - pr_err("spi_on() failed!\n"); - return -1; - } - - 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; } + /* 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 -ENODEV; + } + + if (spi_setup(func)) { + pr_err("spi_setup() failed!\n"); + return -ENODEV; + } + self->pdata = plat_data; self->func = func; spin_lock_init(&self->lock); @@ -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 */ From bed41a344426a407ba5e103b2877a2e560e72229 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 1 Feb 2024 14:12:47 -0600 Subject: [PATCH 0745/2255] 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(-) 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) From df9705eaa0bad034dad0f73386ff82f5c4dd7e24 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 2 Feb 2024 21:51:19 -0800 Subject: [PATCH 0746/2255] bpf: Remove an unnecessary check. The "i" here is always equal to "btf_type_vlen(t)" since the "for_each_member()" loop never breaks. Signed-off-by: Kui-Feng Lee Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240203055119.2235598-1-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/bpf_struct_ops.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 0decd862dfe0..f98f580de77a 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -189,20 +189,17 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, } } - if (i == btf_type_vlen(t)) { - if (st_ops->init(btf)) { - pr_warn("Error in init bpf_struct_ops %s\n", - st_ops->name); - return -EINVAL; - } else { - st_ops_desc->type_id = type_id; - st_ops_desc->type = t; - st_ops_desc->value_id = value_id; - st_ops_desc->value_type = btf_type_by_id(btf, - value_id); - } + if (st_ops->init(btf)) { + pr_warn("Error in init bpf_struct_ops %s\n", + st_ops->name); + return -EINVAL; } + st_ops_desc->type_id = type_id; + st_ops_desc->type = t; + st_ops_desc->value_id = value_id; + st_ops_desc->value_type = btf_type_by_id(btf, value_id); + return 0; } From 7e428638bd784fd9e8944bfbf11513520e141b91 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Sun, 4 Feb 2024 11:44:52 -0800 Subject: [PATCH 0747/2255] selftests/bpf: Fix flaky test ptr_untrusted Somehow recently I frequently hit the following test failure with either ./test_progs or ./test_progs-cpuv4: serial_test_ptr_untrusted:PASS:skel_open 0 nsec serial_test_ptr_untrusted:PASS:lsm_attach 0 nsec serial_test_ptr_untrusted:PASS:raw_tp_attach 0 nsec serial_test_ptr_untrusted:FAIL:cmp_tp_name unexpected cmp_tp_name: actual -115 != expected 0 #182 ptr_untrusted:FAIL Further investigation found the failure is due to bpf_probe_read_user_str() where reading user-level string attr->raw_tracepoint.name is not successfully, most likely due to the string itself still in disk and not populated into memory yet. One solution is do a printf() call of the string before doing bpf syscall which will force the raw_tracepoint.name into memory. But I think a more robust solution is to use bpf_copy_from_user() which is used in sleepable program and can tolerate page fault, and the fix here used the latter approach. Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240204194452.2785936-1-yonghong.song@linux.dev --- tools/testing/selftests/bpf/progs/test_ptr_untrusted.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/test_ptr_untrusted.c b/tools/testing/selftests/bpf/progs/test_ptr_untrusted.c index 4bdd65b5aa2d..2fdc44e76624 100644 --- a/tools/testing/selftests/bpf/progs/test_ptr_untrusted.c +++ b/tools/testing/selftests/bpf/progs/test_ptr_untrusted.c @@ -6,13 +6,13 @@ char tp_name[128]; -SEC("lsm/bpf") +SEC("lsm.s/bpf") int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size) { switch (cmd) { case BPF_RAW_TRACEPOINT_OPEN: - bpf_probe_read_user_str(tp_name, sizeof(tp_name) - 1, - (void *)attr->raw_tracepoint.name); + bpf_copy_from_user(tp_name, sizeof(tp_name) - 1, + (void *)attr->raw_tracepoint.name); break; default: break; From 169e650069647325496e5a65408ff301874c8e01 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Sat, 3 Feb 2024 22:12:04 -0800 Subject: [PATCH 0748/2255] selftests/bpf: Suppress warning message of an unused variable. "r" is used to receive the return value of test_2 in bpf_testmod.c, but it is not actually used. So, we remove "r" and change the return type to "void". Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202401300557.z5vzn8FM-lkp@intel.com/ Signed-off-by: Kui-Feng Lee Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240204061204.1864529-1-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c | 6 ++---- tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h | 2 +- tools/testing/selftests/bpf/progs/struct_ops_module.c | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 4754c662b39f..a06daebc75c9 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -554,9 +554,8 @@ static const struct bpf_verifier_ops bpf_testmod_verifier_ops = { static int bpf_dummy_reg(void *kdata) { struct bpf_testmod_ops *ops = kdata; - int r; - r = ops->test_2(4, 3); + ops->test_2(4, 3); return 0; } @@ -570,9 +569,8 @@ static int bpf_testmod_test_1(void) return 0; } -static int bpf_testmod_test_2(int a, int b) +static void bpf_testmod_test_2(int a, int b) { - return 0; } static struct bpf_testmod_ops __bpf_testmod_ops = { diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h index ca5435751c79..537beca42896 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h @@ -30,7 +30,7 @@ struct bpf_iter_testmod_seq { struct bpf_testmod_ops { int (*test_1)(void); - int (*test_2)(int a, int b); + void (*test_2)(int a, int b); }; #endif /* _BPF_TESTMOD_H */ diff --git a/tools/testing/selftests/bpf/progs/struct_ops_module.c b/tools/testing/selftests/bpf/progs/struct_ops_module.c index e44ac55195ca..b78746b3cef3 100644 --- a/tools/testing/selftests/bpf/progs/struct_ops_module.c +++ b/tools/testing/selftests/bpf/progs/struct_ops_module.c @@ -16,10 +16,9 @@ int BPF_PROG(test_1) } SEC("struct_ops/test_2") -int BPF_PROG(test_2, int a, int b) +void BPF_PROG(test_2, int a, int b) { test_2_result = a + b; - return a + b; } SEC(".struct_ops.link") From e7f31873176a345d72ca77c7b4da48493ccd9efd Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Sun, 4 Feb 2024 21:29:14 -0800 Subject: [PATCH 0749/2255] selftests/bpf: Fix flaky selftest lwt_redirect/lwt_reroute Recently, when running './test_progs -j', I occasionally hit the following errors: test_lwt_redirect:PASS:pthread_create 0 nsec test_lwt_redirect_run:FAIL:netns_create unexpected error: 256 (errno 0) #142/2 lwt_redirect/lwt_redirect_normal_nomac:FAIL #142 lwt_redirect:FAIL test_lwt_reroute:PASS:pthread_create 0 nsec test_lwt_reroute_run:FAIL:netns_create unexpected error: 256 (errno 0) test_lwt_reroute:PASS:pthread_join 0 nsec #143/2 lwt_reroute/lwt_reroute_qdisc_dropped:FAIL #143 lwt_reroute:FAIL The netns_create() definition looks like below: #define NETNS "ns_lwt" static inline int netns_create(void) { return system("ip netns add " NETNS); } One possibility is that both lwt_redirect and lwt_reroute create netns with the same name "ns_lwt" which may cause conflict. I tried the following example: $ sudo ip netns add abc $ echo $? 0 $ sudo ip netns add abc Cannot create namespace file "/var/run/netns/abc": File exists $ echo $? 1 $ The return code for above netns_create() is 256. The internet search suggests that the return value for 'ip netns add ns_lwt' is 1, which matches the above 'sudo ip netns add abc' example. This patch tried to use different netns names for two tests to avoid 'ip netns add ' failure. I ran './test_progs -j' 10 times and all succeeded with lwt_redirect/lwt_reroute tests. Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Tested-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20240205052914.1742687-1-yonghong.song@linux.dev --- tools/testing/selftests/bpf/prog_tests/lwt_helpers.h | 2 -- tools/testing/selftests/bpf/prog_tests/lwt_redirect.c | 1 + tools/testing/selftests/bpf/prog_tests/lwt_reroute.c | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_helpers.h b/tools/testing/selftests/bpf/prog_tests/lwt_helpers.h index e9190574e79f..fb1eb8c67361 100644 --- a/tools/testing/selftests/bpf/prog_tests/lwt_helpers.h +++ b/tools/testing/selftests/bpf/prog_tests/lwt_helpers.h @@ -27,8 +27,6 @@ } \ }) -#define NETNS "ns_lwt" - static inline int netns_create(void) { return system("ip netns add " NETNS); diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c index b5b9e74b1044..835a1d756c16 100644 --- a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c +++ b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c @@ -54,6 +54,7 @@ #include #include +#define NETNS "ns_lwt_redirect" #include "lwt_helpers.h" #include "test_progs.h" #include "network_helpers.h" diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c b/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c index 5610bc76928d..03825d2b45a8 100644 --- a/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c +++ b/tools/testing/selftests/bpf/prog_tests/lwt_reroute.c @@ -48,6 +48,7 @@ * For case 2, force UDP packets to overflow fq limit. As long as kernel * is not crashed, it is considered successful. */ +#define NETNS "ns_lwt_reroute" #include "lwt_helpers.h" #include "network_helpers.h" #include From 2d9a925d0fbf0dae99af148adaf4f5cadf1be5e0 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Fri, 2 Feb 2024 14:11:10 -0800 Subject: [PATCH 0750/2255] bpf, docs: Expand set of initial conformance groups This patch attempts to update the ISA specification according to the latest mailing list discussion about conformance groups, in a way that is intended to be consistent with IANA registry processes and IETF 118 WG meeting discussion. It does the following: * Split basic into base32 and base64 for 32-bit vs 64-bit base instructions * Split division/multiplication/modulo instructions out of base groups * Split atomic instructions out of base groups There may be additional changes as discussion continues, but there seems to be consensus on the principles above. v1->v2: fixed typo pointed out by David Vernet v2->v3: Moved multiplication to same groups as division/modulo Signed-off-by: Dave Thaler Acked-by: David Vernet Link: https://lore.kernel.org/r/20240202221110.3872-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/standardization/instruction-set.rst | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index dcbc9193c66f..1c4258f1ce93 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -102,7 +102,7 @@ Conformance groups An implementation does not need to support all instructions specified in this document (e.g., deprecated instructions). Instead, a number of conformance -groups are specified. An implementation must support the "basic" conformance +groups are specified. An implementation must support the base32 conformance group and may support additional conformance groups, where supporting a conformance group means it must support all instructions in that conformance group. @@ -112,12 +112,21 @@ that executes instructions, and tools as such compilers that generate instructions for the runtime. Thus, capability discovery in terms of conformance groups might be done manually by users or automatically by tools. -Each conformance group has a short ASCII label (e.g., "basic") that +Each conformance group has a short ASCII label (e.g., "base32") that corresponds to a set of instructions that are mandatory. That is, each instruction has one or more conformance groups of which it is a member. -The "basic" conformance group includes all instructions defined in this -specification unless otherwise noted. +This document defines the following conformance groups: +* base32: includes all instructions defined in this + specification unless otherwise noted. +* base64: includes base32, plus instructions explicitly noted + as being in the base64 conformance group. +* atomic32: includes 32-bit atomic operation instructions (see `Atomic operations`_). +* atomic64: includes atomic32, plus 64-bit atomic operation instructions. +* divmul32: includes 32-bit division, multiplication, and modulo instructions. +* divmul64: includes divmul32, plus 64-bit division, multiplication, + and modulo instructions. +* legacy: deprecated packet access instructions. Instruction encoding ==================== @@ -234,7 +243,8 @@ Arithmetic instructions ----------------------- ``BPF_ALU`` uses 32-bit wide operands while ``BPF_ALU64`` uses 64-bit wide operands for -otherwise identical operations. +otherwise identical operations. ``BPF_ALU64`` instructions belong to the +base64 conformance group unless noted otherwise. The 'code' field encodes the operation as below, where 'src' and 'dst' refer to the values of the source and destination registers, respectively. @@ -288,6 +298,10 @@ where '(u32)' indicates that the upper 32 bits are zeroed. Note that most instructions have instruction offset of 0. Only three instructions (``BPF_SDIV``, ``BPF_SMOD``, ``BPF_MOVSX``) have a non-zero offset. +Division, multiplication, and modulo operations for ``BPF_ALU`` are part +of the "divmul32" conformance group, and division, multiplication, and +modulo operations for ``BPF_ALU64`` are part of the "divmul64" conformance +group. The division and modulo operations support both unsigned and signed flavors. For unsigned operations (``BPF_DIV`` and ``BPF_MOD``), for ``BPF_ALU``, @@ -344,7 +358,9 @@ BPF_ALU64 Reserved 0x00 do byte swap unconditionally ========= ========= ===== ================================================= The 'imm' field encodes the width of the swap operations. The following widths -are supported: 16, 32 and 64. +are supported: 16, 32 and 64. Width 64 operations belong to the base64 +conformance group and other swap operations belong to the base32 +conformance group. Examples: @@ -369,8 +385,10 @@ Examples: Jump instructions ----------------- -``BPF_JMP32`` uses 32-bit wide operands while ``BPF_JMP`` uses 64-bit wide operands for -otherwise identical operations. +``BPF_JMP32`` uses 32-bit wide operands and indicates the base32 +conformance group, while ``BPF_JMP`` uses 64-bit wide operands for +otherwise identical operations, and indicates the base64 conformance +group unless otherwise specified. The 'code' field encodes the operation as below: ======== ===== === =============================== ============================================= @@ -419,6 +437,9 @@ specified by the 'imm' field. A > 16-bit conditional jump may be converted to a < 16-bit conditional jump plus a 32-bit unconditional jump. +All ``BPF_CALL`` and ``BPF_JA`` instructions belong to the +base32 conformance group. + Helper functions ~~~~~~~~~~~~~~~~ @@ -476,6 +497,8 @@ The size modifier is one of: BPF_DW 0x18 double word (8 bytes) ============= ===== ===================== +Instructions using ``BPF_DW`` belong to the base64 conformance group. + Regular load and store operations --------------------------------- @@ -520,8 +543,10 @@ by other BPF programs or means outside of this specification. All atomic operations supported by BPF are encoded as store operations that use the ``BPF_ATOMIC`` mode modifier as follows: -* ``BPF_ATOMIC | BPF_W | BPF_STX`` for 32-bit operations -* ``BPF_ATOMIC | BPF_DW | BPF_STX`` for 64-bit operations +* ``BPF_ATOMIC | BPF_W | BPF_STX`` for 32-bit operations, which are + part of the "atomic32" conformance group. +* ``BPF_ATOMIC | BPF_DW | BPF_STX`` for 64-bit operations, which are + part of the "atomic64" conformance group. * 8-bit and 16-bit wide atomic operations are not supported. The 'imm' field is used to encode the actual atomic operation. @@ -634,5 +659,4 @@ carried over from classic BPF. These instructions used an instruction class of BPF_LD, a size modifier of BPF_W, BPF_H, or BPF_B, and a mode modifier of BPF_ABS or BPF_IND. However, these instructions are deprecated and should no longer be used. All legacy packet access -instructions belong to the "legacy" conformance group instead of the "basic" -conformance group. +instructions belong to the "legacy" conformance group. From fd2bc4195d5107f88c1b90e1ec935888ccbfc5c0 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 3 Oct 2023 20:57:20 +0300 Subject: [PATCH 0751/2255] xfrm: generalize xdo_dev_state_update_curlft to allow statistics update In order to allow drivers to fill all statistics, change the name of xdo_dev_state_update_curlft to be xdo_dev_state_update_stats. Acked-by: Steffen Klassert Signed-off-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- Documentation/networking/xfrm_device.rst | 4 ++-- .../net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 7 ++++--- include/linux/netdevice.h | 2 +- include/net/xfrm.h | 11 ++++------- net/xfrm/xfrm_state.c | 4 ++-- net/xfrm/xfrm_user.c | 2 +- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Documentation/networking/xfrm_device.rst b/Documentation/networking/xfrm_device.rst index 535077cbeb07..bfea9d8579ed 100644 --- a/Documentation/networking/xfrm_device.rst +++ b/Documentation/networking/xfrm_device.rst @@ -71,9 +71,9 @@ Callbacks to implement bool (*xdo_dev_offload_ok) (struct sk_buff *skb, struct xfrm_state *x); void (*xdo_dev_state_advance_esn) (struct xfrm_state *x); + void (*xdo_dev_state_update_stats) (struct xfrm_state *x); /* Solely packet offload callbacks */ - void (*xdo_dev_state_update_curlft) (struct xfrm_state *x); int (*xdo_dev_policy_add) (struct xfrm_policy *x, struct netlink_ext_ack *extack); void (*xdo_dev_policy_delete) (struct xfrm_policy *x); void (*xdo_dev_policy_free) (struct xfrm_policy *x); @@ -191,6 +191,6 @@ xdo_dev_policy_free() on any remaining offloaded states. Outcome of HW handling packets, the XFRM core can't count hard, soft limits. The HW/driver are responsible to perform it and provide accurate data when -xdo_dev_state_update_curlft() is called. In case of one of these limits +xdo_dev_state_update_stats() is called. In case of one of these limits occuried, the driver needs to call to xfrm_state_check_expire() to make sure that XFRM performs rekeying sequence. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index 05612d9c6080..f160522fbe75 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -984,7 +984,7 @@ static void mlx5e_xfrm_advance_esn_state(struct xfrm_state *x) queue_work(sa_entry->ipsec->wq, &work->work); } -static void mlx5e_xfrm_update_curlft(struct xfrm_state *x) +static void mlx5e_xfrm_update_stats(struct xfrm_state *x) { struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x); struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule; @@ -993,7 +993,8 @@ static void mlx5e_xfrm_update_curlft(struct xfrm_state *x) lockdep_assert(lockdep_is_held(&x->lock) || lockdep_is_held(&dev_net(x->xso.real_dev)->xfrm.xfrm_cfg_mutex)); - if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ) + if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ || + x->xso.type != XFRM_DEV_OFFLOAD_PACKET) return; mlx5_fc_query_cached(ipsec_rule->fc, &bytes, &packets, &lastuse); @@ -1156,7 +1157,7 @@ static const struct xfrmdev_ops mlx5e_ipsec_xfrmdev_ops = { .xdo_dev_offload_ok = mlx5e_ipsec_offload_ok, .xdo_dev_state_advance_esn = mlx5e_xfrm_advance_esn_state, - .xdo_dev_state_update_curlft = mlx5e_xfrm_update_curlft, + .xdo_dev_state_update_stats = mlx5e_xfrm_update_stats, .xdo_dev_policy_add = mlx5e_xfrm_add_policy, .xdo_dev_policy_delete = mlx5e_xfrm_del_policy, .xdo_dev_policy_free = mlx5e_xfrm_free_policy, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 118c40258d07..9538576dbebc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1062,7 +1062,7 @@ struct xfrmdev_ops { bool (*xdo_dev_offload_ok) (struct sk_buff *skb, struct xfrm_state *x); void (*xdo_dev_state_advance_esn) (struct xfrm_state *x); - void (*xdo_dev_state_update_curlft) (struct xfrm_state *x); + void (*xdo_dev_state_update_stats) (struct xfrm_state *x); int (*xdo_dev_policy_add) (struct xfrm_policy *x, struct netlink_ext_ack *extack); void (*xdo_dev_policy_delete) (struct xfrm_policy *x); void (*xdo_dev_policy_free) (struct xfrm_policy *x); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 1d107241b901..4ca2f3205190 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1578,21 +1578,18 @@ struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, unsigned short family); int xfrm_state_check_expire(struct xfrm_state *x); #ifdef CONFIG_XFRM_OFFLOAD -static inline void xfrm_dev_state_update_curlft(struct xfrm_state *x) +static inline void xfrm_dev_state_update_stats(struct xfrm_state *x) { struct xfrm_dev_offload *xdo = &x->xso; struct net_device *dev = xdo->dev; - if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) - return; - if (dev && dev->xfrmdev_ops && - dev->xfrmdev_ops->xdo_dev_state_update_curlft) - dev->xfrmdev_ops->xdo_dev_state_update_curlft(x); + dev->xfrmdev_ops->xdo_dev_state_update_stats) + dev->xfrmdev_ops->xdo_dev_state_update_stats(x); } #else -static inline void xfrm_dev_state_update_curlft(struct xfrm_state *x) {} +static inline void xfrm_dev_state_update_stats(struct xfrm_state *x) {} #endif void xfrm_state_insert(struct xfrm_state *x); int xfrm_state_add(struct xfrm_state *x); diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index bda5327bf34d..d8701b2d0d57 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -570,7 +570,7 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) int err = 0; spin_lock(&x->lock); - xfrm_dev_state_update_curlft(x); + xfrm_dev_state_update_stats(x); if (x->km.state == XFRM_STATE_DEAD) goto out; @@ -1935,7 +1935,7 @@ EXPORT_SYMBOL(xfrm_state_update); int xfrm_state_check_expire(struct xfrm_state *x) { - xfrm_dev_state_update_curlft(x); + xfrm_dev_state_update_stats(x); if (!READ_ONCE(x->curlft.use_time)) WRITE_ONCE(x->curlft.use_time, ktime_get_real_seconds()); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ad01997c3aa9..dc4f9b8d7cb0 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -902,7 +902,7 @@ static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) memcpy(&p->sel, &x->sel, sizeof(p->sel)); memcpy(&p->lft, &x->lft, sizeof(p->lft)); if (x->xso.dev) - xfrm_dev_state_update_curlft(x); + xfrm_dev_state_update_stats(x); memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); put_unaligned(x->stats.replay_window, &p->stats.replay_window); put_unaligned(x->stats.replay, &p->stats.replay); From f9f221c98fd83df518fbb2f5ad33980cfedfe1bf Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 4 Oct 2023 14:11:48 +0300 Subject: [PATCH 0752/2255] xfrm: get global statistics from the offloaded device Iterate over all SAs in order to fill global IPsec statistics. Acked-by: Steffen Klassert Signed-off-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 3 ++- include/net/xfrm.h | 3 +++ net/xfrm/xfrm_proc.c | 1 + net/xfrm/xfrm_state.c | 13 +++++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index f160522fbe75..46cce4e38d84 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -991,7 +991,8 @@ static void mlx5e_xfrm_update_stats(struct xfrm_state *x) u64 packets, bytes, lastuse; lockdep_assert(lockdep_is_held(&x->lock) || - lockdep_is_held(&dev_net(x->xso.real_dev)->xfrm.xfrm_cfg_mutex)); + lockdep_is_held(&dev_net(x->xso.real_dev)->xfrm.xfrm_cfg_mutex) || + lockdep_is_held(&dev_net(x->xso.real_dev)->xfrm.xfrm_state_lock)); if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ || x->xso.type != XFRM_DEV_OFFLOAD_PACKET) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 4ca2f3205190..57c743b7e4fe 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -51,8 +51,10 @@ #ifdef CONFIG_XFRM_STATISTICS #define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field) +#define XFRM_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.xfrm_statistics, field, val) #else #define XFRM_INC_STATS(net, field) ((void)(net)) +#define XFRM_ADD_STATS(net, field, val) ((void)(net)) #endif @@ -1577,6 +1579,7 @@ struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, unsigned short family); int xfrm_state_check_expire(struct xfrm_state *x); +void xfrm_state_update_stats(struct net *net); #ifdef CONFIG_XFRM_OFFLOAD static inline void xfrm_dev_state_update_stats(struct xfrm_state *x) { diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c index fee9b5cf37a7..5f9bf8e5c933 100644 --- a/net/xfrm/xfrm_proc.c +++ b/net/xfrm/xfrm_proc.c @@ -52,6 +52,7 @@ static int xfrm_statistics_seq_show(struct seq_file *seq, void *v) memset(buff, 0, sizeof(unsigned long) * LINUX_MIB_XFRMMAX); + xfrm_state_update_stats(net); snmp_get_cpu_field_batch(buff, xfrm_mib_list, net->mib.xfrm_statistics); for (i = 0; xfrm_mib_list[i].name; i++) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index d8701b2d0d57..0c306473a79d 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1957,6 +1957,19 @@ int xfrm_state_check_expire(struct xfrm_state *x) } EXPORT_SYMBOL(xfrm_state_check_expire); +void xfrm_state_update_stats(struct net *net) +{ + struct xfrm_state *x; + int i; + + spin_lock_bh(&net->xfrm.xfrm_state_lock); + for (i = 0; i <= net->xfrm.state_hmask; i++) { + hlist_for_each_entry(x, net->xfrm.state_bydst + i, bydst) + xfrm_dev_state_update_stats(x); + } + spin_unlock_bh(&net->xfrm.xfrm_state_lock); +} + struct xfrm_state * xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) From 6fb7f9408779d5153430f207785628f3e16a85fc Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 4 Oct 2023 14:58:37 +0300 Subject: [PATCH 0753/2255] net/mlx5e: Connect mlx5 IPsec statistics with XFRM core Fill integrity, replay and bad trailer counters. As an example, after simulating replay window attack with 5 packets: [leonro@c ~]$ grep XfrmInStateSeqError /proc/net/xfrm_stat XfrmInStateSeqError 5 [leonro@c ~]$ sudo ip -s x s <...> stats: replay-window 0 replay 5 failed 0 Signed-off-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/en_accel/ipsec.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index 46cce4e38d84..c54fd01ea635 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -988,19 +988,37 @@ static void mlx5e_xfrm_update_stats(struct xfrm_state *x) { struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x); struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule; + struct net *net = dev_net(x->xso.dev); u64 packets, bytes, lastuse; lockdep_assert(lockdep_is_held(&x->lock) || lockdep_is_held(&dev_net(x->xso.real_dev)->xfrm.xfrm_cfg_mutex) || lockdep_is_held(&dev_net(x->xso.real_dev)->xfrm.xfrm_state_lock)); - if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ || - x->xso.type != XFRM_DEV_OFFLOAD_PACKET) + if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ) + return; + + if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) { + mlx5_fc_query_cached(ipsec_rule->auth.fc, &bytes, &packets, &lastuse); + x->stats.integrity_failed += packets; + XFRM_ADD_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR, packets); + + mlx5_fc_query_cached(ipsec_rule->trailer.fc, &bytes, &packets, &lastuse); + XFRM_ADD_STATS(net, LINUX_MIB_XFRMINHDRERROR, packets); + } + + if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) return; mlx5_fc_query_cached(ipsec_rule->fc, &bytes, &packets, &lastuse); x->curlft.packets += packets; x->curlft.bytes += bytes; + + if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) { + mlx5_fc_query_cached(ipsec_rule->replay.fc, &bytes, &packets, &lastuse); + x->stats.replay += packets; + XFRM_ADD_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR, packets); + } } static int mlx5e_xfrm_validate_policy(struct mlx5_core_dev *mdev, From 77bed87f76207b73eded817f3c3db2b8b827dfe0 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 4 Oct 2023 15:42:56 +0300 Subject: [PATCH 0754/2255] net/mlx5e: Delete obsolete IPsec code After addition of HW managed counters and implementation drop in flow steering logic, the code in driver which checks syndrome is not reachable anymore. Let's delete it. Signed-off-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/en_accel/ipsec.h | 1 - .../mellanox/mlx5/core/en_accel/ipsec_rxtx.c | 25 ++----------------- .../mellanox/mlx5/core/en_accel/ipsec_rxtx.h | 1 - .../mellanox/mlx5/core/en_accel/ipsec_stats.c | 1 - 4 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h index adaea3493193..7d943e93cf6d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h @@ -137,7 +137,6 @@ struct mlx5e_ipsec_hw_stats { struct mlx5e_ipsec_sw_stats { atomic64_t ipsec_rx_drop_sp_alloc; atomic64_t ipsec_rx_drop_sadb_miss; - atomic64_t ipsec_rx_drop_syndrome; atomic64_t ipsec_tx_drop_bundle; atomic64_t ipsec_tx_drop_no_state; atomic64_t ipsec_tx_drop_not_ip; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c index 51a144246ea6..727fa7c18523 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c @@ -304,12 +304,6 @@ drop: return false; } -enum { - MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_DECRYPTED, - MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_AUTH_FAILED, - MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_BAD_TRAILER, -}; - void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb, u32 ipsec_meta_data) @@ -343,20 +337,7 @@ void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev, xo = xfrm_offload(skb); xo->flags = CRYPTO_DONE; - - switch (MLX5_IPSEC_METADATA_SYNDROM(ipsec_meta_data)) { - case MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_DECRYPTED: - xo->status = CRYPTO_SUCCESS; - break; - case MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_AUTH_FAILED: - xo->status = CRYPTO_TUNNEL_ESP_AUTH_FAILED; - break; - case MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_BAD_TRAILER: - xo->status = CRYPTO_INVALID_PACKET_SYNTAX; - break; - default: - atomic64_inc(&ipsec->sw_stats.ipsec_rx_drop_syndrome); - } + xo->status = CRYPTO_SUCCESS; } int mlx5_esw_ipsec_rx_make_metadata(struct mlx5e_priv *priv, u32 id, u32 *metadata) @@ -374,8 +355,6 @@ int mlx5_esw_ipsec_rx_make_metadata(struct mlx5e_priv *priv, u32 id, u32 *metada return err; } - *metadata = MLX5_IPSEC_METADATA_CREATE(ipsec_obj_id, - MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_DECRYPTED); - + *metadata = ipsec_obj_id; return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h index 2ed99772f168..82064614846f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h @@ -43,7 +43,6 @@ #define MLX5_IPSEC_METADATA_MARKER(metadata) (((metadata) >> 31) & 0x1) #define MLX5_IPSEC_METADATA_SYNDROM(metadata) (((metadata) >> 24) & GENMASK(5, 0)) #define MLX5_IPSEC_METADATA_HANDLE(metadata) ((metadata) & GENMASK(23, 0)) -#define MLX5_IPSEC_METADATA_CREATE(id, syndrome) ((id) | ((syndrome) << 24)) struct mlx5e_accel_tx_ipsec_state { struct xfrm_offload *xo; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c index e0e36a09721c..dd36b04e30a0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c @@ -51,7 +51,6 @@ static const struct counter_desc mlx5e_ipsec_hw_stats_desc[] = { static const struct counter_desc mlx5e_ipsec_sw_stats_desc[] = { { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_rx_drop_sp_alloc) }, { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_rx_drop_sadb_miss) }, - { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_rx_drop_syndrome) }, { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_bundle) }, { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_no_state) }, { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_not_ip) }, From 21e16fa5dc6c6f69d9f2cf84e6d8f147ec4c1fbe Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Fri, 26 Jan 2024 15:05:58 +0200 Subject: [PATCH 0755/2255] Documentation: Fix counter name of mlx5 vnic reporter Fix counter name in documentation of mlx5 vnic health reporter diagnose output: total_error_queues. While here fix alignment in the documentation file of another counter, comp_eq_overrun, as it should have its own line and not be part of another counter's description. Example: $ devlink health diagnose pci/0000:00:04.0 reporter vnic vNIC env counters: total_error_queues: 0 send_queue_priority_update_flow: 0 comp_eq_overrun: 0 async_eq_overrun: 0 cq_overrun: 0 invalid_command: 0 quota_exceeded_command: 0 nic_receive_steering_discard: 0 Signed-off-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- Documentation/networking/devlink/mlx5.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/devlink/mlx5.rst b/Documentation/networking/devlink/mlx5.rst index b9587b3400b9..456985407475 100644 --- a/Documentation/networking/devlink/mlx5.rst +++ b/Documentation/networking/devlink/mlx5.rst @@ -250,7 +250,7 @@ them in realtime. Description of the vnic counters: -- total_q_under_processor_handle +- total_error_queues number of queues in an error state due to an async error or errored command. - send_queue_priority_update_flow @@ -259,7 +259,8 @@ Description of the vnic counters: number of times CQ entered an error state due to an overflow. - async_eq_overrun number of times an EQ mapped to async events was overrun. - comp_eq_overrun number of times an EQ mapped to completion events was +- comp_eq_overrun + number of times an EQ mapped to completion events was overrun. - quota_exceeded_command number of commands issued and failed due to quota exceeded. From 8d7db0abafb8766132c13d32ebe9d5bdb6c968e2 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Sat, 2 Dec 2023 19:13:17 +0200 Subject: [PATCH 0756/2255] net/mlx5: Rename mlx5_sf_dev_remove Mlx5 has two functions with the same name mlx5_sf_dev_remove. Both are static, in different files, so no compilation or logical issue, but it makes it hard to follow the code and some traces even can get both as one leads to the other [1]. Rename one to mlx5_sf_dev_remove_aux() as it actually removes the auxiliary device of the SF. [1] mlx5_sf_dev_remove+0x2a/0x70 [mlx5_core] auxiliary_bus_remove+0x18/0x30 device_release_driver_internal+0x199/0x200 bus_remove_device+0xd7/0x140 device_del+0x153/0x3d0 ? process_one_work+0x16a/0x4b0 mlx5_sf_dev_remove+0x2e/0x90 [mlx5_core] mlx5_sf_dev_table_destroy+0xa0/0x100 [mlx5_core] Signed-off-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c index c93492b67788..99219ea52c4b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c @@ -74,7 +74,8 @@ static void mlx5_sf_dev_release(struct device *device) kfree(sf_dev); } -static void mlx5_sf_dev_remove(struct mlx5_core_dev *dev, struct mlx5_sf_dev *sf_dev) +static void mlx5_sf_dev_remove_aux(struct mlx5_core_dev *dev, + struct mlx5_sf_dev *sf_dev) { int id; @@ -138,7 +139,7 @@ static void mlx5_sf_dev_add(struct mlx5_core_dev *dev, u16 sf_index, u16 fn_id, return; xa_err: - mlx5_sf_dev_remove(dev, sf_dev); + mlx5_sf_dev_remove_aux(dev, sf_dev); add_err: mlx5_core_err(dev, "SF DEV: fail device add for index=%d sfnum=%d err=%d\n", sf_index, sfnum, err); @@ -149,7 +150,7 @@ static void mlx5_sf_dev_del(struct mlx5_core_dev *dev, struct mlx5_sf_dev *sf_de struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; xa_erase(&table->devices, sf_index); - mlx5_sf_dev_remove(dev, sf_dev); + mlx5_sf_dev_remove_aux(dev, sf_dev); } static int @@ -367,7 +368,7 @@ static void mlx5_sf_dev_destroy_all(struct mlx5_sf_dev_table *table) xa_for_each(&table->devices, index, sf_dev) { xa_erase(&table->devices, index); - mlx5_sf_dev_remove(table->dev, sf_dev); + mlx5_sf_dev_remove_aux(table->dev, sf_dev); } } From daa6a6eb8f881a846ef9d1698d1da97999e8d86b Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Thu, 25 Jan 2024 12:49:55 +0200 Subject: [PATCH 0757/2255] net/mlx5: remove fw_fatal reporter dump option for non PF In case function is not a Physical Function it is not allowed to collect crdump, so if tried it will fail the fw_fatal health reporter dump option. Instead of failing on permission, remove the option of fw_fatal health reporter dump for such function. Signed-off-by: Moshe Shemesh Reviewed-by: Aya Levin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/health.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 8ff6dc9bc803..721e343388df 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -646,12 +646,17 @@ static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work) } } -static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = { +static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_pf_ops = { .name = "fw_fatal", .recover = mlx5_fw_fatal_reporter_recover, .dump = mlx5_fw_fatal_reporter_dump, }; +static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = { + .name = "fw_fatal", + .recover = mlx5_fw_fatal_reporter_recover, +}; + #define MLX5_FW_REPORTER_ECPF_GRACEFUL_PERIOD 180000 #define MLX5_FW_REPORTER_PF_GRACEFUL_PERIOD 60000 #define MLX5_FW_REPORTER_VF_GRACEFUL_PERIOD 30000 @@ -659,10 +664,12 @@ static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = { void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) { + const struct devlink_health_reporter_ops *fw_fatal_ops; struct mlx5_core_health *health = &dev->priv.health; struct devlink *devlink = priv_to_devlink(dev); u64 grace_period; + fw_fatal_ops = &mlx5_fw_fatal_reporter_pf_ops; if (mlx5_core_is_ecpf(dev)) { grace_period = MLX5_FW_REPORTER_ECPF_GRACEFUL_PERIOD; } else if (mlx5_core_is_pf(dev)) { @@ -670,6 +677,7 @@ void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) } else { /* VF or SF */ grace_period = MLX5_FW_REPORTER_DEFAULT_GRACEFUL_PERIOD; + fw_fatal_ops = &mlx5_fw_fatal_reporter_ops; } health->fw_reporter = @@ -681,7 +689,7 @@ void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) health->fw_fatal_reporter = devl_health_reporter_create(devlink, - &mlx5_fw_fatal_reporter_ops, + fw_fatal_ops, grace_period, dev); if (IS_ERR(health->fw_fatal_reporter)) From 17aa2d79b7e550acea2eeafb079773344bada714 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Thu, 25 Jan 2024 13:18:55 +0200 Subject: [PATCH 0758/2255] net/mlx5: remove fw reporter dump option for non PF In case function is not a Physical Function it is not allowed to get FW core dump, so if tried it will fail the fw health reporter dump option. Instead of failing, remove the option of fw_fatal health reporter dump for such function. Signed-off-by: Moshe Shemesh Reviewed-by: Aya Levin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/health.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 721e343388df..5c2ac2d9dbd9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -555,12 +555,17 @@ static void mlx5_fw_reporter_err_work(struct work_struct *work) &fw_reporter_ctx); } -static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = { +static const struct devlink_health_reporter_ops mlx5_fw_reporter_pf_ops = { .name = "fw", .diagnose = mlx5_fw_reporter_diagnose, .dump = mlx5_fw_reporter_dump, }; +static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = { + .name = "fw", + .diagnose = mlx5_fw_reporter_diagnose, +}; + static int mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter, void *priv_ctx, @@ -666,10 +671,12 @@ void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) { const struct devlink_health_reporter_ops *fw_fatal_ops; struct mlx5_core_health *health = &dev->priv.health; + const struct devlink_health_reporter_ops *fw_ops; struct devlink *devlink = priv_to_devlink(dev); u64 grace_period; fw_fatal_ops = &mlx5_fw_fatal_reporter_pf_ops; + fw_ops = &mlx5_fw_reporter_pf_ops; if (mlx5_core_is_ecpf(dev)) { grace_period = MLX5_FW_REPORTER_ECPF_GRACEFUL_PERIOD; } else if (mlx5_core_is_pf(dev)) { @@ -678,11 +685,11 @@ void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) /* VF or SF */ grace_period = MLX5_FW_REPORTER_DEFAULT_GRACEFUL_PERIOD; fw_fatal_ops = &mlx5_fw_fatal_reporter_ops; + fw_ops = &mlx5_fw_reporter_ops; } health->fw_reporter = - devl_health_reporter_create(devlink, &mlx5_fw_reporter_ops, - 0, dev); + devl_health_reporter_create(devlink, fw_ops, 0, dev); if (IS_ERR(health->fw_reporter)) mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n", PTR_ERR(health->fw_reporter)); From 137cef6d55564fb687d12fbc5f85be43ff7b53a7 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Thu, 25 Jan 2024 14:24:09 +0200 Subject: [PATCH 0759/2255] net/mlx5: SF, Stop waiting for FW as teardown was called When PF/VF teardown is called the driver sets the flag MLX5_BREAK_FW_WAIT to stop waiting for FW loading and initializing. Same should be applied to SF driver teardown to cut waiting time. On mlx5_sf_dev_remove() set the flag before draining health WQ as recovery flow may also wait for FW reloading while it is not relevant anymore. Signed-off-by: Moshe Shemesh Reviewed-by: Aya Levin Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/sf/dev/driver.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c index 169c2c68ed5c..bc863e1f062e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c @@ -95,24 +95,29 @@ mdev_err: static void mlx5_sf_dev_remove(struct auxiliary_device *adev) { struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); - struct devlink *devlink = priv_to_devlink(sf_dev->mdev); + struct mlx5_core_dev *mdev = sf_dev->mdev; + struct devlink *devlink; - mlx5_drain_health_wq(sf_dev->mdev); + devlink = priv_to_devlink(mdev); + set_bit(MLX5_BREAK_FW_WAIT, &mdev->intf_state); + mlx5_drain_health_wq(mdev); devlink_unregister(devlink); - if (mlx5_dev_is_lightweight(sf_dev->mdev)) - mlx5_uninit_one_light(sf_dev->mdev); + if (mlx5_dev_is_lightweight(mdev)) + mlx5_uninit_one_light(mdev); else - mlx5_uninit_one(sf_dev->mdev); - iounmap(sf_dev->mdev->iseg); - mlx5_mdev_uninit(sf_dev->mdev); + mlx5_uninit_one(mdev); + iounmap(mdev->iseg); + mlx5_mdev_uninit(mdev); mlx5_devlink_free(devlink); } static void mlx5_sf_dev_shutdown(struct auxiliary_device *adev) { struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); + struct mlx5_core_dev *mdev = sf_dev->mdev; - mlx5_unload_one(sf_dev->mdev, false); + set_bit(MLX5_BREAK_FW_WAIT, &mdev->intf_state); + mlx5_unload_one(mdev, false); } static const struct auxiliary_device_id mlx5_sf_dev_id_table[] = { From bcad0e5312314ea6d69989c382df42f9a8348783 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Fri, 26 Jan 2024 09:26:29 +0200 Subject: [PATCH 0760/2255] net/mlx5: Return specific error code for timeout on wait_fw_init The function wait_fw_init() returns same error code either if it breaks waiting due to timeout or other reason. Thus, the function callers print error message on timeout without checking error type. Return different error code for different failure reason and print error message accordingly on wait_fw_init(). Signed-off-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/main.c | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index bccf6e53556c..c2593625c09a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -187,31 +187,36 @@ static struct mlx5_profile profile[] = { }; static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili, - u32 warn_time_mili) + u32 warn_time_mili, const char *init_state) { unsigned long warn = jiffies + msecs_to_jiffies(warn_time_mili); unsigned long end = jiffies + msecs_to_jiffies(max_wait_mili); u32 fw_initializing; - int err = 0; do { fw_initializing = ioread32be(&dev->iseg->initializing); if (!(fw_initializing >> 31)) break; - if (time_after(jiffies, end) || - test_bit(MLX5_BREAK_FW_WAIT, &dev->intf_state)) { - err = -EBUSY; - break; + if (time_after(jiffies, end)) { + mlx5_core_err(dev, "Firmware over %u MS in %s state, aborting\n", + max_wait_mili, init_state); + return -ETIMEDOUT; + } + if (test_bit(MLX5_BREAK_FW_WAIT, &dev->intf_state)) { + mlx5_core_warn(dev, "device is being removed, stop waiting for FW %s\n", + init_state); + return -ENODEV; } if (warn_time_mili && time_after(jiffies, warn)) { - mlx5_core_warn(dev, "Waiting for FW initialization, timeout abort in %ds (0x%x)\n", - jiffies_to_msecs(end - warn) / 1000, fw_initializing); + mlx5_core_warn(dev, "Waiting for FW %s, timeout abort in %ds (0x%x)\n", + init_state, jiffies_to_msecs(end - warn) / 1000, + fw_initializing); warn = jiffies + msecs_to_jiffies(warn_time_mili); } msleep(mlx5_tout_ms(dev, FW_PRE_INIT_WAIT)); } while (true); - return err; + return 0; } static void mlx5_set_driver_version(struct mlx5_core_dev *dev) @@ -1151,12 +1156,10 @@ static int mlx5_function_enable(struct mlx5_core_dev *dev, bool boot, u64 timeou /* wait for firmware to accept initialization segments configurations */ err = wait_fw_init(dev, timeout, - mlx5_tout_ms(dev, FW_PRE_INIT_WARN_MESSAGE_INTERVAL)); - if (err) { - mlx5_core_err(dev, "Firmware over %llu MS in pre-initializing state, aborting\n", - timeout); + mlx5_tout_ms(dev, FW_PRE_INIT_WARN_MESSAGE_INTERVAL), + "pre-initializing"); + if (err) return err; - } err = mlx5_cmd_enable(dev); if (err) { @@ -1166,12 +1169,9 @@ static int mlx5_function_enable(struct mlx5_core_dev *dev, bool boot, u64 timeou mlx5_tout_query_iseg(dev); - err = wait_fw_init(dev, mlx5_tout_ms(dev, FW_INIT), 0); - if (err) { - mlx5_core_err(dev, "Firmware over %llu MS in initializing state, aborting\n", - mlx5_tout_ms(dev, FW_INIT)); + err = wait_fw_init(dev, mlx5_tout_ms(dev, FW_INIT), 0, "initializing"); + if (err) goto err_cmd_cleanup; - } dev->caps.embedded_cpu = mlx5_read_embedded_cpu(dev); mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_UP); From 91a72ada66053b4dba95cf1a60a5a23fdbd6faf7 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Tue, 26 Dec 2023 10:22:08 +0200 Subject: [PATCH 0761/2255] net/mlx5: Remove initial segmentation duplicate definitions Device definitions belong in mlx5_ifc, remove the duplicates in mlx5_core.h. Signed-off-by: Gal Pressman Reviewed-by: Jianbo Liu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 6 +++--- .../net/ethernet/mellanox/mlx5/core/health.c | 20 +++++++++---------- .../ethernet/mellanox/mlx5/core/mlx5_core.h | 7 ------- include/linux/mlx5/mlx5_ifc.h | 1 + 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 58f4c0d0fafa..e7faf7e73ca4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -366,18 +366,18 @@ int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev) return -EIO; } - mlx5_set_nic_state(dev, MLX5_NIC_IFC_DISABLED); + mlx5_set_nic_state(dev, MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED); /* Loop until device state turns to disable */ end = jiffies + msecs_to_jiffies(delay_ms); do { - if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) + if (mlx5_get_nic_state(dev) == MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED) break; cond_resched(); } while (!time_after(jiffies, end)); - if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) { + if (mlx5_get_nic_state(dev) != MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED) { dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n", mlx5_get_nic_state(dev), delay_ms); return -EIO; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 5c2ac2d9dbd9..9463ede84d8d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -116,9 +116,9 @@ u32 mlx5_health_check_fatal_sensors(struct mlx5_core_dev *dev) return MLX5_SENSOR_PCI_COMM_ERR; if (pci_channel_offline(dev->pdev)) return MLX5_SENSOR_PCI_ERR; - if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) + if (mlx5_get_nic_state(dev) == MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED) return MLX5_SENSOR_NIC_DISABLED; - if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_SW_RESET) + if (mlx5_get_nic_state(dev) == MLX5_INITIAL_SEG_NIC_INTERFACE_SW_RESET) return MLX5_SENSOR_NIC_SW_RESET; if (sensor_fw_synd_rfr(dev)) return MLX5_SENSOR_FW_SYND_RFR; @@ -185,7 +185,7 @@ static bool reset_fw_if_needed(struct mlx5_core_dev *dev) /* Write the NIC interface field to initiate the reset, the command * interface address also resides here, don't overwrite it. */ - mlx5_set_nic_state(dev, MLX5_NIC_IFC_SW_RESET); + mlx5_set_nic_state(dev, MLX5_INITIAL_SEG_NIC_INTERFACE_SW_RESET); return true; } @@ -246,13 +246,13 @@ recover_from_sw_reset: /* Recover from SW reset */ end = jiffies + msecs_to_jiffies(delay_ms); do { - if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) + if (mlx5_get_nic_state(dev) == MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED) break; msleep(20); } while (!time_after(jiffies, end)); - if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) { + if (mlx5_get_nic_state(dev) != MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED) { dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n", mlx5_get_nic_state(dev), delay_ms); } @@ -272,26 +272,26 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) u8 nic_interface = mlx5_get_nic_state(dev); switch (nic_interface) { - case MLX5_NIC_IFC_FULL: + case MLX5_INITIAL_SEG_NIC_INTERFACE_FULL_DRIVER: mlx5_core_warn(dev, "Expected to see disabled NIC but it is full driver\n"); break; - case MLX5_NIC_IFC_DISABLED: + case MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED: mlx5_core_warn(dev, "starting teardown\n"); break; - case MLX5_NIC_IFC_NO_DRAM_NIC: + case MLX5_INITIAL_SEG_NIC_INTERFACE_NO_DRAM_NIC: mlx5_core_warn(dev, "Expected to see disabled NIC but it is no dram nic\n"); break; - case MLX5_NIC_IFC_SW_RESET: + case MLX5_INITIAL_SEG_NIC_INTERFACE_SW_RESET: /* The IFC mode field is 3 bits, so it will read 0x7 in 2 cases: * 1. PCI has been disabled (ie. PCI-AER, PF driver unloaded * and this is a VF), this is not recoverable by SW reset. * Logging of this is handled elsewhere. * 2. FW reset has been issued by another function, driver can * be reloaded to recover after the mode switches to - * MLX5_NIC_IFC_DISABLED. + * MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED. */ if (dev->priv.health.fatal_error != MLX5_SENSOR_PCI_COMM_ERR) mlx5_core_warn(dev, "NIC SW reset in progress\n"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index a79b7959361b..58732f44940f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -312,13 +312,6 @@ static inline int mlx5_rescan_drivers(struct mlx5_core_dev *dev) return ret; } -enum { - MLX5_NIC_IFC_FULL = 0, - MLX5_NIC_IFC_DISABLED = 1, - MLX5_NIC_IFC_NO_DRAM_NIC = 2, - MLX5_NIC_IFC_SW_RESET = 7 -}; - u8 mlx5_get_nic_state(struct mlx5_core_dev *dev); void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 6c44f107b8ba..7f5e846eb46d 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -10661,6 +10661,7 @@ enum { MLX5_INITIAL_SEG_NIC_INTERFACE_FULL_DRIVER = 0x0, MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED = 0x1, MLX5_INITIAL_SEG_NIC_INTERFACE_NO_DRAM_NIC = 0x2, + MLX5_INITIAL_SEG_NIC_INTERFACE_SW_RESET = 0x7, }; enum { From 507472ed0e37244e7703378409407b0606de6077 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Tue, 26 Dec 2023 11:12:04 +0200 Subject: [PATCH 0762/2255] net/mlx5: Change missing SyncE capability print to debug Lack of SyncE capability should not emit a warning, change the print to debug level. Signed-off-by: Gal Pressman Reviewed-by: Jianbo Liu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index cf0477f53dc4..47e7c2639774 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -210,7 +210,7 @@ static bool is_dpll_supported(struct mlx5_core_dev *dev) return false; if (!MLX5_CAP_MCAM_REG2(dev, synce_registers)) { - mlx5_core_warn(dev, "Missing SyncE capability\n"); + mlx5_core_dbg(dev, "Missing SyncE capability\n"); return false; } From 917d1e799ddf9492bd0c71a23d84af0b6bb12bae Mon Sep 17 00:00:00 2001 From: Hamdan Igbaria Date: Thu, 16 Nov 2023 13:51:01 +0200 Subject: [PATCH 0763/2255] net/mlx5: DR, Change SWS usage to debug fs seq_file interface In current SWS debug dump mechanism we implement the seq_file interface, but we only implement the 'show' callback to dump the whole steering DB with a single call to this callback. However, for large data size the seq_printf function will fail to allocate a buffer with the adequate capacity to hold such data. This patch solves this problem by utilizing the seq_file interface mechanism in the following way: - when the user triggers a dump procedure, we will allocate a list of buffers that hold the whole data dump (in the start callback) - using the start, next, show and stop callbacks of the seq_file API we iterate through the list and dump the whole data Signed-off-by: Hamdan Igbaria Reviewed-by: Yevgeny Kliteynik Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/steering/dr_dbg.c | 734 ++++++++++++++---- .../mellanox/mlx5/core/steering/dr_dbg.h | 20 + 2 files changed, 620 insertions(+), 134 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c index 7e36e1062139..64f4cc284aea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c @@ -54,6 +54,107 @@ enum dr_dump_rec_type { DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE = 3425, }; +static struct mlx5dr_dbg_dump_buff * +mlx5dr_dbg_dump_data_init_new_buff(struct mlx5dr_dbg_dump_data *dump_data) +{ + struct mlx5dr_dbg_dump_buff *new_buff; + + new_buff = kzalloc(sizeof(*new_buff), GFP_KERNEL); + if (!new_buff) + return NULL; + + new_buff->buff = kvzalloc(MLX5DR_DEBUG_DUMP_BUFF_SIZE, GFP_KERNEL); + if (!new_buff->buff) { + kfree(new_buff); + return NULL; + } + + INIT_LIST_HEAD(&new_buff->node); + list_add_tail(&new_buff->node, &dump_data->buff_list); + + return new_buff; +} + +static struct mlx5dr_dbg_dump_data * +mlx5dr_dbg_create_dump_data(void) +{ + struct mlx5dr_dbg_dump_data *dump_data; + + dump_data = kzalloc(sizeof(*dump_data), GFP_KERNEL); + if (!dump_data) + return NULL; + + INIT_LIST_HEAD(&dump_data->buff_list); + + if (!mlx5dr_dbg_dump_data_init_new_buff(dump_data)) { + kfree(dump_data); + return NULL; + } + + return dump_data; +} + +static void +mlx5dr_dbg_destroy_dump_data(struct mlx5dr_dbg_dump_data *dump_data) +{ + struct mlx5dr_dbg_dump_buff *dump_buff, *tmp_buff; + + if (!dump_data) + return; + + list_for_each_entry_safe(dump_buff, tmp_buff, &dump_data->buff_list, node) { + kvfree(dump_buff->buff); + list_del(&dump_buff->node); + kfree(dump_buff); + } + + kfree(dump_data); +} + +static int +mlx5dr_dbg_dump_data_print(struct seq_file *file, char *str, u32 size) +{ + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + struct mlx5dr_dbg_dump_buff *buff; + u32 buff_capacity, write_size; + int remain_size, ret; + + if (size >= MLX5DR_DEBUG_DUMP_BUFF_SIZE) + return -EINVAL; + + dump_data = dmn->dump_info.dump_data; + buff = list_last_entry(&dump_data->buff_list, + struct mlx5dr_dbg_dump_buff, node); + + buff_capacity = (MLX5DR_DEBUG_DUMP_BUFF_SIZE - 1) - buff->index; + remain_size = buff_capacity - size; + write_size = (remain_size > 0) ? size : buff_capacity; + + if (likely(write_size)) { + ret = snprintf(buff->buff + buff->index, write_size + 1, "%s", str); + if (ret < 0) + return ret; + + buff->index += write_size; + } + + if (remain_size < 0) { + remain_size *= -1; + buff = mlx5dr_dbg_dump_data_init_new_buff(dump_data); + if (!buff) + return -ENOMEM; + + ret = snprintf(buff->buff, remain_size + 1, "%s", str + write_size); + if (ret < 0) + return ret; + + buff->index += remain_size; + } + + return 0; +} + void mlx5dr_dbg_tbl_add(struct mlx5dr_table *tbl) { mutex_lock(&tbl->dmn->dump_info.dbg_mutex); @@ -109,36 +210,68 @@ dr_dump_rule_action_mem(struct seq_file *file, const u64 rule_id, { struct mlx5dr_action *action = action_mem->action; const u64 action_id = DR_DBG_PTR_TO_ID(action); + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; u64 hit_tbl_ptr, miss_tbl_ptr; u32 hit_tbl_id, miss_tbl_id; + int ret; switch (action->action_type) { case DR_ACTION_TYP_DROP: - seq_printf(file, "%d,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_DROP, action_id, rule_id); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_DROP, action_id, + rule_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_FT: if (action->dest_tbl->is_fw_tbl) - seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_FT, action_id, - rule_id, action->dest_tbl->fw_tbl.id, - -1); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_FT, action_id, + rule_id, action->dest_tbl->fw_tbl.id, + -1); else - seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_FT, action_id, - rule_id, action->dest_tbl->tbl->table_id, - DR_DBG_PTR_TO_ID(action->dest_tbl->tbl)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_FT, action_id, + rule_id, action->dest_tbl->tbl->table_id, + DR_DBG_PTR_TO_ID(action->dest_tbl->tbl)); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_CTR: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_CTR, action_id, rule_id, - action->ctr->ctr_id + action->ctr->offset); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_CTR, action_id, rule_id, + action->ctr->ctr_id + action->ctr->offset); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_TAG: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_TAG, action_id, rule_id, - action->flow_tag->flow_tag); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_TAG, action_id, rule_id, + action->flow_tag->flow_tag); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_MODIFY_HDR: { @@ -150,83 +283,171 @@ dr_dump_rule_action_mem(struct seq_file *file, const u64 rule_id, ptrn_arg = !action->rewrite->single_action_opt && ptrn && arg; - seq_printf(file, "%d,0x%llx,0x%llx,0x%x,%d,0x%x,0x%x,0x%x", - DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR, action_id, - rule_id, action->rewrite->index, - action->rewrite->single_action_opt, - ptrn_arg ? action->rewrite->num_of_actions : 0, - ptrn_arg ? ptrn->index : 0, - ptrn_arg ? mlx5dr_arg_get_obj_id(arg) : 0); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,%d,0x%x,0x%x,0x%x", + DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR, action_id, + rule_id, action->rewrite->index, + action->rewrite->single_action_opt, + ptrn_arg ? action->rewrite->num_of_actions : 0, + ptrn_arg ? ptrn->index : 0, + ptrn_arg ? mlx5dr_arg_get_obj_id(arg) : 0); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; if (ptrn_arg) { for (i = 0; i < action->rewrite->num_of_actions; i++) { - seq_printf(file, ",0x%016llx", - be64_to_cpu(((__be64 *)rewrite_data)[i])); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + ",0x%016llx", + be64_to_cpu(((__be64 *)rewrite_data)[i])); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; } } - seq_puts(file, "\n"); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "\n"); + if (ret < 0) + return ret; + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; } case DR_ACTION_TYP_VPORT: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_VPORT, action_id, rule_id, - action->vport->caps->num); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_VPORT, action_id, rule_id, + action->vport->caps->num); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_TNL_L2_TO_L2: - seq_printf(file, "%d,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_DECAP_L2, action_id, - rule_id); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_DECAP_L2, action_id, + rule_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_TNL_L3_TO_L2: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_DECAP_L3, action_id, - rule_id, - (action->rewrite->ptrn && action->rewrite->arg) ? - mlx5dr_arg_get_obj_id(action->rewrite->arg) : - action->rewrite->index); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_DECAP_L3, action_id, + rule_id, + (action->rewrite->ptrn && action->rewrite->arg) ? + mlx5dr_arg_get_obj_id(action->rewrite->arg) : + action->rewrite->index); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_L2_TO_TNL_L2: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_ENCAP_L2, action_id, - rule_id, action->reformat->id); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_ENCAP_L2, action_id, + rule_id, action->reformat->id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_L2_TO_TNL_L3: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_ENCAP_L3, action_id, - rule_id, action->reformat->id); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_ENCAP_L3, action_id, + rule_id, action->reformat->id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_POP_VLAN: - seq_printf(file, "%d,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_POP_VLAN, action_id, - rule_id); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_POP_VLAN, action_id, + rule_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_PUSH_VLAN: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN, action_id, - rule_id, action->push_vlan->vlan_hdr); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN, action_id, + rule_id, action->push_vlan->vlan_hdr); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_INSERT_HDR: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_INSERT_HDR, action_id, - rule_id, action->reformat->id, - action->reformat->param_0, - action->reformat->param_1); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_INSERT_HDR, action_id, + rule_id, action->reformat->id, + action->reformat->param_0, + action->reformat->param_1); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_REMOVE_HDR: - seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR, action_id, - rule_id, action->reformat->id, - action->reformat->param_0, - action->reformat->param_1); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR, action_id, + rule_id, action->reformat->id, + action->reformat->param_0, + action->reformat->param_1); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_SAMPLER: - seq_printf(file, - "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_SAMPLER, action_id, rule_id, - 0, 0, action->sampler->sampler_id, - action->sampler->rx_icm_addr, - action->sampler->tx_icm_addr); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_SAMPLER, action_id, + rule_id, 0, 0, action->sampler->sampler_id, + action->sampler->rx_icm_addr, + action->sampler->tx_icm_addr); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; case DR_ACTION_TYP_RANGE: if (action->range->hit_tbl_action->dest_tbl->is_fw_tbl) { @@ -247,10 +468,17 @@ dr_dump_rule_action_mem(struct seq_file *file, const u64 rule_id, DR_DBG_PTR_TO_ID(action->range->miss_tbl_action->dest_tbl->tbl); } - seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%llx,0x%x,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE, action_id, rule_id, - hit_tbl_id, hit_tbl_ptr, miss_tbl_id, miss_tbl_ptr, - action->range->definer_id); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%llx,0x%x,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE, action_id, + rule_id, hit_tbl_id, hit_tbl_ptr, miss_tbl_id, + miss_tbl_ptr, action->range->definer_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; break; default: return 0; @@ -263,8 +491,10 @@ static int dr_dump_rule_mem(struct seq_file *file, struct mlx5dr_ste *ste, bool is_rx, const u64 rule_id, u8 format_ver) { + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; char hw_ste_dump[DR_HEX_SIZE]; u32 mem_rec_type; + int ret; if (format_ver == MLX5_STEERING_FORMAT_CONNECTX_5) { mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 : @@ -277,9 +507,16 @@ dr_dump_rule_mem(struct seq_file *file, struct mlx5dr_ste *ste, dr_dump_hex_print(hw_ste_dump, (char *)mlx5dr_ste_get_hw_ste(ste), DR_STE_SIZE_REDUCED); - seq_printf(file, "%d,0x%llx,0x%llx,%s\n", mem_rec_type, - dr_dump_icm_to_idx(mlx5dr_ste_get_icm_addr(ste)), rule_id, - hw_ste_dump); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%s\n", mem_rec_type, + dr_dump_icm_to_idx(mlx5dr_ste_get_icm_addr(ste)), + rule_id, hw_ste_dump); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; return 0; } @@ -309,6 +546,7 @@ static int dr_dump_rule(struct seq_file *file, struct mlx5dr_rule *rule) { struct mlx5dr_rule_action_member *action_mem; const u64 rule_id = DR_DBG_PTR_TO_ID(rule); + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; struct mlx5dr_rule_rx_tx *rx = &rule->rx; struct mlx5dr_rule_rx_tx *tx = &rule->tx; u8 format_ver; @@ -316,8 +554,15 @@ static int dr_dump_rule(struct seq_file *file, struct mlx5dr_rule *rule) format_ver = rule->matcher->tbl->dmn->info.caps.sw_format_ver; - seq_printf(file, "%d,0x%llx,0x%llx\n", DR_DUMP_REC_TYPE_RULE, rule_id, - DR_DBG_PTR_TO_ID(rule->matcher)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", DR_DUMP_REC_TYPE_RULE, + rule_id, DR_DBG_PTR_TO_ID(rule->matcher)); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; if (rx->nic_matcher) { ret = dr_dump_rule_rx_tx(file, rx, true, rule_id, format_ver); @@ -344,46 +589,94 @@ static int dr_dump_matcher_mask(struct seq_file *file, struct mlx5dr_match_param *mask, u8 criteria, const u64 matcher_id) { + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; char dump[DR_HEX_SIZE]; + int ret; - seq_printf(file, "%d,0x%llx,", DR_DUMP_REC_TYPE_MATCHER_MASK, - matcher_id); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "%d,0x%llx,", + DR_DUMP_REC_TYPE_MATCHER_MASK, matcher_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; if (criteria & DR_MATCHER_CRITERIA_OUTER) { dr_dump_hex_print(dump, (char *)&mask->outer, sizeof(mask->outer)); - seq_printf(file, "%s,", dump); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); } else { - seq_puts(file, ","); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); } + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + if (criteria & DR_MATCHER_CRITERIA_INNER) { dr_dump_hex_print(dump, (char *)&mask->inner, sizeof(mask->inner)); - seq_printf(file, "%s,", dump); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); } else { - seq_puts(file, ","); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); } + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + if (criteria & DR_MATCHER_CRITERIA_MISC) { dr_dump_hex_print(dump, (char *)&mask->misc, sizeof(mask->misc)); - seq_printf(file, "%s,", dump); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); } else { - seq_puts(file, ","); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); } + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + if (criteria & DR_MATCHER_CRITERIA_MISC2) { dr_dump_hex_print(dump, (char *)&mask->misc2, sizeof(mask->misc2)); - seq_printf(file, "%s,", dump); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); } else { - seq_puts(file, ","); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); } + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + if (criteria & DR_MATCHER_CRITERIA_MISC3) { dr_dump_hex_print(dump, (char *)&mask->misc3, sizeof(mask->misc3)); - seq_printf(file, "%s\n", dump); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s\n", dump); } else { - seq_puts(file, ",\n"); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",\n"); } + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + return 0; } @@ -391,9 +684,19 @@ static int dr_dump_matcher_builder(struct seq_file *file, struct mlx5dr_ste_build *builder, u32 index, bool is_rx, const u64 matcher_id) { - seq_printf(file, "%d,0x%llx,%d,%d,0x%x\n", - DR_DUMP_REC_TYPE_MATCHER_BUILDER, matcher_id, index, is_rx, - builder->lu_type); + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%d,%d,0x%x\n", + DR_DUMP_REC_TYPE_MATCHER_BUILDER, matcher_id, index, + is_rx, builder->lu_type); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; return 0; } @@ -403,6 +706,7 @@ dr_dump_matcher_rx_tx(struct seq_file *file, bool is_rx, struct mlx5dr_matcher_rx_tx *matcher_rx_tx, const u64 matcher_id) { + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; enum dr_dump_rec_type rec_type; u64 s_icm_addr, e_icm_addr; int i, ret; @@ -412,11 +716,19 @@ dr_dump_matcher_rx_tx(struct seq_file *file, bool is_rx, s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->s_htbl->chunk); e_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->e_anchor->chunk); - seq_printf(file, "%d,0x%llx,0x%llx,%d,0x%llx,0x%llx\n", - rec_type, DR_DBG_PTR_TO_ID(matcher_rx_tx), - matcher_id, matcher_rx_tx->num_of_builders, - dr_dump_icm_to_idx(s_icm_addr), - dr_dump_icm_to_idx(e_icm_addr)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%d,0x%llx,0x%llx\n", + rec_type, DR_DBG_PTR_TO_ID(matcher_rx_tx), + matcher_id, matcher_rx_tx->num_of_builders, + dr_dump_icm_to_idx(s_icm_addr), + dr_dump_icm_to_idx(e_icm_addr)); + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; for (i = 0; i < matcher_rx_tx->num_of_builders; i++) { ret = dr_dump_matcher_builder(file, @@ -434,13 +746,22 @@ dr_dump_matcher(struct seq_file *file, struct mlx5dr_matcher *matcher) { struct mlx5dr_matcher_rx_tx *rx = &matcher->rx; struct mlx5dr_matcher_rx_tx *tx = &matcher->tx; + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; u64 matcher_id; int ret; matcher_id = DR_DBG_PTR_TO_ID(matcher); - seq_printf(file, "%d,0x%llx,0x%llx,%d\n", DR_DUMP_REC_TYPE_MATCHER, - matcher_id, DR_DBG_PTR_TO_ID(matcher->tbl), matcher->prio); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%d\n", DR_DUMP_REC_TYPE_MATCHER, + matcher_id, DR_DBG_PTR_TO_ID(matcher->tbl), + matcher->prio); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; ret = dr_dump_matcher_mask(file, &matcher->mask, matcher->match_criteria, matcher_id); @@ -486,15 +807,24 @@ dr_dump_table_rx_tx(struct seq_file *file, bool is_rx, struct mlx5dr_table_rx_tx *table_rx_tx, const u64 table_id) { + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; enum dr_dump_rec_type rec_type; u64 s_icm_addr; + int ret; rec_type = is_rx ? DR_DUMP_REC_TYPE_TABLE_RX : DR_DUMP_REC_TYPE_TABLE_TX; s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(table_rx_tx->s_anchor->chunk); - seq_printf(file, "%d,0x%llx,0x%llx\n", rec_type, table_id, - dr_dump_icm_to_idx(s_icm_addr)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", rec_type, table_id, + dr_dump_icm_to_idx(s_icm_addr)); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; return 0; } @@ -503,11 +833,19 @@ static int dr_dump_table(struct seq_file *file, struct mlx5dr_table *table) { struct mlx5dr_table_rx_tx *rx = &table->rx; struct mlx5dr_table_rx_tx *tx = &table->tx; + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; int ret; - seq_printf(file, "%d,0x%llx,0x%llx,%d,%d\n", DR_DUMP_REC_TYPE_TABLE, - DR_DBG_PTR_TO_ID(table), DR_DBG_PTR_TO_ID(table->dmn), - table->table_type, table->level); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%d,%d\n", DR_DUMP_REC_TYPE_TABLE, + DR_DBG_PTR_TO_ID(table), DR_DBG_PTR_TO_ID(table->dmn), + table->table_type, table->level); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; if (rx->nic_dmn) { ret = dr_dump_table_rx_tx(file, true, rx, @@ -546,46 +884,86 @@ static int dr_dump_send_ring(struct seq_file *file, struct mlx5dr_send_ring *ring, const u64 domain_id) { - seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_DOMAIN_SEND_RING, DR_DBG_PTR_TO_ID(ring), - domain_id, ring->cq->mcq.cqn, ring->qp->qpn); + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_DOMAIN_SEND_RING, + DR_DBG_PTR_TO_ID(ring), domain_id, + ring->cq->mcq.cqn, ring->qp->qpn); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + return 0; } -static int +static noinline_for_stack int dr_dump_domain_info_flex_parser(struct seq_file *file, const char *flex_parser_name, const u8 flex_parser_value, const u64 domain_id) { - seq_printf(file, "%d,0x%llx,%s,0x%x\n", - DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER, domain_id, - flex_parser_name, flex_parser_value); + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%s,0x%x\n", + DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER, domain_id, + flex_parser_name, flex_parser_value); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + return 0; } -static int +static noinline_for_stack int dr_dump_domain_info_caps(struct seq_file *file, struct mlx5dr_cmd_caps *caps, const u64 domain_id) { + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; struct mlx5dr_cmd_vport_cap *vport_caps; unsigned long i, vports_num; + int ret; xa_for_each(&caps->vports.vports_caps_xa, vports_num, vport_caps) ; /* count the number of vports in xarray */ - seq_printf(file, "%d,0x%llx,0x%x,0x%llx,0x%llx,0x%x,%lu,%d\n", - DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS, domain_id, caps->gvmi, - caps->nic_rx_drop_address, caps->nic_tx_drop_address, - caps->flex_protocols, vports_num, caps->eswitch_manager); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%x,0x%llx,0x%llx,0x%x,%lu,%d\n", + DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS, domain_id, caps->gvmi, + caps->nic_rx_drop_address, caps->nic_tx_drop_address, + caps->flex_protocols, vports_num, caps->eswitch_manager); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; xa_for_each(&caps->vports.vports_caps_xa, i, vport_caps) { vport_caps = xa_load(&caps->vports.vports_caps_xa, i); - seq_printf(file, "%d,0x%llx,%lu,0x%x,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT, domain_id, i, - vport_caps->vport_gvmi, vport_caps->icm_address_rx, - vport_caps->icm_address_tx); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%lu,0x%x,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT, + domain_id, i, vport_caps->vport_gvmi, + vport_caps->icm_address_rx, + vport_caps->icm_address_tx); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; } return 0; } @@ -627,24 +1005,32 @@ dr_dump_domain_info(struct seq_file *file, struct mlx5dr_domain_info *info, return 0; } -static int +static noinline_for_stack int dr_dump_domain(struct seq_file *file, struct mlx5dr_domain *dmn) { + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; u64 domain_id = DR_DBG_PTR_TO_ID(dmn); int ret; - seq_printf(file, "%d,0x%llx,%d,0%x,%d,%u.%u.%u,%s,%d,%u,%u,%u\n", - DR_DUMP_REC_TYPE_DOMAIN, - domain_id, dmn->type, dmn->info.caps.gvmi, - dmn->info.supp_sw_steering, - /* package version */ - LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL, - LINUX_VERSION_SUBLEVEL, - pci_name(dmn->mdev->pdev), - 0, /* domain flags */ - dmn->num_buddies[DR_ICM_TYPE_STE], - dmn->num_buddies[DR_ICM_TYPE_MODIFY_ACTION], - dmn->num_buddies[DR_ICM_TYPE_MODIFY_HDR_PTRN]); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%d,0%x,%d,%u.%u.%u,%s,%d,%u,%u,%u\n", + DR_DUMP_REC_TYPE_DOMAIN, + domain_id, dmn->type, dmn->info.caps.gvmi, + dmn->info.supp_sw_steering, + /* package version */ + LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL, + LINUX_VERSION_SUBLEVEL, + pci_name(dmn->mdev->pdev), + 0, /* domain flags */ + dmn->num_buddies[DR_ICM_TYPE_STE], + dmn->num_buddies[DR_ICM_TYPE_MODIFY_ACTION], + dmn->num_buddies[DR_ICM_TYPE_MODIFY_HDR_PTRN]); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; ret = dr_dump_domain_info(file, &dmn->info, domain_id); if (ret < 0) @@ -683,11 +1069,91 @@ unlock_mutex: return ret; } -static int dr_dump_show(struct seq_file *file, void *priv) +static void * +dr_dump_start(struct seq_file *file, loff_t *pos) { - return dr_dump_domain_all(file, file->private); + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + + if (atomic_read(&dmn->dump_info.state) != MLX5DR_DEBUG_DUMP_STATE_FREE) { + mlx5_core_warn(dmn->mdev, "Dump already in progress\n"); + return ERR_PTR(-EBUSY); + } + + atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_IN_PROGRESS); + dump_data = dmn->dump_info.dump_data; + + if (dump_data) { + return seq_list_start(&dump_data->buff_list, *pos); + } else if (*pos == 0) { + dump_data = mlx5dr_dbg_create_dump_data(); + if (!dump_data) + goto exit; + + dmn->dump_info.dump_data = dump_data; + if (dr_dump_domain_all(file, dmn)) { + mlx5dr_dbg_destroy_dump_data(dump_data); + dmn->dump_info.dump_data = NULL; + goto exit; + } + + return seq_list_start(&dump_data->buff_list, *pos); + } + +exit: + atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE); + return NULL; } -DEFINE_SHOW_ATTRIBUTE(dr_dump); + +static void * +dr_dump_next(struct seq_file *file, void *v, loff_t *pos) +{ + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + + dump_data = dmn->dump_info.dump_data; + + return seq_list_next(v, &dump_data->buff_list, pos); +} + +static void +dr_dump_stop(struct seq_file *file, void *v) +{ + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + + if (v && IS_ERR(v)) + return; + + if (!v) { + dump_data = dmn->dump_info.dump_data; + if (dump_data) { + mlx5dr_dbg_destroy_dump_data(dump_data); + dmn->dump_info.dump_data = NULL; + } + } + + atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE); +} + +static int +dr_dump_show(struct seq_file *file, void *v) +{ + struct mlx5dr_dbg_dump_buff *entry; + + entry = list_entry(v, struct mlx5dr_dbg_dump_buff, node); + seq_printf(file, "%s", entry->buff); + + return 0; +} + +static const struct seq_operations dr_dump_sops = { + .start = dr_dump_start, + .next = dr_dump_next, + .stop = dr_dump_stop, + .show = dr_dump_show, +}; +DEFINE_SEQ_ATTRIBUTE(dr_dump); void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h index def6cf853eea..57c6b363b870 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h @@ -1,10 +1,30 @@ /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ /* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ +#define MLX5DR_DEBUG_DUMP_BUFF_SIZE (64 * 1024 * 1024) +#define MLX5DR_DEBUG_DUMP_BUFF_LENGTH 512 + +enum { + MLX5DR_DEBUG_DUMP_STATE_FREE, + MLX5DR_DEBUG_DUMP_STATE_IN_PROGRESS, +}; + +struct mlx5dr_dbg_dump_buff { + char *buff; + u32 index; + struct list_head node; +}; + +struct mlx5dr_dbg_dump_data { + struct list_head buff_list; +}; + struct mlx5dr_dbg_dump_info { struct mutex dbg_mutex; /* protect dbg lists */ struct dentry *steering_debugfs; struct dentry *fdb_debugfs; + struct mlx5dr_dbg_dump_data *dump_data; + atomic_t state; }; void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn); From fb3bfdfcd10609c90911307a545864d2996d951f Mon Sep 17 00:00:00 2001 From: Carolina Jubran Date: Mon, 18 Dec 2023 13:58:27 +0200 Subject: [PATCH 0764/2255] net/mlx5e: XSK, Exclude tailroom from non-linear SKBs memory calculations Packet data buffers lack reserved headroom or tailroom, and SKBs are allocated on a side memory when needed. Exclude the tailroom from the SKB size calculations. Signed-off-by: Carolina Jubran Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en/params.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c index 5d213a9886f1..b9d39ef8053c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c @@ -240,11 +240,14 @@ static u32 mlx5e_rx_get_linear_sz_xsk(struct mlx5e_params *params, return xsk->headroom + hw_mtu; } -static u32 mlx5e_rx_get_linear_sz_skb(struct mlx5e_params *params, bool xsk) +static u32 mlx5e_rx_get_linear_sz_skb(struct mlx5e_params *params, bool no_head_tail_room) { - /* SKBs built on XDP_PASS on XSK RQs don't have headroom. */ - u16 headroom = xsk ? 0 : mlx5e_get_linear_rq_headroom(params, NULL); u32 hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu); + u16 headroom; + + if (no_head_tail_room) + return SKB_DATA_ALIGN(hw_mtu); + headroom = mlx5e_get_linear_rq_headroom(params, NULL); return MLX5_SKB_FRAG_SZ(headroom + hw_mtu); } @@ -289,7 +292,11 @@ bool mlx5e_rx_is_linear_skb(struct mlx5_core_dev *mdev, if (params->packet_merge.type != MLX5E_PACKET_MERGE_NONE) return false; - /* Both XSK and non-XSK cases allocate an SKB on XDP_PASS. Packet data + /* Call mlx5e_rx_get_linear_sz_skb with the no_head_tail_room parameter set + * to exclude headroom and tailroom from calculations. + * no_head_tail_room is true when SKB is built on XDP_PASS on XSK RQs + * since packet data buffers don't have headroom and tailroom resreved for the SKB. + * Both XSK and non-XSK cases allocate an SKB on XDP_PASS. Packet data * must fit into a CPU page. */ if (mlx5e_rx_get_linear_sz_skb(params, xsk) > PAGE_SIZE) From a90f55916f150ced7b2635bedd43676f922ee075 Mon Sep 17 00:00:00 2001 From: Carolina Jubran Date: Tue, 19 Dec 2023 16:23:07 +0200 Subject: [PATCH 0765/2255] net/mlx5e: XDP, Exclude headroom and tailroom from memory calculations In the case of XDP Multi-Buffer with Striding RQ, an extra page is allocated for the linear part of non-linear SKBs. Including headroom and tailroom in the calculation may result in an unnecessary increase in the amount of memory allocated. This could be critical, particularly for large MTUs (e.g. 7975B) and large RQ sizes (e.g. 8192). In this case, the requested page pool size is 64K, but 32K would be sufficient. This causes a failure due to exceeding the page pool size limit of 32K. Exclude headroom and tailroom from SKB size calculations to reduce page pool size. Signed-off-by: Carolina Jubran Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/params.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c index b9d39ef8053c..5757f4f10c12 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c @@ -257,6 +257,7 @@ static u32 mlx5e_rx_get_linear_stride_sz(struct mlx5_core_dev *mdev, struct mlx5e_xsk_param *xsk, bool mpwqe) { + bool no_head_tail_room; u32 sz; /* XSK frames are mapped as individual pages, because frames may come in @@ -265,7 +266,13 @@ static u32 mlx5e_rx_get_linear_stride_sz(struct mlx5_core_dev *mdev, if (xsk) return mpwqe ? 1 << mlx5e_mpwrq_page_shift(mdev, xsk) : PAGE_SIZE; - sz = roundup_pow_of_two(mlx5e_rx_get_linear_sz_skb(params, false)); + no_head_tail_room = params->xdp_prog && mpwqe && !mlx5e_rx_is_linear_skb(mdev, params, xsk); + + /* When no_head_tail_room is set, headroom and tailroom are excluded from skb calculations. + * no_head_tail_room should be set in the case of XDP with Striding RQ + * when SKB is not linear. This is because another page is allocated for the linear part. + */ + sz = roundup_pow_of_two(mlx5e_rx_get_linear_sz_skb(params, no_head_tail_room)); /* XDP in mlx5e doesn't support multiple packets per page. * Do not assume sz <= PAGE_SIZE if params->xdp_prog is set. From a44b1334aadd82203f661adb9adb41e53ad0e8d1 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Sun, 4 Feb 2024 22:23:48 +0000 Subject: [PATCH 0766/2255] bpf: Allow calling static subprogs while holding a bpf_spin_lock Currently, calling any helpers, kfuncs, or subprogs except the graph data structure (lists, rbtrees) API kfuncs while holding a bpf_spin_lock is not allowed. One of the original motivations of this decision was to force the BPF programmer's hand into keeping the bpf_spin_lock critical section small, and to ensure the execution time of the program does not increase due to lock waiting times. In addition to this, some of the helpers and kfuncs may be unsafe to call while holding a bpf_spin_lock. However, when it comes to subprog calls, atleast for static subprogs, the verifier is able to explore their instructions during verification. Therefore, it is similar in effect to having the same code inlined into the critical section. Hence, not allowing static subprog calls in the bpf_spin_lock critical section is mostly an annoyance that needs to be worked around, without providing any tangible benefit. Unlike static subprog calls, global subprog calls are not safe to permit within the critical section, as the verifier does not explore them during verification, therefore whether the same lock will be taken again, or unlocked, cannot be ascertained. Therefore, allow calling static subprogs within a bpf_spin_lock critical section, and only reject it in case the subprog linkage is global. Acked-by: Yonghong Song Acked-by: David Vernet Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20240204222349.938118-2-memxor@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 11 ++++++++--- .../testing/selftests/bpf/progs/verifier_spin_lock.c | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 64fa188d00ad..7d38b2343ad4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9493,6 +9493,13 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, if (subprog_is_global(env, subprog)) { const char *sub_name = subprog_name(env, subprog); + /* Only global subprogs cannot be called with a lock held. */ + if (env->cur_state->active_lock.ptr) { + verbose(env, "global function calls are not allowed while holding a lock,\n" + "use static function instead\n"); + return -EINVAL; + } + if (err) { verbose(env, "Caller passes invalid args into func#%d ('%s')\n", subprog, sub_name); @@ -17644,7 +17651,6 @@ static int do_check(struct bpf_verifier_env *env) if (env->cur_state->active_lock.ptr) { if ((insn->src_reg == BPF_REG_0 && insn->imm != BPF_FUNC_spin_unlock) || - (insn->src_reg == BPF_PSEUDO_CALL) || (insn->src_reg == BPF_PSEUDO_KFUNC_CALL && (insn->off != 0 || !is_bpf_graph_api_kfunc(insn->imm)))) { verbose(env, "function calls are not allowed while holding a lock\n"); @@ -17692,8 +17698,7 @@ static int do_check(struct bpf_verifier_env *env) return -EINVAL; } process_bpf_exit_full: - if (env->cur_state->active_lock.ptr && - !in_rbtree_lock_required_cb(env)) { + if (env->cur_state->active_lock.ptr && !env->cur_state->curframe) { verbose(env, "bpf_spin_unlock is missing\n"); return -EINVAL; } diff --git a/tools/testing/selftests/bpf/progs/verifier_spin_lock.c b/tools/testing/selftests/bpf/progs/verifier_spin_lock.c index 9c1aa69650f8..fb316c080c84 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spin_lock.c +++ b/tools/testing/selftests/bpf/progs/verifier_spin_lock.c @@ -330,7 +330,7 @@ l1_%=: r7 = r0; \ SEC("cgroup/skb") __description("spin_lock: test10 lock in subprog without unlock") -__failure __msg("unlock is missing") +__success __failure_unpriv __msg_unpriv("") __naked void lock_in_subprog_without_unlock(void) { From e8699c4ff85baedcf40f33db816cc487cee39397 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Sun, 4 Feb 2024 22:23:49 +0000 Subject: [PATCH 0767/2255] selftests/bpf: Add test for static subprog call in lock cs Add selftests for static subprog calls within bpf_spin_lock critical section, and ensure we still reject global subprog calls. Also test the case where a subprog call will unlock the caller's held lock, or the caller will unlock a lock taken by a subprog call, ensuring correct transfer of lock state across frames on exit. Acked-by: Yonghong Song Acked-by: David Vernet Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20240204222349.938118-3-memxor@gmail.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/spin_lock.c | 2 + .../selftests/bpf/progs/test_spin_lock.c | 65 +++++++++++++++++++ .../selftests/bpf/progs/test_spin_lock_fail.c | 44 +++++++++++++ 3 files changed, 111 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/spin_lock.c b/tools/testing/selftests/bpf/prog_tests/spin_lock.c index 18d451be57c8..2b0068742ef9 100644 --- a/tools/testing/selftests/bpf/prog_tests/spin_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/spin_lock.c @@ -48,6 +48,8 @@ static struct { { "lock_id_mismatch_innermapval_kptr", "bpf_spin_unlock of different lock" }, { "lock_id_mismatch_innermapval_global", "bpf_spin_unlock of different lock" }, { "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" }, + { "lock_global_subprog_call1", "global function calls are not allowed while holding a lock" }, + { "lock_global_subprog_call2", "global function calls are not allowed while holding a lock" }, }; static int match_regex(const char *pattern, const char *string) diff --git a/tools/testing/selftests/bpf/progs/test_spin_lock.c b/tools/testing/selftests/bpf/progs/test_spin_lock.c index b2440a0ff422..d8d77bdffd3d 100644 --- a/tools/testing/selftests/bpf/progs/test_spin_lock.c +++ b/tools/testing/selftests/bpf/progs/test_spin_lock.c @@ -101,4 +101,69 @@ int bpf_spin_lock_test(struct __sk_buff *skb) err: return err; } + +struct bpf_spin_lock lockA __hidden SEC(".data.A"); + +__noinline +static int static_subprog(struct __sk_buff *ctx) +{ + volatile int ret = 0; + + if (ctx->protocol) + return ret; + return ret + ctx->len; +} + +__noinline +static int static_subprog_lock(struct __sk_buff *ctx) +{ + volatile int ret = 0; + + ret = static_subprog(ctx); + bpf_spin_lock(&lockA); + return ret + ctx->len; +} + +__noinline +static int static_subprog_unlock(struct __sk_buff *ctx) +{ + volatile int ret = 0; + + ret = static_subprog(ctx); + bpf_spin_unlock(&lockA); + return ret + ctx->len; +} + +SEC("tc") +int lock_static_subprog_call(struct __sk_buff *ctx) +{ + int ret = 0; + + bpf_spin_lock(&lockA); + if (ctx->mark == 42) + ret = static_subprog(ctx); + bpf_spin_unlock(&lockA); + return ret; +} + +SEC("tc") +int lock_static_subprog_lock(struct __sk_buff *ctx) +{ + int ret = 0; + + ret = static_subprog_lock(ctx); + bpf_spin_unlock(&lockA); + return ret; +} + +SEC("tc") +int lock_static_subprog_unlock(struct __sk_buff *ctx) +{ + int ret = 0; + + bpf_spin_lock(&lockA); + ret = static_subprog_unlock(ctx); + return ret; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c b/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c index 86cd183ef6dc..43f40c4fe241 100644 --- a/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c +++ b/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c @@ -201,4 +201,48 @@ CHECK(innermapval_mapval, &iv->lock, &v->lock); #undef CHECK +__noinline +int global_subprog(struct __sk_buff *ctx) +{ + volatile int ret = 0; + + if (ctx->protocol) + ret += ctx->protocol; + return ret + ctx->mark; +} + +__noinline +static int static_subprog_call_global(struct __sk_buff *ctx) +{ + volatile int ret = 0; + + if (ctx->protocol) + return ret; + return ret + ctx->len + global_subprog(ctx); +} + +SEC("?tc") +int lock_global_subprog_call1(struct __sk_buff *ctx) +{ + int ret = 0; + + bpf_spin_lock(&lockA); + if (ctx->mark == 42) + ret = global_subprog(ctx); + bpf_spin_unlock(&lockA); + return ret; +} + +SEC("?tc") +int lock_global_subprog_call2(struct __sk_buff *ctx) +{ + int ret = 0; + + bpf_spin_lock(&lockA); + if (ctx->mark == 42) + ret = static_subprog_call_global(ctx); + bpf_spin_unlock(&lockA); + return ret; +} + char _license[] SEC("license") = "GPL"; From 6fceea0fa59f6786a2847a4cae409117624e8b58 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Mon, 5 Feb 2024 05:56:45 +0000 Subject: [PATCH 0768/2255] bpf: Transfer RCU lock state between subprog calls Allow transferring an imbalanced RCU lock state between subprog calls during verification. This allows patterns where a subprog call returns with an RCU lock held, or a subprog call releases an RCU lock held by the caller. Currently, the verifier would end up complaining if the RCU lock is not released when processing an exit from a subprog, which is non-ideal if its execution is supposed to be enclosed in an RCU read section of the caller. Instead, simply only check whether we are processing exit for frame#0 and do not complain on an active RCU lock otherwise. We only need to update the check when processing BPF_EXIT insn, as copy_verifier_state is already set up to do the right thing. Suggested-by: David Vernet Tested-by: Yafang Shao Acked-by: Yonghong Song Signed-off-by: Kumar Kartikeya Dwivedi Acked-by: David Vernet Link: https://lore.kernel.org/r/20240205055646.1112186-2-memxor@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7d38b2343ad4..ddaf09db1175 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17703,8 +17703,7 @@ process_bpf_exit_full: return -EINVAL; } - if (env->cur_state->active_rcu_lock && - !in_rbtree_lock_required_cb(env)) { + if (env->cur_state->active_rcu_lock && !env->cur_state->curframe) { verbose(env, "bpf_rcu_read_unlock is missing\n"); return -EINVAL; } From 8be6a0147af314fd60db9da2158cd737dc6394a7 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Mon, 5 Feb 2024 05:56:46 +0000 Subject: [PATCH 0769/2255] selftests/bpf: Add tests for RCU lock transfer between subprogs Add selftests covering the following cases: - A static or global subprog called from within a RCU read section works - A static subprog taking an RCU read lock which is released in caller works - A static subprog releasing the caller's RCU read lock works Global subprogs that leave the lock in an imbalanced state will not work, as they are verified separately, so ensure those cases fail as well. Acked-by: Yonghong Song Signed-off-by: Kumar Kartikeya Dwivedi Acked-by: David Vernet Link: https://lore.kernel.org/r/20240205055646.1112186-3-memxor@gmail.com Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/rcu_read_lock.c | 6 + .../selftests/bpf/progs/rcu_read_lock.c | 120 ++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c index 3f1f58d3a729..a1f7e7378a64 100644 --- a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c @@ -29,6 +29,10 @@ static void test_success(void) bpf_program__set_autoload(skel->progs.non_sleepable_1, true); bpf_program__set_autoload(skel->progs.non_sleepable_2, true); bpf_program__set_autoload(skel->progs.task_trusted_non_rcuptr, true); + bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog, true); + bpf_program__set_autoload(skel->progs.rcu_read_lock_global_subprog, true); + bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog_lock, true); + bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog_unlock, true); err = rcu_read_lock__load(skel); if (!ASSERT_OK(err, "skel_load")) goto out; @@ -75,6 +79,8 @@ static const char * const inproper_region_tests[] = { "inproper_sleepable_helper", "inproper_sleepable_kfunc", "nested_rcu_region", + "rcu_read_lock_global_subprog_lock", + "rcu_read_lock_global_subprog_unlock", }; static void test_inproper_region(void) diff --git a/tools/testing/selftests/bpf/progs/rcu_read_lock.c b/tools/testing/selftests/bpf/progs/rcu_read_lock.c index 14fb01437fb8..ab3a532b7dd6 100644 --- a/tools/testing/selftests/bpf/progs/rcu_read_lock.c +++ b/tools/testing/selftests/bpf/progs/rcu_read_lock.c @@ -319,3 +319,123 @@ int cross_rcu_region(void *ctx) bpf_rcu_read_unlock(); return 0; } + +__noinline +static int static_subprog(void *ctx) +{ + volatile int ret = 0; + + if (bpf_get_prandom_u32()) + return ret + 42; + return ret + bpf_get_prandom_u32(); +} + +__noinline +int global_subprog(u64 a) +{ + volatile int ret = a; + + return ret + static_subprog(NULL); +} + +__noinline +static int static_subprog_lock(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + if (bpf_get_prandom_u32()) + return ret + 42; + return ret + bpf_get_prandom_u32(); +} + +__noinline +int global_subprog_lock(u64 a) +{ + volatile int ret = a; + + return ret + static_subprog_lock(NULL); +} + +__noinline +static int static_subprog_unlock(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_unlock(); + if (bpf_get_prandom_u32()) + return ret + 42; + return ret + bpf_get_prandom_u32(); +} + +__noinline +int global_subprog_unlock(u64 a) +{ + volatile int ret = a; + + return ret + static_subprog_unlock(NULL); +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_subprog(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + if (bpf_get_prandom_u32()) + ret += static_subprog(ctx); + bpf_rcu_read_unlock(); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_global_subprog(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + if (bpf_get_prandom_u32()) + ret += global_subprog(ret); + bpf_rcu_read_unlock(); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_subprog_lock(void *ctx) +{ + volatile int ret = 0; + + ret += static_subprog_lock(ctx); + bpf_rcu_read_unlock(); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_global_subprog_lock(void *ctx) +{ + volatile int ret = 0; + + ret += global_subprog_lock(ret); + bpf_rcu_read_unlock(); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_subprog_unlock(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + ret += static_subprog_unlock(ctx); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_global_subprog_unlock(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + ret += global_subprog_unlock(ret); + return 0; +} From 2863d665ea41282379f108e4da6c8a2366ba66db Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Mon, 5 Feb 2024 13:35:50 +0100 Subject: [PATCH 0770/2255] xsk: support redirect to any socket bound to the same umem Add support for directing a packet to any socket bound to the same umem. This makes it possible to use the XDP program to select what socket the packet should be received on. The user can populate the XSKMAP with various sockets and as long as they share the same umem, the XDP program can pick any one of them. Suggested-by: Yuval El-Hanany Signed-off-by: Magnus Karlsson Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20240205123553.22180-2-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- net/xdp/xsk.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 1eadfac03cc4..a339e9a1b557 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -313,10 +313,13 @@ static bool xsk_is_bound(struct xdp_sock *xs) static int xsk_rcv_check(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len) { + struct net_device *dev = xdp->rxq->dev; + u32 qid = xdp->rxq->queue_index; + if (!xsk_is_bound(xs)) return -ENXIO; - if (xs->dev != xdp->rxq->dev || xs->queue_id != xdp->rxq->queue_index) + if (!dev->_rx[qid].pool || xs->umem != dev->_rx[qid].pool->umem) return -EINVAL; if (len > xsk_pool_get_rx_frame_size(xs->pool) && !xs->sg) { From 968595a93669b6b4f6d1fcf80cf2d97956b6868f Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Mon, 5 Feb 2024 13:35:51 +0100 Subject: [PATCH 0771/2255] xsk: document ability to redirect to any socket bound to the same umem Document the ability to redirect to any socket bound to the same umem. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20240205123553.22180-3-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- Documentation/networking/af_xdp.rst | 31 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst index dceeb0d763aa..72da7057e4cf 100644 --- a/Documentation/networking/af_xdp.rst +++ b/Documentation/networking/af_xdp.rst @@ -329,23 +329,24 @@ XDP_SHARED_UMEM option and provide the initial socket's fd in the sxdp_shared_umem_fd field as you registered the UMEM on that socket. These two sockets will now share one and the same UMEM. -There is no need to supply an XDP program like the one in the previous -case where sockets were bound to the same queue id and -device. Instead, use the NIC's packet steering capabilities to steer -the packets to the right queue. In the previous example, there is only -one queue shared among sockets, so the NIC cannot do this steering. It -can only steer between queues. +In this case, it is possible to use the NIC's packet steering +capabilities to steer the packets to the right queue. This is not +possible in the previous example as there is only one queue shared +among sockets, so the NIC cannot do this steering as it can only steer +between queues. -In libbpf, you need to use the xsk_socket__create_shared() API as it -takes a reference to a FILL ring and a COMPLETION ring that will be -created for you and bound to the shared UMEM. You can use this -function for all the sockets you create, or you can use it for the -second and following ones and use xsk_socket__create() for the first -one. Both methods yield the same result. +In libxdp (or libbpf prior to version 1.0), you need to use the +xsk_socket__create_shared() API as it takes a reference to a FILL ring +and a COMPLETION ring that will be created for you and bound to the +shared UMEM. You can use this function for all the sockets you create, +or you can use it for the second and following ones and use +xsk_socket__create() for the first one. Both methods yield the same +result. Note that a UMEM can be shared between sockets on the same queue id and device, as well as between queues on the same device and between -devices at the same time. +devices at the same time. It is also possible to redirect to any +socket as long as it is bound to the same umem with XDP_SHARED_UMEM. XDP_USE_NEED_WAKEUP bind flag ----------------------------- @@ -822,6 +823,10 @@ A: The short answer is no, that is not supported at the moment. The switch, or other distribution mechanism, in your NIC to direct traffic to the correct queue id and socket. + Note that if you are using the XDP_SHARED_UMEM option, it is + possible to switch traffic between any socket bound to the same + umem. + Q: My packets are sometimes corrupted. What is wrong? A: Care has to be taken not to feed the same buffer in the UMEM into From d7bc416aa5cc183691287e8f0b1d5b182a7ce9c3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 5 Feb 2024 16:22:43 -0800 Subject: [PATCH 0772/2255] libbpf: fix return value for PERF_EVENT __arg_ctx type fix up check If PERF_EVENT program has __arg_ctx argument with matching architecture-specific pt_regs/user_pt_regs/user_regs_struct pointer type, libbpf should still perform type rewrite for old kernels, but not emit the warning. Fix copy/paste from kernel code where 0 is meant to signify "no error" condition. For libbpf we need to return "true" to proceed with type rewrite (which for PERF_EVENT program will be a canonical `struct bpf_perf_event_data *` type). Fixes: 9eea8fafe33e ("libbpf: fix __arg_ctx type enforcement for perf_event programs") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240206002243.1439450-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 6932f2c4ddfd..01f407591a92 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -6404,13 +6404,13 @@ static bool need_func_arg_type_fixup(const struct btf *btf, const struct bpf_pro case BPF_PROG_TYPE_PERF_EVENT: if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct pt_regs) && btf_is_struct(t) && strcmp(tname, "pt_regs") == 0) - return 0; + return true; if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_pt_regs) && btf_is_struct(t) && strcmp(tname, "user_pt_regs") == 0) - return 0; + return true; if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_regs_struct) && btf_is_struct(t) && strcmp(tname, "user_regs_struct") == 0) - return 0; + return true; break; case BPF_PROG_TYPE_RAW_TRACEPOINT: case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: From c7dcb6c9aa85fa310251dad7e233eb955a5235ed Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 5 Feb 2024 16:40:08 -0800 Subject: [PATCH 0773/2255] selftests/bpf: mark dynptr kfuncs __weak to make them optional on old kernels Mark dynptr kfuncs as __weak to allow verifier_global_subprogs/arg_ctx_{perf,kprobe,raw_tp} subtests to be loadable on old kernels. Because bpf_dynptr_from_xdp() kfunc is used from arg_tag_dynptr BPF program in progs/verifier_global_subprogs.c *and* is not marked as __weak, loading any subtest from verifier_global_subprogs fails on old kernels that don't have bpf_dynptr_from_xdp() kfunc defined. Even if arg_tag_dynptr program itself is not loaded, libbpf bails out on non-weak reference to bpf_dynptr_from_xdp (that can't be resolved), which shared across all programs in progs/verifier_global_subprogs.c. So mark all dynptr-related kfuncs as __weak to unblock libbpf CI ([0]). In the upcoming "kfunc in vmlinux.h" work we should make sure that kfuncs are always declared __weak as well. [0] https://github.com/libbpf/libbpf/actions/runs/7792673215/job/21251250831?pr=776#step:4:7961 Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240206004008.1541513-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_kfuncs.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 0cd4111f954c..14ebe7d9e1a3 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -9,7 +9,7 @@ struct bpf_sock_addr_kern; * Error code */ extern int bpf_dynptr_from_skb(struct __sk_buff *skb, __u64 flags, - struct bpf_dynptr *ptr__uninit) __ksym; + struct bpf_dynptr *ptr__uninit) __ksym __weak; /* Description * Initializes an xdp-type dynptr @@ -17,7 +17,7 @@ extern int bpf_dynptr_from_skb(struct __sk_buff *skb, __u64 flags, * Error code */ extern int bpf_dynptr_from_xdp(struct xdp_md *xdp, __u64 flags, - struct bpf_dynptr *ptr__uninit) __ksym; + struct bpf_dynptr *ptr__uninit) __ksym __weak; /* Description * Obtain a read-only pointer to the dynptr's data @@ -26,7 +26,7 @@ extern int bpf_dynptr_from_xdp(struct xdp_md *xdp, __u64 flags, * buffer if unable to obtain a direct pointer */ extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, __u32 offset, - void *buffer, __u32 buffer__szk) __ksym; + void *buffer, __u32 buffer__szk) __ksym __weak; /* Description * Obtain a read-write pointer to the dynptr's data @@ -35,13 +35,13 @@ extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, __u32 offset, * buffer if unable to obtain a direct pointer */ extern void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *ptr, __u32 offset, - void *buffer, __u32 buffer__szk) __ksym; + void *buffer, __u32 buffer__szk) __ksym __weak; -extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym; -extern bool bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; -extern bool bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; -extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym; -extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym; +extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym __weak; +extern bool bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym __weak; +extern bool bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym __weak; +extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym __weak; +extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym __weak; /* Description * Modify the address of a AF_UNIX sockaddr. From c41dfb0dfbece824143ff51829d42cba4cb3c277 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 1 Feb 2024 11:21:19 -0500 Subject: [PATCH 0774/2255] selftests/net: ignore timing errors in so_txtime if KSFT_MACHINE_SLOW This test is time sensitive. It may fail on virtual machines and for debug builds. Continue to run in these environments to get code coverage. But optionally suppress failure for timing errors (only). This is controlled with environment variable KSFT_MACHINE_SLOW. The test continues to return 0 (KSFT_PASS), rather than KSFT_XFAIL as previously discussed. Because making so_txtime.c return that and then making so_txtime.sh capture runs that pass that vs KSFT_FAIL and pass it on added a bunch of (fragile bash) boilerplate, while the result is interpreted the same as KSFT_PASS anyway. Signed-off-by: Willem de Bruijn Link: https://lore.kernel.org/r/20240201162130.2278240-1-willemdebruijn.kernel@gmail.com Signed-off-by: Paolo Abeni --- tools/testing/selftests/net/so_txtime.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/so_txtime.c b/tools/testing/selftests/net/so_txtime.c index 2672ac0b6d1f..8457b7ccbc09 100644 --- a/tools/testing/selftests/net/so_txtime.c +++ b/tools/testing/selftests/net/so_txtime.c @@ -134,8 +134,11 @@ static void do_recv_one(int fdr, struct timed_send *ts) if (rbuf[0] != ts->data) error(1, 0, "payload mismatch. expected %c", ts->data); - if (llabs(tstop - texpect) > cfg_variance_us) - error(1, 0, "exceeds variance (%d us)", cfg_variance_us); + if (llabs(tstop - texpect) > cfg_variance_us) { + fprintf(stderr, "exceeds variance (%d us)\n", cfg_variance_us); + if (!getenv("KSFT_MACHINE_SLOW")) + exit(1); + } } static void do_recv_verify_empty(int fdr) From 3c974cdce8ddb192e19044f6cf6ddb54543fbc9b Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Fri, 2 Feb 2024 01:43:36 -0500 Subject: [PATCH 0775/2255] net: encx24j600: convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Bo Liu Link: https://lore.kernel.org/r/20240202064336.39138-1-liubo03@inspur.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/microchip/encx24j600-regmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c index 2e0fe16a4082..443128adbcb6 100644 --- a/drivers/net/ethernet/microchip/encx24j600-regmap.c +++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c @@ -464,7 +464,7 @@ static struct regmap_config regcfg = { .val_bits = 16, .max_register = 0xee, .reg_stride = 2, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .val_format_endian = REGMAP_ENDIAN_LITTLE, .readable_reg = encx24j600_regmap_readable, .writeable_reg = encx24j600_regmap_writeable, @@ -485,7 +485,7 @@ static struct regmap_config phycfg = { .reg_bits = 8, .val_bits = 16, .max_register = 0x1f, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .val_format_endian = REGMAP_ENDIAN_LITTLE, .readable_reg = encx24j600_phymap_readable, .writeable_reg = encx24j600_phymap_writeable, From 2b993bfdb47b3aaafd8fe9cd5038b5e297b18ee1 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:22 +0200 Subject: [PATCH 0776/2255] net: ravb: Let IP-specific receive function to interrogate descriptors ravb_poll() initial code used to interrogate the first descriptor of the RX queue in case gPTP is false to determine if ravb_rx() should be called. This is done for non-gPTP IPs. For gPTP IPs the driver PTP-specific information was used to determine if receive function should be called. As every IP has its own receive function that interrogates the RX descriptors list in the same way the ravb_poll() was doing there is no need to double check this in ravb_poll(). Removing the code from ravb_poll() leads to a cleaner code. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 0e3731f50fc2..d371c4bed634 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1288,25 +1288,16 @@ static int ravb_poll(struct napi_struct *napi, int budget) struct net_device *ndev = napi->dev; struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; - bool gptp = info->gptp || info->ccc_gac; - struct ravb_rx_desc *desc; unsigned long flags; int q = napi - priv->napi; int mask = BIT(q); int quota = budget; - unsigned int entry; - if (!gptp) { - entry = priv->cur_rx[q] % priv->num_rx_ring[q]; - desc = &priv->gbeth_rx_ring[entry]; - } /* Processing RX Descriptor Ring */ /* Clear RX interrupt */ ravb_write(ndev, ~(mask | RIS0_RESERVED), RIS0); - if (gptp || desc->die_dt != DT_FEMPTY) { - if (ravb_rx(ndev, "a, q)) - goto out; - } + if (ravb_rx(ndev, "a, q)) + goto out; /* Processing TX Descriptor Ring */ spin_lock_irqsave(&priv->lock, flags); From e1da043f2b2d956818728ca74c8eacd17feccf5c Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:23 +0200 Subject: [PATCH 0777/2255] net: ravb: Rely on PM domain to enable gptp_clk ravb_rzv2m_hw_info::gptp_ref_clk is enabled only for RZ/V2M. RZ/V2M is an ARM64-based device which selects power domains by default and CONFIG_PM. The RZ/V2M Ethernet DT node has proper power-domain binding available in device tree from the commit that added the Ethernet node. (4872ca1f92b0 ("arm64: dts: renesas: r9a09g011: Add ethernet nodes")). Power domain support was available in the rzg2l-cpg.c driver when the Ethernet DT node has been enabled in RZ/V2M device tree. (ef3c613ccd68 ("clk: renesas: Add CPG core wrapper for RZ/G2L SoC")). Thus, remove the explicit clock enable for gptp_clk (and treat it as the other clocks are treated) as it is not needed and removing it doesn't break the ABI according to the above explanations. By removing the enable/disable operation from the driver we can add runtime PM support (which operates on clocks) w/o the need to handle the gptp_clk in the Ethernet driver functions like ravb_runtime_nop(). PM domain does all that is needed. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index d371c4bed634..3181fa73aa32 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2780,7 +2780,6 @@ static int ravb_probe(struct platform_device *pdev) error = PTR_ERR(priv->gptp_clk); goto out_disable_refclk; } - clk_prepare_enable(priv->gptp_clk); } ndev->max_mtu = info->rx_max_buf_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); @@ -2800,13 +2799,13 @@ static int ravb_probe(struct platform_device *pdev) /* Set AVB config mode */ error = ravb_set_config_mode(ndev); if (error) - goto out_disable_gptp_clk; + goto out_disable_refclk; if (info->gptp || info->ccc_gac) { /* Set GTI value */ error = ravb_set_gti(ndev); if (error) - goto out_disable_gptp_clk; + goto out_disable_refclk; /* Request GTI loading */ ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI); @@ -2826,7 +2825,7 @@ static int ravb_probe(struct platform_device *pdev) "Cannot allocate desc base address table (size %d bytes)\n", priv->desc_bat_size); error = -ENOMEM; - goto out_disable_gptp_clk; + goto out_disable_refclk; } for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++) priv->desc_bat[q].die_dt = DT_EOS; @@ -2889,8 +2888,6 @@ out_dma_free: /* Stop PTP Clock driver */ if (info->ccc_gac) ravb_ptp_stop(ndev); -out_disable_gptp_clk: - clk_disable_unprepare(priv->gptp_clk); out_disable_refclk: clk_disable_unprepare(priv->refclk); out_release: @@ -2925,7 +2922,6 @@ static void ravb_remove(struct platform_device *pdev) ravb_set_opmode(ndev, CCC_OPC_RESET); - clk_disable_unprepare(priv->gptp_clk); clk_disable_unprepare(priv->refclk); pm_runtime_put_sync(&pdev->dev); From b1768e3dc47792ac5876643604be25bc8ed17cd4 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:24 +0200 Subject: [PATCH 0778/2255] net: ravb: Make reset controller support mandatory On the RZ/G3S SoC the reset controller is mandatory for the IP to work. The device tree binding documentation for the ravb driver specifies that the resets are mandatory. Based on this, make the resets mandatory also in driver for all ravb devices. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/Kconfig | 1 + drivers/net/ethernet/renesas/ravb_main.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig index d6136fe5c206..b03fae7a0f72 100644 --- a/drivers/net/ethernet/renesas/Kconfig +++ b/drivers/net/ethernet/renesas/Kconfig @@ -34,6 +34,7 @@ config RAVB select MII select MDIO_BITBANG select PHYLIB + select RESET_CONTROLLER help Renesas Ethernet AVB device driver. diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 3181fa73aa32..fd431f1a0b98 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2645,7 +2645,7 @@ static int ravb_probe(struct platform_device *pdev) return -EINVAL; } - rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(rstc)) return dev_err_probe(&pdev->dev, PTR_ERR(rstc), "failed to get cpg reset\n"); From 6ccc22a5afcbac46d55866d72eaba22f43491c00 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:25 +0200 Subject: [PATCH 0779/2255] net: ravb: Switch to SYSTEM_SLEEP_PM_OPS()/RUNTIME_PM_OPS() and pm_ptr() SET_SYSTEM_SLEEP_PM_OPS() and SET_RUNTIME_PM_OPS() are deprecated now and require __maybe_unused protection against unused function warnings. The usage of pm_ptr() and SYSTEM_SLEEP_PM_OPS()/RUNTIME_PM_OPS() allows the compiler to see the functions, thus suppressing the warning. Thus drop the __maybe_unused markings. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index fd431f1a0b98..7ced5db04f75 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2971,7 +2971,7 @@ static int ravb_wol_restore(struct net_device *ndev) return disable_irq_wake(priv->emac_irq); } -static int __maybe_unused ravb_suspend(struct device *dev) +static int ravb_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct ravb_private *priv = netdev_priv(ndev); @@ -2993,7 +2993,7 @@ static int __maybe_unused ravb_suspend(struct device *dev) return ret; } -static int __maybe_unused ravb_resume(struct device *dev) +static int ravb_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct ravb_private *priv = netdev_priv(ndev); @@ -3052,7 +3052,7 @@ static int __maybe_unused ravb_resume(struct device *dev) return ret; } -static int __maybe_unused ravb_runtime_nop(struct device *dev) +static int ravb_runtime_nop(struct device *dev) { /* Runtime PM callback shared between ->runtime_suspend() * and ->runtime_resume(). Simply returns success. @@ -3065,8 +3065,8 @@ static int __maybe_unused ravb_runtime_nop(struct device *dev) } static const struct dev_pm_ops ravb_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ravb_suspend, ravb_resume) - SET_RUNTIME_PM_OPS(ravb_runtime_nop, ravb_runtime_nop, NULL) + SYSTEM_SLEEP_PM_OPS(ravb_suspend, ravb_resume) + RUNTIME_PM_OPS(ravb_runtime_nop, ravb_runtime_nop, NULL) }; static struct platform_driver ravb_driver = { @@ -3074,7 +3074,7 @@ static struct platform_driver ravb_driver = { .remove_new = ravb_remove, .driver = { .name = "ravb", - .pm = &ravb_dev_pm_ops, + .pm = pm_ptr(&ravb_dev_pm_ops), .of_match_table = ravb_match_table, }, }; From 7493bb4c400ce5e36cdc962349d7987d0bc1ccd2 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:26 +0200 Subject: [PATCH 0780/2255] net: ravb: Use tabs instead of spaces Use tabs instead of spaces in the ravb_set_rate_gbeth() function. This aligns with the coding style requirements. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 7ced5db04f75..c05d4a2664eb 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -96,13 +96,13 @@ static void ravb_set_rate_gbeth(struct net_device *ndev) struct ravb_private *priv = netdev_priv(ndev); switch (priv->speed) { - case 10: /* 10BASE */ + case 10: /* 10BASE */ ravb_write(ndev, GBETH_GECMR_SPEED_10, GECMR); break; - case 100: /* 100BASE */ + case 100: /* 100BASE */ ravb_write(ndev, GBETH_GECMR_SPEED_100, GECMR); break; - case 1000: /* 1000BASE */ + case 1000: /* 1000BASE */ ravb_write(ndev, GBETH_GECMR_SPEED_1000, GECMR); break; } From c5c0714e29508fd748ee5df09ae242476bf2e451 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:27 +0200 Subject: [PATCH 0781/2255] net: ravb: Assert/de-assert reset on suspend/resume RZ/G3S can go to deep sleep states where power to most of the SoC parts is off. When resuming from such a state, the Ethernet controller needs to be reinitialized. De-asserting the reset signal for it should also be done. Thus, add reset assert/de-assert on suspend/resume functions. On the resume function, the de-assert was not reverted in case of failures to give the user a chance to restore the interface (e.g., bringing down/up the interface) in case suspend/resume failed. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index c05d4a2664eb..c2b65bdad13c 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2978,7 +2978,7 @@ static int ravb_suspend(struct device *dev) int ret; if (!netif_running(ndev)) - return 0; + goto reset_assert; netif_device_detach(ndev); @@ -2990,7 +2990,11 @@ static int ravb_suspend(struct device *dev) if (priv->info->ccc_gac) ravb_ptp_stop(ndev); - return ret; + if (priv->wol_enabled) + return ret; + +reset_assert: + return reset_control_assert(priv->rstc); } static int ravb_resume(struct device *dev) @@ -2998,7 +3002,11 @@ static int ravb_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; - int ret = 0; + int ret; + + ret = reset_control_deassert(priv->rstc); + if (ret) + return ret; /* If WoL is enabled set reset mode to rearm the WoL logic */ if (priv->wol_enabled) { From a654f6e875b753d11643840e266f7fd75e5ee1fa Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:28 +0200 Subject: [PATCH 0782/2255] net: ravb: Move reference clock enable/disable on runtime PM APIs Reference clock could be or not be part of the power domain. If it is part of the power domain, the power domain takes care of properly setting it. In case it is not part of the power domain and full runtime PM support is available in driver the clock will not be propertly disabled/enabled at runtime. For this, keep the prepare/unprepare operations in the driver's probe()/remove() functions and move the enable/disable in runtime PM functions. By doing this, the previous ravb_runtime_nop() function was renamed ravb_runtime_suspend() and the comment was removed. A proper runtime PM resume function was added (ravb_runtime_resume()). The current driver still don't need to make any register settings on runtime suspend/resume (as expressed in the removed comment) because, currently, pm_runtime_put_sync() is called on the driver remove function. This will be changed in the next commits (that extends the runtime PM support) such that proper register settings (along with runtime resume/suspend) will be done on ravb_open()/ravb_close(). Along with it, the other clock request operations were moved close to reference clock request and prepare to have all the clock requests specific code grouped together. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 110 ++++++++++++----------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index c2b65bdad13c..e70c930840ce 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2664,11 +2664,6 @@ static int ravb_probe(struct platform_device *pdev) if (error) goto out_free_netdev; - pm_runtime_enable(&pdev->dev); - error = pm_runtime_resume_and_get(&pdev->dev); - if (error < 0) - goto out_rpm_disable; - if (info->multi_irqs) { if (info->err_mgmt_irqs) irq = platform_get_irq_byname(pdev, "dia"); @@ -2679,7 +2674,7 @@ static int ravb_probe(struct platform_device *pdev) } if (irq < 0) { error = irq; - goto out_release; + goto out_reset_assert; } ndev->irq = irq; @@ -2697,10 +2692,37 @@ static int ravb_probe(struct platform_device *pdev) priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE; } + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + error = PTR_ERR(priv->clk); + goto out_reset_assert; + } + + if (info->gptp_ref_clk) { + priv->gptp_clk = devm_clk_get(&pdev->dev, "gptp"); + if (IS_ERR(priv->gptp_clk)) { + error = PTR_ERR(priv->gptp_clk); + goto out_reset_assert; + } + } + + priv->refclk = devm_clk_get_optional(&pdev->dev, "refclk"); + if (IS_ERR(priv->refclk)) { + error = PTR_ERR(priv->refclk); + goto out_reset_assert; + } + clk_prepare(priv->refclk); + + platform_set_drvdata(pdev, ndev); + pm_runtime_enable(&pdev->dev); + error = pm_runtime_resume_and_get(&pdev->dev); + if (error < 0) + goto out_rpm_disable; + priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(priv->addr)) { error = PTR_ERR(priv->addr); - goto out_release; + goto out_rpm_put; } /* The Ether-specific entries in the device structure. */ @@ -2711,7 +2733,7 @@ static int ravb_probe(struct platform_device *pdev) error = of_get_phy_mode(np, &priv->phy_interface); if (error && error != -ENODEV) - goto out_release; + goto out_rpm_put; priv->no_avb_link = of_property_read_bool(np, "renesas,no-ether-link"); priv->avb_link_active_low = @@ -2724,14 +2746,14 @@ static int ravb_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, "ch24"); if (irq < 0) { error = irq; - goto out_release; + goto out_rpm_put; } priv->emac_irq = irq; for (i = 0; i < NUM_RX_QUEUE; i++) { irq = platform_get_irq_byname(pdev, ravb_rx_irqs[i]); if (irq < 0) { error = irq; - goto out_release; + goto out_rpm_put; } priv->rx_irqs[i] = irq; } @@ -2739,7 +2761,7 @@ static int ravb_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, ravb_tx_irqs[i]); if (irq < 0) { error = irq; - goto out_release; + goto out_rpm_put; } priv->tx_irqs[i] = irq; } @@ -2748,40 +2770,19 @@ static int ravb_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, "err_a"); if (irq < 0) { error = irq; - goto out_release; + goto out_rpm_put; } priv->erra_irq = irq; irq = platform_get_irq_byname(pdev, "mgmt_a"); if (irq < 0) { error = irq; - goto out_release; + goto out_rpm_put; } priv->mgmta_irq = irq; } } - priv->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) { - error = PTR_ERR(priv->clk); - goto out_release; - } - - priv->refclk = devm_clk_get_optional(&pdev->dev, "refclk"); - if (IS_ERR(priv->refclk)) { - error = PTR_ERR(priv->refclk); - goto out_release; - } - clk_prepare_enable(priv->refclk); - - if (info->gptp_ref_clk) { - priv->gptp_clk = devm_clk_get(&pdev->dev, "gptp"); - if (IS_ERR(priv->gptp_clk)) { - error = PTR_ERR(priv->gptp_clk); - goto out_disable_refclk; - } - } - ndev->max_mtu = info->rx_max_buf_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); ndev->min_mtu = ETH_MIN_MTU; @@ -2799,13 +2800,13 @@ static int ravb_probe(struct platform_device *pdev) /* Set AVB config mode */ error = ravb_set_config_mode(ndev); if (error) - goto out_disable_refclk; + goto out_rpm_put; if (info->gptp || info->ccc_gac) { /* Set GTI value */ error = ravb_set_gti(ndev); if (error) - goto out_disable_refclk; + goto out_rpm_put; /* Request GTI loading */ ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI); @@ -2825,7 +2826,7 @@ static int ravb_probe(struct platform_device *pdev) "Cannot allocate desc base address table (size %d bytes)\n", priv->desc_bat_size); error = -ENOMEM; - goto out_disable_refclk; + goto out_rpm_put; } for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++) priv->desc_bat[q].die_dt = DT_EOS; @@ -2871,8 +2872,6 @@ static int ravb_probe(struct platform_device *pdev) netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n", (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); - platform_set_drvdata(pdev, ndev); - return 0; out_napi_del: @@ -2888,12 +2887,12 @@ out_dma_free: /* Stop PTP Clock driver */ if (info->ccc_gac) ravb_ptp_stop(ndev); -out_disable_refclk: - clk_disable_unprepare(priv->refclk); -out_release: +out_rpm_put: pm_runtime_put(&pdev->dev); out_rpm_disable: pm_runtime_disable(&pdev->dev); + clk_unprepare(priv->refclk); +out_reset_assert: reset_control_assert(rstc); out_free_netdev: free_netdev(ndev); @@ -2922,10 +2921,9 @@ static void ravb_remove(struct platform_device *pdev) ravb_set_opmode(ndev, CCC_OPC_RESET); - clk_disable_unprepare(priv->refclk); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + clk_unprepare(priv->refclk); reset_control_assert(priv->rstc); free_netdev(ndev); platform_set_drvdata(pdev, NULL); @@ -3060,21 +3058,27 @@ static int ravb_resume(struct device *dev) return ret; } -static int ravb_runtime_nop(struct device *dev) +static int ravb_runtime_suspend(struct device *dev) { - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * This driver re-initializes all registers after - * pm_runtime_get_sync() anyway so there is no need - * to save and restore registers here. - */ + struct net_device *ndev = dev_get_drvdata(dev); + struct ravb_private *priv = netdev_priv(ndev); + + clk_disable(priv->refclk); + return 0; } +static int ravb_runtime_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct ravb_private *priv = netdev_priv(ndev); + + return clk_enable(priv->refclk); +} + static const struct dev_pm_ops ravb_dev_pm_ops = { SYSTEM_SLEEP_PM_OPS(ravb_suspend, ravb_resume) - RUNTIME_PM_OPS(ravb_runtime_nop, ravb_runtime_nop, NULL) + RUNTIME_PM_OPS(ravb_runtime_suspend, ravb_runtime_resume, NULL) }; static struct platform_driver ravb_driver = { From 32f012b8c01ca9fd26a28134cc2165ead93c22d0 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:29 +0200 Subject: [PATCH 0783/2255] net: ravb: Move getting/requesting IRQs in the probe() method The runtime PM implementation will disable clocks at the end of ravb_probe(). As some IP variants switch to reset mode as a result of setting module standby through clock disable APIs, to implement runtime PM the resource parsing and requesting are moved in the probe function and IP settings are moved in the open function. This is done because at the end of the probe some IP variants will switch anyway to reset mode and the registers content is lost. Also keeping only register settings operations in the ravb_open()/ravb_close() functions will make them faster. Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when the interface is open. As now getting/requesting IRQs is done in a single place there is no need to keep intermediary data (like ravb_rx_irqs[] and ravb_tx_irqs[] arrays or IRQs in struct ravb_private). In order to avoid accessing the IP registers while the IP is runtime suspended (e.g. in the timeframe b/w the probe requests shared IRQs and IP clocks are enabled) in the interrupt handlers were introduced pm_runtime_active() checks. The device runtime PM usage counter has been incremented to avoid disabling the device's clocks while the check is in progress (if any). This is a preparatory change to add runtime PM support for all IP variants. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb.h | 4 - drivers/net/ethernet/renesas/ravb_main.c | 299 ++++++++++------------- 2 files changed, 130 insertions(+), 173 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index e0f8276cffed..e3506888cca6 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1089,10 +1089,6 @@ struct ravb_private { int msg_enable; int speed; int emac_irq; - int erra_irq; - int mgmta_irq; - int rx_irqs[NUM_RX_QUEUE]; - int tx_irqs[NUM_TX_QUEUE]; unsigned no_avb_link:1; unsigned avb_link_active_low:1; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index e70c930840ce..f9297224e527 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -38,16 +38,6 @@ NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) -static const char *ravb_rx_irqs[NUM_RX_QUEUE] = { - "ch0", /* RAVB_BE */ - "ch1", /* RAVB_NC */ -}; - -static const char *ravb_tx_irqs[NUM_TX_QUEUE] = { - "ch18", /* RAVB_BE */ - "ch19", /* RAVB_NC */ -}; - void ravb_modify(struct net_device *ndev, enum ravb_reg reg, u32 clear, u32 set) { @@ -1092,11 +1082,23 @@ static irqreturn_t ravb_emac_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct ravb_private *priv = netdev_priv(ndev); + struct device *dev = &priv->pdev->dev; + irqreturn_t result = IRQ_HANDLED; + + pm_runtime_get_noresume(dev); + + if (unlikely(!pm_runtime_active(dev))) { + result = IRQ_NONE; + goto out_rpm_put; + } spin_lock(&priv->lock); ravb_emac_interrupt_unlocked(ndev); spin_unlock(&priv->lock); - return IRQ_HANDLED; + +out_rpm_put: + pm_runtime_put_noidle(dev); + return result; } /* Error interrupt handler */ @@ -1176,9 +1178,15 @@ static irqreturn_t ravb_interrupt(int irq, void *dev_id) struct net_device *ndev = dev_id; struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; + struct device *dev = &priv->pdev->dev; irqreturn_t result = IRQ_NONE; u32 iss; + pm_runtime_get_noresume(dev); + + if (unlikely(!pm_runtime_active(dev))) + goto out_rpm_put; + spin_lock(&priv->lock); /* Get interrupt status */ iss = ravb_read(ndev, ISS); @@ -1222,6 +1230,9 @@ static irqreturn_t ravb_interrupt(int irq, void *dev_id) } spin_unlock(&priv->lock); + +out_rpm_put: + pm_runtime_put_noidle(dev); return result; } @@ -1230,9 +1241,15 @@ static irqreturn_t ravb_multi_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct ravb_private *priv = netdev_priv(ndev); + struct device *dev = &priv->pdev->dev; irqreturn_t result = IRQ_NONE; u32 iss; + pm_runtime_get_noresume(dev); + + if (unlikely(!pm_runtime_active(dev))) + goto out_rpm_put; + spin_lock(&priv->lock); /* Get interrupt status */ iss = ravb_read(ndev, ISS); @@ -1254,6 +1271,9 @@ static irqreturn_t ravb_multi_interrupt(int irq, void *dev_id) } spin_unlock(&priv->lock); + +out_rpm_put: + pm_runtime_put_noidle(dev); return result; } @@ -1261,8 +1281,14 @@ static irqreturn_t ravb_dma_interrupt(int irq, void *dev_id, int q) { struct net_device *ndev = dev_id; struct ravb_private *priv = netdev_priv(ndev); + struct device *dev = &priv->pdev->dev; irqreturn_t result = IRQ_NONE; + pm_runtime_get_noresume(dev); + + if (unlikely(!pm_runtime_active(dev))) + goto out_rpm_put; + spin_lock(&priv->lock); /* Network control/Best effort queue RX/TX */ @@ -1270,6 +1296,9 @@ static irqreturn_t ravb_dma_interrupt(int irq, void *dev_id, int q) result = IRQ_HANDLED; spin_unlock(&priv->lock); + +out_rpm_put: + pm_runtime_put_noidle(dev); return result; } @@ -1727,85 +1756,21 @@ static const struct ethtool_ops ravb_ethtool_ops = { .set_wol = ravb_set_wol, }; -static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler, - struct net_device *ndev, struct device *dev, - const char *ch) -{ - char *name; - int error; - - name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch); - if (!name) - return -ENOMEM; - error = request_irq(irq, handler, 0, name, ndev); - if (error) - netdev_err(ndev, "cannot request IRQ %s\n", name); - - return error; -} - /* Network device open function for Ethernet AVB */ static int ravb_open(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; - struct platform_device *pdev = priv->pdev; - struct device *dev = &pdev->dev; int error; napi_enable(&priv->napi[RAVB_BE]); if (info->nc_queues) napi_enable(&priv->napi[RAVB_NC]); - if (!info->multi_irqs) { - error = request_irq(ndev->irq, ravb_interrupt, IRQF_SHARED, - ndev->name, ndev); - if (error) { - netdev_err(ndev, "cannot request IRQ\n"); - goto out_napi_off; - } - } else { - error = ravb_hook_irq(ndev->irq, ravb_multi_interrupt, ndev, - dev, "ch22:multi"); - if (error) - goto out_napi_off; - error = ravb_hook_irq(priv->emac_irq, ravb_emac_interrupt, ndev, - dev, "ch24:emac"); - if (error) - goto out_free_irq; - error = ravb_hook_irq(priv->rx_irqs[RAVB_BE], ravb_be_interrupt, - ndev, dev, "ch0:rx_be"); - if (error) - goto out_free_irq_emac; - error = ravb_hook_irq(priv->tx_irqs[RAVB_BE], ravb_be_interrupt, - ndev, dev, "ch18:tx_be"); - if (error) - goto out_free_irq_be_rx; - error = ravb_hook_irq(priv->rx_irqs[RAVB_NC], ravb_nc_interrupt, - ndev, dev, "ch1:rx_nc"); - if (error) - goto out_free_irq_be_tx; - error = ravb_hook_irq(priv->tx_irqs[RAVB_NC], ravb_nc_interrupt, - ndev, dev, "ch19:tx_nc"); - if (error) - goto out_free_irq_nc_rx; - - if (info->err_mgmt_irqs) { - error = ravb_hook_irq(priv->erra_irq, ravb_multi_interrupt, - ndev, dev, "err_a"); - if (error) - goto out_free_irq_nc_tx; - error = ravb_hook_irq(priv->mgmta_irq, ravb_multi_interrupt, - ndev, dev, "mgmt_a"); - if (error) - goto out_free_irq_erra; - } - } - /* Device init */ error = ravb_dmac_init(ndev); if (error) - goto out_free_irq_mgmta; + goto out_napi_off; ravb_emac_init(ndev); /* Initialise PTP Clock driver */ @@ -1826,26 +1791,6 @@ out_ptp_stop: if (info->gptp) ravb_ptp_stop(ndev); ravb_stop_dma(ndev); -out_free_irq_mgmta: - if (!info->multi_irqs) - goto out_free_irq; - if (info->err_mgmt_irqs) - free_irq(priv->mgmta_irq, ndev); -out_free_irq_erra: - if (info->err_mgmt_irqs) - free_irq(priv->erra_irq, ndev); -out_free_irq_nc_tx: - free_irq(priv->tx_irqs[RAVB_NC], ndev); -out_free_irq_nc_rx: - free_irq(priv->rx_irqs[RAVB_NC], ndev); -out_free_irq_be_tx: - free_irq(priv->tx_irqs[RAVB_BE], ndev); -out_free_irq_be_rx: - free_irq(priv->rx_irqs[RAVB_BE], ndev); -out_free_irq_emac: - free_irq(priv->emac_irq, ndev); -out_free_irq: - free_irq(ndev->irq, ndev); out_napi_off: if (info->nc_queues) napi_disable(&priv->napi[RAVB_NC]); @@ -2180,19 +2125,6 @@ static int ravb_close(struct net_device *ndev) cancel_work_sync(&priv->work); - if (info->multi_irqs) { - free_irq(priv->tx_irqs[RAVB_NC], ndev); - free_irq(priv->rx_irqs[RAVB_NC], ndev); - free_irq(priv->tx_irqs[RAVB_BE], ndev); - free_irq(priv->rx_irqs[RAVB_BE], ndev); - free_irq(priv->emac_irq, ndev); - if (info->err_mgmt_irqs) { - free_irq(priv->erra_irq, ndev); - free_irq(priv->mgmta_irq, ndev); - } - } - free_irq(ndev->irq, ndev); - if (info->nc_queues) napi_disable(&priv->napi[RAVB_NC]); napi_disable(&priv->napi[RAVB_BE]); @@ -2616,6 +2548,90 @@ static void ravb_parse_delay_mode(struct device_node *np, struct net_device *nde } } +static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name, + const char *ch, int *irq, irq_handler_t handler) +{ + struct platform_device *pdev = priv->pdev; + struct net_device *ndev = priv->ndev; + struct device *dev = &pdev->dev; + const char *dev_name; + unsigned long flags; + int error; + + if (irq_name) { + dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch); + if (!dev_name) + return -ENOMEM; + + *irq = platform_get_irq_byname(pdev, irq_name); + flags = 0; + } else { + dev_name = ndev->name; + *irq = platform_get_irq(pdev, 0); + flags = IRQF_SHARED; + } + if (*irq < 0) + return *irq; + + error = devm_request_irq(dev, *irq, handler, flags, dev_name, ndev); + if (error) + netdev_err(ndev, "cannot request IRQ %s\n", dev_name); + + return error; +} + +static int ravb_setup_irqs(struct ravb_private *priv) +{ + const struct ravb_hw_info *info = priv->info; + struct net_device *ndev = priv->ndev; + const char *irq_name, *emac_irq_name; + int error, irq; + + if (!info->multi_irqs) + return ravb_setup_irq(priv, NULL, NULL, &ndev->irq, ravb_interrupt); + + if (info->err_mgmt_irqs) { + irq_name = "dia"; + emac_irq_name = "line3"; + } else { + irq_name = "ch22"; + emac_irq_name = "ch24"; + } + + error = ravb_setup_irq(priv, irq_name, "ch22:multi", &ndev->irq, ravb_multi_interrupt); + if (error) + return error; + + error = ravb_setup_irq(priv, emac_irq_name, "ch24:emac", &priv->emac_irq, + ravb_emac_interrupt); + if (error) + return error; + + if (info->err_mgmt_irqs) { + error = ravb_setup_irq(priv, "err_a", "err_a", &irq, ravb_multi_interrupt); + if (error) + return error; + + error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", &irq, ravb_multi_interrupt); + if (error) + return error; + } + + error = ravb_setup_irq(priv, "ch0", "ch0:rx_be", &irq, ravb_be_interrupt); + if (error) + return error; + + error = ravb_setup_irq(priv, "ch1", "ch1:rx_nc", &irq, ravb_nc_interrupt); + if (error) + return error; + + error = ravb_setup_irq(priv, "ch18", "ch18:tx_be", &irq, ravb_be_interrupt); + if (error) + return error; + + return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", &irq, ravb_nc_interrupt); +} + static void ravb_set_delay_mode(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); @@ -2635,9 +2651,8 @@ static int ravb_probe(struct platform_device *pdev) struct reset_control *rstc; struct ravb_private *priv; struct net_device *ndev; - int error, irq, q; struct resource *res; - int i; + int error, q; if (!np) { dev_err(&pdev->dev, @@ -2664,20 +2679,6 @@ static int ravb_probe(struct platform_device *pdev) if (error) goto out_free_netdev; - if (info->multi_irqs) { - if (info->err_mgmt_irqs) - irq = platform_get_irq_byname(pdev, "dia"); - else - irq = platform_get_irq_byname(pdev, "ch22"); - } else { - irq = platform_get_irq(pdev, 0); - } - if (irq < 0) { - error = irq; - goto out_reset_assert; - } - ndev->irq = irq; - SET_NETDEV_DEV(ndev, &pdev->dev); priv = netdev_priv(ndev); @@ -2692,6 +2693,10 @@ static int ravb_probe(struct platform_device *pdev) priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE; } + error = ravb_setup_irqs(priv); + if (error) + goto out_reset_assert; + priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { error = PTR_ERR(priv->clk); @@ -2739,50 +2744,6 @@ static int ravb_probe(struct platform_device *pdev) priv->avb_link_active_low = of_property_read_bool(np, "renesas,ether-link-active-low"); - if (info->multi_irqs) { - if (info->err_mgmt_irqs) - irq = platform_get_irq_byname(pdev, "line3"); - else - irq = platform_get_irq_byname(pdev, "ch24"); - if (irq < 0) { - error = irq; - goto out_rpm_put; - } - priv->emac_irq = irq; - for (i = 0; i < NUM_RX_QUEUE; i++) { - irq = platform_get_irq_byname(pdev, ravb_rx_irqs[i]); - if (irq < 0) { - error = irq; - goto out_rpm_put; - } - priv->rx_irqs[i] = irq; - } - for (i = 0; i < NUM_TX_QUEUE; i++) { - irq = platform_get_irq_byname(pdev, ravb_tx_irqs[i]); - if (irq < 0) { - error = irq; - goto out_rpm_put; - } - priv->tx_irqs[i] = irq; - } - - if (info->err_mgmt_irqs) { - irq = platform_get_irq_byname(pdev, "err_a"); - if (irq < 0) { - error = irq; - goto out_rpm_put; - } - priv->erra_irq = irq; - - irq = platform_get_irq_byname(pdev, "mgmt_a"); - if (irq < 0) { - error = irq; - goto out_rpm_put; - } - priv->mgmta_irq = irq; - } - } - ndev->max_mtu = info->rx_max_buf_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); ndev->min_mtu = ETH_MIN_MTU; From f384ab481cab6ad71afdf9c80a8b407a70a8624c Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:30 +0200 Subject: [PATCH 0784/2255] net: ravb: Split GTI computation and set operations ravb_set_gti() was computing the value of GTI based on the reference clock rate and then applied it to register. This was done on the driver's probe function. In order to implement runtime PM for all IP variants (as some IP variants switches to reset mode (and thus the registers content is lost) when module standby is configured through clock APIs) the GTI setup was split in 2 parts: one computing the value of the GTI register (done in the driver's probe function) and one applying the computed value to register (done in the driver's ndo_open API). Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb.h | 2 + drivers/net/ethernet/renesas/ravb_main.c | 96 ++++++++++++------------ 2 files changed, 52 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index e3506888cca6..268ccfafe7aa 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1102,6 +1102,8 @@ struct ravb_private { const struct ravb_hw_info *info; struct reset_control *rstc; + + u32 gti_tiv; }; static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index f9297224e527..0f7b1d503618 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1756,6 +1756,50 @@ static const struct ethtool_ops ravb_ethtool_ops = { .set_wol = ravb_set_wol, }; +static void ravb_set_gti(struct net_device *ndev) +{ + struct ravb_private *priv = netdev_priv(ndev); + const struct ravb_hw_info *info = priv->info; + + if (!(info->gptp || info->ccc_gac)) + return; + + ravb_write(ndev, priv->gti_tiv, GTI); + + /* Request GTI loading */ + ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI); +} + +static int ravb_compute_gti(struct net_device *ndev) +{ + struct ravb_private *priv = netdev_priv(ndev); + const struct ravb_hw_info *info = priv->info; + struct device *dev = ndev->dev.parent; + unsigned long rate; + u64 inc; + + if (!(info->gptp || info->ccc_gac)) + return 0; + + if (info->gptp_ref_clk) + rate = clk_get_rate(priv->gptp_clk); + else + rate = clk_get_rate(priv->clk); + if (!rate) + return -EINVAL; + + inc = div64_ul(1000000000ULL << 20, rate); + + if (inc < GTI_TIV_MIN || inc > GTI_TIV_MAX) { + dev_err(dev, "gti.tiv increment 0x%llx is outside the range 0x%x - 0x%x\n", + inc, GTI_TIV_MIN, GTI_TIV_MAX); + return -EINVAL; + } + priv->gti_tiv = inc; + + return 0; +} + /* Network device open function for Ethernet AVB */ static int ravb_open(struct net_device *ndev) { @@ -1773,6 +1817,8 @@ static int ravb_open(struct net_device *ndev) goto out_napi_off; ravb_emac_init(ndev); + ravb_set_gti(ndev); + /* Initialise PTP Clock driver */ if (info->gptp) ravb_ptp_init(ndev, priv->pdev); @@ -2464,34 +2510,6 @@ static const struct of_device_id ravb_match_table[] = { }; MODULE_DEVICE_TABLE(of, ravb_match_table); -static int ravb_set_gti(struct net_device *ndev) -{ - struct ravb_private *priv = netdev_priv(ndev); - const struct ravb_hw_info *info = priv->info; - struct device *dev = ndev->dev.parent; - unsigned long rate; - uint64_t inc; - - if (info->gptp_ref_clk) - rate = clk_get_rate(priv->gptp_clk); - else - rate = clk_get_rate(priv->clk); - if (!rate) - return -EINVAL; - - inc = div64_ul(1000000000ULL << 20, rate); - - if (inc < GTI_TIV_MIN || inc > GTI_TIV_MAX) { - dev_err(dev, "gti.tiv increment 0x%llx is outside the range 0x%x - 0x%x\n", - inc, GTI_TIV_MIN, GTI_TIV_MAX); - return -EINVAL; - } - - ravb_write(ndev, inc, GTI); - - return 0; -} - static int ravb_set_config_mode(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); @@ -2763,15 +2781,9 @@ static int ravb_probe(struct platform_device *pdev) if (error) goto out_rpm_put; - if (info->gptp || info->ccc_gac) { - /* Set GTI value */ - error = ravb_set_gti(ndev); - if (error) - goto out_rpm_put; - - /* Request GTI loading */ - ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI); - } + error = ravb_compute_gti(ndev); + if (error) + goto out_rpm_put; if (info->internal_delay) { ravb_parse_delay_mode(np, ndev); @@ -2984,15 +2996,7 @@ static int ravb_resume(struct device *dev) if (ret) return ret; - if (info->gptp || info->ccc_gac) { - /* Set GTI value */ - ret = ravb_set_gti(ndev); - if (ret) - return ret; - - /* Request GTI loading */ - ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI); - } + ravb_set_gti(ndev); if (info->internal_delay) ravb_set_delay_mode(ndev); From 23698a9abb629009b42ef419072e567b43ca6866 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:31 +0200 Subject: [PATCH 0785/2255] net: ravb: Move delay mode set in the driver's ndo_open API Delay parsing and setting were done in the driver's probe API. As some IP variants switch to reset mode (and thus the register contents is lost) when setting clocks (due to module standby functionality) to be able to implement runtime PM keep the delay parsing in the driver's probe function and move the delay applying function to the driver's ndo_open API. Along with it, ravb_parse_delay_mode() function was moved close to ravb_set_delay_mode() function to have the delay specific code in the same place. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 107 ++++++++++++----------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 0f7b1d503618..e5805e0d8e13 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1800,6 +1800,59 @@ static int ravb_compute_gti(struct net_device *ndev) return 0; } +/* Set tx and rx clock internal delay modes */ +static void ravb_parse_delay_mode(struct device_node *np, struct net_device *ndev) +{ + struct ravb_private *priv = netdev_priv(ndev); + bool explicit_delay = false; + u32 delay; + + if (!priv->info->internal_delay) + return; + + if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay)) { + /* Valid values are 0 and 1800, according to DT bindings */ + priv->rxcidm = !!delay; + explicit_delay = true; + } + if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay)) { + /* Valid values are 0 and 2000, according to DT bindings */ + priv->txcidm = !!delay; + explicit_delay = true; + } + + if (explicit_delay) + return; + + /* Fall back to legacy rgmii-*id behavior */ + if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || + priv->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) { + priv->rxcidm = 1; + priv->rgmii_override = 1; + } + + if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || + priv->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) { + priv->txcidm = 1; + priv->rgmii_override = 1; + } +} + +static void ravb_set_delay_mode(struct net_device *ndev) +{ + struct ravb_private *priv = netdev_priv(ndev); + u32 set = 0; + + if (!priv->info->internal_delay) + return; + + if (priv->rxcidm) + set |= APSR_RDM; + if (priv->txcidm) + set |= APSR_TDM; + ravb_modify(ndev, APSR, APSR_RDM | APSR_TDM, set); +} + /* Network device open function for Ethernet AVB */ static int ravb_open(struct net_device *ndev) { @@ -1811,6 +1864,8 @@ static int ravb_open(struct net_device *ndev) if (info->nc_queues) napi_enable(&priv->napi[RAVB_NC]); + ravb_set_delay_mode(ndev); + /* Device init */ error = ravb_dmac_init(ndev); if (error) @@ -2531,41 +2586,6 @@ static int ravb_set_config_mode(struct net_device *ndev) return error; } -/* Set tx and rx clock internal delay modes */ -static void ravb_parse_delay_mode(struct device_node *np, struct net_device *ndev) -{ - struct ravb_private *priv = netdev_priv(ndev); - bool explicit_delay = false; - u32 delay; - - if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay)) { - /* Valid values are 0 and 1800, according to DT bindings */ - priv->rxcidm = !!delay; - explicit_delay = true; - } - if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay)) { - /* Valid values are 0 and 2000, according to DT bindings */ - priv->txcidm = !!delay; - explicit_delay = true; - } - - if (explicit_delay) - return; - - /* Fall back to legacy rgmii-*id behavior */ - if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || - priv->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) { - priv->rxcidm = 1; - priv->rgmii_override = 1; - } - - if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || - priv->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) { - priv->txcidm = 1; - priv->rgmii_override = 1; - } -} - static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name, const char *ch, int *irq, irq_handler_t handler) { @@ -2650,18 +2670,6 @@ static int ravb_setup_irqs(struct ravb_private *priv) return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", &irq, ravb_nc_interrupt); } -static void ravb_set_delay_mode(struct net_device *ndev) -{ - struct ravb_private *priv = netdev_priv(ndev); - u32 set = 0; - - if (priv->rxcidm) - set |= APSR_RDM; - if (priv->txcidm) - set |= APSR_TDM; - ravb_modify(ndev, APSR, APSR_RDM | APSR_TDM, set); -} - static int ravb_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -2785,10 +2793,7 @@ static int ravb_probe(struct platform_device *pdev) if (error) goto out_rpm_put; - if (info->internal_delay) { - ravb_parse_delay_mode(np, ndev); - ravb_set_delay_mode(ndev); - } + ravb_parse_delay_mode(np, ndev); /* Allocate descriptor base address table */ priv->desc_bat_size = sizeof(struct ravb_desc) * DBAT_ENTRY_NUM; From cd1fb46e02de3c70d6379b00c0e860ca44954574 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:32 +0200 Subject: [PATCH 0786/2255] net: ravb: Move DBAT configuration to the driver's ndo_open API DBAT setup was done in the driver's probe API. As some IP variants switch to reset mode (and thus registers content is lost) when setting clocks (due to module standby functionality) to be able to implement runtime PM move the DBAT configuration in the driver's ndo_open API. This commit prepares the code for the addition of runtime PM. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index e5805e0d8e13..318ab27635bb 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1865,6 +1865,7 @@ static int ravb_open(struct net_device *ndev) napi_enable(&priv->napi[RAVB_NC]); ravb_set_delay_mode(ndev); + ravb_write(ndev, priv->desc_bat_dma, DBAT); /* Device init */ error = ravb_dmac_init(ndev); @@ -2808,7 +2809,6 @@ static int ravb_probe(struct platform_device *pdev) } for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++) priv->desc_bat[q].die_dt = DT_EOS; - ravb_write(ndev, priv->desc_bat_dma, DBAT); /* Initialise HW timestamp list */ INIT_LIST_HEAD(&priv->ts_skb_list); From a6a85ba36fd0d3e5595a4fcf57e0811826254ff7 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:33 +0200 Subject: [PATCH 0787/2255] net: ravb: Move PTP initialization in the driver's ndo_open API for ccc_gac platorms The initialization sequence for PTP is the same for platforms with ccc_gac and gptp (according to "Figure 50.71 Flow of gPTP Initialization (Normal, Common to All Modes)" of the R-Car Series, 3rd generation hardware manual and "Figure 37A.53 Flow of gPTP Initialization (Normal, Common to All Modes)" of the RZ/G Series hardware manual). As some IP variants switch to reset mode (and thus the registers content is lost) when setting clocks (due to module standby functionality) to be able to implement runtime PM, move the PTP initialization to the driver's ndo_open API. This commit prepares the code for the addition of runtime PM. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 318ab27635bb..54099fef946e 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1876,7 +1876,7 @@ static int ravb_open(struct net_device *ndev) ravb_set_gti(ndev); /* Initialise PTP Clock driver */ - if (info->gptp) + if (info->gptp || info->ccc_gac) ravb_ptp_init(ndev, priv->pdev); /* PHY control start */ @@ -1890,7 +1890,7 @@ static int ravb_open(struct net_device *ndev) out_ptp_stop: /* Stop PTP Clock driver */ - if (info->gptp) + if (info->gptp || info->ccc_gac) ravb_ptp_stop(ndev); ravb_stop_dma(ndev); out_napi_off: @@ -2200,7 +2200,7 @@ static int ravb_close(struct net_device *ndev) ravb_write(ndev, 0, TIC); /* Stop PTP Clock driver */ - if (info->gptp) + if (info->gptp || info->ccc_gac) ravb_ptp_stop(ndev); /* Set the config mode to stop the AVB-DMAC's processes */ @@ -2813,10 +2813,6 @@ static int ravb_probe(struct platform_device *pdev) /* Initialise HW timestamp list */ INIT_LIST_HEAD(&priv->ts_skb_list); - /* Initialise PTP Clock driver */ - if (info->ccc_gac) - ravb_ptp_init(ndev, pdev); - /* Debug message level */ priv->msg_enable = RAVB_DEF_MSG_ENABLE; @@ -2861,10 +2857,6 @@ out_napi_del: out_dma_free: dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat, priv->desc_bat_dma); - - /* Stop PTP Clock driver */ - if (info->ccc_gac) - ravb_ptp_stop(ndev); out_rpm_put: pm_runtime_put(&pdev->dev); out_rpm_disable: @@ -2890,10 +2882,6 @@ static void ravb_remove(struct platform_device *pdev) ravb_mdio_release(priv); - /* Stop PTP Clock driver */ - if (info->ccc_gac) - ravb_ptp_stop(ndev); - dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat, priv->desc_bat_dma); From 76fd52c1007785fcea1d3405907cec940d44f403 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:34 +0200 Subject: [PATCH 0788/2255] net: ravb: Set config mode in ndo_open and reset mode in ndo_close As some IP variants switch to reset mode (and thus the register contents is lost) when setting clocks (due to module standby functionality) to be able to implement runtime PM and save more power, set the IP's operating mode to reset at the end of the probe. Along with it, in the ndo_open API the IP will be switched to configuration, then operation mode. In the ndo_close API, the IP will be switched back to reset mode. This allows implementing runtime PM and, along with it, save more power when the IP is not used. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 78 ++++++++++++++---------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 54099fef946e..0dab98ea615a 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1756,6 +1756,27 @@ static const struct ethtool_ops ravb_ethtool_ops = { .set_wol = ravb_set_wol, }; +static int ravb_set_config_mode(struct net_device *ndev) +{ + struct ravb_private *priv = netdev_priv(ndev); + const struct ravb_hw_info *info = priv->info; + int error; + + if (info->gptp) { + error = ravb_set_opmode(ndev, CCC_OPC_CONFIG); + if (error) + return error; + /* Set CSEL value */ + ravb_modify(ndev, CCC, CCC_CSEL, CCC_CSEL_HPB); + } else if (info->ccc_gac) { + error = ravb_set_opmode(ndev, CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB); + } else { + error = ravb_set_opmode(ndev, CCC_OPC_CONFIG); + } + + return error; +} + static void ravb_set_gti(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); @@ -1864,13 +1885,19 @@ static int ravb_open(struct net_device *ndev) if (info->nc_queues) napi_enable(&priv->napi[RAVB_NC]); + /* Set AVB config mode */ + error = ravb_set_config_mode(ndev); + if (error) + goto out_napi_off; + ravb_set_delay_mode(ndev); ravb_write(ndev, priv->desc_bat_dma, DBAT); /* Device init */ error = ravb_dmac_init(ndev); if (error) - goto out_napi_off; + goto out_set_reset; + ravb_emac_init(ndev); ravb_set_gti(ndev); @@ -1893,6 +1920,8 @@ out_ptp_stop: if (info->gptp || info->ccc_gac) ravb_ptp_stop(ndev); ravb_stop_dma(ndev); +out_set_reset: + ravb_set_opmode(ndev, CCC_OPC_RESET); out_napi_off: if (info->nc_queues) napi_disable(&priv->napi[RAVB_NC]); @@ -2236,7 +2265,8 @@ static int ravb_close(struct net_device *ndev) if (info->nc_queues) ravb_ring_free(ndev, RAVB_NC); - return 0; + /* Set reset mode. */ + return ravb_set_opmode(ndev, CCC_OPC_RESET); } static int ravb_hwtstamp_get(struct net_device *ndev, struct ifreq *req) @@ -2566,27 +2596,6 @@ static const struct of_device_id ravb_match_table[] = { }; MODULE_DEVICE_TABLE(of, ravb_match_table); -static int ravb_set_config_mode(struct net_device *ndev) -{ - struct ravb_private *priv = netdev_priv(ndev); - const struct ravb_hw_info *info = priv->info; - int error; - - if (info->gptp) { - error = ravb_set_opmode(ndev, CCC_OPC_CONFIG); - if (error) - return error; - /* Set CSEL value */ - ravb_modify(ndev, CCC, CCC_CSEL, CCC_CSEL_HPB); - } else if (info->ccc_gac) { - error = ravb_set_opmode(ndev, CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB); - } else { - error = ravb_set_opmode(ndev, CCC_OPC_CONFIG); - } - - return error; -} - static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name, const char *ch, int *irq, irq_handler_t handler) { @@ -2785,11 +2794,6 @@ static int ravb_probe(struct platform_device *pdev) ndev->netdev_ops = &ravb_netdev_ops; ndev->ethtool_ops = &ravb_ethtool_ops; - /* Set AVB config mode */ - error = ravb_set_config_mode(ndev); - if (error) - goto out_rpm_put; - error = ravb_compute_gti(ndev); if (error) goto out_rpm_put; @@ -2816,6 +2820,11 @@ static int ravb_probe(struct platform_device *pdev) /* Debug message level */ priv->msg_enable = RAVB_DEF_MSG_ENABLE; + /* Set config mode as this is needed for PHY initialization. */ + error = ravb_set_opmode(ndev, CCC_OPC_CONFIG); + if (error) + goto out_rpm_put; + /* Read and set MAC address */ ravb_read_mac_address(np, ndev); if (!is_valid_ether_addr(ndev->dev_addr)) { @@ -2828,9 +2837,14 @@ static int ravb_probe(struct platform_device *pdev) error = ravb_mdio_init(priv); if (error) { dev_err(&pdev->dev, "failed to initialize MDIO\n"); - goto out_dma_free; + goto out_reset_mode; } + /* Undo previous switch to config opmode. */ + error = ravb_set_opmode(ndev, CCC_OPC_RESET); + if (error) + goto out_mdio_release; + netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll); if (info->nc_queues) netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll); @@ -2853,8 +2867,10 @@ out_napi_del: netif_napi_del(&priv->napi[RAVB_NC]); netif_napi_del(&priv->napi[RAVB_BE]); +out_mdio_release: ravb_mdio_release(priv); -out_dma_free: +out_reset_mode: + ravb_set_opmode(ndev, CCC_OPC_RESET); dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat, priv->desc_bat_dma); out_rpm_put: @@ -2885,8 +2901,6 @@ static void ravb_remove(struct platform_device *pdev) dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat, priv->desc_bat_dma); - ravb_set_opmode(ndev, CCC_OPC_RESET); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); clk_unprepare(priv->refclk); From b07bc55cbb1cf88a527d687fccd4a12bac744486 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:35 +0200 Subject: [PATCH 0789/2255] net: ravb: Simplify ravb_suspend() As ravb_close() contains now the call to ravb_ptp_stop() for both ccc_gac and gPTP aware platforms, there is no need to keep the separate call in ravb_suspend(). Instead, move it to ravb_wol_setup(). In this way the resulting code is cleaner. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 0dab98ea615a..661236affa5b 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2929,6 +2929,9 @@ static int ravb_wol_setup(struct net_device *ndev) /* Enable MagicPacket */ ravb_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE); + if (priv->info->ccc_gac) + ravb_ptp_stop(ndev); + return enable_irq_wake(priv->emac_irq); } @@ -2961,14 +2964,10 @@ static int ravb_suspend(struct device *dev) netif_device_detach(ndev); if (priv->wol_enabled) - ret = ravb_wol_setup(ndev); - else - ret = ravb_close(ndev); + return ravb_wol_setup(ndev); - if (priv->info->ccc_gac) - ravb_ptp_stop(ndev); - - if (priv->wol_enabled) + ret = ravb_close(ndev); + if (ret) return ret; reset_assert: From e95273fe4d02a6096ba5fe8287bcd9513396ec71 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 2 Feb 2024 10:41:36 +0200 Subject: [PATCH 0790/2255] net: ravb: Simplify ravb_resume() Remove explicit calls to functions that are called by ravb_open(). There is no need to have them doubled now that the ravb_open() already contains what is needed for the interface configuration. Along with it, configurations needed by PTP were moved to ravb_wol_restore(). With this, code in ravb_resume() becomes simpler. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: Paolo Abeni --- drivers/net/ethernet/renesas/ravb_main.c | 58 ++++++++++-------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 661236affa5b..9521cd054274 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2939,6 +2939,20 @@ static int ravb_wol_restore(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; + int error; + + /* Set reset mode to rearm the WoL logic. */ + error = ravb_set_opmode(ndev, CCC_OPC_RESET); + if (error) + return error; + + /* Set AVB config mode. */ + error = ravb_set_config_mode(ndev); + if (error) + return error; + + if (priv->info->ccc_gac) + ravb_ptp_init(ndev, priv->pdev); if (info->nc_queues) napi_enable(&priv->napi[RAVB_NC]); @@ -2978,53 +2992,29 @@ static int ravb_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct ravb_private *priv = netdev_priv(ndev); - const struct ravb_hw_info *info = priv->info; int ret; ret = reset_control_deassert(priv->rstc); if (ret) return ret; - /* If WoL is enabled set reset mode to rearm the WoL logic */ + if (!netif_running(ndev)) + return 0; + + /* If WoL is enabled restore the interface. */ if (priv->wol_enabled) { - ret = ravb_set_opmode(ndev, CCC_OPC_RESET); + ret = ravb_wol_restore(ndev); if (ret) return ret; } - /* All register have been reset to default values. - * Restore all registers which where setup at probe time and - * reopen device if it was running before system suspended. - */ - - /* Set AVB config mode */ - ret = ravb_set_config_mode(ndev); - if (ret) + /* Reopening the interface will restore the device to the working state. */ + ret = ravb_open(ndev); + if (ret < 0) return ret; - ravb_set_gti(ndev); - - if (info->internal_delay) - ravb_set_delay_mode(ndev); - - /* Restore descriptor base address table */ - ravb_write(ndev, priv->desc_bat_dma, DBAT); - - if (priv->info->ccc_gac) - ravb_ptp_init(ndev, priv->pdev); - - if (netif_running(ndev)) { - if (priv->wol_enabled) { - ret = ravb_wol_restore(ndev); - if (ret) - return ret; - } - ret = ravb_open(ndev); - if (ret < 0) - return ret; - ravb_set_rx_mode(ndev); - netif_device_attach(ndev); - } + ravb_set_rx_mode(ndev); + netif_device_attach(ndev); return ret; } From 03ba6dc035c60991033529e630bd1552b2bca4d7 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 2 Feb 2024 17:37:46 +0100 Subject: [PATCH 0791/2255] net: dst: Make dst_destroy() static and return void. Since commit 52df157f17e56 ("xfrm: take refcnt of dst when creating struct xfrm_dst bundle") dst_destroy() returns only NULL and no caller cares about the return value. There are no in in-tree users of dst_destroy() outside of the file. Make dst_destroy() static and return void. Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20240202163746.2489150-1-bigeasy@linutronix.de Signed-off-by: Paolo Abeni --- include/net/dst.h | 1 - net/core/dst.c | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index f5dfc8fb7b37..0aa331bd2fdb 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -390,7 +390,6 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, void dst_init(struct dst_entry *dst, struct dst_ops *ops, struct net_device *dev, int initial_obsolete, unsigned short flags); -struct dst_entry *dst_destroy(struct dst_entry *dst); void dst_dev_put(struct dst_entry *dst); static inline void dst_confirm(struct dst_entry *dst) diff --git a/net/core/dst.c b/net/core/dst.c index 6838d3212c37..95f533844f17 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -96,7 +96,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, } EXPORT_SYMBOL(dst_alloc); -struct dst_entry *dst_destroy(struct dst_entry * dst) +static void dst_destroy(struct dst_entry *dst) { struct dst_entry *child = NULL; @@ -126,15 +126,13 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) dst = child; if (dst) dst_release_immediate(dst); - return NULL; } -EXPORT_SYMBOL(dst_destroy); static void dst_destroy_rcu(struct rcu_head *head) { struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head); - dst = dst_destroy(dst); + dst_destroy(dst); } /* Operations to mark dst as DEAD and clean up the net device referenced From 0bd199fd9c19aa545f677fd0a99f2be101cb6309 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 2 Feb 2024 17:41:45 +0000 Subject: [PATCH 0792/2255] net: phy: constify phydev->drv Device driver structures are shared between all devices that they match, and thus nothing should never write to the device driver structure through the phydev->drv pointer. Let's make this pointer const to catch code that attempts to do so. Suggested-by: Christian Marangi Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1rVxXt-002YqY-9G@rmk-PC.armlinux.org.uk Signed-off-by: Paolo Abeni --- drivers/net/phy/phy.c | 3 +-- drivers/net/phy/phy_device.c | 6 +++--- drivers/net/phy/xilinx_gmii2rgmii.c | 2 +- include/linux/phy.h | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3b9531143be1..14224e06d69f 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1290,7 +1290,6 @@ int phy_disable_interrupts(struct phy_device *phydev) static irqreturn_t phy_interrupt(int irq, void *phy_dat) { struct phy_device *phydev = phy_dat; - struct phy_driver *drv = phydev->drv; irqreturn_t ret; /* Wakeup interrupts may occur during a system sleep transition. @@ -1316,7 +1315,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) } mutex_lock(&phydev->lock); - ret = drv->handle_interrupt(phydev); + ret = phydev->drv->handle_interrupt(phydev); mutex_unlock(&phydev->lock); return ret; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 52828d1c64f7..2eed8f03621d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1413,7 +1413,7 @@ int phy_sfp_probe(struct phy_device *phydev, } EXPORT_SYMBOL(phy_sfp_probe); -static bool phy_drv_supports_irq(struct phy_driver *phydrv) +static bool phy_drv_supports_irq(const struct phy_driver *phydrv) { return phydrv->config_intr && phydrv->handle_interrupt; } @@ -1867,7 +1867,7 @@ int phy_suspend(struct phy_device *phydev) { struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; struct net_device *netdev = phydev->attached_dev; - struct phy_driver *phydrv = phydev->drv; + const struct phy_driver *phydrv = phydev->drv; int ret; if (phydev->suspended) @@ -1892,7 +1892,7 @@ EXPORT_SYMBOL(phy_suspend); int __phy_resume(struct phy_device *phydev) { - struct phy_driver *phydrv = phydev->drv; + const struct phy_driver *phydrv = phydev->drv; int ret; lockdep_assert_held(&phydev->lock); diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c index 7fd9fe6a602b..7b1bc5fcef9b 100644 --- a/drivers/net/phy/xilinx_gmii2rgmii.c +++ b/drivers/net/phy/xilinx_gmii2rgmii.c @@ -22,7 +22,7 @@ struct gmii2rgmii { struct phy_device *phy_dev; - struct phy_driver *phy_drv; + const struct phy_driver *phy_drv; struct phy_driver conv_phy_drv; struct mdio_device *mdio; }; diff --git a/include/linux/phy.h b/include/linux/phy.h index a66f07d3f5f4..ad93f8b1b128 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -638,7 +638,7 @@ struct phy_device { /* Information about the PHY type */ /* And management functions */ - struct phy_driver *drv; + const struct phy_driver *drv; struct device_link *devlink; From 240fd405528bbf7fafa0559202ca7aa524c9cd96 Mon Sep 17 00:00:00 2001 From: Aahil Awatramani Date: Fri, 2 Feb 2024 17:58:58 +0000 Subject: [PATCH 0793/2255] bonding: Add independent control state machine Add support for the independent control state machine per IEEE 802.1AX-2008 5.4.15 in addition to the existing implementation of the coupled control state machine. Introduces two new states, AD_MUX_COLLECTING and AD_MUX_DISTRIBUTING in the LACP MUX state machine for separated handling of an initial Collecting state before the Collecting and Distributing state. This enables a port to be in a state where it can receive incoming packets while not still distributing. This is useful for reducing packet loss when a port begins distributing before its partner is able to collect. Added new functions such as bond_set_slave_tx_disabled_flags and bond_set_slave_rx_enabled_flags to precisely manage the port's collecting and distributing states. Previously, there was no dedicated method to disable TX while keeping RX enabled, which this patch addresses. Note that the regular flow process in the kernel's bonding driver remains unaffected by this patch. The extension requires explicit opt-in by the user (in order to ensure no disruptions for existing setups) via netlink support using the new bonding parameter coupled_control. The default value for coupled_control is set to 1 so as to preserve existing behaviour. Signed-off-by: Aahil Awatramani Reviewed-by: Hangbin Liu Link: https://lore.kernel.org/r/20240202175858.1573852-1-aahila@google.com Signed-off-by: Paolo Abeni --- Documentation/networking/bonding.rst | 12 ++ drivers/net/bonding/bond_3ad.c | 157 +++++++++++++++++++++++++-- drivers/net/bonding/bond_main.c | 1 + drivers/net/bonding/bond_netlink.c | 16 +++ drivers/net/bonding/bond_options.c | 28 ++++- include/net/bond_3ad.h | 2 + include/net/bond_options.h | 1 + include/net/bonding.h | 23 ++++ include/uapi/linux/if_link.h | 1 + tools/include/uapi/linux/if_link.h | 1 + 10 files changed, 234 insertions(+), 8 deletions(-) diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst index f7a73421eb76..e774b48de9f5 100644 --- a/Documentation/networking/bonding.rst +++ b/Documentation/networking/bonding.rst @@ -444,6 +444,18 @@ arp_missed_max The default value is 2, and the allowable range is 1 - 255. +coupled_control + + Specifies whether the LACP state machine's MUX in the 802.3ad mode + should have separate Collecting and Distributing states. + + This is by implementing the independent control state machine per + IEEE 802.1AX-2008 5.4.15 in addition to the existing coupled control + state machine. + + The default value is 1. This setting does not separate the Collecting + and Distributing states, maintaining the bond in coupled control. + downdelay Specifies the time, in milliseconds, to wait before disabling diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index c99ffe6c683a..f2942e8c6c91 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -106,6 +106,9 @@ static void ad_agg_selection_logic(struct aggregator *aggregator, static void ad_clear_agg(struct aggregator *aggregator); static void ad_initialize_agg(struct aggregator *aggregator); static void ad_initialize_port(struct port *port, int lacp_fast); +static void ad_enable_collecting(struct port *port); +static void ad_disable_distributing(struct port *port, + bool *update_slave_arr); static void ad_enable_collecting_distributing(struct port *port, bool *update_slave_arr); static void ad_disable_collecting_distributing(struct port *port, @@ -171,9 +174,38 @@ static inline int __agg_has_partner(struct aggregator *agg) return !is_zero_ether_addr(agg->partner_system.mac_addr_value); } +/** + * __disable_distributing_port - disable the port's slave for distributing. + * Port will still be able to collect. + * @port: the port we're looking at + * + * This will disable only distributing on the port's slave. + */ +static void __disable_distributing_port(struct port *port) +{ + bond_set_slave_tx_disabled_flags(port->slave, BOND_SLAVE_NOTIFY_LATER); +} + +/** + * __enable_collecting_port - enable the port's slave for collecting, + * if it's up + * @port: the port we're looking at + * + * This will enable only collecting on the port's slave. + */ +static void __enable_collecting_port(struct port *port) +{ + struct slave *slave = port->slave; + + if (slave->link == BOND_LINK_UP && bond_slave_is_up(slave)) + bond_set_slave_rx_enabled_flags(slave, BOND_SLAVE_NOTIFY_LATER); +} + /** * __disable_port - disable the port's slave * @port: the port we're looking at + * + * This will disable both collecting and distributing on the port's slave. */ static inline void __disable_port(struct port *port) { @@ -183,6 +215,8 @@ static inline void __disable_port(struct port *port) /** * __enable_port - enable the port's slave, if it's up * @port: the port we're looking at + * + * This will enable both collecting and distributing on the port's slave. */ static inline void __enable_port(struct port *port) { @@ -193,10 +227,27 @@ static inline void __enable_port(struct port *port) } /** - * __port_is_enabled - check if the port's slave is in active state + * __port_move_to_attached_state - check if port should transition back to attached + * state. * @port: the port we're looking at */ -static inline int __port_is_enabled(struct port *port) +static bool __port_move_to_attached_state(struct port *port) +{ + if (!(port->sm_vars & AD_PORT_SELECTED) || + (port->sm_vars & AD_PORT_STANDBY) || + !(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) || + !(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) + port->sm_mux_state = AD_MUX_ATTACHED; + + return port->sm_mux_state == AD_MUX_ATTACHED; +} + +/** + * __port_is_collecting_distributing - check if the port's slave is in the + * combined collecting/distributing state + * @port: the port we're looking at + */ +static int __port_is_collecting_distributing(struct port *port) { return bond_is_active_slave(port->slave); } @@ -942,6 +993,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) */ static void ad_mux_machine(struct port *port, bool *update_slave_arr) { + struct bonding *bond = __get_bond_by_port(port); mux_states_t last_state; /* keep current State Machine state to compare later if it was @@ -999,9 +1051,13 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { - if (port->aggregator->is_active) - port->sm_mux_state = - AD_MUX_COLLECTING_DISTRIBUTING; + if (port->aggregator->is_active) { + int state = AD_MUX_COLLECTING_DISTRIBUTING; + + if (!bond->params.coupled_control) + state = AD_MUX_COLLECTING; + port->sm_mux_state = state; + } } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { /* if UNSELECTED or STANDBY */ @@ -1019,11 +1075,45 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) } break; case AD_MUX_COLLECTING_DISTRIBUTING: + if (!__port_move_to_attached_state(port)) { + /* if port state hasn't changed make + * sure that a collecting distributing + * port in an active aggregator is enabled + */ + if (port->aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; + } + } + break; + case AD_MUX_COLLECTING: + if (!__port_move_to_attached_state(port)) { + if ((port->sm_vars & AD_PORT_SELECTED) && + (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && + (port->partner_oper.port_state & LACP_STATE_COLLECTING)) { + port->sm_mux_state = AD_MUX_DISTRIBUTING; + } else { + /* If port state hasn't changed, make sure that a collecting + * port is enabled for an active aggregator. + */ + struct slave *slave = port->slave; + + if (port->aggregator->is_active && + bond_is_slave_rx_disabled(slave)) { + ad_enable_collecting(port); + *update_slave_arr = true; + } + } + } + break; + case AD_MUX_DISTRIBUTING: if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) || + !(port->partner_oper.port_state & LACP_STATE_COLLECTING) || !(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) || !(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) { - port->sm_mux_state = AD_MUX_ATTACHED; + port->sm_mux_state = AD_MUX_COLLECTING; } else { /* if port state hasn't changed make * sure that a collecting distributing @@ -1031,7 +1121,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) */ if (port->aggregator && port->aggregator->is_active && - !__port_is_enabled(port)) { + !__port_is_collecting_distributing(port)) { __enable_port(port); *update_slave_arr = true; } @@ -1082,6 +1172,20 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) update_slave_arr); port->ntt = true; break; + case AD_MUX_COLLECTING: + port->actor_oper_port_state |= LACP_STATE_COLLECTING; + port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING; + port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION; + ad_enable_collecting(port); + ad_disable_distributing(port, update_slave_arr); + port->ntt = true; + break; + case AD_MUX_DISTRIBUTING: + port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING; + port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION; + ad_enable_collecting_distributing(port, + update_slave_arr); + break; default: break; } @@ -1906,6 +2010,45 @@ static void ad_initialize_port(struct port *port, int lacp_fast) } } +/** + * ad_enable_collecting - enable a port's receive + * @port: the port we're looking at + * + * Enable @port if it's in an active aggregator + */ +static void ad_enable_collecting(struct port *port) +{ + if (port->aggregator->is_active) { + struct slave *slave = port->slave; + + slave_dbg(slave->bond->dev, slave->dev, + "Enabling collecting on port %d (LAG %d)\n", + port->actor_port_number, + port->aggregator->aggregator_identifier); + __enable_collecting_port(port); + } +} + +/** + * ad_disable_distributing - disable a port's transmit + * @port: the port we're looking at + * @update_slave_arr: Does slave array need update? + */ +static void ad_disable_distributing(struct port *port, bool *update_slave_arr) +{ + if (port->aggregator && + !MAC_ADDRESS_EQUAL(&port->aggregator->partner_system, + &(null_mac_addr))) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling distributing on port %d (LAG %d)\n", + port->actor_port_number, + port->aggregator->aggregator_identifier); + __disable_distributing_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; + } +} + /** * ad_enable_collecting_distributing - enable a port's transmit/receive * @port: the port we're looking at diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4e0600c7b050..ae9d32c0faf4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -6306,6 +6306,7 @@ static int __init bond_check_params(struct bond_params *params) params->ad_actor_sys_prio = ad_actor_sys_prio; eth_zero_addr(params->ad_actor_system); params->ad_user_port_key = ad_user_port_key; + params->coupled_control = 1; if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index cfa74cf8bb1a..29b4c3d1b9b6 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -122,6 +122,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_PEER_NOTIF_DELAY] = NLA_POLICY_FULL_RANGE(NLA_U32, &delay_range), [IFLA_BOND_MISSED_MAX] = { .type = NLA_U8 }, [IFLA_BOND_NS_IP6_TARGET] = { .type = NLA_NESTED }, + [IFLA_BOND_COUPLED_CONTROL] = { .type = NLA_U8 }, }; static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { @@ -549,6 +550,16 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], return err; } + if (data[IFLA_BOND_COUPLED_CONTROL]) { + int coupled_control = nla_get_u8(data[IFLA_BOND_COUPLED_CONTROL]); + + bond_opt_initval(&newval, coupled_control); + err = __bond_opt_set(bond, BOND_OPT_COUPLED_CONTROL, &newval, + data[IFLA_BOND_COUPLED_CONTROL], extack); + if (err) + return err; + } + return 0; } @@ -615,6 +626,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) /* IFLA_BOND_NS_IP6_TARGET */ nla_total_size(sizeof(struct nlattr)) + nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS + + nla_total_size(sizeof(u8)) + /* IFLA_BOND_COUPLED_CONTROL */ 0; } @@ -774,6 +786,10 @@ static int bond_fill_info(struct sk_buff *skb, bond->params.missed_max)) goto nla_put_failure; + if (nla_put_u8(skb, IFLA_BOND_COUPLED_CONTROL, + bond->params.coupled_control)) + goto nla_put_failure; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { struct ad_info info; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index f3f27f0bd2a6..4cdbc7e084f4 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -84,7 +84,8 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_missed_max_set(struct bonding *bond, const struct bond_opt_value *newval); - +static int bond_option_coupled_control_set(struct bonding *bond, + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT}, @@ -232,6 +233,12 @@ static const struct bond_opt_value bond_missed_max_tbl[] = { { NULL, -1, 0}, }; +static const struct bond_opt_value bond_coupled_control_tbl[] = { + { "on", 1, BOND_VALFLAG_DEFAULT}, + { "off", 0, 0}, + { NULL, -1, 0}, +}; + static const struct bond_option bond_opts[BOND_OPT_LAST] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, @@ -496,6 +503,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .desc = "Delay between each peer notification on failover event, in milliseconds", .values = bond_peer_notif_delay_tbl, .set = bond_option_peer_notif_delay_set + }, + [BOND_OPT_COUPLED_CONTROL] = { + .id = BOND_OPT_COUPLED_CONTROL, + .name = "coupled_control", + .desc = "Opt into using coupled control MUX for LACP states", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_IFDOWN, + .values = bond_coupled_control_tbl, + .set = bond_option_coupled_control_set, } }; @@ -1692,3 +1708,13 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond, bond->params.ad_user_port_key = newval->value; return 0; } + +static int bond_option_coupled_control_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + netdev_info(bond->dev, "Setting coupled_control to %s (%llu)\n", + newval->string, newval->value); + + bond->params.coupled_control = newval->value; + return 0; +} diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h index c5e57c6bd873..9ce5ac2bfbad 100644 --- a/include/net/bond_3ad.h +++ b/include/net/bond_3ad.h @@ -54,6 +54,8 @@ typedef enum { AD_MUX_DETACHED, /* mux machine */ AD_MUX_WAITING, /* mux machine */ AD_MUX_ATTACHED, /* mux machine */ + AD_MUX_COLLECTING, /* mux machine */ + AD_MUX_DISTRIBUTING, /* mux machine */ AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */ } mux_states_t; diff --git a/include/net/bond_options.h b/include/net/bond_options.h index 69292ecc0325..473a0147769e 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -76,6 +76,7 @@ enum { BOND_OPT_MISSED_MAX, BOND_OPT_NS_TARGETS, BOND_OPT_PRIO, + BOND_OPT_COUPLED_CONTROL, BOND_OPT_LAST }; diff --git a/include/net/bonding.h b/include/net/bonding.h index 5b8b1b644a2d..b61fb1aa3a56 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -148,6 +148,7 @@ struct bond_params { #if IS_ENABLED(CONFIG_IPV6) struct in6_addr ns_targets[BOND_MAX_NS_TARGETS]; #endif + int coupled_control; /* 2 bytes of padding : see ether_addr_equal_64bits() */ u8 ad_actor_system[ETH_ALEN + 2]; @@ -167,6 +168,7 @@ struct slave { u8 backup:1, /* indicates backup slave. Value corresponds with BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ inactive:1, /* indicates inactive slave */ + rx_disabled:1, /* indicates whether slave's Rx is disabled */ should_notify:1, /* indicates whether the state changed */ should_notify_link:1; /* indicates whether the link changed */ u8 duplex; @@ -568,6 +570,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave, bond_set_slave_state(slave, BOND_STATE_BACKUP, notify); if (!slave->bond->params.all_slaves_active) slave->inactive = 1; + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) + slave->rx_disabled = 1; +} + +static inline void bond_set_slave_tx_disabled_flags(struct slave *slave, + bool notify) +{ + bond_set_slave_state(slave, BOND_STATE_BACKUP, notify); } static inline void bond_set_slave_active_flags(struct slave *slave, @@ -575,6 +585,14 @@ static inline void bond_set_slave_active_flags(struct slave *slave, { bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify); slave->inactive = 0; + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) + slave->rx_disabled = 0; +} + +static inline void bond_set_slave_rx_enabled_flags(struct slave *slave, + bool notify) +{ + slave->rx_disabled = 0; } static inline bool bond_is_slave_inactive(struct slave *slave) @@ -582,6 +600,11 @@ static inline bool bond_is_slave_inactive(struct slave *slave) return slave->inactive; } +static inline bool bond_is_slave_rx_disabled(struct slave *slave) +{ + return slave->rx_disabled; +} + static inline void bond_propose_link_state(struct slave *slave, int state) { slave->link_new_state = state; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index ab9bcff96e4d..ffa637b38c93 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -1505,6 +1505,7 @@ enum { IFLA_BOND_AD_LACP_ACTIVE, IFLA_BOND_MISSED_MAX, IFLA_BOND_NS_IP6_TARGET, + IFLA_BOND_COUPLED_CONTROL, __IFLA_BOND_MAX, }; diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index a0aa05a28cf2..f0d71b2a3f1e 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -974,6 +974,7 @@ enum { IFLA_BOND_AD_LACP_ACTIVE, IFLA_BOND_MISSED_MAX, IFLA_BOND_NS_IP6_TARGET, + IFLA_BOND_COUPLED_CONTROL, __IFLA_BOND_MAX, }; From 02daffa903e60a864b43a17f7074bb3f7b7baac7 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 2 Feb 2024 11:59:08 -0800 Subject: [PATCH 0794/2255] pds_core: Don't assign interrupt index/bound_intr to notifyq The notifyq rides on the adminq's interrupt, so there's no need to setup and/or access the notifyq's interrupt index or bound_intr. The driver sets the bound_intr using qcq->intx = -1 for the notifyq, but luckily nothing accesses that field for notifyq. Instead of expecting that remains the case, just clean up the notifyq's interrupt index and bound_intr fields. Signed-off-by: Brett Creeley Reviewed-by: Shannon Nelson Reviewed-by: Przemek Kitszel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amd/pds_core/core.c | 5 +---- drivers/net/ethernet/amd/pds_core/debugfs.c | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c index 7658a7286767..41507ade3570 100644 --- a/drivers/net/ethernet/amd/pds_core/core.c +++ b/drivers/net/ethernet/amd/pds_core/core.c @@ -129,6 +129,7 @@ static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq) if (index < 0) return index; qcq->intx = index; + qcq->cq.bound_intr = &pdsc->intr_info[index]; return 0; } @@ -222,7 +223,6 @@ int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, goto err_out_free_irq; } - qcq->cq.bound_intr = &pdsc->intr_info[qcq->intx]; qcq->cq.num_descs = num_descs; qcq->cq.desc_size = cq_desc_size; qcq->cq.tail_idx = 0; @@ -430,9 +430,6 @@ int pdsc_setup(struct pdsc *pdsc, bool init) if (err) goto err_out_teardown; - /* NotifyQ rides on the AdminQ interrupt */ - pdsc->notifyqcq.intx = pdsc->adminqcq.intx; - /* Set up the Core with the AdminQ and NotifyQ info */ err = pdsc_core_init(pdsc); if (err) diff --git a/drivers/net/ethernet/amd/pds_core/debugfs.c b/drivers/net/ethernet/amd/pds_core/debugfs.c index 4e8579ca1c8c..ba592dbeef14 100644 --- a/drivers/net/ethernet/amd/pds_core/debugfs.c +++ b/drivers/net/ethernet/amd/pds_core/debugfs.c @@ -109,7 +109,6 @@ void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq) struct dentry *qcq_dentry, *q_dentry, *cq_dentry; struct dentry *intr_dentry; struct debugfs_regset32 *intr_ctrl_regset; - struct pdsc_intr_info *intr = &pdsc->intr_info[qcq->intx]; struct pdsc_queue *q = &qcq->q; struct pdsc_cq *cq = &qcq->cq; @@ -147,6 +146,8 @@ void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq) debugfs_create_u16("tail", 0400, cq_dentry, &cq->tail_idx); if (qcq->flags & PDS_CORE_QCQ_F_INTR) { + struct pdsc_intr_info *intr = &pdsc->intr_info[qcq->intx]; + intr_dentry = debugfs_create_dir("intr", qcq->dentry); if (IS_ERR_OR_NULL(intr_dentry)) return; From bca10f2c2518b333275becb7f53d6511f622e084 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 2 Feb 2024 11:59:09 -0800 Subject: [PATCH 0795/2255] pds_core: Unmask adminq interrupt in work thread Unmasking the interrupt during the pdsc_adminq_isr is a bit early and could cause unnecessary interrupts. Instead always unmask after processing the adminq and notifyq in pdsc_work_thread()->pdsc_process_adminq(). Also, since we are always unmasking, there's no need for the local credits variable in pdsc_process_adminq(). Signed-off-by: Brett Creeley Reviewed-by: Shannon Nelson Reviewed-by: Przemek Kitszel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amd/pds_core/adminq.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/amd/pds_core/adminq.c b/drivers/net/ethernet/amd/pds_core/adminq.c index ea773cfa0af6..c83a0a80d533 100644 --- a/drivers/net/ethernet/amd/pds_core/adminq.c +++ b/drivers/net/ethernet/amd/pds_core/adminq.c @@ -82,7 +82,6 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq) unsigned long irqflags; int nq_work = 0; int aq_work = 0; - int credits; /* Don't process AdminQ when it's not up */ if (!pdsc_adminq_inc_if_up(pdsc)) { @@ -128,11 +127,9 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq) credits: /* Return the interrupt credits, one for each completion */ - credits = nq_work + aq_work; - if (credits) - pds_core_intr_credits(&pdsc->intr_ctrl[qcq->intx], - credits, - PDS_CORE_INTR_CRED_REARM); + pds_core_intr_credits(&pdsc->intr_ctrl[qcq->intx], + nq_work + aq_work, + PDS_CORE_INTR_CRED_REARM); refcount_dec(&pdsc->adminq_refcnt); } @@ -157,7 +154,6 @@ irqreturn_t pdsc_adminq_isr(int irq, void *data) qcq = &pdsc->adminqcq; queue_work(pdsc->wq, &qcq->work); - pds_core_intr_mask(&pdsc->intr_ctrl[qcq->intx], PDS_CORE_INTR_MASK_CLEAR); refcount_dec(&pdsc->adminq_refcnt); return IRQ_HANDLED; From 247c4ed03321cd1c971195b8127764d0826664a7 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 2 Feb 2024 11:59:10 -0800 Subject: [PATCH 0796/2255] pds_core: Fix up some minor issues Running xmastree.py against the driver found some RCT issues, so fix them. Also, if allocating pdsc->intr_info in pdsc_dev_init() fails the driver still tries to free pdsc->intr_info. Fix this by just returning -ENOMEM since there's nothing to free at this point of failure. Signed-off-by: Brett Creeley Reviewed-by: Shannon Nelson Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amd/pds_core/debugfs.c | 5 ++--- drivers/net/ethernet/amd/pds_core/dev.c | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/amd/pds_core/debugfs.c b/drivers/net/ethernet/amd/pds_core/debugfs.c index ba592dbeef14..6bdd02b7aa6d 100644 --- a/drivers/net/ethernet/amd/pds_core/debugfs.c +++ b/drivers/net/ethernet/amd/pds_core/debugfs.c @@ -32,8 +32,8 @@ void pdsc_debugfs_del_dev(struct pdsc *pdsc) static int identity_show(struct seq_file *seq, void *v) { - struct pdsc *pdsc = seq->private; struct pds_core_dev_identity *ident; + struct pdsc *pdsc = seq->private; int vt; ident = &pdsc->dev_ident; @@ -106,8 +106,7 @@ static const struct debugfs_reg32 intr_ctrl_regs[] = { void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq) { - struct dentry *qcq_dentry, *q_dentry, *cq_dentry; - struct dentry *intr_dentry; + struct dentry *qcq_dentry, *q_dentry, *cq_dentry, *intr_dentry; struct debugfs_regset32 *intr_ctrl_regset; struct pdsc_queue *q = &qcq->q; struct pdsc_cq *cq = &qcq->cq; diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c index e65a1632df50..7dc102a31185 100644 --- a/drivers/net/ethernet/amd/pds_core/dev.c +++ b/drivers/net/ethernet/amd/pds_core/dev.c @@ -341,10 +341,8 @@ int pdsc_dev_init(struct pdsc *pdsc) /* Get intr_info struct array for tracking */ pdsc->intr_info = kcalloc(nintrs, sizeof(*pdsc->intr_info), GFP_KERNEL); - if (!pdsc->intr_info) { - err = -ENOMEM; - goto err_out; - } + if (!pdsc->intr_info) + return -ENOMEM; err = pci_alloc_irq_vectors(pdsc->pdev, nintrs, nintrs, PCI_IRQ_MSIX); if (err != nintrs) { From 792d36ccc163ac4aa606b3f5ec31cfd2c3a365de Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 2 Feb 2024 11:59:11 -0800 Subject: [PATCH 0797/2255] pds_core: Clean up init/uninit flows to be more readable The setup and teardown flows are somewhat hard to follow regarding pdsc_core_init()/pdsc_dev_init() and their corresponding teardown flows being in pdsc_teardown(). Improve the readability by adding new pdsc_core_uninit()/pdsc_dev_unint() functions that mirror their init counterparts. Also, move the notify and admin qcq allocations into pdsc_core_init(), so they can be freed in pdsc_core_uninit(). Signed-off-by: Brett Creeley Reviewed-by: Shannon Nelson Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amd/pds_core/core.c | 87 ++++++++++++------------ drivers/net/ethernet/amd/pds_core/core.h | 1 + drivers/net/ethernet/amd/pds_core/dev.c | 16 +++++ 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c index 41507ade3570..1234a4a8a4ae 100644 --- a/drivers/net/ethernet/amd/pds_core/core.c +++ b/drivers/net/ethernet/amd/pds_core/core.c @@ -300,6 +300,17 @@ err_out: return err; } +static void pdsc_core_uninit(struct pdsc *pdsc) +{ + pdsc_qcq_free(pdsc, &pdsc->notifyqcq); + pdsc_qcq_free(pdsc, &pdsc->adminqcq); + + if (pdsc->kern_dbpage) { + iounmap(pdsc->kern_dbpage); + pdsc->kern_dbpage = NULL; + } +} + static int pdsc_core_init(struct pdsc *pdsc) { union pds_core_dev_comp comp = {}; @@ -310,9 +321,32 @@ static int pdsc_core_init(struct pdsc *pdsc) struct pds_core_dev_init_data_in cidi; u32 dbid_count; u32 dbpage_num; + int numdescs; size_t sz; int err; + /* Scale the descriptor ring length based on number of CPUs and VFs */ + numdescs = max_t(int, PDSC_ADMINQ_MIN_LENGTH, num_online_cpus()); + numdescs += 2 * pci_sriov_get_totalvfs(pdsc->pdev); + numdescs = roundup_pow_of_two(numdescs); + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_ADMINQ, 0, "adminq", + PDS_CORE_QCQ_F_CORE | PDS_CORE_QCQ_F_INTR, + numdescs, + sizeof(union pds_core_adminq_cmd), + sizeof(union pds_core_adminq_comp), + 0, &pdsc->adminqcq); + if (err) + return err; + + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_NOTIFYQ, 0, "notifyq", + PDS_CORE_QCQ_F_NOTIFYQ, + PDSC_NOTIFYQ_LENGTH, + sizeof(struct pds_core_notifyq_cmd), + sizeof(union pds_core_notifyq_comp), + 0, &pdsc->notifyqcq); + if (err) + goto err_out_uninit; + cidi.adminq_q_base = cpu_to_le64(pdsc->adminqcq.q_base_pa); cidi.adminq_cq_base = cpu_to_le64(pdsc->adminqcq.cq_base_pa); cidi.notifyq_cq_base = cpu_to_le64(pdsc->notifyqcq.cq.base_pa); @@ -336,7 +370,7 @@ static int pdsc_core_init(struct pdsc *pdsc) if (err) { dev_err(pdsc->dev, "Device init command failed: %pe\n", ERR_PTR(err)); - return err; + goto err_out_uninit; } pdsc->hw_index = le32_to_cpu(cido.core_hw_index); @@ -346,7 +380,8 @@ static int pdsc_core_init(struct pdsc *pdsc) pdsc->kern_dbpage = pdsc_map_dbpage(pdsc, dbpage_num); if (!pdsc->kern_dbpage) { dev_err(pdsc->dev, "Cannot map dbpage, aborting\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_out_uninit; } pdsc->adminqcq.q.hw_type = cido.adminq_hw_type; @@ -359,6 +394,10 @@ static int pdsc_core_init(struct pdsc *pdsc) pdsc->last_eid = 0; + return 0; + +err_out_uninit: + pdsc_core_uninit(pdsc); return err; } @@ -401,35 +440,12 @@ static int pdsc_viftypes_init(struct pdsc *pdsc) int pdsc_setup(struct pdsc *pdsc, bool init) { - int numdescs; int err; err = pdsc_dev_init(pdsc); if (err) return err; - /* Scale the descriptor ring length based on number of CPUs and VFs */ - numdescs = max_t(int, PDSC_ADMINQ_MIN_LENGTH, num_online_cpus()); - numdescs += 2 * pci_sriov_get_totalvfs(pdsc->pdev); - numdescs = roundup_pow_of_two(numdescs); - err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_ADMINQ, 0, "adminq", - PDS_CORE_QCQ_F_CORE | PDS_CORE_QCQ_F_INTR, - numdescs, - sizeof(union pds_core_adminq_cmd), - sizeof(union pds_core_adminq_comp), - 0, &pdsc->adminqcq); - if (err) - goto err_out_teardown; - - err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_NOTIFYQ, 0, "notifyq", - PDS_CORE_QCQ_F_NOTIFYQ, - PDSC_NOTIFYQ_LENGTH, - sizeof(struct pds_core_notifyq_cmd), - sizeof(union pds_core_notifyq_comp), - 0, &pdsc->notifyqcq); - if (err) - goto err_out_teardown; - /* Set up the Core with the AdminQ and NotifyQ info */ err = pdsc_core_init(pdsc); if (err) @@ -455,35 +471,20 @@ err_out_teardown: void pdsc_teardown(struct pdsc *pdsc, bool removing) { - int i; - if (!pdsc->pdev->is_virtfn) pdsc_devcmd_reset(pdsc); if (pdsc->adminqcq.work.func) cancel_work_sync(&pdsc->adminqcq.work); - pdsc_qcq_free(pdsc, &pdsc->notifyqcq); - pdsc_qcq_free(pdsc, &pdsc->adminqcq); + + pdsc_core_uninit(pdsc); if (removing) { kfree(pdsc->viftype_status); pdsc->viftype_status = NULL; } - if (pdsc->intr_info) { - for (i = 0; i < pdsc->nintrs; i++) - pdsc_intr_free(pdsc, i); + pdsc_dev_uninit(pdsc); - kfree(pdsc->intr_info); - pdsc->intr_info = NULL; - pdsc->nintrs = 0; - } - - if (pdsc->kern_dbpage) { - iounmap(pdsc->kern_dbpage); - pdsc->kern_dbpage = NULL; - } - - pci_free_irq_vectors(pdsc->pdev); set_bit(PDSC_S_FW_DEAD, &pdsc->state); } diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h index 110c4b826b22..3468a63f5ae9 100644 --- a/drivers/net/ethernet/amd/pds_core/core.h +++ b/drivers/net/ethernet/amd/pds_core/core.h @@ -282,6 +282,7 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, int pdsc_devcmd_init(struct pdsc *pdsc); int pdsc_devcmd_reset(struct pdsc *pdsc); int pdsc_dev_init(struct pdsc *pdsc); +void pdsc_dev_uninit(struct pdsc *pdsc); void pdsc_reset_prepare(struct pci_dev *pdev); void pdsc_reset_done(struct pci_dev *pdev); diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c index 7dc102a31185..e494e1298dc9 100644 --- a/drivers/net/ethernet/amd/pds_core/dev.c +++ b/drivers/net/ethernet/amd/pds_core/dev.c @@ -316,6 +316,22 @@ static int pdsc_identify(struct pdsc *pdsc) return 0; } +void pdsc_dev_uninit(struct pdsc *pdsc) +{ + if (pdsc->intr_info) { + int i; + + for (i = 0; i < pdsc->nintrs; i++) + pdsc_intr_free(pdsc, i); + + kfree(pdsc->intr_info); + pdsc->intr_info = NULL; + pdsc->nintrs = 0; + } + + pci_free_irq_vectors(pdsc->pdev); +} + int pdsc_dev_init(struct pdsc *pdsc) { unsigned int nintrs; From 06e6bc1b7aafa309c38d9d6623e8be3846647207 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Fri, 2 Feb 2024 15:11:09 -0500 Subject: [PATCH 0798/2255] tipc: rename the module name diag to tipc_diag It is not appropriate for TIPC to use "diag" as its diag module name while the other protocols are using "$(protoname)_diag" like tcp_diag, udp_diag and sctp_diag etc. So this patch is to rename diag.ko to tipc_diag.ko in tipc's Makefile. Signed-off-by: Xin Long Reviewed-by: Tung Nguyen Link: https://lore.kernel.org/r/d909edeef072da1810bd5869fdbbfe84411efdb2.1706904669.git.lucien.xin@gmail.com Signed-off-by: Paolo Abeni --- net/tipc/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/Makefile b/net/tipc/Makefile index ee49a9f1dd4f..18e1636aa036 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile @@ -18,5 +18,5 @@ tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o tipc-$(CONFIG_SYSCTL) += sysctl.o tipc-$(CONFIG_TIPC_CRYPTO) += crypto.o - -obj-$(CONFIG_TIPC_DIAG) += diag.o +obj-$(CONFIG_TIPC_DIAG) += tipc_diag.o +tipc_diag-y += diag.o From d6f4aac19ad44998c6b1cde0334ad76900136ca4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 3 Feb 2024 08:51:03 +0100 Subject: [PATCH 0799/2255] nfc: hci: Introduce nfc_llc_del_engine() to reduce code duplication Add a new helper to avoid code duplication between nfc_llc_exit() and nfc_llc_unregister(). Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- net/nfc/hci/llc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c index 2140f6724644..480c17f372a5 100644 --- a/net/nfc/hci/llc.c +++ b/net/nfc/hci/llc.c @@ -30,15 +30,19 @@ exit: return r; } +static void nfc_llc_del_engine(struct nfc_llc_engine *llc_engine) +{ + list_del(&llc_engine->entry); + kfree(llc_engine->name); + kfree(llc_engine); +} + void nfc_llc_exit(void) { struct nfc_llc_engine *llc_engine, *n; - list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) { - list_del(&llc_engine->entry); - kfree(llc_engine->name); - kfree(llc_engine); - } + list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) + nfc_llc_del_engine(llc_engine); } int nfc_llc_register(const char *name, const struct nfc_llc_ops *ops) @@ -82,9 +86,7 @@ void nfc_llc_unregister(const char *name) if (llc_engine == NULL) return; - list_del(&llc_engine->entry); - kfree(llc_engine->name); - kfree(llc_engine); + nfc_llc_del_engine(llc_engine); } struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev, From 83cdd8db75085f3e415f420d6022f9c813ea50af Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 3 Feb 2024 08:51:04 +0100 Subject: [PATCH 0800/2255] nfc: hci: Save a few bytes of memory when registering a 'nfc_llc' engine nfc_llc_register() calls pass a string literal as the 'name' parameter. So kstrdup_const() can be used instead of kfree() to avoid a memory allocation in such cases. Signed-off-by: Christophe JAILLET Signed-off-by: Paolo Abeni --- net/nfc/hci/llc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c index 480c17f372a5..ba91284f4086 100644 --- a/net/nfc/hci/llc.c +++ b/net/nfc/hci/llc.c @@ -33,7 +33,7 @@ exit: static void nfc_llc_del_engine(struct nfc_llc_engine *llc_engine) { list_del(&llc_engine->entry); - kfree(llc_engine->name); + kfree_const(llc_engine->name); kfree(llc_engine); } @@ -53,7 +53,7 @@ int nfc_llc_register(const char *name, const struct nfc_llc_ops *ops) if (llc_engine == NULL) return -ENOMEM; - llc_engine->name = kstrdup(name, GFP_KERNEL); + llc_engine->name = kstrdup_const(name, GFP_KERNEL); if (llc_engine->name == NULL) { kfree(llc_engine); return -ENOMEM; From 563918a0e3afd97bcfb680b72c52ec080c82aea6 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Mon, 5 Feb 2024 20:51:46 -0800 Subject: [PATCH 0801/2255] bpf, docs: Fix typos in instructions-set.rst * "imm32" should just be "imm" * Add blank line to fix formatting error reported by Stephen Rothwell [0] [0]: https://lore.kernel.org/bpf/20240206153301.4ead0bad@canb.auug.org.au/T/#u Signed-off-by: Dave Thaler Acked-by: David Vernet Link: https://lore.kernel.org/r/20240206045146.4965-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov --- Documentation/bpf/standardization/instruction-set.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index 1c4258f1ce93..bdfe0cd0e499 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -117,6 +117,7 @@ corresponds to a set of instructions that are mandatory. That is, each instruction has one or more conformance groups of which it is a member. This document defines the following conformance groups: + * base32: includes all instructions defined in this specification unless otherwise noted. * base64: includes base32, plus instructions explicitly noted @@ -289,11 +290,11 @@ where '(u32)' indicates that the upper 32 bits are zeroed. ``BPF_XOR | BPF_K | BPF_ALU`` means:: - dst = (u32) dst ^ (u32) imm32 + dst = (u32) dst ^ (u32) imm ``BPF_XOR | BPF_K | BPF_ALU64`` means:: - dst = dst ^ imm32 + dst = dst ^ imm Note that most instructions have instruction offset of 0. Only three instructions (``BPF_SDIV``, ``BPF_SMOD``, ``BPF_MOVSX``) have a non-zero offset. @@ -511,7 +512,7 @@ instructions that transfer data between a register and memory. ``BPF_MEM | | BPF_ST`` means:: - *(size *) (dst + offset) = imm32 + *(size *) (dst + offset) = imm ``BPF_MEM | | BPF_LDX`` means:: From c27aa462aa78ff157fdda222af242e4571803d4a Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Tue, 6 Feb 2024 11:23:30 +0100 Subject: [PATCH 0802/2255] bpf: Use -Wno-address-of-packed-member in some selftests [Differences from V2: - Remove conditionals in the source files pragmas, as the pragma is supported by both GCC and clang.] Both GCC and clang implement the -Wno-address-of-packed-member warning, which is enabled by -Wall, that warns about taking the address of a packed struct field when it can lead to an "unaligned" address. This triggers the following errors (-Werror) when building three particular BPF selftests with GCC: progs/test_cls_redirect.c 986 | if (ipv4_is_fragment((void *)&encap->ip)) { progs/test_cls_redirect_dynptr.c 410 | pkt_ipv4_checksum((void *)&encap_gre->ip); progs/test_cls_redirect.c 521 | pkt_ipv4_checksum((void *)&encap_gre->ip); progs/test_tc_tunnel.c 232 | set_ipv4_csum((void *)&h_outer.ip); These warnings do not signal any real problem in the tests as far as I can see. This patch adds pragmas to these test files that inhibit the -Waddress-of-packed-member warning. Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240206102330.7113-1-jose.marchesi@oracle.com --- tools/testing/selftests/bpf/progs/test_cls_redirect.c | 2 ++ tools/testing/selftests/bpf/progs/test_cls_redirect_dynptr.c | 2 ++ tools/testing/selftests/bpf/progs/test_tc_tunnel.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/test_cls_redirect.c b/tools/testing/selftests/bpf/progs/test_cls_redirect.c index 66b304982245..bfc9179259d5 100644 --- a/tools/testing/selftests/bpf/progs/test_cls_redirect.c +++ b/tools/testing/selftests/bpf/progs/test_cls_redirect.c @@ -22,6 +22,8 @@ #include "test_cls_redirect.h" +#pragma GCC diagnostic ignored "-Waddress-of-packed-member" + #ifdef SUBPROGS #define INLINING __noinline #else diff --git a/tools/testing/selftests/bpf/progs/test_cls_redirect_dynptr.c b/tools/testing/selftests/bpf/progs/test_cls_redirect_dynptr.c index f41c81212ee9..da54c09e9a15 100644 --- a/tools/testing/selftests/bpf/progs/test_cls_redirect_dynptr.c +++ b/tools/testing/selftests/bpf/progs/test_cls_redirect_dynptr.c @@ -23,6 +23,8 @@ #include "test_cls_redirect.h" #include "bpf_kfuncs.h" +#pragma GCC diagnostic ignored "-Waddress-of-packed-member" + #define offsetofend(TYPE, MEMBER) \ (offsetof(TYPE, MEMBER) + sizeof((((TYPE *)0)->MEMBER))) diff --git a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c index e6e678aa9874..d8d7ab5e8e30 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c +++ b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c @@ -20,6 +20,8 @@ #include #include +#pragma GCC diagnostic ignored "-Waddress-of-packed-member" + static const int cfg_port = 8000; static const int cfg_udp_src = 20000; From 92a871ab9fa59a74d013bc04f321026a057618e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Tue, 6 Feb 2024 13:59:22 +0100 Subject: [PATCH 0803/2255] libbpf: Use OPTS_SET() macro in bpf_xdp_query() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the feature_flags and xdp_zc_max_segs fields were added to the libbpf bpf_xdp_query_opts, the code writing them did not use the OPTS_SET() macro. This causes libbpf to write to those fields unconditionally, which means that programs compiled against an older version of libbpf (with a smaller size of the bpf_xdp_query_opts struct) will have its stack corrupted by libbpf writing out of bounds. The patch adding the feature_flags field has an early bail out if the feature_flags field is not part of the opts struct (via the OPTS_HAS) macro, but the patch adding xdp_zc_max_segs does not. For consistency, this fix just changes the assignments to both fields to use the OPTS_SET() macro. Fixes: 13ce2daa259a ("xsk: add new netlink attribute dedicated for ZC max frags") Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240206125922.1992815-1-toke@redhat.com --- tools/lib/bpf/netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index 090bcf6e3b3d..68a2def17175 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -496,8 +496,8 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) if (err) return libbpf_err(err); - opts->feature_flags = md.flags; - opts->xdp_zc_max_segs = md.xdp_zc_max_segs; + OPTS_SET(opts, feature_flags, md.flags); + OPTS_SET(opts, xdp_zc_max_segs, md.xdp_zc_max_segs); skip_feature_flags: return 0; From ad1c86e92698fa524078abc83a0709ccca06dbcd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:32 +0800 Subject: [PATCH 0804/2255] 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(+) 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, From 80f47f82f3191b5d2530ad510814b4afab121672 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:33 +0800 Subject: [PATCH 0805/2255] 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(-) 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 From 9c66da3b19b5526b00bdd9ca2ef20560be21291f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:34 +0800 Subject: [PATCH 0806/2255] 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(+) 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); From 32919a0438946170bd944c557833186514c399f3 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:35 +0800 Subject: [PATCH 0807/2255] 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(+) 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); From b835141be5a94c3f170107c1f5446a4a7b204ac6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:36 +0800 Subject: [PATCH 0808/2255] 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(+) 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, From 1a0cba5dc983048ec0e13615b97c87a8882dff36 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:37 +0800 Subject: [PATCH 0809/2255] 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(+) 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, From af41e89ea323ca48d3ddf1a55b0f632d19ae0ae6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:38 +0800 Subject: [PATCH 0810/2255] 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(+) 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, From bd6f5f27cb2c2b0635cc9212fb82e6f112e7e681 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:39 +0800 Subject: [PATCH 0811/2255] 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(+) 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, From ff146ec22d5fe136b71b31703b1bea540ffc4d5f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:40 +0800 Subject: [PATCH 0812/2255] 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(-) 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, From 7e2629dc843fb46f0b8b3aba44708b508f6f98cf Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:41 +0800 Subject: [PATCH 0813/2255] 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(+) 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, From 4dbd964f33aab6f99891b9610ad4b36cc215be0d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:42 +0800 Subject: [PATCH 0814/2255] 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 + .../net/wireless/realtek/rtw89/rtw8922a_rfk.c | 202 ++++++++++++++++++ .../net/wireless/realtek/rtw89/rtw8922a_rfk.h | 1 + 11 files changed, 226 insertions(+) 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 From dedf78efd2885048ca36bc17fbd4e1c0af33f2ad Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:24 +0800 Subject: [PATCH 0815/2255] 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(+) 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) From 5462b8505f538b00d287a6de9a0fb2be6059bfc4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:25 +0800 Subject: [PATCH 0816/2255] 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(+) 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; } From 12ff5e1cca33b32fae0b183203f5b58a610e137e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:26 +0800 Subject: [PATCH 0817/2255] 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(-) 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)); From 43f8a4dc40a70b3598dd0aae401dddaf63ca0d5b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:27 +0800 Subject: [PATCH 0818/2255] 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(-) 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, From b8cfb7c819dd39965136a66fe3a7fde688d976fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Fri, 2 Feb 2024 17:42:13 +0100 Subject: [PATCH 0819/2255] 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(-) 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, From 78092e68557b9d062b8c4058be609254c804f14b Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 17:44:21 -0300 Subject: [PATCH 0820/2255] ssb: make ssb_bustype const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the driver core can properly handle constant struct bus_type, move the ssb_bustype variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Acked-by: Michael Büsch Reviewed-by: Greg Kroah-Hartman Signed-off-by: Kalle Valo Link: https://msgid.link/20240204-bus_cleanup-ssb-v1-1-511026cd5f3c@marliere.net --- drivers/ssb/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index b9934b9c2d70..9f30e0edadfe 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -384,7 +384,7 @@ static struct attribute *ssb_device_attrs[] = { }; ATTRIBUTE_GROUPS(ssb_device); -static struct bus_type ssb_bustype = { +static const struct bus_type ssb_bustype = { .name = "ssb", .match = ssb_bus_match, .probe = ssb_device_probe, From 06b5b2942cf2b0878bd5bda2d35ffdb997874012 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 17:57:23 -0300 Subject: [PATCH 0821/2255] bcma: make bcma_bus_type const Now that the driver core can properly handle constant struct bus_type, move the bcma_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Signed-off-by: Kalle Valo Link: https://msgid.link/20240204-bus_cleanup-bcma-v1-1-0d881c793190@marliere.net --- drivers/bcma/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 7061d3ee836a..6b5d34919c72 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -68,7 +68,7 @@ static struct attribute *bcma_device_attrs[] = { }; ATTRIBUTE_GROUPS(bcma_device); -static struct bus_type bcma_bus_type = { +static const struct bus_type bcma_bus_type = { .name = "bcma", .match = bcma_bus_match, .probe = bcma_device_probe, From 94dd7ce1885e530a7b10bbe50d5d68ba1bb99e6e Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Mon, 5 Feb 2024 10:30:40 +0100 Subject: [PATCH 0822/2255] 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 --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 +- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 194 ++++++++++++++---- 2 files changed, 161 insertions(+), 41 deletions(-) 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_ra_iter(void *data, struct ieee80211_sta *sta) +{ + 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->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), + rtl8xxxu_signal_to_snr(signal)); + rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); +} + +struct rtl8xxxu_stas_entry { + struct list_head list; + struct ieee80211_sta *sta; +}; + +struct rtl8xxxu_iter_stas_data { + struct rtl8xxxu_priv *priv; + struct list_head list; +}; + +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; + + stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC); + if (!stas_entry) + return; + + stas_entry->sta = sta; + list_add_tail(&stas_entry->list, &iter_stas->list); +} + static void rtl8xxxu_watchdog_callback(struct work_struct *work) { - struct ieee80211_vif *vif; + + struct rtl8xxxu_iter_stas_data iter_data; + struct rtl8xxxu_stas_entry *sta_entry, *tmp; struct rtl8xxxu_priv *priv; - int i; priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); - for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { - vif = priv->vifs[i]; + iter_data.priv = priv; + INIT_LIST_HEAD(&iter_data.list); - if (!vif || vif->type != NL80211_IFTYPE_STATION) - continue; - - int signal; - struct ieee80211_sta *sta; - - rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (!sta) { - struct device *dev = &priv->udev->dev; - - dev_dbg(dev, "%s: no sta found\n", __func__); - rcu_read_unlock(); - continue; - } - rcu_read_unlock(); - - signal = ieee80211_ave_rssi(vif); - - priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), - rtl8xxxu_signal_to_snr(signal)); - - rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); + 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); From 8f76c0f4c3ce489a7616f712fc08c032582145d9 Mon Sep 17 00:00:00 2001 From: Jedrzej Jagielski Date: Wed, 31 Jan 2024 12:04:17 +0100 Subject: [PATCH 0823/2255] ixgbe: Convert ret val type from s32 to int Currently big amount of the functions returning standard error codes are of type s32. Convert them to regular ints as typdefs here are not necessary to return standard error codes. Fix incorrect args alignment in touched functions. Suggested-by: Jacob Keller Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Signed-off-by: Jedrzej Jagielski Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 16 +- .../net/ethernet/intel/ixgbe/ixgbe_82598.c | 64 ++--- .../net/ethernet/intel/ixgbe/ixgbe_82599.c | 124 ++++---- .../net/ethernet/intel/ixgbe/ixgbe_common.c | 226 +++++++-------- .../net/ethernet/intel/ixgbe/ixgbe_common.h | 112 ++++---- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c | 12 +- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h | 10 +- .../ethernet/intel/ixgbe/ixgbe_dcb_82598.c | 26 +- .../ethernet/intel/ixgbe/ixgbe_dcb_82598.h | 24 +- .../ethernet/intel/ixgbe/ixgbe_dcb_82599.c | 12 +- .../ethernet/intel/ixgbe/ixgbe_dcb_82599.h | 29 +- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 10 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 +- drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c | 46 +-- drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h | 10 +- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 180 ++++++------ drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h | 52 ++-- .../net/ethernet/intel/ixgbe/ixgbe_sriov.c | 8 +- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 186 ++++++------ drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 62 ++-- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h | 18 +- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 270 +++++++++--------- 22 files changed, 738 insertions(+), 763 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index b6f0376e42f4..559b443c409f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -949,19 +949,19 @@ void ixgbe_alloc_rx_buffers(struct ixgbe_ring *, u16); void ixgbe_write_eitr(struct ixgbe_q_vector *); int ixgbe_poll(struct napi_struct *napi, int budget); int ethtool_ioctl(struct ifreq *ifr); -s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw); -s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl); -s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl); -s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, +int ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw); +int ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl); +int ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl); +int ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, union ixgbe_atr_hash_dword input, union ixgbe_atr_hash_dword common, u8 queue); -s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, +int ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, union ixgbe_atr_input *input_mask); -s32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, +int ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, union ixgbe_atr_input *input, u16 soft_id, u8 queue); -s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, +int ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, union ixgbe_atr_input *input, u16 soft_id); void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input, @@ -1059,7 +1059,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, u32 ixgbe_rss_indir_tbl_entries(struct ixgbe_adapter *adapter); void ixgbe_store_key(struct ixgbe_adapter *adapter); void ixgbe_store_reta(struct ixgbe_adapter *adapter); -s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, +int ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); #ifdef CONFIG_IXGBE_IPSEC void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 6835d5f18753..51baa176b99f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -15,10 +15,10 @@ #define IXGBE_82598_VFT_TBL_SIZE 128 #define IXGBE_82598_RX_PB_SIZE 512 -static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, +static int ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); -static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, u8 *eeprom_data); /** @@ -66,7 +66,7 @@ out: IXGBE_WRITE_REG(hw, IXGBE_GCR, gcr); } -static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) +static int ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; @@ -93,11 +93,11 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) * not known. Perform the SFP init if necessary. * **/ -static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) +static int ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val; + int ret_val; u16 list_offset, data_offset; /* Identify the PHY */ @@ -148,9 +148,9 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) * Then set pcie completion timeout * **/ -static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) +static int ixgbe_start_hw_82598(struct ixgbe_hw *hw) { - s32 ret_val; + int ret_val; ret_val = ixgbe_start_hw_generic(hw); if (ret_val) @@ -170,7 +170,7 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) * * Determines the link capabilities by reading the AUTOC register. **/ -static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, +static int ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { @@ -271,7 +271,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) * * Enable flow control according to the current settings. **/ -static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) +static int ixgbe_fc_enable_82598(struct ixgbe_hw *hw) { u32 fctrl_reg; u32 rmcs_reg; @@ -411,13 +411,13 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -static s32 ixgbe_start_mac_link_82598(struct ixgbe_hw *hw, +static int ixgbe_start_mac_link_82598(struct ixgbe_hw *hw, bool autoneg_wait_to_complete) { u32 autoc_reg; u32 links_reg; u32 i; - s32 status = 0; + int status = 0; /* Restart link */ autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -457,7 +457,7 @@ static s32 ixgbe_start_mac_link_82598(struct ixgbe_hw *hw, * Function indicates success when phy link is available. If phy is not ready * within 5 seconds of MAC indicating link, the function returns error. **/ -static s32 ixgbe_validate_link_ready(struct ixgbe_hw *hw) +static int ixgbe_validate_link_ready(struct ixgbe_hw *hw) { u32 timeout; u16 an_reg; @@ -493,7 +493,7 @@ static s32 ixgbe_validate_link_ready(struct ixgbe_hw *hw) * * Reads the links register to determine if link is up and the current speed **/ -static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, +static int ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete) { @@ -579,7 +579,7 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, +static int ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { @@ -624,11 +624,11 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, * * Sets the link speed in the AUTOC register in the MAC and restarts link. **/ -static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg_wait_to_complete) +static int ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg_wait_to_complete) { - s32 status; + int status; /* Setup the PHY according to input speed */ status = hw->phy.ops.setup_link_speed(hw, speed, @@ -647,10 +647,10 @@ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, * clears all interrupts, performing a PHY reset, and performing a link (MAC) * reset. **/ -static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) +static int ixgbe_reset_hw_82598(struct ixgbe_hw *hw) { - s32 status; - s32 phy_status = 0; + int status; + int phy_status = 0; u32 ctrl; u32 gheccr; u32 i; @@ -781,7 +781,7 @@ mac_reset_top: * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq set index **/ -static s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static int ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 rar_high; u32 rar_entries = hw->mac.num_rar_entries; @@ -805,7 +805,7 @@ static s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq clear index (not used in 82598, but elsewhere) **/ -static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static int ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 rar_high; u32 rar_entries = hw->mac.num_rar_entries; @@ -836,7 +836,7 @@ static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * * Turn on/off specified VLAN in the VLAN filter table. **/ -static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, +static int ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on, bool vlvf_bypass) { u32 regindex; @@ -881,7 +881,7 @@ static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, * * Clears the VLAN filter table, and the VMDq index associated with the filter **/ -static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw) +static int ixgbe_clear_vfta_82598(struct ixgbe_hw *hw) { u32 offset; u32 vlanbyte; @@ -905,7 +905,7 @@ static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw) * * Performs read operation to Atlas analog register specified. **/ -static s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) +static int ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) { u32 atlas_ctl; @@ -927,7 +927,7 @@ static s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) * * Performs write operation to Atlas analog register specified. **/ -static s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) +static int ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) { u32 atlas_ctl; @@ -948,10 +948,10 @@ static s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) * * Performs 8 byte read operation to SFP module's data over I2C interface. **/ -static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr, +static int ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr, u8 byte_offset, u8 *eeprom_data) { - s32 status = 0; + int status = 0; u16 sfp_addr = 0; u16 sfp_data = 0; u16 sfp_stat = 0; @@ -1019,7 +1019,7 @@ out: * * Performs 8 byte read operation to SFP module's EEPROM over I2C interface. **/ -static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, u8 *eeprom_data) { return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR, @@ -1034,8 +1034,8 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, * * Performs 8 byte read operation to SFP module's SFF-8472 data over I2C **/ -static s32 ixgbe_read_i2c_sff8472_82598(struct ixgbe_hw *hw, u8 byte_offset, - u8 *sff8472_data) +static int ixgbe_read_i2c_sff8472_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *sff8472_data) { return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR2, byte_offset, sff8472_data); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 339e106a5732..2ae659b123e4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -21,24 +21,24 @@ static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); static void ixgbe_set_hard_rate_select_speed(struct ixgbe_hw *, ixgbe_link_speed); -static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, +static int ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw); -static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, +static int ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, bool autoneg_wait_to_complete); -static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg_wait_to_complete); -static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, +static int ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg_wait_to_complete); +static int ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); -static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); -static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); +static int ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data); -static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data); -static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); +static int ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); bool ixgbe_mng_enabled(struct ixgbe_hw *hw) @@ -98,9 +98,9 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) } } -static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) +static int ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { - s32 ret_val; + int ret_val; u16 list_offset, data_offset, data_value; if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { @@ -173,10 +173,10 @@ setup_sfp_err: * prot_autoc_write_82599(). Note, that locked can only be true in cases * where this function doesn't return an error. **/ -static s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked, +static int prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked, u32 *reg_val) { - s32 ret_val; + int ret_val; *locked = false; /* If LESM is on then we need to hold the SW/FW semaphore. */ @@ -203,9 +203,9 @@ static s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked, * This part (82599) may need to hold a the SW/FW lock around all writes to * AUTOC. Likewise after a write we need to do a pipeline reset. **/ -static s32 prot_autoc_write_82599(struct ixgbe_hw *hw, u32 autoc, bool locked) +static int prot_autoc_write_82599(struct ixgbe_hw *hw, u32 autoc, bool locked) { - s32 ret_val = 0; + int ret_val = 0; /* Blocked by MNG FW so bail */ if (ixgbe_check_reset_blocked(hw)) @@ -237,7 +237,7 @@ out: return ret_val; } -static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) +static int ixgbe_get_invariants_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; @@ -263,11 +263,11 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) * not known. Perform the SFP init if necessary. * **/ -static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) +static int ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val; + int ret_val; u32 esdp; if (hw->device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP) { @@ -322,7 +322,7 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) * * Determines the link capabilities by reading the AUTOC register. **/ -static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, +static int ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { @@ -500,13 +500,13 @@ static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw) * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, - bool autoneg_wait_to_complete) +static int ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, + bool autoneg_wait_to_complete) { u32 autoc_reg; u32 links_reg; u32 i; - s32 status = 0; + int status = 0; bool got_lock = false; if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { @@ -657,11 +657,11 @@ ixgbe_set_hard_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed) * * Implements the Intel SmartSpeed algorithm. **/ -static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg_wait_to_complete) +static int ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg_wait_to_complete) { - s32 status = 0; + int status = 0; ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; s32 i, j; bool link_up = false; @@ -767,12 +767,12 @@ out: * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, +static int ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { bool autoneg = false; - s32 status; + int status; u32 pma_pmd_1g, link_mode, links_reg, i; u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; @@ -882,11 +882,11 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, * * Restarts link on PHY and MAC based on settings passed in. **/ -static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, +static int ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { - s32 status; + int status; /* Setup the PHY according to input speed */ status = hw->phy.ops.setup_link_speed(hw, speed, @@ -905,10 +905,10 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, * and clears all interrupts, perform a PHY reset, and perform a link (MAC) * reset. **/ -static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) +static int ixgbe_reset_hw_82599(struct ixgbe_hw *hw) { ixgbe_link_speed link_speed; - s32 status; + int status; u32 ctrl, i, autoc, autoc2; u32 curr_lms; bool link_up = false; @@ -1081,7 +1081,7 @@ mac_reset_top: * @hw: pointer to hardware structure * @fdircmd: current value of FDIRCMD register */ -static s32 ixgbe_fdir_check_cmd_complete(struct ixgbe_hw *hw, u32 *fdircmd) +static int ixgbe_fdir_check_cmd_complete(struct ixgbe_hw *hw, u32 *fdircmd) { int i; @@ -1099,12 +1099,12 @@ static s32 ixgbe_fdir_check_cmd_complete(struct ixgbe_hw *hw, u32 *fdircmd) * ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables. * @hw: pointer to hardware structure **/ -s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) +int ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) { int i; u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); u32 fdircmd; - s32 err; + int err; fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE; @@ -1212,7 +1212,7 @@ static void ixgbe_fdir_enable_82599(struct ixgbe_hw *hw, u32 fdirctrl) * @fdirctrl: value to write to flow director control register, initially * contains just the value of the Rx packet buffer allocation **/ -s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl) +int ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl) { /* * Continue setup of fdirctrl register bits: @@ -1236,7 +1236,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl) * @fdirctrl: value to write to flow director control register, initially * contains just the value of the Rx packet buffer allocation **/ -s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl) +int ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl) { /* * Continue setup of fdirctrl register bits: @@ -1359,7 +1359,7 @@ static u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input, * Note that the tunnel bit in input must not be set when the hardware * tunneling support does not exist. **/ -s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, +int ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, union ixgbe_atr_hash_dword input, union ixgbe_atr_hash_dword common, u8 queue) @@ -1515,7 +1515,7 @@ static u32 ixgbe_get_fdirtcpm_82599(union ixgbe_atr_input *input_mask) #define IXGBE_STORE_AS_BE16(_value) __swab16(ntohs((_value))) -s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, +int ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, union ixgbe_atr_input *input_mask) { /* mask IPv6 since it is currently not supported */ @@ -1627,12 +1627,12 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, return 0; } -s32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, +int ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, union ixgbe_atr_input *input, u16 soft_id, u8 queue) { u32 fdirport, fdirvlan, fdirhash, fdircmd; - s32 err; + int err; /* currently IPv6 is not supported, must be programmed with 0 */ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIPv6(0), @@ -1690,13 +1690,13 @@ s32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, return 0; } -s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, +int ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, union ixgbe_atr_input *input, u16 soft_id) { u32 fdirhash; u32 fdircmd; - s32 err; + int err; /* configure FDIRHASH register */ fdirhash = (__force u32)input->formatted.bkt_hash; @@ -1734,7 +1734,7 @@ s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, * * Performs read operation to Omer analog register specified. **/ -static s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) +static int ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) { u32 core_ctl; @@ -1756,7 +1756,7 @@ static s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) * * Performs write operation to Omer analog register specified. **/ -static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) +static int ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) { u32 core_ctl; @@ -1776,9 +1776,9 @@ static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) * and the generation start_hw function. * Then performs revision-specific operations, if any. **/ -static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) +static int ixgbe_start_hw_82599(struct ixgbe_hw *hw) { - s32 ret_val = 0; + int ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); if (ret_val) @@ -1802,9 +1802,9 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) * If PHY already detected, maintains current PHY type in hw struct, * otherwise executes the PHY detection routine. **/ -static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) +static int ixgbe_identify_phy_82599(struct ixgbe_hw *hw) { - s32 status; + int status; /* Detect PHY if not unknown - returns success if already detected. */ status = ixgbe_identify_phy_generic(hw); @@ -1835,7 +1835,7 @@ static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) * * Enables the Rx DMA unit for 82599 **/ -static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) +static int ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) { /* * Workaround for 82599 silicon errata when enabling the Rx datapath. @@ -1865,10 +1865,10 @@ static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) * Return: -EACCES if the FW is not present or if the FW version is * not supported. **/ -static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) +static int ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) { u16 fw_offset, fw_ptp_cfg_offset; - s32 status = -EACCES; + int status = -EACCES; u16 offset; u16 fw_version = 0; @@ -1917,7 +1917,7 @@ fw_version_err: static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) { u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; - s32 status; + int status; /* get the offset to the Firmware Module block */ status = hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); @@ -1956,7 +1956,7 @@ static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) * * Retrieves 16 bit word(s) read from EEPROM **/ -static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, +static int ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; @@ -1982,7 +1982,7 @@ static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, * * Reads a 16 bit word from the EEPROM **/ -static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, +static int ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, u16 offset, u16 *data) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; @@ -2006,9 +2006,9 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, * full pipeline reset. Note - We must hold the SW/FW semaphore before writing * to AUTOC, so this function assumes the semaphore is held. **/ -static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) +static int ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) { - s32 ret_val; + int ret_val; u32 anlp1_reg = 0; u32 i, autoc_reg, autoc2_reg; @@ -2061,11 +2061,11 @@ reset_pipeline_out: * Performs byte read operation to SFP module's EEPROM over I2C interface at * a specified device address. **/ -static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data) { u32 esdp; - s32 status; + int status; s32 timeout = 200; if (hw->phy.qsfp_shared_i2c_bus == true) { @@ -2115,11 +2115,11 @@ release_i2c_access: * Performs byte write operation to SFP module's EEPROM over I2C interface at * a specified device address. **/ -static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data) { u32 esdp; - s32 status; + int status; s32 timeout = 200; if (hw->phy.qsfp_shared_i2c_bus == true) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 2e6e0365154a..a8fee17cb653 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -10,10 +10,10 @@ #include "ixgbe_common.h" #include "ixgbe_phy.h" -static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw); -static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); +static int ixgbe_acquire_eeprom(struct ixgbe_hw *hw); +static int ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw); -static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw); +static int ixgbe_ready_eeprom(struct ixgbe_hw *hw); static void ixgbe_standby_eeprom(struct ixgbe_hw *hw); static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, u16 count); @@ -22,15 +22,15 @@ static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); static void ixgbe_release_eeprom(struct ixgbe_hw *hw); -static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); -static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); -static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, +static int ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); +static int ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); +static int ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data); -static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, - u16 words, u16 *data); -static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, +static int ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); +static int ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, u16 offset); -static s32 ixgbe_disable_pcie_primary(struct ixgbe_hw *hw); +static int ixgbe_disable_pcie_primary(struct ixgbe_hw *hw); /* Base table for registers values that change by MAC */ const u32 ixgbe_mvals_8259X[IXGBE_MVALS_IDX_LIMIT] = { @@ -111,9 +111,9 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) * * Called at init time to set up flow control. **/ -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw) +int ixgbe_setup_fc_generic(struct ixgbe_hw *hw) { - s32 ret_val = 0; + int ret_val = 0; u32 reg = 0, reg_bp = 0; u16 reg_cu = 0; bool locked = false; @@ -267,9 +267,9 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw) * table, VLAN filter table, calls routine to set up link and flow control * settings, and leaves transmit and receive units disabled and uninitialized **/ -s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) +int ixgbe_start_hw_generic(struct ixgbe_hw *hw) { - s32 ret_val; + int ret_val; u32 ctrl_ext; u16 device_caps; @@ -330,7 +330,7 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) * 82599 * X540 **/ -s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) +int ixgbe_start_hw_gen2(struct ixgbe_hw *hw) { u32 i; @@ -354,9 +354,9 @@ s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) * up link and flow control settings, and leaves transmit and receive units * disabled and uninitialized **/ -s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) +int ixgbe_init_hw_generic(struct ixgbe_hw *hw) { - s32 status; + int status; /* Reset the hardware */ status = hw->mac.ops.reset_hw(hw); @@ -380,7 +380,7 @@ s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) * Clears all hardware statistics counters by reading them from the hardware * Statistics counters are clear on read. **/ -s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw) +int ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw) { u16 i = 0; @@ -489,10 +489,10 @@ s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw) * * Reads the part number string from the EEPROM. **/ -s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, +int ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size) { - s32 ret_val; + int ret_val; u16 data; u16 pba_ptr; u16 offset; @@ -599,7 +599,7 @@ s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, * A reset of the adapter must be performed prior to calling this function * in order for the MAC address to have been loaded from the EEPROM into RAR0 **/ -s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr) +int ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr) { u32 rar_high; u32 rar_low; @@ -653,7 +653,7 @@ enum ixgbe_bus_speed ixgbe_convert_bus_speed(u16 link_status) * * Sets the PCI bus info (speed, width, type) within the ixgbe_hw structure **/ -s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw) +int ixgbe_get_bus_info_generic(struct ixgbe_hw *hw) { u16 link_status; @@ -709,7 +709,7 @@ void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw) * the shared code and drivers to determine if the adapter is in a stopped * state and should not touch the hardware. **/ -s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) +int ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) { u32 reg_val; u16 i; @@ -759,7 +759,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) * Store the index for the link active LED. This will be used to support * blinking the LED. **/ -s32 ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw) +int ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; u32 led_reg, led_mode; @@ -800,7 +800,7 @@ s32 ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw) * @hw: pointer to hardware structure * @index: led number to turn on **/ -s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index) +int ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index) { u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); @@ -821,7 +821,7 @@ s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index) * @hw: pointer to hardware structure * @index: led number to turn off **/ -s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index) +int ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index) { u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); @@ -844,7 +844,7 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index) * Initializes the EEPROM parameters ixgbe_eeprom_info within the * ixgbe_hw struct in order to set up EEPROM access. **/ -s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) +int ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; u32 eec; @@ -895,10 +895,10 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) * * Reads 16 bit word(s) from EEPROM through bit-bang method **/ -s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status; + int status; u16 i, count; hw->eeprom.ops.init_params(hw); @@ -942,10 +942,10 @@ s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, * If ixgbe_eeprom_update_checksum is not called after this function, the * EEPROM will most likely contain an invalid checksum. **/ -static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, +static int ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status; + int status; u16 word; u16 page_size; u16 i; @@ -1019,7 +1019,7 @@ static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, * If ixgbe_eeprom_update_checksum is not called after this function, the * EEPROM will most likely contain an invalid checksum. **/ -s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +int ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) { hw->eeprom.ops.init_params(hw); @@ -1038,10 +1038,10 @@ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) * * Reads 16 bit word(s) from EEPROM through bit-bang method **/ -s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status; + int status; u16 i, count; hw->eeprom.ops.init_params(hw); @@ -1077,10 +1077,10 @@ s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, * * Reads 16 bit word(s) from EEPROM through bit-bang method **/ -static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, +static int ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status; + int status; u16 word_in; u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; u16 i; @@ -1129,7 +1129,7 @@ static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, * * Reads 16 bit value from EEPROM through bit-bang method **/ -s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) { hw->eeprom.ops.init_params(hw); @@ -1149,11 +1149,11 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, * * Reads a 16 bit word(s) from the EEPROM using the EERD register. **/ -s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { u32 eerd; - s32 status; + int status; u32 i; hw->eeprom.ops.init_params(hw); @@ -1189,11 +1189,11 @@ s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, * This function is called only when we are writing a new large buffer * at given offset so the data would be overwritten anyway. **/ -static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, +static int ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, u16 offset) { u16 data[IXGBE_EEPROM_PAGE_SIZE_MAX]; - s32 status; + int status; u16 i; for (i = 0; i < IXGBE_EEPROM_PAGE_SIZE_MAX; i++) @@ -1229,7 +1229,7 @@ static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, * * Reads a 16 bit word from the EEPROM using the EERD register. **/ -s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) +int ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) { return ixgbe_read_eerd_buffer_generic(hw, offset, 1, data); } @@ -1243,11 +1243,11 @@ s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) * * Write a 16 bit word(s) to the EEPROM using the EEWR register. **/ -s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { u32 eewr; - s32 status; + int status; u16 i; hw->eeprom.ops.init_params(hw); @@ -1286,7 +1286,7 @@ s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, * * Write a 16 bit word to the EEPROM using the EEWR register. **/ -s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +int ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) { return ixgbe_write_eewr_buffer_generic(hw, offset, 1, &data); } @@ -1299,7 +1299,7 @@ s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) * Polls the status bit (bit 1) of the EERD or EEWR to determine when the * read or write is done respectively. **/ -static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) +static int ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) { u32 i; u32 reg; @@ -1325,7 +1325,7 @@ static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) * Prepares EEPROM for access using bit-bang method. This function should * be called before issuing a command to the EEPROM. **/ -static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) +static int ixgbe_acquire_eeprom(struct ixgbe_hw *hw) { u32 eec; u32 i; @@ -1371,7 +1371,7 @@ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) * * Sets the hardware semaphores so EEPROM access can occur for bit-bang method **/ -static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) +static int ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) { u32 timeout = 2000; u32 i; @@ -1462,7 +1462,7 @@ static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) * ixgbe_ready_eeprom - Polls for EEPROM ready * @hw: pointer to hardware structure **/ -static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) +static int ixgbe_ready_eeprom(struct ixgbe_hw *hw) { u16 i; u8 spi_stat_reg; @@ -1680,7 +1680,7 @@ static void ixgbe_release_eeprom(struct ixgbe_hw *hw) * ixgbe_calc_eeprom_checksum_generic - Calculates and returns the checksum * @hw: pointer to hardware structure **/ -s32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw) +int ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw) { u16 i; u16 j; @@ -1728,7 +1728,7 @@ s32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw) checksum = (u16)IXGBE_EEPROM_SUM - checksum; - return (s32)checksum; + return (int)checksum; } /** @@ -1739,10 +1739,10 @@ s32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw) * Performs checksum calculation and validates the EEPROM checksum. If the * caller does not need checksum_val, the value can be NULL. **/ -s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, +int ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, u16 *checksum_val) { - s32 status; + int status; u16 checksum; u16 read_checksum = 0; @@ -1786,9 +1786,9 @@ s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, * ixgbe_update_eeprom_checksum_generic - Updates the EEPROM checksum * @hw: pointer to hardware structure **/ -s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw) +int ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw) { - s32 status; + int status; u16 checksum; /* @@ -1823,7 +1823,7 @@ s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw) * * Puts an ethernet address into a receive address register. **/ -s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, +int ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr) { u32 rar_low, rar_high; @@ -1876,7 +1876,7 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, * * Clears an ethernet address from a receive address register. **/ -s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) +int ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) { u32 rar_high; u32 rar_entries = hw->mac.num_rar_entries; @@ -1917,7 +1917,7 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) * of the receive address registers. Clears the multicast table. Assumes * the receiver is in reset when the routine is called. **/ -s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) +int ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) { u32 i; u32 rar_entries = hw->mac.num_rar_entries; @@ -1980,7 +1980,7 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) * by the MO field of the MCSTCTRL. The MO field is set during initialization * to mc_filter_type. **/ -static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) +static int ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) { u32 vector = 0; @@ -2049,7 +2049,7 @@ static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr) * registers for the first multicast addresses, and hashes the rest into the * multicast table. **/ -s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, +int ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, struct net_device *netdev) { struct netdev_hw_addr *ha; @@ -2091,7 +2091,7 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, * * Enables multicast address in RAR and the use of the multicast hash table. **/ -s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw) +int ixgbe_enable_mc_generic(struct ixgbe_hw *hw) { struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; @@ -2108,7 +2108,7 @@ s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw) * * Disables multicast address in RAR and the use of the multicast hash table. **/ -s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) +int ixgbe_disable_mc_generic(struct ixgbe_hw *hw) { struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; @@ -2124,7 +2124,7 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) * * Enable flow control according to the current settings. **/ -s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) +int ixgbe_fc_enable_generic(struct ixgbe_hw *hw) { u32 mflcn_reg, fccfg_reg; u32 reg; @@ -2252,7 +2252,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) * Find the intersection between advertised settings and link partner's * advertised settings **/ -s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, +int ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) { if ((!(adv_reg)) || (!(lp_reg))) @@ -2294,10 +2294,10 @@ s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, * * Enable flow control according on 1 gig fiber. **/ -static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) +static int ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) { u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; - s32 ret_val; + int ret_val; /* * On multispeed fiber at 1g, bail out if @@ -2328,10 +2328,10 @@ static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) * * Enable flow control according to IEEE clause 37. **/ -static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) +static int ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) { u32 links2, anlp1_reg, autoc_reg, links; - s32 ret_val; + int ret_val; /* * On backplane, bail out if @@ -2367,7 +2367,7 @@ static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) * * Enable flow control according to IEEE clause 37. **/ -static s32 ixgbe_fc_autoneg_copper(struct ixgbe_hw *hw) +static int ixgbe_fc_autoneg_copper(struct ixgbe_hw *hw) { u16 technology_ability_reg = 0; u16 lp_technology_ability_reg = 0; @@ -2395,7 +2395,7 @@ static s32 ixgbe_fc_autoneg_copper(struct ixgbe_hw *hw) void ixgbe_fc_autoneg(struct ixgbe_hw *hw) { ixgbe_link_speed speed; - s32 ret_val = -EIO; + int ret_val = -EIO; bool link_up; /* @@ -2501,7 +2501,7 @@ static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw) * bit hasn't caused the primary requests to be disabled, else 0 * is returned signifying primary requests disabled. **/ -static s32 ixgbe_disable_pcie_primary(struct ixgbe_hw *hw) +static int ixgbe_disable_pcie_primary(struct ixgbe_hw *hw) { u32 i, poll; u16 value; @@ -2573,7 +2573,7 @@ gio_disable_fail: * Acquires the SWFW semaphore through the GSSR register for the specified * function (CSR, PHY0, PHY1, EEPROM, Flash) **/ -s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u32 mask) +int ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u32 mask) { u32 gssr = 0; u32 swmask = mask; @@ -2641,7 +2641,7 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u32 mask) * * The default case requires no protection so just to the register read. **/ -s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *locked, u32 *reg_val) +int prot_autoc_read_generic(struct ixgbe_hw *hw, bool *locked, u32 *reg_val) { *locked = false; *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -2655,7 +2655,7 @@ s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *locked, u32 *reg_val) * @locked: bool to indicate whether the SW/FW lock was already taken by * previous read. **/ -s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked) +int prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked) { IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_val); return 0; @@ -2668,7 +2668,7 @@ s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked) * Stops the receive data path and waits for the HW to internally * empty the Rx security block. **/ -s32 ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw) +int ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw) { #define IXGBE_MAX_SECRX_POLL 40 int i; @@ -2700,7 +2700,7 @@ s32 ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw) * * Enables the receive data path **/ -s32 ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw) +int ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw) { u32 secrxreg; @@ -2719,7 +2719,7 @@ s32 ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw) * * Enables the Rx DMA unit **/ -s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval) +int ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval) { if (regval & IXGBE_RXCTRL_RXEN) hw->mac.ops.enable_rx(hw); @@ -2734,14 +2734,14 @@ s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval) * @hw: pointer to hardware structure * @index: led number to blink **/ -s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) +int ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) { ixgbe_link_speed speed = 0; bool link_up = false; u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); bool locked = false; - s32 ret_val; + int ret_val; if (index > 3) return -EINVAL; @@ -2782,12 +2782,12 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) * @hw: pointer to hardware structure * @index: led number to stop blinking **/ -s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) +int ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) { u32 autoc_reg = 0; u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); bool locked = false; - s32 ret_val; + int ret_val; if (index > 3) return -EINVAL; @@ -2821,10 +2821,10 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) * pointer, and returns the value at that location. This is used in both * get and set mac_addr routines. **/ -static s32 ixgbe_get_san_mac_addr_offset(struct ixgbe_hw *hw, - u16 *san_mac_offset) +static int ixgbe_get_san_mac_addr_offset(struct ixgbe_hw *hw, + u16 *san_mac_offset) { - s32 ret_val; + int ret_val; /* * First read the EEPROM pointer to see if the MAC addresses are @@ -2849,11 +2849,11 @@ static s32 ixgbe_get_san_mac_addr_offset(struct ixgbe_hw *hw, * set_lan_id() is called by identify_sfp(), but this cannot be relied * upon for non-SFP connections, so we must call it here. **/ -s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) +int ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) { u16 san_mac_data, san_mac_offset; u8 i; - s32 ret_val; + int ret_val; /* * First read the EEPROM pointer to see if the MAC addresses are @@ -2942,7 +2942,7 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) * @rar: receive address register index to disassociate * @vmdq: VMDq pool index to remove from the rar **/ -s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +int ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 mpsar_lo, mpsar_hi; u32 rar_entries = hw->mac.num_rar_entries; @@ -2993,7 +2993,7 @@ s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq pool index **/ -s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +int ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 mpsar; u32 rar_entries = hw->mac.num_rar_entries; @@ -3026,7 +3026,7 @@ s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * VFs advertized and not 0. * MPSAR table needs to be updated for SAN_MAC RAR [hw->mac.san_mac_rar_index] **/ -s32 ixgbe_set_vmdq_san_mac_generic(struct ixgbe_hw *hw, u32 vmdq) +int ixgbe_set_vmdq_san_mac_generic(struct ixgbe_hw *hw, u32 vmdq) { u32 rar = hw->mac.san_mac_rar_index; @@ -3045,7 +3045,7 @@ s32 ixgbe_set_vmdq_san_mac_generic(struct ixgbe_hw *hw, u32 vmdq) * ixgbe_init_uta_tables_generic - Initialize the Unicast Table Array * @hw: pointer to hardware structure **/ -s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw) +int ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw) { int i; @@ -3065,9 +3065,9 @@ s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw) * return the VLVF index where this VLAN id should be placed * **/ -static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass) +static int ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass) { - s32 regindex, first_empty_slot; + int regindex, first_empty_slot; u32 bits; /* short cut the special case */ @@ -3115,11 +3115,11 @@ static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass) * * Turn on/off specified VLAN in the VLAN filter table. **/ -s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, +int ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on, bool vlvf_bypass) { u32 regidx, vfta_delta, vfta, bits; - s32 vlvf_index; + int vlvf_index; if ((vlan > 4095) || (vind > 63)) return -EINVAL; @@ -3226,7 +3226,7 @@ vfta_update: * * Clears the VLAN filter table, and the VMDq index associated with the filter **/ -s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw) +int ixgbe_clear_vfta_generic(struct ixgbe_hw *hw) { u32 offset; @@ -3276,7 +3276,7 @@ static bool ixgbe_need_crosstalk_fix(struct ixgbe_hw *hw) * * Reads the links register to determine if link is up and the current speed **/ -s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, +int ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete) { bool crosstalk_fix_active = ixgbe_need_crosstalk_fix(hw); @@ -3396,8 +3396,8 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, * This function will read the EEPROM from the alternative SAN MAC address * block to check the support for the alternative WWNN/WWPN prefix support. **/ -s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, - u16 *wwpn_prefix) +int ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, + u16 *wwpn_prefix) { u16 offset, caps; u16 alt_san_mac_blk_offset; @@ -3494,7 +3494,7 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) * This function will read the EEPROM location for the device capabilities, * and return the word through device_caps. **/ -s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps) +int ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps) { hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); @@ -3604,7 +3604,7 @@ u8 ixgbe_calculate_checksum(u8 *buffer, u32 length) * This function assumes that the IXGBE_GSSR_SW_MNG_SM semaphore is held * by the caller. **/ -s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length, +int ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length, u32 timeout) { u32 hicr, i, fwsts; @@ -3676,7 +3676,7 @@ s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length, * Communicates with the manageability block. On success return 0 * else return -EIO or -EINVAL. **/ -s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer, +int ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer, u32 length, u32 timeout, bool return_data) { @@ -3684,7 +3684,7 @@ s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer, struct ixgbe_hic_hdr *hdr = buffer; u32 *u32arr = buffer; u16 buf_len, dword_len; - s32 status; + int status; u32 bi; if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { @@ -3753,13 +3753,13 @@ rel_out: * else returns -EBUSY when encountering an error acquiring * semaphore or -EIO when command fails. **/ -s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, +int ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build, u8 sub, __always_unused u16 len, __always_unused const char *driver_ver) { struct ixgbe_hic_drv_info fw_cmd; int i; - s32 ret_val; + int ret_val; fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; @@ -3875,10 +3875,10 @@ static const u8 ixgbe_emc_therm_limit[4] = { * * Returns error code. **/ -static s32 ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg, +static int ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg, u16 *ets_offset) { - s32 status; + int status; status = hw->eeprom.ops.read(hw, IXGBE_ETS_CFG, ets_offset); if (status) @@ -3903,9 +3903,9 @@ static s32 ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg, * * Returns the thermal sensor data structure **/ -s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) +int ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) { - s32 status; + int status; u16 ets_offset; u16 ets_cfg; u16 ets_sensor; @@ -3959,9 +3959,9 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) * Inits the thermal sensor thresholds according to the NVM map * and save off the threshold and location values into mac.thermal_sensor_data **/ -s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) +int ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) { - s32 status; + int status; u16 ets_offset; u16 ets_cfg; u16 ets_sensor; @@ -4192,13 +4192,13 @@ bool ixgbe_mng_present(struct ixgbe_hw *hw) * * Set the link speed in the MAC and/or PHY register and restarts link. */ -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, +int ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN; - s32 status = 0; + int status = 0; u32 speedcnt = 0; u32 i = 0; bool autoneg, link_up = false; @@ -4340,7 +4340,7 @@ out: void ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed) { - s32 status; + int status; u8 rs, eeprom_data; switch (speed) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index 34761e691d52..6493abf189de 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -8,89 +8,89 @@ #include "ixgbe.h" u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); -s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw); -s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw); -s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, +int ixgbe_init_hw_generic(struct ixgbe_hw *hw); +int ixgbe_start_hw_generic(struct ixgbe_hw *hw); +int ixgbe_start_hw_gen2(struct ixgbe_hw *hw); +int ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw); +int ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size); -s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr); +int ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr); enum ixgbe_bus_width ixgbe_convert_bus_width(u16 link_status); enum ixgbe_bus_speed ixgbe_convert_bus_speed(u16 link_status); -s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw); +int ixgbe_get_bus_info_generic(struct ixgbe_hw *hw); void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw); -s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw); +int ixgbe_stop_adapter_generic(struct ixgbe_hw *hw); -s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw); +int ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index); +int ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); +int ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw); -s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); -s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); -s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); +int ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); +int ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data); -s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); -s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +int ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data); -s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data); -s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data); +int ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data); -s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); -s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, +int ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data); -s32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); -s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, +int ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); +int ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, u16 *checksum_val); -s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); +int ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); -s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, +int ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr); -s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw); -s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, +int ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index); +int ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw); +int ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, struct net_device *netdev); -s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); -s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); -s32 ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw); -s32 ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw); -s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); -s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw); -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *); +int ixgbe_enable_mc_generic(struct ixgbe_hw *hw); +int ixgbe_disable_mc_generic(struct ixgbe_hw *hw); +int ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw); +int ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw); +int ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); +int ixgbe_fc_enable_generic(struct ixgbe_hw *hw); +int ixgbe_setup_fc_generic(struct ixgbe_hw *); bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw); void ixgbe_fc_autoneg(struct ixgbe_hw *hw); -s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u32 mask); +int ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u32 mask); void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u32 mask); -s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr); -s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vmdq_san_mac_generic(struct ixgbe_hw *hw, u32 vmdq); -s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw); -s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, +int ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr); +int ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq); +int ixgbe_set_vmdq_san_mac_generic(struct ixgbe_hw *hw, u32 vmdq); +int ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq); +int ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw); +int ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on, bool vlvf_bypass); -s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw); -s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, +int ixgbe_clear_vfta_generic(struct ixgbe_hw *hw); +int ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete); -s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, +int ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, u16 *wwpn_prefix); -s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *, u32 *reg_val); -s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked); +int prot_autoc_read_generic(struct ixgbe_hw *hw, bool *, u32 *reg_val); +int prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked); -s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index); +int ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index); +int ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index); void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); -s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps); -s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, +int ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps); +int ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build, u8 ver, u16 len, const char *str); u8 ixgbe_calculate_checksum(u8 *buffer, u32 length); -s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *, u32 length, +int ixgbe_host_interface_command(struct ixgbe_hw *hw, void *, u32 length, u32 timeout, bool return_data); -s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 len, u32 timeout); -s32 ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity, +int ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 len, u32 timeout); +int ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity, u32 (*data)[FW_PHY_ACT_DATA_COUNT]); void ixgbe_clear_tx_pending(struct ixgbe_hw *hw); bool ixgbe_mng_present(struct ixgbe_hw *hw); @@ -111,8 +111,8 @@ extern const u32 ixgbe_mvals_8259X[IXGBE_MVALS_IDX_LIMIT]; #define IXGBE_EMC_DIODE3_DATA 0x2A #define IXGBE_EMC_DIODE3_THERM_LIMIT 0x30 -s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw); -s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw); +int ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw); +int ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw); void ixgbe_get_etk_id(struct ixgbe_hw *hw, struct ixgbe_nvm_version *nvm_ver); void ixgbe_get_oem_prod_version(struct ixgbe_hw *hw, @@ -121,7 +121,7 @@ void ixgbe_get_orom_version(struct ixgbe_hw *hw, struct ixgbe_nvm_version *nvm_ver); void ixgbe_disable_rx_generic(struct ixgbe_hw *hw); void ixgbe_enable_rx_generic(struct ixgbe_hw *hw); -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, +int ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); void ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c index d26cea5b43bd..502666f28124 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c @@ -18,7 +18,7 @@ * @max: max credits by traffic class * @max_frame: maximum frame size */ -static s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, +static int ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame) { int min_percent = 100; @@ -59,7 +59,7 @@ static s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, * It should be called only after the rules are checked by * ixgbe_dcb_check_config(). */ -s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *hw, +int ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *hw, struct ixgbe_dcb_config *dcb_config, int max_frame, u8 direction) { @@ -247,7 +247,7 @@ void ixgbe_dcb_unpack_map(struct ixgbe_dcb_config *cfg, int direction, u8 *map) * * Configure dcb settings and enable dcb mode. */ -s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, +int ixgbe_dcb_hw_config(struct ixgbe_hw *hw, struct ixgbe_dcb_config *dcb_config) { u8 pfc_en; @@ -283,7 +283,7 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, } /* Helper routines to abstract HW specifics from DCB netlink ops */ -s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) +int ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) { switch (hw->mac.type) { case ixgbe_mac_82598EB: @@ -300,7 +300,7 @@ s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) return -EINVAL; } -s32 ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max_frame) +int ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max_frame) { __u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS]; __u8 prio_type[IEEE_8021QAZ_MAX_TCS]; @@ -333,7 +333,7 @@ s32 ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max_frame) bwg_id, prio_type, ets->prio_tc); } -s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, +int ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type, u8 *prio_tc) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h index 60cd5863bf5e..91788e4c4e19 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h @@ -124,15 +124,15 @@ void ixgbe_dcb_unpack_map(struct ixgbe_dcb_config *, int, u8 *); u8 ixgbe_dcb_get_tc_from_up(struct ixgbe_dcb_config *, int, u8); /* DCB credits calculation */ -s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *, +int ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *, struct ixgbe_dcb_config *, int, u8); /* DCB hw initialization */ -s32 ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max); -s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, u16 *refill, u16 *max, +int ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max); +int ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type, u8 *tc_prio); -s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *tc_prio); -s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); +int ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *tc_prio); +int ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); void ixgbe_dcb_read_rtrup2tc(struct ixgbe_hw *hw, u8 *map); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c index 379ae747cdce..185c3e5f9837 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c @@ -15,10 +15,8 @@ * * Configure Rx Data Arbiter and credits for each traffic class. */ -s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *prio_type) +int ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *prio_type) { u32 reg = 0; u32 credit_refill = 0; @@ -75,11 +73,8 @@ s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, * * Configure Tx Descriptor Arbiter and credits for each traffic class. */ -s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *bwg_id, - u8 *prio_type) +int ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type) { u32 reg, max_credits; u8 i; @@ -124,11 +119,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, * * Configure Tx Data Arbiter and credits for each traffic class. */ -s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *bwg_id, - u8 *prio_type) +int ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type) { u32 reg; u8 i; @@ -171,7 +163,7 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, * * Configure Priority Flow Control for each traffic class. */ -s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) +int ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) { u32 fcrtl, reg; u8 i; @@ -224,7 +216,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) * Configure queue statistics registers, all queues belonging to same traffic * class uses a single set of queue statistics counters. */ -static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) +static int ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) { u32 reg = 0; u8 i = 0; @@ -260,7 +252,7 @@ static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) * * Configure dcb settings and enable dcb mode. */ -s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, +int ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type) { ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, prio_type); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h index fdca41abb44c..5bf3f13c6953 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h @@ -46,27 +46,19 @@ /* DCB hardware-specific driver APIs */ /* DCB PFC functions */ -s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, u8 pfc_en); +int ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, u8 pfc_en); /* DCB hw initialization */ -s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *prio_type); +int ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *prio_type); -s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *bwg_id, - u8 *prio_type); +int ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type); -s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *bwg_id, - u8 *prio_type); +int ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type); -s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, +int ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type); #endif /* _DCB_82598_CONFIG_H */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c index 7948849840a5..c61bd9059541 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c @@ -17,7 +17,7 @@ * * Configure Rx Packet Arbiter and credits for each traffic class. */ -s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, +int ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, u16 *max, u8 *bwg_id, @@ -76,7 +76,7 @@ s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, * * Configure Tx Descriptor Arbiter and credits for each traffic class. */ -s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, +int ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, u16 *max, u8 *bwg_id, @@ -128,7 +128,7 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, * * Configure Tx Packet Arbiter and credits for each traffic class. */ -s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, +int ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, u16 *max, u8 *bwg_id, @@ -187,7 +187,7 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, * * Configure Priority Flow Control (PFC) for each traffic class. */ -s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) +int ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) { u32 i, j, fcrtl, reg; u8 max_tc = 0; @@ -272,7 +272,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) * Configure queue statistics registers, all queues belonging to same traffic * class uses a single set of queue statistics counters. */ -static s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw) +static int ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw) { u32 reg = 0; u8 i = 0; @@ -330,7 +330,7 @@ static s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw) * * Configure dcb settings and enable dcb mode. */ -s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, +int ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type, u8 *prio_tc) { ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwg_id, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h index c6f084883cab..f6e5a87c03e3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h @@ -70,30 +70,21 @@ /* DCB hardware-specific driver APIs */ /* DCB PFC functions */ -s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc); +int ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc); /* DCB hw initialization */ -s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *bwg_id, - u8 *prio_type, - u8 *prio_tc); +int ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type, + u8 *prio_tc); -s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *bwg_id, - u8 *prio_type); +int ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type); -s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, - u16 *refill, - u16 *max, - u8 *bwg_id, - u8 *prio_type, - u8 *prio_tc); +int ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type, + u8 *prio_tc); -s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, +int ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type, u8 *prio_tc); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index ca69a8221793..6058daca1876 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -459,7 +459,7 @@ static int ixgbe_set_link_ksettings(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 advertised, old; - s32 err = 0; + int err = 0; if ((hw->phy.media_type == ixgbe_media_type_copper) || (hw->phy.multispeed_fiber)) { @@ -3326,7 +3326,7 @@ static int ixgbe_get_module_info(struct net_device *dev, { struct ixgbe_adapter *adapter = netdev_priv(dev); struct ixgbe_hw *hw = &adapter->hw; - s32 status; + int status; u8 sff8472_rev, addr_mode; bool page_swap = false; @@ -3372,7 +3372,7 @@ static int ixgbe_get_module_eeprom(struct net_device *dev, { struct ixgbe_adapter *adapter = netdev_priv(dev); struct ixgbe_hw *hw = &adapter->hw; - s32 status = -EFAULT; + int status = -EFAULT; u8 databyte = 0xFF; int i = 0; @@ -3429,7 +3429,7 @@ ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata) { u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; struct ixgbe_hw *hw = &adapter->hw; - s32 rc; + int rc; u16 i; rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_UD_2, &info); @@ -3481,7 +3481,7 @@ static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_keee *edata) struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; struct ethtool_keee eee_data; - s32 ret_val; + int ret_val; if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE)) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index bd541527c8c7..e23c3614fb10 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -205,7 +205,7 @@ static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter, return 0; } -static s32 ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter) +static int ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; u16 link_status = 0; @@ -7809,7 +7809,7 @@ static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter) static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; - s32 err; + int err; /* not searching for SFP so there is nothing to do here */ if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) && diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c index fe7ef5773369..d67d77e5dacc 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c @@ -15,7 +15,7 @@ * * returns SUCCESS if it successfully read message from buffer **/ -s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) +int ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; @@ -38,7 +38,7 @@ s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) * * returns SUCCESS if it successfully copied message into the buffer **/ -s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) +int ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; @@ -58,7 +58,7 @@ s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) * * returns SUCCESS if the Status bit was found or else ERR_MBX **/ -s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) +int ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; @@ -75,7 +75,7 @@ s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) * * returns SUCCESS if the Status bit was found or else ERR_MBX **/ -s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) +int ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; @@ -92,7 +92,7 @@ s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) * * returns SUCCESS if the Status bit was found or else ERR_MBX **/ -s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) +int ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; @@ -109,7 +109,7 @@ s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) * * returns SUCCESS if it successfully received a message notification **/ -static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) +static int ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; int countdown = mbx->timeout; @@ -134,7 +134,7 @@ static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) * * returns SUCCESS if it successfully received a message acknowledgement **/ -static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) +static int ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; int countdown = mbx->timeout; @@ -162,11 +162,11 @@ static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) * returns SUCCESS if it successfully received a message notification and * copied it into the receive buffer. **/ -static s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, +static int ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val; + int ret_val; if (!mbx->ops) return -EIO; @@ -189,11 +189,11 @@ static s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, * returns SUCCESS if it successfully copied message into the buffer and * received an ack to that message within delay * timeout period **/ -static s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, - u16 mbx_id) +static int ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val; + int ret_val; /* exit if either we can't write or there isn't a defined timeout */ if (!mbx->ops || !mbx->timeout) @@ -208,7 +208,7 @@ static s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, return ixgbe_poll_for_ack(hw, mbx_id); } -static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) +static int ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) { u32 mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index)); @@ -227,9 +227,9 @@ static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) * * returns SUCCESS if the VF has set the Status bit or else ERR_MBX **/ -static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) +static int ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) { - s32 index = IXGBE_MBVFICR_INDEX(vf_number); + int index = IXGBE_MBVFICR_INDEX(vf_number); u32 vf_bit = vf_number % 16; if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFREQ_VF1 << vf_bit, @@ -248,9 +248,9 @@ static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) * * returns SUCCESS if the VF has set the Status bit or else ERR_MBX **/ -static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) +static int ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) { - s32 index = IXGBE_MBVFICR_INDEX(vf_number); + int index = IXGBE_MBVFICR_INDEX(vf_number); u32 vf_bit = vf_number % 16; if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFACK_VF1 << vf_bit, @@ -269,7 +269,7 @@ static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) * * returns SUCCESS if the VF has set the Status bit or else ERR_MBX **/ -static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) +static int ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) { u32 reg_offset = (vf_number < 32) ? 0 : 1; u32 vf_shift = vf_number % 32; @@ -305,7 +305,7 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) * * return SUCCESS if we obtained the mailbox lock **/ -static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) +static int ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) { u32 p2v_mailbox; @@ -329,10 +329,10 @@ static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) * * returns SUCCESS if it successfully copied message into the buffer **/ -static s32 ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, +static int ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 vf_number) { - s32 ret_val; + int ret_val; u16 i; /* lock the mailbox to prevent pf/vf race condition */ @@ -368,10 +368,10 @@ static s32 ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, * memory buffer. The presumption is that the caller knows that there was * a message due to a VF request so no polling for message is needed. **/ -static s32 ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, +static int ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 vf_number) { - s32 ret_val; + int ret_val; u16 i; /* lock the mailbox to prevent pf/vf race condition */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h index 6434c190e7a4..bd205306934b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h @@ -96,11 +96,11 @@ enum ixgbe_pfvf_api_rev { #define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */ #define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */ -s32 ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16); -s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16); -s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16); -s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16); -s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16); +int ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16); +int ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16); +int ixgbe_check_for_msg(struct ixgbe_hw *, u16); +int ixgbe_check_for_ack(struct ixgbe_hw *, u16); +int ixgbe_check_for_rst(struct ixgbe_hw *, u16); #ifdef CONFIG_PCI_IOV void ixgbe_init_mbx_params_pf(struct ixgbe_hw *); #endif /* CONFIG_PCI_IOV */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index f28140a05f09..471c1446267b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -11,19 +11,19 @@ static void ixgbe_i2c_start(struct ixgbe_hw *hw); static void ixgbe_i2c_stop(struct ixgbe_hw *hw); -static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data); -static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data); -static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw); -static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data); -static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data); +static int ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data); +static int ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data); +static int ixgbe_get_i2c_ack(struct ixgbe_hw *hw); +static int ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data); +static int ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data); static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); -static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); +static int ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl); static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw); static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); -static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); -static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw); +static int ixgbe_get_phy_id(struct ixgbe_hw *hw); +static int ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw); /** * ixgbe_out_i2c_byte_ack - Send I2C byte with ack @@ -32,9 +32,9 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw); * * Returns an error code on error. **/ -static s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte) +static int ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte) { - s32 status; + int status; status = ixgbe_clock_out_i2c_byte(hw, byte); if (status) @@ -49,9 +49,9 @@ static s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte) * * Returns an error code on error. **/ -static s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte) +static int ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte) { - s32 status; + int status; status = ixgbe_clock_in_i2c_byte(hw, byte); if (status) @@ -85,7 +85,7 @@ static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2) * * Returns an error code on error. */ -s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, +int ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val, bool lock) { u32 swfw_mask = hw->phy.phy_semaphore_mask; @@ -163,7 +163,7 @@ fail: * * Returns an error code on error. */ -s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, +int ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val, bool lock) { u32 swfw_mask = hw->phy.phy_semaphore_mask; @@ -260,7 +260,7 @@ static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr) * * Determines the physical layer module found on the current adapter. **/ -s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) +int ixgbe_identify_phy_generic(struct ixgbe_hw *hw) { u32 status = -EFAULT; u32 phy_addr; @@ -332,9 +332,9 @@ bool ixgbe_check_reset_blocked(struct ixgbe_hw *hw) * @hw: pointer to hardware structure * **/ -static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) +static int ixgbe_get_phy_id(struct ixgbe_hw *hw) { - s32 status; + int status; u16 phy_id_high = 0; u16 phy_id_low = 0; @@ -394,11 +394,11 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) * ixgbe_reset_phy_generic - Performs a PHY reset * @hw: pointer to hardware structure **/ -s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) +int ixgbe_reset_phy_generic(struct ixgbe_hw *hw) { u32 i; u16 ctrl = 0; - s32 status = 0; + int status = 0; if (hw->phy.type == ixgbe_phy_unknown) status = ixgbe_identify_phy_generic(hw); @@ -470,8 +470,8 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) * * Reads a value from a specified PHY register without the SWFW lock **/ -s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, - u16 *phy_data) +int ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, + u16 *phy_data) { u32 i, data, command; @@ -546,10 +546,10 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, * @device_type: 5 bit device type * @phy_data: Pointer to read data from PHY register **/ -s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, +int ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data) { - s32 status; + int status; u32 gssr = hw->phy.phy_semaphore_mask; if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { @@ -571,8 +571,8 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, * @device_type: 5 bit device type * @phy_data: Data to write to the PHY register **/ -s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u16 phy_data) +int ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, + u16 phy_data) { u32 i, command; @@ -644,10 +644,10 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, * @device_type: 5 bit device type * @phy_data: Data to write to the PHY register **/ -s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, +int ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data) { - s32 status; + int status; u32 gssr = hw->phy.phy_semaphore_mask; if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { @@ -668,7 +668,7 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, * @hw: pointer to hardware structure * @cmd: command register value to write **/ -static s32 ixgbe_msca_cmd(struct ixgbe_hw *hw, u32 cmd) +static int ixgbe_msca_cmd(struct ixgbe_hw *hw, u32 cmd) { IXGBE_WRITE_REG(hw, IXGBE_MSCA, cmd); @@ -684,11 +684,11 @@ static s32 ixgbe_msca_cmd(struct ixgbe_hw *hw, u32 cmd) * @regnum: register number * @gssr: semaphore flags to acquire **/ -static s32 ixgbe_mii_bus_read_generic_c22(struct ixgbe_hw *hw, int addr, +static int ixgbe_mii_bus_read_generic_c22(struct ixgbe_hw *hw, int addr, int regnum, u32 gssr) { u32 hwaddr, cmd; - s32 data; + int data; if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) return -EBUSY; @@ -718,11 +718,11 @@ mii_bus_read_done: * @regnum: register number * @gssr: semaphore flags to acquire **/ -static s32 ixgbe_mii_bus_read_generic_c45(struct ixgbe_hw *hw, int addr, +static int ixgbe_mii_bus_read_generic_c45(struct ixgbe_hw *hw, int addr, int devad, int regnum, u32 gssr) { u32 hwaddr, cmd; - s32 data; + int data; if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) return -EBUSY; @@ -756,11 +756,11 @@ mii_bus_read_done: * @val: value to write * @gssr: semaphore flags to acquire **/ -static s32 ixgbe_mii_bus_write_generic_c22(struct ixgbe_hw *hw, int addr, +static int ixgbe_mii_bus_write_generic_c22(struct ixgbe_hw *hw, int addr, int regnum, u16 val, u32 gssr) { u32 hwaddr, cmd; - s32 err; + int err; if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) return -EBUSY; @@ -787,12 +787,12 @@ static s32 ixgbe_mii_bus_write_generic_c22(struct ixgbe_hw *hw, int addr, * @val: value to write * @gssr: semaphore flags to acquire **/ -static s32 ixgbe_mii_bus_write_generic_c45(struct ixgbe_hw *hw, int addr, +static int ixgbe_mii_bus_write_generic_c45(struct ixgbe_hw *hw, int addr, int devad, int regnum, u16 val, u32 gssr) { u32 hwaddr, cmd; - s32 err; + int err; if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) return -EBUSY; @@ -821,7 +821,7 @@ mii_bus_write_done: * @addr: address * @regnum: register number **/ -static s32 ixgbe_mii_bus_read_c22(struct mii_bus *bus, int addr, int regnum) +static int ixgbe_mii_bus_read_c22(struct mii_bus *bus, int addr, int regnum) { struct ixgbe_adapter *adapter = bus->priv; struct ixgbe_hw *hw = &adapter->hw; @@ -837,7 +837,7 @@ static s32 ixgbe_mii_bus_read_c22(struct mii_bus *bus, int addr, int regnum) * @addr: address * @regnum: register number **/ -static s32 ixgbe_mii_bus_read_c45(struct mii_bus *bus, int devad, int addr, +static int ixgbe_mii_bus_read_c45(struct mii_bus *bus, int devad, int addr, int regnum) { struct ixgbe_adapter *adapter = bus->priv; @@ -854,7 +854,7 @@ static s32 ixgbe_mii_bus_read_c45(struct mii_bus *bus, int devad, int addr, * @regnum: register number * @val: value to write **/ -static s32 ixgbe_mii_bus_write_c22(struct mii_bus *bus, int addr, int regnum, +static int ixgbe_mii_bus_write_c22(struct mii_bus *bus, int addr, int regnum, u16 val) { struct ixgbe_adapter *adapter = bus->priv; @@ -872,7 +872,7 @@ static s32 ixgbe_mii_bus_write_c22(struct mii_bus *bus, int addr, int regnum, * @regnum: register number * @val: value to write **/ -static s32 ixgbe_mii_bus_write_c45(struct mii_bus *bus, int addr, int devad, +static int ixgbe_mii_bus_write_c45(struct mii_bus *bus, int addr, int devad, int regnum, u16 val) { struct ixgbe_adapter *adapter = bus->priv; @@ -889,7 +889,7 @@ static s32 ixgbe_mii_bus_write_c45(struct mii_bus *bus, int addr, int devad, * @addr: address * @regnum: register number **/ -static s32 ixgbe_x550em_a_mii_bus_read_c22(struct mii_bus *bus, int addr, +static int ixgbe_x550em_a_mii_bus_read_c22(struct mii_bus *bus, int addr, int regnum) { struct ixgbe_adapter *adapter = bus->priv; @@ -907,7 +907,7 @@ static s32 ixgbe_x550em_a_mii_bus_read_c22(struct mii_bus *bus, int addr, * @devad: device address to read * @regnum: register number **/ -static s32 ixgbe_x550em_a_mii_bus_read_c45(struct mii_bus *bus, int addr, +static int ixgbe_x550em_a_mii_bus_read_c45(struct mii_bus *bus, int addr, int devad, int regnum) { struct ixgbe_adapter *adapter = bus->priv; @@ -925,7 +925,7 @@ static s32 ixgbe_x550em_a_mii_bus_read_c45(struct mii_bus *bus, int addr, * @regnum: register number * @val: value to write **/ -static s32 ixgbe_x550em_a_mii_bus_write_c22(struct mii_bus *bus, int addr, +static int ixgbe_x550em_a_mii_bus_write_c22(struct mii_bus *bus, int addr, int regnum, u16 val) { struct ixgbe_adapter *adapter = bus->priv; @@ -944,7 +944,7 @@ static s32 ixgbe_x550em_a_mii_bus_write_c22(struct mii_bus *bus, int addr, * @regnum: register number * @val: value to write **/ -static s32 ixgbe_x550em_a_mii_bus_write_c45(struct mii_bus *bus, int addr, +static int ixgbe_x550em_a_mii_bus_write_c45(struct mii_bus *bus, int addr, int devad, int regnum, u16 val) { struct ixgbe_adapter *adapter = bus->priv; @@ -1023,13 +1023,13 @@ out: * * ixgbe_mii_bus_init initializes a mii_bus structure in adapter **/ -s32 ixgbe_mii_bus_init(struct ixgbe_hw *hw) +int ixgbe_mii_bus_init(struct ixgbe_hw *hw) { - s32 (*write_c22)(struct mii_bus *bus, int addr, int regnum, u16 val); - s32 (*read_c22)(struct mii_bus *bus, int addr, int regnum); - s32 (*write_c45)(struct mii_bus *bus, int addr, int devad, int regnum, + int (*write_c22)(struct mii_bus *bus, int addr, int regnum, u16 val); + int (*read_c22)(struct mii_bus *bus, int addr, int regnum); + int (*write_c45)(struct mii_bus *bus, int addr, int devad, int regnum, u16 val); - s32 (*read_c45)(struct mii_bus *bus, int addr, int devad, int regnum); + int (*read_c45)(struct mii_bus *bus, int addr, int devad, int regnum); struct ixgbe_adapter *adapter = hw->back; struct pci_dev *pdev = adapter->pdev; struct device *dev = &adapter->netdev->dev; @@ -1095,9 +1095,9 @@ s32 ixgbe_mii_bus_init(struct ixgbe_hw *hw) * * Restart autonegotiation and PHY and waits for completion. **/ -s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) +int ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) { - s32 status = 0; + int status = 0; u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; bool autoneg = false; ixgbe_link_speed speed; @@ -1173,7 +1173,7 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) * @speed: new link speed * @autoneg_wait_to_complete: unused **/ -s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, +int ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { @@ -1214,10 +1214,10 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, * Determines the supported link capabilities by reading the PHY auto * negotiation register. */ -static s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) +static int ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) { u16 speed_ability; - s32 status; + int status; status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, &speed_ability); @@ -1253,11 +1253,11 @@ static s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) * @speed: pointer to link speed * @autoneg: boolean auto-negotiation value */ -s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, +int ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { - s32 status = 0; + int status = 0; *autoneg = true; if (!hw->phy.speeds_supported) @@ -1276,10 +1276,10 @@ s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, * Reads the VS1 register to determine if link is up and the current speed for * the PHY. **/ -s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, +int ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up) { - s32 status; + int status; u32 time_out; u32 max_time_out = 10; u16 phy_link = 0; @@ -1326,7 +1326,7 @@ s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, * it is called via a function pointer that could call other * functions that could return an error. **/ -s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) +int ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) { u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; bool autoneg = false; @@ -1399,13 +1399,13 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) * ixgbe_reset_phy_nl - Performs a PHY reset * @hw: pointer to hardware structure **/ -s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) +int ixgbe_reset_phy_nl(struct ixgbe_hw *hw) { u16 phy_offset, control, eword, edata, block_crc; bool end_data = false; u16 list_offset, data_offset; u16 phy_data = 0; - s32 ret_val; + int ret_val; u32 i; /* Blocked by MNG FW so bail */ @@ -1506,7 +1506,7 @@ err_eeprom: * * Determines HW type and calls appropriate function. **/ -s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw) +int ixgbe_identify_module_generic(struct ixgbe_hw *hw) { switch (hw->mac.ops.get_media_type(hw)) { case ixgbe_media_type_fiber: @@ -1527,10 +1527,10 @@ s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw) * * Searches for and identifies the SFP module and assigns appropriate PHY type. **/ -s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) +int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; - s32 status; + int status; u32 vendor_oui = 0; enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; u8 identifier = 0; @@ -1792,10 +1792,10 @@ err_read_i2c_eeprom: * * Searches for and identifies the QSFP module and assigns appropriate PHY type **/ -static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) +static int ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; - s32 status; + int status; u32 vendor_oui = 0; enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; u8 identifier = 0; @@ -1975,7 +1975,7 @@ err_read_i2c_eeprom: * Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if * so it returns the offsets to the phy init sequence block. **/ -s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, +int ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, u16 *list_offset, u16 *data_offset) { @@ -2065,7 +2065,7 @@ err_phy: * * Performs byte read operation to SFP module's EEPROM over I2C interface. **/ -s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 *eeprom_data) { return hw->phy.ops.read_i2c_byte(hw, byte_offset, @@ -2081,7 +2081,7 @@ s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, * * Performs byte read operation to SFP module's SFF-8472 data over I2C **/ -s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 *sff8472_data) { return hw->phy.ops.read_i2c_byte(hw, byte_offset, @@ -2097,7 +2097,7 @@ s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, * * Performs byte write operation to SFP module's EEPROM over I2C interface. **/ -s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 eeprom_data) { return hw->phy.ops.write_i2c_byte(hw, byte_offset, @@ -2131,10 +2131,10 @@ static bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr) * Performs byte read operation to SFP module's EEPROM over I2C interface at * a specified device address. */ -static s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data, bool lock) { - s32 status; + int status; u32 max_retry = 10; u32 retry = 0; u32 swfw_mask = hw->phy.phy_semaphore_mask; @@ -2221,7 +2221,7 @@ fail: * Performs byte read operation to SFP module's EEPROM over I2C interface at * a specified device address. */ -s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data) { return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, @@ -2238,7 +2238,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, * Performs byte read operation to SFP module's EEPROM over I2C interface at * a specified device address. */ -s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data) { return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, @@ -2256,10 +2256,10 @@ s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, * Performs byte write operation to SFP module's EEPROM over I2C interface at * a specified device address. */ -static s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, +static int ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data, bool lock) { - s32 status; + int status; u32 max_retry = 1; u32 retry = 0; u32 swfw_mask = hw->phy.phy_semaphore_mask; @@ -2324,7 +2324,7 @@ fail: * Performs byte write operation to SFP module's EEPROM over I2C interface at * a specified device address. */ -s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data) { return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, @@ -2341,7 +2341,7 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, * Performs byte write operation to SFP module's EEPROM over I2C interface at * a specified device address. */ -s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data) { return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, @@ -2422,9 +2422,9 @@ static void ixgbe_i2c_stop(struct ixgbe_hw *hw) * * Clocks in one byte data via I2C data/clock **/ -static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) +static int ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) { - s32 i; + int i; bool bit = false; *data = 0; @@ -2443,10 +2443,10 @@ static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) * * Clocks out one byte data via I2C data/clock **/ -static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) +static int ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) { - s32 status; - s32 i; + int status; + int i; u32 i2cctl; bool bit = false; @@ -2474,10 +2474,10 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) * * Clocks in/out one bit via I2C data/clock **/ -static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) +static int ixgbe_get_i2c_ack(struct ixgbe_hw *hw) { u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); - s32 status = 0; + int status = 0; u32 i = 0; u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); u32 timeout = 10; @@ -2525,7 +2525,7 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) * * Clocks in one bit via I2C data/clock **/ -static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) +static int ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) { u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); @@ -2559,9 +2559,9 @@ static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) * * Clocks out one bit via I2C data/clock **/ -static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) +static int ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) { - s32 status; + int status; u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); status = ixgbe_set_i2c_data(hw, &i2cctl, data); @@ -2647,7 +2647,7 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) * Sets the I2C data bit * Asserts the I2C data output enable on X550 hardware. **/ -static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) +static int ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) { u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); @@ -2769,7 +2769,7 @@ bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) * @hw: pointer to hardware structure * @on: true for on, false for off **/ -s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on) +int ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on) { u32 status; u16 reg; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index ef72729d7c93..beedcb7bec0d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -121,57 +121,57 @@ /* SFP+ SFF-8472 Compliance code */ #define IXGBE_SFF_SFF_8472_UNSUP 0x00 -s32 ixgbe_mii_bus_init(struct ixgbe_hw *hw); +int ixgbe_mii_bus_init(struct ixgbe_hw *hw); -s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); -s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw); -s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, +int ixgbe_identify_phy_generic(struct ixgbe_hw *hw); +int ixgbe_reset_phy_generic(struct ixgbe_hw *hw); +int ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data); -s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, +int ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data); -s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, +int ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data); -s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, +int ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data); -s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw); -s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, +int ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw); +int ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); -s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, +int ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); bool ixgbe_check_reset_blocked(struct ixgbe_hw *hw); /* PHY specific */ -s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, +int ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up); -s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw); +int ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw); -s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw); -s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on); -s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw); -s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); -s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, +int ixgbe_reset_phy_nl(struct ixgbe_hw *hw); +int ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on); +int ixgbe_identify_module_generic(struct ixgbe_hw *hw); +int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); +int ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, u16 *list_offset, u16 *data_offset); bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw); -s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data); -s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data); -s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data); -s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data); -s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 *eeprom_data); -s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 *sff8472_data); -s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, +int ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 eeprom_data); -s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg, +int ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val, bool lock); -s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg, +int ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg, u16 val, bool lock); #endif /* _IXGBE_PHY_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 7299a830f6e4..fcfd0a075eee 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -492,7 +492,7 @@ static int ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 max_frame, u32 vf struct net_device *dev = adapter->netdev; int pf_max_frame = dev->mtu + ETH_HLEN; u32 reg_offset, vf_shift, vfre; - s32 err = 0; + int err = 0; #ifdef CONFIG_FCOE if (dev->features & NETIF_F_FCOE_MTU) @@ -775,7 +775,7 @@ static void ixgbe_vf_clear_mbx(struct ixgbe_adapter *adapter, u32 vf) static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, int vf, unsigned char *mac_addr) { - s32 retval; + int retval; ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); retval = ixgbe_add_mac_filter(adapter, mac_addr, vf); @@ -1254,7 +1254,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) u32 mbx_size = IXGBE_VFMAILBOX_SIZE; u32 msgbuf[IXGBE_VFMAILBOX_SIZE]; struct ixgbe_hw *hw = &adapter->hw; - s32 retval; + int retval; retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf); @@ -1418,7 +1418,7 @@ void ixgbe_set_all_vfs(struct ixgbe_adapter *adapter) int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - s32 retval; + int retval; if (vf >= adapter->num_vfs) return -EINVAL; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 61b9774b3d31..d44c58130be2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3393,50 +3393,50 @@ struct ixgbe_hw; /* Function pointer table */ struct ixgbe_eeprom_operations { - s32 (*init_params)(struct ixgbe_hw *); - s32 (*read)(struct ixgbe_hw *, u16, u16 *); - s32 (*read_buffer)(struct ixgbe_hw *, u16, u16, u16 *); - s32 (*write)(struct ixgbe_hw *, u16, u16); - s32 (*write_buffer)(struct ixgbe_hw *, u16, u16, u16 *); - s32 (*validate_checksum)(struct ixgbe_hw *, u16 *); - s32 (*update_checksum)(struct ixgbe_hw *); - s32 (*calc_checksum)(struct ixgbe_hw *); + int (*init_params)(struct ixgbe_hw *); + int (*read)(struct ixgbe_hw *, u16, u16 *); + int (*read_buffer)(struct ixgbe_hw *, u16, u16, u16 *); + int (*write)(struct ixgbe_hw *, u16, u16); + int (*write_buffer)(struct ixgbe_hw *, u16, u16, u16 *); + int (*validate_checksum)(struct ixgbe_hw *, u16 *); + int (*update_checksum)(struct ixgbe_hw *); + int (*calc_checksum)(struct ixgbe_hw *); }; struct ixgbe_mac_operations { - s32 (*init_hw)(struct ixgbe_hw *); - s32 (*reset_hw)(struct ixgbe_hw *); - s32 (*start_hw)(struct ixgbe_hw *); - s32 (*clear_hw_cntrs)(struct ixgbe_hw *); + int (*init_hw)(struct ixgbe_hw *); + int (*reset_hw)(struct ixgbe_hw *); + int (*start_hw)(struct ixgbe_hw *); + int (*clear_hw_cntrs)(struct ixgbe_hw *); enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); - s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); - s32 (*get_san_mac_addr)(struct ixgbe_hw *, u8 *); - s32 (*get_device_caps)(struct ixgbe_hw *, u16 *); - s32 (*get_wwn_prefix)(struct ixgbe_hw *, u16 *, u16 *); - s32 (*stop_adapter)(struct ixgbe_hw *); - s32 (*get_bus_info)(struct ixgbe_hw *); + int (*get_mac_addr)(struct ixgbe_hw *, u8 *); + int (*get_san_mac_addr)(struct ixgbe_hw *, u8 *); + int (*get_device_caps)(struct ixgbe_hw *, u16 *); + int (*get_wwn_prefix)(struct ixgbe_hw *, u16 *, u16 *); + int (*stop_adapter)(struct ixgbe_hw *); + int (*get_bus_info)(struct ixgbe_hw *); void (*set_lan_id)(struct ixgbe_hw *); - s32 (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*); - s32 (*write_analog_reg8)(struct ixgbe_hw*, u32, u8); - s32 (*setup_sfp)(struct ixgbe_hw *); - s32 (*disable_rx_buff)(struct ixgbe_hw *); - s32 (*enable_rx_buff)(struct ixgbe_hw *); - s32 (*enable_rx_dma)(struct ixgbe_hw *, u32); - s32 (*acquire_swfw_sync)(struct ixgbe_hw *, u32); + int (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*); + int (*write_analog_reg8)(struct ixgbe_hw*, u32, u8); + int (*setup_sfp)(struct ixgbe_hw *); + int (*disable_rx_buff)(struct ixgbe_hw *); + int (*enable_rx_buff)(struct ixgbe_hw *); + int (*enable_rx_dma)(struct ixgbe_hw *, u32); + int (*acquire_swfw_sync)(struct ixgbe_hw *, u32); void (*release_swfw_sync)(struct ixgbe_hw *, u32); void (*init_swfw_sync)(struct ixgbe_hw *); - s32 (*prot_autoc_read)(struct ixgbe_hw *, bool *, u32 *); - s32 (*prot_autoc_write)(struct ixgbe_hw *, u32, bool); + int (*prot_autoc_read)(struct ixgbe_hw *, bool *, u32 *); + int (*prot_autoc_write)(struct ixgbe_hw *, u32, bool); /* Link */ void (*disable_tx_laser)(struct ixgbe_hw *); void (*enable_tx_laser)(struct ixgbe_hw *); void (*flap_tx_laser)(struct ixgbe_hw *); void (*stop_link_on_d3)(struct ixgbe_hw *); - s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool); - s32 (*setup_mac_link)(struct ixgbe_hw *, ixgbe_link_speed, bool); - s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); - s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, + int (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool); + int (*setup_mac_link)(struct ixgbe_hw *, ixgbe_link_speed, bool); + int (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); + int (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); void (*set_rate_select_speed)(struct ixgbe_hw *, ixgbe_link_speed); @@ -3444,38 +3444,38 @@ struct ixgbe_mac_operations { void (*set_rxpba)(struct ixgbe_hw *, int, u32, int); /* LED */ - s32 (*led_on)(struct ixgbe_hw *, u32); - s32 (*led_off)(struct ixgbe_hw *, u32); - s32 (*blink_led_start)(struct ixgbe_hw *, u32); - s32 (*blink_led_stop)(struct ixgbe_hw *, u32); - s32 (*init_led_link_act)(struct ixgbe_hw *); + int (*led_on)(struct ixgbe_hw *, u32); + int (*led_off)(struct ixgbe_hw *, u32); + int (*blink_led_start)(struct ixgbe_hw *, u32); + int (*blink_led_stop)(struct ixgbe_hw *, u32); + int (*init_led_link_act)(struct ixgbe_hw *); /* RAR, Multicast, VLAN */ - s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32, u32); - s32 (*clear_rar)(struct ixgbe_hw *, u32); - s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32); - s32 (*set_vmdq_san_mac)(struct ixgbe_hw *, u32); - s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32); - s32 (*init_rx_addrs)(struct ixgbe_hw *); - s32 (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *); - s32 (*enable_mc)(struct ixgbe_hw *); - s32 (*disable_mc)(struct ixgbe_hw *); - s32 (*clear_vfta)(struct ixgbe_hw *); - s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool, bool); - s32 (*init_uta_tables)(struct ixgbe_hw *); + int (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32, u32); + int (*clear_rar)(struct ixgbe_hw *, u32); + int (*set_vmdq)(struct ixgbe_hw *, u32, u32); + int (*set_vmdq_san_mac)(struct ixgbe_hw *, u32); + int (*clear_vmdq)(struct ixgbe_hw *, u32, u32); + int (*init_rx_addrs)(struct ixgbe_hw *); + int (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *); + int (*enable_mc)(struct ixgbe_hw *); + int (*disable_mc)(struct ixgbe_hw *); + int (*clear_vfta)(struct ixgbe_hw *); + int (*set_vfta)(struct ixgbe_hw *, u32, u32, bool, bool); + int (*init_uta_tables)(struct ixgbe_hw *); void (*set_mac_anti_spoofing)(struct ixgbe_hw *, bool, int); void (*set_vlan_anti_spoofing)(struct ixgbe_hw *, bool, int); /* Flow Control */ - s32 (*fc_enable)(struct ixgbe_hw *); - s32 (*setup_fc)(struct ixgbe_hw *); + int (*fc_enable)(struct ixgbe_hw *); + int (*setup_fc)(struct ixgbe_hw *); void (*fc_autoneg)(struct ixgbe_hw *); /* Manageability interface */ - s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8, u16, + int (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8, u16, const char *); - s32 (*get_thermal_sensor_data)(struct ixgbe_hw *); - s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw); + int (*get_thermal_sensor_data)(struct ixgbe_hw *); + int (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw); bool (*fw_recovery_mode)(struct ixgbe_hw *hw); void (*disable_rx)(struct ixgbe_hw *hw); void (*enable_rx)(struct ixgbe_hw *hw); @@ -3484,47 +3484,47 @@ struct ixgbe_mac_operations { void (*set_ethertype_anti_spoofing)(struct ixgbe_hw *, bool, int); /* DMA Coalescing */ - s32 (*dmac_config)(struct ixgbe_hw *hw); - s32 (*dmac_update_tcs)(struct ixgbe_hw *hw); - s32 (*dmac_config_tcs)(struct ixgbe_hw *hw); - s32 (*read_iosf_sb_reg)(struct ixgbe_hw *, u32, u32, u32 *); - s32 (*write_iosf_sb_reg)(struct ixgbe_hw *, u32, u32, u32); + int (*dmac_config)(struct ixgbe_hw *hw); + int (*dmac_update_tcs)(struct ixgbe_hw *hw); + int (*dmac_config_tcs)(struct ixgbe_hw *hw); + int (*read_iosf_sb_reg)(struct ixgbe_hw *, u32, u32, u32 *); + int (*write_iosf_sb_reg)(struct ixgbe_hw *, u32, u32, u32); }; struct ixgbe_phy_operations { - s32 (*identify)(struct ixgbe_hw *); - s32 (*identify_sfp)(struct ixgbe_hw *); - s32 (*init)(struct ixgbe_hw *); - s32 (*reset)(struct ixgbe_hw *); - s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *); - s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16); - s32 (*read_reg_mdi)(struct ixgbe_hw *, u32, u32, u16 *); - s32 (*write_reg_mdi)(struct ixgbe_hw *, u32, u32, u16); - s32 (*setup_link)(struct ixgbe_hw *); - s32 (*setup_internal_link)(struct ixgbe_hw *); - s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool); - s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); - s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); - s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); - s32 (*read_i2c_sff8472)(struct ixgbe_hw *, u8 , u8 *); - s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); - s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8); + int (*identify)(struct ixgbe_hw *); + int (*identify_sfp)(struct ixgbe_hw *); + int (*init)(struct ixgbe_hw *); + int (*reset)(struct ixgbe_hw *); + int (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *); + int (*write_reg)(struct ixgbe_hw *, u32, u32, u16); + int (*read_reg_mdi)(struct ixgbe_hw *, u32, u32, u16 *); + int (*write_reg_mdi)(struct ixgbe_hw *, u32, u32, u16); + int (*setup_link)(struct ixgbe_hw *); + int (*setup_internal_link)(struct ixgbe_hw *); + int (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool); + int (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); + int (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); + int (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); + int (*read_i2c_sff8472)(struct ixgbe_hw *, u8, u8 *); + int (*read_i2c_eeprom)(struct ixgbe_hw *, u8, u8 *); + int (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8); bool (*check_overtemp)(struct ixgbe_hw *); - s32 (*set_phy_power)(struct ixgbe_hw *, bool on); - s32 (*enter_lplu)(struct ixgbe_hw *); - s32 (*handle_lasi)(struct ixgbe_hw *hw, bool *); - s32 (*read_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr, + int (*set_phy_power)(struct ixgbe_hw *, bool on); + int (*enter_lplu)(struct ixgbe_hw *); + int (*handle_lasi)(struct ixgbe_hw *hw, bool *); + int (*read_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr, u8 *value); - s32 (*write_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr, + int (*write_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr, u8 value); }; struct ixgbe_link_operations { - s32 (*read_link)(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val); - s32 (*read_link_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, + int (*read_link)(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val); + int (*read_link_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val); - s32 (*write_link)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val); - s32 (*write_link_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, + int (*write_link)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val); + int (*write_link_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val); }; @@ -3602,14 +3602,14 @@ struct ixgbe_phy_info { #include "ixgbe_mbx.h" struct ixgbe_mbx_operations { - s32 (*init_params)(struct ixgbe_hw *hw); - s32 (*read)(struct ixgbe_hw *, u32 *, u16, u16); - s32 (*write)(struct ixgbe_hw *, u32 *, u16, u16); - s32 (*read_posted)(struct ixgbe_hw *, u32 *, u16, u16); - s32 (*write_posted)(struct ixgbe_hw *, u32 *, u16, u16); - s32 (*check_for_msg)(struct ixgbe_hw *, u16); - s32 (*check_for_ack)(struct ixgbe_hw *, u16); - s32 (*check_for_rst)(struct ixgbe_hw *, u16); + int (*init_params)(struct ixgbe_hw *hw); + int (*read)(struct ixgbe_hw *, u32 *, u16, u16); + int (*write)(struct ixgbe_hw *, u32 *, u16, u16); + int (*read_posted)(struct ixgbe_hw *, u32 *, u16, u16); + int (*write_posted)(struct ixgbe_hw *, u32 *, u16, u16); + int (*check_for_msg)(struct ixgbe_hw *, u16); + int (*check_for_ack)(struct ixgbe_hw *, u16); + int (*check_for_rst)(struct ixgbe_hw *, u16); }; struct ixgbe_mbx_stats { @@ -3656,7 +3656,7 @@ struct ixgbe_hw { struct ixgbe_info { enum ixgbe_mac_type mac; - s32 (*get_invariants)(struct ixgbe_hw *); + int (*get_invariants)(struct ixgbe_hw *); const struct ixgbe_mac_operations *mac_ops; const struct ixgbe_eeprom_operations *eeprom_ops; const struct ixgbe_phy_operations *phy_ops; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 57a912e4653f..39357af77c64 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -16,9 +16,9 @@ #define IXGBE_X540_VFT_TBL_SIZE 128 #define IXGBE_X540_RX_PB_SIZE 384 -static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw); -static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); -static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw); +static int ixgbe_update_flash_X540(struct ixgbe_hw *hw); +static int ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); +static int ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw); static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw); enum ixgbe_media_type ixgbe_get_media_type_X540(struct ixgbe_hw *hw) @@ -26,7 +26,7 @@ enum ixgbe_media_type ixgbe_get_media_type_X540(struct ixgbe_hw *hw) return ixgbe_media_type_copper; } -s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw) +int ixgbe_get_invariants_X540(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; @@ -51,7 +51,7 @@ s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw) * @speed: new link speed * @autoneg_wait_to_complete: true when waiting for completion is needed **/ -s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, +int ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { return hw->phy.ops.setup_link_speed(hw, speed, @@ -66,9 +66,9 @@ s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, * and clears all interrupts, perform a PHY reset, and perform a link (MAC) * reset. **/ -s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw) +int ixgbe_reset_hw_X540(struct ixgbe_hw *hw) { - s32 status; + int status; u32 ctrl, i; u32 swfw_mask = hw->phy.phy_semaphore_mask; @@ -166,9 +166,9 @@ mac_reset_top: * and the generation start_hw function. * Then performs revision-specific operations, if any. **/ -s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) +int ixgbe_start_hw_X540(struct ixgbe_hw *hw) { - s32 ret_val; + int ret_val; ret_val = ixgbe_start_hw_generic(hw); if (ret_val) @@ -184,7 +184,7 @@ s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) * Initializes the EEPROM parameters ixgbe_eeprom_info within the * ixgbe_hw struct in order to set up EEPROM access. **/ -s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw) +int ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; @@ -215,9 +215,9 @@ s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw) * * Reads a 16 bit word from the EEPROM using the EERD register. **/ -static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) +static int ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) { - s32 status; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) return -EBUSY; @@ -237,10 +237,10 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) * * Reads a 16 bit word(s) from the EEPROM using the EERD register. **/ -static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, +static int ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) return -EBUSY; @@ -259,9 +259,9 @@ static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, * * Write a 16 bit word to the EEPROM using the EEWR register. **/ -static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) +static int ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) { - s32 status; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) return -EBUSY; @@ -281,10 +281,10 @@ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) * * Write a 16 bit word(s) to the EEPROM using the EEWR register. **/ -static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, +static int ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) return -EBUSY; @@ -303,7 +303,7 @@ static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, * * @hw: pointer to hardware structure **/ -static s32 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) +static int ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) { u16 i; u16 j; @@ -368,7 +368,7 @@ static s32 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) checksum = (u16)IXGBE_EEPROM_SUM - checksum; - return (s32)checksum; + return (int)checksum; } /** @@ -379,10 +379,10 @@ static s32 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) * Performs checksum calculation and validates the EEPROM checksum. If the * caller does not need checksum_val, the value can be NULL. **/ -static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, +static int ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, u16 *checksum_val) { - s32 status; + int status; u16 checksum; u16 read_checksum = 0; @@ -439,9 +439,9 @@ out: * checksum and updates the EEPROM and instructs the hardware to update * the flash. **/ -static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) +static int ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) { - s32 status; + int status; u16 checksum; /* Read the first word from the EEPROM. If this times out or fails, do @@ -484,10 +484,10 @@ out: * Set FLUP (bit 23) of the EEC register to instruct Hardware to copy * EEPROM from shadow RAM to the flash device. **/ -static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) +static int ixgbe_update_flash_X540(struct ixgbe_hw *hw) { u32 flup; - s32 status; + int status; status = ixgbe_poll_flash_update_done_X540(hw); if (status == -EIO) { @@ -529,7 +529,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) * Polls the FLUDONE (bit 26) of the EEC Register to determine when the * flash update is done. **/ -static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw) +static int ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw) { u32 i; u32 reg; @@ -551,7 +551,7 @@ static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw) * Acquires the SWFW semaphore thought the SW_FW_SYNC register for * the specified function (CSR, PHY0, PHY1, NVM, Flash) **/ -s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) +int ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) { u32 swmask = mask & IXGBE_GSSR_NVM_PHY_MASK; u32 swi2c_mask = mask & IXGBE_GSSR_I2C_MASK; @@ -660,7 +660,7 @@ void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) * * Sets the hardware semaphores so SW/FW can gain control of shared resources */ -static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw) +static int ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw) { u32 timeout = 2000; u32 i; @@ -760,7 +760,7 @@ void ixgbe_init_swfw_sync_X540(struct ixgbe_hw *hw) * Devices that implement the version 2 interface: * X540 **/ -s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index) +int ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index) { u32 macc_reg; u32 ledctl_reg; @@ -798,7 +798,7 @@ s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index) * Devices that implement the version 2 interface: * X540 **/ -s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index) +int ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index) { u32 macc_reg; u32 ledctl_reg; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h index e246c0d2a427..b69a680d3ab5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h @@ -3,17 +3,17 @@ #include "ixgbe_type.h" -s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw); -s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, +int ixgbe_get_invariants_X540(struct ixgbe_hw *hw); +int ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); -s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw); +int ixgbe_reset_hw_X540(struct ixgbe_hw *hw); +int ixgbe_start_hw_X540(struct ixgbe_hw *hw); enum ixgbe_media_type ixgbe_get_media_type_X540(struct ixgbe_hw *hw); -s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, +int ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); -s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask); +int ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index); +int ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index); +int ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask); void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask); void ixgbe_init_swfw_sync_X540(struct ixgbe_hw *hw); -s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw); +int ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index c1adc94a5a65..aec38de1921f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -6,13 +6,13 @@ #include "ixgbe_common.h" #include "ixgbe_phy.h" -static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *, ixgbe_link_speed); -static s32 ixgbe_setup_fc_x550em(struct ixgbe_hw *); +static int ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *, ixgbe_link_speed); +static int ixgbe_setup_fc_x550em(struct ixgbe_hw *); static void ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *); static void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *); -static s32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *); +static int ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *); -static s32 ixgbe_get_invariants_X550_x(struct ixgbe_hw *hw) +static int ixgbe_get_invariants_X550_x(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; @@ -29,7 +29,7 @@ static s32 ixgbe_get_invariants_X550_x(struct ixgbe_hw *hw) return 0; } -static s32 ixgbe_get_invariants_X550_x_fw(struct ixgbe_hw *hw) +static int ixgbe_get_invariants_X550_x_fw(struct ixgbe_hw *hw) { struct ixgbe_phy_info *phy = &hw->phy; @@ -41,7 +41,7 @@ static s32 ixgbe_get_invariants_X550_x_fw(struct ixgbe_hw *hw) return 0; } -static s32 ixgbe_get_invariants_X550_a(struct ixgbe_hw *hw) +static int ixgbe_get_invariants_X550_a(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; @@ -55,7 +55,7 @@ static s32 ixgbe_get_invariants_X550_a(struct ixgbe_hw *hw) return 0; } -static s32 ixgbe_get_invariants_X550_a_fw(struct ixgbe_hw *hw) +static int ixgbe_get_invariants_X550_a_fw(struct ixgbe_hw *hw) { struct ixgbe_phy_info *phy = &hw->phy; @@ -91,7 +91,7 @@ static void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw) * * Returns status code */ -static s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value) +static int ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value) { return hw->link.ops.read_link_unlocked(hw, hw->link.addr, reg, value); } @@ -104,7 +104,7 @@ static s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value) * * Returns status code */ -static s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value) +static int ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value) { return hw->link.ops.write_link_unlocked(hw, hw->link.addr, reg, value); } @@ -117,9 +117,9 @@ static s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value) * * Returns status code */ -static s32 ixgbe_read_pe(struct ixgbe_hw *hw, u8 reg, u8 *value) +static int ixgbe_read_pe(struct ixgbe_hw *hw, u8 reg, u8 *value) { - s32 status; + int status; status = ixgbe_read_i2c_byte_generic_unlocked(hw, reg, IXGBE_PE, value); if (status) @@ -135,9 +135,9 @@ static s32 ixgbe_read_pe(struct ixgbe_hw *hw, u8 reg, u8 *value) * * Returns status code */ -static s32 ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value) +static int ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value) { - s32 status; + int status; status = ixgbe_write_i2c_byte_generic_unlocked(hw, reg, IXGBE_PE, value); @@ -153,9 +153,9 @@ static s32 ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value) * This function assumes that the caller has acquired the proper semaphore. * Returns error code */ -static s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw) +static int ixgbe_reset_cs4227(struct ixgbe_hw *hw) { - s32 status; + int status; u32 retry; u16 value; u8 reg; @@ -225,7 +225,7 @@ static s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw) static void ixgbe_check_cs4227(struct ixgbe_hw *hw) { u32 swfw_mask = hw->phy.phy_semaphore_mask; - s32 status; + int status; u16 value; u8 retry; @@ -292,7 +292,7 @@ out: * * Returns error code */ -static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw) +static int ixgbe_identify_phy_x550em(struct ixgbe_hw *hw) { switch (hw->device_id) { case IXGBE_DEV_ID_X550EM_A_SFP: @@ -347,13 +347,13 @@ static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw) return 0; } -static s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data) { return -EOPNOTSUPP; } -static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data) { return -EOPNOTSUPP; @@ -368,7 +368,7 @@ static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, * * Returns an error code on error. **/ -static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, +static int ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val) { return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, true); @@ -383,7 +383,7 @@ static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, * * Returns an error code on error. **/ -static s32 +static int ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val) { @@ -399,7 +399,7 @@ ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr, * * Returns an error code on error. **/ -static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, +static int ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val) { return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, true); @@ -414,7 +414,7 @@ static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, * * Returns an error code on error. **/ -static s32 +static int ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val) { @@ -427,7 +427,7 @@ ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, * @activity: activity to perform * @data: Pointer to 4 32-bit words of data */ -s32 ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity, +int ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity, u32 (*data)[FW_PHY_ACT_DATA_COUNT]) { union { @@ -435,7 +435,7 @@ s32 ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity, struct ixgbe_hic_phy_activity_resp rsp; } hic; u16 retries = FW_PHY_ACT_RETRIES; - s32 rc; + int rc; u32 i; do { @@ -484,12 +484,12 @@ static const struct { * * Returns error code */ -static s32 ixgbe_get_phy_id_fw(struct ixgbe_hw *hw) +static int ixgbe_get_phy_id_fw(struct ixgbe_hw *hw) { u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; u16 phy_speeds; u16 phy_id_lo; - s32 rc; + int rc; u16 i; if (hw->phy.id) @@ -526,7 +526,7 @@ static s32 ixgbe_get_phy_id_fw(struct ixgbe_hw *hw) * * Returns error code */ -static s32 ixgbe_identify_phy_fw(struct ixgbe_hw *hw) +static int ixgbe_identify_phy_fw(struct ixgbe_hw *hw) { if (hw->bus.lan_id) hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; @@ -545,7 +545,7 @@ static s32 ixgbe_identify_phy_fw(struct ixgbe_hw *hw) * * Returns error code */ -static s32 ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw) +static int ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw) { u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 }; @@ -557,10 +557,10 @@ static s32 ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw) * ixgbe_setup_fw_link - Setup firmware-controlled PHYs * @hw: pointer to hardware structure */ -static s32 ixgbe_setup_fw_link(struct ixgbe_hw *hw) +static int ixgbe_setup_fw_link(struct ixgbe_hw *hw) { u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 }; - s32 rc; + int rc; u16 i; if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw)) @@ -613,7 +613,7 @@ static s32 ixgbe_setup_fw_link(struct ixgbe_hw *hw) * * Called at init time to set up flow control. */ -static s32 ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw) +static int ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw) { if (hw->fc.requested_mode == ixgbe_fc_default) hw->fc.requested_mode = ixgbe_fc_full; @@ -627,7 +627,7 @@ static s32 ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw) * Initializes the EEPROM parameters ixgbe_eeprom_info within the * ixgbe_hw struct in order to set up EEPROM access. **/ -static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) +static int ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; @@ -659,7 +659,7 @@ static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) * * Note: ctrl can be NULL if the IOSF control register value is not needed */ -static s32 ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl) +static int ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl) { u32 i, command; @@ -690,12 +690,12 @@ static s32 ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl) * @device_type: 3 bit device type * @phy_data: Pointer to read data from the register **/ -static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u32 *data) { u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM; u32 command, error; - s32 ret; + int ret; ret = hw->mac.ops.acquire_swfw_sync(hw, gssr); if (ret) @@ -732,10 +732,10 @@ out: * ixgbe_get_phy_token - Get the token for shared PHY access * @hw: Pointer to hardware structure */ -static s32 ixgbe_get_phy_token(struct ixgbe_hw *hw) +static int ixgbe_get_phy_token(struct ixgbe_hw *hw) { struct ixgbe_hic_phy_token_req token_cmd; - s32 status; + int status; token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; @@ -761,10 +761,10 @@ static s32 ixgbe_get_phy_token(struct ixgbe_hw *hw) * ixgbe_put_phy_token - Put the token for shared PHY access * @hw: Pointer to hardware structure */ -static s32 ixgbe_put_phy_token(struct ixgbe_hw *hw) +static int ixgbe_put_phy_token(struct ixgbe_hw *hw) { struct ixgbe_hic_phy_token_req token_cmd; - s32 status; + int status; token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; @@ -790,7 +790,7 @@ static s32 ixgbe_put_phy_token(struct ixgbe_hw *hw) * @device_type: 3 bit device type * @data: Data to write to the register **/ -static s32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, __always_unused u32 device_type, u32 data) { @@ -816,7 +816,7 @@ static s32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, * @device_type: 3 bit device type * @data: Pointer to read data from the register **/ -static s32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, __always_unused u32 device_type, u32 *data) { @@ -824,7 +824,7 @@ static s32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, struct ixgbe_hic_internal_phy_req cmd; struct ixgbe_hic_internal_phy_resp rsp; } hic; - s32 status; + int status; memset(&hic, 0, sizeof(hic)); hic.cmd.hdr.cmd = FW_INT_PHY_REQ_CMD; @@ -851,14 +851,14 @@ static s32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, * * Reads a 16 bit word(s) from the EEPROM using the hostif. **/ -static s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, +static int ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM; struct ixgbe_hic_read_shadow_ram buffer; u32 current_word = 0; u16 words_to_read; - s32 status; + int status; u32 i; /* Take semaphore for the entire operation. */ @@ -923,12 +923,12 @@ out: * * Returns error status for any failure **/ -static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr, +static int ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr, u16 size, u16 *csum, u16 *buffer, u32 buffer_size) { u16 buf[256]; - s32 status; + int status; u16 length, bufsz, i, start; u16 *local_buffer; @@ -991,12 +991,12 @@ static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr, * * Returns a negative error code on error, or the 16-bit checksum **/ -static s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, +static int ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size) { u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1]; u16 *local_buffer; - s32 status; + int status; u16 checksum = 0; u16 pointer, i, size; @@ -1060,7 +1060,7 @@ static s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, checksum = (u16)IXGBE_EEPROM_SUM - checksum; - return (s32)checksum; + return (int)checksum; } /** ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum @@ -1068,7 +1068,7 @@ static s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, * * Returns a negative error code on error, or the 16-bit checksum **/ -static s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) +static int ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) { return ixgbe_calc_checksum_X550(hw, NULL, 0); } @@ -1080,11 +1080,11 @@ static s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) * * Reads a 16 bit word from the EEPROM using the hostif. **/ -static s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) +static int ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) { const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM; struct ixgbe_hic_read_shadow_ram buffer; - s32 status; + int status; buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; buffer.hdr.req.buf_lenh = 0; @@ -1118,10 +1118,10 @@ static s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) * Performs checksum calculation and validates the EEPROM checksum. If the * caller does not need checksum_val, the value can be NULL. **/ -static s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, +static int ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val) { - s32 status; + int status; u16 checksum; u16 read_checksum = 0; @@ -1168,10 +1168,10 @@ static s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, * * Write a 16 bit word to the EEPROM using the hostif. **/ -static s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, +static int ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data) { - s32 status; + int status; struct ixgbe_hic_write_shadow_ram buffer; buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD; @@ -1196,9 +1196,9 @@ static s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, * * Write a 16 bit word to the EEPROM using the hostif. **/ -static s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) +static int ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) { - s32 status = 0; + int status = 0; if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { status = ixgbe_write_ee_hostif_data_X550(hw, offset, data); @@ -1216,9 +1216,9 @@ static s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) * * Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash. **/ -static s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) +static int ixgbe_update_flash_X550(struct ixgbe_hw *hw) { - s32 status = 0; + int status = 0; union ixgbe_hic_hdr2 buffer; buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD; @@ -1238,7 +1238,7 @@ static s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) * Sets bus link width and speed to unknown because X550em is * not a PCI device. **/ -static s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw) +static int ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw) { hw->bus.type = ixgbe_bus_type_internal; hw->bus.width = ixgbe_bus_width_unknown; @@ -1270,7 +1270,7 @@ static bool ixgbe_fw_recovery_mode_X550(struct ixgbe_hw *hw) static void ixgbe_disable_rx_x550(struct ixgbe_hw *hw) { u32 rxctrl, pfdtxgswc; - s32 status; + int status; struct ixgbe_hic_disable_rxen fw_cmd; rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); @@ -1311,9 +1311,9 @@ static void ixgbe_disable_rx_x550(struct ixgbe_hw *hw) * checksum and updates the EEPROM and instructs the hardware to update * the flash. **/ -static s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) +static int ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) { - s32 status; + int status; u16 checksum = 0; /* Read the first word from the EEPROM. If this times out or fails, do @@ -1351,11 +1351,11 @@ static s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) * * Write a 16 bit word(s) to the EEPROM using the hostif. **/ -static s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, +static int ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status = 0; + int status = 0; u32 i = 0; /* Take semaphore for the entire operation. */ @@ -1387,12 +1387,12 @@ static s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, * @device_type: 3 bit device type * @data: Data to write to the register **/ -static s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u32 data) { u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM; u32 command, error; - s32 ret; + int ret; ret = hw->mac.ops.acquire_swfw_sync(hw, gssr); if (ret) @@ -1430,9 +1430,9 @@ out: * * iXfI configuration needed for ixgbe_mac_X550EM_x devices. **/ -static s32 ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) +static int ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) { - s32 status; + int status; u32 reg_val; /* Disable training protocol FSM. */ @@ -1502,9 +1502,9 @@ static s32 ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) * internal PHY * @hw: pointer to hardware structure **/ -static s32 ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw) +static int ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw) { - s32 status; + int status; u32 link_ctrl; /* Restart auto-negotiation. */ @@ -1551,10 +1551,10 @@ static s32 ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw) * Configures the integrated KR PHY to use iXFI mode. Used to connect an * internal and external PHY at a specific speed, without autonegotiation. **/ -static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) +static int ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) { struct ixgbe_mac_info *mac = &hw->mac; - s32 status; + int status; u32 reg_val; /* iXFI is only supported with X552 */ @@ -1608,7 +1608,7 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) * @hw: pointer to hardware structure * @linear: true if SFP module is linear */ -static s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear) +static int ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear) { switch (hw->phy.sfp_type) { case ixgbe_sfp_type_not_present: @@ -1645,12 +1645,12 @@ static s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear) * * Configures the extern PHY and the integrated KR PHY for SFP support. */ -static s32 +static int ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, ixgbe_link_speed speed, __always_unused bool autoneg_wait_to_complete) { - s32 status; + int status; u16 reg_slice, reg_val; bool setup_linear = false; @@ -1691,10 +1691,10 @@ ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, * Configures the integrated PHY for native SFI mode. Used to connect the * internal PHY directly to an SFP cage, without autonegotiation. **/ -static s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed) +static int ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed) { struct ixgbe_mac_info *mac = &hw->mac; - s32 status; + int status; u32 reg_val; /* Disable all AN and force speed to 10G Serial. */ @@ -1790,13 +1790,13 @@ static s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed) * * Configure the integrated PHY for native SFP support. */ -static s32 +static int ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed, __always_unused bool autoneg_wait_to_complete) { bool setup_linear = false; u32 reg_phy_int; - s32 ret_val; + int ret_val; /* Check if SFP module is supported and linear */ ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); @@ -1839,14 +1839,14 @@ ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed, * * Configure the integrated PHY for SFP support. */ -static s32 +static int ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, __always_unused bool autoneg_wait_to_complete) { u32 reg_slice, slice_offset; bool setup_linear = false; u16 reg_phy_ext; - s32 ret_val; + int ret_val; /* Check if SFP module is supported and linear */ ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); @@ -1918,11 +1918,11 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, * * Returns error status for any failure **/ -static s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw, +static int ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait) { - s32 status; + int status; ixgbe_link_speed force_speed; /* Setup internal/external PHY link speed to iXFI (10G), unless @@ -1954,7 +1954,7 @@ static s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw, * * Check that both the MAC and X557 external PHY have link. **/ -static s32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, +static int ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete) @@ -1998,13 +1998,13 @@ static s32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, * @speed: unused * @autoneg_wait_to_complete: unused */ -static s32 +static int ixgbe_setup_sgmii(struct ixgbe_hw *hw, __always_unused ixgbe_link_speed speed, __always_unused bool autoneg_wait_to_complete) { struct ixgbe_mac_info *mac = &hw->mac; u32 lval, sval, flx_val; - s32 rc; + int rc; rc = mac->ops.read_iosf_sb_reg(hw, IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), @@ -2071,12 +2071,12 @@ ixgbe_setup_sgmii(struct ixgbe_hw *hw, __always_unused ixgbe_link_speed speed, * @speed: the link speed to force * @autoneg_wait: true when waiting for completion is needed */ -static s32 ixgbe_setup_sgmii_fw(struct ixgbe_hw *hw, ixgbe_link_speed speed, +static int ixgbe_setup_sgmii_fw(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait) { struct ixgbe_mac_info *mac = &hw->mac; u32 lval, sval, flx_val; - s32 rc; + int rc; rc = mac->ops.read_iosf_sb_reg(hw, IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), @@ -2148,7 +2148,7 @@ static void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw) { u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; ixgbe_link_speed speed; - s32 status = -EIO; + int status = -EIO; bool link_up; /* AN should have completed when the cable was plugged in. @@ -2276,9 +2276,9 @@ static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) /** ixgbe_setup_sfp_modules_X550em - Setup SFP module * @hw: pointer to hardware structure */ -static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) +static int ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) { - s32 status; + int status; bool linear; /* Check if SFP module is supported */ @@ -2297,7 +2297,7 @@ static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) * @speed: pointer to link speed * @autoneg: true when autoneg or autotry is enabled **/ -static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, +static int ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { @@ -2375,7 +2375,7 @@ static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, * Determime if external Base T PHY interrupt cause is high temperature * failure alarm or link status change. **/ -static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc, +static int ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc, bool *is_overtemp) { u32 status; @@ -2463,7 +2463,7 @@ static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc, * * Returns PHY access status **/ -static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw) +static int ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw) { bool lsc, overtemp; u32 status; @@ -2555,7 +2555,7 @@ static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw) * failure alarm then return error, else if link status change * then setup internal/external PHY link **/ -static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw, +static int ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *is_overtemp) { struct ixgbe_phy_info *phy = &hw->phy; @@ -2579,10 +2579,10 @@ static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw, * * Configures the integrated KR PHY. **/ -static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw, +static int ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw, ixgbe_link_speed speed) { - s32 status; + int status; u32 reg_val; status = hw->mac.ops.read_iosf_sb_reg(hw, @@ -2634,7 +2634,7 @@ static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw, * ixgbe_setup_kr_x550em - Configure the KR PHY * @hw: pointer to hardware structure **/ -static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) +static int ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) { /* leave link alone for 2.5G */ if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) @@ -2652,7 +2652,7 @@ static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) * * Returns error code if unable to get link status. **/ -static s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up) +static int ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up) { u32 ret; u16 autoneg_status; @@ -2686,7 +2686,7 @@ static s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up) * A return of a non-zero value indicates an error, and the base driver should * not report link up. **/ -static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw) +static int ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw) { ixgbe_link_speed force_speed; bool link_up; @@ -2746,9 +2746,9 @@ static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw) /** ixgbe_reset_phy_t_X550em - Performs X557 PHY reset and enables LASI * @hw: pointer to hardware structure **/ -static s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw) +static int ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw) { - s32 status; + int status; status = ixgbe_reset_phy_generic(hw); @@ -2764,7 +2764,7 @@ static s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw) * @hw: pointer to hardware structure * @led_idx: led number to turn on **/ -static s32 ixgbe_led_on_t_x550em(struct ixgbe_hw *hw, u32 led_idx) +static int ixgbe_led_on_t_x550em(struct ixgbe_hw *hw, u32 led_idx) { u16 phy_data; @@ -2786,7 +2786,7 @@ static s32 ixgbe_led_on_t_x550em(struct ixgbe_hw *hw, u32 led_idx) * @hw: pointer to hardware structure * @led_idx: led number to turn off **/ -static s32 ixgbe_led_off_t_x550em(struct ixgbe_hw *hw, u32 led_idx) +static int ixgbe_led_off_t_x550em(struct ixgbe_hw *hw, u32 led_idx) { u16 phy_data; @@ -2819,12 +2819,12 @@ static s32 ixgbe_led_off_t_x550em(struct ixgbe_hw *hw, u32 led_idx) * semaphore, -EIO when command fails or -ENIVAL when incorrect * params passed. **/ -static s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min, +static int ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build, u8 sub, u16 len, const char *driver_ver) { struct ixgbe_hic_drv_info2 fw_cmd; - s32 ret_val; + int ret_val; int i; if (!len || !driver_ver || (len > sizeof(fw_cmd.driver_string))) @@ -2866,11 +2866,11 @@ static s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min, * * Determine lowest common link speed with link partner. **/ -static s32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, +static int ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed) { u16 an_lp_status; - s32 status; + int status; u16 word = hw->eeprom.ctrl_word_3; *lcd_speed = IXGBE_LINK_SPEED_UNKNOWN; @@ -2901,11 +2901,11 @@ static s32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, * ixgbe_setup_fc_x550em - Set up flow control * @hw: pointer to hardware structure */ -static s32 ixgbe_setup_fc_x550em(struct ixgbe_hw *hw) +static int ixgbe_setup_fc_x550em(struct ixgbe_hw *hw) { bool pause, asm_dir; u32 reg_val; - s32 rc = 0; + int rc = 0; /* Validate the requested mode */ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { @@ -2990,7 +2990,7 @@ static void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw) { u32 link_s1, lp_an_page_low, an_cntl_1; ixgbe_link_speed speed; - s32 status = -EIO; + int status = -EIO; bool link_up; /* AN should have completed when the cable was plugged in. @@ -3073,10 +3073,10 @@ static void ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw) * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting * the X557 PHY immediately prior to entering LPLU. **/ -static s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) +static int ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) { u16 an_10g_cntl_reg, autoneg_reg, speed; - s32 status; + int status; ixgbe_link_speed lcd_speed; u32 save_autoneg; bool link_up; @@ -3167,10 +3167,10 @@ static s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) * ixgbe_reset_phy_fw - Reset firmware-controlled PHYs * @hw: pointer to hardware structure */ -static s32 ixgbe_reset_phy_fw(struct ixgbe_hw *hw) +static int ixgbe_reset_phy_fw(struct ixgbe_hw *hw) { u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 }; - s32 rc; + int rc; if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw)) return 0; @@ -3196,7 +3196,7 @@ static s32 ixgbe_reset_phy_fw(struct ixgbe_hw *hw) static bool ixgbe_check_overtemp_fw(struct ixgbe_hw *hw) { u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 }; - s32 rc; + int rc; rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &store); if (rc) @@ -3239,10 +3239,10 @@ static void ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw) * set during init_shared_code because the PHY/SFP type was * not known. Perform the SFP init if necessary. **/ -static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) +static int ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) { struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val; + int ret_val; hw->mac.ops.set_lan_id(hw); @@ -3367,9 +3367,9 @@ static enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) /** ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY. ** @hw: pointer to hardware structure **/ -static s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) +static int ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) { - s32 status; + int status; u16 reg; status = hw->phy.ops.read_reg(hw, @@ -3441,10 +3441,10 @@ static void ixgbe_set_mdio_speed(struct ixgbe_hw *hw) ** and clears all interrupts, perform a PHY reset, and perform a link (MAC) ** reset. **/ -static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) +static int ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) { ixgbe_link_speed link_speed; - s32 status; + int status; u32 ctrl = 0; u32 i; bool link_up = false; @@ -3609,9 +3609,9 @@ static void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, * * Called at init time to set up flow control. **/ -static s32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw) +static int ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw) { - s32 status = 0; + int status = 0; u32 an_cntl = 0; /* Validate the requested mode */ @@ -3714,9 +3714,9 @@ static void ixgbe_set_mux(struct ixgbe_hw *hw, u8 state) * * Acquires the SWFW semaphore and sets the I2C MUX */ -static s32 ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask) +static int ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask) { - s32 status; + int status; status = ixgbe_acquire_swfw_sync_X540(hw, mask); if (status) @@ -3750,11 +3750,11 @@ static void ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask) * * Acquires the SWFW semaphore and get the shared PHY token as needed */ -static s32 ixgbe_acquire_swfw_sync_x550em_a(struct ixgbe_hw *hw, u32 mask) +static int ixgbe_acquire_swfw_sync_x550em_a(struct ixgbe_hw *hw, u32 mask) { u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM; int retries = FW_PHY_TOKEN_RETRIES; - s32 status; + int status; while (--retries) { status = 0; @@ -3807,11 +3807,11 @@ static void ixgbe_release_swfw_sync_x550em_a(struct ixgbe_hw *hw, u32 mask) * Token. The PHY Token is needed since the MDIO is shared between to MAC * instances. */ -static s32 ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data) { u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; - s32 status; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, mask)) return -EBUSY; @@ -3833,11 +3833,11 @@ static s32 ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, * Writes a value to specified PHY register using the SWFW lock and PHY Token. * The PHY Token is needed since the MDIO is shared between to MAC instances. */ -static s32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, +static int ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data) { u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; - s32 status; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, mask)) return -EBUSY; From b678b63a2454983cf22ffc8f8e5366ac9f376972 Mon Sep 17 00:00:00 2001 From: Jedrzej Jagielski Date: Wed, 31 Jan 2024 12:04:18 +0100 Subject: [PATCH 0824/2255] ixgbe: Rearrange args to fix reverse Christmas tree Clean up the code touched during type conversion by the previous patch of the series. Suggested-by: Tony Nguyen Reviewed-by: Przemek Kitszel Reviewed-by: Simon Horman Signed-off-by: Jedrzej Jagielski Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/ixgbe/ixgbe_82598.c | 16 ++--- .../net/ethernet/intel/ixgbe/ixgbe_82599.c | 41 +++++------ .../net/ethernet/intel/ixgbe/ixgbe_common.c | 68 +++++++++---------- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 58 ++++++++-------- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 12 ++-- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 56 +++++++-------- 7 files changed, 127 insertions(+), 126 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 51baa176b99f..283a23150a4d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -97,8 +97,8 @@ static int ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; - int ret_val; u16 list_offset, data_offset; + int ret_val; /* Identify the PHY */ phy->ops.identify(hw); @@ -414,10 +414,10 @@ static int ixgbe_fc_enable_82598(struct ixgbe_hw *hw) static int ixgbe_start_mac_link_82598(struct ixgbe_hw *hw, bool autoneg_wait_to_complete) { + int status = 0; u32 autoc_reg; u32 links_reg; u32 i; - int status = 0; /* Restart link */ autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -649,13 +649,13 @@ static int ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, **/ static int ixgbe_reset_hw_82598(struct ixgbe_hw *hw) { - int status; int phy_status = 0; - u32 ctrl; - u32 gheccr; - u32 i; - u32 autoc; u8 analog_val; + u32 gheccr; + int status; + u32 autoc; + u32 ctrl; + u32 i; /* Call adapter stop to disable tx/rx and clear interrupts */ status = hw->mac.ops.stop_adapter(hw); @@ -951,10 +951,10 @@ static int ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) static int ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr, u8 byte_offset, u8 *eeprom_data) { - int status = 0; u16 sfp_addr = 0; u16 sfp_data = 0; u16 sfp_stat = 0; + int status = 0; u16 gssr; u32 i; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 2ae659b123e4..e0c300fe5cee 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -100,8 +100,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) static int ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { - int ret_val; u16 list_offset, data_offset, data_value; + int ret_val; if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { ixgbe_init_mac_link_ops_82599(hw); @@ -503,11 +503,11 @@ static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw) static int ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, bool autoneg_wait_to_complete) { + bool got_lock = false; + int status = 0; u32 autoc_reg; u32 links_reg; u32 i; - int status = 0; - bool got_lock = false; if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { status = hw->mac.ops.acquire_swfw_sync(hw, @@ -661,11 +661,11 @@ static int ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { - int status = 0; ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; - s32 i, j; - bool link_up = false; u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + bool link_up = false; + int status = 0; + s32 i, j; /* Set autoneg_advertised value based on input link speed */ hw->phy.autoneg_advertised = 0; @@ -771,12 +771,11 @@ static int ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { + ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; + u32 pma_pmd_10g_serial, pma_pmd_1g, link_mode, links_reg, i; + u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); bool autoneg = false; int status; - u32 pma_pmd_1g, link_mode, links_reg, i; - u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); - u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; - ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; /* holds the value of AUTOC register at this current point in time */ u32 current_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -785,6 +784,8 @@ static int ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, /* temporary variable used for comparison purposes */ u32 autoc = current_autoc; + pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; + /* Check to see if speed passed in is supported. */ status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities, &autoneg); @@ -908,10 +909,10 @@ static int ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, static int ixgbe_reset_hw_82599(struct ixgbe_hw *hw) { ixgbe_link_speed link_speed; - int status; u32 ctrl, i, autoc, autoc2; - u32 curr_lms; bool link_up = false; + u32 curr_lms; + int status; /* Call adapter stop to disable tx/rx and clear interrupts */ status = hw->mac.ops.stop_adapter(hw); @@ -1101,10 +1102,10 @@ static int ixgbe_fdir_check_cmd_complete(struct ixgbe_hw *hw, u32 *fdircmd) **/ int ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) { - int i; u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); u32 fdircmd; int err; + int i; fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE; @@ -1869,8 +1870,8 @@ static int ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) { u16 fw_offset, fw_ptp_cfg_offset; int status = -EACCES; - u16 offset; u16 fw_version = 0; + u16 offset; /* firmware check is only necessary for SFI devices */ if (hw->phy.media_type != ixgbe_media_type_fiber) @@ -2008,9 +2009,9 @@ static int ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, **/ static int ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) { - int ret_val; - u32 anlp1_reg = 0; u32 i, autoc_reg, autoc2_reg; + u32 anlp1_reg = 0; + int ret_val; /* Enable link if disabled in NVM */ autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2); @@ -2064,9 +2065,9 @@ reset_pipeline_out: static int ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data) { - u32 esdp; - int status; s32 timeout = 200; + int status; + u32 esdp; if (hw->phy.qsfp_shared_i2c_bus == true) { /* Acquire I2C bus ownership. */ @@ -2118,9 +2119,9 @@ release_i2c_access: static int ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data) { - u32 esdp; - int status; s32 timeout = 200; + int status; + u32 esdp; if (hw->phy.qsfp_shared_i2c_bus == true) { /* Acquire I2C bus ownership. */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index a8fee17cb653..3be1bfb16498 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -113,10 +113,10 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) **/ int ixgbe_setup_fc_generic(struct ixgbe_hw *hw) { - int ret_val = 0; u32 reg = 0, reg_bp = 0; - u16 reg_cu = 0; bool locked = false; + int ret_val = 0; + u16 reg_cu = 0; /* * Validate the requested mode. Strict IEEE mode does not allow @@ -269,9 +269,9 @@ int ixgbe_setup_fc_generic(struct ixgbe_hw *hw) **/ int ixgbe_start_hw_generic(struct ixgbe_hw *hw) { - int ret_val; - u32 ctrl_ext; u16 device_caps; + u32 ctrl_ext; + int ret_val; /* Set the media type */ hw->phy.media_type = hw->mac.ops.get_media_type(hw); @@ -493,10 +493,10 @@ int ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size) { int ret_val; - u16 data; u16 pba_ptr; u16 offset; u16 length; + u16 data; if (pba_num == NULL) { hw_dbg(hw, "PBA string buffer was null\n"); @@ -898,8 +898,8 @@ int ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) int ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - int status; u16 i, count; + int status; hw->eeprom.ops.init_params(hw); @@ -945,11 +945,11 @@ int ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, static int ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { + u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI; + u16 page_size; int status; u16 word; - u16 page_size; u16 i; - u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI; /* Prepare the EEPROM for writing */ status = ixgbe_acquire_eeprom(hw); @@ -1041,8 +1041,8 @@ int ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) int ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - int status; u16 i, count; + int status; hw->eeprom.ops.init_params(hw); @@ -1080,9 +1080,9 @@ int ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, static int ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - int status; - u16 word_in; u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; + u16 word_in; + int status; u16 i; /* Prepare the EEPROM for reading */ @@ -1152,8 +1152,8 @@ int ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, int ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - u32 eerd; int status; + u32 eerd; u32 i; hw->eeprom.ops.init_params(hw); @@ -1246,8 +1246,8 @@ int ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) int ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - u32 eewr; int status; + u32 eewr; u16 i; hw->eeprom.ops.init_params(hw); @@ -1742,9 +1742,9 @@ int ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw) int ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, u16 *checksum_val) { - int status; - u16 checksum; u16 read_checksum = 0; + u16 checksum; + int status; /* * Read the first word from the EEPROM. If this times out or fails, do @@ -1788,8 +1788,8 @@ int ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, **/ int ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw) { - int status; u16 checksum; + int status; /* * Read the first word from the EEPROM. If this times out or fails, do @@ -2736,10 +2736,10 @@ int ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval) **/ int ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) { - ixgbe_link_speed speed = 0; - bool link_up = false; u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + ixgbe_link_speed speed = 0; + bool link_up = false; bool locked = false; int ret_val; @@ -2784,9 +2784,9 @@ int ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) **/ int ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) { - u32 autoc_reg = 0; u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); bool locked = false; + u32 autoc_reg = 0; int ret_val; if (index > 3) @@ -2852,8 +2852,8 @@ static int ixgbe_get_san_mac_addr_offset(struct ixgbe_hw *hw, int ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) { u16 san_mac_data, san_mac_offset; - u8 i; int ret_val; + u8 i; /* * First read the EEPROM pointer to see if the MAC addresses are @@ -3682,8 +3682,8 @@ int ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer, { u32 hdr_size = sizeof(struct ixgbe_hic_hdr); struct ixgbe_hic_hdr *hdr = buffer; - u32 *u32arr = buffer; u16 buf_len, dword_len; + u32 *u32arr = buffer; int status; u32 bi; @@ -3758,8 +3758,8 @@ int ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, __always_unused const char *driver_ver) { struct ixgbe_hic_drv_info fw_cmd; - int i; int ret_val; + int i; fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; @@ -3905,11 +3905,11 @@ static int ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg, **/ int ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) { - int status; u16 ets_offset; - u16 ets_cfg; u16 ets_sensor; u8 num_sensors; + u16 ets_cfg; + int status; u8 i; struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; @@ -3961,15 +3961,15 @@ int ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) **/ int ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) { - int status; - u16 ets_offset; - u16 ets_cfg; - u16 ets_sensor; + struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; u8 low_thresh_delta; u8 num_sensors; u8 therm_limit; + u16 ets_sensor; + u16 ets_offset; + u16 ets_cfg; + int status; u8 i; - struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; memset(data, 0, sizeof(struct ixgbe_thermal_sensor_data)); @@ -4196,12 +4196,12 @@ int ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { - ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN; - int status = 0; - u32 speedcnt = 0; - u32 i = 0; + ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; bool autoneg, link_up = false; + u32 speedcnt = 0; + int status = 0; + u32 i = 0; /* Mask off requested but non-supported speeds */ status = hw->mac.ops.get_link_capabilities(hw, &link_speed, &autoneg); @@ -4340,8 +4340,8 @@ out: void ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed) { - int status; u8 rs, eeprom_data; + int status; switch (speed) { case IXGBE_LINK_SPEED_10GB_FULL: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 6058daca1876..b1e7338a4ed1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -3326,9 +3326,9 @@ static int ixgbe_get_module_info(struct net_device *dev, { struct ixgbe_adapter *adapter = netdev_priv(dev); struct ixgbe_hw *hw = &adapter->hw; - int status; u8 sff8472_rev, addr_mode; bool page_swap = false; + int status; if (hw->phy.type == ixgbe_phy_fw) return -ENXIO; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 471c1446267b..75e9453331ed 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -334,9 +334,9 @@ bool ixgbe_check_reset_blocked(struct ixgbe_hw *hw) **/ static int ixgbe_get_phy_id(struct ixgbe_hw *hw) { - int status; u16 phy_id_high = 0; u16 phy_id_low = 0; + int status; status = hw->phy.ops.read_reg(hw, MDIO_DEVID1, MDIO_MMD_PMAPMD, &phy_id_high); @@ -549,8 +549,8 @@ int ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, int ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data) { - int status; u32 gssr = hw->phy.phy_semaphore_mask; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type, @@ -647,8 +647,8 @@ int ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, int ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data) { - int status; u32 gssr = hw->phy.phy_semaphore_mask; + int status; if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, @@ -1097,10 +1097,10 @@ int ixgbe_mii_bus_init(struct ixgbe_hw *hw) **/ int ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) { - int status = 0; u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; - bool autoneg = false; ixgbe_link_speed speed; + bool autoneg = false; + int status = 0; ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); @@ -1279,12 +1279,12 @@ int ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, int ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up) { - int status; - u32 time_out; u32 max_time_out = 10; - u16 phy_link = 0; u16 phy_speed = 0; + u16 phy_link = 0; u16 phy_data = 0; + u32 time_out; + int status; /* Initialize speed and link to default case */ *link_up = false; @@ -1402,8 +1402,8 @@ int ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) int ixgbe_reset_phy_nl(struct ixgbe_hw *hw) { u16 phy_offset, control, eword, edata, block_crc; - bool end_data = false; u16 list_offset, data_offset; + bool end_data = false; u16 phy_data = 0; int ret_val; u32 i; @@ -1529,17 +1529,17 @@ int ixgbe_identify_module_generic(struct ixgbe_hw *hw) **/ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) { - struct ixgbe_adapter *adapter = hw->back; - int status; - u32 vendor_oui = 0; enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; - u8 identifier = 0; - u8 comp_codes_1g = 0; - u8 comp_codes_10g = 0; + struct ixgbe_adapter *adapter = hw->back; u8 oui_bytes[3] = {0, 0, 0}; + u8 comp_codes_10g = 0; + u8 comp_codes_1g = 0; + u16 enforce_sfp = 0; + u32 vendor_oui = 0; + u8 identifier = 0; u8 cable_tech = 0; u8 cable_spec = 0; - u16 enforce_sfp = 0; + int status; if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { hw->phy.sfp_type = ixgbe_sfp_type_not_present; @@ -2134,11 +2134,11 @@ static bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr) static int ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data, bool lock) { - int status; - u32 max_retry = 10; - u32 retry = 0; u32 swfw_mask = hw->phy.phy_semaphore_mask; + u32 max_retry = 10; bool nack = true; + u32 retry = 0; + int status; if (hw->mac.type >= ixgbe_mac_X550) max_retry = 3; @@ -2259,10 +2259,10 @@ int ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, static int ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data, bool lock) { - int status; + u32 swfw_mask = hw->phy.phy_semaphore_mask; u32 max_retry = 1; u32 retry = 0; - u32 swfw_mask = hw->phy.phy_semaphore_mask; + int status; if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) return -EBUSY; @@ -2424,8 +2424,8 @@ static void ixgbe_i2c_stop(struct ixgbe_hw *hw) **/ static int ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) { - int i; bool bit = false; + int i; *data = 0; for (i = 7; i >= 0; i--) { @@ -2445,10 +2445,10 @@ static int ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) **/ static int ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) { - int status; - int i; - u32 i2cctl; bool bit = false; + int status; + u32 i2cctl; + int i; for (i = 7; i >= 0; i--) { bit = (data >> i) & 0x1; @@ -2476,12 +2476,12 @@ static int ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) **/ static int ixgbe_get_i2c_ack(struct ixgbe_hw *hw) { - u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); - int status = 0; - u32 i = 0; u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); + u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); u32 timeout = 10; bool ack = true; + int status = 0; + u32 i = 0; if (data_oe_bit) { i2cctl |= IXGBE_I2C_DATA_OUT(hw); @@ -2561,8 +2561,8 @@ static int ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) **/ static int ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) { - int status; u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); + int status; status = ixgbe_set_i2c_data(hw, &i2cctl, data); if (status == 0) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 39357af77c64..f1ffa398f6df 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -68,9 +68,9 @@ int ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, **/ int ixgbe_reset_hw_X540(struct ixgbe_hw *hw) { - int status; - u32 ctrl, i; u32 swfw_mask = hw->phy.phy_semaphore_mask; + u32 ctrl, i; + int status; /* Call adapter stop to disable tx/rx and clear interrupts */ status = hw->mac.ops.stop_adapter(hw); @@ -382,9 +382,9 @@ static int ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) static int ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, u16 *checksum_val) { - int status; - u16 checksum; u16 read_checksum = 0; + u16 checksum; + int status; /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every @@ -441,8 +441,8 @@ out: **/ static int ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) { - int status; u16 checksum; + int status; /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every @@ -486,8 +486,8 @@ out: **/ static int ixgbe_update_flash_X540(struct ixgbe_hw *hw) { - u32 flup; int status; + u32 flup; status = ixgbe_poll_flash_update_done_X540(hw); if (status == -EIO) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index aec38de1921f..6419c159c1b1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -927,10 +927,10 @@ static int ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr, u16 size, u16 *csum, u16 *buffer, u32 buffer_size) { - u16 buf[256]; - int status; u16 length, bufsz, i, start; u16 *local_buffer; + u16 buf[256]; + int status; bufsz = ARRAY_SIZE(buf); @@ -995,10 +995,10 @@ static int ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size) { u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1]; - u16 *local_buffer; - int status; - u16 checksum = 0; u16 pointer, i, size; + u16 *local_buffer; + u16 checksum = 0; + int status; hw->eeprom.ops.init_params(hw); @@ -1121,9 +1121,9 @@ static int ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) static int ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val) { - int status; - u16 checksum; u16 read_checksum = 0; + u16 checksum; + int status; /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every @@ -1171,8 +1171,8 @@ static int ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, static int ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data) { - int status; struct ixgbe_hic_write_shadow_ram buffer; + int status; buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD; buffer.hdr.req.buf_lenh = 0; @@ -1218,8 +1218,8 @@ static int ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) **/ static int ixgbe_update_flash_X550(struct ixgbe_hw *hw) { - int status = 0; union ixgbe_hic_hdr2 buffer; + int status = 0; buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD; buffer.req.buf_lenh = 0; @@ -1269,9 +1269,9 @@ static bool ixgbe_fw_recovery_mode_X550(struct ixgbe_hw *hw) **/ static void ixgbe_disable_rx_x550(struct ixgbe_hw *hw) { + struct ixgbe_hic_disable_rxen fw_cmd; u32 rxctrl, pfdtxgswc; int status; - struct ixgbe_hic_disable_rxen fw_cmd; rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); if (rxctrl & IXGBE_RXCTRL_RXEN) { @@ -1313,8 +1313,8 @@ static void ixgbe_disable_rx_x550(struct ixgbe_hw *hw) **/ static int ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) { - int status; u16 checksum = 0; + int status; /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every @@ -1432,8 +1432,8 @@ out: **/ static int ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) { - int status; u32 reg_val; + int status; /* Disable training protocol FSM. */ status = ixgbe_read_iosf_sb_reg_x550(hw, @@ -1504,8 +1504,8 @@ static int ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) **/ static int ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw) { - int status; u32 link_ctrl; + int status; /* Restart auto-negotiation. */ status = hw->mac.ops.read_iosf_sb_reg(hw, @@ -1554,8 +1554,8 @@ static int ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw) static int ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) { struct ixgbe_mac_info *mac = &hw->mac; - int status; u32 reg_val; + int status; /* iXFI is only supported with X552 */ if (mac->type != ixgbe_mac_X550EM_x) @@ -1650,9 +1650,9 @@ ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, ixgbe_link_speed speed, __always_unused bool autoneg_wait_to_complete) { - int status; - u16 reg_slice, reg_val; bool setup_linear = false; + u16 reg_slice, reg_val; + int status; /* Check if SFP module is supported and linear */ status = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); @@ -1694,8 +1694,8 @@ ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, static int ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed) { struct ixgbe_mac_info *mac = &hw->mac; - int status; u32 reg_val; + int status; /* Disable all AN and force speed to 10G Serial. */ status = mac->ops.read_iosf_sb_reg(hw, @@ -1922,8 +1922,8 @@ static int ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait) { - int status; ixgbe_link_speed force_speed; + int status; /* Setup internal/external PHY link speed to iXFI (10G), unless * only 1G is auto advertised then setup KX link. @@ -2278,8 +2278,8 @@ static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) */ static int ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) { - int status; bool linear; + int status; /* Check if SFP module is supported */ status = ixgbe_supported_sfp_modules_X550em(hw, &linear); @@ -2582,8 +2582,8 @@ static int ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw, static int ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw, ixgbe_link_speed speed) { - int status; u32 reg_val; + int status; status = hw->mac.ops.read_iosf_sb_reg(hw, IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), @@ -2869,9 +2869,9 @@ static int ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min, static int ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed) { + u16 word = hw->eeprom.ctrl_word_3; u16 an_lp_status; int status; - u16 word = hw->eeprom.ctrl_word_3; *lcd_speed = IXGBE_LINK_SPEED_UNKNOWN; @@ -3076,10 +3076,10 @@ static void ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw) static int ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) { u16 an_10g_cntl_reg, autoneg_reg, speed; - int status; ixgbe_link_speed lcd_speed; u32 save_autoneg; bool link_up; + int status; /* If blocked by MNG FW, then don't restart AN */ if (ixgbe_check_reset_blocked(hw)) @@ -3443,12 +3443,12 @@ static void ixgbe_set_mdio_speed(struct ixgbe_hw *hw) **/ static int ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) { - ixgbe_link_speed link_speed; - int status; - u32 ctrl = 0; - u32 i; - bool link_up = false; u32 swfw_mask = hw->phy.phy_semaphore_mask; + ixgbe_link_speed link_speed; + bool link_up = false; + u32 ctrl = 0; + int status; + u32 i; /* Call adapter stop to disable Tx/Rx and clear interrupts */ status = hw->mac.ops.stop_adapter(hw); @@ -3611,8 +3611,8 @@ static void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, **/ static int ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw) { - int status = 0; u32 an_cntl = 0; + int status = 0; /* Validate the requested mode */ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { From ef3dd596504777266619252efff67149aa921ed3 Mon Sep 17 00:00:00 2001 From: Jedrzej Jagielski Date: Wed, 31 Jan 2024 12:04:19 +0100 Subject: [PATCH 0825/2255] ixgbe: Clarify the values of the returning status Converting s32 functions to regular int in the previous patch of the series caused triggering smatch warnings about missing error code. New smatch warnings: drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c:2884 ixgbe_get_lcd_t_x550em() warn: missing error code? 'status' drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c:3130 ixgbe_enter_lplu_t_x550em() warn: missing error code? 'status' Old smatch warnings: drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c:2890 ixgbe_get_lcd_t_x550em() warn: missing error code? 'status' Fix it by clearly stating returning error code as 0. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202401041701.6QKTsZmx-lkp@intel.com/ Reviewed-by: Simon Horman Signed-off-by: Jedrzej Jagielski Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 6419c159c1b1..2decb0710b6e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -2884,17 +2884,17 @@ static int ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, /* If link partner advertised 1G, return 1G */ if (an_lp_status & IXGBE_AUTO_NEG_LP_1000BASE_CAP) { *lcd_speed = IXGBE_LINK_SPEED_1GB_FULL; - return status; + return 0; } /* If 10G disabled for LPLU via NVM D10GMP, then return no valid LCD */ if ((hw->bus.lan_id && (word & NVM_INIT_CTRL_3_D10GMP_PORT1)) || (word & NVM_INIT_CTRL_3_D10GMP_PORT0)) - return status; + return 0; /* Link partner not capable of lower speeds, return 10G */ *lcd_speed = IXGBE_LINK_SPEED_10GB_FULL; - return status; + return 0; } /** @@ -3130,7 +3130,7 @@ static int ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) (lcd_speed == IXGBE_LINK_SPEED_1GB_FULL)) || ((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB) && (lcd_speed == IXGBE_LINK_SPEED_10GB_FULL))) - return status; + return 0; /* Clear AN completed indication */ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM, From 6cc9c6fbc79f64a0c5ebdaec77684888665d4ab3 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 5 Feb 2024 11:51:57 +0000 Subject: [PATCH 0826/2255] mlx4: Address spelling errors Address spelling errors flagged by codespell. This patch follows-up on an earlier patch by Colin Ian King, which addressed a spelling error in a user-visible log message [1]. This patch includes that change. [1] https://lore.kernel.org/netdev/20231209225135.4055334-1-colin.i.king@gmail.com/ This patch is intended to cover all files under drivers/net/ethernet/mellanox/mlx4 Signed-off-by: Simon Horman Reviewed-by: Tariq Toukan Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20240205-mlx5-codespell-v1-1-63b86dffbb61@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 7 ++++--- drivers/net/ethernet/mellanox/mlx4/cq.c | 4 ++-- drivers/net/ethernet/mellanox/mlx4/en_clock.c | 4 ++-- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 5 +++-- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 2 +- drivers/net/ethernet/mellanox/mlx4/eq.c | 2 +- drivers/net/ethernet/mellanox/mlx4/fw_qos.h | 8 ++++---- drivers/net/ethernet/mellanox/mlx4/main.c | 4 ++-- drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h | 2 +- drivers/net/ethernet/mellanox/mlx4/port.c | 2 +- 11 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index f5b1f8c7834f..7f20813456e2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2199,8 +2199,9 @@ reset_slave: if (cmd != MLX4_COMM_CMD_RESET) { mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n", slave, cmd); - /* Turn on internal error letting slave reset itself immeditaly, - * otherwise it might take till timeout on command is passed + /* Turn on internal error letting slave reset itself + * immediately, otherwise it might take till timeout on + * command is passed */ reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR); } @@ -2954,7 +2955,7 @@ static bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port, dummy_admin.default_vlan = vlan; /* VF wants to move to other VST state which is valid with current - * rate limit. Either differnt default vlan in VST or other + * rate limit. Either different default vlan in VST or other * supported QoS priority. Otherwise we don't allow this change when * the TX rate is still configured. */ diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index 4d4f9cf9facb..e130e7259275 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -115,7 +115,7 @@ void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn) return; } - /* Acessing the CQ outside of rcu_read_lock is safe, because + /* Accessing the CQ outside of rcu_read_lock is safe, because * the CQ is freed only after interrupt handling is completed. */ ++cq->arm_sn; @@ -137,7 +137,7 @@ void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type) return; } - /* Acessing the CQ outside of rcu_read_lock is safe, because + /* Accessing the CQ outside of rcu_read_lock is safe, because * the CQ is freed only after interrupt handling is completed. */ cq->event(cq, event_type); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 9e3b76182088..cd754cd76bde 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -96,8 +96,8 @@ void mlx4_en_remove_timestamp(struct mlx4_en_dev *mdev) #define MLX4_EN_WRAP_AROUND_SEC 10UL /* By scheduling the overflow check every 5 seconds, we have a reasonably - * good chance we wont miss a wrap around. - * TOTO: Use a timer instead of a work queue to increase the guarantee. + * good chance we won't miss a wrap around. + * TODO: Use a timer instead of a work queue to increase the guarantee. */ #define MLX4_EN_OVERFLOW_PERIOD (MLX4_EN_WRAP_AROUND_SEC * HZ / 2) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 33bbcced8105..d7da62cda821 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1072,7 +1072,8 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, 1, MLX4_MCAST_CONFIG); /* Update multicast list - we cache all addresses so they won't - * change while HW is updated holding the command semaphor */ + * change while HW is updated holding the command semaphore + */ netif_addr_lock_bh(dev); mlx4_en_cache_mclist(dev); netif_addr_unlock_bh(dev); @@ -1817,7 +1818,7 @@ int mlx4_en_start_port(struct net_device *dev) mlx4_en_set_rss_steer_rules(priv)) mlx4_warn(mdev, "Failed setting steering rules\n"); - /* Attach rx QP to bradcast address */ + /* Attach rx QP to broadcast address */ eth_broadcast_addr(&mc_list[10]); mc_list[5] = priv->port; /* needed for B0 steering support */ if (mlx4_multicast_attach(mdev->dev, priv->rss_map.indir_qp, mc_list, diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index a09b6e05337d..eac49657bd07 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -762,7 +762,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud /* Drop packet on bad receive or bad checksum */ if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_ERROR)) { - en_err(priv, "CQE completed in error - vendor syndrom:%d syndrom:%d\n", + en_err(priv, "CQE completed in error - vendor syndrome:%d syndrome:%d\n", ((struct mlx4_err_cqe *)cqe)->vendor_err_syndrome, ((struct mlx4_err_cqe *)cqe)->syndrome); goto next; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 65cb63f6c465..1ddb11cb25f9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -992,7 +992,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) tx_info->ts_requested = 1; } - /* Prepare ctrl segement apart opcode+ownership, which depends on + /* Prepare ctrl segment apart opcode+ownership, which depends on * whether LSO is used */ tx_desc->ctrl.srcrb_flags = priv->ctrl_flags; if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 6598b10a9ff4..9572a45f6143 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -210,7 +210,7 @@ static void slave_event(struct mlx4_dev *dev, u8 slave, struct mlx4_eqe *eqe) memcpy(s_eqe, eqe, sizeof(struct mlx4_eqe) - 1); s_eqe->slave_id = slave; - /* ensure all information is written before setting the ownersip bit */ + /* ensure all information is written before setting the ownership bit */ dma_wmb(); s_eqe->owner = !!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE) ? 0x0 : 0x80; ++slave_eq->prod; diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h index 954b86faac29..40ca29bb928c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h @@ -44,7 +44,7 @@ /* Default supported priorities for VPP allocation */ #define MLX4_DEFAULT_QOS_PRIO (0) -/* Derived from FW feature definition, 0 is the default vport fo all QPs */ +/* Derived from FW feature definition, 0 is the default vport for all QPs */ #define MLX4_VPP_DEFAULT_VPORT (0) struct mlx4_vport_qos_param { @@ -98,7 +98,7 @@ int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, int mlx4_ALLOCATE_VPP_get(struct mlx4_dev *dev, u8 port, u16 *available_vpp, u8 *vpp_p_up); /** - * mlx4_ALLOCATE_VPP_set - Distribution of VPPs among differnt priorities. + * mlx4_ALLOCATE_VPP_set - Distribution of VPPs among different priorities. * The total number of VPPs assigned to all for a port must not exceed * the value reported by available_vpp in mlx4_ALLOCATE_VPP_get. * VPP allocation is allowed only after the port type has been set, @@ -113,7 +113,7 @@ int mlx4_ALLOCATE_VPP_get(struct mlx4_dev *dev, u8 port, int mlx4_ALLOCATE_VPP_set(struct mlx4_dev *dev, u8 port, u8 *vpp_p_up); /** - * mlx4_SET_VPORT_QOS_get - Query QoS proporties of a Vport. + * mlx4_SET_VPORT_QOS_get - Query QoS properties of a Vport. * Each priority allowed for the Vport is assigned with a share of the BW, * and a BW limitation. This commands query the current QoS values. * @@ -128,7 +128,7 @@ int mlx4_SET_VPORT_QOS_get(struct mlx4_dev *dev, u8 port, u8 vport, struct mlx4_vport_qos_param *out_param); /** - * mlx4_SET_VPORT_QOS_set - Set QoS proporties of a Vport. + * mlx4_SET_VPORT_QOS_set - Set QoS properties of a Vport. * QoS parameters can be modified at any time, but must be initialized * before any QP is associated with the VPort. * diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 2581226836b5..7b02ff61126d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -129,7 +129,7 @@ static const struct mlx4_profile default_profile = { .num_cq = 1 << 16, .num_mcg = 1 << 13, .num_mpt = 1 << 19, - .num_mtt = 1 << 20, /* It is really num mtt segements */ + .num_mtt = 1 << 20, /* It is really num mtt segments */ }; static const struct mlx4_profile low_mem_profile = { @@ -1508,7 +1508,7 @@ static int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p) priv->v2p.port1 = port1; priv->v2p.port2 = port2; } else { - mlx4_err(dev, "Failed to change port mape: %d\n", err); + mlx4_err(dev, "Failed to change port map: %d\n", err); } } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h index e9cd4bb6f83d..d3d9ec042d2c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h @@ -112,7 +112,7 @@ struct mlx4_en_stat_out_flow_control_mbox { __be64 tx_pause_duration; /* Number of transmitter transitions from XOFF state to XON state */ __be64 tx_pause_transition; - /* Reserverd */ + /* Reserved */ __be64 reserved[2]; }; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 256a06b3c096..4e43f4a7d246 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -2118,7 +2118,7 @@ static void mlx4_qsfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset) * @data: output buffer to put the requested data into. * * Reads cable module eeprom data, puts the outcome data into - * data pointer paramer. + * data pointer parameter. * Returns num of read bytes on success or a negative error * code. */ From 7b4434a8face07aa1a9737637e58de028a5972d8 Mon Sep 17 00:00:00 2001 From: Alessandro Marcolini Date: Sat, 3 Feb 2024 14:16:51 +0100 Subject: [PATCH 0827/2255] tools: ynl: correct typo and docstring Correct typo in SpecAttr docstring. Changed SpecSubMessageFormat docstring. Signed-off-by: Alessandro Marcolini Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/6ab1dea7fb1f635c0d8b237f03a49eaa448c2bf4.1706962013.git.alessandromarcolini99@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/nlspec.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 5d197a12ab8d..fbce52395b3b 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -144,7 +144,7 @@ class SpecEnumSet(SpecElement): class SpecAttr(SpecElement): - """ Single Netlink atttribute type + """ Single Netlink attribute type Represents a single attribute type within an attr space. @@ -308,10 +308,9 @@ class SpecSubMessage(SpecElement): class SpecSubMessageFormat(SpecElement): - """ Netlink sub-message definition + """ Netlink sub-message format definition - Represents a set of sub-message formats for polymorphic nlattrs - that contain type-specific sub messages. + Represents a single format for a sub-message. Attributes: value attribute value to match against type selector From 70ff9a91e86850103f71d5920eff6bee81bd2a0d Mon Sep 17 00:00:00 2001 From: Alessandro Marcolini Date: Sat, 3 Feb 2024 14:16:52 +0100 Subject: [PATCH 0828/2255] doc: netlink: specs: tc: add multi-attr to tc-taprio-sched-entry Add multi-attr attribute to tc-taprio-sched-entry to specify multiple entries. Signed-off-by: Alessandro Marcolini Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/0ba5088ea715103a2bce83b12e2dcbdaa08da6ac.1706962013.git.alessandromarcolini99@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/tc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/netlink/specs/tc.yaml b/Documentation/netlink/specs/tc.yaml index 4b21b00dbebe..324fa182cd14 100644 --- a/Documentation/netlink/specs/tc.yaml +++ b/Documentation/netlink/specs/tc.yaml @@ -3376,6 +3376,7 @@ attribute-sets: name: entry type: nest nested-attributes: tc-taprio-sched-entry + multi-attr: true - name: tc-taprio-sched-entry attributes: From b9bcfc3bc978f7b81104d2c01d4fe29a6f45e17a Mon Sep 17 00:00:00 2001 From: Alessandro Marcolini Date: Sat, 3 Feb 2024 14:16:53 +0100 Subject: [PATCH 0829/2255] tools: ynl: add support for encoding multi-attr Multi-attr elements could not be encoded because of missing logic in the ynl code. Enable encoding of these attributes by checking if the attribute is a multi-attr and if the value to be processed is a list. This has been tested both with the taprio and ets qdisc which contain this kind of attributes. Signed-off-by: Alessandro Marcolini Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/c5bc9f5797168dbf7a4379c42f38d5de8ac7f38a.1706962013.git.alessandromarcolini99@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 0f4193cc2e3b..03c7ca6aaae9 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -444,6 +444,13 @@ class YnlFamily(SpecFamily): except KeyError: raise Exception(f"Space '{space}' has no attribute '{name}'") nl_type = attr.value + + if attr.is_multi and isinstance(value, list): + attr_payload = b'' + for subvalue in value: + attr_payload += self._add_attr(space, name, subvalue, search_attrs) + return attr_payload + if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED attr_payload = b'' From b64691274f5d33fc9d93af73483162967f7ec5bb Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 3 Feb 2024 20:53:15 +0100 Subject: [PATCH 0830/2255] net: phy: add helper phy_advertise_eee_all Per default phylib preserves the EEE advertising at the time of phy probing. The EEE advertising can be changed from user space, in addition this helper allows to set the EEE advertising to all supported modes from drivers in kernel space. Suggested-by: Andrew Lunn Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20bfc471-aeeb-4ae4-ba09-7d6d4be6b86a@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy_device.c | 16 ++++++++++++++++ include/linux/phy.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2eed8f03621d..839e42f9e16a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2777,6 +2777,22 @@ void phy_advertise_supported(struct phy_device *phydev) } EXPORT_SYMBOL(phy_advertise_supported); +/** + * phy_advertise_eee_all - Advertise all supported EEE modes + * @phydev: target phy_device struct + * + * Description: Per default phylib preserves the EEE advertising at the time of + * phy probing, which might be a subset of the supported EEE modes. Use this + * function when all supported EEE modes should be advertised. This does not + * trigger auto-negotiation, so must be called before phy_start()/ + * phylink_start() which will start auto-negotiation. + */ +void phy_advertise_eee_all(struct phy_device *phydev) +{ + linkmode_copy(phydev->advertising_eee, phydev->supported_eee); +} +EXPORT_SYMBOL_GPL(phy_advertise_eee_all); + /** * phy_support_sym_pause - Enable support of symmetrical pause * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index ad93f8b1b128..fd8dbea9b4d9 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1960,6 +1960,7 @@ int phy_get_rate_matching(struct phy_device *phydev, void phy_set_max_speed(struct phy_device *phydev, u32 max_speed); void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode); void phy_advertise_supported(struct phy_device *phydev); +void phy_advertise_eee_all(struct phy_device *phydev); void phy_support_sym_pause(struct phy_device *phydev); void phy_support_asym_pause(struct phy_device *phydev); void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx, From 7cc0187ea2522bae916e443e66a8952b71e667e2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 3 Feb 2024 20:54:48 +0100 Subject: [PATCH 0831/2255] r8169: use new helper phy_advertise_eee_all Use new helper phy_advertise_eee_all() to simplify the code. Reviewed-by: Andrew Lunn Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/ddedd82e-55da-4db5-acc6-9407c03f168c@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index c7086953974e..b43db3c49d82 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5091,8 +5091,7 @@ static int r8169_mdio_register(struct rtl8169_private *tp) tp->phydev->mac_managed_pm = true; if (rtl_supports_eee(tp)) - linkmode_copy(tp->phydev->advertising_eee, - tp->phydev->supported_eee); + phy_advertise_eee_all(tp->phydev); phy_support_asym_pause(tp->phydev); /* PHY will be woken up in rtl_open() */ From 9bc791341bc9a5c22b94889aa37993bb69faa317 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 3 Feb 2024 22:12:50 +0100 Subject: [PATCH 0832/2255] tg3: convert EEE handling to use linkmode bitmaps Convert EEE handling to use linkmode bitmaps. This prepares for removing the legacy bitmaps from struct ethtool_keee. No functional change intended. Note: The change to mii_eee_cap1_mod_linkmode_t(tp->eee.advertised, val) in tg3_phy_autoneg_cfg() isn't completely obvious, but it doesn't change the current functionality. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/0652b910-6bcc-421f-8769-38f7dae5037e@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/tg3.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index f644a91317c9..50f674031f72 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2362,13 +2362,13 @@ static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_keee *eee) /* Pull lp advertised settings */ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &val)) return; - dest->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(dest->lp_advertised, val); /* Pull advertised and eee_enabled settings */ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val)) return; dest->eee_enabled = !!val; - dest->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(dest->advertised, val); /* Pull tx_lpi_enabled */ val = tr32(TG3_CPMU_EEE_MODE); @@ -4364,11 +4364,9 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) if (!tp->eee.eee_enabled) { val = 0; - tp->eee.advertised_u32 = 0; + linkmode_zero(tp->eee.advertised); } else { - tp->eee.advertised_u32 = advertise & - (ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full); + mii_eee_cap1_mod_linkmode_t(tp->eee.advertised, val); } err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); @@ -4626,13 +4624,13 @@ static bool tg3_phy_eee_config_ok(struct tg3 *tp) tg3_eee_pull_config(tp, &eee); if (tp->eee.eee_enabled) { - if (tp->eee.advertised_u32 != eee.advertised_u32 || + if (!linkmode_equal(tp->eee.advertised, eee.advertised) || tp->eee.tx_lpi_timer != eee.tx_lpi_timer || tp->eee.tx_lpi_enabled != eee.tx_lpi_enabled) return false; } else { /* EEE is disabled but we're advertising */ - if (eee.advertised_u32) + if (!linkmode_empty(eee.advertised)) return false; } @@ -14189,7 +14187,7 @@ static int tg3_set_eee(struct net_device *dev, struct ethtool_keee *edata) return -EOPNOTSUPP; } - if (edata->advertised_u32 != tp->eee.advertised_u32) { + if (!linkmode_equal(edata->advertised, tp->eee.advertised)) { netdev_warn(tp->dev, "Direct manipulation of EEE advertisement is not supported\n"); return -EINVAL; @@ -15655,10 +15653,13 @@ static int tg3_phy_probe(struct tg3 *tp) tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0))) { tp->phy_flags |= TG3_PHYFLG_EEE_CAP; - tp->eee.supported_u32 = SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full; - tp->eee.advertised_u32 = ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full; + linkmode_zero(tp->eee.supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + tp->eee.supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + tp->eee.supported); + linkmode_copy(tp->eee.advertised, tp->eee.supported); + tp->eee.eee_enabled = 1; tp->eee.tx_lpi_enabled = 1; tp->eee.tx_lpi_timer = TG3_CPMU_DBTMR1_LNKIDLE_2047US; From 23c5ae6d467520987dbc8682c3ae6ea0e80a5f27 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Feb 2024 10:35:31 +0800 Subject: [PATCH 0833/2255] netlabel: cleanup struct netlbl_lsm_catmap Simplify the code from macro NETLBL_CATMAP_MAPTYPE to u64, and fix warning "Macros with complex values should be enclosed in parentheses" on "#define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01", which is modified to "#define NETLBL_CATMAP_BIT ((u64)0x01)". Signed-off-by: George Guo Acked-by: Paul Moore Signed-off-by: David S. Miller --- include/net/netlabel.h | 7 +++---- net/netlabel/netlabel_kapi.c | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 43ae50337685..f3ab0b8a4b18 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -145,15 +145,14 @@ struct netlbl_lsm_cache { * processing. * */ -#define NETLBL_CATMAP_MAPTYPE u64 #define NETLBL_CATMAP_MAPCNT 4 -#define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8) +#define NETLBL_CATMAP_MAPSIZE (sizeof(u64) * 8) #define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \ NETLBL_CATMAP_MAPCNT) -#define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01 +#define NETLBL_CATMAP_BIT ((u64)0x01) struct netlbl_lsm_catmap { u32 startbit; - NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; + u64 bitmap[NETLBL_CATMAP_MAPCNT]; struct netlbl_lsm_catmap *next; }; diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 27511c90a26f..7b844581ebee 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -610,7 +610,7 @@ int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset) struct netlbl_lsm_catmap *iter; u32 idx; u32 bit; - NETLBL_CATMAP_MAPTYPE bitmap; + u64 bitmap; iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); if (iter == NULL) @@ -666,8 +666,8 @@ int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset) struct netlbl_lsm_catmap *prev = NULL; u32 idx; u32 bit; - NETLBL_CATMAP_MAPTYPE bitmask; - NETLBL_CATMAP_MAPTYPE bitmap; + u64 bitmask; + u64 bitmap; iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); if (iter == NULL) @@ -857,7 +857,7 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, offset -= iter->startbit; idx = offset / NETLBL_CATMAP_MAPSIZE; - iter->bitmap[idx] |= (NETLBL_CATMAP_MAPTYPE)bitmap + iter->bitmap[idx] |= (u64)bitmap << (offset % NETLBL_CATMAP_MAPSIZE); return 0; From 81f61c108838190a3e00bcb8f973966b7a90794c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 4 Feb 2024 21:31:51 +0900 Subject: [PATCH 0834/2255] net: ethernet: remove duplicated CONFIG_SUNGEM_PHY entry Both drivers/net/Kconfig and drivers/net/ethernet/Kconfig contain the same config entry: config SUNGEM_PHY tristate Commit f860b0522f65 ("drivers/net: Kconfig and Makefile cleanup") moved SUNGEM_PHY from drivers/net/Kconfig to drivers/net/ethernet/Kconfig. Shortly after it was applied, commit 19e2f6fe9601 ("net: Fix sungem_phy sharing.") added the second one to drivers/net/Kconfig. I kept the one in drivers/net/Kconfig because this CONFIG option controls the compilation of drivers/net/sungem_phy.c. Signed-off-by: Masahiro Yamada Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 5a274b99f299..6a19b5393ed1 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -15,9 +15,6 @@ if ETHERNET config MDIO tristate -config SUNGEM_PHY - tristate - source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/actions/Kconfig" source "drivers/net/ethernet/adaptec/Kconfig" From 59d6bccebe5c747d6f4dcbc4862ad7b52571b3fc Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 4 Feb 2024 22:12:26 +0900 Subject: [PATCH 0835/2255] net: tipc: remove redundant 'bool' from CONFIG_TIPC_{MEDIA_UDP,CRYPTO} The 'bool' is already specified for these options. The second 'bool' under the help message is redundant. While I am here, I moved 'default y' above, as it is common to place the help text last. Signed-off-by: Masahiro Yamada Reviewed-by: Randy Dunlap Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/tipc/Kconfig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig index be1c4003d67d..bb0d71eb02a6 100644 --- a/net/tipc/Kconfig +++ b/net/tipc/Kconfig @@ -32,16 +32,17 @@ config TIPC_MEDIA_UDP bool "IP/UDP media type support" depends on TIPC select NET_UDP_TUNNEL + default y help Saying Y here will enable support for running TIPC over IP/UDP - bool - default y + config TIPC_CRYPTO bool "TIPC encryption support" depends on TIPC select CRYPTO select CRYPTO_AES select CRYPTO_GCM + default y help Saying Y here will enable support for TIPC encryption. All TIPC messages will be encrypted/decrypted by using the currently most @@ -49,8 +50,6 @@ config TIPC_CRYPTO entering the TIPC stack. Key setting from user-space is performed via netlink by a user program (e.g. the iproute2 'tipc' tool). - bool - default y config TIPC_DIAG tristate "TIPC: socket monitoring interface" From 56b93cd358b304b2d1945c0330dffe8f872bc0d3 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 17:16:34 -0300 Subject: [PATCH 0836/2255] netdevsim: make nsim_bus const Now that the driver core can properly handle constant struct bus_type, move the nsim_bus variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/net/netdevsim/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index bcbc1e19edde..aedab1d9623a 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -260,7 +260,7 @@ static int nsim_num_vf(struct device *dev) return nsim_bus_dev->num_vfs; } -static struct bus_type nsim_bus = { +static const struct bus_type nsim_bus = { .name = DRV_NAME, .dev_name = DRV_NAME, .bus_groups = nsim_bus_groups, From 17b447539408a0feff81637c7cc1c4c68efa73c0 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 4 Feb 2024 17:14:14 -0600 Subject: [PATCH 0837/2255] net: phy: c45 scanning: Don't consider -ENODEV fatal When scanning the MDIO bus for C22 devices, the driver returning -ENODEV is not considered fatal, it just indicates the MDIO bus master knows there is no device at that address, maybe because of hardware limitation. Make the C45 scan code act on -ENODEV the same way, to make C22 and C45 more uniform. It is expected all reads for a given address will return -ENODEV, so within get_phy_c45_ids() only the first place a read occurs has been changed. Reviewed-by: Florian Fainelli Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 839e42f9e16a..2e7d5bfb338e 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -780,7 +780,7 @@ static int get_phy_c45_devs_in_pkg(struct mii_bus *bus, int addr, int dev_addr, * and identifiers in @c45_ids. * * Returns zero on success, %-EIO on bus access error, or %-ENODEV if - * the "devices in package" is invalid. + * the "devices in package" is invalid or no device responds. */ static int get_phy_c45_ids(struct mii_bus *bus, int addr, struct phy_c45_device_ids *c45_ids) @@ -803,7 +803,11 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr, */ ret = phy_c45_probe_present(bus, addr, i); if (ret < 0) - return -EIO; + /* returning -ENODEV doesn't stop bus + * scanning + */ + return (phy_reg == -EIO || + phy_reg == -ENODEV) ? -ENODEV : -EIO; if (!ret) continue; From 88b3934e3f31e15b40896aa8ebb0a8040d150c1c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 4 Feb 2024 17:14:15 -0600 Subject: [PATCH 0838/2255] net: dsa: mv88e6xxx: Return -ENODEV when C45 not supported MDIO bus drivers can return -ENODEV when they know the bus does not have a device at the given address, e.g. because of hardware limitation. One such limitation is that the bus does not support C45 at all. This is more efficient than returning 0xffff, since it immediately stops the probing on the given address, where as further reads can be made when 0xffff is returned. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 6eec2e4aa031..9caecb4dfbfa 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3659,7 +3659,7 @@ static int mv88e6xxx_mdio_read_c45(struct mii_bus *bus, int phy, int devad, int err; if (!chip->info->ops->phy_read_c45) - return 0xffff; + return -ENODEV; mv88e6xxx_reg_lock(chip); err = chip->info->ops->phy_read_c45(chip, bus, phy, devad, reg, &val); From 4f684533afe2317b5338209cbad4551bae7949a2 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:27 +0200 Subject: [PATCH 0839/2255] wifi: ath12k: fix broken structure wmi_vdev_create_cmd Current structure wmi_vdev_create_cmd is not matched to the firmware definition. So update it. And update vdev_stats_id_valid for vdev_stats_id. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-2-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 3 +++ drivers/net/wireless/ath/ath12k/wmi.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 5acbed4f64f2..49ac8d4ccbef 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -824,6 +824,9 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr, cmd->vdev_stats_id = cpu_to_le32(args->if_stats_id); ether_addr_copy(cmd->vdev_macaddr.addr, macaddr); + if (args->if_stats_id != ATH12K_INVAL_VDEV_STATS_ID) + cmd->vdev_stats_id_valid = cpu_to_le32(BIT(0)); + ptr = skb->data + sizeof(*cmd); len = WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index dceb55ca153a..61b2dd1d32cd 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2724,6 +2724,9 @@ struct wmi_vdev_create_cmd { struct ath12k_wmi_mac_addr_params vdev_macaddr; __le32 num_cfg_txrx_streams; __le32 pdev_id; + __le32 mbssid_flags; + __le32 mbssid_tx_vdev_id; + __le32 vdev_stats_id_valid; __le32 vdev_stats_id; } __packed; From 019b58dcb6ed267e17b7efd03ec8575c1b67d942 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:27 +0200 Subject: [PATCH 0840/2255] wifi: ath12k: fix incorrect logic of calculating vdev_stats_id During calculate vdev_stats_id, will compare vdev_stats_id with ATH12K_INVAL_VDEV_STATS_ID by '<='. If vdev_stats_id is relatively small, then assign ATH12K_INVAL_VDEV_STATS_ID to vdev_stats_id. This logic is incorrect. Firstly, should use '>=' instead of '<=' to check if this u8 variable exceeds the max valid range. Secondly, should use the maximum value as comparison value. Correct comparison symbols and use the maximum value ATH12K_MAX_VDEV_STATS_ID for comparison. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-3-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index fb5bf500ed87..078dda43dded 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5421,7 +5421,7 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) do { if (ab->free_vdev_stats_id_map & (1LL << vdev_stats_id)) { vdev_stats_id++; - if (vdev_stats_id <= ATH12K_INVAL_VDEV_STATS_ID) { + if (vdev_stats_id >= ATH12K_MAX_VDEV_STATS_ID) { vdev_stats_id = ATH12K_INVAL_VDEV_STATS_ID; break; } From ef860c6a3adfc5f3fc5b5c96fc0e1856c944a1d1 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:27 +0200 Subject: [PATCH 0841/2255] wifi: ath12k: change interface combination for P2P mode Current interface combination doesn't support P2P mode. Change the combination for P2P mode. Also, there is a bug that when mesh is enabled but ap is not enabled. In this situation, the mesh's max_interface of interface combination won't be set. So assign the max_interfaces for mesh directly. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-4-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 078dda43dded..f2920a3401c6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7539,9 +7539,10 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; - bool ap, mesh; + bool ap, mesh, p2p; ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP); + p2p = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_P2P_DEVICE); mesh = IS_ENABLED(CONFIG_MAC80211_MESH) && ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT); @@ -7550,9 +7551,15 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) if (!combinations) return -ENOMEM; - if (ap || mesh) { + if ((ap || mesh) && !p2p) { n_limits = 2; max_interfaces = 16; + } else if (p2p) { + n_limits = 3; + if (ap || mesh) + max_interfaces = 16; + else + max_interfaces = 3; } else { n_limits = 1; max_interfaces = 1; @@ -7567,14 +7574,22 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) limits[0].max = 1; limits[0].types |= BIT(NL80211_IFTYPE_STATION); - if (ap) { + if (ap || mesh || p2p) limits[1].max = max_interfaces; + + if (ap) limits[1].types |= BIT(NL80211_IFTYPE_AP); - } if (mesh) limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + if (p2p) { + limits[1].types |= BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + limits[2].max = 1; + limits[2].types |= BIT(NL80211_IFTYPE_P2P_DEVICE); + } + combinations[0].limits = limits; combinations[0].n_limits = n_limits; combinations[0].max_interfaces = max_interfaces; From 575ec73cb8803b4e149df5ff5cdb9f1ce3735554 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:28 +0200 Subject: [PATCH 0842/2255] wifi: ath12k: add P2P IE in beacon template P2P Element is a necessary component of P2P protocol communication. It contains the Vendor Specific Information Element which includes the WFA OUI and an OUI Type indicating P2P. Add P2P IE in beacon template, and implement WMI interface for it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-5-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 84 ++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.c | 42 ++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 8 +++ 3 files changed, 132 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f2920a3401c6..7bfc6ee6567c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1139,6 +1139,63 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) return ret; } +static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_vif *arvif, + struct sk_buff *bcn) +{ + struct ath12k *ar = arvif->ar; + struct ieee80211_mgmt *mgmt; + const u8 *p2p_ie; + int ret; + + mgmt = (void *)bcn->data; + p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt->u.beacon.variable, + bcn->len - (mgmt->u.beacon.variable - + bcn->data)); + if (!p2p_ie) { + ath12k_warn(ar->ab, "no P2P ie found in beacon\n"); + return -ENOENT; + } + + ret = ath12k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); + if (ret) { + ath12k_warn(ar->ab, "failed to submit P2P GO bcn ie for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, + u8 oui_type, size_t ie_offset) +{ + const u8 *next, *end; + size_t len; + u8 *ie; + + if (WARN_ON(skb->len < ie_offset)) + return -EINVAL; + + ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ie_offset, + skb->len - ie_offset); + if (!ie) + return -ENOENT; + + len = ie[1] + 2; + end = skb->data + skb->len; + next = ie + len; + + if (WARN_ON(next > end)) + return -EINVAL; + + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); + + return 0; +} + static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { struct ath12k *ar = arvif->ar; @@ -1171,14 +1228,37 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) ies, (skb_tail_pointer(bcn) - ies))) arvif->wpaie_present = true; - ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) { + ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn); + if (ret) { + ath12k_warn(ab, "failed to setup P2P GO bcn ie: %d\n", + ret); + goto free_bcn_skb; + } - kfree_skb(bcn); + /* P2P IE is inserted by firmware automatically (as + * configured above) so remove it from the base beacon + * template to avoid duplicate P2P IEs in beacon frames. + */ + ret = ath12k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, + offsetof(struct ieee80211_mgmt, + u.beacon.variable)); + if (ret) { + ath12k_warn(ab, "failed to remove P2P vendor ie: %d\n", + ret); + goto free_bcn_skb; + } + } + + ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); if (ret) ath12k_warn(ab, "failed to submit beacon template command: %d\n", ret); +free_bcn_skb: + kfree_skb(bcn); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 49ac8d4ccbef..61fc7ec86985 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1712,6 +1712,48 @@ int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar, return ret; } +int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, + const u8 *p2p_ie) +{ + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct wmi_p2p_go_set_beacon_ie_cmd *cmd; + size_t p2p_ie_len, aligned_len; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + int ret, len; + + p2p_ie_len = p2p_ie[1] + 2; + aligned_len = roundup(p2p_ie_len, sizeof(u32)); + + len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; + + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + ptr = skb->data; + cmd = ptr; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_P2P_GO_SET_BEACON_IE, + sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(vdev_id); + cmd->ie_buf_len = cpu_to_le32(p2p_ie_len); + + ptr += sizeof(*cmd); + tlv = ptr; + tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ARRAY_BYTE, + aligned_len); + memcpy(tlv->value, p2p_ie, p2p_ie_len); + + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_P2P_GO_SET_BEACON_IE); + if (ret) { + ath12k_warn(ar->ab, "failed to send WMI_P2P_GO_SET_BEACON_IE\n"); + dev_kfree_skb(skb); + } + + return ret; +} + int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 61b2dd1d32cd..c5002468b1de 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3518,6 +3518,12 @@ struct wmi_bcn_tmpl_cmd { __le32 esp_ie_offset; } __packed; +struct wmi_p2p_go_set_beacon_ie_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 ie_buf_len; +} __packed; + struct wmi_vdev_install_key_cmd { __le32 tlv_header; __le32 vdev_id; @@ -4831,6 +4837,8 @@ int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len); int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, struct sk_buff *frame); +int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, + const u8 *p2p_ie); int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn); From 9411eecb60cbc36edcbd47176e2bec85776e62e3 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:28 +0200 Subject: [PATCH 0843/2255] wifi: ath12k: implement handling of P2P NoA event The Notice of Absence (NoA) attribute is used by the P2P Group Owner to signal its absence due to power save timing, concurrent operation, or off-channel scanning. It is also used in the P2P Presence Request-Response mechanism. The NoA attribute shall be present in the P2P IE in the beacon frames transmitted by a P2P Group Owner when a NoA schedule is being advertised, or when the CTWindow is non-zero. So add support to update P2P information after P2P GO is up through event WMI_P2P_NOA_EVENTID, and always put it in probe resp. Create p2p.c and p2p.h for P2P related functions and definitions. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-6-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/Makefile | 3 +- drivers/net/wireless/ath/ath12k/mac.c | 28 ++++- drivers/net/wireless/ath/ath12k/p2p.c | 142 +++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/p2p.h | 23 ++++ drivers/net/wireless/ath/ath12k/wmi.c | 57 ++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 31 +++++ 6 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 drivers/net/wireless/ath/ath12k/p2p.c create mode 100644 drivers/net/wireless/ath/ath12k/p2p.h diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 0d723e85cf6b..71669f94ff75 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -20,7 +20,8 @@ ath12k-y += core.o \ mhi.o \ pci.o \ dp_mon.o \ - fw.o + fw.o \ + p2p.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 7bfc6ee6567c..ceb5be5a6a95 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5173,6 +5173,27 @@ static int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb, return 0; } +static void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar, + struct ieee80211_vif *vif, + struct sk_buff *skb, + bool is_prb_rsp) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + if (likely(!is_prb_rsp)) + return; + + spin_lock_bh(&ar->data_lock); + + if (arvif->u.ap.noa_data && + !pskb_expand_head(skb, 0, arvif->u.ap.noa_len, + GFP_ATOMIC)) + skb_put_data(skb, arvif->u.ap.noa_data, + arvif->u.ap.noa_len); + + spin_unlock_bh(&ar->data_lock); +} + static void ath12k_mac_op_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -5196,10 +5217,11 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, skb_cb->flags |= ATH12K_SKB_CIPHER_SET; } + is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); + if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP; } else if (ieee80211_is_mgmt(hdr->frame_control)) { - is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp); if (ret) { ath12k_warn(ar->ab, "failed to queue management frame %d\n", @@ -5209,6 +5231,10 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, return; } + /* This is case only for P2P_GO */ + if (vif->type == NL80211_IFTYPE_AP && vif->p2p) + ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp); + ret = ath12k_dp_tx(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c new file mode 100644 index 000000000000..61e919b23b16 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "core.h" +#include "mac.h" +#include "p2p.h" + +static void ath12k_p2p_noa_ie_fill(u8 *data, size_t len, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ieee80211_p2p_noa_attr *noa_attr; + u8 ctwindow = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_CTWIN_TU); + bool oppps = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS); + __le16 *noa_attr_len; + u16 attr_len; + u8 noa_descriptors = le32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + int i; + + /* P2P IE */ + data[0] = WLAN_EID_VENDOR_SPECIFIC; + data[1] = len - 2; + data[2] = (WLAN_OUI_WFA >> 16) & 0xff; + data[3] = (WLAN_OUI_WFA >> 8) & 0xff; + data[4] = (WLAN_OUI_WFA >> 0) & 0xff; + data[5] = WLAN_OUI_TYPE_WFA_P2P; + + /* NOA ATTR */ + data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE; + noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */ + noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9]; + + noa_attr->index = le32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_INDEX); + noa_attr->oppps_ctwindow = ctwindow; + if (oppps) + noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; + + for (i = 0; i < noa_descriptors; i++) { + noa_attr->desc[i].count = + __le32_to_cpu(noa->descriptors[i].type_count); + noa_attr->desc[i].duration = noa->descriptors[i].duration; + noa_attr->desc[i].interval = noa->descriptors[i].interval; + noa_attr->desc[i].start_time = noa->descriptors[i].start_time; + } + + attr_len = 2; /* index + oppps_ctwindow */ + attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); + *noa_attr_len = __cpu_to_le16(attr_len); +} + +static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info *noa) +{ + size_t len = 0; + + if (!(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)) && + !(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS))) + return 0; + + len += 1 + 1 + 4; /* EID + len + OUI */ + len += 1 + 2; /* noa attr + attr len */ + len += 1 + 1; /* index + oppps_ctwindow */ + len += le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM) * + sizeof(struct ieee80211_p2p_noa_desc); + + return len; +} + +static void ath12k_p2p_noa_ie_assign(struct ath12k_vif *arvif, void *ie, + size_t len) +{ + struct ath12k *ar = arvif->ar; + + lockdep_assert_held(&ar->data_lock); + + kfree(arvif->u.ap.noa_data); + + arvif->u.ap.noa_data = ie; + arvif->u.ap.noa_len = len; +} + +static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k *ar = arvif->ar; + void *ie; + size_t len; + + lockdep_assert_held(&ar->data_lock); + + ath12k_p2p_noa_ie_assign(arvif, NULL, 0); + + len = ath12k_p2p_noa_ie_len_compute(noa); + if (!len) + return; + + ie = kmalloc(len, GFP_ATOMIC); + if (!ie) + return; + + ath12k_p2p_noa_ie_fill(ie, len, noa); + ath12k_p2p_noa_ie_assign(arvif, ie, len); +} + +void ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k *ar = arvif->ar; + + spin_lock_bh(&ar->data_lock); + __ath12k_p2p_noa_update(arvif, noa); + spin_unlock_bh(&ar->data_lock); +} + +static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_p2p_noa_arg *arg = data; + + if (arvif->vdev_id != arg->vdev_id) + return; + + ath12k_p2p_noa_update(arvif, arg->noa); +} + +void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k_p2p_noa_arg arg = { + .vdev_id = vdev_id, + .noa = noa, + }; + + ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), + IEEE80211_IFACE_ITER_NORMAL, + ath12k_p2p_noa_update_vdev_iter, + &arg); +} diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h new file mode 100644 index 000000000000..b6f177fe4ff4 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/p2p.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.. + */ + +#ifndef ATH12K_P2P_H +#define ATH12K_P2P_H + +#include "wmi.h" + +struct ath12k_wmi_p2p_noa_info; + +struct ath12k_p2p_noa_arg { + u32 vdev_id; + const struct ath12k_wmi_p2p_noa_info *noa; +}; + +void ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa); +void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, + const struct ath12k_wmi_p2p_noa_info *noa); + +#endif diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 61fc7ec86985..ff086428fb0c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -19,6 +19,7 @@ #include "mac.h" #include "hw.h" #include "peer.h" +#include "p2p.h" struct ath12k_wmi_svc_ready_parse { bool wmi_svc_bitmap_done; @@ -166,6 +167,10 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_twt_enable_event) }, [WMI_TAG_TWT_DISABLE_COMPLETE_EVENT] = { .min_len = sizeof(struct wmi_twt_disable_event) }, + [WMI_TAG_P2P_NOA_INFO] = { + .min_len = sizeof(struct ath12k_wmi_p2p_noa_info) }, + [WMI_TAG_P2P_NOA_EVENT] = { + .min_len = sizeof(struct wmi_p2p_noa_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -1053,7 +1058,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, 0); /* Note: This is a nested TLV containing: - * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. + * [wmi_tlv][ath12k_wmi_p2p_noa_descriptor][wmi_tlv].. */ ptr += sizeof(*tlv); @@ -6678,6 +6683,53 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, kfree(tb); } +static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_p2p_noa_event *ev; + const struct ath12k_wmi_p2p_noa_info *noa; + struct ath12k *ar; + int ret, vdev_id; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse P2P NoA TLV: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_P2P_NOA_EVENT]; + noa = tb[WMI_TAG_P2P_NOA_INFO]; + + if (!ev || !noa) { + ret = -EPROTO; + goto out; + } + + vdev_id = __le32_to_cpu(ev->vdev_id); + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi tlv p2p noa vdev_id %i descriptors %u\n", + vdev_id, le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)); + + ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath12k_warn(ab, "invalid vdev id %d in P2P NoA event\n", + vdev_id); + ret = -EINVAL; + goto out; + } + + ath12k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa); + + ret = 0; + +out: + kfree(tb); + return ret; +} + static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, struct sk_buff *skb) { @@ -6877,6 +6929,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_TWT_DISABLE_EVENTID: ath12k_wmi_twt_disable_event(ab, skb); break; + case WMI_P2P_NOA_EVENTID: + ath12k_wmi_p2p_noa_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index c5002468b1de..be6bf93f091d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3504,6 +3504,37 @@ struct wmi_get_pdev_temperature_cmd { __le32 pdev_id; } __packed; +#define WMI_P2P_MAX_NOA_DESCRIPTORS 4 + +struct wmi_p2p_noa_event { + __le32 vdev_id; +} __packed; + +struct ath12k_wmi_p2p_noa_descriptor { + __le32 type_count; /* 255: continuous schedule, 0: reserved */ + __le32 duration; /* Absent period duration in micro seconds */ + __le32 interval; /* Absent period interval in micro seconds */ + __le32 start_time; /* 32 bit tsf time when in starts */ +} __packed; + +#define WMI_P2P_NOA_INFO_CHANGED_FLAG BIT(0) +#define WMI_P2P_NOA_INFO_INDEX GENMASK(15, 8) +#define WMI_P2P_NOA_INFO_OPP_PS BIT(16) +#define WMI_P2P_NOA_INFO_CTWIN_TU GENMASK(23, 17) +#define WMI_P2P_NOA_INFO_DESC_NUM GENMASK(31, 24) + +struct ath12k_wmi_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + * Bits 15-8 - Index (identifies the instance of NOA sub element) + * Bit 16 - Opp PS state of the AP + * Bits 23-17 - Ctwindow in TUs + * Bits 31-24 - Number of NOA descriptors + */ + __le32 noa_attr; + struct ath12k_wmi_p2p_noa_descriptor descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + #define WMI_BEACON_TX_BUFFER_SIZE 512 struct wmi_bcn_tmpl_cmd { From 2830bc9e784ff18ecb0eafd53d0bdae32c478c16 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:29 +0200 Subject: [PATCH 0844/2255] wifi: ath12k: implement remain on channel for P2P mode Implement remain on channel for p2p mode in ath12k_ops: ath12k_mac_op_remain_on_channel ath12k_mac_op_cancel_remain_on_channel P2P device can trigger ROC scan. Then keep listening or sending management frames on particular channels. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-7-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/mac.c | 122 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.c | 8 ++ 3 files changed, 131 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index b82550b35149..391b6fb2bd42 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -988,6 +988,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) ath12k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); + complete(&ar->scan.on_channel); complete(&ar->peer_assoc_done); complete(&ar->peer_delete_done); complete(&ar->install_key_done); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ceb5be5a6a95..dbaef009e972 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7451,6 +7451,125 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } +static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + ar->scan.roc_notify = false; + spin_unlock_bh(&ar->data_lock); + + ath12k_scan_abort(ar); + + mutex_unlock(&ar->conf_mutex); + + cancel_delayed_work_sync(&ar->scan.timeout); + + return 0; +} + +static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, + int duration, + enum ieee80211_roc_type type) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k_wmi_scan_req_arg arg; + struct ath12k *ar; + u32 scan_time_msec; + int ret; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->data_lock); + + switch (ar->scan.state) { + case ATH12K_SCAN_IDLE: + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + reinit_completion(&ar->scan.on_channel); + ar->scan.state = ATH12K_SCAN_STARTING; + ar->scan.is_roc = true; + ar->scan.vdev_id = arvif->vdev_id; + ar->scan.roc_freq = chan->center_freq; + ar->scan.roc_notify = true; + ret = 0; + break; + case ATH12K_SCAN_STARTING: + case ATH12K_SCAN_RUNNING: + case ATH12K_SCAN_ABORTING: + ret = -EBUSY; + break; + } + + spin_unlock_bh(&ar->data_lock); + + if (ret) + goto exit; + + scan_time_msec = hw->wiphy->max_remain_on_channel_duration * 2; + + memset(&arg, 0, sizeof(arg)); + ath12k_wmi_start_scan_init(ar, &arg); + arg.num_chan = 1; + arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), + GFP_KERNEL); + if (!arg.chan_list) { + ret = -ENOMEM; + goto exit; + } + + arg.vdev_id = arvif->vdev_id; + arg.scan_id = ATH12K_SCAN_ID; + arg.chan_list[0] = chan->center_freq; + arg.dwell_time_active = scan_time_msec; + arg.dwell_time_passive = scan_time_msec; + arg.max_scan_time = scan_time_msec; + arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg.burst_duration = duration; + + ret = ath12k_start_scan(ar, &arg); + if (ret) { + ath12k_warn(ar->ab, "failed to start roc scan: %d\n", ret); + + spin_lock_bh(&ar->data_lock); + ar->scan.state = ATH12K_SCAN_IDLE; + spin_unlock_bh(&ar->data_lock); + goto free_chan_list; + } + + ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ); + if (ret == 0) { + ath12k_warn(ar->ab, "failed to switch to channel for roc scan\n"); + ret = ath12k_scan_stop(ar); + if (ret) + ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret); + ret = -ETIMEDOUT; + goto free_chan_list; + } + + ieee80211_queue_delayed_work(hw, &ar->scan.timeout, + msecs_to_jiffies(duration)); + + ret = 0; + +free_chan_list: + kfree(arg.chan_list); +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + static const struct ieee80211_ops ath12k_ops = { .tx = ath12k_mac_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, @@ -7485,6 +7604,8 @@ static const struct ieee80211_ops ath12k_ops = { .get_survey = ath12k_mac_op_get_survey, .flush = ath12k_mac_op_flush, .sta_statistics = ath12k_mac_op_sta_statistics, + .remain_on_channel = ath12k_mac_op_remain_on_channel, + .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, }; static void ath12k_mac_update_ch_list(struct ath12k *ar, @@ -8012,6 +8133,7 @@ static void ath12k_mac_setup(struct ath12k *ar) init_completion(&ar->bss_survey_done); init_completion(&ar->scan.started); init_completion(&ar->scan.completed); + init_completion(&ar->scan.on_channel); INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index ff086428fb0c..37cfd607c043 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -5059,6 +5059,10 @@ static void ath12k_wmi_event_scan_started(struct ath12k *ar) break; case ATH12K_SCAN_STARTING: ar->scan.state = ATH12K_SCAN_RUNNING; + + if (ar->scan.is_roc) + ieee80211_ready_on_channel(ath12k_ar_to_hw(ar)); + complete(&ar->scan.started); break; } @@ -5143,6 +5147,10 @@ static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq) case ATH12K_SCAN_RUNNING: case ATH12K_SCAN_ABORTING: ar->scan_channel = ieee80211_get_channel(hw->wiphy, freq); + + if (ar->scan.is_roc && ar->scan.roc_freq == freq) + complete(&ar->scan.on_channel); + break; } } From 28035a88f8b3cc849e4b13b9b5f5dd0aa1e18365 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:29 +0200 Subject: [PATCH 0845/2255] wifi: ath12k: change WLAN_SCAN_PARAMS_MAX_IE_LEN from 256 to 512 Mac80211 needs more space for P2P scan ie in P2P mode, 256 is not enough, resize it to 512. Also delete the duplicate macro definitions in wmi.h. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-8-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index be6bf93f091d..4bd1d0f270a1 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -168,10 +168,6 @@ struct wmi_tlv { #define WLAN_SCAN_MAX_HINT_BSSID 10 #define MAX_RNR_BSS 5 -#define WLAN_SCAN_PARAMS_MAX_SSID 16 -#define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 - #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 #define WMI_BA_MODE_BUFFER_SIZE_256 3 @@ -3161,7 +3157,7 @@ struct ath12k_wmi_element_info_arg { #define WLAN_SCAN_PARAMS_MAX_SSID 16 #define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +#define WLAN_SCAN_PARAMS_MAX_IE_LEN 512 /* Values lower than this may be refused by some firmware revisions with a scan * completion with a timedout reason. From 32e7b12e2611e6b49510a3b36c0ba4deafac10c7 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:29 +0200 Subject: [PATCH 0846/2255] wifi: ath12k: allow specific mgmt frame tx while vdev is not up In current code, the management frames must be sent after vdev is started. But for P2P device, vdev won't start until P2P negotiation is done. So this logic doesn't make sense for P2P device. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-9-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index dbaef009e972..04a4a7c0eedf 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5123,8 +5123,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) } arvif = ath12k_vif_to_arvif(skb_cb->vif); - if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && - arvif->is_started) { + + if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", From c9e4e41e71ffaf3f6ff1fafcb96fda92a12dc2f5 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:30 +0200 Subject: [PATCH 0847/2255] wifi: ath12k: move peer delete after vdev stop of station for WCN7850 In current code, when STA/P2P Client connect to AP/P2P GO, the WMI command sequence is: peer_create->vdev_start->vdev_up And sequence of STA/P2P Client disconnect from AP/P2P GO is: peer_delete->vdev_down->vdev_stop This sequence of disconnect is not opposite of connect. For STA or P2P GO, bss peer is not needed by firmware during handling vdev stop command. So with this sequence, STA and P2P GO can work normally. But for P2P Client, firmware needs bss peer in some functions during handling vdev stop command. The opposite sequence of disconnect should be: vdev_down->vdev_stop->peer_delete So change the sequence of disconnect as above opposite sequence for WCN7850. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-10-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 99 +++++++++++++++------------ 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 04a4a7c0eedf..810be179e8b6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1084,6 +1084,46 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) return ret; } +static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_setup_done); + + ret = ath12k_wmi_vdev_stop(ar, arvif->vdev_id); + if (ret) { + ath12k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", + arvif->vdev_id, ret); + goto err; + } + + ret = ath12k_mac_vdev_setup_sync(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n", + arvif->vdev_id, ret); + goto err; + } + + WARN_ON(ar->num_started_vdevs == 0); + + ar->num_started_vdevs--; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", + arvif->vif->addr, arvif->vdev_id); + + if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { + clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", + arvif->vdev_id); + } + + return 0; +err: + return ret; +} + static int ath12k_mac_config(struct ath12k *ar, u32 changed) { struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); @@ -3959,6 +3999,13 @@ static int ath12k_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)) { + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { + ath12k_bss_disassoc(ar, arvif); + ret = ath12k_mac_vdev_stop(arvif); + if (ret) + ath12k_warn(ar->ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + } ath12k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); ret = ath12k_peer_delete(ar, arvif->vdev_id, sta->addr); @@ -6395,46 +6442,6 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, return 0; } -static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) -{ - struct ath12k *ar = arvif->ar; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - reinit_completion(&ar->vdev_setup_done); - - ret = ath12k_wmi_vdev_stop(ar, arvif->vdev_id); - if (ret) { - ath12k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", - arvif->vdev_id, ret); - goto err; - } - - ret = ath12k_mac_vdev_setup_sync(ar); - if (ret) { - ath12k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n", - arvif->vdev_id, ret); - goto err; - } - - WARN_ON(ar->num_started_vdevs == 0); - - ar->num_started_vdevs--; - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", - arvif->vif->addr, arvif->vdev_id); - - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { - clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", - arvif->vdev_id); - } - - return 0; -err: - return ret; -} - static int ath12k_mac_vdev_start(struct ath12k_vif *arvif, struct ieee80211_chanctx_conf *ctx) { @@ -6801,11 +6808,13 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = false; } - ret = ath12k_mac_vdev_stop(arvif); - if (ret) - ath12k_warn(ab, "failed to stop vdev %i: %d\n", - arvif->vdev_id, ret); - + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) { + ath12k_bss_disassoc(ar, arvif); + ret = ath12k_mac_vdev_stop(arvif); + if (ret) + ath12k_warn(ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + } arvif->is_started = false; if (ab->hw_params->vdev_start_delay && From cf0425eead75687078369e48691b8a5f624885cd Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:30 +0200 Subject: [PATCH 0848/2255] wifi: ath12k: designating channel frequency for ROC scan For P2P mode, the WLAN interface may be requested to remain on a specific channel and then to send some management frames on that channel. Now chananel frequency of wmi_mgmt_send_cmd is set as 0. As a result, firmware may choose a default but wrong channel. Fix it by assigning chanfreq field with the ROC channel frequency. This change only applies to WCN7850, other chips are not affected. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-11-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 37cfd607c043..84d7d6584fba 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -730,6 +730,20 @@ static int ath12k_service_ready_event(struct ath12k_base *ab, struct sk_buff *sk return 0; } +static u32 ath12k_wmi_mgmt_get_freq(struct ath12k *ar, + struct ieee80211_tx_info *info) +{ + struct ath12k_base *ab = ar->ab; + u32 freq = 0; + + if (ab->hw_params->single_pdev_only && + ar->scan.is_roc && + (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) + freq = ar->scan.roc_freq; + + return freq; +} + struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len) { struct sk_buff *skb; @@ -755,6 +769,7 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, { struct ath12k_wmi_pdev *wmi = ar->wmi; struct wmi_mgmt_send_cmd *cmd; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame); struct wmi_tlv *frame_tlv; struct sk_buff *skb; u32 buf_len; @@ -773,7 +788,7 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, sizeof(*cmd)); cmd->vdev_id = cpu_to_le32(vdev_id); cmd->desc_id = cpu_to_le32(buf_id); - cmd->chanfreq = 0; + cmd->chanfreq = cpu_to_le32(ath12k_wmi_mgmt_get_freq(ar, info)); cmd->paddr_lo = cpu_to_le32(lower_32_bits(ATH12K_SKB_CB(frame)->paddr)); cmd->paddr_hi = cpu_to_le32(upper_32_bits(ATH12K_SKB_CB(frame)->paddr)); cmd->frame_len = cpu_to_le32(frame->len); From e65a6398657561831b8a1a5aa3ec43ff24c428f2 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 5 Feb 2024 19:03:31 +0200 Subject: [PATCH 0849/2255] wifi: ath12k: advertise P2P dev support for WCN7850 Now that all the necessary pieces are implemented we can enable P2P support for WCN7850. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240130040303.370590-12-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 5 ++++- drivers/net/wireless/ath/ath12k/mac.c | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 6e2242a79a2f..0b17dfd47856 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -956,7 +956,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .vdev_start_delay = true, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .idle_ps = true, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 810be179e8b6..a3b002d77a07 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5799,17 +5799,29 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; + + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; + break; case NL80211_IFTYPE_MESH_POINT: arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; fallthrough; case NL80211_IFTYPE_AP: arvif->vdev_type = WMI_VDEV_TYPE_AP; + + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; + break; case NL80211_IFTYPE_MONITOR: arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ar->monitor_vdev_id = bit; break; + case NL80211_IFTYPE_P2P_DEVICE: + arvif->vdev_type = WMI_VDEV_TYPE_STA; + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + break; default: WARN_ON(1); break; From d7a5c7cde2cb6b5d83e1c95892d6bc4650c0a3a2 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 5 Feb 2024 08:16:18 -0800 Subject: [PATCH 0850/2255] wifi: ath11k: Really consistently use ath11k_vif_to_arvif() Commit 9476cda44c13 ("wifi: ath11k: Consistently use ath11k_vif_to_arvif()") previously replaced all open coding of the ath11k_vif_to_arvif() functionality. Subsequently two more instances of open coding were introduced, one in commit 92425f788fee ("wifi: ath11k: fill parameters for vdev set tpc power WMI command") and one in commit 6f4e235be655 ("wifi: ath11k: add parse of transmit power envelope element"), so fix those as well. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240205-ath11k_vif_to_arvif-v1-1-7c41313c8318@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index dc2bf13f00c1..be04f823566f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7590,7 +7590,7 @@ void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath11k_base *ab = ar->ab; - struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); 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; @@ -7764,7 +7764,7 @@ static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath11k_base *ab = ar->ab; - struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ieee80211_tx_pwr_env *single_tpe; enum wmi_reg_6ghz_client_type client_type; From 04edb5dc68f4356fd8df44c04547a729dc44f43e Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 5 Feb 2024 12:49:53 -0700 Subject: [PATCH 0851/2255] wifi: ath12k: Fix uninitialized use of ret in ath12k_mac_allocate() Clang warns (or errors with CONFIG_WERROR=y): drivers/net/wireless/ath/ath12k/mac.c:8060:9: error: variable 'ret' is uninitialized when used here [-Werror,-Wuninitialized] 8060 | return ret; | ^~~ drivers/net/wireless/ath/ath12k/mac.c:8022:9: note: initialize the variable 'ret' to silence this warning 8022 | int ret, i, j; | ^ | = 0 1 error generated. Commit 6db6e70a17f6 ("wifi: ath12k: Introduce the container for mac80211 hw") added a completely uninitialized use of ret. Prior to that change, -ENOMEM was returned to the callers of ath12k_mac_allocate() whenever ath12k_mac_hw_allocate() failed. Assign that value to ret to make sure it is always initialized when used and clear up the warning. Closes: https://github.com/ClangBuiltLinux/linux/issues/1989i Fixes: 6db6e70a17f6 ("wifi: ath12k: Introduce the container for mac80211 hw") Signed-off-by: Nathan Chancellor Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240205-ath12k-mac-wuninitialized-v1-1-3fda7b17357f@kernel.org --- drivers/net/wireless/ath/ath12k/mac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a3b002d77a07..a737a09a0b9c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8302,6 +8302,7 @@ int ath12k_mac_allocate(struct ath12k_base *ab) if (!ah) { ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n", i); + ret = -ENOMEM; goto err; } From 0cb6daf549f99cc978fe4dd531d2426313fc08e4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 4 Feb 2024 12:13:02 +0000 Subject: [PATCH 0852/2255] net: stmmac: remove eee_enabled/eee_active in stmmac_ethtool_op_get_eee() stmmac_ethtool_op_get_eee() sets both eee_enabled and eee_active, and then goes on to call phylink_ethtool_get_eee(). phylink_ethtool_get_eee() will return -EOPNOTSUPP if there is no PHY present, otherwise calling phy_ethtool_get_eee() which in turn will call genphy_c45_ethtool_get_eee(). genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active with its own interpretation from the PHYs settings and negotiation result. Thus, when there is no PHY, stmmac_ethtool_op_get_eee() will fail with -EOPNOTSUPP, meaning eee_enabled and eee_active will not be returned to userspace. When there is a PHY, eee_enabled and eee_active will be overwritten by phylib, making the setting of these members in stmmac_ethtool_op_get_eee() entirely unnecessary. Remove this code, thus simplifying stmmac_ethtool_op_get_eee(). Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Russell King (Oracle) Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/E1rWbMs-002cCV-EE@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index bbecb3b89535..411c3ac8cb17 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -859,8 +859,6 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, if (!priv->dma_cap.eee) return -EOPNOTSUPP; - edata->eee_enabled = priv->eee_enabled; - edata->eee_active = priv->eee_active; edata->tx_lpi_timer = priv->tx_lpi_timer; edata->tx_lpi_enabled = priv->tx_lpi_enabled; From d0d8c548789d45391c7c592fb763fab2fee0f632 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 4 Feb 2024 12:13:07 +0000 Subject: [PATCH 0853/2255] net: sxgbe: remove eee_enabled/eee_active in sxgbe_get_eee() sxgbe_get_eee() sets edata->eee_active and edata->eee_enabled from its own copy, and then calls phy_ethtool_get_eee() which in turn will call genphy_c45_ethtool_get_eee(). genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active with its own interpretation from the PHYs settings and negotiation result. Therefore, setting these members in sxgbe_get_eee() is redundant. Remove this, and remove the priv->eee_active member which then becomes a write-only variable. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1rWbMx-002cCb-IU@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h | 1 - drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c | 2 -- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 1 - 3 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h index d14e0cfc3a6b..1458939c3bf5 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h @@ -503,7 +503,6 @@ struct sxgbe_priv_data { bool tx_path_in_lpi_mode; int lpi_irq; int eee_enabled; - int eee_active; int tx_lpi_timer; }; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c index d93b628b7046..4a439b34114d 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c @@ -140,8 +140,6 @@ static int sxgbe_get_eee(struct net_device *dev, if (!priv->hw_cap.eee) return -EOPNOTSUPP; - edata->eee_enabled = priv->eee_enabled; - edata->eee_active = priv->eee_active; edata->tx_lpi_timer = priv->tx_lpi_timer; return phy_ethtool_get_eee(dev->phydev, edata); diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 71439825ea4e..ecbe3994f2b1 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -130,7 +130,6 @@ bool sxgbe_eee_init(struct sxgbe_priv_data * const priv) if (phy_init_eee(ndev->phydev, true)) return false; - priv->eee_active = 1; timer_setup(&priv->eee_ctrl_timer, sxgbe_eee_ctrl_timer, 0); priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer); add_timer(&priv->eee_ctrl_timer); From b573cb0a55866830586eb26ce53e1163c1580667 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 4 Feb 2024 12:13:12 +0000 Subject: [PATCH 0854/2255] net: fec: remove eee_enabled/eee_active in fec_enet_get_eee() fec_enet_get_eee() sets edata->eee_active and edata->eee_enabled from its own copy, and then calls phy_ethtool_get_eee() which in turn will call genphy_c45_ethtool_get_eee(). genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active with its own interpretation from the PHYs settings and negotiation result. Therefore, setting these members in fec_enet_get_eee() is redundant. Remove this, and remove the setting of fep->eee.eee_active member which becomes a write-only variable. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1rWbN2-002cCh-MY@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fec_main.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 63707e065141..42bdc01a304e 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3139,8 +3139,6 @@ static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) } p->tx_lpi_enabled = enable; - p->eee_enabled = enable; - p->eee_active = enable; writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP); writel(wake_cycle, fep->hwp + FEC_LPI_WAKE); @@ -3160,8 +3158,6 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata) if (!netif_running(ndev)) return -ENETDOWN; - edata->eee_enabled = p->eee_enabled; - edata->eee_active = p->eee_active; edata->tx_lpi_timer = p->tx_lpi_timer; edata->tx_lpi_enabled = p->tx_lpi_enabled; From 409359c1c2ef30788477b150c8837d8714117d13 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 4 Feb 2024 12:13:17 +0000 Subject: [PATCH 0855/2255] net: bcmgenet: remove eee_enabled/eee_active in bcmgenet_get_eee() bcmgenet_get_eee() sets edata->eee_active and edata->eee_enabled from its own copy, and then calls phy_ethtool_get_eee() which in turn will call genphy_c45_ethtool_get_eee(). genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active with its own interpretation from the PHYs settings and negotiation result. Therefore, setting these members in bcmgenet_get_eee() is redundant, and can be removed. This also makes priv->eee.eee_active unnecessary, so remove this and use a local variable where appropriate. Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1rWbN7-002cCn-RO@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 8 +++----- drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 +++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 051c31fb17c2..7396e2823e32 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1313,7 +1313,6 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable, } priv->eee.eee_enabled = enable; - priv->eee.eee_active = enable; priv->eee.tx_lpi_enabled = tx_lpi_enabled; } @@ -1328,8 +1327,6 @@ static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_keee *e) if (!dev->phydev) return -ENODEV; - e->eee_enabled = p->eee_enabled; - e->eee_active = p->eee_active; e->tx_lpi_enabled = p->tx_lpi_enabled; e->tx_lpi_timer = bcmgenet_umac_readl(priv, UMAC_EEE_LPI_TIMER); @@ -1340,6 +1337,7 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmgenet_priv *priv = netdev_priv(dev); struct ethtool_keee *p = &priv->eee; + bool active; if (GENET_IS_V1(priv)) return -EOPNOTSUPP; @@ -1352,9 +1350,9 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e) if (!p->eee_enabled) { bcmgenet_eee_enable_set(dev, false, false); } else { - p->eee_active = phy_init_eee(dev->phydev, false) >= 0; + active = phy_init_eee(dev->phydev, false) >= 0; bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER); - bcmgenet_eee_enable_set(dev, p->eee_active, e->tx_lpi_enabled); + bcmgenet_eee_enable_set(dev, active, e->tx_lpi_enabled); } return phy_ethtool_set_eee(dev->phydev, e); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 97ea76d443ab..cbbe004621bc 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -30,6 +30,7 @@ static void bcmgenet_mac_config(struct net_device *dev) struct bcmgenet_priv *priv = netdev_priv(dev); struct phy_device *phydev = dev->phydev; u32 reg, cmd_bits = 0; + bool active; /* speed */ if (phydev->speed == SPEED_1000) @@ -88,9 +89,9 @@ static void bcmgenet_mac_config(struct net_device *dev) } bcmgenet_umac_writel(priv, reg, UMAC_CMD); - priv->eee.eee_active = phy_init_eee(phydev, 0) >= 0; + active = phy_init_eee(phydev, 0) >= 0; bcmgenet_eee_enable_set(dev, - priv->eee.eee_enabled && priv->eee.eee_active, + priv->eee.eee_enabled && active, priv->eee.tx_lpi_enabled); } From 0cbfdfe3fb806e90e9c146974b250d7227f26790 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 4 Feb 2024 12:13:22 +0000 Subject: [PATCH 0856/2255] net: bcmasp: remove eee_enabled/eee_active in bcmasp_get_eee() bcmasp_get_eee() sets edata->eee_active and edata->eee_enabled from its own copy, and then calls phy_ethtool_get_eee() which in turn will call genphy_c45_ethtool_get_eee(). genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active with its own interpretation from the PHYs settings and negotiation result. Therefore, setting these members in bcmasp_get_eee() is redundant, and can be removed. This also makes intf->eee.eee_active unnecessary, so remove this and use a local variable where appropriate. Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1rWbNC-002cCt-W7@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c | 4 ---- drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c index 2851bed153e6..484fc2b5626f 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c @@ -360,7 +360,6 @@ void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable) umac_wl(intf, reg, UMC_EEE_CTRL); intf->eee.eee_enabled = enable; - intf->eee.eee_active = enable; } static int bcmasp_get_eee(struct net_device *dev, struct ethtool_keee *e) @@ -371,8 +370,6 @@ static int bcmasp_get_eee(struct net_device *dev, struct ethtool_keee *e) if (!dev->phydev) return -ENODEV; - e->eee_enabled = p->eee_enabled; - e->eee_active = p->eee_active; e->tx_lpi_enabled = p->tx_lpi_enabled; e->tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER); @@ -399,7 +396,6 @@ static int bcmasp_set_eee(struct net_device *dev, struct ethtool_keee *e) } umac_wl(intf, e->tx_lpi_timer, UMC_EEE_LPI_TIMER); - intf->eee.eee_active = ret >= 0; intf->eee.tx_lpi_enabled = e->tx_lpi_enabled; bcmasp_eee_enable_set(intf, true); } diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index 53e542881255..3a15f269c7d1 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -607,6 +607,7 @@ static void bcmasp_adj_link(struct net_device *dev) struct phy_device *phydev = dev->phydev; u32 cmd_bits = 0, reg; int changed = 0; + bool active; if (intf->old_link != phydev->link) { changed = 1; @@ -658,8 +659,8 @@ static void bcmasp_adj_link(struct net_device *dev) reg |= cmd_bits; umac_wl(intf, reg, UMC_CMD); - intf->eee.eee_active = phy_init_eee(phydev, 0) >= 0; - bcmasp_eee_enable_set(intf, intf->eee.eee_active); + active = phy_init_eee(phydev, 0) >= 0; + bcmasp_eee_enable_set(intf, active); } reg = rgmii_rl(intf, RGMII_OOB_CNTRL); From 3465df5533af94af8e3d3a524329e21a7698618c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 4 Feb 2024 12:13:28 +0000 Subject: [PATCH 0857/2255] net: dsa: b53: remove eee_enabled/eee_active in b53_get_mac_eee() b53_get_mac_eee() sets both eee_enabled and eee_active, and then returns zero. dsa_slave_get_eee(), which calls this function, will then continue to call phylink_ethtool_get_eee(), which will return -EOPNOTSUPP if there is no PHY present, otherwise calling phy_ethtool_get_eee() which in turn will call genphy_c45_ethtool_get_eee(). genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active with its own interpretation from the PHYs settings and negotiation result. Thus, when there is no PHY, dsa_slave_get_eee() will fail with -EOPNOTSUPP, meaning eee_enabled and eee_active will not be returned to userspace. When there is a PHY, eee_enabled and eee_active will be overwritten by phylib, making the setting of these members in b53_get_mac_eee() entirely unnecessary. Remove this code, thus simplifying b53_get_mac_eee(). Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Russell King (Oracle) Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/E1rWbNI-002cCz-4x@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index adc93abf4551..9e4c9bd6abcc 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2227,16 +2227,10 @@ EXPORT_SYMBOL(b53_eee_init); int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e) { struct b53_device *dev = ds->priv; - struct ethtool_keee *p = &dev->ports[port].eee; - u16 reg; if (is5325(dev) || is5365(dev)) return -EOPNOTSUPP; - b53_read16(dev, B53_EEE_PAGE, B53_EEE_LPI_INDICATE, ®); - e->eee_enabled = p->eee_enabled; - e->eee_active = !!(reg & BIT(port)); - return 0; } EXPORT_SYMBOL(b53_get_mac_eee); From d160c66cda0ac8614adc53a5b5b0e6d6f1a05a5b Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 5 Feb 2024 12:30:22 +0200 Subject: [PATCH 0858/2255] net: Do not return value from init_dummy_netdev() init_dummy_netdev() always returns zero and all the callers do not check the returned value. Set the function to not return value, as it is not really used today. Signed-off-by: Amit Cohen Reviewed-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240205103022.440946-1-amcohen@nvidia.com Signed-off-by: Jakub Kicinski --- include/linux/netdevice.h | 2 +- net/core/dev.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 118c40258d07..1845dd5043b4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3198,7 +3198,7 @@ static inline void unregister_netdevice(struct net_device *dev) int netdev_refcnt_read(const struct net_device *dev); void free_netdev(struct net_device *dev); void netdev_freemem(struct net_device *dev); -int init_dummy_netdev(struct net_device *dev); +void init_dummy_netdev(struct net_device *dev); struct net_device *netdev_get_xmit_slave(struct net_device *dev, struct sk_buff *skb, diff --git a/net/core/dev.c b/net/core/dev.c index 27ba057d06c4..e52e2888cccd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10345,7 +10345,7 @@ EXPORT_SYMBOL(register_netdevice); * that need to tie several hardware interfaces to a single NAPI * poll scheduler due to HW limitations. */ -int init_dummy_netdev(struct net_device *dev) +void init_dummy_netdev(struct net_device *dev) { /* Clear everything. Note we don't initialize spinlocks * are they aren't supposed to be taken by any of the @@ -10373,8 +10373,6 @@ int init_dummy_netdev(struct net_device *dev) * because users of this 'device' dont need to change * its refcount. */ - - return 0; } EXPORT_SYMBOL_GPL(init_dummy_netdev); From c474dd5a52df18f255509733f087b5c0b471eb4d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 5 Feb 2024 13:43:14 +0100 Subject: [PATCH 0859/2255] tsnep: Use devm_platform_get_and_ioremap_resource() in tsnep_probe() A wrapper function is available since the commit 890cc39a879906b63912482dfc41944579df2dc6 ("drivers: provide devm_platform_get_and_ioremap_resource()"). Thus reuse existing functionality instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Tested-by: Gerhard Engleder Link: https://lore.kernel.org/r/29e9dc0f-5597-4fee-be5c-25a5ab4fe2dc@web.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/engleder/tsnep_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index 6cb3817d2877..5bf6840c6701 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -2563,8 +2563,7 @@ static int tsnep_probe(struct platform_device *pdev) mutex_init(&adapter->rxnfc_lock); INIT_LIST_HEAD(&adapter->rxnfc_rules); - io = platform_get_resource(pdev, IORESOURCE_MEM, 0); - adapter->addr = devm_ioremap_resource(&pdev->dev, io); + adapter->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &io); if (IS_ERR(adapter->addr)) return PTR_ERR(adapter->addr); netdev->mem_start = io->start; From 50534a55774ce5f6180eaca854fb3c63578b7cf7 Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Wed, 24 Jan 2024 09:55:30 +0100 Subject: [PATCH 0860/2255] igc: Use reverse xmas tree Use reverse xmas tree coding style convention in igc_add_flex_filter(). Signed-off-by: Kurt Kanzenbach Acked-by: Vinicius Costa Gomes Reviewed-by: Simon Horman Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index ba8d3fe186ae..4b3faa9a667f 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3577,9 +3577,9 @@ static bool igc_flex_filter_in_use(struct igc_adapter *adapter) static int igc_add_flex_filter(struct igc_adapter *adapter, struct igc_nfc_rule *rule) { - struct igc_flex_filter flex = { }; struct igc_nfc_filter *filter = &rule->filter; unsigned int eth_offset, user_offset; + struct igc_flex_filter flex = { }; int ret, index; bool vlan; From 5edcf51d0b5e0257587d918a7bae8e5a1af63fb8 Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Wed, 24 Jan 2024 09:55:31 +0100 Subject: [PATCH 0861/2255] igc: Use netdev printing functions for flex filters All igc filter implementations use netdev_*() printing functions except for the flex filters. Unify it. Signed-off-by: Kurt Kanzenbach Acked-by: Vinicius Costa Gomes Reviewed-by: Simon Horman Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 4b3faa9a667f..91297b561519 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3385,7 +3385,7 @@ static int igc_flex_filter_select(struct igc_adapter *adapter, u32 fhftsl; if (input->index >= MAX_FLEX_FILTER) { - dev_err(&adapter->pdev->dev, "Wrong Flex Filter index selected!\n"); + netdev_err(adapter->netdev, "Wrong Flex Filter index selected!\n"); return -EINVAL; } @@ -3420,7 +3420,6 @@ static int igc_flex_filter_select(struct igc_adapter *adapter, static int igc_write_flex_filter_ll(struct igc_adapter *adapter, struct igc_flex_filter *input) { - struct device *dev = &adapter->pdev->dev; struct igc_hw *hw = &adapter->hw; u8 *data = input->data; u8 *mask = input->mask; @@ -3434,7 +3433,7 @@ static int igc_write_flex_filter_ll(struct igc_adapter *adapter, * out early to avoid surprises later. */ if (input->length % 8 != 0) { - dev_err(dev, "The length of a flex filter has to be 8 byte aligned!\n"); + netdev_err(adapter->netdev, "The length of a flex filter has to be 8 byte aligned!\n"); return -EINVAL; } @@ -3504,8 +3503,8 @@ static int igc_write_flex_filter_ll(struct igc_adapter *adapter, } wr32(IGC_WUFC, wufc); - dev_dbg(&adapter->pdev->dev, "Added flex filter %u to HW.\n", - input->index); + netdev_dbg(adapter->netdev, "Added flex filter %u to HW.\n", + input->index); return 0; } From b7471025942d786ab5f3f84932d6d1015511d197 Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Wed, 24 Jan 2024 09:55:32 +0100 Subject: [PATCH 0862/2255] igc: Unify filtering rule fields All filtering parameters such as EtherType and VLAN TCI are stored in host byte order except for the VLAN EtherType. Unify it. Signed-off-by: Kurt Kanzenbach Acked-by: Vinicius Costa Gomes Reviewed-by: Simon Horman Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc.h | 2 +- drivers/net/ethernet/intel/igc/igc_ethtool.c | 4 ++-- drivers/net/ethernet/intel/igc/igc_main.c | 10 ++++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 75f7c5ba65e0..d5833c057de4 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -585,7 +585,7 @@ enum igc_filter_match_flags { struct igc_nfc_filter { u8 match_flags; u16 etype; - __be16 vlan_etype; + u16 vlan_etype; u16 vlan_tci; u16 vlan_tci_mask; u8 src_addr[ETH_ALEN]; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 7f844e967421..47c797dd2cd9 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -981,7 +981,7 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_ETYPE) { fsp->flow_type |= FLOW_EXT; - fsp->h_ext.vlan_etype = rule->filter.vlan_etype; + fsp->h_ext.vlan_etype = htons(rule->filter.vlan_etype); fsp->m_ext.vlan_etype = ETHER_TYPE_FULL_MASK; } @@ -1249,7 +1249,7 @@ static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, /* VLAN etype matching */ if ((fsp->flow_type & FLOW_EXT) && fsp->h_ext.vlan_etype) { - rule->filter.vlan_etype = fsp->h_ext.vlan_etype; + rule->filter.vlan_etype = ntohs(fsp->h_ext.vlan_etype); rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_ETYPE; } diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 91297b561519..c3fe62813f43 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3614,10 +3614,12 @@ static int igc_add_flex_filter(struct igc_adapter *adapter, ETH_ALEN, NULL); /* Add VLAN etype */ - if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_ETYPE) - igc_flex_filter_add_field(&flex, &filter->vlan_etype, 12, - sizeof(filter->vlan_etype), - NULL); + if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_ETYPE) { + __be16 vlan_etype = cpu_to_be16(filter->vlan_etype); + + igc_flex_filter_add_field(&flex, &vlan_etype, 12, + sizeof(vlan_etype), NULL); + } /* Add VLAN TCI */ if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) From 9736c648370d237f61065a7e45e668e2db4374e9 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 6 Feb 2024 08:48:53 +0100 Subject: [PATCH 0863/2255] dpll: check that pin is registered in __dpll_pin_unregister() Similar to what is done in dpll_device_unregister(), add assertion to __dpll_pin_unregister() to make sure driver does not try to unregister non-registered pin. Signed-off-by: Jiri Pirko Reviewed-by: Vadim Fedorenko Reviewed-by: Arkadiusz Kubalewski Link: https://lore.kernel.org/r/20240206074853.345744-1-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- drivers/dpll/dpll_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 61e5c607a72f..93c1bb7a6ef7 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -29,6 +29,8 @@ static u32 dpll_pin_xa_id; WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) #define ASSERT_DPLL_NOT_REGISTERED(d) \ WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) +#define ASSERT_DPLL_PIN_REGISTERED(p) \ + WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED)) struct dpll_device_registration { struct list_head list; @@ -631,6 +633,7 @@ static void __dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, const struct dpll_pin_ops *ops, void *priv) { + ASSERT_DPLL_PIN_REGISTERED(pin); dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv); if (xa_empty(&pin->dpll_refs)) From 9707ac4fe2f5bac6406d2403f8b8a64d7b3d8e43 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Feb 2024 13:46:09 +0100 Subject: [PATCH 0864/2255] tools/resolve_btfids: Refactor set sorting with types from btf_ids.h Instead of using magic offsets to access BTF ID set data, leverage types from btf_ids.h (btf_id_set and btf_id_set8) which define the actual layout of the data. Thanks to this change, set sorting should also continue working if the layout changes. This requires to sync the definition of 'struct btf_id_set8' from include/linux/btf_ids.h to tools/include/linux/btf_ids.h. We don't sync the rest of the file at the moment, b/c that would require to also sync multiple dependent headers and we don't need any other defs from btf_ids.h. Signed-off-by: Viktor Malik Signed-off-by: Andrii Nakryiko Acked-by: Daniel Xu Link: https://lore.kernel.org/bpf/ff7f062ddf6a00815fda3087957c4ce667f50532.1707223196.git.vmalik@redhat.com --- tools/bpf/resolve_btfids/main.c | 35 ++++++++++++++++++++------------- tools/include/linux/btf_ids.h | 9 +++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c index 27a23196d58e..32634f00abba 100644 --- a/tools/bpf/resolve_btfids/main.c +++ b/tools/bpf/resolve_btfids/main.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -78,7 +79,7 @@ #include #define BTF_IDS_SECTION ".BTF_ids" -#define BTF_ID "__BTF_ID__" +#define BTF_ID_PREFIX "__BTF_ID__" #define BTF_STRUCT "struct" #define BTF_UNION "union" @@ -161,7 +162,7 @@ static int eprintf(int level, int var, const char *fmt, ...) static bool is_btf_id(const char *name) { - return name && !strncmp(name, BTF_ID, sizeof(BTF_ID) - 1); + return name && !strncmp(name, BTF_ID_PREFIX, sizeof(BTF_ID_PREFIX) - 1); } static struct btf_id *btf_id__find(struct rb_root *root, const char *name) @@ -441,7 +442,7 @@ static int symbols_collect(struct object *obj) * __BTF_ID__TYPE__vfs_truncate__0 * prefix = ^ */ - prefix = name + sizeof(BTF_ID) - 1; + prefix = name + sizeof(BTF_ID_PREFIX) - 1; /* struct */ if (!strncmp(prefix, BTF_STRUCT, sizeof(BTF_STRUCT) - 1)) { @@ -649,19 +650,18 @@ static int cmp_id(const void *pa, const void *pb) static int sets_patch(struct object *obj) { Elf_Data *data = obj->efile.idlist; - int *ptr = data->d_buf; struct rb_node *next; next = rb_first(&obj->sets); while (next) { - unsigned long addr, idx; + struct btf_id_set8 *set8; + struct btf_id_set *set; + unsigned long addr, off; struct btf_id *id; - int *base; - int cnt; id = rb_entry(next, struct btf_id, rb_node); addr = id->addr[0]; - idx = addr - obj->efile.idlist_addr; + off = addr - obj->efile.idlist_addr; /* sets are unique */ if (id->addr_cnt != 1) { @@ -670,14 +670,21 @@ static int sets_patch(struct object *obj) return -1; } - idx = idx / sizeof(int); - base = &ptr[idx] + (id->is_set8 ? 2 : 1); - cnt = ptr[idx]; + if (id->is_set) { + set = data->d_buf + off; + qsort(set->ids, set->cnt, sizeof(set->ids[0]), cmp_id); + } else { + set8 = data->d_buf + off; + /* + * Make sure id is at the beginning of the pairs + * struct, otherwise the below qsort would not work. + */ + BUILD_BUG_ON(set8->pairs != &set8->pairs[0].id); + qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id); + } pr_debug("sorting addr %5lu: cnt %6d [%s]\n", - (idx + 1) * sizeof(int), cnt, id->name); - - qsort(base, cnt, id->is_set8 ? sizeof(uint64_t) : sizeof(int), cmp_id); + off, id->is_set ? set->cnt : set8->cnt, id->name); next = rb_next(next); } diff --git a/tools/include/linux/btf_ids.h b/tools/include/linux/btf_ids.h index 2f882d5cb30f..72535f00572f 100644 --- a/tools/include/linux/btf_ids.h +++ b/tools/include/linux/btf_ids.h @@ -8,6 +8,15 @@ struct btf_id_set { u32 ids[]; }; +struct btf_id_set8 { + u32 cnt; + u32 flags; + struct { + u32 id; + u32 flags; + } pairs[]; +}; + #ifdef CONFIG_DEBUG_INFO_BTF #include /* for __PASTE */ From 903fad4394666bc23975c93fb58f137ce64b5192 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Feb 2024 13:46:10 +0100 Subject: [PATCH 0865/2255] tools/resolve_btfids: Fix cross-compilation to non-host endianness The .BTF_ids section is pre-filled with zeroed BTF ID entries during the build and afterwards patched by resolve_btfids with correct values. Since resolve_btfids always writes in host-native endianness, it relies on libelf to do the translation when the target ELF is cross-compiled to a different endianness (this was introduced in commit 61e8aeda9398 ("bpf: Fix libelf endian handling in resolv_btfids")). Unfortunately, the translation will corrupt the flags fields of SET8 entries because these were written during vmlinux compilation and are in the correct endianness already. This will lead to numerous selftests failures such as: $ sudo ./test_verifier 502 502 #502/p sleepable fentry accept FAIL Failed to load prog 'Invalid argument'! bpf_fentry_test1 is not sleepable verification time 34 usec stack depth 0 processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 Summary: 0 PASSED, 0 SKIPPED, 1 FAILED Since it's not possible to instruct libelf to translate just certain values, let's manually bswap the flags (both global and entry flags) in resolve_btfids when needed, so that libelf then translates everything correctly. Fixes: ef2c6f370a63 ("tools/resolve_btfids: Add support for 8-byte BTF sets") Signed-off-by: Viktor Malik Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/7b6bff690919555574ce0f13d2a5996cacf7bf69.1707223196.git.vmalik@redhat.com --- tools/bpf/resolve_btfids/main.c | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c index 32634f00abba..d9520cb826b3 100644 --- a/tools/bpf/resolve_btfids/main.c +++ b/tools/bpf/resolve_btfids/main.c @@ -90,6 +90,14 @@ #define ADDR_CNT 100 +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define ELFDATANATIVE ELFDATA2LSB +#elif __BYTE_ORDER == __BIG_ENDIAN +# define ELFDATANATIVE ELFDATA2MSB +#else +# error "Unknown machine endianness!" +#endif + struct btf_id { struct rb_node rb_node; char *name; @@ -117,6 +125,7 @@ struct object { int idlist_shndx; size_t strtabidx; unsigned long idlist_addr; + int encoding; } efile; struct rb_root sets; @@ -320,6 +329,7 @@ static int elf_collect(struct object *obj) { Elf_Scn *scn = NULL; size_t shdrstrndx; + GElf_Ehdr ehdr; int idx = 0; Elf *elf; int fd; @@ -351,6 +361,13 @@ static int elf_collect(struct object *obj) return -1; } + if (gelf_getehdr(obj->efile.elf, &ehdr) == NULL) { + pr_err("FAILED cannot get ELF header: %s\n", + elf_errmsg(-1)); + return -1; + } + obj->efile.encoding = ehdr.e_ident[EI_DATA]; + /* * Scan all the elf sections and look for save data * from .BTF_ids section and symbols. @@ -681,6 +698,24 @@ static int sets_patch(struct object *obj) */ BUILD_BUG_ON(set8->pairs != &set8->pairs[0].id); qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id); + + /* + * When ELF endianness does not match endianness of the + * host, libelf will do the translation when updating + * the ELF. This, however, corrupts SET8 flags which are + * already in the target endianness. So, let's bswap + * them to the host endianness and libelf will then + * correctly translate everything. + */ + if (obj->efile.encoding != ELFDATANATIVE) { + int i; + + set8->flags = bswap_32(set8->flags); + for (i = 0; i < set8->cnt; i++) { + set8->pairs[i].flags = + bswap_32(set8->pairs[i].flags); + } + } } pr_debug("sorting addr %5lu: cnt %6d [%s]\n", From a2bff65cfca93f0fe4c5996f55ce8f413e85e4fe Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Tue, 6 Feb 2024 16:14:14 +0800 Subject: [PATCH 0866/2255] selftests/bpf: Fix error checking for cpumask_success__load() We should verify the return value of cpumask_success__load(). Signed-off-by: Yafang Shao Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240206081416.26242-4-laoar.shao@gmail.com --- tools/testing/selftests/bpf/prog_tests/cpumask.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c index c2e886399e3c..ecf89df78109 100644 --- a/tools/testing/selftests/bpf/prog_tests/cpumask.c +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -27,7 +27,7 @@ static void verify_success(const char *prog_name) struct bpf_program *prog; struct bpf_link *link = NULL; pid_t child_pid; - int status; + int status, err; skel = cpumask_success__open(); if (!ASSERT_OK_PTR(skel, "cpumask_success__open")) @@ -36,8 +36,8 @@ static void verify_success(const char *prog_name) skel->bss->pid = getpid(); skel->bss->nr_cpus = libbpf_num_possible_cpus(); - cpumask_success__load(skel); - if (!ASSERT_OK_PTR(skel, "cpumask_success__load")) + err = cpumask_success__load(skel); + if (!ASSERT_OK(err, "cpumask_success__load")) goto cleanup; prog = bpf_object__find_program_by_name(skel->obj, prog_name); From ba6a6abb3bfa8377bcf386a11077c0533909f9e8 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Tue, 6 Feb 2024 16:14:15 +0800 Subject: [PATCH 0867/2255] selftests/bpf: Mark cpumask kfunc declarations as __weak After the series "Annotate kfuncs in .BTF_ids section"[0], kfuncs can be generated from bpftool. Let's mark the existing cpumask kfunc declarations __weak so they don't conflict with definitions that will eventually come from vmlinux.h. [0]. https://lore.kernel.org/all/cover.1706491398.git.dxu@dxuuu.xyz Suggested-by: Andrii Nakryiko Signed-off-by: Yafang Shao Signed-off-by: Andrii Nakryiko Acked-by: Daniel Xu Link: https://lore.kernel.org/bpf/20240206081416.26242-5-laoar.shao@gmail.com --- .../selftests/bpf/progs/cpumask_common.h | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index 0cd4aebb97cf..c705d8112a35 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -23,41 +23,42 @@ struct array_map { __uint(max_entries, 1); } __cpumask_map SEC(".maps"); -struct bpf_cpumask *bpf_cpumask_create(void) __ksym; -void bpf_cpumask_release(struct bpf_cpumask *cpumask) __ksym; -struct bpf_cpumask *bpf_cpumask_acquire(struct bpf_cpumask *cpumask) __ksym; -u32 bpf_cpumask_first(const struct cpumask *cpumask) __ksym; -u32 bpf_cpumask_first_zero(const struct cpumask *cpumask) __ksym; +struct bpf_cpumask *bpf_cpumask_create(void) __ksym __weak; +void bpf_cpumask_release(struct bpf_cpumask *cpumask) __ksym __weak; +struct bpf_cpumask *bpf_cpumask_acquire(struct bpf_cpumask *cpumask) __ksym __weak; +u32 bpf_cpumask_first(const struct cpumask *cpumask) __ksym __weak; +u32 bpf_cpumask_first_zero(const struct cpumask *cpumask) __ksym __weak; u32 bpf_cpumask_first_and(const struct cpumask *src1, - const struct cpumask *src2) __ksym; -void bpf_cpumask_set_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; -void bpf_cpumask_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; -bool bpf_cpumask_test_cpu(u32 cpu, const struct cpumask *cpumask) __ksym; -bool bpf_cpumask_test_and_set_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; -bool bpf_cpumask_test_and_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; -void bpf_cpumask_setall(struct bpf_cpumask *cpumask) __ksym; -void bpf_cpumask_clear(struct bpf_cpumask *cpumask) __ksym; + const struct cpumask *src2) __ksym __weak; +void bpf_cpumask_set_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym __weak; +void bpf_cpumask_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym __weak; +bool bpf_cpumask_test_cpu(u32 cpu, const struct cpumask *cpumask) __ksym __weak; +bool bpf_cpumask_test_and_set_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym __weak; +bool bpf_cpumask_test_and_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym __weak; +void bpf_cpumask_setall(struct bpf_cpumask *cpumask) __ksym __weak; +void bpf_cpumask_clear(struct bpf_cpumask *cpumask) __ksym __weak; bool bpf_cpumask_and(struct bpf_cpumask *cpumask, const struct cpumask *src1, - const struct cpumask *src2) __ksym; + const struct cpumask *src2) __ksym __weak; void bpf_cpumask_or(struct bpf_cpumask *cpumask, const struct cpumask *src1, - const struct cpumask *src2) __ksym; + const struct cpumask *src2) __ksym __weak; void bpf_cpumask_xor(struct bpf_cpumask *cpumask, const struct cpumask *src1, - const struct cpumask *src2) __ksym; -bool bpf_cpumask_equal(const struct cpumask *src1, const struct cpumask *src2) __ksym; -bool bpf_cpumask_intersects(const struct cpumask *src1, const struct cpumask *src2) __ksym; -bool bpf_cpumask_subset(const struct cpumask *src1, const struct cpumask *src2) __ksym; -bool bpf_cpumask_empty(const struct cpumask *cpumask) __ksym; -bool bpf_cpumask_full(const struct cpumask *cpumask) __ksym; -void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym; -u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym; -u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, const struct cpumask *src2) __ksym; -u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym; + const struct cpumask *src2) __ksym __weak; +bool bpf_cpumask_equal(const struct cpumask *src1, const struct cpumask *src2) __ksym __weak; +bool bpf_cpumask_intersects(const struct cpumask *src1, const struct cpumask *src2) __ksym __weak; +bool bpf_cpumask_subset(const struct cpumask *src1, const struct cpumask *src2) __ksym __weak; +bool bpf_cpumask_empty(const struct cpumask *cpumask) __ksym __weak; +bool bpf_cpumask_full(const struct cpumask *cpumask) __ksym __weak; +void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym __weak; +u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym __weak; +u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, + const struct cpumask *src2) __ksym __weak; +u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym __weak; -void bpf_rcu_read_lock(void) __ksym; -void bpf_rcu_read_unlock(void) __ksym; +void bpf_rcu_read_lock(void) __ksym __weak; +void bpf_rcu_read_unlock(void) __ksym __weak; static inline const struct cpumask *cast(struct bpf_cpumask *cpumask) { From e55dad12abe42383b68ba88212eb3d0fba0e9820 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 4 Feb 2024 16:56:34 +0900 Subject: [PATCH 0868/2255] bpf: Merge two CONFIG_BPF entries 'config BPF' exists in both init/Kconfig and kernel/bpf/Kconfig. Commit b24abcff918a ("bpf, kconfig: Add consolidated menu entry for bpf with core options") added the second one to kernel/bpf/Kconfig instead of moving the existing one. Merge them together. Signed-off-by: Masahiro Yamada Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240204075634.32969-1-masahiroy@kernel.org --- init/Kconfig | 5 ----- kernel/bpf/Kconfig | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 8d4e836e1b6b..46ccad83a664 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1457,11 +1457,6 @@ config SYSCTL_ARCH_UNALIGN_ALLOW config HAVE_PCSPKR_PLATFORM bool -# interpreter that classic socket filters depend on -config BPF - bool - select CRYPTO_LIB_SHA1 - menuconfig EXPERT bool "Configure standard kernel features (expert users)" # Unhide debug options, to make the on-by-default options visible diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig index 6a906ff93006..bc25f5098a25 100644 --- a/kernel/bpf/Kconfig +++ b/kernel/bpf/Kconfig @@ -3,6 +3,7 @@ # BPF interpreter that, for example, classic socket filters depend on. config BPF bool + select CRYPTO_LIB_SHA1 # Used by archs to tell that they support BPF JIT compiler plus which # flavour. Only one of the two can be selected for a specific arch since From 6c06c88fa838fcc1b7e5380facd086f57fd9d1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 4 Feb 2024 15:16:46 +0100 Subject: [PATCH 0869/2255] net: mdio: add 2.5g and 5g related PMA speed constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add constants indicating 2.5g and 5g ability in the MMD PMA speed register. Signed-off-by: Marek Behún Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/98e15038-d96c-442f-93e4-410100d27866@gmail.com Signed-off-by: Jakub Kicinski --- include/uapi/linux/mdio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index d03863da180e..3c9097502403 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -138,6 +138,8 @@ #define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */ #define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */ #define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */ +#define MDIO_PMA_SPEED_2_5G 0x2000 /* 2.5G capable */ +#define MDIO_PMA_SPEED_5G 0x4000 /* 5G capable */ #define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */ #define MDIO_PCS_SPEED_2_5G 0x0040 /* 2.5G capable */ #define MDIO_PCS_SPEED_5G 0x0080 /* 5G capable */ From 2b9ec5dfb8255656ca731ab9d9bf59d94566d377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 4 Feb 2024 15:17:53 +0100 Subject: [PATCH 0870/2255] net: phy: realtek: use generic MDIO constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the ad-hoc MDIO constants used in the driver and use generic constants instead. Signed-off-by: Marek Behún Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/732a70d6-4191-4aae-8862-3716b062aa9e@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 132784321e44..b5deccafdd9e 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -57,14 +57,6 @@ #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) -#define RTL_SUPPORTS_5000FULL BIT(14) -#define RTL_SUPPORTS_2500FULL BIT(13) -#define RTL_SUPPORTS_10000FULL BIT(0) -#define RTL_ADV_2500FULL BIT(7) -#define RTL_LPADV_10000FULL BIT(11) -#define RTL_LPADV_5000FULL BIT(6) -#define RTL_LPADV_2500FULL BIT(5) - #define RTL9000A_GINMR 0x14 #define RTL9000A_GINMR_LINK_STATUS BIT(4) @@ -674,11 +666,11 @@ static int rtl822x_get_features(struct phy_device *phydev) return val; linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, - phydev->supported, val & RTL_SUPPORTS_2500FULL); + phydev->supported, val & MDIO_PMA_SPEED_2_5G); linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, - phydev->supported, val & RTL_SUPPORTS_5000FULL); + phydev->supported, val & MDIO_PMA_SPEED_5G); linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, - phydev->supported, val & RTL_SUPPORTS_10000FULL); + phydev->supported, val & MDIO_SPEED_10G); return genphy_read_abilities(phydev); } @@ -692,10 +684,11 @@ static int rtl822x_config_aneg(struct phy_device *phydev) if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) - adv2500 = RTL_ADV_2500FULL; + adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G; ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, - RTL_ADV_2500FULL, adv2500); + MDIO_AN_10GBT_CTRL_ADV2_5G, + adv2500); if (ret < 0) return ret; } @@ -714,11 +707,14 @@ static int rtl822x_read_status(struct phy_device *phydev) return lpadv; linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, - phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL); + phydev->lp_advertising, + lpadv & MDIO_AN_10GBT_STAT_LP10G); linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, - phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL); + phydev->lp_advertising, + lpadv & MDIO_AN_10GBT_STAT_LP5G); linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, - phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL); + phydev->lp_advertising, + lpadv & MDIO_AN_10GBT_STAT_LP2_5G); } ret = genphy_read_status(phydev); @@ -736,7 +732,7 @@ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) val = phy_read(phydev, 0x13); phy_write(phydev, RTL821x_PAGE_SELECT, 0); - return val >= 0 && val & RTL_SUPPORTS_2500FULL; + return val >= 0 && val & MDIO_PMA_SPEED_2_5G; } static int rtlgen_match_phy_device(struct phy_device *phydev) From db1bb7741ff29bf2cefcbc0ca567644e9ed1caa9 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 4 Feb 2024 15:18:50 +0100 Subject: [PATCH 0871/2255] net: phy: realtek: add 5Gbps support to rtl822x_config_aneg() RTL8126 as an evolution of RTL8125 supports 5Gbps. rtl822x_config_aneg() is used by the PHY driver for the integrated PHY, therefore add 5Gbps support to it. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/5644ab50-e3e9-477c-96db-05cd5bdc2563@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index b5deccafdd9e..962df2b83070 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -680,15 +680,19 @@ static int rtl822x_config_aneg(struct phy_device *phydev) int ret = 0; if (phydev->autoneg == AUTONEG_ENABLE) { - u16 adv2500 = 0; + u16 adv = 0; if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) - adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G; + adv |= MDIO_AN_10GBT_CTRL_ADV2_5G; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + phydev->advertising)) + adv |= MDIO_AN_10GBT_CTRL_ADV5G; ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, - MDIO_AN_10GBT_CTRL_ADV2_5G, - adv2500); + MDIO_AN_10GBT_CTRL_ADV2_5G | + MDIO_AN_10GBT_CTRL_ADV5G, + adv); if (ret < 0) return ret; } From b27696cd8fcc0ace1b2dfd81b7bff824a30b1fd1 Mon Sep 17 00:00:00 2001 From: Wen Gu Date: Mon, 5 Feb 2024 11:33:17 +0800 Subject: [PATCH 0872/2255] net/smc: change the term virtual ISM to Emulated-ISM According to latest release of SMCv2.1[1], the term 'virtual ISM' has been changed to 'Emulated-ISM' to avoid the ambiguity of the word 'virtual' in different contexts. So the names or comments in the code need be modified accordingly. [1] https://www.ibm.com/support/pages/node/7112343 Signed-off-by: Wen Gu Reviewed-by: Simon Horman Reviewed-by: Wenjia Zhang Link: https://lore.kernel.org/r/20240205033317.127269-1-guwen@linux.alibaba.com Signed-off-by: Jakub Kicinski --- net/smc/af_smc.c | 22 +++++++++++----------- net/smc/smc.h | 4 ++-- net/smc/smc_clc.c | 6 +++--- net/smc/smc_clc.h | 2 +- net/smc/smc_core.c | 4 ++-- net/smc/smc_ism.h | 10 +++++----- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index a2cb30af46cb..66763c74ab76 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -1045,7 +1045,7 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc, int rc = SMC_CLC_DECL_NOSMCDDEV; struct smcd_dev *smcd; int i = 1, entry = 1; - bool is_virtual; + bool is_emulated; u16 chid; if (smcd_indicated(ini->smc_type_v1)) @@ -1057,12 +1057,12 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc, chid = smc_ism_get_chid(smcd); if (!smc_find_ism_v2_is_unique_chid(chid, ini, i)) continue; - is_virtual = __smc_ism_is_virtual(chid); + is_emulated = __smc_ism_is_emulated(chid); if (!smc_pnet_is_pnetid_set(smcd->pnetid) || smc_pnet_is_ndev_pnetid(sock_net(&smc->sk), smcd->pnetid)) { - if (is_virtual && entry == SMCD_CLC_MAX_V2_GID_ENTRIES) + if (is_emulated && entry == SMCD_CLC_MAX_V2_GID_ENTRIES) /* It's the last GID-CHID entry left in CLC - * Proposal SMC-Dv2 extension, but a virtual + * Proposal SMC-Dv2 extension, but an Emulated- * ISM device will take two entries. So give * up it and try the next potential ISM device. */ @@ -1072,7 +1072,7 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc, ini->is_smcd = true; rc = 0; i++; - entry = is_virtual ? entry + 2 : entry + 1; + entry = is_emulated ? entry + 2 : entry + 1; if (entry > SMCD_CLC_MAX_V2_GID_ENTRIES) break; } @@ -1413,10 +1413,10 @@ static int smc_connect_ism(struct smc_sock *smc, if (rc) return rc; - if (__smc_ism_is_virtual(ini->ism_chid[ini->ism_selected])) + if (__smc_ism_is_emulated(ini->ism_chid[ini->ism_selected])) ini->ism_peer_gid[ini->ism_selected].gid_ext = ntohll(aclc->d1.gid_ext); - /* for non-virtual ISM devices, peer gid_ext remains 0. */ + /* for non-Emulated-ISM devices, peer gid_ext remains 0. */ } ini->ism_peer_gid[ini->ism_selected].gid = ntohll(aclc->d0.gid); @@ -2117,10 +2117,10 @@ static void smc_check_ism_v2_match(struct smc_init_info *ini, if (smc_ism_get_chid(smcd) == proposed_chid && !smc_ism_cantalk(proposed_gid, ISM_RESERVED_VLANID, smcd)) { ini->ism_peer_gid[*matches].gid = proposed_gid->gid; - if (__smc_ism_is_virtual(proposed_chid)) + if (__smc_ism_is_emulated(proposed_chid)) ini->ism_peer_gid[*matches].gid_ext = proposed_gid->gid_ext; - /* non-virtual ISM's peer gid_ext remains 0. */ + /* non-Emulated-ISM's peer gid_ext remains 0. */ ini->ism_dev[*matches] = smcd; (*matches)++; break; @@ -2170,10 +2170,10 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc, smcd_gid.gid = ntohll(smcd_v2_ext->gidchid[i].gid); smcd_gid.gid_ext = 0; chid = ntohs(smcd_v2_ext->gidchid[i].chid); - if (__smc_ism_is_virtual(chid)) { + if (__smc_ism_is_emulated(chid)) { if ((i + 1) == smc_v2_ext->hdr.ism_gid_cnt || chid != ntohs(smcd_v2_ext->gidchid[i + 1].chid)) - /* each virtual ISM device takes two GID-CHID + /* each Emulated-ISM device takes two GID-CHID * entries and CHID of the second entry repeats * that of the first entry. * diff --git a/net/smc/smc.h b/net/smc/smc.h index df64efd2dee8..18c8b7870198 100644 --- a/net/smc/smc.h +++ b/net/smc/smc.h @@ -56,11 +56,11 @@ enum smc_state { /* possible states of an SMC socket */ }; enum smc_supplemental_features { - SMC_SPF_VIRT_ISM_DEV = 0, + SMC_SPF_EMULATED_ISM_DEV = 0, }; #define SMC_FEATURE_MASK \ - (BIT(SMC_SPF_VIRT_ISM_DEV)) + (BIT(SMC_SPF_EMULATED_ISM_DEV)) struct smc_link_group; diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c index 9a13709bea1c..e55026c7529c 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c @@ -952,8 +952,8 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) gidchids[entry].chid = htons(smc_ism_get_chid(ini->ism_dev[i])); gidchids[entry].gid = htonll(smcd_gid.gid); - if (smc_ism_is_virtual(smcd)) { - /* a virtual ISM device takes two + if (smc_ism_is_emulated(smcd)) { + /* an Emulated-ISM device takes two * entries. CHID of the second entry * repeats that of the first entry. */ @@ -1055,7 +1055,7 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn, clc->d1.chid = htons(chid); if (eid && eid[0]) memcpy(clc->d1.eid, eid, SMC_MAX_EID_LEN); - if (__smc_ism_is_virtual(chid)) + if (__smc_ism_is_emulated(chid)) clc->d1.gid_ext = htonll(smcd_gid.gid_ext); len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; if (first_contact) { diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h index a9f9bdd26dcd..7cc7070b9772 100644 --- a/net/smc/smc_clc.h +++ b/net/smc/smc_clc.h @@ -175,7 +175,7 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */ #define SMCD_CLC_MAX_V2_GID_ENTRIES 8 /* max # of CHID-GID entries in CLC * proposal SMC-Dv2 extension. * each ISM device takes one entry and - * each virtual ISM takes two entries. + * each Emulated-ISM takes two entries */ struct smc_clc_msg_proposal_area { diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index e4c858411207..9b84d5897aa5 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -1535,7 +1535,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid, list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) { if ((!peer_gid->gid || (lgr->peer_gid.gid == peer_gid->gid && - !smc_ism_is_virtual(dev) ? 1 : + !smc_ism_is_emulated(dev) ? 1 : lgr->peer_gid.gid_ext == peer_gid->gid_ext)) && (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) { if (peer_gid->gid) /* peer triggered termination */ @@ -1881,7 +1881,7 @@ static bool smcd_lgr_match(struct smc_link_group *lgr, lgr->smcd != smcismdev) return false; - if (smc_ism_is_virtual(smcismdev) && + if (smc_ism_is_emulated(smcismdev) && lgr->peer_gid.gid_ext != peer_gid->gid_ext) return false; diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h index ffff40c30a06..165cd013404b 100644 --- a/net/smc/smc_ism.h +++ b/net/smc/smc_ism.h @@ -15,7 +15,7 @@ #include "smc.h" -#define SMC_VIRTUAL_ISM_CHID_MASK 0xFF00 +#define SMC_EMULATED_ISM_CHID_MASK 0xFF00 #define SMC_ISM_IDENT_MASK 0x00FFFF struct smcd_dev_list { /* List of SMCD devices */ @@ -66,10 +66,10 @@ static inline int smc_ism_write(struct smcd_dev *smcd, u64 dmb_tok, return rc < 0 ? rc : 0; } -static inline bool __smc_ism_is_virtual(u16 chid) +static inline bool __smc_ism_is_emulated(u16 chid) { /* CHIDs in range of 0xFF00 to 0xFFFF are reserved - * for virtual ISM device. + * for Emulated-ISM device. * * loopback-ism: 0xFFFF * virtio-ism: 0xFF00 ~ 0xFFFE @@ -77,11 +77,11 @@ static inline bool __smc_ism_is_virtual(u16 chid) return ((chid & 0xFF00) == 0xFF00); } -static inline bool smc_ism_is_virtual(struct smcd_dev *smcd) +static inline bool smc_ism_is_emulated(struct smcd_dev *smcd) { u16 chid = smcd->ops->get_chid(smcd); - return __smc_ism_is_virtual(chid); + return __smc_ism_is_emulated(chid); } #endif From c8f4b19d64b93091ca30fe6800f41d1532bd7507 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 5 Feb 2024 21:00:45 +0800 Subject: [PATCH 0873/2255] selftests/net/forwarding: add slowwait functions Add slowwait functions to wait for some operations that may need a long time to finish. The busywait executes the cmd too fast, which is kind of wasting cpu in this scenario. At the same time, if shell debugging is enabled with `set -x`. the busywait will output too much logs. Reviewed-by: Przemek Kitszel Signed-off-by: Hangbin Liu Link: https://lore.kernel.org/r/20240205130048.282087-2-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/lib.sh | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index a7ecfc8cae98..db3688f52888 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -37,6 +37,32 @@ fi source "$net_forwarding_dir/../lib.sh" +# timeout in seconds +slowwait() +{ + local timeout=$1; shift + + local start_time="$(date -u +%s)" + while true + do + local out + out=$("$@") + local ret=$? + if ((!ret)); then + echo -n "$out" + return 0 + fi + + local current_time="$(date -u +%s)" + if ((current_time - start_time > timeout)); then + echo -n "$out" + return 1 + fi + + sleep 0.1 + done +} + ############################################################################## # Sanity checks @@ -478,6 +504,15 @@ busywait_for_counter() busywait "$timeout" until_counter_is ">= $((base + delta))" "$@" } +slowwait_for_counter() +{ + local timeout=$1; shift + local delta=$1; shift + + local base=$("$@") + slowwait "$timeout" until_counter_is ">= $((base + delta))" "$@" +} + setup_wait_dev() { local dev=$1; shift From 9150820c88304a9f52452bc18725c88f137688d8 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 5 Feb 2024 21:00:46 +0800 Subject: [PATCH 0874/2255] selftests: bonding: use tc filter to check if LACP was sent Use tc filter to check if LACP was sent, which is accurate and save more time. No need to remove bonding module as some test env may buildin bonding. And the bond link has been deleted. Reviewed-by: Przemek Kitszel Signed-off-by: Hangbin Liu Link: https://lore.kernel.org/r/20240205130048.282087-3-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski --- .../net/bonding/bond-break-lacpdu-tx.sh | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/drivers/net/bonding/bond-break-lacpdu-tx.sh b/tools/testing/selftests/drivers/net/bonding/bond-break-lacpdu-tx.sh index 6358df5752f9..1ec7f59db7f4 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond-break-lacpdu-tx.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond-break-lacpdu-tx.sh @@ -20,21 +20,21 @@ # +------+ +------+ # # We use veths instead of physical interfaces +REQUIRE_MZ=no +NUM_NETIFS=0 +lib_dir=$(dirname "$0") +source "$lib_dir"/../../../net/forwarding/lib.sh set -e -tmp=$(mktemp -q dump.XXXXXX) cleanup() { ip link del fab-br0 >/dev/null 2>&1 || : ip link del fbond >/dev/null 2>&1 || : ip link del veth1-bond >/dev/null 2>&1 || : ip link del veth2-bond >/dev/null 2>&1 || : - modprobe -r bonding >/dev/null 2>&1 || : - rm -f -- ${tmp} } trap cleanup 0 1 2 cleanup -sleep 1 # create the bridge ip link add fab-br0 address 52:54:00:3B:7C:A6 mtu 1500 type bridge \ @@ -67,13 +67,12 @@ ip link set fab-br0 up ip link set fbond up ip addr add dev fab-br0 10.0.0.3 -tcpdump -n -i veth1-end -e ether proto 0x8809 >${tmp} 2>&1 & -sleep 15 -pkill tcpdump >/dev/null 2>&1 rc=0 -num=$(grep "packets captured" ${tmp} | awk '{print $1}') -if test "$num" -gt 0; then - echo "PASS, captured ${num}" +tc qdisc add dev veth1-end clsact +tc filter add dev veth1-end ingress protocol 0x8809 pref 1 handle 101 flower skip_hw action pass +if slowwait_for_counter 15 2 \ + tc_rule_handle_stats_get "dev veth1-end ingress" 101 ".packets" "" &> /dev/null; then + echo "PASS, captured 2" else echo "FAIL" rc=1 From 45bf79bc56c4158afb6f57cca67ac0ef0a7073ef Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 5 Feb 2024 21:00:47 +0800 Subject: [PATCH 0875/2255] selftests: bonding: reduce garp_test/arp_validate test time The purpose of grat_arp is testing commit 9949e2efb54e ("bonding: fix send_peer_notif overflow"). As the send_peer_notif was defined to u8, to overflow it, we need to send_peer_notif = num_peer_notif * peer_notif_delay = num_grat_arp * peer_notify_delay / miimon > 255 (kernel) (kernel parameter) (user parameter) e.g. 30 (num_grat_arp) * 1000 (peer_notify_delay) / 100 (miimon) > 255. Which need 30s to complete sending garp messages. To save the testing time, the only way is reduce the miimon number. Something like 30 (num_grat_arp) * 100 (peer_notify_delay) / 10 (miimon) > 255. To save more time, the 50 num_grat_arp testing could be removed. The arp_validate_test also need to check the mii_status, which sleep too long. Use slowwait to save some time. For other connection checkings, make sure active slave changed first. Reviewed-by: Przemek Kitszel Signed-off-by: Hangbin Liu Link: https://lore.kernel.org/r/20240205130048.282087-4-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski --- .../drivers/net/bonding/bond_options.sh | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/drivers/net/bonding/bond_options.sh b/tools/testing/selftests/drivers/net/bonding/bond_options.sh index d508486cc0bd..6fd0cff3e1e9 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond_options.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond_options.sh @@ -45,15 +45,23 @@ skip_ns() } active_slave="" +active_slave_changed() +{ + local old_active_slave=$1 + local new_active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" \ + ".[].linkinfo.info_data.active_slave") + test "$old_active_slave" != "$new_active_slave" +} + check_active_slave() { local target_active_slave=$1 + slowwait 2 active_slave_changed $active_slave active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave") test "$active_slave" = "$target_active_slave" check_err $? "Current active slave is $active_slave but not $target_active_slave" } - # Test bonding prio option prio_test() { @@ -84,13 +92,13 @@ prio_test() # active slave should be the higher prio slave ip -n ${s_ns} link set $active_slave down - bond_check_connection "fail over" check_active_slave eth2 + bond_check_connection "fail over" # when only 1 slave is up ip -n ${s_ns} link set $active_slave down - bond_check_connection "only 1 slave up" check_active_slave eth0 + bond_check_connection "only 1 slave up" # when a higher prio slave change to up ip -n ${s_ns} link set eth2 up @@ -140,8 +148,8 @@ prio_test() check_active_slave "eth1" ip -n ${s_ns} link set $active_slave down - bond_check_connection "change slave prio" check_active_slave "eth0" + bond_check_connection "change slave prio" fi } @@ -199,6 +207,15 @@ prio() prio_ns "active-backup" } +wait_mii_up() +{ + for i in $(seq 0 2); do + mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status") + [ ${mii_status} != "UP" ] && return 1 + done + return 0 +} + arp_validate_test() { local param="$1" @@ -211,7 +228,7 @@ arp_validate_test() [ $RET -ne 0 ] && log_test "arp_validate" "$retmsg" # wait for a while to make sure the mii status stable - sleep 5 + slowwait 5 wait_mii_up for i in $(seq 0 2); do mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status") if [ ${mii_status} != "UP" ]; then @@ -276,10 +293,13 @@ garp_test() active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave") ip -n ${s_ns} link set ${active_slave} down - exp_num=$(echo "${param}" | cut -f6 -d ' ') - sleep $((exp_num + 2)) + # wait for active link change + slowwait 2 active_slave_changed $active_slave + exp_num=$(echo "${param}" | cut -f6 -d ' ') active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave") + slowwait_for_counter $((exp_num + 5)) $exp_num \ + tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}" # check result real_num=$(tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}") @@ -296,8 +316,8 @@ garp_test() num_grat_arp() { local val - for val in 10 20 30 50; do - garp_test "mode active-backup miimon 100 num_grat_arp $val peer_notify_delay 1000" + for val in 10 20 30; do + garp_test "mode active-backup miimon 10 num_grat_arp $val peer_notify_delay 100" log_test "num_grat_arp" "active-backup miimon num_grat_arp $val" done } From e1f0da9b90fbe0886f57f8cbe0b84ce82fc20e75 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 5 Feb 2024 21:00:48 +0800 Subject: [PATCH 0876/2255] selftests: bonding: use slowwait instead of hard code sleep Use slowwait instead of hard code sleep for bonding tests. In function setup_prepare(), the client_create() will be called after server_create(). So I think there is no need to sleep in server_create() and remove it. For lab_lib.sh, remove bonding module may affect other running bonding tests. And some test env may buildin bond which can't be removed. The bonding link should be removed by lag_reset_network() or netns delete. Signed-off-by: Hangbin Liu Link: https://lore.kernel.org/r/20240205130048.282087-5-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski --- .../drivers/net/bonding/bond-lladdr-target.sh | 21 ++++++++++++++++--- .../drivers/net/bonding/bond_topo_2d1c.sh | 6 +++--- .../selftests/drivers/net/bonding/lag_lib.sh | 7 +++---- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/drivers/net/bonding/bond-lladdr-target.sh b/tools/testing/selftests/drivers/net/bonding/bond-lladdr-target.sh index 89af402fabbe..78d3e0fe6604 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond-lladdr-target.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond-lladdr-target.sh @@ -17,6 +17,11 @@ # +----------------+ # # We use veths instead of physical interfaces +REQUIRE_MZ=no +NUM_NETIFS=0 +lib_dir=$(dirname "$0") +source "$lib_dir"/../../../net/forwarding/lib.sh + sw="sw-$(mktemp -u XXXXXX)" host="ns-$(mktemp -u XXXXXX)" @@ -26,6 +31,16 @@ cleanup() ip netns del $host } +wait_lladdr_dad() +{ + $@ | grep fe80 | grep -qv tentative +} + +wait_bond_up() +{ + $@ | grep -q 'state UP' +} + trap cleanup 0 1 2 ip netns add $sw @@ -37,8 +52,8 @@ ip -n $host link add veth1 type veth peer name veth1 netns $sw ip -n $sw link add br0 type bridge ip -n $sw link set br0 up sw_lladdr=$(ip -n $sw addr show br0 | awk '/fe80/{print $2}' | cut -d'/' -f1) -# sleep some time to make sure bridge lladdr pass DAD -sleep 2 +# wait some time to make sure bridge lladdr pass DAD +slowwait 2 wait_lladdr_dad ip -n $sw addr show br0 ip -n $host link add bond0 type bond mode 1 ns_ip6_target ${sw_lladdr} \ arp_validate 3 arp_interval 1000 @@ -53,7 +68,7 @@ ip -n $sw link set veth1 master br0 ip -n $sw link set veth0 up ip -n $sw link set veth1 up -sleep 5 +slowwait 5 wait_bond_up ip -n $host link show bond0 rc=0 if ip -n $host link show bond0 | grep -q LOWER_UP; then diff --git a/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh b/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh index 0eb7edfb584c..195ef83cfbf1 100644 --- a/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond_topo_2d1c.sh @@ -73,7 +73,6 @@ server_create() ip -n ${s_ns} link set bond0 up ip -n ${s_ns} addr add ${s_ip4}/24 dev bond0 ip -n ${s_ns} addr add ${s_ip6}/24 dev bond0 - sleep 2 } # Reset bond with new mode and options @@ -96,7 +95,8 @@ bond_reset() ip -n ${s_ns} link set bond0 up ip -n ${s_ns} addr add ${s_ip4}/24 dev bond0 ip -n ${s_ns} addr add ${s_ip6}/24 dev bond0 - sleep 2 + # Wait for IPv6 address ready as it needs DAD + slowwait 2 ip netns exec ${s_ns} ping6 ${c_ip6} -c 1 -W 0.1 &> /dev/null } server_destroy() @@ -150,7 +150,7 @@ bond_check_connection() { local msg=${1:-"check connection"} - sleep 2 + slowwait 2 ip netns exec ${s_ns} ping ${c_ip4} -c 1 -W 0.1 &> /dev/null ip netns exec ${s_ns} ping ${c_ip4} -c5 -i 0.1 &>/dev/null check_err $? "${msg}: ping failed" ip netns exec ${s_ns} ping6 ${c_ip6} -c5 -i 0.1 &>/dev/null diff --git a/tools/testing/selftests/drivers/net/bonding/lag_lib.sh b/tools/testing/selftests/drivers/net/bonding/lag_lib.sh index dbdd736a41d3..bf9bcd1b5ec0 100644 --- a/tools/testing/selftests/drivers/net/bonding/lag_lib.sh +++ b/tools/testing/selftests/drivers/net/bonding/lag_lib.sh @@ -107,13 +107,12 @@ lag_setup2x2() NAMESPACES="${namespaces}" } -# cleanup all lag related namespaces and remove the bonding module +# cleanup all lag related namespaces lag_cleanup() { for n in ${NAMESPACES}; do ip netns delete ${n} >/dev/null 2>&1 || true done - modprobe -r bonding } SWITCH="lag_node1" @@ -159,7 +158,7 @@ test_bond_recovery() create_bond $@ # verify connectivity - ip netns exec ${CLIENT} ping ${SWITCHIP} -c 2 >/dev/null 2>&1 + slowwait 2 ip netns exec ${CLIENT} ping ${SWITCHIP} -c 2 -W 0.1 &> /dev/null check_err $? "No connectivity" # force the links of the bond down @@ -169,7 +168,7 @@ test_bond_recovery() ip netns exec ${SWITCH} ip link set eth1 down # re-verify connectivity - ip netns exec ${CLIENT} ping ${SWITCHIP} -c 2 >/dev/null 2>&1 + slowwait 2 ip netns exec ${CLIENT} ping ${SWITCHIP} -c 2 -W 0.1 &> /dev/null local rc=$? check_err $rc "Bond failed to recover" From c885b95c58dd81d45e30a5608d1b6ef1f93a5717 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 5 Feb 2024 22:54:08 +0100 Subject: [PATCH 0877/2255] r8169: remove setting LED default trigger, this is done by LED core now After 1c75c424bd43 ("leds: class: If no default trigger is given, make hw_control trigger the default trigger") this line isn't needed any longer. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/3a9cd1a1-40ad-487d-8b1e-6bf255419232@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_leds.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_leds.c b/drivers/net/ethernet/realtek/r8169_leds.c index 007d077edcad..f082bd7d6194 100644 --- a/drivers/net/ethernet/realtek/r8169_leds.c +++ b/drivers/net/ethernet/realtek/r8169_leds.c @@ -129,7 +129,6 @@ static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); led_cdev->name = led_name; - led_cdev->default_trigger = "netdev"; led_cdev->hw_control_trigger = "netdev"; led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported; From 01fc42942e30bd56cbb4a4f2107617dc8030b6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 6 Feb 2024 01:08:02 +0300 Subject: [PATCH 0878/2255] net: dsa: mt7530: empty default case on mt7530_setup_port5() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There're two code paths for setting up port 5: mt7530_setup() -> mt7530_setup_port5() mt753x_phylink_mac_config() -> mt753x_mac_config() -> mt7530_mac_config() -> mt7530_setup_port5() On the first code path, priv->p5_intf_sel is either set to P5_INTF_SEL_PHY_P0 or P5_INTF_SEL_PHY_P4 when mt7530_setup_port5() is run. On the second code path, priv->p5_intf_sel is set to P5_INTF_SEL_GMAC5 when mt7530_setup_port5() is run. Empty the default case which will never run but is needed nonetheless to handle all the remaining enumeration values. Reviewed-by: Vladimir Oltean Reviewed-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-1-d7d92a185cb1@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 216596b86de8..e1bbd9172493 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -943,9 +943,7 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) val &= ~MHWTRAP_P5_DIS; break; default: - dev_err(ds->dev, "Unsupported p5_intf_sel %d\n", - priv->p5_intf_sel); - goto unlock_exit; + break; } /* Setup RGMII settings */ @@ -975,7 +973,6 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n", val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface)); -unlock_exit: mutex_unlock(&priv->reg_mutex); } From fd7929095a5211a4cfddb15dd568b4258b07990b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 6 Feb 2024 01:08:03 +0300 Subject: [PATCH 0879/2255] net: dsa: mt7530: move XTAL check to mt7530_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The crystal frequency concerns the switch core. The frequency should be checked when the switch is being set up so the driver can reject the unsupported hardware earlier and without requiring port 6 to be used. Move it to mt7530_setup(). Drop the unnecessary function printing. Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Reviewed-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-2-d7d92a185cb1@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index e1bbd9172493..954434ce0f01 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -422,13 +422,6 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK; - if (xtal == HWTRAP_XTAL_20MHZ) { - dev_err(priv->dev, - "%s: MT7530 with a 20MHz XTAL is not supported!\n", - __func__); - return -EINVAL; - } - switch (interface) { case PHY_INTERFACE_MODE_RGMII: trgint = 0; @@ -2259,6 +2252,12 @@ mt7530_setup(struct dsa_switch *ds) return -ENODEV; } + if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_20MHZ) { + dev_err(priv->dev, + "MT7530 with a 20MHz XTAL is not supported!\n"); + return -EINVAL; + } + /* Reset the switch through internal reset */ mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | From 4eec447ef640a90e31812036c4669a2b8388bc09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 6 Feb 2024 01:08:04 +0300 Subject: [PATCH 0880/2255] net: dsa: mt7530: simplify mt7530_pad_clk_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code is from before this driver was converted to phylink API. Phylink deals with the unsupported interface cases before mt7530_pad_clk_setup() is run. Therefore, the default case would never run. However, it must be defined nonetheless to handle all the remaining enumeration values, the phy-modes. Switch to if statement for RGMII and return which simplifies the code and saves an indent. Set P6_INTF_MODE, which is the three least significant bits of the MT7530_P6ECR register, to 0 for RGMII even though it will already be 0 after reset. This is to keep supporting dynamic reconfiguration of the port in the case the interface changes from TRGMII to RGMII. Disable the TRGMII clocks for all cases. They will be enabled if TRGMII is being used. Read XTAL after checking for RGMII as it's only needed for the TRGMII interface mode. Reviewed-by: Daniel Golle Reviewed-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-3-d7d92a185cb1@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 91 ++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 954434ce0f01..ff72f5c6d80d 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -418,64 +418,53 @@ static int mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) { struct mt7530_priv *priv = ds->priv; - u32 ncpo1, ssc_delta, trgint, xtal; + u32 ncpo1, ssc_delta, xtal; + + /* Disable the MT7530 TRGMII clocks */ + core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); + + if (interface == PHY_INTERFACE_MODE_RGMII) { + mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, + P6_INTF_MODE(0)); + return 0; + } + + mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1)); xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK; - switch (interface) { - case PHY_INTERFACE_MODE_RGMII: - trgint = 0; - break; - case PHY_INTERFACE_MODE_TRGMII: - trgint = 1; + if (xtal == HWTRAP_XTAL_25MHZ) + ssc_delta = 0x57; + else + ssc_delta = 0x87; + + if (priv->id == ID_MT7621) { + /* PLL frequency: 125MHz: 1.0GBit */ + if (xtal == HWTRAP_XTAL_40MHZ) + ncpo1 = 0x0640; if (xtal == HWTRAP_XTAL_25MHZ) - ssc_delta = 0x57; - else - ssc_delta = 0x87; - if (priv->id == ID_MT7621) { - /* PLL frequency: 125MHz: 1.0GBit */ - if (xtal == HWTRAP_XTAL_40MHZ) - ncpo1 = 0x0640; - if (xtal == HWTRAP_XTAL_25MHZ) - ncpo1 = 0x0a00; - } else { /* PLL frequency: 250MHz: 2.0Gbit */ - if (xtal == HWTRAP_XTAL_40MHZ) - ncpo1 = 0x0c80; - if (xtal == HWTRAP_XTAL_25MHZ) - ncpo1 = 0x1400; - } - break; - default: - dev_err(priv->dev, "xMII interface %d not supported\n", - interface); - return -EINVAL; + ncpo1 = 0x0a00; + } else { /* PLL frequency: 250MHz: 2.0Gbit */ + if (xtal == HWTRAP_XTAL_40MHZ) + ncpo1 = 0x0c80; + if (xtal == HWTRAP_XTAL_25MHZ) + ncpo1 = 0x1400; } - mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, - P6_INTF_MODE(trgint)); + /* Setup the MT7530 TRGMII Tx Clock */ + core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1)); + core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0)); + core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); + core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta)); + core_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN | + RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN); + core_write(priv, CORE_PLL_GROUP2, RG_SYSPLL_EN_NORMAL | + RG_SYSPLL_VODEN | RG_SYSPLL_POSDIV(1)); + core_write(priv, CORE_PLL_GROUP7, RG_LCDDS_PCW_NCPO_CHG | + RG_LCCDS_C(3) | RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); - if (trgint) { - /* Disable the MT7530 TRGMII clocks */ - core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); - - /* Setup the MT7530 TRGMII Tx Clock */ - core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1)); - core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0)); - core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); - core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta)); - core_write(priv, CORE_PLL_GROUP4, - RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN | - RG_SYSPLL_BIAS_LPF_EN); - core_write(priv, CORE_PLL_GROUP2, - RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | - RG_SYSPLL_POSDIV(1)); - core_write(priv, CORE_PLL_GROUP7, - RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) | - RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); - - /* Enable the MT7530 TRGMII clocks */ - core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); - } + /* Enable the MT7530 TRGMII clocks */ + core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); return 0; } From 4ea4c040ddc8ee43d2bfe00fad8aa9b730711520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 6 Feb 2024 01:08:05 +0300 Subject: [PATCH 0881/2255] net: dsa: mt7530: call port 6 setup from mt7530_mac_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mt7530_pad_clk_setup() is called if port 6 is enabled. It used to do more things than setting up port 6. That part was moved to more appropriate locations, mt7530_setup() and mt7530_pll_setup(). Now that all it does is set up port 6, rename it to mt7530_setup_port6(), and move it to a more appropriate location, under mt7530_mac_config(). Change mt7530_setup_port6() to void as there're no error cases. Leave an empty mt7530_pad_clk_setup() to satisfy the pad_setup function pointer. This is the code path for setting up the ports before: dsa_switch_ops :: phylink_mac_config() -> mt753x_phylink_mac_config() -> mt753x_mac_config() -> mt753x_info :: mac_port_config() -> mt7530_mac_config() -> mt7530_setup_port5() -> mt753x_pad_setup() -> mt753x_info :: pad_setup() -> mt7530_pad_clk_setup() This is after: dsa_switch_ops :: phylink_mac_config() -> mt753x_phylink_mac_config() -> mt753x_mac_config() -> mt753x_info :: mac_port_config() -> mt7530_mac_config() -> mt7530_setup_port5() -> mt7530_setup_port6() Reviewed-by: Vladimir Oltean Reviewed-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-4-d7d92a185cb1@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index ff72f5c6d80d..46758aef767d 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -414,8 +414,8 @@ mt753x_preferred_default_local_cpu_port(struct dsa_switch *ds) } /* Setup port 6 interface mode and TRGMII TX circuit */ -static int -mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) +static void +mt7530_setup_port6(struct dsa_switch *ds, phy_interface_t interface) { struct mt7530_priv *priv = ds->priv; u32 ncpo1, ssc_delta, xtal; @@ -426,7 +426,7 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) if (interface == PHY_INTERFACE_MODE_RGMII) { mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(0)); - return 0; + return; } mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1)); @@ -465,7 +465,11 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) /* Enable the MT7530 TRGMII clocks */ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); +} +static int +mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) +{ return 0; } @@ -2613,11 +2617,10 @@ mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode, { struct mt7530_priv *priv = ds->priv; - /* Only need to setup port5. */ - if (port != 5) - return 0; - - mt7530_setup_port5(priv->ds, interface); + if (port == 5) + mt7530_setup_port5(priv->ds, interface); + else if (port == 6) + mt7530_setup_port6(priv->ds, interface); return 0; } From 8c2703f558379b89d079fe437659db9564977893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 6 Feb 2024 01:08:06 +0300 Subject: [PATCH 0882/2255] net: dsa: mt7530: remove pad_setup function pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pad_setup function pointer was introduced with 88bdef8be9f6 ("net: dsa: mt7530: Extend device data ready for adding a new hardware"). It was being used to set up the core clock and port 6 of the MT7530 switch, and pll of the MT7531 switch. All of these were moved to more appropriate locations, and it was never used for the switch on the MT7988 SoC. Therefore, this function pointer hasn't got a use anymore. Remove it. Acked-by: Daniel Golle Reviewed-by: Vladimir Oltean Reviewed-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-5-d7d92a185cb1@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 36 ++---------------------------------- drivers/net/dsa/mt7530.h | 3 --- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 46758aef767d..b6ca373a7a50 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -467,18 +467,6 @@ mt7530_setup_port6(struct dsa_switch *ds, phy_interface_t interface) core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN); } -static int -mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) -{ - return 0; -} - -static int -mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface) -{ - return 0; -} - static void mt7531_pll_setup(struct mt7530_priv *priv) { @@ -2603,14 +2591,6 @@ static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, } } -static int -mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state) -{ - struct mt7530_priv *priv = ds->priv; - - return priv->info->pad_setup(ds, state->interface); -} - static int mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) @@ -2776,8 +2756,6 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, if (priv->p6_interface == state->interface) break; - mt753x_pad_setup(ds, state); - if (mt753x_mac_config(ds, port, mode, state) < 0) goto unsupported; @@ -3094,11 +3072,6 @@ mt753x_conduit_state_change(struct dsa_switch *ds, mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val); } -static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface) -{ - return 0; -} - static int mt7988_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; @@ -3162,7 +3135,6 @@ const struct mt753x_info mt753x_table[] = { .phy_write_c22 = mt7530_phy_write_c22, .phy_read_c45 = mt7530_phy_read_c45, .phy_write_c45 = mt7530_phy_write_c45, - .pad_setup = mt7530_pad_clk_setup, .mac_port_get_caps = mt7530_mac_port_get_caps, .mac_port_config = mt7530_mac_config, }, @@ -3174,7 +3146,6 @@ const struct mt753x_info mt753x_table[] = { .phy_write_c22 = mt7530_phy_write_c22, .phy_read_c45 = mt7530_phy_read_c45, .phy_write_c45 = mt7530_phy_write_c45, - .pad_setup = mt7530_pad_clk_setup, .mac_port_get_caps = mt7530_mac_port_get_caps, .mac_port_config = mt7530_mac_config, }, @@ -3186,7 +3157,6 @@ const struct mt753x_info mt753x_table[] = { .phy_write_c22 = mt7531_ind_c22_phy_write, .phy_read_c45 = mt7531_ind_c45_phy_read, .phy_write_c45 = mt7531_ind_c45_phy_write, - .pad_setup = mt7531_pad_setup, .cpu_port_config = mt7531_cpu_port_config, .mac_port_get_caps = mt7531_mac_port_get_caps, .mac_port_config = mt7531_mac_config, @@ -3199,7 +3169,6 @@ const struct mt753x_info mt753x_table[] = { .phy_write_c22 = mt7531_ind_c22_phy_write, .phy_read_c45 = mt7531_ind_c45_phy_read, .phy_write_c45 = mt7531_ind_c45_phy_write, - .pad_setup = mt7988_pad_setup, .cpu_port_config = mt7988_cpu_port_config, .mac_port_get_caps = mt7988_mac_port_get_caps, .mac_port_config = mt7988_mac_config, @@ -3229,9 +3198,8 @@ mt7530_probe_common(struct mt7530_priv *priv) /* Sanity check if these required device operations are filled * properly. */ - if (!priv->info->sw_setup || !priv->info->pad_setup || - !priv->info->phy_read_c22 || !priv->info->phy_write_c22 || - !priv->info->mac_port_get_caps || + if (!priv->info->sw_setup || !priv->info->phy_read_c22 || + !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps || !priv->info->mac_port_config) return -EINVAL; diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 80060cc740d2..26a6d2160c08 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -704,8 +704,6 @@ struct mt753x_pcs { * @phy_write_c22: Holding the way writing PHY port using C22 * @phy_read_c45: Holding the way reading PHY port using C45 * @phy_write_c45: Holding the way writing PHY port using C45 - * @pad_setup: Holding the way setting up the bus pad for a certain - * MAC port * @phy_mode_supported: Check if the PHY type is being supported on a certain * port * @mac_port_validate: Holding the way to set addition validate type for a @@ -726,7 +724,6 @@ struct mt753x_info { int regnum); int (*phy_write_c45)(struct mt7530_priv *priv, int port, int devad, int regnum, u16 val); - int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface); int (*cpu_port_config)(struct dsa_switch *ds, int port); void (*mac_port_get_caps)(struct dsa_switch *ds, int port, struct phylink_config *config); From c9d70a1d3d64cf4bc5646f2dabe6879650033896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 6 Feb 2024 01:08:07 +0300 Subject: [PATCH 0883/2255] net: dsa: mt7530: correct port capabilities of MT7988 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the switch on the MT7988 SoC, as shown in Block Diagram 8.1.1.3 on page 125 of "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open Version) v0.1", there are only 4 PHYs. That's port 0 to 3. Set the case for ports which connect to switch PHYs to '0 ... 3'. Port 4 and 5 are not used at all in this design. Link: https://wiki.banana-pi.org/Banana_Pi_BPI-R4#Documents [1] Acked-by: Daniel Golle Reviewed-by: Vladimir Oltean Signed-off-by: Arınç ÜNAL Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-6-d7d92a185cb1@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b6ca373a7a50..6b29dec7c6bb 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2577,7 +2577,7 @@ static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, switch (port) { /* Ports which are connected to switch PHYs. There is no MII pinout. */ - case 0 ... 4: + case 0 ... 3: __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); break; From b43990bc552ed8d772269d856766795bb8a85dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 6 Feb 2024 01:08:08 +0300 Subject: [PATCH 0884/2255] net: dsa: mt7530: do not clear config->supported_interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to clear the config->supported_interfaces bitmap before reporting the supported interfaces as all bits in the bitmap will already be initialized to zero when the phylink_config structure is allocated. The "config" pointer points to &dp->phylink_config, and "dp" is allocated by dsa_port_touch() with kzalloc(), so all its fields are filled with zeroes. There's no code that would change the bitmap beforehand. Remove it. Acked-by: Daniel Golle Reviewed-by: Vladimir Oltean Reviewed-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-7-d7d92a185cb1@arinc9.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 6b29dec7c6bb..03d966fa67b2 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2573,8 +2573,6 @@ static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { - phy_interface_zero(config->supported_interfaces); - switch (port) { /* Ports which are connected to switch PHYs. There is no MII pinout. */ case 0 ... 3: From fd4f101edbd9f99567ab2adb1f2169579ede7c13 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:42:57 +0000 Subject: [PATCH 0885/2255] net: add exit_batch_rtnl() method Many (struct pernet_operations)->exit_batch() methods have to acquire rtnl. In presence of rtnl mutex pressure, this makes cleanup_net() very slow. This patch adds a new exit_batch_rtnl() method to reduce number of rtnl acquisitions from cleanup_net(). exit_batch_rtnl() handlers are called while rtnl is locked, and devices to be killed can be queued in a list provided as their second argument. A single unregister_netdevice_many() is called right before rtnl is released. exit_batch_rtnl() handlers are called before ->exit() and ->exit_batch() handlers. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/net_namespace.h | 3 +++ net/core/net_namespace.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index cd0c2eedbb5e..20c34bd7a077 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -448,6 +448,9 @@ struct pernet_operations { void (*pre_exit)(struct net *net); void (*exit)(struct net *net); void (*exit_batch)(struct list_head *net_exit_list); + /* Following method is called with RTNL held. */ + void (*exit_batch_rtnl)(struct list_head *net_exit_list, + struct list_head *dev_kill_list); unsigned int *id; size_t size; }; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 72799533426b..233ec0cdd011 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -318,8 +318,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) { /* Must be called with pernet_ops_rwsem held */ const struct pernet_operations *ops, *saved_ops; - int error = 0; LIST_HEAD(net_exit_list); + LIST_HEAD(dev_kill_list); + int error = 0; refcount_set(&net->ns.count, 1); ref_tracker_dir_init(&net->refcnt_tracker, 128, "net refcnt"); @@ -357,6 +358,15 @@ out_undo: synchronize_rcu(); + ops = saved_ops; + rtnl_lock(); + list_for_each_entry_continue_reverse(ops, &pernet_list, list) { + if (ops->exit_batch_rtnl) + ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list); + } + unregister_netdevice_many(&dev_kill_list); + rtnl_unlock(); + ops = saved_ops; list_for_each_entry_continue_reverse(ops, &pernet_list, list) ops_exit_list(ops, &net_exit_list); @@ -573,6 +583,7 @@ static void cleanup_net(struct work_struct *work) struct net *net, *tmp, *last; struct llist_node *net_kill_list; LIST_HEAD(net_exit_list); + LIST_HEAD(dev_kill_list); /* Atomically snapshot the list of namespaces to cleanup */ net_kill_list = llist_del_all(&cleanup_list); @@ -613,6 +624,14 @@ static void cleanup_net(struct work_struct *work) */ synchronize_rcu(); + rtnl_lock(); + list_for_each_entry_reverse(ops, &pernet_list, list) { + if (ops->exit_batch_rtnl) + ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list); + } + unregister_netdevice_many(&dev_kill_list); + rtnl_unlock(); + /* Run all of the network namespace exit methods */ list_for_each_entry_reverse(ops, &pernet_list, list) ops_exit_list(ops, &net_exit_list); @@ -1193,7 +1212,17 @@ static void free_exit_list(struct pernet_operations *ops, struct list_head *net_ { ops_pre_exit_list(ops, net_exit_list); synchronize_rcu(); + + if (ops->exit_batch_rtnl) { + LIST_HEAD(dev_kill_list); + + rtnl_lock(); + ops->exit_batch_rtnl(net_exit_list, &dev_kill_list); + unregister_netdevice_many(&dev_kill_list); + rtnl_unlock(); + } ops_exit_list(ops, net_exit_list); + ops_free_list(ops, net_exit_list); } From a7ec2512ad7b23340059f59f3fd710cab056791a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:42:59 +0000 Subject: [PATCH 0886/2255] nexthop: convert nexthop_net_exit_batch to exit_batch_rtnl method exit_batch_rtnl() is called while RTNL is held. This saves one rtnl_lock()/rtnl_unlock() pair. We also need to create nexthop_net_exit() to make sure net->nexthop.devhash is not freed too soon, otherwise we will not be able to unregister netdev from exit_batch_rtnl() methods. Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-4-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/nexthop.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index bbff68b5b5d4..7270a8631406 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -3737,16 +3737,20 @@ out: } EXPORT_SYMBOL(nexthop_res_grp_activity_update); -static void __net_exit nexthop_net_exit_batch(struct list_head *net_list) +static void __net_exit nexthop_net_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { struct net *net; - rtnl_lock(); - list_for_each_entry(net, net_list, exit_list) { + ASSERT_RTNL(); + list_for_each_entry(net, net_list, exit_list) flush_all_nexthops(net); - kfree(net->nexthop.devhash); - } - rtnl_unlock(); +} + +static void __net_exit nexthop_net_exit(struct net *net) +{ + kfree(net->nexthop.devhash); + net->nexthop.devhash = NULL; } static int __net_init nexthop_net_init(struct net *net) @@ -3764,7 +3768,8 @@ static int __net_init nexthop_net_init(struct net *net) static struct pernet_operations nexthop_net_ops = { .init = nexthop_net_init, - .exit_batch = nexthop_net_exit_batch, + .exit = nexthop_net_exit, + .exit_batch_rtnl = nexthop_net_exit_batch_rtnl, }; static int __init nexthop_init(void) From 422b5ae9c5e507f913118d086431c46022aa50c2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:00 +0000 Subject: [PATCH 0887/2255] bareudp: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair, and one unregister_netdevice_many() call. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-5-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/bareudp.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index 31377bb1cc97..4db6122c9b43 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -760,23 +760,18 @@ static void bareudp_destroy_tunnels(struct net *net, struct list_head *head) unregister_netdevice_queue(bareudp->dev, head); } -static void __net_exit bareudp_exit_batch_net(struct list_head *net_list) +static void __net_exit bareudp_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_kill_list) { struct net *net; - LIST_HEAD(list); - rtnl_lock(); list_for_each_entry(net, net_list, exit_list) - bareudp_destroy_tunnels(net, &list); - - /* unregister the devices gathered above */ - unregister_netdevice_many(&list); - rtnl_unlock(); + bareudp_destroy_tunnels(net, dev_kill_list); } static struct pernet_operations bareudp_net_ops = { .init = bareudp_init_net, - .exit_batch = bareudp_exit_batch_net, + .exit_batch_rtnl = bareudp_exit_batch_rtnl, .id = &bareudp_net_id, .size = sizeof(struct bareudp_net), }; From 669966bc94d82e614d894899328486613769f0c6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:01 +0000 Subject: [PATCH 0888/2255] bonding: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair, and one unregister_netdevice_many() call. v2: Added bond_net_pre_exit() method to make sure bond_destroy_sysfs() is called before we unregister the devices in bond_net_exit_batch_rtnl (Antoine Tenart : https://lore.kernel.org/netdev/170688415193.5216.10499830272732622816@kwain/) Signed-off-by: Eric Dumazet Acked-by: Jay Vosburgh Cc: Andy Gospodarek Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-6-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 37 +++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ae9d32c0faf4..cb67ece47328 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -6416,28 +6416,41 @@ static int __net_init bond_net_init(struct net *net) return 0; } -static void __net_exit bond_net_exit_batch(struct list_head *net_list) +/* According to commit 69b0216ac255 ("bonding: fix bonding_masters + * race condition in bond unloading") we need to remove sysfs files + * before we remove our devices (done later in bond_net_exit_batch_rtnl()) + */ +static void __net_exit bond_net_pre_exit(struct net *net) +{ + struct bond_net *bn = net_generic(net, bond_net_id); + + bond_destroy_sysfs(bn); +} + +static void __net_exit bond_net_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_kill_list) { struct bond_net *bn; struct net *net; - LIST_HEAD(list); - - list_for_each_entry(net, net_list, exit_list) { - bn = net_generic(net, bond_net_id); - bond_destroy_sysfs(bn); - } /* Kill off any bonds created after unregistering bond rtnl ops */ - rtnl_lock(); list_for_each_entry(net, net_list, exit_list) { struct bonding *bond, *tmp_bond; bn = net_generic(net, bond_net_id); list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list) - unregister_netdevice_queue(bond->dev, &list); + unregister_netdevice_queue(bond->dev, dev_kill_list); } - unregister_netdevice_many(&list); - rtnl_unlock(); +} + +/* According to commit 23fa5c2caae0 ("bonding: destroy proc directory + * only after all bonds are gone") bond_destroy_proc_dir() is called + * after bond_net_exit_batch_rtnl() has completed. + */ +static void __net_exit bond_net_exit_batch(struct list_head *net_list) +{ + struct bond_net *bn; + struct net *net; list_for_each_entry(net, net_list, exit_list) { bn = net_generic(net, bond_net_id); @@ -6447,6 +6460,8 @@ static void __net_exit bond_net_exit_batch(struct list_head *net_list) static struct pernet_operations bond_net_ops = { .init = bond_net_init, + .pre_exit = bond_net_pre_exit, + .exit_batch_rtnl = bond_net_exit_batch_rtnl, .exit_batch = bond_net_exit_batch, .id = &bond_net_id, .size = sizeof(struct bond_net), From f4b57b9dc96bbdb5beb2c93619c7904e4909b366 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:02 +0000 Subject: [PATCH 0889/2255] geneve: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair, and one unregister_netdevice_many() call. Note: it should be possible to remove the synchronize_net() call from geneve_sock_release() in a future patch. v4: move WARN_ON_ONCE(!list_empty(&gn->sock_list)) into geneve_exit_net(), after devices have been unregistered. (Antoine Tenart feedback) Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-7-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/geneve.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 32c51c244153..23e97c2e4f6f 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1900,29 +1900,26 @@ static void geneve_destroy_tunnels(struct net *net, struct list_head *head) } } -static void __net_exit geneve_exit_batch_net(struct list_head *net_list) +static void __net_exit geneve_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { struct net *net; - LIST_HEAD(list); - rtnl_lock(); list_for_each_entry(net, net_list, exit_list) - geneve_destroy_tunnels(net, &list); + geneve_destroy_tunnels(net, dev_to_kill); +} - /* unregister the devices gathered above */ - unregister_netdevice_many(&list); - rtnl_unlock(); +static void __net_exit geneve_exit_net(struct net *net) +{ + const struct geneve_net *gn = net_generic(net, geneve_net_id); - list_for_each_entry(net, net_list, exit_list) { - const struct geneve_net *gn = net_generic(net, geneve_net_id); - - WARN_ON_ONCE(!list_empty(&gn->sock_list)); - } + WARN_ON_ONCE(!list_empty(&gn->sock_list)); } static struct pernet_operations geneve_net_ops = { .init = geneve_init_net, - .exit_batch = geneve_exit_batch_net, + .exit_batch_rtnl = geneve_exit_batch_rtnl, + .exit = geneve_exit_net, .id = &geneve_net_id, .size = sizeof(struct geneve_net), }; From 6eedda01b2bfdcf427b37759e053dc27232f3af1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:03 +0000 Subject: [PATCH 0890/2255] gtp: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair per netns and one unregister_netdevice_many() call per netns. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-8-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/gtp.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index b1919278e931..62c601d9f752 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -1876,23 +1876,23 @@ static int __net_init gtp_net_init(struct net *net) return 0; } -static void __net_exit gtp_net_exit(struct net *net) +static void __net_exit gtp_net_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { - struct gtp_net *gn = net_generic(net, gtp_net_id); - struct gtp_dev *gtp; - LIST_HEAD(list); + struct net *net; - rtnl_lock(); - list_for_each_entry(gtp, &gn->gtp_dev_list, list) - gtp_dellink(gtp->dev, &list); + list_for_each_entry(net, net_list, exit_list) { + struct gtp_net *gn = net_generic(net, gtp_net_id); + struct gtp_dev *gtp; - unregister_netdevice_many(&list); - rtnl_unlock(); + list_for_each_entry(gtp, &gn->gtp_dev_list, list) + gtp_dellink(gtp->dev, dev_to_kill); + } } static struct pernet_operations gtp_net_ops = { .init = gtp_net_init, - .exit = gtp_net_exit, + .exit_batch_rtnl = gtp_net_exit_batch_rtnl, .id = >p_net_id, .size = sizeof(struct gtp_net), }; From 70f16ea2e4f673fc769fd13c00c20a32b4fe238a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:04 +0000 Subject: [PATCH 0891/2255] ipv4: add __unregister_nexthop_notifier() unregister_nexthop_notifier() assumes the caller does not hold rtnl. We need in the following patch to use it from a context already holding rtnl. Add __unregister_nexthop_notifier(). unregister_nexthop_notifier() becomes a wrapper. Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-9-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/nexthop.h | 1 + net/ipv4/nexthop.c | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/net/nexthop.h b/include/net/nexthop.h index d92046a4a078..6647ad509faa 100644 --- a/include/net/nexthop.h +++ b/include/net/nexthop.h @@ -218,6 +218,7 @@ struct nh_notifier_info { int register_nexthop_notifier(struct net *net, struct notifier_block *nb, struct netlink_ext_ack *extack); +int __unregister_nexthop_notifier(struct net *net, struct notifier_block *nb); int unregister_nexthop_notifier(struct net *net, struct notifier_block *nb); void nexthop_set_hw_flags(struct net *net, u32 id, bool offload, bool trap); void nexthop_bucket_set_hw_flags(struct net *net, u32 id, u16 bucket_index, diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index 7270a8631406..70509da4f080 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -3631,17 +3631,24 @@ unlock: } EXPORT_SYMBOL(register_nexthop_notifier); +int __unregister_nexthop_notifier(struct net *net, struct notifier_block *nb) +{ + int err; + + err = blocking_notifier_chain_unregister(&net->nexthop.notifier_chain, + nb); + if (!err) + nexthops_dump(net, nb, NEXTHOP_EVENT_DEL, NULL); + return err; +} +EXPORT_SYMBOL(__unregister_nexthop_notifier); + int unregister_nexthop_notifier(struct net *net, struct notifier_block *nb) { int err; rtnl_lock(); - err = blocking_notifier_chain_unregister(&net->nexthop.notifier_chain, - nb); - if (err) - goto unlock; - nexthops_dump(net, nb, NEXTHOP_EVENT_DEL, NULL); -unlock: + err = __unregister_nexthop_notifier(net, nb); rtnl_unlock(); return err; } From 110d3047a3ec033de00322b1a8068b1215efa97a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:05 +0000 Subject: [PATCH 0892/2255] vxlan: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair per netns and one unregister_netdevice_many() call. v4: (Paolo feedback : https://netdev-3.bots.linux.dev/vmksft-net/results/453141/17-udpgro-fwd-sh/stdout ) - Changed vxlan_destroy_tunnels() to use vxlan_dellink() instead of unregister_netdevice_queue to propely remove devices from vn->vxlan_list. - vxlan_destroy_tunnels() can simply iterate one list (vn->vxlan_list) to find all devices in the most efficient way. - Moved sanity checks in a separate vxlan_exit_net() method. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-10-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/vxlan/vxlan_core.c | 60 ++++++++++++++-------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 16106e088c63..11707647afb9 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -4826,55 +4826,43 @@ static __net_init int vxlan_init_net(struct net *net) NULL); } -static void vxlan_destroy_tunnels(struct net *net, struct list_head *head) +static void __net_exit vxlan_destroy_tunnels(struct vxlan_net *vn, + struct list_head *dev_to_kill) { - struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_dev *vxlan, *next; - struct net_device *dev, *aux; - - for_each_netdev_safe(net, dev, aux) - if (dev->rtnl_link_ops == &vxlan_link_ops) - unregister_netdevice_queue(dev, head); - - list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) { - /* If vxlan->dev is in the same netns, it has already been added - * to the list by the previous loop. - */ - if (!net_eq(dev_net(vxlan->dev), net)) - unregister_netdevice_queue(vxlan->dev, head); - } + list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) + vxlan_dellink(vxlan->dev, dev_to_kill); } -static void __net_exit vxlan_exit_batch_net(struct list_head *net_list) +static void __net_exit vxlan_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { struct net *net; - LIST_HEAD(list); + + ASSERT_RTNL(); + list_for_each_entry(net, net_list, exit_list) { + struct vxlan_net *vn = net_generic(net, vxlan_net_id); + + __unregister_nexthop_notifier(net, &vn->nexthop_notifier_block); + + vxlan_destroy_tunnels(vn, dev_to_kill); + } +} + +static void __net_exit vxlan_exit_net(struct net *net) +{ + struct vxlan_net *vn = net_generic(net, vxlan_net_id); unsigned int h; - list_for_each_entry(net, net_list, exit_list) { - struct vxlan_net *vn = net_generic(net, vxlan_net_id); - - unregister_nexthop_notifier(net, &vn->nexthop_notifier_block); - } - rtnl_lock(); - list_for_each_entry(net, net_list, exit_list) - vxlan_destroy_tunnels(net, &list); - - unregister_netdevice_many(&list); - rtnl_unlock(); - - list_for_each_entry(net, net_list, exit_list) { - struct vxlan_net *vn = net_generic(net, vxlan_net_id); - - for (h = 0; h < PORT_HASH_SIZE; ++h) - WARN_ON_ONCE(!hlist_empty(&vn->sock_list[h])); - } + for (h = 0; h < PORT_HASH_SIZE; ++h) + WARN_ON_ONCE(!hlist_empty(&vn->sock_list[h])); } static struct pernet_operations vxlan_net_ops = { .init = vxlan_init_net, - .exit_batch = vxlan_exit_batch_net, + .exit_batch_rtnl = vxlan_exit_batch_rtnl, + .exit = vxlan_exit_net, .id = &vxlan_net_id, .size = sizeof(struct vxlan_net), }; From bc50c535c3a011605f4e0d219431a8e42249e71e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:06 +0000 Subject: [PATCH 0893/2255] ip6_gre: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair and one unregister_netdevice_many() call. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-11-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/ip6_gre.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 070d87abf7c0..428f03e9da45 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1632,21 +1632,19 @@ err_alloc_dev: return err; } -static void __net_exit ip6gre_exit_batch_net(struct list_head *net_list) +static void __net_exit ip6gre_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { struct net *net; - LIST_HEAD(list); - rtnl_lock(); + ASSERT_RTNL(); list_for_each_entry(net, net_list, exit_list) - ip6gre_destroy_tunnels(net, &list); - unregister_netdevice_many(&list); - rtnl_unlock(); + ip6gre_destroy_tunnels(net, dev_to_kill); } static struct pernet_operations ip6gre_net_ops = { .init = ip6gre_init_net, - .exit_batch = ip6gre_exit_batch_net, + .exit_batch_rtnl = ip6gre_exit_batch_rtnl, .id = &ip6gre_net_id, .size = sizeof(struct ip6gre_net), }; From a1fab9aff5c05589ece2893a8d312f16eb0ff5e6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:07 +0000 Subject: [PATCH 0894/2255] ip6_tunnel: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair and one unregister_netdevice_many() call. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-12-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/ip6_tunnel.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9bbabf750a21..bfb0a6c601c1 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -2282,21 +2282,19 @@ err_alloc_dev: return err; } -static void __net_exit ip6_tnl_exit_batch_net(struct list_head *net_list) +static void __net_exit ip6_tnl_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { struct net *net; - LIST_HEAD(list); - rtnl_lock(); + ASSERT_RTNL(); list_for_each_entry(net, net_list, exit_list) - ip6_tnl_destroy_tunnels(net, &list); - unregister_netdevice_many(&list); - rtnl_unlock(); + ip6_tnl_destroy_tunnels(net, dev_to_kill); } static struct pernet_operations ip6_tnl_net_ops = { .init = ip6_tnl_init_net, - .exit_batch = ip6_tnl_exit_batch_net, + .exit_batch_rtnl = ip6_tnl_exit_batch_rtnl, .id = &ip6_tnl_net_id, .size = sizeof(struct ip6_tnl_net), }; From 7a99f3c1994b2c3add235090d8721bfbb2b95320 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:08 +0000 Subject: [PATCH 0895/2255] ip6_vti: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair and one unregister_netdevice_many() call. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-13-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/ip6_vti.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index e550240c85e1..cfe1b1ad4d85 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -1174,24 +1174,22 @@ err_alloc_dev: return err; } -static void __net_exit vti6_exit_batch_net(struct list_head *net_list) +static void __net_exit vti6_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { struct vti6_net *ip6n; struct net *net; - LIST_HEAD(list); - rtnl_lock(); + ASSERT_RTNL(); list_for_each_entry(net, net_list, exit_list) { ip6n = net_generic(net, vti6_net_id); - vti6_destroy_tunnels(ip6n, &list); + vti6_destroy_tunnels(ip6n, dev_to_kill); } - unregister_netdevice_many(&list); - rtnl_unlock(); } static struct pernet_operations vti6_net_ops = { .init = vti6_init_net, - .exit_batch = vti6_exit_batch_net, + .exit_batch_rtnl = vti6_exit_batch_rtnl, .id = &vti6_net_id, .size = sizeof(struct vti6_net), }; From de02deab27fd63063e056811d0473ad5b9a56e5e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:09 +0000 Subject: [PATCH 0896/2255] sit: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair and one unregister_netdevice_many() call. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-14-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/sit.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index cc24cefdb85c..61b2b71fa8be 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1875,22 +1875,19 @@ err_alloc_dev: return err; } -static void __net_exit sit_exit_batch_net(struct list_head *net_list) +static void __net_exit sit_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { - LIST_HEAD(list); struct net *net; - rtnl_lock(); + ASSERT_RTNL(); list_for_each_entry(net, net_list, exit_list) - sit_destroy_tunnels(net, &list); - - unregister_netdevice_many(&list); - rtnl_unlock(); + sit_destroy_tunnels(net, dev_to_kill); } static struct pernet_operations sit_net_ops = { .init = sit_init_net, - .exit_batch = sit_exit_batch_net, + .exit_batch_rtnl = sit_exit_batch_rtnl, .id = &sit_net_id, .size = sizeof(struct sit_net), }; From 9b5b36374ed6953f3efcc82e7cb4c353b9869faf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:10 +0000 Subject: [PATCH 0897/2255] ip_tunnel: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair and one unregister_netdevice_many() call. This patch takes care of ipip, ip_vti, and ip_gre tunnels. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-15-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/ip_tunnels.h | 3 ++- net/ipv4/ip_gre.c | 24 +++++++++++++++--------- net/ipv4/ip_tunnel.c | 10 ++++------ net/ipv4/ip_vti.c | 8 +++++--- net/ipv4/ipip.c | 8 +++++--- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 2d746f4c9a0a..5cd64bb2104d 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -284,7 +284,8 @@ int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id, struct rtnl_link_ops *ops, char *devname); void ip_tunnel_delete_nets(struct list_head *list_net, unsigned int id, - struct rtnl_link_ops *ops); + struct rtnl_link_ops *ops, + struct list_head *dev_to_kill); void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, const struct iphdr *tnl_params, const u8 protocol); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 5169c3c72cff..aad5125b7a65 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1025,14 +1025,16 @@ static int __net_init ipgre_init_net(struct net *net) return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL); } -static void __net_exit ipgre_exit_batch_net(struct list_head *list_net) +static void __net_exit ipgre_exit_batch_rtnl(struct list_head *list_net, + struct list_head *dev_to_kill) { - ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops); + ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops, + dev_to_kill); } static struct pernet_operations ipgre_net_ops = { .init = ipgre_init_net, - .exit_batch = ipgre_exit_batch_net, + .exit_batch_rtnl = ipgre_exit_batch_rtnl, .id = &ipgre_net_id, .size = sizeof(struct ip_tunnel_net), }; @@ -1697,14 +1699,16 @@ static int __net_init ipgre_tap_init_net(struct net *net) return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0"); } -static void __net_exit ipgre_tap_exit_batch_net(struct list_head *list_net) +static void __net_exit ipgre_tap_exit_batch_rtnl(struct list_head *list_net, + struct list_head *dev_to_kill) { - ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops); + ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops, + dev_to_kill); } static struct pernet_operations ipgre_tap_net_ops = { .init = ipgre_tap_init_net, - .exit_batch = ipgre_tap_exit_batch_net, + .exit_batch_rtnl = ipgre_tap_exit_batch_rtnl, .id = &gre_tap_net_id, .size = sizeof(struct ip_tunnel_net), }; @@ -1715,14 +1719,16 @@ static int __net_init erspan_init_net(struct net *net) &erspan_link_ops, "erspan0"); } -static void __net_exit erspan_exit_batch_net(struct list_head *net_list) +static void __net_exit erspan_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { - ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops); + ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops, + dev_to_kill); } static struct pernet_operations erspan_net_ops = { .init = erspan_init_net, - .exit_batch = erspan_exit_batch_net, + .exit_batch_rtnl = erspan_exit_batch_rtnl, .id = &erspan_net_id, .size = sizeof(struct ip_tunnel_net), }; diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index beeae624c412..00da0b80320f 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1130,19 +1130,17 @@ static void ip_tunnel_destroy(struct net *net, struct ip_tunnel_net *itn, } void ip_tunnel_delete_nets(struct list_head *net_list, unsigned int id, - struct rtnl_link_ops *ops) + struct rtnl_link_ops *ops, + struct list_head *dev_to_kill) { struct ip_tunnel_net *itn; struct net *net; - LIST_HEAD(list); - rtnl_lock(); + ASSERT_RTNL(); list_for_each_entry(net, net_list, exit_list) { itn = net_generic(net, id); - ip_tunnel_destroy(net, itn, &list, ops); + ip_tunnel_destroy(net, itn, dev_to_kill, ops); } - unregister_netdevice_many(&list); - rtnl_unlock(); } EXPORT_SYMBOL_GPL(ip_tunnel_delete_nets); diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 9ab9b3ebe0cd..fb1f52d21311 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -510,14 +510,16 @@ static int __net_init vti_init_net(struct net *net) return 0; } -static void __net_exit vti_exit_batch_net(struct list_head *list_net) +static void __net_exit vti_exit_batch_rtnl(struct list_head *list_net, + struct list_head *dev_to_kill) { - ip_tunnel_delete_nets(list_net, vti_net_id, &vti_link_ops); + ip_tunnel_delete_nets(list_net, vti_net_id, &vti_link_ops, + dev_to_kill); } static struct pernet_operations vti_net_ops = { .init = vti_init_net, - .exit_batch = vti_exit_batch_net, + .exit_batch_rtnl = vti_exit_batch_rtnl, .id = &vti_net_id, .size = sizeof(struct ip_tunnel_net), }; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 27b8f83c6ea2..0151eea06cc5 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -592,14 +592,16 @@ static int __net_init ipip_init_net(struct net *net) return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); } -static void __net_exit ipip_exit_batch_net(struct list_head *list_net) +static void __net_exit ipip_exit_batch_rtnl(struct list_head *list_net, + struct list_head *dev_to_kill) { - ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops); + ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops, + dev_to_kill); } static struct pernet_operations ipip_net_ops = { .init = ipip_init_net, - .exit_batch = ipip_exit_batch_net, + .exit_batch_rtnl = ipip_exit_batch_rtnl, .id = &ipip_net_id, .size = sizeof(struct ip_tunnel_net), }; From 806b67850787bae3df1bc2e5a30e8c658c579d80 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:11 +0000 Subject: [PATCH 0898/2255] bridge: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair per netns and one unregister_netdevice_many() call. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-16-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/bridge/br.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/net/bridge/br.c b/net/bridge/br.c index ac19b797dbec..2cab878e0a39 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -356,26 +356,21 @@ void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on) clear_bit(opt, &br->options); } -static void __net_exit br_net_exit_batch(struct list_head *net_list) +static void __net_exit br_net_exit_batch_rtnl(struct list_head *net_list, + struct list_head *dev_to_kill) { struct net_device *dev; struct net *net; - LIST_HEAD(list); - - rtnl_lock(); + ASSERT_RTNL(); list_for_each_entry(net, net_list, exit_list) for_each_netdev(net, dev) if (netif_is_bridge_master(dev)) - br_dev_delete(dev, &list); - - unregister_netdevice_many(&list); - - rtnl_unlock(); + br_dev_delete(dev, dev_to_kill); } static struct pernet_operations br_net_ops = { - .exit_batch = br_net_exit_batch, + .exit_batch_rtnl = br_net_exit_batch_rtnl, }; static const struct stp_proto br_stp_proto = { From 8962daccc2d32812fe24bd21496c036eb4f454b0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Feb 2024 14:43:12 +0000 Subject: [PATCH 0899/2255] xfrm: interface: use exit_batch_rtnl() method exit_batch_rtnl() is called while RTNL is held, and devices to be unregistered can be queued in the dev_kill_list. This saves one rtnl_lock()/rtnl_unlock() pair per netns and one unregister_netdevice_many() call. Signed-off-by: Eric Dumazet Reviewed-by: Antoine Tenart Link: https://lore.kernel.org/r/20240206144313.2050392-17-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/xfrm/xfrm_interface_core.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/net/xfrm/xfrm_interface_core.c b/net/xfrm/xfrm_interface_core.c index 21d50d75c260..dafefef3cf51 100644 --- a/net/xfrm/xfrm_interface_core.c +++ b/net/xfrm/xfrm_interface_core.c @@ -957,12 +957,12 @@ static struct rtnl_link_ops xfrmi_link_ops __read_mostly = { .get_link_net = xfrmi_get_link_net, }; -static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list) +static void __net_exit xfrmi_exit_batch_rtnl(struct list_head *net_exit_list, + struct list_head *dev_to_kill) { struct net *net; - LIST_HEAD(list); - rtnl_lock(); + ASSERT_RTNL(); list_for_each_entry(net, net_exit_list, exit_list) { struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id); struct xfrm_if __rcu **xip; @@ -973,18 +973,16 @@ static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list) for (xip = &xfrmn->xfrmi[i]; (xi = rtnl_dereference(*xip)) != NULL; xip = &xi->next) - unregister_netdevice_queue(xi->dev, &list); + unregister_netdevice_queue(xi->dev, dev_to_kill); } xi = rtnl_dereference(xfrmn->collect_md_xfrmi); if (xi) - unregister_netdevice_queue(xi->dev, &list); + unregister_netdevice_queue(xi->dev, dev_to_kill); } - unregister_netdevice_many(&list); - rtnl_unlock(); } static struct pernet_operations xfrmi_net_ops = { - .exit_batch = xfrmi_exit_batch_net, + .exit_batch_rtnl = xfrmi_exit_batch_rtnl, .id = &xfrmi_net_id, .size = sizeof(struct xfrmi_net), }; From 2fd53eb04c492eb9a2b06f994b36e5cf34ba7541 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 16:49:07 +0100 Subject: [PATCH 0900/2255] wifi: mac80211: remove unused MAX_MSG_LEN define This got unused when the tracing was converted to dynamic strings, so the define can be removed. Signed-off-by: Johannes Berg --- net/mac80211/trace_msg.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/mac80211/trace_msg.h b/net/mac80211/trace_msg.h index c9dbe9aab7bd..aea4ce55c5ac 100644 --- a/net/mac80211/trace_msg.h +++ b/net/mac80211/trace_msg.h @@ -16,8 +16,6 @@ #undef TRACE_SYSTEM #define TRACE_SYSTEM mac80211_msg -#define MAX_MSG_LEN 120 - DECLARE_EVENT_CLASS(mac80211_msg_event, TP_PROTO(struct va_format *vaf), From efa2cce6e272b36c7f9687385ef4fd538cc3bf51 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 16:49:04 +0100 Subject: [PATCH 0901/2255] wifi: mac80211: remove extra shadowing variable Not sure how this happened or how nothing complained, but this variable already exists in the outer function scope with the same value (and the SKB isn't changed either.) Remove the extra one. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 615795c4b052..76798e8057f7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -5214,7 +5214,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, */ if (!status->link_valid && pubsta->mlo) { - struct ieee80211_hdr *hdr = (void *)skb->data; struct link_sta_info *link_sta; link_sta = link_sta_info_get_bss(rx.sdata, From 61f0261131c8dc2beeb6b34781a54788221081e9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:35 +0100 Subject: [PATCH 0902/2255] wifi: mac80211: clean up band switch in duration Most devices now do duration calculations, so we don't hit this code at all any more. Clearly the approach of warning at compile time here when new bands are added didn't work, the new bands were just added with "TODO". Clean it up, it won't matter for new bands since they'll just not have any need to calculate durations in software. While at it, also clean up and unify the code a bit. Link: https://msgid.link/20240129194108.70a97bd69265.Icdd8b0ac60a382244466510090eb0f5868151f39@changeid Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e448ab338448..7b33942ea51f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -133,6 +133,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, mrate = sband->bitrates[0].bitrate; for (i = 0; i < sband->n_bitrates; i++) { struct ieee80211_rate *r = &sband->bitrates[i]; + u32 flag; if (r->bitrate > txrate->bitrate) break; @@ -145,28 +146,24 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, switch (sband->band) { case NL80211_BAND_2GHZ: - case NL80211_BAND_LC: { - u32 flag; + case NL80211_BAND_LC: if (tx->sdata->deflink.operating_11g_mode) flag = IEEE80211_RATE_MANDATORY_G; else flag = IEEE80211_RATE_MANDATORY_B; - if (r->flags & flag) - mrate = r->bitrate; break; - } case NL80211_BAND_5GHZ: case NL80211_BAND_6GHZ: - if (r->flags & IEEE80211_RATE_MANDATORY_A) - mrate = r->bitrate; + flag = IEEE80211_RATE_MANDATORY_A; break; - case NL80211_BAND_S1GHZ: - case NL80211_BAND_60GHZ: - /* TODO, for now fall through */ - case NUM_NL80211_BANDS: + default: + flag = 0; WARN_ON(1); break; } + + if (r->flags & flag) + mrate = r->bitrate; } if (rate == -1) { /* No matching basic rate found; use highest suitable mandatory From 310c8387c63830bc375827242e0f9fa689f82e21 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:36 +0100 Subject: [PATCH 0903/2255] wifi: mac80211: clean up connection process Rewrite the station-side connection handling. The connection flags (IEEE80211_DISABLE_*) are rather confusing, and they're not always maintained well. Additionally, for wider-bandwidth OFDMA support we need to know the precise bandwidth of the AP, which is currently somewhat difficult. Rewrite this to have a 'mode' (S1G/legacy/HT/...) and a limit on the bandwidth. This is not entirely clean because some of those modes aren't completely sequenced (as this assumes in some places), e.g. VHT doesn't exist on 2.4 GHz, but HE does. However, it still simplifies things and gives us a good idea what we're operating as, so we can parse elements accordingly etc. This leaves a FIXME for puncturing, this is addressed in a later patch. Reviewed-by: Ilan Peer Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240129194108.9451722c0110.I3e61f4cfe9da89008e1854160093c76a1e69dc2a@changeid Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 2 +- net/mac80211/debug.h | 18 +- net/mac80211/ibss.c | 15 +- net/mac80211/ieee80211_i.h | 60 +- net/mac80211/mesh.c | 21 +- net/mac80211/mlme.c | 2075 +++++++++++++++++++----------------- net/mac80211/spectmgmt.c | 21 +- net/mac80211/tdls.c | 8 +- net/mac80211/tests/elems.c | 1 + net/mac80211/util.c | 164 ++- 10 files changed, 1328 insertions(+), 1057 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index ef4c2cebc080..70ba5dc4b283 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -382,7 +382,7 @@ _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, /* downgrade chandef up to max_bw */ min_def = ctx->conf.def; while (min_def.width > max_bw) - ieee80211_chandef_downgrade(&min_def); + ieee80211_chandef_downgrade(&min_def, NULL); if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def)) return 0; diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index d49894df2351..49da401c5340 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h @@ -152,16 +152,17 @@ do { \ else \ _sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \ } while (0) -#define link_dbg(link, fmt, ...) \ +#define _link_id_dbg(print, sdata, link_id, fmt, ...) \ do { \ - if (ieee80211_vif_is_mld(&(link)->sdata->vif)) \ - _sdata_dbg(1, (link)->sdata, "[link %d] " fmt, \ - (link)->link_id, \ - ##__VA_ARGS__); \ + if (ieee80211_vif_is_mld(&(sdata)->vif)) \ + _sdata_dbg(print, sdata, "[link %d] " fmt, \ + link_id, ##__VA_ARGS__); \ else \ - _sdata_dbg(1, (link)->sdata, fmt, \ - ##__VA_ARGS__); \ + _sdata_dbg(1, sdata, fmt, ##__VA_ARGS__); \ } while (0) +#define link_dbg(link, fmt, ...) \ + _link_id_dbg(1, (link)->sdata, (link)->link_id, \ + fmt, ##__VA_ARGS__) #define ht_dbg(sdata, fmt, ...) \ _sdata_dbg(MAC80211_HT_DEBUG, \ @@ -226,6 +227,9 @@ do { \ #define mlme_dbg(sdata, fmt, ...) \ _sdata_dbg(MAC80211_MLME_DEBUG, \ sdata, fmt, ##__VA_ARGS__) +#define mlme_link_id_dbg(sdata, link_id, fmt, ...) \ + _link_id_dbg(MAC80211_MLME_DEBUG, sdata, link_id, \ + fmt, ##__VA_ARGS__) #define mlme_dbg_ratelimited(sdata, fmt, ...) \ _sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(), \ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8f2b445a5ec3..c23f46218af7 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -757,21 +757,22 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; enum nl80211_channel_type ch_type; int err; - ieee80211_conn_flags_t conn_flags; + struct ieee80211_conn_settings conn = { + .mode = IEEE80211_CONN_MODE_HT, + .bw_limit = IEEE80211_CONN_BW_LIMIT_40, + }; u32 vht_cap_info = 0; lockdep_assert_wiphy(sdata->local->hw.wiphy); - conn_flags = IEEE80211_CONN_DISABLE_VHT; - switch (ifibss->chandef.width) { case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: case NL80211_CHAN_WIDTH_20_NOHT: - conn_flags |= IEEE80211_CONN_DISABLE_HT; + conn.mode = IEEE80211_CONN_MODE_LEGACY; fallthrough; case NL80211_CHAN_WIDTH_20: - conn_flags |= IEEE80211_CONN_DISABLE_40MHZ; + conn.bw_limit = IEEE80211_CONN_BW_LIMIT_20; break; default: break; @@ -783,8 +784,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, memset(¶ms, 0, sizeof(params)); err = ieee80211_parse_ch_switch_ie(sdata, elems, ifibss->chandef.chan->band, - vht_cap_info, - conn_flags, ifibss->bssid, &csa_ie); + vht_cap_info, &conn, + ifibss->bssid, &csa_ie); /* can't switch to destination channel, fail */ if (err < 0) goto disconnect; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index eb32174984c3..112029f5a7df 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -370,19 +370,32 @@ enum ieee80211_sta_flags { IEEE80211_STA_ENABLE_RRM = BIT(15), }; -typedef u32 __bitwise ieee80211_conn_flags_t; - -enum ieee80211_conn_flags { - IEEE80211_CONN_DISABLE_HT = (__force ieee80211_conn_flags_t)BIT(0), - IEEE80211_CONN_DISABLE_40MHZ = (__force ieee80211_conn_flags_t)BIT(1), - IEEE80211_CONN_DISABLE_VHT = (__force ieee80211_conn_flags_t)BIT(2), - IEEE80211_CONN_DISABLE_80P80MHZ = (__force ieee80211_conn_flags_t)BIT(3), - IEEE80211_CONN_DISABLE_160MHZ = (__force ieee80211_conn_flags_t)BIT(4), - IEEE80211_CONN_DISABLE_HE = (__force ieee80211_conn_flags_t)BIT(5), - IEEE80211_CONN_DISABLE_EHT = (__force ieee80211_conn_flags_t)BIT(6), - IEEE80211_CONN_DISABLE_320MHZ = (__force ieee80211_conn_flags_t)BIT(7), +enum ieee80211_conn_mode { + IEEE80211_CONN_MODE_S1G, + IEEE80211_CONN_MODE_LEGACY, + IEEE80211_CONN_MODE_HT, + IEEE80211_CONN_MODE_VHT, + IEEE80211_CONN_MODE_HE, + IEEE80211_CONN_MODE_EHT, }; +#define IEEE80211_CONN_MODE_HIGHEST IEEE80211_CONN_MODE_EHT + +enum ieee80211_conn_bw_limit { + IEEE80211_CONN_BW_LIMIT_20, + IEEE80211_CONN_BW_LIMIT_40, + IEEE80211_CONN_BW_LIMIT_80, + IEEE80211_CONN_BW_LIMIT_160, /* also 80+80 */ + IEEE80211_CONN_BW_LIMIT_320, +}; + +struct ieee80211_conn_settings { + enum ieee80211_conn_mode mode; + enum ieee80211_conn_bw_limit bw_limit; +}; + +extern const struct ieee80211_conn_settings ieee80211_conn_settings_unlimited; + struct ieee80211_mgd_auth_data { struct cfg80211_bss *bss; unsigned long timeout; @@ -416,7 +429,7 @@ struct ieee80211_mgd_assoc_data { size_t elems_len; u8 *elems; /* pointing to inside ie[] below */ - ieee80211_conn_flags_t conn_flags; + struct ieee80211_conn_settings conn; u16 status; @@ -943,7 +956,7 @@ struct ieee80211_link_data_managed { enum ieee80211_smps_mode req_smps, /* requested smps mode */ driver_smps_mode; /* smps mode request */ - ieee80211_conn_flags_t conn_flags; + struct ieee80211_conn_settings conn; s16 p2p_noa_index; @@ -2171,9 +2184,8 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, * @elems: parsed 802.11 elements received with the frame * @current_band: indicates the current band * @vht_cap_info: VHT capabilities of the transmitter - * @conn_flags: contains information about own capabilities and restrictions - * to decide which channel switch announcements can be accepted, using - * flags from &enum ieee80211_conn_flags. + * @conn: contains information about own capabilities and restrictions + * to decide which channel switch announcements can be accepted * @bssid: the currently connected bssid (for reporting) * @csa_ie: parsed 802.11 csa elements on count, mode, chandef and mesh ttl. * All of them will be filled with if success only. @@ -2183,7 +2195,8 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, enum nl80211_band current_band, u32 vht_cap_info, - ieee80211_conn_flags_t conn_flags, u8 *bssid, + struct ieee80211_conn_settings *conn, + u8 *bssid, struct ieee80211_csa_ie *csa_ie); /* Suspend/resume and hw reconfiguration */ @@ -2207,6 +2220,9 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) /* utility functions/constants */ extern const void *const mac80211_wiphy_privid; /* for wiphy privid */ +const char *ieee80211_conn_mode_str(enum ieee80211_conn_mode mode); +enum ieee80211_conn_bw_limit +ieee80211_min_bw_limit_from_chandef(struct cfg80211_chan_def *chandef); int ieee80211_frame_duration(enum nl80211_band band, size_t len, int rate, int erp, int short_preamble); void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, @@ -2248,6 +2264,7 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, /** * struct ieee80211_elems_parse_params - element parsing parameters + * @mode: connection mode for parsing * @start: pointer to the elements * @len: length of the elements * @action: %true if the elements came from an action frame @@ -2265,6 +2282,7 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, * for EHT capabilities parsing) */ struct ieee80211_elems_parse_params { + enum ieee80211_conn_mode mode; const u8 *start; size_t len; bool action; @@ -2284,6 +2302,7 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, struct cfg80211_bss *bss) { struct ieee80211_elems_parse_params params = { + .mode = IEEE80211_CONN_MODE_HIGHEST, .start = start, .len = len, .action = action, @@ -2459,9 +2478,9 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, const struct cfg80211_chan_def *chandef); u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype); -u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos, +u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, const struct ieee80211_sta_he_cap *he_cap, - u8 *end); + u8 *pos, u8 *end); void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode smps_mode, struct sk_buff *skb); @@ -2501,7 +2520,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, struct cfg80211_chan_def *chandef); bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper, struct cfg80211_chan_def *chandef); -ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); +void ieee80211_chandef_downgrade(struct cfg80211_chan_def *chandef, + struct ieee80211_conn_settings *conn); int __must_check ieee80211_link_use_channel(struct ieee80211_link_data *link, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index fccbcde3359a..6b48914b39fd 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -586,7 +586,7 @@ int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata, return -ENOMEM; pos = skb_put(skb, ie_len); - ieee80211_ie_build_he_cap(0, pos, he_cap, pos + ie_len); + ieee80211_ie_build_he_cap(NULL, he_cap, pos, pos + ie_len); return 0; } @@ -1292,7 +1292,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_supported_band *sband; int err; - ieee80211_conn_flags_t conn_flags = 0; + struct ieee80211_conn_settings conn = ieee80211_conn_settings_unlimited; u32 vht_cap_info = 0; lockdep_assert_wiphy(sdata->local->hw.wiphy); @@ -1303,13 +1303,16 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, switch (sdata->vif.bss_conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: - conn_flags |= IEEE80211_CONN_DISABLE_HT; - fallthrough; + conn.mode = IEEE80211_CONN_MODE_LEGACY; + conn.bw_limit = IEEE80211_CONN_BW_LIMIT_20; + break; case NL80211_CHAN_WIDTH_20: - conn_flags |= IEEE80211_CONN_DISABLE_40MHZ; - fallthrough; + conn.mode = IEEE80211_CONN_MODE_HT; + conn.bw_limit = IEEE80211_CONN_BW_LIMIT_20; + break; case NL80211_CHAN_WIDTH_40: - conn_flags |= IEEE80211_CONN_DISABLE_VHT; + conn.mode = IEEE80211_CONN_MODE_HT; + conn.bw_limit = IEEE80211_CONN_BW_LIMIT_40; break; default: break; @@ -1321,8 +1324,8 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, memset(¶ms, 0, sizeof(params)); err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band, - vht_cap_info, - conn_flags, sdata->vif.addr, + vht_cap_info, &conn, + sdata->vif.addr, &csa_ie); if (err < 0) return false; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e5d0988513dd..549a06c9a2e5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -157,8 +157,7 @@ ieee80211_handle_puncturing_bitmap(struct ieee80211_link_data *link, !(bitmap && ieee80211_hw_check(&local->hw, DISALLOW_PUNCTURING))) break; - link->u.mgd.conn_flags |= - ieee80211_chandef_downgrade(chandef); + ieee80211_chandef_downgrade(chandef, &link->u.mgd.conn); *changed |= BSS_CHANGED_BANDWIDTH; } @@ -225,77 +224,84 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } -static ieee80211_conn_flags_t -ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, - struct ieee80211_link_data *link, - ieee80211_conn_flags_t conn_flags, - struct ieee80211_supported_band *sband, - struct ieee80211_channel *channel, - u32 vht_cap_info, - const struct ieee80211_ht_operation *ht_oper, - const struct ieee80211_vht_operation *vht_oper, - const struct ieee80211_he_operation *he_oper, - const struct ieee80211_eht_operation *eht_oper, - const struct ieee80211_s1g_oper_ie *s1g_oper, - struct cfg80211_chan_def *chandef, bool tracking) +static enum ieee80211_conn_mode +ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + u32 vht_cap_info, + const struct ieee802_11_elems *elems, + bool ignore_ht_channel_mismatch, + const struct ieee80211_conn_settings *conn, + struct cfg80211_chan_def *chandef) { + const struct ieee80211_ht_operation *ht_oper = elems->ht_operation; + const struct ieee80211_vht_operation *vht_oper = elems->vht_operation; + const struct ieee80211_he_operation *he_oper = elems->he_operation; + const struct ieee80211_eht_operation *eht_oper = elems->eht_operation; + struct ieee80211_supported_band *sband = + sdata->local->hw.wiphy->bands[channel->band]; struct cfg80211_chan_def vht_chandef; - struct ieee80211_sta_ht_cap sta_ht_cap; - ieee80211_conn_flags_t ret; + bool no_vht = false; u32 ht_cfreq; - memset(chandef, 0, sizeof(struct cfg80211_chan_def)); - chandef->chan = channel; - chandef->width = NL80211_CHAN_WIDTH_20_NOHT; - chandef->center_freq1 = channel->center_freq; - chandef->freq1_offset = channel->freq_offset; + *chandef = (struct cfg80211_chan_def) { + .chan = channel, + .width = NL80211_CHAN_WIDTH_20_NOHT, + .center_freq1 = channel->center_freq, + .freq1_offset = channel->freq_offset, + }; - if (channel->band == NL80211_BAND_6GHZ) { - if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, eht_oper, - chandef)) { - mlme_dbg(sdata, - "bad 6 GHz operation, disabling HT/VHT/HE/EHT\n"); - ret = IEEE80211_CONN_DISABLE_HT | - IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - } else { - ret = 0; - } - vht_chandef = *chandef; - goto out; - } else if (sband->band == NL80211_BAND_S1GHZ) { - if (!ieee80211_chandef_s1g_oper(s1g_oper, chandef)) { + /* get special S1G case out of the way */ + if (sband->band == NL80211_BAND_S1GHZ) { + if (!ieee80211_chandef_s1g_oper(elems->s1g_oper, chandef)) { sdata_info(sdata, "Missing S1G Operation Element? Trying operating == primary\n"); chandef->width = ieee80211_s1g_channel_width(channel); } - ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_40MHZ | - IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_80P80MHZ | - IEEE80211_CONN_DISABLE_160MHZ; - goto out; + return IEEE80211_CONN_MODE_S1G; } - memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); - ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); + /* get special 6 GHz case out of the way */ + if (sband->band == NL80211_BAND_6GHZ) { + enum ieee80211_conn_mode mode = IEEE80211_CONN_MODE_EHT; - if (!ht_oper || !sta_ht_cap.ht_supported) { - mlme_dbg(sdata, "HT operation missing / HT not supported\n"); - ret = IEEE80211_CONN_DISABLE_HT | - IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - goto out; + /* this is an error */ + if (conn->mode < IEEE80211_CONN_MODE_HE) + return IEEE80211_CONN_MODE_LEGACY; + + if (!elems->he_6ghz_capa || !elems->he_cap) { + sdata_info(sdata, + "HE 6 GHz AP is missing HE/HE 6 GHz band capability\n"); + return IEEE80211_CONN_MODE_LEGACY; + } + + if (!eht_oper || !elems->eht_cap) { + eht_oper = NULL; + mode = IEEE80211_CONN_MODE_HE; + } + + if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, + eht_oper, chandef)) { + sdata_info(sdata, "bad HE/EHT 6 GHz operation\n"); + return IEEE80211_CONN_MODE_LEGACY; + } + + return mode; } + /* now we have the progression HT, VHT, ... */ + if (conn->mode < IEEE80211_CONN_MODE_HT) + return IEEE80211_CONN_MODE_LEGACY; + + if (!ht_oper || !elems->ht_cap_elem) + return IEEE80211_CONN_MODE_LEGACY; + chandef->width = NL80211_CHAN_WIDTH_20; ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, channel->band); /* check that channel matches the right operating channel */ - if (!tracking && channel->center_freq != ht_cfreq) { + if (!ignore_ht_channel_mismatch && channel->center_freq != ht_cfreq) { /* * It's possible that some APs are confused here; * Netgear WNDR3700 sometimes reports 4 higher than @@ -307,36 +313,22 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", channel->center_freq, ht_cfreq, ht_oper->primary_chan, channel->band); - ret = IEEE80211_CONN_DISABLE_HT | - IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - goto out; + return IEEE80211_CONN_MODE_LEGACY; } - /* check 40 MHz support, if we have it */ - if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - ieee80211_chandef_ht_oper(ht_oper, chandef); - } else { - mlme_dbg(sdata, "40 MHz not supported\n"); - /* 40 MHz (and 80 MHz) must be supported for VHT */ - ret = IEEE80211_CONN_DISABLE_VHT; - /* also mark 40 MHz disabled */ - ret |= IEEE80211_CONN_DISABLE_40MHZ; - goto out; - } + ieee80211_chandef_ht_oper(ht_oper, chandef); - if (!vht_oper || !sband->vht_cap.vht_supported) { - mlme_dbg(sdata, "VHT operation missing / VHT not supported\n"); - ret = IEEE80211_CONN_DISABLE_VHT; - goto out; - } + if (conn->mode < IEEE80211_CONN_MODE_VHT) + return IEEE80211_CONN_MODE_HT; vht_chandef = *chandef; - if (!(conn_flags & IEEE80211_CONN_DISABLE_HE) && - he_oper && - (le32_to_cpu(he_oper->he_oper_params) & - IEEE80211_HE_OPERATION_VHT_OPER_INFO)) { + + /* + * having he_cap/he_oper parsed out implies we're at + * least operating as HE STA + */ + if (elems->he_cap && he_oper && + he_oper->he_oper_params & cpu_to_le32(IEEE80211_HE_OPERATION_VHT_OPER_INFO)) { struct ieee80211_vht_operation he_oper_vht_cap; /* @@ -349,52 +341,56 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, &he_oper_vht_cap, ht_oper, &vht_chandef)) { - if (!(conn_flags & IEEE80211_CONN_DISABLE_HE)) - sdata_info(sdata, - "HE AP VHT information is invalid, disabling HE\n"); - ret = IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT; - goto out; + sdata_info(sdata, + "HE AP VHT information is invalid, disabling HE\n"); + /* this will cause us to re-parse as VHT STA */ + return IEEE80211_CONN_MODE_VHT; } + } else if (!vht_oper || !elems->vht_cap_elem) { + if (sband->band == NL80211_BAND_5GHZ) { + sdata_info(sdata, + "VHT information is missing, disabling VHT\n"); + return IEEE80211_CONN_MODE_HT; + } + no_vht = true; + } else if (sband->band == NL80211_BAND_2GHZ) { + no_vht = true; } else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, vht_oper, ht_oper, &vht_chandef)) { - if (!(conn_flags & IEEE80211_CONN_DISABLE_VHT)) - sdata_info(sdata, - "AP VHT information is invalid, disabling VHT\n"); - ret = IEEE80211_CONN_DISABLE_VHT; - goto out; - } - - if (!cfg80211_chandef_valid(&vht_chandef)) { - if (!(conn_flags & IEEE80211_CONN_DISABLE_VHT)) - sdata_info(sdata, - "AP VHT information is invalid, disabling VHT\n"); - ret = IEEE80211_CONN_DISABLE_VHT; - goto out; - } - - if (cfg80211_chandef_identical(chandef, &vht_chandef)) { - ret = 0; - goto out; + sdata_info(sdata, + "AP VHT information is invalid, disabling VHT\n"); + return IEEE80211_CONN_MODE_HT; } if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { - if (!(conn_flags & IEEE80211_CONN_DISABLE_VHT)) - sdata_info(sdata, - "AP VHT information doesn't match HT, disabling VHT\n"); - ret = IEEE80211_CONN_DISABLE_VHT; - goto out; + sdata_info(sdata, + "AP VHT information doesn't match HT, disabling VHT\n"); + return IEEE80211_CONN_MODE_HT; } *chandef = vht_chandef; + /* stick to current max mode if we or the AP don't have HE */ + if (conn->mode < IEEE80211_CONN_MODE_HE || + !elems->he_operation || !elems->he_cap) { + if (no_vht) + return IEEE80211_CONN_MODE_HT; + return IEEE80211_CONN_MODE_VHT; + } + + /* stick to HE if we or the AP don't have EHT */ + if (conn->mode < IEEE80211_CONN_MODE_EHT || + !eht_oper || !elems->eht_cap) + return IEEE80211_CONN_MODE_HE; + /* * handle the case that the EHT operation indicates that it holds EHT * operation information (in case that the channel width differs from * the channel width reported in HT/VHT/HE). */ - if (eht_oper && (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) { + if (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) { struct cfg80211_chan_def eht_chandef = *chandef; ieee80211_chandef_eht_oper((const void *)eht_oper->optional, @@ -403,37 +399,547 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, false, &eht_chandef); if (!cfg80211_chandef_valid(&eht_chandef)) { - if (!(conn_flags & IEEE80211_CONN_DISABLE_EHT)) - sdata_info(sdata, - "AP EHT information is invalid, disabling EHT\n"); - ret = IEEE80211_CONN_DISABLE_EHT; - goto out; + sdata_info(sdata, + "AP EHT information is invalid, disabling EHT\n"); + return IEEE80211_CONN_MODE_HE; } if (!cfg80211_chandef_compatible(chandef, &eht_chandef)) { - if (!(conn_flags & IEEE80211_CONN_DISABLE_EHT)) - sdata_info(sdata, - "AP EHT information is incompatible, disabling EHT\n"); - ret = IEEE80211_CONN_DISABLE_EHT; - goto out; + sdata_info(sdata, + "AP EHT information doesn't match HT/VHT/HE, disabling EHT\n"); + return IEEE80211_CONN_MODE_HE; } *chandef = eht_chandef; } - ret = 0; + return IEEE80211_CONN_MODE_EHT; +} + +static bool +ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata, + const struct ieee80211_he_cap_elem *he_cap, + const struct ieee80211_he_operation *he_op) +{ + struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp; + u16 mcs_80_map_tx, mcs_80_map_rx; + u16 ap_min_req_set; + int nss; + + if (!he_cap) + return false; + + /* mcs_nss is right after he_cap info */ + he_mcs_nss_supp = (void *)(he_cap + 1); + + mcs_80_map_tx = le16_to_cpu(he_mcs_nss_supp->tx_mcs_80); + mcs_80_map_rx = le16_to_cpu(he_mcs_nss_supp->rx_mcs_80); + + /* P802.11-REVme/D0.3 + * 27.1.1 Introduction to the HE PHY + * ... + * An HE STA shall support the following features: + * ... + * Single spatial stream HE-MCSs 0 to 7 (transmit and receive) in all + * supported channel widths for HE SU PPDUs + */ + if ((mcs_80_map_tx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED || + (mcs_80_map_rx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED) { + sdata_info(sdata, + "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n", + mcs_80_map_tx, mcs_80_map_rx); + return false; + } + + if (!he_op) + return true; + + ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); -out: /* - * When tracking the current AP, don't do any further checks if the - * new chandef is identical to the one we're currently using for the - * connection. This keeps us from playing ping-pong with regulatory, - * without it the following can happen (for example): + * Apparently iPhone 13 (at least iOS version 15.3.1) sets this to all + * zeroes, which is nonsense, and completely inconsistent with itself + * (it doesn't have 8 streams). Accept the settings in this case anyway. + */ + if (!ap_min_req_set) + return true; + + /* make sure the AP is consistent with itself + * + * P802.11-REVme/D0.3 + * 26.17.1 Basic HE BSS operation + * + * A STA that is operating in an HE BSS shall be able to receive and + * transmit at each of the tuple values indicated by the + * Basic HE-MCS And NSS Set field of the HE Operation parameter of the + * MLME-START.request primitive and shall be able to receive at each of + * the tuple values indicated by the Supported HE-MCS and + * NSS Set field in the HE Capabilities parameter of the MLMESTART.request + * primitive + */ + for (nss = 8; nss > 0; nss--) { + u8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; + u8 ap_rx_val; + u8 ap_tx_val; + + if (ap_op_val == IEEE80211_HE_MCS_NOT_SUPPORTED) + continue; + + ap_rx_val = (mcs_80_map_rx >> (2 * (nss - 1))) & 3; + ap_tx_val = (mcs_80_map_tx >> (2 * (nss - 1))) & 3; + + if (ap_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + ap_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) { + sdata_info(sdata, + "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n", + nss, ap_rx_val, ap_rx_val, ap_op_val); + return false; + } + } + + return true; +} + +static bool +ieee80211_verify_sta_he_mcs_support(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + const struct ieee80211_he_operation *he_op) +{ + const struct ieee80211_sta_he_cap *sta_he_cap = + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + u16 ap_min_req_set; + int i; + + if (!sta_he_cap || !he_op) + return false; + + ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); + + /* + * Apparently iPhone 13 (at least iOS version 15.3.1) sets this to all + * zeroes, which is nonsense, and completely inconsistent with itself + * (it doesn't have 8 streams). Accept the settings in this case anyway. + */ + if (!ap_min_req_set) + return true; + + /* Need to go over for 80MHz, 160MHz and for 80+80 */ + for (i = 0; i < 3; i++) { + const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp = + &sta_he_cap->he_mcs_nss_supp; + u16 sta_mcs_map_rx = + le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]); + u16 sta_mcs_map_tx = + le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]); + u8 nss; + bool verified = true; + + /* + * For each band there is a maximum of 8 spatial streams + * possible. Each of the sta_mcs_map_* is a 16-bit struct built + * of 2 bits per NSS (1-8), with the values defined in enum + * ieee80211_he_mcs_support. Need to make sure STA TX and RX + * capabilities aren't less than the AP's minimum requirements + * for this HE BSS per SS. + * It is enough to find one such band that meets the reqs. + */ + for (nss = 8; nss > 0; nss--) { + u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3; + u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3; + u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; + + if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED) + continue; + + /* + * Make sure the HE AP doesn't require MCSs that aren't + * supported by the client as required by spec + * + * P802.11-REVme/D0.3 + * 26.17.1 Basic HE BSS operation + * + * An HE STA shall not attempt to join * (MLME-JOIN.request primitive) + * a BSS, unless it supports (i.e., is able to both transmit and + * receive using) all of the tuples in the basic + * HE-MCS and NSS set. + */ + if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + (ap_val > sta_rx_val) || (ap_val > sta_tx_val)) { + verified = false; + break; + } + } + + if (verified) + return true; + } + + /* If here, STA doesn't meet AP's HE min requirements */ + return false; +} + +static u8 +ieee80211_get_eht_cap_mcs_nss(const struct ieee80211_sta_he_cap *sta_he_cap, + const struct ieee80211_sta_eht_cap *sta_eht_cap, + unsigned int idx, int bw) +{ + u8 he_phy_cap0 = sta_he_cap->he_cap_elem.phy_cap_info[0]; + u8 eht_phy_cap0 = sta_eht_cap->eht_cap_elem.phy_cap_info[0]; + + /* handle us being a 20 MHz-only EHT STA - with four values + * for MCS 0-7, 8-9, 10-11, 12-13. + */ + if (!(he_phy_cap0 & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) + return sta_eht_cap->eht_mcs_nss_supp.only_20mhz.rx_tx_max_nss[idx]; + + /* the others have MCS 0-9 together, rather than separately from 0-7 */ + if (idx > 0) + idx--; + + switch (bw) { + case 0: + return sta_eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_max_nss[idx]; + case 1: + if (!(he_phy_cap0 & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G))) + return 0xff; /* pass check */ + return sta_eht_cap->eht_mcs_nss_supp.bw._160.rx_tx_max_nss[idx]; + case 2: + if (!(eht_phy_cap0 & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)) + return 0xff; /* pass check */ + return sta_eht_cap->eht_mcs_nss_supp.bw._320.rx_tx_max_nss[idx]; + } + + WARN_ON(1); + return 0; +} + +static bool +ieee80211_verify_sta_eht_mcs_support(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + const struct ieee80211_eht_operation *eht_op) +{ + const struct ieee80211_sta_he_cap *sta_he_cap = + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + const struct ieee80211_sta_eht_cap *sta_eht_cap = + ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); + const struct ieee80211_eht_mcs_nss_supp_20mhz_only *req; + unsigned int i; + + if (!sta_he_cap || !sta_eht_cap || !eht_op) + return false; + + req = &eht_op->basic_mcs_nss; + + for (i = 0; i < ARRAY_SIZE(req->rx_tx_max_nss); i++) { + u8 req_rx_nss, req_tx_nss; + unsigned int bw; + + req_rx_nss = u8_get_bits(req->rx_tx_max_nss[i], + IEEE80211_EHT_MCS_NSS_RX); + req_tx_nss = u8_get_bits(req->rx_tx_max_nss[i], + IEEE80211_EHT_MCS_NSS_TX); + + for (bw = 0; bw < 3; bw++) { + u8 have, have_rx_nss, have_tx_nss; + + have = ieee80211_get_eht_cap_mcs_nss(sta_he_cap, + sta_eht_cap, + i, bw); + have_rx_nss = u8_get_bits(have, + IEEE80211_EHT_MCS_NSS_RX); + have_tx_nss = u8_get_bits(have, + IEEE80211_EHT_MCS_NSS_TX); + + if (req_rx_nss > have_rx_nss || + req_tx_nss > have_tx_nss) + 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 cfg80211_chan_def *chandef) +{ + 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; + struct ieee80211_elems_parse_params parse_params = { + .link_id = -1, + .from_ap = true, + .start = ies->data, + .len = ies->len, + .mode = conn->mode, + }; + struct ieee802_11_elems *elems; + struct ieee80211_supported_band *sband; + struct cfg80211_chan_def ap_chandef; + enum ieee80211_conn_mode ap_mode; + int ret; + +again: + elems = ieee802_11_parse_elems_full(&parse_params); + if (!elems) + return ERR_PTR(-ENOMEM); + + ap_mode = ieee80211_determine_ap_chan(sdata, channel, bss->vht_cap_info, + elems, false, conn, &ap_chandef); + + mlme_link_id_dbg(sdata, link_id, "determined AP %pM to be %s\n", + cbss->bssid, ieee80211_conn_mode_str(ap_mode)); + + /* this should be impossible since parsing depends on our mode */ + if (WARN_ON(ap_mode > conn->mode)) { + ret = -EINVAL; + goto free; + } + + sband = sdata->local->hw.wiphy->bands[channel->band]; + + switch (channel->band) { + case NL80211_BAND_S1GHZ: + if (WARN_ON(ap_mode != IEEE80211_CONN_MODE_S1G)) { + ret = -EINVAL; + goto free; + } + return elems; + case NL80211_BAND_6GHZ: + if (ap_mode < IEEE80211_CONN_MODE_HE) { + sdata_info(sdata, + "Rejecting non-HE 6/7 GHz connection"); + ret = -EINVAL; + goto free; + } + break; + default: + if (WARN_ON(ap_mode == IEEE80211_CONN_MODE_S1G)) { + ret = -EINVAL; + goto free; + } + } + + switch (ap_mode) { + case IEEE80211_CONN_MODE_S1G: + WARN_ON(1); + ret = -EINVAL; + goto free; + case IEEE80211_CONN_MODE_LEGACY: + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; + break; + case IEEE80211_CONN_MODE_HT: + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, + IEEE80211_CONN_BW_LIMIT_40); + break; + case IEEE80211_CONN_MODE_VHT: + case IEEE80211_CONN_MODE_HE: + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, + IEEE80211_CONN_BW_LIMIT_160); + break; + case IEEE80211_CONN_MODE_EHT: + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, + IEEE80211_CONN_BW_LIMIT_320); + break; + } + + conn->mode = ap_mode; + *chandef = ap_chandef; + + while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, + IEEE80211_CHAN_DISABLED)) { + if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { + ret = -EINVAL; + goto free; + } + + ieee80211_chandef_downgrade(chandef, conn); + } + + if (conn->mode >= IEEE80211_CONN_MODE_HE && + !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, + IEEE80211_CHAN_NO_HE)) { + conn->mode = IEEE80211_CONN_MODE_VHT; + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, + IEEE80211_CONN_BW_LIMIT_160); + } + + if (conn->mode >= IEEE80211_CONN_MODE_EHT && + !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, + IEEE80211_CHAN_NO_EHT)) { + conn->mode = IEEE80211_CONN_MODE_HE; + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, + IEEE80211_CONN_BW_LIMIT_160); + } + + if (chandef->width != ap_chandef.width || ap_mode != conn->mode) + sdata_info(sdata, + "regulatory prevented using AP config, downgraded\n"); + + if (conn->mode >= IEEE80211_CONN_MODE_HE && + (!ieee80211_verify_peer_he_mcs_support(sdata, (void *)elems->he_cap, + elems->he_operation) || + !ieee80211_verify_sta_he_mcs_support(sdata, sband, + elems->he_operation))) { + conn->mode = IEEE80211_CONN_MODE_VHT; + sdata_info(sdata, "required MCSes not supported, disabling HE\n"); + } + + if (conn->mode >= IEEE80211_CONN_MODE_EHT && + !ieee80211_verify_sta_eht_mcs_support(sdata, sband, + elems->eht_operation)) { + 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, "required MCSes not supported, disabling EHT\n"); + } + + if (conn->mode >= IEEE80211_CONN_MODE_EHT) { + const struct ieee80211_eht_operation *eht_oper; + + eht_oper = elems->eht_operation; + + if (WARN_ON_ONCE(!eht_oper)) { + ret = -EINVAL; + goto free; + } + + if (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT && + eht_oper->params & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT) { + const struct ieee80211_eht_operation_info *info = + (void *)eht_oper->optional; + const u8 *disable_subchannel_bitmap = info->optional; + u16 bitmap; + + bitmap = get_unaligned_le16(disable_subchannel_bitmap); + 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; + + mlme_link_id_dbg(sdata, link_id, + "connecting with %s mode, max bandwidth %d MHz\n", + ieee80211_conn_mode_str(conn->mode), + 20 * (1 << conn->bw_limit)); + + if (WARN_ON_ONCE(!cfg80211_chandef_valid(chandef))) { + ret = -EINVAL; + goto free; + } + + return elems; +free: + kfree(elems); + return ERR_PTR(ret); +} + +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_sub_if_data *sdata = link->sdata; + struct cfg80211_chan_def ap_chandef; + enum ieee80211_conn_mode ap_mode; + u32 vht_cap_info = 0; + u16 ht_opmode; + int ret; + + /* don't track any bandwidth changes in legacy/S1G modes */ + if (link->u.mgd.conn.mode == IEEE80211_CONN_MODE_LEGACY || + link->u.mgd.conn.mode == IEEE80211_CONN_MODE_S1G) + return 0; + + if (elems->vht_cap_elem) + vht_cap_info = le32_to_cpu(elems->vht_cap_elem->vht_cap_info); + + ap_mode = ieee80211_determine_ap_chan(sdata, channel, vht_cap_info, + elems, true, &link->u.mgd.conn, + &ap_chandef); + + if (ap_mode != link->u.mgd.conn.mode) { + link_info(link, + "AP appears to change mode (expected %s, found %s), disconnect\n", + ieee80211_conn_mode_str(link->u.mgd.conn.mode), + ieee80211_conn_mode_str(ap_mode)); + return -EINVAL; + } + + /* + * if HT operation mode changed store the new one - + * this may be applicable even if channel is identical + */ + if (elems->ht_operation) { + ht_opmode = le16_to_cpu(elems->ht_operation->operation_mode); + if (link->conf->ht_operation_mode != ht_opmode) { + *changed |= BSS_CHANGED_HT; + link->conf->ht_operation_mode = ht_opmode; + } + } + + /* + * Downgrade the new channel if we associated with restricted + * bandwidth capabilities. For example, if we associated as a + * 20 MHz STA to a 40 MHz AP (due to regulatory, capabilities + * or config reasons) then switching to a 40 MHz channel now + * won't do us any good -- we couldn't use it with the AP. + */ + while (link->u.mgd.conn.bw_limit < + ieee80211_min_bw_limit_from_chandef(&ap_chandef)) + ieee80211_chandef_downgrade(&ap_chandef, NULL); + + if (cfg80211_chandef_identical(&ap_chandef, &link->conf->chandef)) + return 0; + + link_info(link, + "AP %pM changed bandwidth, new config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n", + link->u.mgd.bssid, ap_chandef.chan->center_freq, + ap_chandef.chan->freq_offset, ap_chandef.width, + ap_chandef.center_freq1, ap_chandef.freq1_offset, + ap_chandef.center_freq2); + + if (!cfg80211_chandef_valid(&ap_chandef)) { + sdata_info(sdata, + "AP %pM changed caps/bw in a way we can't support - disconnect\n", + link->u.mgd.bssid); + return -EINVAL; + } + + /* + * We're tracking the current AP here, so don't do any further checks + * here. This keeps us from playing ping-pong with regulatory, without + * it the following can happen (for example): * - connect to an AP with 80 MHz, world regdom allows 80 MHz * - AP advertises regdom US * - CRDA loads regdom US with 80 MHz prohibited (old database) - * - the code below detects an unsupported channel, downgrades, and - * we disconnect from the AP in the caller + * - we detect an unsupported channel and disconnect * - disconnect causes CRDA to reload world regdomain and the game * starts anew. * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881) @@ -442,160 +948,8 @@ out: * bandwidth changes where a this could happen, but those cases are * less common and wouldn't completely prevent using the AP. */ - if (tracking && - cfg80211_chandef_identical(chandef, &link->conf->chandef)) - return ret; - - /* don't print the message below for VHT mismatch if VHT is disabled */ - if (ret & IEEE80211_CONN_DISABLE_VHT) - vht_chandef = *chandef; - - /* - * Ignore the DISABLED flag when we're already connected and only - * tracking the APs beacon for bandwidth changes - otherwise we - * might get disconnected here if we connect to an AP, update our - * regulatory information based on the AP's country IE and the - * information we have is wrong/outdated and disables the channel - * that we're actually using for the connection to the AP. - */ - while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, - tracking ? 0 : - IEEE80211_CHAN_DISABLED)) { - if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { - ret = IEEE80211_CONN_DISABLE_HT | - IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - break; - } - - ret |= ieee80211_chandef_downgrade(chandef); - } - - if (!he_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, - IEEE80211_CHAN_NO_HE)) - ret |= IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT; - - if (!eht_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, - IEEE80211_CHAN_NO_EHT)) - ret |= IEEE80211_CONN_DISABLE_EHT; - - if (chandef->width != vht_chandef.width && !tracking) - sdata_info(sdata, - "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); - - WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); - return ret; -} - -static int ieee80211_config_bw(struct ieee80211_link_data *link, - struct ieee802_11_elems *elems, - const u8 *bssid, u64 *changed) -{ - const struct ieee80211_vht_cap *vht_cap = elems->vht_cap_elem; - const struct ieee80211_ht_operation *ht_oper = elems->ht_operation; - const struct ieee80211_vht_operation *vht_oper = elems->vht_operation; - const struct ieee80211_he_operation *he_oper = elems->he_operation; - const struct ieee80211_eht_operation *eht_oper = elems->eht_operation; - const struct ieee80211_s1g_oper_ie *s1g_oper = elems->s1g_oper; - struct ieee80211_sub_if_data *sdata = link->sdata; - struct ieee80211_local *local = sdata->local; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_channel *chan = link->conf->chandef.chan; - struct ieee80211_supported_band *sband = - local->hw.wiphy->bands[chan->band]; - struct cfg80211_chan_def chandef; - u16 ht_opmode; - ieee80211_conn_flags_t flags; - u32 vht_cap_info = 0; - int ret; - - /* if HT was/is disabled, don't track any bandwidth changes */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || !ht_oper) - return 0; - - /* don't check VHT if we associated as non-VHT station */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) - vht_oper = NULL; - - /* don't check HE if we associated as non-HE station */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE || - !ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif)) { - he_oper = NULL; - eht_oper = NULL; - } - - /* don't check EHT if we associated as non-EHT station */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT || - !ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif)) - eht_oper = NULL; - - /* - * if bss configuration changed store the new one - - * this may be applicable even if channel is identical - */ - ht_opmode = le16_to_cpu(ht_oper->operation_mode); - if (link->conf->ht_operation_mode != ht_opmode) { - *changed |= BSS_CHANGED_HT; - link->conf->ht_operation_mode = ht_opmode; - } - - if (vht_cap) - vht_cap_info = le32_to_cpu(vht_cap->vht_cap_info); - - /* calculate new channel (type) based on HT/VHT/HE operation IEs */ - flags = ieee80211_determine_chantype(sdata, link, - link->u.mgd.conn_flags, - sband, chan, vht_cap_info, - ht_oper, vht_oper, - he_oper, eht_oper, - s1g_oper, &chandef, true); - - /* - * Downgrade the new channel if we associated with restricted - * capabilities. For example, if we associated as a 20 MHz STA - * to a 40 MHz AP (due to regulatory, capabilities or config - * reasons) then switching to a 40 MHz channel now won't do us - * any good -- we couldn't use it with the AP. - */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ && - chandef.width == NL80211_CHAN_WIDTH_80P80) - flags |= ieee80211_chandef_downgrade(&chandef); - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ && - chandef.width == NL80211_CHAN_WIDTH_160) - flags |= ieee80211_chandef_downgrade(&chandef); - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ && - chandef.width > NL80211_CHAN_WIDTH_20) - flags |= ieee80211_chandef_downgrade(&chandef); - - if (cfg80211_chandef_identical(&chandef, &link->conf->chandef)) - return 0; - - link_info(link, - "AP %pM changed bandwidth, new config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n", - link->u.mgd.bssid, chandef.chan->center_freq, - chandef.chan->freq_offset, chandef.width, - chandef.center_freq1, chandef.freq1_offset, - chandef.center_freq2); - - if (flags != (link->u.mgd.conn_flags & - (IEEE80211_CONN_DISABLE_HT | - IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT | - IEEE80211_CONN_DISABLE_40MHZ | - IEEE80211_CONN_DISABLE_80P80MHZ | - IEEE80211_CONN_DISABLE_160MHZ | - IEEE80211_CONN_DISABLE_320MHZ)) || - !cfg80211_chandef_valid(&chandef)) { - sdata_info(sdata, - "AP %pM changed caps/bw in a way we can't support (0x%x/0x%x) - disconnect\n", - link->u.mgd.bssid, flags, ifmgd->flags); - return -EINVAL; - } - - ret = ieee80211_link_change_bandwidth(link, &chandef, changed); + ret = ieee80211_link_change_bandwidth(link, &ap_chandef, changed); if (ret) { sdata_info(sdata, "AP %pM changed bandwidth to incompatible one - disconnect\n", @@ -614,7 +968,7 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, struct ieee80211_channel *channel, enum ieee80211_smps_mode smps, - ieee80211_conn_flags_t conn_flags) + const struct ieee80211_conn_settings *conn) { u8 *pos; u32 flags = channel->flags; @@ -649,7 +1003,7 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, * capable of 40 MHz -- some broken APs will never fall * back to trying to transmit in 20 MHz. */ - if (conn_flags & IEEE80211_CONN_DISABLE_40MHZ) { + if (conn->bw_limit <= IEEE80211_CONN_BW_LIMIT_20) { cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; cap &= ~IEEE80211_HT_CAP_SGI_40; } @@ -688,7 +1042,7 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_supported_band *sband, struct ieee80211_vht_cap *ap_vht_cap, - ieee80211_conn_flags_t conn_flags) + const struct ieee80211_conn_settings *conn) { struct ieee80211_local *local = sdata->local; u8 *pos; @@ -705,16 +1059,7 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, /* determine capability flags */ cap = vht_cap.cap; - if (conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ) { - u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; - - cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; - if (bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ || - bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) - cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - } - - if (conn_flags & IEEE80211_CONN_DISABLE_160MHZ) { + if (conn->bw_limit <= IEEE80211_CONN_BW_LIMIT_80) { cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; } @@ -778,7 +1123,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_supported_band *sband, enum ieee80211_smps_mode smps_mode, - ieee80211_conn_flags_t conn_flags) + const struct ieee80211_conn_settings *conn) { u8 *pos, *pre_he_pos; const struct ieee80211_sta_he_cap *he_cap; @@ -796,8 +1141,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, he_cap->he_cap_elem.phy_cap_info); pos = skb_put(skb, he_cap_size); pre_he_pos = pos; - pos = ieee80211_ie_build_he_cap(conn_flags, - pos, he_cap, pos + he_cap_size); + pos = ieee80211_ie_build_he_cap(conn, he_cap, pos, pos + he_cap_size); /* trim excess if any */ skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos)); @@ -1135,11 +1479,11 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, offset); if (sband->band != NL80211_BAND_6GHZ && - !(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HT)) { + assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_HT) { ieee80211_add_ht_ie(sdata, skb, assoc_data->link[link_id].ap_ht_param, sband, chan, smps_mode, - assoc_data->link[link_id].conn_flags); + &assoc_data->link[link_id].conn); ADD_PRESENT_ELEM(WLAN_EID_HT_CAPABILITY); } @@ -1149,36 +1493,25 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, offset); if (sband->band != NL80211_BAND_6GHZ && - !(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_VHT)) { + assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_VHT) { bool mu_mimo_owner = ieee80211_add_vht_ie(sdata, skb, sband, &assoc_data->link[link_id].ap_vht_cap, - assoc_data->link[link_id].conn_flags); + &assoc_data->link[link_id].conn); if (link) link->conf->mu_mimo_owner = mu_mimo_owner; ADD_PRESENT_ELEM(WLAN_EID_VHT_CAPABILITY); } - /* - * If AP doesn't support HT, mark HE and EHT as disabled. - * If on the 5GHz band, make sure it supports VHT. - */ - if (assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HT || - (sband->band == NL80211_BAND_5GHZ && - assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_VHT)) - assoc_data->link[link_id].conn_flags |= - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - /* if present, add any custom IEs that go before HE */ offset = ieee80211_add_before_he_elems(skb, extra_elems, extra_elems_len, offset); - if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HE)) { + if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_HE) { ieee80211_add_he_ie(sdata, skb, sband, smps_mode, - assoc_data->link[link_id].conn_flags); + &assoc_data->link[link_id].conn); ADD_PRESENT_EXT_ELEM(WLAN_EID_EXT_HE_CAPABILITY); } @@ -1187,7 +1520,7 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, * calling ieee80211_assoc_add_ml_elem(), so add this one if * we're going to put it after the ML element */ - if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_EHT)) + if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_EHT) ADD_PRESENT_EXT_ELEM(WLAN_EID_EXT_EHT_CAPABILITY); if (link_id == assoc_data->assoc_link_id) @@ -1197,7 +1530,7 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, /* crash if somebody gets it wrong */ present_elems = NULL; - if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_EHT)) + if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_EHT) ieee80211_add_eht_ie(sdata, skb, sband); if (sband->band == NL80211_BAND_S1GHZ) { @@ -1208,9 +1541,6 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, if (iftd && iftd->vendor_elems.data && iftd->vendor_elems.len) skb_put_data(skb, iftd->vendor_elems.data, iftd->vendor_elems.len); - if (link) - link->u.mgd.conn_flags = assoc_data->link[link_id].conn_flags; - return offset; } @@ -1499,7 +1829,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) /* Set MBSSID support for HE AP if needed */ if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HE && ext_capa && ext_capa->datalen >= 3) ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; @@ -1544,7 +1874,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) * for some reason check it and want it to be set, set the bit for all * pre-EHT connections as we used to do. */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT) + if (link->u.mgd.conn.mode < IEEE80211_CONN_MODE_EHT) capab |= WLAN_CAPABILITY_ESS; /* add the elements for the assoc (main) link */ @@ -1876,7 +2206,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, bss = (void *)cbss->priv; res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band, bss->vht_cap_info, - link->u.mgd.conn_flags, + &link->u.mgd.conn, link->u.mgd.bssid, &csa_ie); if (!res) { @@ -3057,8 +3387,9 @@ 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; - sdata->deflink.u.mgd.conn_flags = 0; for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { struct ieee80211_link_data *link; @@ -3526,7 +3857,6 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, sta_info_destroy_addr(sdata, auth_data->ap_addr); /* other links are destroyed */ - sdata->deflink.u.mgd.conn_flags = 0; eth_zero_addr(sdata->deflink.u.mgd.bssid); ieee80211_link_info_change_notify(sdata, &sdata->deflink, BSS_CHANGED_BSSID); @@ -3564,7 +3894,6 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, del_timer_sync(&sdata->u.mgd.timer); sta_info_destroy_addr(sdata, assoc_data->ap_addr); - sdata->deflink.u.mgd.conn_flags = 0; eth_zero_addr(sdata->deflink.u.mgd.bssid); ieee80211_link_info_change_notify(sdata, &sdata->deflink, BSS_CHANGED_BSSID); @@ -4014,11 +4343,13 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, struct ieee80211_local *local = sdata->local; unsigned int link_id = link->link_id; struct ieee80211_elems_parse_params parse_params = { + .mode = link->u.mgd.conn.mode, .start = elem_start, .len = elem_len, .link_id = link_id == assoc_data->assoc_link_id ? -1 : link_id, .from_ap = true, }; + bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ; const struct cfg80211_bss_ies *bss_ies = NULL; @@ -4094,9 +4425,9 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, */ if (!is_6ghz && ((assoc_data->wmm && !elems->wmm_param) || - (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && + (link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT && (!elems->ht_cap_elem || !elems->ht_operation)) || - (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && + (link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_VHT && (!elems->vht_cap_elem || !elems->vht_operation)))) { const struct cfg80211_bss_ies *ies; struct ieee802_11_elems *bss_elems; @@ -4133,25 +4464,25 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, * have to include the IEs in the (re)association response. */ if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) { + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT) { elems->ht_cap_elem = bss_elems->ht_cap_elem; sdata_info(sdata, "AP bug: HT capability missing from AssocResp\n"); } if (!elems->ht_operation && bss_elems->ht_operation && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) { + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT) { elems->ht_operation = bss_elems->ht_operation; sdata_info(sdata, "AP bug: HT operation missing from AssocResp\n"); } if (!elems->vht_cap_elem && bss_elems->vht_cap_elem && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) { + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_VHT) { elems->vht_cap_elem = bss_elems->vht_cap_elem; sdata_info(sdata, "AP bug: VHT capa missing from AssocResp\n"); } if (!elems->vht_operation && bss_elems->vht_operation && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) { + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_VHT) { elems->vht_operation = bss_elems->vht_operation; sdata_info(sdata, "AP bug: VHT operation missing from AssocResp\n"); @@ -4164,7 +4495,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, * We previously checked these in the beacon/probe response, so * they should be present here. This is just a safety net. */ - if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && + if (!is_6ghz && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT && (!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) { sdata_info(sdata, "HT AP is missing WMM params or HT capability/operation\n"); @@ -4172,7 +4503,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, goto out; } - if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && + if (is_5ghz && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_VHT && (!elems->vht_cap_elem || !elems->vht_operation)) { sdata_info(sdata, "VHT AP is missing VHT capability/operation\n"); @@ -4180,36 +4511,20 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, goto out; } - if (is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && - !elems->he_6ghz_capa) { - sdata_info(sdata, - "HE 6 GHz AP is missing HE 6 GHz band capability\n"); - ret = false; - goto out; - } - if (WARN_ON(!link->conf->chandef.chan)) { ret = false; goto out; } sband = local->hw.wiphy->bands[link->conf->chandef.chan->band]; - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && - (!elems->he_cap || !elems->he_operation)) { - sdata_info(sdata, - "HE AP is missing HE capability/operation\n"); - ret = false; - goto out; - } - /* Set up internal HT/VHT capabilities */ - if (elems->ht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) + if (elems->ht_cap_elem && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, link_sta); if (elems->vht_cap_elem && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) { + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_VHT) { const struct ieee80211_vht_cap *bss_vht_cap = NULL; const struct cfg80211_bss_ies *ies; @@ -4236,7 +4551,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, rcu_read_unlock(); } - if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && + if (elems->he_operation && + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HE && elems->he_cap) { const struct ieee80211_he_6ghz_oper *he_6ghz_oper; @@ -4283,7 +4599,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, link_sta, elems); if (elems->eht_operation && elems->eht_cap && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) { + link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_EHT) { ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, elems->he_cap, elems->he_cap_len, @@ -4490,7 +4806,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, bool support_160; u8 chains = 1; - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) + if (link->u.mgd.conn.mode < IEEE80211_CONN_MODE_HT) return chains; ht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_CAPABILITY); @@ -4503,7 +4819,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, */ } - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) + if (link->u.mgd.conn.mode < IEEE80211_CONN_MODE_VHT) return chains; vht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); @@ -4522,7 +4838,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, chains = max(chains, nss); } - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) + if (link->u.mgd.conn.mode < IEEE80211_CONN_MODE_HE) return chains; ies = rcu_dereference(cbss->ies); @@ -4573,465 +4889,311 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, return chains; } -static bool -ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata, - const struct ieee80211_he_cap_elem *he_cap, - const struct ieee80211_he_operation *he_op) +static void +ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + struct cfg80211_assoc_request *req, + bool wmm_used, int link_id, + struct ieee80211_conn_settings *conn) { - struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp; - u16 mcs_80_map_tx, mcs_80_map_rx; - u16 ap_min_req_set; - int nss; + struct ieee80211_sta_ht_cap sta_ht_cap = sband->ht_cap; + bool is_5ghz = sband->band == NL80211_BAND_5GHZ; + bool is_6ghz = sband->band == NL80211_BAND_6GHZ; + const struct ieee80211_sta_he_cap *he_cap; + const struct ieee80211_sta_eht_cap *eht_cap; + struct ieee80211_sta_vht_cap vht_cap; - if (!he_cap) - return false; - - /* mcs_nss is right after he_cap info */ - he_mcs_nss_supp = (void *)(he_cap + 1); - - mcs_80_map_tx = le16_to_cpu(he_mcs_nss_supp->tx_mcs_80); - mcs_80_map_rx = le16_to_cpu(he_mcs_nss_supp->rx_mcs_80); - - /* P802.11-REVme/D0.3 - * 27.1.1 Introduction to the HE PHY - * ... - * An HE STA shall support the following features: - * ... - * Single spatial stream HE-MCSs 0 to 7 (transmit and receive) in all - * supported channel widths for HE SU PPDUs - */ - if ((mcs_80_map_tx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED || - (mcs_80_map_rx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED) { - sdata_info(sdata, - "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n", - mcs_80_map_tx, mcs_80_map_rx); - return false; + if (sband->band == NL80211_BAND_S1GHZ) { + conn->mode = IEEE80211_CONN_MODE_S1G; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; + mlme_dbg(sdata, "operating as S1G STA\n"); + return; } - if (!he_op) - return true; + conn->mode = IEEE80211_CONN_MODE_LEGACY; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; - ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); + ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); - /* - * Apparently iPhone 13 (at least iOS version 15.3.1) sets this to all - * zeroes, which is nonsense, and completely inconsistent with itself - * (it doesn't have 8 streams). Accept the settings in this case anyway. - */ - if (!ap_min_req_set) - return true; - - /* make sure the AP is consistent with itself - * - * P802.11-REVme/D0.3 - * 26.17.1 Basic HE BSS operation - * - * A STA that is operating in an HE BSS shall be able to receive and - * transmit at each of the tuple values indicated by the - * Basic HE-MCS And NSS Set field of the HE Operation parameter of the - * MLME-START.request primitive and shall be able to receive at each of - * the tuple values indicated by the Supported HE-MCS and - * NSS Set field in the HE Capabilities parameter of the MLMESTART.request - * primitive - */ - for (nss = 8; nss > 0; nss--) { - u8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; - u8 ap_rx_val; - u8 ap_tx_val; - - if (ap_op_val == IEEE80211_HE_MCS_NOT_SUPPORTED) - continue; - - ap_rx_val = (mcs_80_map_rx >> (2 * (nss - 1))) & 3; - ap_tx_val = (mcs_80_map_tx >> (2 * (nss - 1))) & 3; - - if (ap_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - ap_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) { - sdata_info(sdata, - "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n", - nss, ap_rx_val, ap_rx_val, ap_op_val); - return false; - } + if (req && req->flags & ASSOC_REQ_DISABLE_HT) { + mlme_link_id_dbg(sdata, link_id, + "HT disabled by flag, limiting to legacy\n"); + goto out; } - return true; -} + if (!wmm_used) { + mlme_link_id_dbg(sdata, link_id, + "WMM/QoS not supported, limiting to legacy\n"); + goto out; + } -static bool -ieee80211_verify_sta_he_mcs_support(struct ieee80211_sub_if_data *sdata, - struct ieee80211_supported_band *sband, - const struct ieee80211_he_operation *he_op) -{ - const struct ieee80211_sta_he_cap *sta_he_cap = - ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); - u16 ap_min_req_set; - int i; + if (req) { + unsigned int i; - if (!sta_he_cap || !he_op) - return false; - - ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); - - /* - * Apparently iPhone 13 (at least iOS version 15.3.1) sets this to all - * zeroes, which is nonsense, and completely inconsistent with itself - * (it doesn't have 8 streams). Accept the settings in this case anyway. - */ - if (!ap_min_req_set) - return true; - - /* Need to go over for 80MHz, 160MHz and for 80+80 */ - for (i = 0; i < 3; i++) { - const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp = - &sta_he_cap->he_mcs_nss_supp; - u16 sta_mcs_map_rx = - le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]); - u16 sta_mcs_map_tx = - le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]); - u8 nss; - bool verified = true; - - /* - * For each band there is a maximum of 8 spatial streams - * possible. Each of the sta_mcs_map_* is a 16-bit struct built - * of 2 bits per NSS (1-8), with the values defined in enum - * ieee80211_he_mcs_support. Need to make sure STA TX and RX - * capabilities aren't less than the AP's minimum requirements - * for this HE BSS per SS. - * It is enough to find one such band that meets the reqs. - */ - for (nss = 8; nss > 0; nss--) { - u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3; - u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3; - u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; - - if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED) - continue; - - /* - * Make sure the HE AP doesn't require MCSs that aren't - * supported by the client as required by spec - * - * P802.11-REVme/D0.3 - * 26.17.1 Basic HE BSS operation - * - * An HE STA shall not attempt to join * (MLME-JOIN.request primitive) - * a BSS, unless it supports (i.e., is able to both transmit and - * receive using) all of the tuples in the basic - * HE-MCS and NSS set. - */ - if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - (ap_val > sta_rx_val) || (ap_val > sta_tx_val)) { - verified = false; - break; + for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) { + if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { + netdev_info(sdata->dev, + "WEP/TKIP use, limiting to legacy\n"); + goto out; } } - - if (verified) - return true; } - /* If here, STA doesn't meet AP's HE min requirements */ - return false; -} - -static u8 -ieee80211_get_eht_cap_mcs_nss(const struct ieee80211_sta_he_cap *sta_he_cap, - const struct ieee80211_sta_eht_cap *sta_eht_cap, - unsigned int idx, int bw) -{ - u8 he_phy_cap0 = sta_he_cap->he_cap_elem.phy_cap_info[0]; - u8 eht_phy_cap0 = sta_eht_cap->eht_cap_elem.phy_cap_info[0]; - - /* handle us being a 20 MHz-only EHT STA - with four values - * for MCS 0-7, 8-9, 10-11, 12-13. - */ - if (!(he_phy_cap0 & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) - return sta_eht_cap->eht_mcs_nss_supp.only_20mhz.rx_tx_max_nss[idx]; - - /* the others have MCS 0-9 together, rather than separately from 0-7 */ - if (idx > 0) - idx--; - - switch (bw) { - case 0: - return sta_eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_max_nss[idx]; - case 1: - if (!(he_phy_cap0 & - (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G))) - return 0xff; /* pass check */ - return sta_eht_cap->eht_mcs_nss_supp.bw._160.rx_tx_max_nss[idx]; - case 2: - if (!(eht_phy_cap0 & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)) - return 0xff; /* pass check */ - return sta_eht_cap->eht_mcs_nss_supp.bw._320.rx_tx_max_nss[idx]; + if (!sta_ht_cap.ht_supported && !is_6ghz) { + mlme_link_id_dbg(sdata, link_id, + "HT not supported (and not on 6 GHz), limiting to legacy\n"); + goto out; } - WARN_ON(1); - return 0; -} + /* HT is fine */ + conn->mode = IEEE80211_CONN_MODE_HT; + conn->bw_limit = sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + IEEE80211_CONN_BW_LIMIT_40 : + IEEE80211_CONN_BW_LIMIT_20; -static bool -ieee80211_verify_sta_eht_mcs_support(struct ieee80211_sub_if_data *sdata, - struct ieee80211_supported_band *sband, - const struct ieee80211_eht_operation *eht_op) -{ - const struct ieee80211_sta_he_cap *sta_he_cap = - ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); - const struct ieee80211_sta_eht_cap *sta_eht_cap = - ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); - const struct ieee80211_eht_mcs_nss_supp_20mhz_only *req; - unsigned int i; + memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); + ieee80211_apply_vhtcap_overrides(sdata, &vht_cap); - if (!sta_he_cap || !sta_eht_cap || !eht_op) - return false; + if (req && req->flags & ASSOC_REQ_DISABLE_VHT) { + mlme_link_id_dbg(sdata, link_id, + "VHT disabled by flag, limiting to HT\n"); + goto out; + } - req = &eht_op->basic_mcs_nss; + if (vht_cap.vht_supported && is_5ghz) { + bool have_80mhz = false; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(req->rx_tx_max_nss); i++) { - u8 req_rx_nss, req_tx_nss; - unsigned int bw; - - req_rx_nss = u8_get_bits(req->rx_tx_max_nss[i], - IEEE80211_EHT_MCS_NSS_RX); - req_tx_nss = u8_get_bits(req->rx_tx_max_nss[i], - IEEE80211_EHT_MCS_NSS_TX); - - for (bw = 0; bw < 3; bw++) { - u8 have, have_rx_nss, have_tx_nss; - - have = ieee80211_get_eht_cap_mcs_nss(sta_he_cap, - sta_eht_cap, - i, bw); - have_rx_nss = u8_get_bits(have, - IEEE80211_EHT_MCS_NSS_RX); - have_tx_nss = u8_get_bits(have, - IEEE80211_EHT_MCS_NSS_TX); - - if (req_rx_nss > have_rx_nss || - req_tx_nss > have_tx_nss) - return false; + if (conn->bw_limit == IEEE80211_CONN_BW_LIMIT_20) { + mlme_link_id_dbg(sdata, link_id, + "no 40 MHz support on 5 GHz, limiting to HT\n"); + goto out; } + + /* Allow VHT if at least one channel on the sband supports 80 MHz */ + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_80MHZ)) + continue; + + have_80mhz = true; + break; + } + + if (!have_80mhz) { + mlme_link_id_dbg(sdata, link_id, + "no 80 MHz channel support on 5 GHz, limiting to HT\n"); + goto out; + } + } else if (is_5ghz) { /* !vht_supported but on 5 GHz */ + mlme_link_id_dbg(sdata, link_id, + "no VHT support on 5 GHz, limiting to HT\n"); + goto out; } - return true; + /* VHT - if we have - is fine, including 80 MHz, check 160 below again */ + if (sband->band != NL80211_BAND_2GHZ) { + conn->mode = IEEE80211_CONN_MODE_VHT; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_160; + } + + if (is_5ghz && + !(vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; + mlme_link_id_dbg(sdata, link_id, + "no VHT 160 MHz capability on 5 GHz, limiting to 80 MHz"); + } + + if (req && req->flags & ASSOC_REQ_DISABLE_HE) { + mlme_link_id_dbg(sdata, link_id, + "HE disabled by flag, limiting to HT/VHT\n"); + goto out; + } + + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + if (!he_cap) { + WARN_ON(is_6ghz); + mlme_link_id_dbg(sdata, link_id, + "no HE support, limiting to HT/VHT\n"); + goto out; + } + + /* so we have HE */ + conn->mode = IEEE80211_CONN_MODE_HE; + + /* check bandwidth */ + switch (sband->band) { + default: + case NL80211_BAND_2GHZ: + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) + break; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; + mlme_link_id_dbg(sdata, link_id, + "no 40 MHz HE cap in 2.4 GHz, limiting to 20 MHz\n"); + break; + case NL80211_BAND_5GHZ: + if (!(he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; + mlme_link_id_dbg(sdata, link_id, + "no 40/80 MHz HE cap in 5 GHz, limiting to 20 MHz\n"); + break; + } + if (!(he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) { + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, + IEEE80211_CONN_BW_LIMIT_80); + mlme_link_id_dbg(sdata, link_id, + "no 160 MHz HE cap in 5 GHz, limiting to 80 MHz\n"); + } + break; + case NL80211_BAND_6GHZ: + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + break; + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, + IEEE80211_CONN_BW_LIMIT_80); + mlme_link_id_dbg(sdata, link_id, + "no 160 MHz HE cap in 6 GHz, limiting to 80 MHz\n"); + break; + } + + if (req && req->flags & ASSOC_REQ_DISABLE_EHT) { + mlme_link_id_dbg(sdata, link_id, + "EHT disabled by flag, limiting to HE\n"); + goto out; + } + + eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); + if (!eht_cap) { + mlme_link_id_dbg(sdata, link_id, + "no EHT support, limiting to HE\n"); + goto out; + } + + /* we have EHT */ + + conn->mode = IEEE80211_CONN_MODE_EHT; + + /* check bandwidth */ + if (is_6ghz && + eht_cap->eht_cap_elem.phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_320; + else if (is_6ghz) + mlme_link_id_dbg(sdata, link_id, + "no EHT 320 MHz cap in 6 GHz, limiting to 160 MHz\n"); + +out: + mlme_link_id_dbg(sdata, link_id, + "determined local STA to be %s, BW limited to %d MHz\n", + ieee80211_conn_mode_str(conn->mode), + 20 * (1 << conn->bw_limit)); +} + +static void +ieee80211_determine_our_sta_mode_auth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + struct cfg80211_auth_request *req, + bool wmm_used, + struct ieee80211_conn_settings *conn) +{ + ieee80211_determine_our_sta_mode(sdata, sband, NULL, wmm_used, + req->link_id > 0 ? req->link_id : 0, + conn); +} + +static void +ieee80211_determine_our_sta_mode_assoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + struct cfg80211_assoc_request *req, + bool wmm_used, int link_id, + struct ieee80211_conn_settings *conn) +{ + struct ieee80211_conn_settings tmp; + + WARN_ON(!req); + + ieee80211_determine_our_sta_mode(sdata, sband, req, wmm_used, link_id, + &tmp); + + conn->mode = min_t(enum ieee80211_conn_mode, + conn->mode, tmp.mode); + conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, + conn->bw_limit, tmp.bw_limit); } static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_link_data *link, - struct cfg80211_bss *cbss, - bool mlo, - ieee80211_conn_flags_t *conn_flags) + int link_id, + struct cfg80211_bss *cbss, bool mlo, + struct ieee80211_conn_settings *conn) { struct ieee80211_local *local = sdata->local; - const struct ieee80211_ht_cap *ht_cap = NULL; - const struct ieee80211_ht_operation *ht_oper = NULL; - const struct ieee80211_vht_operation *vht_oper = NULL; - const struct ieee80211_he_operation *he_oper = NULL; - const struct ieee80211_eht_operation *eht_oper = NULL; - const struct ieee80211_s1g_oper_ie *s1g_oper = NULL; - struct ieee80211_supported_band *sband; struct cfg80211_chan_def chandef; bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; - bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; - bool supports_mlo = false; - struct ieee80211_bss *bss = (void *)cbss->priv; - struct ieee80211_elems_parse_params parse_params = { - .link_id = -1, - .from_ap = true, - }; struct ieee802_11_elems *elems; - const struct cfg80211_bss_ies *ies; int ret; u32 i; - bool have_80mhz; lockdep_assert_wiphy(local->hw.wiphy); rcu_read_lock(); + elems = ieee80211_determine_chan_mode(sdata, conn, cbss, link_id, + &chandef); - ies = rcu_dereference(cbss->ies); - parse_params.start = ies->data; - parse_params.len = ies->len; - elems = ieee802_11_parse_elems_full(&parse_params); - if (!elems) { + if (IS_ERR(elems)) { rcu_read_unlock(); - return -ENOMEM; + return PTR_ERR(elems); } - sband = local->hw.wiphy->bands[cbss->channel->band]; - - *conn_flags &= ~(IEEE80211_CONN_DISABLE_40MHZ | - IEEE80211_CONN_DISABLE_80P80MHZ | - IEEE80211_CONN_DISABLE_160MHZ); - - /* disable HT/VHT/HE if we don't support them */ - if (!sband->ht_cap.ht_supported && !is_6ghz) { - mlme_dbg(sdata, "HT not supported, disabling HT/VHT/HE/EHT\n"); - *conn_flags |= IEEE80211_CONN_DISABLE_HT; - *conn_flags |= IEEE80211_CONN_DISABLE_VHT; - *conn_flags |= IEEE80211_CONN_DISABLE_HE; - *conn_flags |= IEEE80211_CONN_DISABLE_EHT; + if (mlo && !elems->ml_basic) { + sdata_info(sdata, "Rejecting MLO as it is not supported by AP\n"); + rcu_read_unlock(); + kfree(elems); + return -EINVAL; } - if (!sband->vht_cap.vht_supported && is_5ghz) { - mlme_dbg(sdata, "VHT not supported, disabling VHT/HE/EHT\n"); - *conn_flags |= IEEE80211_CONN_DISABLE_VHT; - *conn_flags |= IEEE80211_CONN_DISABLE_HE; - *conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } + if (link && is_6ghz && conn->mode >= IEEE80211_CONN_MODE_HE) { + struct ieee80211_bss_conf *bss_conf; + u8 j = 0; - if (!ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif)) { - mlme_dbg(sdata, "HE not supported, disabling HE and EHT\n"); - *conn_flags |= IEEE80211_CONN_DISABLE_HE; - *conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } + bss_conf = link->conf; - if (!ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif)) { - mlme_dbg(sdata, "EHT not supported, disabling EHT\n"); - *conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } + if (elems->pwr_constr_elem) + bss_conf->pwr_reduction = *elems->pwr_constr_elem; - if (!(*conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) { - ht_oper = elems->ht_operation; - ht_cap = elems->ht_cap_elem; + BUILD_BUG_ON(ARRAY_SIZE(bss_conf->tx_pwr_env) != + ARRAY_SIZE(elems->tx_pwr_env)); - if (!ht_cap) { - *conn_flags |= IEEE80211_CONN_DISABLE_HT; - ht_oper = NULL; + for (i = 0; i < elems->tx_pwr_env_num; i++) { + if (elems->tx_pwr_env_len[i] > sizeof(bss_conf->tx_pwr_env[j])) + continue; + + bss_conf->tx_pwr_env_num++; + memcpy(&bss_conf->tx_pwr_env[j], elems->tx_pwr_env[i], + elems->tx_pwr_env_len[i]); + j++; } } - - if (!(*conn_flags & IEEE80211_CONN_DISABLE_VHT) && !is_6ghz) { - vht_oper = elems->vht_operation; - if (vht_oper && !ht_oper) { - vht_oper = NULL; - sdata_info(sdata, - "AP advertised VHT without HT, disabling HT/VHT/HE\n"); - *conn_flags |= IEEE80211_CONN_DISABLE_HT; - *conn_flags |= IEEE80211_CONN_DISABLE_VHT; - *conn_flags |= IEEE80211_CONN_DISABLE_HE; - *conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } - - if (!elems->vht_cap_elem) { - *conn_flags |= IEEE80211_CONN_DISABLE_VHT; - vht_oper = NULL; - } - } - - if (!(*conn_flags & IEEE80211_CONN_DISABLE_HE)) { - he_oper = elems->he_operation; - - if (link && is_6ghz) { - struct ieee80211_bss_conf *bss_conf; - u8 j = 0; - - bss_conf = link->conf; - - if (elems->pwr_constr_elem) - bss_conf->pwr_reduction = *elems->pwr_constr_elem; - - BUILD_BUG_ON(ARRAY_SIZE(bss_conf->tx_pwr_env) != - ARRAY_SIZE(elems->tx_pwr_env)); - - for (i = 0; i < elems->tx_pwr_env_num; i++) { - if (elems->tx_pwr_env_len[i] > - sizeof(bss_conf->tx_pwr_env[j])) - continue; - - bss_conf->tx_pwr_env_num++; - memcpy(&bss_conf->tx_pwr_env[j], elems->tx_pwr_env[i], - elems->tx_pwr_env_len[i]); - j++; - } - } - - if (!ieee80211_verify_peer_he_mcs_support(sdata, - (void *)elems->he_cap, - he_oper) || - !ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper)) - *conn_flags |= IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - } - - /* - * EHT requires HE to be supported as well. Specifically for 6 GHz - * channels, the operation channel information can only be deduced from - * both the 6 GHz operation information (from the HE operation IE) and - * EHT operation. - */ - if (!(*conn_flags & - (IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT)) && - he_oper) { - eht_oper = elems->eht_operation; - - if (!ieee80211_verify_sta_eht_mcs_support(sdata, sband, eht_oper)) - *conn_flags |= IEEE80211_CONN_DISABLE_EHT; - - supports_mlo = elems->ml_basic; - } - - /* Allow VHT if at least one channel on the sband supports 80 MHz */ - have_80mhz = false; - for (i = 0; i < sband->n_channels; i++) { - if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_NO_80MHZ)) - continue; - - have_80mhz = true; - break; - } - - if (!have_80mhz) { - sdata_info(sdata, "80 MHz not supported, disabling VHT\n"); - *conn_flags |= IEEE80211_CONN_DISABLE_VHT; - } - - if (sband->band == NL80211_BAND_S1GHZ) { - s1g_oper = elems->s1g_oper; - if (!s1g_oper) - sdata_info(sdata, - "AP missing S1G operation element?\n"); - } - - *conn_flags |= - ieee80211_determine_chantype(sdata, link, *conn_flags, - sband, - cbss->channel, - bss->vht_cap_info, - ht_oper, vht_oper, - he_oper, eht_oper, - s1g_oper, - &chandef, false); - - if (link) - link->needed_rx_chains = - min(ieee80211_max_rx_chains(link, cbss), - local->rx_chains); - rcu_read_unlock(); /* the element data was RCU protected so no longer valid anyway */ kfree(elems); elems = NULL; - if (*conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) { - sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection"); - return -EINVAL; - } - - if (mlo && !supports_mlo) { - sdata_info(sdata, "Rejecting MLO as it is not supported by AP\n"); - return -EINVAL; - } - if (!link) return 0; + rcu_read_lock(); + link->needed_rx_chains = min(ieee80211_max_rx_chains(link, cbss), + local->rx_chains); + rcu_read_unlock(); + /* * If this fails (possibly due to channel context sharing * on incompatible channels, e.g. 80+80 and 160 sharing the @@ -5043,15 +5205,14 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, /* don't downgrade for 5 and 10 MHz channels, though. */ if (chandef.width == NL80211_CHAN_WIDTH_5 || chandef.width == NL80211_CHAN_WIDTH_10) - goto out; + return ret; while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { - *conn_flags |= - ieee80211_chandef_downgrade(&chandef); + ieee80211_chandef_downgrade(&chandef, conn); ret = ieee80211_link_use_channel(link, &chandef, IEEE80211_CHANCTX_SHARED); } - out: + return ret; } @@ -5177,8 +5338,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, link->conf->dtim_period = link->u.mgd.dtim_period ?: 1; if (link_id != assoc_data->assoc_link_id) { - err = ieee80211_prep_channel(sdata, link, cbss, true, - &link->u.mgd.conn_flags); + link->u.mgd.conn = assoc_data->link[link_id].conn; + + err = ieee80211_prep_channel(sdata, link, link_id, cbss, + true, &link->u.mgd.conn); if (err) { link_info(link, "prep_channel failed\n"); goto out_err; @@ -5296,6 +5459,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (!assoc_data) return; + parse_params.mode = + assoc_data->link[assoc_data->assoc_link_id].conn.mode; + if (!ether_addr_equal(assoc_data->ap_addr, mgmt->bssid) || !ether_addr_equal(assoc_data->ap_addr, mgmt->sa)) return; @@ -6162,6 +6328,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, u8 *bssid, *variable = mgmt->u.beacon.variable; u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; struct ieee80211_elems_parse_params parse_params = { + .mode = link->u.mgd.conn.mode, .link_id = -1, .from_ap = true, }; @@ -6416,10 +6583,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, changed |= ieee80211_recalc_twt_req(sdata, sband, link, link_sta, elems); - if (ieee80211_config_bw(link, elems, bssid, &changed)) { - sdata_info(sdata, - "failed to follow AP %pM bandwidth change, disconnect\n", - bssid); + if (ieee80211_config_bw(link, elems, &changed)) { ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DEAUTH_LEAVING, true, deauth_buf); @@ -6442,7 +6606,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, elems->cisco_dtpc_elem); if (elems->eht_operation && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) { + 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, @@ -7494,7 +7658,6 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) unsigned int link_id = link->link_id; link->u.mgd.p2p_noa_index = -1; - link->u.mgd.conn_flags = 0; link->conf->bssid = link->u.mgd.bssid; link->smps_mode = IEEE80211_SMPS_OFF; @@ -7534,6 +7697,7 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, struct cfg80211_bss *cbss, s8 link_id, const u8 *ap_mld_addr, bool assoc, + struct ieee80211_conn_settings *conn, bool override) { struct ieee80211_local *local = sdata->local; @@ -7665,13 +7829,22 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, } if (new_sta || override) { - err = ieee80211_prep_channel(sdata, link, cbss, mlo, - &link->u.mgd.conn_flags); + /* + * Only set this if we're also going to calculate the AP + * settings etc., otherwise this was set before in a + * previous call. Note override is set to %true in assoc + * if the settings were changed. + */ + link->u.mgd.conn = *conn; + err = ieee80211_prep_channel(sdata, link, link->link_id, cbss, + mlo, &link->u.mgd.conn); if (err) { if (new_sta) sta_info_free(local, new_sta); goto out_err; } + /* pass out for use in assoc */ + *conn = link->u.mgd.conn; } if (new_sta) { @@ -7786,10 +7959,13 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_auth_data *auth_data; + struct ieee80211_conn_settings conn; struct ieee80211_link_data *link; + struct ieee80211_supported_band *sband; + struct ieee80211_bss *bss; u16 auth_alg; int err; - bool cont_auth; + bool cont_auth, wmm_used; lockdep_assert_wiphy(sdata->local->hw.wiphy); @@ -7920,8 +8096,17 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, /* needed for transmitting the auth frame(s) properly */ memcpy(sdata->vif.cfg.ap_addr, auth_data->ap_addr, ETH_ALEN); + bss = (void *)req->bss->priv; + wmm_used = bss->wmm_used && (local->hw.queues >= IEEE80211_NUM_ACS); + + sband = local->hw.wiphy->bands[req->bss->channel->band]; + + ieee80211_determine_our_sta_mode_auth(sdata, sband, req, wmm_used, + &conn); + err = ieee80211_prep_connection(sdata, req->bss, req->link_id, - req->ap_mld_addr, cont_auth, false); + req->ap_mld_addr, cont_auth, + &conn, false); if (err) goto err_clear; @@ -7960,38 +8145,33 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return err; } -static ieee80211_conn_flags_t +static void ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_assoc_data *assoc_data, struct cfg80211_assoc_request *req, - ieee80211_conn_flags_t conn_flags, + struct ieee80211_conn_settings *conn, unsigned int link_id) { struct ieee80211_local *local = sdata->local; const struct cfg80211_bss_ies *bss_ies; struct ieee80211_supported_band *sband; - const struct element *ht_elem, *vht_elem; struct ieee80211_link_data *link; struct cfg80211_bss *cbss; struct ieee80211_bss *bss; - bool is_5ghz, is_6ghz; cbss = assoc_data->link[link_id].bss; if (WARN_ON(!cbss)) - return 0; + return; bss = (void *)cbss->priv; sband = local->hw.wiphy->bands[cbss->channel->band]; if (WARN_ON(!sband)) - return 0; + return; link = sdata_dereference(sdata->link[link_id], sdata); if (WARN_ON(!link)) - return 0; - - is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; - is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; + return; /* for MLO connections assume advertising all rates is OK */ if (!req->ap_mld_addr) { @@ -8008,40 +8188,18 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, assoc_data->ie_pos += req->links[link_id].elems_len; } - rcu_read_lock(); - ht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_OPERATION); - if (ht_elem && ht_elem->datalen >= sizeof(struct ieee80211_ht_operation)) - assoc_data->link[link_id].ap_ht_param = - ((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param; - else if (!is_6ghz) - conn_flags |= IEEE80211_CONN_DISABLE_HT; - vht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); - if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) { - memcpy(&assoc_data->link[link_id].ap_vht_cap, vht_elem->data, - sizeof(struct ieee80211_vht_cap)); - } else if (is_5ghz) { - link_info(link, - "VHT capa missing/short, disabling VHT/HE/EHT\n"); - conn_flags |= IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - } - rcu_read_unlock(); - link->u.mgd.beacon_crc_valid = false; link->u.mgd.dtim_period = 0; link->u.mgd.have_beacon = false; - /* override HT/VHT configuration only if the AP and we support it */ - if (!(conn_flags & IEEE80211_CONN_DISABLE_HT)) { + /* override HT configuration only if the AP and we support it */ + if (conn->mode >= IEEE80211_CONN_MODE_HT) { struct ieee80211_sta_ht_cap sta_ht_cap; memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); } - link->conf->eht_puncturing = 0; - rcu_read_lock(); bss_ies = rcu_dereference(cbss->beacon_ies); if (bss_ies) { @@ -8062,7 +8220,6 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, } if (bss_ies) { - const struct ieee80211_eht_operation *eht_oper; const struct element *elem; elem = cfg80211_find_ext_elem(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION, @@ -8079,32 +8236,6 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, link->conf->ema_ap = true; else link->conf->ema_ap = false; - - elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION, - bss_ies->data, bss_ies->len); - eht_oper = (const void *)(elem->data + 1); - - if (elem && - ieee80211_eht_oper_size_ok((const void *)(elem->data + 1), - elem->datalen - 1) && - (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) && - (eht_oper->params & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) { - const struct ieee80211_eht_operation_info *info = - (void *)eht_oper->optional; - const u8 *disable_subchannel_bitmap = info->optional; - u16 bitmap; - - bitmap = get_unaligned_le16(disable_subchannel_bitmap); - if (cfg80211_valid_disable_subchannel_bitmap(&bitmap, - &link->conf->chandef) && - !(bitmap && ieee80211_hw_check(&local->hw, DISALLOW_PUNCTURING))) - ieee80211_handle_puncturing_bitmap(link, - eht_oper, - bitmap, - NULL); - else - conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } } rcu_read_unlock(); @@ -8131,8 +8262,6 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, } else { link->smps_mode = link->u.mgd.req_smps; } - - return conn_flags; } int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, @@ -8144,11 +8273,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_assoc_data *assoc_data; const struct element *ssid_elem; struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; - ieee80211_conn_flags_t conn_flags = 0; struct ieee80211_link_data *link; struct cfg80211_bss *cbss; - struct ieee80211_bss *bss; - bool override; + bool override, uapsd_supported; + bool match_auth; int i, err; size_t size = sizeof(*assoc_data) + req->ie_len; @@ -8167,44 +8295,26 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (ieee80211_mgd_csa_in_process(sdata, cbss)) { sdata_info(sdata, "AP is in CSA process, reject assoc\n"); - kfree(assoc_data); - return -EINVAL; + err = -EINVAL; + goto err_free; } rcu_read_lock(); ssid_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_SSID); if (!ssid_elem || ssid_elem->datalen > sizeof(assoc_data->ssid)) { rcu_read_unlock(); - kfree(assoc_data); - return -EINVAL; + err = -EINVAL; + goto err_free; } memcpy(assoc_data->ssid, ssid_elem->data, ssid_elem->datalen); assoc_data->ssid_len = ssid_elem->datalen; - memcpy(vif_cfg->ssid, assoc_data->ssid, assoc_data->ssid_len); - vif_cfg->ssid_len = assoc_data->ssid_len; rcu_read_unlock(); - if (req->ap_mld_addr) { - for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { - if (!req->links[i].bss) - continue; - link = sdata_dereference(sdata->link[i], sdata); - if (link) - ether_addr_copy(assoc_data->link[i].addr, - link->conf->addr); - else - eth_random_addr(assoc_data->link[i].addr); - } - } else { - memcpy(assoc_data->link[0].addr, sdata->vif.addr, ETH_ALEN); - } - - assoc_data->s1g = cbss->channel->band == NL80211_BAND_S1GHZ; - - memcpy(assoc_data->ap_addr, - req->ap_mld_addr ?: req->bss->bssid, - ETH_ALEN); + if (req->ap_mld_addr) + memcpy(assoc_data->ap_addr, req->ap_mld_addr, ETH_ALEN); + else + memcpy(assoc_data->ap_addr, cbss->bssid, ETH_ALEN); if (ifmgd->associated) { u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; @@ -8222,89 +8332,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, false); } - if (ifmgd->auth_data && !ifmgd->auth_data->done) { - err = -EBUSY; - goto err_free; - } - - if (ifmgd->assoc_data) { - err = -EBUSY; - goto err_free; - } - - if (ifmgd->auth_data) { - bool match; - - /* keep sta info, bssid if matching */ - match = ether_addr_equal(ifmgd->auth_data->ap_addr, - assoc_data->ap_addr) && - ifmgd->auth_data->link_id == req->link_id; - - /* Cleanup is delayed if auth_data matches */ - if (!match) - ieee80211_destroy_auth_data(sdata, false); - } - - /* prepare assoc data */ - - bss = (void *)cbss->priv; - assoc_data->wmm = bss->wmm_used && - (local->hw.queues >= IEEE80211_NUM_ACS); - - assoc_data->spp_amsdu = req->flags & ASSOC_REQ_SPP_AMSDU; - - /* - * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. - * We still associate in non-HT mode (11a/b/g) if any one of these - * ciphers is configured as pairwise. - * We can set this to true for non-11n hardware, that'll be checked - * separately along with the peer capabilities. - */ - for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) { - if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { - conn_flags |= IEEE80211_CONN_DISABLE_HT; - conn_flags |= IEEE80211_CONN_DISABLE_VHT; - conn_flags |= IEEE80211_CONN_DISABLE_HE; - conn_flags |= IEEE80211_CONN_DISABLE_EHT; - netdev_info(sdata->dev, - "disabling HT/VHT/HE due to WEP/TKIP use\n"); - } - } - - /* also disable HT/VHT/HE/EHT if the AP doesn't use WMM */ - if (!bss->wmm_used) { - conn_flags |= IEEE80211_CONN_DISABLE_HT; - conn_flags |= IEEE80211_CONN_DISABLE_VHT; - conn_flags |= IEEE80211_CONN_DISABLE_HE; - conn_flags |= IEEE80211_CONN_DISABLE_EHT; - netdev_info(sdata->dev, - "disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n"); - } - - if (req->flags & ASSOC_REQ_DISABLE_HT) { - mlme_dbg(sdata, "HT disabled by flag, disabling HT/VHT/HE\n"); - conn_flags |= IEEE80211_CONN_DISABLE_HT; - conn_flags |= IEEE80211_CONN_DISABLE_VHT; - conn_flags |= IEEE80211_CONN_DISABLE_HE; - conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } - - if (req->flags & ASSOC_REQ_DISABLE_VHT) { - mlme_dbg(sdata, "VHT disabled by flag, disabling VHT\n"); - conn_flags |= IEEE80211_CONN_DISABLE_VHT; - } - - if (req->flags & ASSOC_REQ_DISABLE_HE) { - mlme_dbg(sdata, "HE disabled by flag, disabling HE/EHT\n"); - conn_flags |= IEEE80211_CONN_DISABLE_HE; - conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } - - if (req->flags & ASSOC_REQ_DISABLE_EHT) - conn_flags |= IEEE80211_CONN_DISABLE_EHT; - memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, sizeof(ifmgd->ht_capa_mask)); @@ -8317,6 +8344,123 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, memcpy(&ifmgd->s1g_capa_mask, &req->s1g_capa_mask, sizeof(ifmgd->s1g_capa_mask)); + /* keep some setup (AP STA, channel, ...) if matching */ + if (ifmgd->auth_data) + match_auth = ether_addr_equal(ifmgd->auth_data->ap_addr, + assoc_data->ap_addr) && + ifmgd->auth_data->link_id == req->link_id; + + if (req->ap_mld_addr) { + uapsd_supported = true; + + for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { + struct ieee80211_supported_band *sband; + struct cfg80211_bss *link_cbss = req->links[i].bss; + struct ieee80211_bss *bss; + + if (!link_cbss) + continue; + + bss = (void *)link_cbss->priv; + + if (!bss->wmm_used) { + err = -EINVAL; + goto err_free; + } + + if (req->flags & (ASSOC_REQ_DISABLE_HT | + ASSOC_REQ_DISABLE_VHT | + ASSOC_REQ_DISABLE_HE | + ASSOC_REQ_DISABLE_EHT)) { + err = -EINVAL; + goto err_free; + } + + if (link_cbss->channel->band == NL80211_BAND_S1GHZ) { + err = -EINVAL; + goto err_free; + } + + link = sdata_dereference(sdata->link[i], sdata); + if (link) + ether_addr_copy(assoc_data->link[i].addr, + link->conf->addr); + else + eth_random_addr(assoc_data->link[i].addr); + sband = local->hw.wiphy->bands[link_cbss->channel->band]; + + if (match_auth && i == assoc_link_id) + assoc_data->link[i].conn = link->u.mgd.conn; + else + assoc_data->link[i].conn = + ieee80211_conn_settings_unlimited; + ieee80211_determine_our_sta_mode_assoc(sdata, sband, + req, true, i, + &assoc_data->link[i].conn); + assoc_data->link[i].bss = link_cbss; + assoc_data->link[i].disabled = req->links[i].disabled; + + if (!bss->uapsd_supported) + uapsd_supported = false; + + if (assoc_data->link[i].conn.mode < IEEE80211_CONN_MODE_EHT) { + err = -EINVAL; + req->links[i].error = err; + goto err_free; + } + } + + assoc_data->wmm = true; + } else { + struct ieee80211_supported_band *sband; + struct ieee80211_bss *bss = (void *)cbss->priv; + + memcpy(assoc_data->link[0].addr, sdata->vif.addr, ETH_ALEN); + assoc_data->s1g = cbss->channel->band == NL80211_BAND_S1GHZ; + + assoc_data->wmm = bss->wmm_used && + (local->hw.queues >= IEEE80211_NUM_ACS); + + if (cbss->channel->band == NL80211_BAND_6GHZ && + req->flags & (ASSOC_REQ_DISABLE_HT | + ASSOC_REQ_DISABLE_VHT | + ASSOC_REQ_DISABLE_HE)) { + err = -EINVAL; + goto err_free; + } + + sband = local->hw.wiphy->bands[cbss->channel->band]; + + assoc_data->link[0].bss = cbss; + + if (match_auth) + assoc_data->link[0].conn = sdata->deflink.u.mgd.conn; + else + assoc_data->link[0].conn = + ieee80211_conn_settings_unlimited; + ieee80211_determine_our_sta_mode_assoc(sdata, sband, req, + assoc_data->wmm, 0, + &assoc_data->link[0].conn); + + uapsd_supported = bss->uapsd_supported; + } + + assoc_data->spp_amsdu = req->flags & ASSOC_REQ_SPP_AMSDU; + + if (ifmgd->auth_data && !ifmgd->auth_data->done) { + err = -EBUSY; + goto err_free; + } + + if (ifmgd->assoc_data) { + err = -EBUSY; + goto err_free; + } + + /* Cleanup is delayed if auth_data matches */ + if (ifmgd->auth_data && !match_auth) + ieee80211_destroy_auth_data(sdata, false); + if (req->ie && req->ie_len) { memcpy(assoc_data->ie, req->ie, req->ie_len); assoc_data->ie_len = req->ie_len; @@ -8347,19 +8491,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->assoc_link_id = assoc_link_id; if (req->ap_mld_addr) { - for (i = 0; i < ARRAY_SIZE(assoc_data->link); i++) { - assoc_data->link[i].conn_flags = conn_flags; - assoc_data->link[i].bss = req->links[i].bss; - assoc_data->link[i].disabled = req->links[i].disabled; - } - /* if there was no authentication, set up the link */ err = ieee80211_vif_set_links(sdata, BIT(assoc_link_id), 0); if (err) goto err_clear; - } else { - assoc_data->link[0].conn_flags = conn_flags; - assoc_data->link[0].bss = cbss; } link = sdata_dereference(sdata->link[assoc_link_id], sdata); @@ -8368,19 +8503,21 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, goto err_clear; } - /* keep old conn_flags from ieee80211_prep_channel() from auth */ - conn_flags |= link->u.mgd.conn_flags; - conn_flags |= ieee80211_setup_assoc_link(sdata, assoc_data, req, - conn_flags, assoc_link_id); - override = link->u.mgd.conn_flags != conn_flags; - link->u.mgd.conn_flags |= conn_flags; + override = link->u.mgd.conn.mode != + assoc_data->link[assoc_link_id].conn.mode || + link->u.mgd.conn.bw_limit != + assoc_data->link[assoc_link_id].conn.bw_limit; + link->u.mgd.conn = assoc_data->link[assoc_link_id].conn; + + ieee80211_setup_assoc_link(sdata, assoc_data, req, &link->u.mgd.conn, + assoc_link_id); if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) && ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK), "U-APSD not supported with HW_PS_NULLFUNC_STACK\n")) sdata->vif.driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; - if (bss->wmm_used && bss->uapsd_supported && + if (assoc_data->wmm && uapsd_supported && (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD)) { assoc_data->uapsd = true; ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; @@ -8424,27 +8561,29 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, continue; if (i == assoc_data->assoc_link_id) continue; - /* only calculate the flags, hence link == NULL */ - err = ieee80211_prep_channel(sdata, NULL, + /* only calculate the mode, hence link == NULL */ + err = ieee80211_prep_channel(sdata, NULL, i, assoc_data->link[i].bss, true, - &assoc_data->link[i].conn_flags); + &assoc_data->link[i].conn); if (err) { req->links[i].error = err; goto err_clear; } } + memcpy(vif_cfg->ssid, assoc_data->ssid, assoc_data->ssid_len); + vif_cfg->ssid_len = assoc_data->ssid_len; + /* needed for transmitting the assoc frames properly */ memcpy(sdata->vif.cfg.ap_addr, assoc_data->ap_addr, ETH_ALEN); err = ieee80211_prep_connection(sdata, cbss, req->link_id, - req->ap_mld_addr, true, override); + req->ap_mld_addr, true, + &assoc_data->link[assoc_link_id].conn, + override); if (err) goto err_clear; - assoc_data->link[assoc_data->assoc_link_id].conn_flags = - link->u.mgd.conn_flags; - if (ieee80211_hw_check(&sdata->local->hw, NEED_DTIM_BEFORE_ASSOC)) { const struct cfg80211_bss_ies *beacon_ies; diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 55959b0b24c5..d8c7b3e16eb7 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -23,7 +23,8 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, enum nl80211_band current_band, u32 vht_cap_info, - ieee80211_conn_flags_t conn_flags, u8 *bssid, + struct ieee80211_conn_settings *conn, + u8 *bssid, struct ieee80211_csa_ie *csa_ie) { enum nl80211_band new_band = current_band; @@ -42,13 +43,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, wide_bw_chansw_ie = elems->wide_bw_chansw_ie; bwi = elems->bandwidth_indication; - if (conn_flags & (IEEE80211_CONN_DISABLE_HT | - IEEE80211_CONN_DISABLE_40MHZ)) { + if (conn->mode < IEEE80211_CONN_MODE_HT || + conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) { sec_chan_offs = NULL; wide_bw_chansw_ie = NULL; } - if (conn_flags & IEEE80211_CONN_DISABLE_VHT) + if (conn->mode < IEEE80211_CONN_MODE_VHT) wide_bw_chansw_ie = NULL; if (elems->ext_chansw_ie) { @@ -95,7 +96,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, if (sec_chan_offs) { secondary_channel_offset = sec_chan_offs->sec_chan_offs; - } else if (!(conn_flags & IEEE80211_CONN_DISABLE_HT)) { + } else if (conn->mode >= IEEE80211_CONN_MODE_HT) { /* If the secondary channel offset IE is not present, * we can't know what's the post-CSA offset, so the * best we can do is use 20MHz. @@ -169,12 +170,10 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, &new_vht_chandef)) new_vht_chandef.chan = NULL; - if (conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ && - new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80) - ieee80211_chandef_downgrade(&new_vht_chandef); - if (conn_flags & IEEE80211_CONN_DISABLE_160MHZ && - new_vht_chandef.width == NL80211_CHAN_WIDTH_160) - ieee80211_chandef_downgrade(&new_vht_chandef); + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160 && + (new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80 || + new_vht_chandef.width == NL80211_CHAN_WIDTH_160)) + ieee80211_chandef_downgrade(&new_vht_chandef, NULL); } /* if VHT data is there validate & use it */ diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 49730b424141..396fd54d8bf7 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -347,7 +347,7 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, (uc.width > sta->tdls_chandef.width && !cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &uc, sdata->wdev.iftype))) - ieee80211_chandef_downgrade(&uc); + ieee80211_chandef_downgrade(&uc, NULL); if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) { tdls_dbg(sdata, "TDLS ch width upgraded %d -> %d\n", @@ -561,7 +561,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, ieee80211_he_ppe_size(he_cap->ppe_thres[0], he_cap->he_cap_elem.phy_cap_info); pos = skb_put(skb, cap_size); - pos = ieee80211_ie_build_he_cap(0, pos, he_cap, pos + cap_size); + pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, pos + cap_size); /* Build HE 6Ghz capa IE from sband */ if (sband->band == NL80211_BAND_6GHZ) { @@ -1413,8 +1413,8 @@ iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata, IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; u16 opmode; - /* Nothing to do if the BSS connection uses HT */ - if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) + /* Nothing to do if the BSS connection uses (at least) HT */ + if (sdata->deflink.u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT) return; tdls_ht = (sta && sta->sta.deflink.ht_cap.ht_supported) || diff --git a/net/mac80211/tests/elems.c b/net/mac80211/tests/elems.c index 997d0cd27b2d..30fc0acb7ac2 100644 --- a/net/mac80211/tests/elems.c +++ b/net/mac80211/tests/elems.c @@ -14,6 +14,7 @@ static void mle_defrag(struct kunit *test) struct ieee80211_elems_parse_params parse_params = { .link_id = 12, .from_ap = true, + .mode = IEEE80211_CONN_MODE_EHT, }; struct ieee802_11_elems *parsed; struct sk_buff *skb; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 685b55a053f3..1d504c8e6bfc 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -46,6 +46,11 @@ struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) } EXPORT_SYMBOL(wiphy_to_ieee80211_hw); +const struct ieee80211_conn_settings ieee80211_conn_settings_unlimited = { + .mode = IEEE80211_CONN_MODE_EHT, + .bw_limit = IEEE80211_CONN_BW_LIMIT_320, +}; + u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum nl80211_iftype type) { @@ -929,23 +934,31 @@ ieee80211_parse_extension_element(u32 *crc, switch (elem->data[0]) { case WLAN_EID_EXT_HE_MU_EDCA: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; calc_crc = true; if (len >= sizeof(*elems->mu_edca_param_set)) elems->mu_edca_param_set = data; break; case WLAN_EID_EXT_HE_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; if (ieee80211_he_capa_size_ok(data, len)) { elems->he_cap = data; elems->he_cap_len = len; } break; case WLAN_EID_EXT_HE_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; calc_crc = true; if (len >= sizeof(*elems->he_operation) && len >= ieee80211_he_oper_size(data) - 1) elems->he_operation = data; break; case WLAN_EID_EXT_UORA: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; if (len >= 1) elems->uora_element = data; break; @@ -958,15 +971,21 @@ ieee80211_parse_extension_element(u32 *crc, elems->mbssid_config_ie = data; break; case WLAN_EID_EXT_HE_SPR: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; if (len >= sizeof(*elems->he_spr) && len >= ieee80211_he_spr_size(data)) elems->he_spr = data; break; case WLAN_EID_EXT_HE_6GHZ_CAPA: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; if (len >= sizeof(*elems->he_6ghz_capa)) elems->he_6ghz_capa = data; break; case WLAN_EID_EXT_EHT_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; if (ieee80211_eht_capa_size_ok(elems->he_cap, data, len, params->from_ap)) { @@ -975,11 +994,15 @@ ieee80211_parse_extension_element(u32 *crc, } break; case WLAN_EID_EXT_EHT_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; if (ieee80211_eht_oper_size_ok(data, len)) elems->eht_operation = data; calc_crc = true; break; case WLAN_EID_EXT_EHT_MULTI_LINK: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; calc_crc = true; if (ieee80211_mle_size_ok(data, len)) { @@ -1004,11 +1027,15 @@ ieee80211_parse_extension_element(u32 *crc, } break; case WLAN_EID_EXT_BANDWIDTH_INDICATION: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; if (ieee80211_bandwidth_indication_size_ok(data, len)) elems->bandwidth_indication = data; calc_crc = true; break; case WLAN_EID_EXT_TID_TO_LINK_MAPPING: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; calc_crc = true; if (ieee80211_tid_to_link_map_size_ok(data, len) && elems->ttlm_num < ARRAY_SIZE(elems->ttlm)) { @@ -1178,24 +1205,32 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->ext_supp_rates_len = elen; break; case WLAN_EID_HT_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_HT) + break; if (elen >= sizeof(struct ieee80211_ht_cap)) elems->ht_cap_elem = (void *)pos; else elem_parse_failed = true; break; case WLAN_EID_HT_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_HT) + break; if (elen >= sizeof(struct ieee80211_ht_operation)) elems->ht_operation = (void *)pos; else elem_parse_failed = true; break; case WLAN_EID_VHT_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; if (elen >= sizeof(struct ieee80211_vht_cap)) elems->vht_cap_elem = (void *)pos; else elem_parse_failed = true; break; case WLAN_EID_VHT_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; if (elen >= sizeof(struct ieee80211_vht_operation)) { elems->vht_operation = (void *)pos; if (calc_crc) @@ -1205,6 +1240,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elem_parse_failed = true; break; case WLAN_EID_OPMODE_NOTIF: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; if (elen > 0) { elems->opmode_notif = pos; if (calc_crc) @@ -1264,6 +1301,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->ext_chansw_ie = (void *)pos; break; case WLAN_EID_SECONDARY_CHANNEL_OFFSET: + if (params->mode < IEEE80211_CONN_MODE_HT) + break; if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) { elem_parse_failed = true; break; @@ -1279,6 +1318,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->mesh_chansw_params_ie = (void *)pos; break; case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; if (!params->action || elen < sizeof(*elems->wide_bw_chansw_ie)) { elem_parse_failed = true; @@ -1287,6 +1328,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->wide_bw_chansw_ie = (void *)pos; break; case WLAN_EID_CHANNEL_SWITCH_WRAPPER: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; if (params->action) { elem_parse_failed = true; break; @@ -1305,6 +1348,9 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elem_parse_failed = true; } + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; + subelem = cfg80211_find_ext_elem(WLAN_EID_EXT_BANDWIDTH_INDICATION, pos, elen); if (subelem) { @@ -1393,24 +1439,32 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elem, elems, params); break; case WLAN_EID_S1G_CAPABILITIES: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; if (elen >= sizeof(*elems->s1g_capab)) elems->s1g_capab = (void *)pos; else elem_parse_failed = true; break; case WLAN_EID_S1G_OPERATION: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; if (elen == sizeof(*elems->s1g_oper)) elems->s1g_oper = (void *)pos; else elem_parse_failed = true; break; case WLAN_EID_S1G_BCN_COMPAT: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; if (elen == sizeof(*elems->s1g_bcn_compat)) elems->s1g_bcn_compat = (void *)pos; else elem_parse_failed = true; break; case WLAN_EID_AID_RESPONSE: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; if (elen == sizeof(struct ieee80211_aid_response_ie)) elems->aid_resp = (void *)pos; else @@ -1562,6 +1616,7 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, { struct ieee80211_mle_per_sta_profile *prof; struct ieee80211_elems_parse_params sub = { + .mode = params->mode, .action = params->action, .from_ap = params->from_ap, .link_id = -1, @@ -1649,6 +1704,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) /* Override with nontransmitted profile, if found */ if (nontransmitted_profile_len) { struct ieee80211_elems_parse_params sub = { + .mode = params->mode, .start = nontransmitted_profile, .len = nontransmitted_profile_len, .action = params->action, @@ -2142,7 +2198,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, if (he_cap && cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE)) { - pos = ieee80211_ie_build_he_cap(0, pos, he_cap, end); + pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, end); if (!pos) goto out_err; } @@ -3201,15 +3257,18 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype) he_cap->he_cap_elem.phy_cap_info); } -u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos, +u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, const struct ieee80211_sta_he_cap *he_cap, - u8 *end) + u8 *pos, u8 *end) { struct ieee80211_he_cap_elem elem; u8 n; u8 ie_len; u8 *orig_pos = pos; + if (!conn) + conn = &ieee80211_conn_settings_unlimited; + /* Make sure we have place for the IE */ /* * TODO: the 1 added is because this temporarily is under the EXTENSION @@ -3221,18 +3280,15 @@ u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos, /* modify on stack first to calculate 'n' and 'ie_len' correctly */ elem = he_cap->he_cap_elem; - if (disable_flags & IEEE80211_CONN_DISABLE_40MHZ) + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) elem.phy_cap_info[0] &= ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G); - if (disable_flags & IEEE80211_CONN_DISABLE_160MHZ) + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160) elem.phy_cap_info[0] &= - ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; - - if (disable_flags & IEEE80211_CONN_DISABLE_80P80MHZ) - elem.phy_cap_info[0] &= - ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G); n = ieee80211_he_mcs_nss_size(&elem); ie_len = 2 + 1 + @@ -4367,21 +4423,32 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_radar_detected); -ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c) +void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, + struct ieee80211_conn_settings *conn) { - ieee80211_conn_flags_t ret; + struct ieee80211_conn_settings _ignored = {}; int tmp; + /* allow passing NULL if caller doesn't care */ + if (!conn) + conn = &_ignored; + switch (c->width) { + default: + case NL80211_CHAN_WIDTH_20_NOHT: + WARN_ON_ONCE(1); + fallthrough; case NL80211_CHAN_WIDTH_20: c->width = NL80211_CHAN_WIDTH_20_NOHT; - ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT; + conn->mode = IEEE80211_CONN_MODE_LEGACY; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; break; case NL80211_CHAN_WIDTH_40: c->width = NL80211_CHAN_WIDTH_20; c->center_freq1 = c->chan->center_freq; - ret = IEEE80211_CONN_DISABLE_40MHZ | - IEEE80211_CONN_DISABLE_VHT; + if (conn->mode == IEEE80211_CONN_MODE_VHT) + conn->mode = IEEE80211_CONN_MODE_HT; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; break; case NL80211_CHAN_WIDTH_80: tmp = (30 + c->chan->center_freq - c->center_freq1)/20; @@ -4390,13 +4457,14 @@ ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c) /* freq_P40 */ c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; c->width = NL80211_CHAN_WIDTH_40; - ret = IEEE80211_CONN_DISABLE_VHT; + if (conn->mode == IEEE80211_CONN_MODE_VHT) + conn->mode = IEEE80211_CONN_MODE_HT; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_40; break; case NL80211_CHAN_WIDTH_80P80: c->center_freq2 = 0; c->width = NL80211_CHAN_WIDTH_80; - ret = IEEE80211_CONN_DISABLE_80P80MHZ | - IEEE80211_CONN_DISABLE_160MHZ; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; break; case NL80211_CHAN_WIDTH_160: /* n_P20 */ @@ -4405,8 +4473,7 @@ ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c) tmp /= 4; c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; c->width = NL80211_CHAN_WIDTH_80; - ret = IEEE80211_CONN_DISABLE_80P80MHZ | - IEEE80211_CONN_DISABLE_160MHZ; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; break; case NL80211_CHAN_WIDTH_320: /* n_P20 */ @@ -4415,30 +4482,28 @@ ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c) tmp /= 8; c->center_freq1 = c->center_freq1 - 80 + 160 * tmp; c->width = NL80211_CHAN_WIDTH_160; - ret = IEEE80211_CONN_DISABLE_320MHZ; - break; - default: - case NL80211_CHAN_WIDTH_20_NOHT: - WARN_ON_ONCE(1); - c->width = NL80211_CHAN_WIDTH_20_NOHT; - ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_160; break; case NL80211_CHAN_WIDTH_1: case NL80211_CHAN_WIDTH_2: case NL80211_CHAN_WIDTH_4: case NL80211_CHAN_WIDTH_8: case NL80211_CHAN_WIDTH_16: + WARN_ON_ONCE(1); + /* keep c->width */ + conn->mode = IEEE80211_CONN_MODE_S1G; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; + break; case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: WARN_ON_ONCE(1); /* keep c->width */ - ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT; + conn->mode = IEEE80211_CONN_MODE_LEGACY; + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; break; } WARN_ON_ONCE(!cfg80211_chandef_valid(c)); - - return ret; } /* @@ -5090,3 +5155,42 @@ u8 *ieee80211_ie_build_eht_cap(u8 *pos, return pos; } + +const char *ieee80211_conn_mode_str(enum ieee80211_conn_mode mode) +{ + static const char * const modes[] = { + [IEEE80211_CONN_MODE_S1G] = "S1G", + [IEEE80211_CONN_MODE_LEGACY] = "legacy", + [IEEE80211_CONN_MODE_HT] = "HT", + [IEEE80211_CONN_MODE_VHT] = "VHT", + [IEEE80211_CONN_MODE_HE] = "HE", + [IEEE80211_CONN_MODE_EHT] = "EHT", + }; + + if (WARN_ON(mode >= ARRAY_SIZE(modes))) + return ""; + + return modes[mode] ?: ""; +} + +enum ieee80211_conn_bw_limit +ieee80211_min_bw_limit_from_chandef(struct cfg80211_chan_def *chandef) +{ + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + return IEEE80211_CONN_BW_LIMIT_20; + case NL80211_CHAN_WIDTH_40: + return IEEE80211_CONN_BW_LIMIT_40; + case NL80211_CHAN_WIDTH_80: + return IEEE80211_CONN_BW_LIMIT_80; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + return IEEE80211_CONN_BW_LIMIT_160; + case NL80211_CHAN_WIDTH_320: + return IEEE80211_CONN_BW_LIMIT_320; + default: + WARN(1, "unhandled chandef width %d\n", chandef->width); + return IEEE80211_CONN_BW_LIMIT_20; + } +} From 2d9698dd32d086e47b8bff3df4322cc017c17b55 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:37 +0100 Subject: [PATCH 0904/2255] wifi: mac80211: clean up HE 6 GHz and EHT chandef parsing In the code we currently check for support 80+80, 160 and 320 channel widths, but really the way this should be (and is otherwise) handled is that we compute the highest channel bandwidth given there, and then cut it down to what we support. This is also needed for wider bandwidth OFDMA support. Change the code to remove this limitation and always parse the highest possible channel width. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240129194108.d06f85082e29.I47e68ed3d97b0a2f4ee61e5d8abfcefc8a5b9c08@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/mesh.c | 3 +- net/mac80211/mlme.c | 8 ++- net/mac80211/spectmgmt.c | 4 +- net/mac80211/util.c | 104 ++++++++----------------------------- 5 files changed, 29 insertions(+), 93 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 112029f5a7df..29294cf88d39 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2512,9 +2512,8 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info, const struct ieee80211_ht_operation *htop, struct cfg80211_chan_def *chandef); void ieee80211_chandef_eht_oper(const struct ieee80211_eht_operation_info *info, - bool support_160, bool support_320, struct cfg80211_chan_def *chandef); -bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, +bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_local *local, const struct ieee80211_he_operation *he_oper, const struct ieee80211_eht_operation *eht_oper, struct cfg80211_chan_def *chandef); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6b48914b39fd..60dc453acb5a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -107,7 +107,8 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, ie->vht_operation, ie->ht_operation, &sta_chan_def); - ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, ie->eht_operation, + ieee80211_chandef_he_6ghz_oper(sdata->local, ie->he_operation, + ie->eht_operation, &sta_chan_def); if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 549a06c9a2e5..7c0339d4f059 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -116,7 +116,7 @@ ieee80211_extract_dis_subch_bmap(const struct ieee80211_eht_operation *eht_oper, /* set 160/320 supported to get the full AP definition */ ieee80211_chandef_eht_oper((const void *)eht_oper->optional, - true, true, &ap_chandef); + &ap_chandef); ap_center_freq = ap_chandef.center_freq1; ap_bw = 20 * BIT(u8_get_bits(info->control, IEEE80211_EHT_OPER_CHAN_WIDTH)); @@ -280,7 +280,7 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata, mode = IEEE80211_CONN_MODE_HE; } - if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, + if (!ieee80211_chandef_he_6ghz_oper(sdata->local, he_oper, eht_oper, chandef)) { sdata_info(sdata, "bad HE/EHT 6 GHz operation\n"); return IEEE80211_CONN_MODE_LEGACY; @@ -394,9 +394,7 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata, struct cfg80211_chan_def eht_chandef = *chandef; ieee80211_chandef_eht_oper((const void *)eht_oper->optional, - eht_chandef.width == - NL80211_CHAN_WIDTH_160, - false, &eht_chandef); + &eht_chandef); if (!cfg80211_chandef_valid(&eht_chandef)) { sdata_info(sdata, diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index d8c7b3e16eb7..51efc9bc8168 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -139,9 +139,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, /* start with the CSA one */ new_vht_chandef = csa_ie->chandef; /* and update the width accordingly */ - /* FIXME: support 160/320 */ - ieee80211_chandef_eht_oper(&bwi->info, true, true, - &new_vht_chandef); + ieee80211_chandef_eht_oper(&bwi->info, &new_vht_chandef); } else if (wide_bw_chansw_ie) { u8 new_seg1 = wide_bw_chansw_ie->new_center_freq_seg1; struct ieee80211_vht_operation vht_oper = { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1d504c8e6bfc..1a2522e699d4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3841,7 +3841,6 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info, } void ieee80211_chandef_eht_oper(const struct ieee80211_eht_operation_info *info, - bool support_160, bool support_320, struct cfg80211_chan_def *chandef) { chandef->center_freq1 = @@ -3860,80 +3859,34 @@ void ieee80211_chandef_eht_oper(const struct ieee80211_eht_operation_info *info, chandef->width = NL80211_CHAN_WIDTH_80; break; case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ: - if (support_160) { - chandef->width = NL80211_CHAN_WIDTH_160; - chandef->center_freq1 = - ieee80211_channel_to_frequency(info->ccfs1, - chandef->chan->band); - } else { - chandef->width = NL80211_CHAN_WIDTH_80; - } + chandef->width = NL80211_CHAN_WIDTH_160; + chandef->center_freq1 = + ieee80211_channel_to_frequency(info->ccfs1, + chandef->chan->band); break; case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ: - if (support_320) { - chandef->width = NL80211_CHAN_WIDTH_320; - chandef->center_freq1 = - ieee80211_channel_to_frequency(info->ccfs1, - chandef->chan->band); - } else if (support_160) { - chandef->width = NL80211_CHAN_WIDTH_160; - } else { - chandef->width = NL80211_CHAN_WIDTH_80; - - if (chandef->center_freq1 > chandef->chan->center_freq) - chandef->center_freq1 -= 40; - else - chandef->center_freq1 += 40; - } + chandef->width = NL80211_CHAN_WIDTH_320; + chandef->center_freq1 = + ieee80211_channel_to_frequency(info->ccfs1, + chandef->chan->band); break; } } -bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, +bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_local *local, const struct ieee80211_he_operation *he_oper, const struct ieee80211_eht_operation *eht_oper, struct cfg80211_chan_def *chandef) { - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; - enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif); - const struct ieee80211_sta_he_cap *he_cap; - const struct ieee80211_sta_eht_cap *eht_cap; struct cfg80211_chan_def he_chandef = *chandef; const struct ieee80211_he_6ghz_oper *he_6ghz_oper; - bool support_80_80, support_160, support_320; - u8 he_phy_cap, eht_phy_cap; u32 freq; if (chandef->chan->band != NL80211_BAND_6GHZ) return true; - sband = local->hw.wiphy->bands[NL80211_BAND_6GHZ]; - - he_cap = ieee80211_get_he_iftype_cap(sband, iftype); - if (!he_cap) { - sdata_info(sdata, "Missing iftype sband data/HE cap"); + if (!he_oper) return false; - } - - he_phy_cap = he_cap->he_cap_elem.phy_cap_info[0]; - support_160 = - he_phy_cap & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; - support_80_80 = - he_phy_cap & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; - - if (!he_oper) { - sdata_info(sdata, - "HE is not advertised on (on %d MHz), expect issues\n", - chandef->chan->center_freq); - return false; - } - - eht_cap = ieee80211_get_eht_iftype_cap(sband, iftype); - if (!eht_cap) - eht_oper = NULL; he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); if (!he_6ghz_oper) @@ -3946,7 +3899,10 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, */ freq = ieee80211_channel_to_frequency(he_6ghz_oper->primary, NL80211_BAND_6GHZ); - he_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq); + he_chandef.chan = ieee80211_get_channel(local->hw.wiphy, freq); + + if (!he_chandef.chan) + return false; if (!eht_oper || !(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) { @@ -3965,13 +3921,10 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, he_chandef.width = NL80211_CHAN_WIDTH_80; if (!he_6ghz_oper->ccfs1) break; - if (abs(he_6ghz_oper->ccfs1 - he_6ghz_oper->ccfs0) == 8) { - if (support_160) - he_chandef.width = NL80211_CHAN_WIDTH_160; - } else { - if (support_80_80) - he_chandef.width = NL80211_CHAN_WIDTH_80P80; - } + if (abs(he_6ghz_oper->ccfs1 - he_6ghz_oper->ccfs0) == 8) + he_chandef.width = NL80211_CHAN_WIDTH_160; + else + he_chandef.width = NL80211_CHAN_WIDTH_80P80; break; } @@ -3983,30 +3936,17 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, he_chandef.center_freq1 = ieee80211_channel_to_frequency(he_6ghz_oper->ccfs0, NL80211_BAND_6GHZ); - if (support_80_80 || support_160) - he_chandef.center_freq2 = - ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1, - NL80211_BAND_6GHZ); + he_chandef.center_freq2 = + ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1, + NL80211_BAND_6GHZ); } } else { - eht_phy_cap = eht_cap->eht_cap_elem.phy_cap_info[0]; - support_320 = - eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; - ieee80211_chandef_eht_oper((const void *)eht_oper->optional, - support_160, support_320, &he_chandef); } - if (!cfg80211_chandef_valid(&he_chandef)) { - sdata_info(sdata, - "HE 6GHz operation resulted in invalid chandef: %d MHz/%d/%d MHz/%d MHz\n", - he_chandef.chan ? he_chandef.chan->center_freq : 0, - he_chandef.width, - he_chandef.center_freq1, - he_chandef.center_freq2); + if (!cfg80211_chandef_valid(&he_chandef)) return false; - } *chandef = he_chandef; From 0a44dfc070749514b804ccac0b1fd38718f7daa1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:38 +0100 Subject: [PATCH 0905/2255] 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 + .../net/wireless/broadcom/b43legacy/main.c | 4 + .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 4 + .../net/wireless/intel/iwlegacy/3945-mac.c | 4 + .../net/wireless/intel/iwlegacy/4965-mac.c | 4 + .../net/wireless/intel/iwlwifi/dvm/mac80211.c | 4 + drivers/net/wireless/intersil/p54/main.c | 4 + .../net/wireless/marvell/libertas_tf/main.c | 4 + drivers/net/wireless/marvell/mwl8k.c | 4 + .../net/wireless/mediatek/mt76/mt7603/main.c | 4 + .../net/wireless/mediatek/mt76/mt76x0/pci.c | 4 + .../net/wireless/mediatek/mt76/mt76x0/usb.c | 4 + .../wireless/mediatek/mt76/mt76x2/pci_main.c | 4 + .../wireless/mediatek/mt76/mt76x2/usb_main.c | 4 + .../net/wireless/mediatek/mt76/mt792x_core.c | 7 +- .../net/wireless/mediatek/mt76/mt7996/main.c | 4 + drivers/net/wireless/mediatek/mt7601u/main.c | 4 + drivers/net/wireless/purelifi/plfxlc/mac.c | 4 + .../net/wireless/ralink/rt2x00/rt2400pci.c | 4 + .../net/wireless/ralink/rt2x00/rt2500pci.c | 4 + .../net/wireless/ralink/rt2x00/rt2500usb.c | 4 + .../net/wireless/ralink/rt2x00/rt2800pci.c | 4 + .../net/wireless/ralink/rt2x00/rt2800soc.c | 4 + .../net/wireless/ralink/rt2x00/rt2800usb.c | 4 + drivers/net/wireless/ralink/rt2x00/rt61pci.c | 4 + drivers/net/wireless/ralink/rt2x00/rt73usb.c | 4 + .../wireless/realtek/rtl818x/rtl8180/dev.c | 4 + .../wireless/realtek/rtl818x/rtl8187/dev.c | 4 + .../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 | 207 +++++++++++++++--- net/mac80211/mlme.c | 3 +- net/mac80211/offchannel.c | 21 +- net/mac80211/scan.c | 18 +- net/mac80211/tx.c | 2 - net/mac80211/util.c | 25 +-- 58 files changed, 444 insertions(+), 207 deletions(-) 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->hw.conf.chandef = dflt_chandef; - local->_oper_chandef = dflt_chandef; - } local->monitor_chandef = dflt_chandef; + if (local->emulate_chanctx) { + local->dflt_chandef = dflt_chandef; + local->hw.conf.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)); + 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); - } + 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); From 9bf7079bc2271321fac467cae981c44e495b76b9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:39 +0100 Subject: [PATCH 0906/2255] wifi: mac80211: chan: chandef is non-NULL for reserved The last caller of this with a NULL argument was related to the non-chanctx code, so we can now remove this odd logic. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240129194108.bad8ec1e76c8.I12287452f42c54baf75821e75491cf6d021af20a@changeid Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index cf6297ffaef3..6b82c79cf7a6 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -90,11 +90,11 @@ ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, lockdep_assert_wiphy(local->hw.wiphy); + if (WARN_ON(!compat)) + return NULL; + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (!compat) - compat = &link->reserved_chandef; - compat = cfg80211_chandef_compatible(&link->reserved_chandef, compat); if (!compat) From 6092077ad09ce880c61735c314060f0bd79ae4aa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:40 +0100 Subject: [PATCH 0907/2255] 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 --- .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 8 +- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 +- .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 10 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 +- .../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 +- .../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(-) 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); From d1256c1546a0e03f103e2f0381103dc747ea7f81 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:41 +0100 Subject: [PATCH 0908/2255] wifi: mac80211: add and use a link iteration macro In the channel context code we have quite a few instances of nested loops iterating the interfaces and then links. Add a new for_each_sdata_link() macro and use it. Also, since it's easier, convert all the loops and a few other places away from RCU as we now hold the wiphy mutex everywhere anyway. This does cause a little bit more work (such as checking interface types for each link of an interface rather than not iterating links in some cases), but that's not a huge issue and seems like an acceptable trade-off, readability is important too. Link: https://msgid.link/20240129194108.7240829bd96d.I5ccbb8dd019cbcb5326c85d76121359225d6541a@changeid Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 246 ++++++++++++------------------------- net/mac80211/ieee80211_i.h | 13 ++ 2 files changed, 89 insertions(+), 170 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f1cef332e4db..c84449bdc928 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -211,7 +211,7 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta, enum ieee80211_sta_rx_bandwidth width; struct link_sta_info *link_sta; - link_sta = rcu_dereference(sta->link[link_id]); + link_sta = wiphy_dereference(sta->local->hw.wiphy, sta->link[link_id]); /* no effect if this STA has no presence on this link */ if (!link_sta) @@ -249,9 +249,10 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta, } static enum nl80211_chan_width -ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata, - unsigned int link_id) +ieee80211_get_max_required_bw(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; struct sta_info *sta; @@ -267,31 +268,25 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata, } static enum nl80211_chan_width -ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, - struct ieee80211_chanctx *ctx, - struct ieee80211_link_data *rsvd_for) +ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + struct ieee80211_link_data *rsvd_for) { + struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; - struct ieee80211_vif *vif = &sdata->vif; - int link_id; - rcu_read_lock(); - for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + for_each_sdata_link(local, link) { enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; - struct ieee80211_link_data *link = - rcu_dereference(sdata->link[link_id]); - - if (!link) - continue; if (link != rsvd_for && rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf) continue; - switch (vif->type) { + switch (link->sdata->vif.type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: - width = ieee80211_get_max_required_bw(sdata, link_id); + width = ieee80211_get_max_required_bw(link); break; case NL80211_IFTYPE_STATION: /* @@ -300,7 +295,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, * account also for TDLS peers */ width = max(link->conf->chanreq.oper.width, - ieee80211_get_max_required_bw(sdata, link_id)); + ieee80211_get_max_required_bw(link)); break; case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_NAN: @@ -321,40 +316,13 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, max_bw = max(max_bw, width); } - rcu_read_unlock(); - - return max_bw; -} - -static enum nl80211_chan_width -ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx, - struct ieee80211_link_data *rsvd_for) -{ - struct ieee80211_sub_if_data *sdata; - enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - enum nl80211_chan_width width; - - if (!ieee80211_sdata_running(sdata)) - continue; - - width = ieee80211_get_chanctx_vif_max_required_bw(sdata, ctx, - rsvd_for); - - max_bw = max(max_bw, width); - } /* use the configured bandwidth in case of monitor interface */ - sdata = rcu_dereference(local->monitor_sdata); + sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata && rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &ctx->conf) max_bw = max(max_bw, ctx->conf.def.width); - rcu_read_unlock(); - return max_bw; } @@ -582,26 +550,14 @@ ieee80211_find_chanctx(struct ieee80211_local *local, bool ieee80211_is_radar_required(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; lockdep_assert_wiphy(local->hw.wiphy); - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - unsigned int link_id; - - for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - struct ieee80211_link_data *link; - - link = rcu_dereference(sdata->link[link_id]); - - if (link && link->radar_required) { - rcu_read_unlock(); - return true; - } - } + for_each_sdata_link(local, link) { + if (link->radar_required) + return true; } - rcu_read_unlock(); return false; } @@ -611,38 +567,19 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { struct ieee80211_chanctx_conf *conf = &ctx->conf; - struct ieee80211_sub_if_data *sdata; - bool required = false; + struct ieee80211_link_data *link; lockdep_assert_wiphy(local->hw.wiphy); - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - unsigned int link_id; - - if (!ieee80211_sdata_running(sdata)) + for_each_sdata_link(local, link) { + if (rcu_access_pointer(link->conf->chanctx_conf) != conf) continue; - for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - struct ieee80211_link_data *link; - - link = rcu_dereference(sdata->link[link_id]); - if (!link) - continue; - - if (rcu_access_pointer(link->conf->chanctx_conf) != conf) - continue; - if (!link->radar_required) - continue; - required = true; - break; - } - - if (required) - break; + if (!link->radar_required) + continue; + return true; } - rcu_read_unlock(); - return required; + return false; } static struct ieee80211_chanctx * @@ -746,50 +683,38 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { struct ieee80211_chanctx_conf *conf = &ctx->conf; - struct ieee80211_sub_if_data *sdata; const struct cfg80211_chan_def *compat = NULL; + struct ieee80211_link_data *link; struct ieee80211_chan_req chanreq = {}; struct sta_info *sta; lockdep_assert_wiphy(local->hw.wiphy); - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - int link_id; + for_each_sdata_link(local, link) { + struct ieee80211_bss_conf *link_conf; - if (!ieee80211_sdata_running(sdata)) + if (link->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + link_conf = link->conf; + + if (rcu_access_pointer(link_conf->chanctx_conf) != conf) continue; - for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - struct ieee80211_bss_conf *link_conf = - rcu_dereference(sdata->vif.link_conf[link_id]); + if (!compat) + compat = &link_conf->chanreq.oper; - if (!link_conf) - continue; - - if (rcu_access_pointer(link_conf->chanctx_conf) != conf) - continue; - - if (!compat) - compat = &link_conf->chanreq.oper; - - compat = cfg80211_chandef_compatible(&link_conf->chanreq.oper, - compat); - if (WARN_ON_ONCE(!compat)) - break; - } + compat = cfg80211_chandef_compatible(&link_conf->chanreq.oper, + compat); + if (WARN_ON_ONCE(!compat)) + return; } - if (WARN_ON_ONCE(!compat)) { - rcu_read_unlock(); + if (WARN_ON_ONCE(!compat)) return; - } /* TDLS peers can sometimes affect the chandef width */ - list_for_each_entry_rcu(sta, &local->sta_list, list) { + list_for_each_entry(sta, &local->sta_list, list) { if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) || !test_sta_flag(sta, WLAN_STA_AUTHORIZED) || @@ -799,9 +724,8 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, compat = cfg80211_chandef_compatible(&sta->tdls_chandef, compat); if (WARN_ON_ONCE(!compat)) - break; + return; } - rcu_read_unlock(); if (!compat) return; @@ -895,23 +819,19 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, { struct ieee80211_sub_if_data *sdata; u8 rx_chains_static, rx_chains_dynamic; + struct ieee80211_link_data *link; lockdep_assert_wiphy(local->hw.wiphy); rx_chains_static = 1; rx_chains_dynamic = 1; - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { + for_each_sdata_link(local, link) { u8 needed_static, needed_dynamic; - unsigned int link_id; - if (!ieee80211_sdata_running(sdata)) - continue; - - switch (sdata->vif.type) { + switch (link->sdata->vif.type) { case NL80211_IFTYPE_STATION: - if (!sdata->u.mgd.associated) + if (!link->sdata->u.mgd.associated) continue; break; case NL80211_IFTYPE_AP: @@ -923,49 +843,38 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, continue; } - for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - struct ieee80211_link_data *link; + if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf) + continue; - link = rcu_dereference(sdata->link[link_id]); - - if (!link) - continue; - - if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf) - continue; - - switch (link->smps_mode) { - default: - WARN_ONCE(1, "Invalid SMPS mode %d\n", - link->smps_mode); - fallthrough; - case IEEE80211_SMPS_OFF: - needed_static = link->needed_rx_chains; - needed_dynamic = link->needed_rx_chains; - break; - case IEEE80211_SMPS_DYNAMIC: - needed_static = 1; - needed_dynamic = link->needed_rx_chains; - break; - case IEEE80211_SMPS_STATIC: - needed_static = 1; - needed_dynamic = 1; - break; - } - - rx_chains_static = max(rx_chains_static, needed_static); - rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); + switch (link->smps_mode) { + default: + WARN_ONCE(1, "Invalid SMPS mode %d\n", + link->smps_mode); + fallthrough; + case IEEE80211_SMPS_OFF: + needed_static = link->needed_rx_chains; + needed_dynamic = link->needed_rx_chains; + break; + case IEEE80211_SMPS_DYNAMIC: + needed_static = 1; + needed_dynamic = link->needed_rx_chains; + break; + case IEEE80211_SMPS_STATIC: + needed_static = 1; + needed_dynamic = 1; + break; } + + rx_chains_static = max(rx_chains_static, needed_static); + rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); } /* Disable SMPS for the monitor interface */ - sdata = rcu_dereference(local->monitor_sdata); + sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata && rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf) rx_chains_dynamic = rx_chains_static = local->rx_chains; - rcu_read_unlock(); - if (rx_chains_static == chanctx->conf.rx_chains_static && rx_chains_dynamic == chanctx->conf.rx_chains_dynamic) return; @@ -1004,17 +913,16 @@ __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, if (clear) conf = NULL; - rcu_read_lock(); list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { struct ieee80211_bss_conf *vlan_conf; - vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]); + vlan_conf = wiphy_dereference(local->hw.wiphy, + vlan->vif.link_conf[link_id]); if (WARN_ON(!vlan_conf)) continue; rcu_assign_pointer(vlan_conf->chanctx_conf, conf); } - rcu_read_unlock(); } void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, @@ -1204,17 +1112,16 @@ ieee80211_link_update_chanreq(struct ieee80211_link_data *link, if (sdata->vif.type != NL80211_IFTYPE_AP) return; - rcu_read_lock(); list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { struct ieee80211_bss_conf *vlan_conf; - vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]); + vlan_conf = wiphy_dereference(sdata->local->hw.wiphy, + vlan->vif.link_conf[link_id]); if (WARN_ON(!vlan_conf)) continue; vlan_conf->chanreq = *chanreq; } - rcu_read_unlock(); } static int @@ -1955,12 +1862,11 @@ void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link) ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); - rcu_read_lock(); - ap_conf = rcu_dereference(ap->vif.link_conf[link_id]); - conf = rcu_dereference_protected(ap_conf->chanctx_conf, - lockdep_is_held(&local->hw.wiphy->mtx)); + ap_conf = wiphy_dereference(local->hw.wiphy, + ap->vif.link_conf[link_id]); + conf = wiphy_dereference(local->hw.wiphy, + ap_conf->chanctx_conf); rcu_assign_pointer(link_conf->chanctx_conf, conf); - rcu_read_unlock(); } void ieee80211_iter_chan_contexts_atomic( diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 70c48cad180a..601b889b6237 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1181,6 +1181,19 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) #define sdata_dereference(p, sdata) \ wiphy_dereference(sdata->local->hw.wiphy, p) +#define for_each_sdata_link(_local, _link) \ + /* outer loop just to define the variables ... */ \ + for (struct ieee80211_sub_if_data *___sdata = NULL; \ + !___sdata; \ + ___sdata = (void *)~0 /* always stop */) \ + list_for_each_entry(___sdata, &(_local)->interfaces, list) \ + if (ieee80211_sdata_running(___sdata)) \ + for (int ___link_id = 0; \ + ___link_id < ARRAY_SIZE(___sdata->link); \ + ___link_id++) \ + if ((_link = wiphy_dereference((local)->hw.wiphy, \ + ___sdata->link[___link_id]))) + static inline int ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems, struct cfg80211_rnr_elems *rnr_elems, From 761748f001800d925c2ee8b04407e7aee12c3ffb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:42 +0100 Subject: [PATCH 0909/2255] wifi: mac80211: support wider bandwidth OFDMA config EHT requires that stations are able to participate in wider bandwidth OFDMA, i.e. parse downlink OFDMA and uplink OFDMA triggers when they're not capable of (or not connected at) the (wider) bandwidth that the AP is using. This requires hardware configuration, since the entity responsible for parsing (possibly hardware) needs to know the AP bandwidth. To support this, change the channel request to have the AP's bandwidth for clients, and track that in the channel context in mac80211. This means that the same chandef might need to be split up into two different contexts, if the APs are different. Interfaces other than client are not participating in OFDMA the same way, so they don't request any AP setting. Note that this doesn't introduce any API to split a channel context, so that there are cases where this might lead to a disconnect, e.g. if there are two client interfaces using the same channel context, e.g. both 160 MHz connected to different 320 MHz APs, and one of the APs switches to 160 MHz. Note also there are possible cases where this can be optimised, e.g. when using the upper or lower 160 Mhz, but I haven't been able to really fully understand the spec and/or hardware limitations. If, for some reason, there are no hardware limits on this because the OFDMA (downlink/trigger) parsing is done in firmware and can take the transmitter into account, then drivers can set the new flag IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW on interfaces to not have them request any AP bandwidth in the channel context and ignore this issue entirely. The bss_conf still contains the AP configuration (if any, i.e. EHT) in the chanreq. Link: https://msgid.link/20240129194108.d3d5b35dd783.I939d04674f4ff06f39934b1591c8d36a30ce74c2@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 14 ++++ net/mac80211/chan.c | 167 ++++++++++++++++++++++++++++--------- net/mac80211/ieee80211_i.h | 13 +++ net/mac80211/mlme.c | 60 +++++++------ net/mac80211/trace.h | 31 ++++++- 5 files changed, 215 insertions(+), 70 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index dd8a66e9afd9..ab6bc89d3394 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -214,6 +214,8 @@ struct ieee80211_low_level_stats { * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel, * this is used only with channel switching with CSA * @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 */ enum ieee80211_chanctx_change { IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), @@ -221,14 +223,18 @@ enum ieee80211_chanctx_change { IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2), IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3), IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4), + IEEE80211_CHANCTX_CHANGE_AP = BIT(5), }; /** * struct ieee80211_chan_req - A channel "request" * @oper: channel definition to use for operation + * @ap: the channel definition of the AP, if any + * (otherwise the chan member is %NULL) */ struct ieee80211_chan_req { struct cfg80211_chan_def oper; + struct cfg80211_chan_def ap; }; /** @@ -239,6 +245,8 @@ struct ieee80211_chan_req { * * @def: the channel definition * @min_def: the minimum channel definition currently required. + * @ap: the channel definition the AP actually is operating as, + * for use with (wider bandwidth) OFDMA * @rx_chains_static: The number of RX chains that must always be * active on the channel to receive MIMO transmissions * @rx_chains_dynamic: The number of RX chains that must be enabled @@ -251,6 +259,7 @@ struct ieee80211_chan_req { struct ieee80211_chanctx_conf { struct cfg80211_chan_def def; struct cfg80211_chan_def min_def; + struct cfg80211_chan_def ap; u8 rx_chains_static, rx_chains_dynamic; @@ -1782,6 +1791,10 @@ struct ieee80211_channel_switch { * this is not pure P2P vif. * @IEEE80211_VIF_EML_ACTIVE: The driver indicates that EML operation is * enabled for the interface. + * @IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW: Ignore wider bandwidth OFDMA + * operation on this interface and request a channel context without + * the AP definition. Use this e.g. because the device is able to + * handle OFDMA (downlink and trigger for uplink) on a per-AP basis. */ enum ieee80211_vif_flags { IEEE80211_VIF_BEACON_FILTER = BIT(0), @@ -1789,6 +1802,7 @@ enum ieee80211_vif_flags { IEEE80211_VIF_SUPPORTS_UAPSD = BIT(2), IEEE80211_VIF_GET_NOA_UPDATE = BIT(3), IEEE80211_VIF_EML_ACTIVE = BIT(4), + IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW = BIT(5), }; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index c84449bdc928..fe1489ba58c6 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -81,22 +81,35 @@ ieee80211_link_get_chanctx(struct ieee80211_link_data *link) return container_of(conf, struct ieee80211_chanctx, conf); } +bool ieee80211_chanreq_identical(const struct ieee80211_chan_req *a, + const struct ieee80211_chan_req *b) +{ + if (!cfg80211_chandef_identical(&a->oper, &b->oper)) + return false; + if (!a->ap.chan && !b->ap.chan) + return true; + return cfg80211_chandef_identical(&a->ap, &b->ap); +} + static const struct ieee80211_chan_req * ieee80211_chanreq_compatible(const struct ieee80211_chan_req *a, - const struct ieee80211_chan_req *b) + const struct ieee80211_chan_req *b, + struct ieee80211_chan_req *tmp) { const struct cfg80211_chan_def *compat; + if (a->ap.chan && b->ap.chan && + !cfg80211_chandef_identical(&a->ap, &b->ap)) + return NULL; + compat = cfg80211_chandef_compatible(&a->oper, &b->oper); + if (!compat) + return NULL; - if (compat == &a->oper) - return a; - - if (compat == &b->oper) - return b; - - WARN_ON(compat); - return NULL; + /* Note: later code assumes this always fills & returns tmp if compat */ + tmp->oper = *compat; + tmp->ap = a->ap.chan ? a->ap : b->ap; + return tmp; } static const struct ieee80211_chan_req * @@ -104,17 +117,26 @@ ieee80211_chanctx_compatible(struct ieee80211_chanctx *ctx, const struct ieee80211_chan_req *req, struct ieee80211_chan_req *tmp) { + const struct ieee80211_chan_req *ret; + struct ieee80211_chan_req tmp2; + *tmp = (struct ieee80211_chan_req){ .oper = ctx->conf.def, + .ap = ctx->conf.ap, }; - return ieee80211_chanreq_compatible(tmp, req); + ret = ieee80211_chanreq_compatible(tmp, req, &tmp2); + if (!ret) + return NULL; + *tmp = *ret; + return tmp; } static const struct ieee80211_chan_req * ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, - const struct ieee80211_chan_req *req) + const struct ieee80211_chan_req *req, + struct ieee80211_chan_req *tmp) { struct ieee80211_link_data *link; @@ -124,7 +146,7 @@ ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local, return NULL; list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - req = ieee80211_chanreq_compatible(&link->reserved, req); + req = ieee80211_chanreq_compatible(&link->reserved, req, tmp); if (!req) break; } @@ -135,7 +157,8 @@ ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local, static const struct ieee80211_chan_req * ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, - const struct ieee80211_chan_req *compat) + const struct ieee80211_chan_req *compat, + struct ieee80211_chan_req *tmp) { struct ieee80211_link_data *link; const struct ieee80211_chan_req *comp_def = compat; @@ -149,7 +172,7 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, continue; comp_def = ieee80211_chanreq_compatible(&link_conf->chanreq, - comp_def); + comp_def, tmp); if (!comp_def) break; } @@ -162,16 +185,18 @@ ieee80211_chanctx_can_reserve(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, const struct ieee80211_chan_req *req) { + struct ieee80211_chan_req tmp; + lockdep_assert_wiphy(local->hw.wiphy); - if (!ieee80211_chanctx_reserved_chanreq(local, ctx, req)) + if (!ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp)) return false; - if (!ieee80211_chanctx_non_reserved_chandef(local, ctx, req)) + if (!ieee80211_chanctx_non_reserved_chandef(local, ctx, req, &tmp)) return false; if (!list_empty(&ctx->reserved_links) && - ieee80211_chanctx_reserved_chanreq(local, ctx, req)) + ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp)) return true; return false; @@ -456,7 +481,11 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local, struct ieee80211_link_data *rsvd_for) { const struct cfg80211_chan_def *chandef = &chanreq->oper; - u32 changed; + struct ieee80211_chan_req ctx_req = { + .oper = ctx->conf.def, + .ap = ctx->conf.ap, + }; + u32 changed = 0; /* expected to handle only 20/40/80/160/320 channel widths */ switch (chandef->width) { @@ -478,26 +507,31 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local, */ ieee80211_chan_bw_change(local, old_ctx, true); - if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) { + if (ieee80211_chanreq_identical(&ctx_req, chanreq)) { ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for); return; } - WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); + WARN_ON(ieee80211_chanctx_refcount(local, ctx) > 1 && + !cfg80211_chandef_compatible(&ctx->conf.def, &chanreq->oper)); 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.ap, &chanreq->ap)) + changed |= IEEE80211_CHANCTX_CHANGE_AP; ctx->conf.def = *chandef; + ctx->conf.ap = chanreq->ap; /* check if min chanctx also changed */ - changed = IEEE80211_CHANCTX_CHANGE_WIDTH | - _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for); + changed |= _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for); ieee80211_add_wbrf(local, &ctx->conf.def); drv_change_chanctx(local, ctx, changed); - /* check is BW wider */ + /* check if BW is wider */ ieee80211_chan_bw_change(local, old_ctx, false); } @@ -536,7 +570,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, continue; compat = ieee80211_chanctx_reserved_chanreq(local, ctx, - compat); + compat, &tmp); if (!compat) continue; @@ -598,6 +632,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local, INIT_LIST_HEAD(&ctx->assigned_links); INIT_LIST_HEAD(&ctx->reserved_links); ctx->conf.def = chanreq->oper; + ctx->conf.ap = chanreq->ap; ctx->conf.rx_chains_static = 1; ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; @@ -683,9 +718,9 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { struct ieee80211_chanctx_conf *conf = &ctx->conf; - const struct cfg80211_chan_def *compat = NULL; + const struct ieee80211_chan_req *compat = NULL; struct ieee80211_link_data *link; - struct ieee80211_chan_req chanreq = {}; + struct ieee80211_chan_req tmp; struct sta_info *sta; lockdep_assert_wiphy(local->hw.wiphy); @@ -702,10 +737,10 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, continue; if (!compat) - compat = &link_conf->chanreq.oper; + compat = &link_conf->chanreq; - compat = cfg80211_chandef_compatible(&link_conf->chanreq.oper, - compat); + compat = ieee80211_chanreq_compatible(&link_conf->chanreq, + compat, &tmp); if (WARN_ON_ONCE(!compat)) return; } @@ -715,24 +750,23 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, /* TDLS peers can sometimes affect the chandef width */ list_for_each_entry(sta, &local->sta_list, list) { + struct ieee80211_chan_req tdls_chanreq = {}; if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) || !test_sta_flag(sta, WLAN_STA_AUTHORIZED) || !sta->tdls_chandef.chan) continue; - compat = cfg80211_chandef_compatible(&sta->tdls_chandef, - compat); + tdls_chanreq.oper = sta->tdls_chandef; + + /* note this always fills and returns &tmp if compat */ + compat = ieee80211_chanreq_compatible(&tdls_chanreq, + compat, &tmp); if (WARN_ON_ONCE(!compat)) return; } - if (!compat) - return; - - chanreq.oper = *compat; - - ieee80211_change_chanctx(local, ctx, ctx, &chanreq); + ieee80211_change_chanctx(local, ctx, ctx, compat); } static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, @@ -1133,6 +1167,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; struct ieee80211_chanctx *old_ctx, *new_ctx; const struct ieee80211_chan_req *chanreq; + struct ieee80211_chan_req tmp; u64 changed = 0; int err; @@ -1155,7 +1190,8 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) return -EINVAL; chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &link->reserved); + &link->reserved, + &tmp); if (WARN_ON(!chanreq)) return -EINVAL; @@ -1213,6 +1249,7 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *old_ctx, *new_ctx; const struct ieee80211_chan_req *chanreq; + struct ieee80211_chan_req tmp; int err; old_ctx = ieee80211_link_get_chanctx(link); @@ -1232,7 +1269,8 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) return -EINVAL; chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &link->reserved); + &link->reserved, + &tmp); if (WARN_ON(!chanreq)) return -EINVAL; @@ -1770,6 +1808,52 @@ int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link) return 0; } +/* + * This is similar to ieee80211_chanctx_compatible(), but rechecks + * against all the links actually using it (except the one that's + * passed, since that one is changing). + * This is done in order to allow changes to the AP's bandwidth for + * wider bandwidth OFDMA purposes, which wouldn't be treated as + * compatible by ieee80211_chanctx_recheck() but is OK if the link + * requesting the update is the only one using it. + */ +static const struct ieee80211_chan_req * +ieee80211_chanctx_recheck(struct ieee80211_local *local, + struct ieee80211_link_data *skip_link, + struct ieee80211_chanctx *ctx, + const struct ieee80211_chan_req *req, + struct ieee80211_chan_req *tmp) +{ + const struct ieee80211_chan_req *ret = req; + struct ieee80211_link_data *link; + + lockdep_assert_wiphy(local->hw.wiphy); + + for_each_sdata_link(local, link) { + if (link == skip_link) + continue; + + if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) { + ret = ieee80211_chanreq_compatible(ret, + &link->conf->chanreq, + tmp); + if (!ret) + return NULL; + } + + if (link->reserved_chanctx == ctx) { + ret = ieee80211_chanreq_compatible(ret, + &link->reserved, + tmp); + if (!ret) + return NULL; + } + } + + *tmp = *ret; + return tmp; +} + int ieee80211_link_change_chanreq(struct ieee80211_link_data *link, const struct ieee80211_chan_req *chanreq, u64 *changed) @@ -1806,13 +1890,14 @@ int ieee80211_link_change_chanreq(struct ieee80211_link_data *link, ctx = container_of(conf, struct ieee80211_chanctx, conf); - compat = ieee80211_chanctx_compatible(ctx, chanreq, &tmp); + compat = ieee80211_chanctx_recheck(local, link, ctx, chanreq, &tmp); if (!compat) return -EINVAL; switch (ctx->replace_state) { case IEEE80211_CHANCTX_REPLACE_NONE: - if (!ieee80211_chanctx_reserved_chanreq(local, ctx, compat)) + if (!ieee80211_chanctx_reserved_chanreq(local, ctx, compat, + &tmp)) return -EBUSY; break; case IEEE80211_CHANCTX_WILL_BE_REPLACED: diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 601b889b6237..534cac3fc8df 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2536,6 +2536,19 @@ bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper, struct cfg80211_chan_def *chandef); void ieee80211_chandef_downgrade(struct cfg80211_chan_def *chandef, struct ieee80211_conn_settings *conn); +static inline void +ieee80211_chanreq_downgrade(struct ieee80211_chan_req *chanreq, + struct ieee80211_conn_settings *conn) +{ + ieee80211_chandef_downgrade(&chanreq->oper, conn); + if (WARN_ON(!conn)) + return; + if (conn->mode < IEEE80211_CONN_MODE_EHT) + chanreq->ap.chan = NULL; +} + +bool ieee80211_chanreq_identical(const struct ieee80211_chan_req *a, + const struct ieee80211_chan_req *b); int __must_check ieee80211_link_use_channel(struct ieee80211_link_data *link, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e9d720f25ddf..31d6a5603582 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -665,7 +665,7 @@ 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 cfg80211_chan_def *chandef) + struct ieee80211_chan_req *chanreq) { struct ieee80211_local *local = sdata->local; const struct cfg80211_bss_ies *ies = rcu_dereference(cbss->ies); @@ -752,20 +752,27 @@ again: } conn->mode = ap_mode; - *chandef = ap_chandef; + chanreq->oper = ap_chandef; - while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, + /* wider-bandwidth OFDMA is only done in EHT */ + if (conn->mode >= IEEE80211_CONN_MODE_EHT && + !(sdata->vif.driver_flags & IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW)) + chanreq->ap = ap_chandef; + else + chanreq->ap.chan = NULL; + + while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &chanreq->oper, IEEE80211_CHAN_DISABLED)) { - if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { + if (WARN_ON(chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT)) { ret = -EINVAL; goto free; } - ieee80211_chandef_downgrade(chandef, conn); + ieee80211_chanreq_downgrade(chanreq, conn); } if (conn->mode >= IEEE80211_CONN_MODE_HE && - !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, + !cfg80211_chandef_usable(sdata->wdev.wiphy, &chanreq->oper, IEEE80211_CHAN_NO_HE)) { conn->mode = IEEE80211_CONN_MODE_VHT; conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, @@ -774,7 +781,7 @@ again: } if (conn->mode >= IEEE80211_CONN_MODE_EHT && - !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, + !cfg80211_chandef_usable(sdata->wdev.wiphy, &chanreq->oper, IEEE80211_CHAN_NO_EHT)) { conn->mode = IEEE80211_CONN_MODE_HE; conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, @@ -782,7 +789,7 @@ again: IEEE80211_CONN_BW_LIMIT_160); } - if (chandef->width != ap_chandef.width || ap_mode != conn->mode) + if (chanreq->oper.width != ap_chandef.width || ap_mode != conn->mode) sdata_info(sdata, "regulatory prevented using AP config, downgraded\n"); @@ -847,7 +854,7 @@ again: ieee80211_conn_mode_str(conn->mode), 20 * (1 << conn->bw_limit)); - if (WARN_ON_ONCE(!cfg80211_chandef_valid(chandef))) { + if (WARN_ON_ONCE(!cfg80211_chandef_valid(&chanreq->oper))) { ret = -EINVAL; goto free; } @@ -865,7 +872,6 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, 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; u16 ht_opmode; @@ -881,7 +887,7 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, ap_mode = ieee80211_determine_ap_chan(sdata, channel, vht_cap_info, elems, true, &link->u.mgd.conn, - &ap_chandef); + &chanreq.ap); if (ap_mode != link->u.mgd.conn.mode) { link_info(link, @@ -891,6 +897,11 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, return -EINVAL; } + chanreq.oper = chanreq.ap; + if (link->u.mgd.conn.mode < IEEE80211_CONN_MODE_EHT || + sdata->vif.driver_flags & IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW) + chanreq.ap.chan = NULL; + /* * if HT operation mode changed store the new one - * this may be applicable even if channel is identical @@ -911,20 +922,20 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, * won't do us any good -- we couldn't use it with the AP. */ while (link->u.mgd.conn.bw_limit < - ieee80211_min_bw_limit_from_chandef(&ap_chandef)) - ieee80211_chandef_downgrade(&ap_chandef, NULL); + ieee80211_min_bw_limit_from_chandef(&chanreq.oper)) + ieee80211_chandef_downgrade(&chanreq.oper, NULL); - if (cfg80211_chandef_identical(&ap_chandef, &link->conf->chanreq.oper)) + if (ieee80211_chanreq_identical(&chanreq, &link->conf->chanreq)) return 0; link_info(link, - "AP %pM changed bandwidth, new config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n", - link->u.mgd.bssid, ap_chandef.chan->center_freq, - ap_chandef.chan->freq_offset, ap_chandef.width, - ap_chandef.center_freq1, ap_chandef.freq1_offset, - ap_chandef.center_freq2); + "AP %pM changed bandwidth, new used config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n", + link->u.mgd.bssid, chanreq.oper.chan->center_freq, + chanreq.oper.chan->freq_offset, chanreq.oper.width, + chanreq.oper.center_freq1, chanreq.oper.freq1_offset, + chanreq.oper.center_freq2); - if (!cfg80211_chandef_valid(&ap_chandef)) { + if (!cfg80211_chandef_valid(&chanreq.oper)) { sdata_info(sdata, "AP %pM changed caps/bw in a way we can't support - disconnect\n", link->u.mgd.bssid); @@ -947,7 +958,6 @@ 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_chanreq(link, &chanreq, changed); if (ret) { @@ -2071,8 +2081,8 @@ static void ieee80211_chswitch_work(struct wiphy *wiphy, return; } - if (!cfg80211_chandef_identical(&link->conf->chanreq.oper, - &link->csa_chanreq.oper)) { + if (!ieee80211_chanreq_identical(&link->conf->chanreq, + &link->csa_chanreq)) { sdata_info(sdata, "failed to finalize channel switch, disconnecting\n"); wiphy_work_queue(sdata->local->hw.wiphy, @@ -5146,7 +5156,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, - &chanreq.oper); + &chanreq); if (IS_ERR(elems)) { rcu_read_unlock(); @@ -5209,7 +5219,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, return ret; while (ret && chanreq.oper.width != NL80211_CHAN_WIDTH_20_NOHT) { - ieee80211_chandef_downgrade(&chanreq.oper, conn); + ieee80211_chanreq_downgrade(&chanreq, conn); ret = ieee80211_link_use_channel(link, &chanreq, IEEE80211_CHANCTX_SHARED); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index efff20d7fe0e..478b32d2520a 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -50,7 +50,7 @@ __entry->center_freq1 = (c) ? (c)->center_freq1 : 0; \ __entry->freq1_offset = (c) ? (c)->freq1_offset : 0; \ __entry->center_freq2 = (c) ? (c)->center_freq2 : 0; -#define CHANDEF_PR_FMT " control:%d.%03d MHz width:%d center: %d.%03d/%d MHz" +#define CHANDEF_PR_FMT " chandef(%d.%03d MHz,width:%d,center: %d.%03d/%d MHz)" #define CHANDEF_PR_ARG __entry->control_freq, __entry->freq_offset, __entry->chan_width, \ __entry->center_freq1, __entry->freq1_offset, __entry->center_freq2 @@ -69,22 +69,45 @@ __entry->min_center_freq1 = (c)->center_freq1; \ __entry->min_freq1_offset = (c)->freq1_offset; \ __entry->min_center_freq2 = (c)->center_freq2; -#define MIN_CHANDEF_PR_FMT " min_control:%d.%03d MHz min_width:%d min_center: %d.%03d/%d MHz" +#define MIN_CHANDEF_PR_FMT " mindef(%d.%03d MHz,width:%d,center: %d.%03d/%d MHz)" #define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_freq_offset, \ __entry->min_chan_width, \ __entry->min_center_freq1, __entry->min_freq1_offset, \ __entry->min_center_freq2 +#define AP_CHANDEF_ENTRY \ + __field(u32, ap_control_freq) \ + __field(u32, ap_freq_offset) \ + __field(u32, ap_chan_width) \ + __field(u32, ap_center_freq1) \ + __field(u32, ap_freq1_offset) \ + __field(u32, ap_center_freq2) + +#define AP_CHANDEF_ASSIGN(c) \ + __entry->ap_control_freq = (c)->chan ? (c)->chan->center_freq : 0;\ + __entry->ap_freq_offset = (c)->chan ? (c)->chan->freq_offset : 0;\ + __entry->ap_chan_width = (c)->chan ? (c)->width : 0; \ + __entry->ap_center_freq1 = (c)->chan ? (c)->center_freq1 : 0; \ + __entry->ap_freq1_offset = (c)->chan ? (c)->freq1_offset : 0; \ + __entry->ap_center_freq2 = (c)->chan ? (c)->center_freq2 : 0; +#define AP_CHANDEF_PR_FMT " ap(%d.%03d MHz,width:%d,center: %d.%03d/%d MHz)" +#define AP_CHANDEF_PR_ARG __entry->ap_control_freq, __entry->ap_freq_offset, \ + __entry->ap_chan_width, \ + __entry->ap_center_freq1, __entry->ap_freq1_offset, \ + __entry->ap_center_freq2 + #define CHANCTX_ENTRY CHANDEF_ENTRY \ MIN_CHANDEF_ENTRY \ + AP_CHANDEF_ENTRY \ __field(u8, rx_chains_static) \ __field(u8, rx_chains_dynamic) #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \ MIN_CHANDEF_ASSIGN(&ctx->conf.min_def) \ + AP_CHANDEF_ASSIGN(&ctx->conf.ap) \ __entry->rx_chains_static = ctx->conf.rx_chains_static; \ __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic -#define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d" -#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, \ +#define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT AP_CHANDEF_PR_FMT " chains:%d/%d" +#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, AP_CHANDEF_PR_ARG, \ __entry->rx_chains_static, __entry->rx_chains_dynamic #define KEY_ENTRY __field(u32, cipher) \ From 6bc574a7cd27ba0c8d77425055a8fd672ec928f2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:43 +0100 Subject: [PATCH 0910/2255] wifi: mac80211: validate assoc response channel config Due to the earlier restructuring we now mostly ignore the channel configuration in the association response, apart from the HT/VHT checks we had. Don't do that, but parse it and update, also dropping the association if the AP changed its mode in the response. Link: https://msgid.link/20240129194108.b3efa5eae60c.I1b70c9fd56781b22cdfdca55d34d69f7d0733e31@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 31d6a5603582..da202103faf0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -867,7 +867,7 @@ free: static int ieee80211_config_bw(struct ieee80211_link_data *link, struct ieee802_11_elems *elems, - u64 *changed) + bool update, u64 *changed) { struct ieee80211_channel *channel = link->conf->chanreq.oper.chan; struct ieee80211_sub_if_data *sdata = link->sdata; @@ -942,6 +942,11 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, return -EINVAL; } + if (!update) { + link->conf->chanreq = chanreq; + return 0; + } + /* * We're tracking the current AP here, so don't do any further checks * here. This keeps us from playing ping-pong with regulatory, without @@ -4505,6 +4510,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, /* * We previously checked these in the beacon/probe response, so * they should be present here. This is just a safety net. + * Note that the ieee80211_config_bw() below would also check + * for this (and more), but this has better error reporting. */ if (!is_6ghz && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT && (!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) { @@ -4522,6 +4529,14 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, goto out; } + /* check/update if AP changed anything in assoc response vs. scan */ + if (ieee80211_config_bw(link, elems, + link_id == assoc_data->assoc_link_id, + changed)) { + ret = false; + goto out; + } + if (WARN_ON(!link->conf->chanreq.oper.chan)) { ret = false; goto out; @@ -6595,7 +6610,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, changed |= ieee80211_recalc_twt_req(sdata, sband, link, link_sta, elems); - if (ieee80211_config_bw(link, elems, &changed)) { + if (ieee80211_config_bw(link, elems, true, &changed)) { ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DEAUTH_LEAVING, true, deauth_buf); From 719036ae06d4bfdb65139e3947a8404dec298bc5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:44 +0100 Subject: [PATCH 0911/2255] wifi: cfg80211: move puncturing validation code Upcoming patches will move the puncturing bitmap into the chandef, so chandef validation will need to check for correct puncturing. Purely move the code first so later changes are easier to review. Link: https://msgid.link/20240129194108.1ca184427c76.I077deb8d52c4648eac145b63f88b6c5a3b920ddc@changeid Signed-off-by: Johannes Berg --- net/wireless/chan.c | 138 ++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index ceb9174c5c3d..71f1bd456d88 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -56,6 +56,75 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, } EXPORT_SYMBOL(cfg80211_chandef_create); +struct cfg80211_per_bw_puncturing_values { + u8 len; + const u16 *valid_values; +}; + +static const u16 puncturing_values_80mhz[] = { + 0x8, 0x4, 0x2, 0x1 +}; + +static const u16 puncturing_values_160mhz[] = { + 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, 0xc0, 0x30, 0xc, 0x3 +}; + +static const u16 puncturing_values_320mhz[] = { + 0xc000, 0x3000, 0xc00, 0x300, 0xc0, 0x30, 0xc, 0x3, 0xf000, 0xf00, + 0xf0, 0xf, 0xfc00, 0xf300, 0xf0c0, 0xf030, 0xf00c, 0xf003, 0xc00f, + 0x300f, 0xc0f, 0x30f, 0xcf, 0x3f +}; + +#define CFG80211_PER_BW_VALID_PUNCTURING_VALUES(_bw) \ + { \ + .len = ARRAY_SIZE(puncturing_values_ ## _bw ## mhz), \ + .valid_values = puncturing_values_ ## _bw ## mhz \ + } + +static const struct cfg80211_per_bw_puncturing_values per_bw_puncturing[] = { + CFG80211_PER_BW_VALID_PUNCTURING_VALUES(80), + CFG80211_PER_BW_VALID_PUNCTURING_VALUES(160), + CFG80211_PER_BW_VALID_PUNCTURING_VALUES(320) +}; + +bool cfg80211_valid_disable_subchannel_bitmap(u16 *bitmap, + const struct cfg80211_chan_def *chandef) +{ + u32 idx, i, start_freq; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_80: + idx = 0; + start_freq = chandef->center_freq1 - 40; + break; + case NL80211_CHAN_WIDTH_160: + idx = 1; + start_freq = chandef->center_freq1 - 80; + break; + case NL80211_CHAN_WIDTH_320: + idx = 2; + start_freq = chandef->center_freq1 - 160; + break; + default: + *bitmap = 0; + break; + } + + if (!*bitmap) + return true; + + /* check if primary channel is punctured */ + if (*bitmap & (u16)BIT((chandef->chan->center_freq - start_freq) / 20)) + return false; + + for (i = 0; i < per_bw_puncturing[idx].len; i++) + if (per_bw_puncturing[idx].valid_values[i] == *bitmap) + return true; + + return false; +} +EXPORT_SYMBOL(cfg80211_valid_disable_subchannel_bitmap); + static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef) { int max_contiguous = 0; @@ -1532,72 +1601,3 @@ struct cfg80211_chan_def *wdev_chandef(struct wireless_dev *wdev, } } EXPORT_SYMBOL(wdev_chandef); - -struct cfg80211_per_bw_puncturing_values { - u8 len; - const u16 *valid_values; -}; - -static const u16 puncturing_values_80mhz[] = { - 0x8, 0x4, 0x2, 0x1 -}; - -static const u16 puncturing_values_160mhz[] = { - 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, 0xc0, 0x30, 0xc, 0x3 -}; - -static const u16 puncturing_values_320mhz[] = { - 0xc000, 0x3000, 0xc00, 0x300, 0xc0, 0x30, 0xc, 0x3, 0xf000, 0xf00, - 0xf0, 0xf, 0xfc00, 0xf300, 0xf0c0, 0xf030, 0xf00c, 0xf003, 0xc00f, - 0x300f, 0xc0f, 0x30f, 0xcf, 0x3f -}; - -#define CFG80211_PER_BW_VALID_PUNCTURING_VALUES(_bw) \ - { \ - .len = ARRAY_SIZE(puncturing_values_ ## _bw ## mhz), \ - .valid_values = puncturing_values_ ## _bw ## mhz \ - } - -static const struct cfg80211_per_bw_puncturing_values per_bw_puncturing[] = { - CFG80211_PER_BW_VALID_PUNCTURING_VALUES(80), - CFG80211_PER_BW_VALID_PUNCTURING_VALUES(160), - CFG80211_PER_BW_VALID_PUNCTURING_VALUES(320) -}; - -bool cfg80211_valid_disable_subchannel_bitmap(u16 *bitmap, - const struct cfg80211_chan_def *chandef) -{ - u32 idx, i, start_freq; - - switch (chandef->width) { - case NL80211_CHAN_WIDTH_80: - idx = 0; - start_freq = chandef->center_freq1 - 40; - break; - case NL80211_CHAN_WIDTH_160: - idx = 1; - start_freq = chandef->center_freq1 - 80; - break; - case NL80211_CHAN_WIDTH_320: - idx = 2; - start_freq = chandef->center_freq1 - 160; - break; - default: - *bitmap = 0; - break; - } - - if (!*bitmap) - return true; - - /* check if primary channel is punctured */ - if (*bitmap & (u16)BIT((chandef->chan->center_freq - start_freq) / 20)) - return false; - - for (i = 0; i < per_bw_puncturing[idx].len; i++) - if (per_bw_puncturing[idx].valid_values[i] == *bitmap) - return true; - - return false; -} -EXPORT_SYMBOL(cfg80211_valid_disable_subchannel_bitmap); From c478db84c8544156b80c5e5d3a8c7840d557707a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:45 +0100 Subject: [PATCH 0912/2255] wifi: mac80211: refactor puncturing bitmap extraction Add a new inline helper function to ieee80211.h to extract the disabled subchannels bitmap from an EHT operation element, and use that in mac80211 where we do that. Link: https://msgid.link/20240129194108.d9f50dcec8d0.I8b08cbc2490a734fafcce0fa0fc328211ba6f10b@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 16 +++++++++++++ net/mac80211/mlme.c | 50 +++++++++++++-------------------------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index a70388ae3a7b..d9d2c1253157 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -3189,6 +3189,22 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len) return len >= needed; } +/* must validate ieee80211_eht_oper_size_ok() first */ +static inline u16 +ieee80211_eht_oper_dis_subchan_bitmap(const struct ieee80211_eht_operation *eht_oper) +{ + const struct ieee80211_eht_operation_info *info = + (const void *)eht_oper->optional; + + if (!(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) + return 0; + + if (!(eht_oper->params & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) + return 0; + + return get_unaligned_le16(info->optional); +} + #define IEEE80211_BW_IND_DIS_SUBCH_PRESENT BIT(1) struct ieee80211_bandwidth_indication { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index da202103faf0..74a15f18e7ee 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -813,36 +813,27 @@ again: } if (conn->mode >= IEEE80211_CONN_MODE_EHT) { - const struct ieee80211_eht_operation *eht_oper; + u16 bitmap; - eht_oper = elems->eht_operation; - - if (WARN_ON_ONCE(!eht_oper)) { + if (WARN_ON_ONCE(!elems->eht_operation)) { ret = -EINVAL; goto free; } - if (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT && - eht_oper->params & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT) { - const struct ieee80211_eht_operation_info *info = - (void *)eht_oper->optional; - const u8 *disable_subchannel_bitmap = info->optional; - u16 bitmap; + bitmap = ieee80211_eht_oper_dis_subchan_bitmap(elems->eht_operation); - bitmap = get_unaligned_le16(disable_subchannel_bitmap); - 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 */ + 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 */ @@ -5879,18 +5870,9 @@ static bool ieee80211_config_puncturing(struct ieee80211_link_data *link, u64 *changed) { struct ieee80211_local *local = link->sdata->local; - u16 bitmap = 0, extracted; - - if ((eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) && - (eht_oper->params & - IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) { - const struct ieee80211_eht_operation_info *info = - (void *)eht_oper->optional; - const u8 *disable_subchannel_bitmap = info->optional; - - bitmap = get_unaligned_le16(disable_subchannel_bitmap); - } + 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); From b9d908dc3a294d25c7d6c2f54ca3987cbd98f040 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:46 +0100 Subject: [PATCH 0913/2255] wifi: wireless: declare different S1G chandefs incompatible It doesn't look like we can get into this code, but make it more robust and declare two S1G chandefs to be incompatible unless they're identical. Link: https://msgid.link/20240129194108.b28fb0644a8c.I9297ada5cf1baf00dbbdf8fcffd1806883489fc9@changeid Signed-off-by: Johannes Berg --- net/wireless/chan.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 71f1bd456d88..159b8aac451e 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -465,13 +465,18 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, return NULL; /* - * can't be compatible if one of them is 5 or 10 MHz, + * can't be compatible if one of them is 5/10 MHz or S1G * but they don't have the same width. */ - if (c1->width == NL80211_CHAN_WIDTH_5 || - c1->width == NL80211_CHAN_WIDTH_10 || - c2->width == NL80211_CHAN_WIDTH_5 || - c2->width == NL80211_CHAN_WIDTH_10) +#define NARROW_OR_S1G(width) ((width) == NL80211_CHAN_WIDTH_5 || \ + (width) == NL80211_CHAN_WIDTH_10 || \ + (width) == NL80211_CHAN_WIDTH_1 || \ + (width) == NL80211_CHAN_WIDTH_2 || \ + (width) == NL80211_CHAN_WIDTH_4 || \ + (width) == NL80211_CHAN_WIDTH_8 || \ + (width) == NL80211_CHAN_WIDTH_16) + + if (NARROW_OR_S1G(c1->width) || NARROW_OR_S1G(c2->width)) return NULL; if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || From 8f251a0a1566e3e1da0f1d9322c8ffae808a7509 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:47 +0100 Subject: [PATCH 0914/2255] wifi: cfg80211: simplify cfg80211_chandef_compatible() Simplify cfg80211_chandef_compatible() a bit by switching c1 and c2 around so that c1 is always the narrower one (once they're not identical or narrow/S1G). Then we can just check the various primary channels and exit with the wider one (c2), or NULL. Also refactor the primary 40/80/160 function to not have all the calculations hard-coded, and use a wrapper around it to check primary 40/80/160 compatibility. While at it, add some kunit tests for this functionality. Also expose the new cfg80211_chandef_primary_freq() to drivers, mac80211 will use it. Link: https://msgid.link/20240129194108.be3e6eccaba3.I8399c2ff1435d7378e5837794cb5aa6dd2ee1416@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 11 +++ net/wireless/chan.c | 190 +++++++++++++++++++----------------- net/wireless/tests/Makefile | 2 +- net/wireless/tests/chan.c | 182 ++++++++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+), 91 deletions(-) create mode 100644 net/wireless/tests/chan.c diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5b42bfc1b660..fc2ad80118e8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1047,6 +1047,17 @@ unsigned int cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef); +/** + * 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 + * + * Returns: the primary 40/80/160 MHz channel center frequency, or -1 + * for errors + */ +int cfg80211_chandef_primary_freq(const struct cfg80211_chan_def *chandef, + enum nl80211_chan_width primary_chan_width); + /** * nl80211_send_chandef - sends the channel definition. * @msg: the msg to send channel definition diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 159b8aac451e..bfa2ea935fc2 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -390,68 +390,60 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) } EXPORT_SYMBOL(cfg80211_chandef_valid); -static void chandef_primary_freqs(const struct cfg80211_chan_def *c, - u32 *pri40, u32 *pri80, u32 *pri160) +int cfg80211_chandef_primary_freq(const struct cfg80211_chan_def *c, + enum nl80211_chan_width primary_chan_width) { - int tmp; + 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; - switch (c->width) { - case NL80211_CHAN_WIDTH_40: - *pri40 = c->center_freq1; - *pri80 = 0; - *pri160 = 0; - break; - case NL80211_CHAN_WIDTH_80: - case NL80211_CHAN_WIDTH_80P80: - *pri160 = 0; - *pri80 = c->center_freq1; - /* n_P20 */ - tmp = (30 + c->chan->center_freq - c->center_freq1)/20; - /* n_P40 */ - tmp /= 2; - /* freq_P40 */ - *pri40 = c->center_freq1 - 20 + 40 * tmp; - break; - case NL80211_CHAN_WIDTH_160: - *pri160 = c->center_freq1; - /* n_P20 */ - tmp = (70 + c->chan->center_freq - c->center_freq1)/20; - /* n_P40 */ - tmp /= 2; - /* freq_P40 */ - *pri40 = c->center_freq1 - 60 + 40 * tmp; - /* n_P80 */ - tmp /= 2; - *pri80 = c->center_freq1 - 40 + 80 * tmp; - break; - case NL80211_CHAN_WIDTH_320: - /* n_P20 */ - tmp = (150 + c->chan->center_freq - c->center_freq1) / 20; - /* n_P40 */ - tmp /= 2; - /* freq_P40 */ - *pri40 = c->center_freq1 - 140 + 40 * tmp; - /* n_P80 */ - tmp /= 2; - *pri80 = c->center_freq1 - 120 + 80 * tmp; - /* n_P160 */ - tmp /= 2; - *pri160 = c->center_freq1 - 80 + 160 * tmp; - break; - default: - WARN_ON_ONCE(1); + if (WARN_ON_ONCE(pri_width < 0 || width < 0)) + return -1; + + /* not intended to be called this way, can't determine */ + if (WARN_ON_ONCE(pri_width > width)) + return -1; + + while (width > pri_width) { + if (control > center) + center += width / 4; + else + center -= width / 4; + width /= 2; } + + return center; +} +EXPORT_SYMBOL(cfg80211_chandef_primary_freq); + +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) +{ + /* check primary is compatible -> error if not */ + if (cfg80211_chandef_primary_freq(c1, primary_chan_width) != + cfg80211_chandef_primary_freq(c2, primary_chan_width)) + return ERR_PTR(-EINVAL); + + /* assumes c1 is smaller width, if that was just checked -> done */ + if (c1->width == primary_chan_width) + return c2; + + /* otherwise continue checking the next width */ + return NULL; } -const struct cfg80211_chan_def * -cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, - const struct cfg80211_chan_def *c2) +static const struct cfg80211_chan_def * +_cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, + const struct cfg80211_chan_def *c2) { - u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80, c1_pri160, c2_pri160; + const struct cfg80211_chan_def *ret; /* If they are identical, return */ if (cfg80211_chandef_identical(c1, c2)) - return c1; + return c2; /* otherwise, must have same control channel */ if (c1->chan != c2->chan) @@ -479,44 +471,62 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, if (NARROW_OR_S1G(c1->width) || NARROW_OR_S1G(c2->width)) return NULL; - if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || - c1->width == NL80211_CHAN_WIDTH_20) - return c2; - - if (c2->width == NL80211_CHAN_WIDTH_20_NOHT || - c2->width == NL80211_CHAN_WIDTH_20) - return c1; - - chandef_primary_freqs(c1, &c1_pri40, &c1_pri80, &c1_pri160); - chandef_primary_freqs(c2, &c2_pri40, &c2_pri80, &c2_pri160); - - if (c1_pri40 != c2_pri40) - return NULL; - - if (c1->width == NL80211_CHAN_WIDTH_40) - return c2; - - if (c2->width == NL80211_CHAN_WIDTH_40) - return c1; - - if (c1_pri80 != c2_pri80) - return NULL; - - if (c1->width == NL80211_CHAN_WIDTH_80 && - c2->width > NL80211_CHAN_WIDTH_80) - return c2; - - if (c2->width == NL80211_CHAN_WIDTH_80 && - c1->width > NL80211_CHAN_WIDTH_80) - return c1; - - WARN_ON(!c1_pri160 && !c2_pri160); - if (c1_pri160 && c2_pri160 && c1_pri160 != c2_pri160) - return NULL; - + /* + * Make sure that c1 is always the narrower one, so that later + * we either return NULL or c2 and don't have to check both + * directions. + */ if (c1->width > c2->width) - return c1; - return c2; + swap(c1, c2); + + /* + * No further checks needed if the "narrower" one is only 20 MHz. + * Here "narrower" includes being a 20 MHz non-HT channel vs. a + * 20 MHz HT (or later) one. + */ + if (c1->width <= NL80211_CHAN_WIDTH_20) + return c2; + + ret = check_chandef_primary_compat(c1, c2, NL80211_CHAN_WIDTH_40); + if (ret) + return ret; + + ret = check_chandef_primary_compat(c1, c2, NL80211_CHAN_WIDTH_80); + if (ret) + return ret; + + /* + * If c1 is 80+80, then c2 is 160 or higher, but that cannot + * match. If c2 was also 80+80 it was already either accepted + * or rejected above (identical or not, respectively.) + */ + if (c1->width == NL80211_CHAN_WIDTH_80P80) + return NULL; + + ret = check_chandef_primary_compat(c1, c2, NL80211_CHAN_WIDTH_160); + if (ret) + return ret; + + /* + * Getting here would mean they're both wider than 160, have the + * same primary 160, but are not identical - this cannot happen + * since they must be 320 (no wider chandefs exist, at least yet.) + */ + WARN_ON_ONCE(1); + + return NULL; +} + +const struct cfg80211_chan_def * +cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, + const struct cfg80211_chan_def *c2) +{ + const struct cfg80211_chan_def *ret; + + ret = _cfg80211_chandef_compatible(c1, c2); + if (IS_ERR(ret)) + return NULL; + return ret; } EXPORT_SYMBOL(cfg80211_chandef_compatible); diff --git a/net/wireless/tests/Makefile b/net/wireless/tests/Makefile index 1f6622fcb758..c364e63b508e 100644 --- a/net/wireless/tests/Makefile +++ b/net/wireless/tests/Makefile @@ -1,3 +1,3 @@ -cfg80211-tests-y += module.o fragmentation.o scan.o util.o +cfg80211-tests-y += module.o fragmentation.o scan.o util.o chan.o obj-$(CONFIG_CFG80211_KUNIT_TEST) += cfg80211-tests.o diff --git a/net/wireless/tests/chan.c b/net/wireless/tests/chan.c new file mode 100644 index 000000000000..b9e7a27e43cb --- /dev/null +++ b/net/wireless/tests/chan.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit tests for channel helper functions + * + * Copyright (C) 2023 Intel Corporation + */ +#include +#include + +MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); + +static struct ieee80211_channel chan_6ghz_1 = { + .band = NL80211_BAND_6GHZ, + .center_freq = 5955, +}; + +static struct ieee80211_channel chan_6ghz_5 = { + .band = NL80211_BAND_6GHZ, + .center_freq = 5975, +}; + +static struct ieee80211_channel chan_6ghz_105 = { + .band = NL80211_BAND_6GHZ, + .center_freq = 6475, +}; + +static const struct chandef_compat_case { + const char *desc; + /* leave c1 empty for tests for identical */ + struct cfg80211_chan_def c1, c2; + /* we test both ways around, so c2 should always be the compat one */ + bool compat; +} chandef_compat_cases[] = { + { + .desc = "identical non-HT", + .c2 = { + .width = NL80211_CHAN_WIDTH_20_NOHT, + .chan = &chan_6ghz_1, + .center_freq1 = 5955, + }, + .compat = true, + }, + { + .desc = "identical 20 MHz", + .c2 = { + .width = NL80211_CHAN_WIDTH_20, + .chan = &chan_6ghz_1, + .center_freq1 = 5955, + }, + .compat = true, + }, + { + .desc = "identical 40 MHz", + .c2 = { + .width = NL80211_CHAN_WIDTH_40, + .chan = &chan_6ghz_1, + .center_freq1 = 5955 + 10, + }, + .compat = true, + }, + { + .desc = "identical 80 MHz", + .c2 = { + .width = NL80211_CHAN_WIDTH_80, + .chan = &chan_6ghz_1, + .center_freq1 = 5955 + 10 + 20, + }, + .compat = true, + }, + { + .desc = "identical 160 MHz", + .c2 = { + .width = NL80211_CHAN_WIDTH_160, + .chan = &chan_6ghz_1, + .center_freq1 = 5955 + 10 + 20 + 40, + }, + .compat = true, + }, + { + .desc = "identical 320 MHz", + .c2 = { + .width = NL80211_CHAN_WIDTH_320, + .chan = &chan_6ghz_1, + .center_freq1 = 5955 + 10 + 20 + 40 + 80, + }, + .compat = true, + }, + { + .desc = "20 MHz in 320 MHz\n", + .c1 = { + .width = NL80211_CHAN_WIDTH_20, + .chan = &chan_6ghz_1, + .center_freq1 = 5955, + }, + .c2 = { + .width = NL80211_CHAN_WIDTH_320, + .chan = &chan_6ghz_1, + .center_freq1 = 5955 + 10 + 20 + 40 + 80, + }, + .compat = true, + }, + { + .desc = "different 20 MHz", + .c1 = { + .width = NL80211_CHAN_WIDTH_20, + .chan = &chan_6ghz_1, + .center_freq1 = 5955, + }, + .c2 = { + .width = NL80211_CHAN_WIDTH_20, + .chan = &chan_6ghz_5, + .center_freq1 = 5975, + }, + }, + { + .desc = "different primary 160 MHz", + .c1 = { + .width = NL80211_CHAN_WIDTH_320, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 + 150, + }, + .c2 = { + .width = NL80211_CHAN_WIDTH_320, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 - 10, + }, + }, + { + /* similar to previous test but one has lower BW */ + .desc = "matching primary 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, + }, + .compat = true, + }, +}; + +KUNIT_ARRAY_PARAM_DESC(chandef_compat, chandef_compat_cases, desc) + +static void test_chandef_compat(struct kunit *test) +{ + const struct chandef_compat_case *params = test->param_value; + const struct cfg80211_chan_def *ret, *expect; + struct cfg80211_chan_def c1 = params->c1; + + /* tests with identical ones */ + if (!params->c1.chan) + c1 = params->c2; + + KUNIT_EXPECT_EQ(test, cfg80211_chandef_valid(&c1), true); + KUNIT_EXPECT_EQ(test, cfg80211_chandef_valid(¶ms->c2), true); + + expect = params->compat ? ¶ms->c2 : NULL; + + ret = cfg80211_chandef_compatible(&c1, ¶ms->c2); + KUNIT_EXPECT_PTR_EQ(test, ret, expect); + + if (!params->c1.chan) + expect = &c1; + + ret = cfg80211_chandef_compatible(¶ms->c2, &c1); + KUNIT_EXPECT_PTR_EQ(test, ret, expect); +} + +static struct kunit_case chandef_compat_test_cases[] = { + KUNIT_CASE_PARAM(test_chandef_compat, chandef_compat_gen_params), + {} +}; + +static struct kunit_suite chandef_compat = { + .name = "cfg80211-chandef-compat", + .test_cases = chandef_compat_test_cases, +}; + +kunit_test_suite(chandef_compat); From 8616f27b3fb0d47be053d7bebc9539171a514917 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:48 +0100 Subject: [PATCH 0915/2255] wifi: mac80211: use cfg80211_chandef_primary_freq() Instead of calculating the new primary 40/80/160 MHz center frequency here, use the new helper function from cfg80211. Link: https://msgid.link/20240129194108.eb59d6433d18.I74b745f0d1a32e779fb25d50c56407be7c35b840@changeid Signed-off-by: Johannes Berg --- net/mac80211/util.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 49eef33b5e70..63a88169d53d 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -4365,8 +4365,9 @@ 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; struct ieee80211_conn_settings _ignored = {}; - int tmp; /* allow passing NULL if caller doesn't care */ if (!conn) @@ -4390,12 +4391,7 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; break; case NL80211_CHAN_WIDTH_80: - tmp = (30 + c->chan->center_freq - c->center_freq1)/20; - /* n_P40 */ - tmp /= 2; - /* freq_P40 */ - c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; - c->width = NL80211_CHAN_WIDTH_40; + new_primary_width = NL80211_CHAN_WIDTH_40; if (conn->mode == IEEE80211_CONN_MODE_VHT) conn->mode = IEEE80211_CONN_MODE_HT; conn->bw_limit = IEEE80211_CONN_BW_LIMIT_40; @@ -4406,21 +4402,11 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; break; case NL80211_CHAN_WIDTH_160: - /* n_P20 */ - tmp = (70 + c->chan->center_freq - c->center_freq1)/20; - /* n_P80 */ - tmp /= 4; - c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; - c->width = NL80211_CHAN_WIDTH_80; + new_primary_width = NL80211_CHAN_WIDTH_80; conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; break; case NL80211_CHAN_WIDTH_320: - /* n_P20 */ - tmp = (150 + c->chan->center_freq - c->center_freq1) / 20; - /* n_P160 */ - tmp /= 8; - c->center_freq1 = c->center_freq1 - 80 + 160 * tmp; - c->width = NL80211_CHAN_WIDTH_160; + new_primary_width = NL80211_CHAN_WIDTH_160; conn->bw_limit = IEEE80211_CONN_BW_LIMIT_160; break; case NL80211_CHAN_WIDTH_1: @@ -4442,6 +4428,12 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, break; } + if (new_primary_width != NL80211_CHAN_WIDTH_20_NOHT) { + c->center_freq1 = + cfg80211_chandef_primary_freq(c, new_primary_width); + c->width = new_primary_width; + } + WARN_ON_ONCE(!cfg80211_chandef_valid(c)); } From b82730bf57b54803ab94abbfd8c4422a7081886d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:49 +0100 Subject: [PATCH 0916/2255] 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 +- .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 6 +- drivers/net/wireless/marvell/mwifiex/11h.c | 2 +- .../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(-) 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, From b1344b1399daec9aca62bd0b2ea94874f5b8e126 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:04:56 +0100 Subject: [PATCH 0917/2255] wifi: mac80211: add/use ieee80211_get_sn() This will also be useful for MLO duplicate multicast detection, but add it already here and use it in one place that trivially converts. Link: https://msgid.link/20240129200456.f0ff49c80006.I850d2785ab1640e56e262d3ad7343b87f6962552@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 7 ++++++- net/mac80211/rx.c | 5 ++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index d9d2c1253157..b9367d5f04c4 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -9,7 +9,7 @@ * Copyright (c) 2006, Michael Wu * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright (c) 2016 - 2017 Intel Deutschland GmbH - * Copyright (c) 2018 - 2023 Intel Corporation + * Copyright (c) 2018 - 2024 Intel Corporation */ #ifndef LINUX_IEEE80211_H @@ -808,6 +808,11 @@ static inline bool ieee80211_is_frag(struct ieee80211_hdr *hdr) hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG); } +static inline u16 ieee80211_get_sn(struct ieee80211_hdr *hdr) +{ + return le16_get_bits(hdr->seq_ctrl, IEEE80211_SCTL_SEQ); +} + struct ieee80211s_hdr { u8 flags; u8 ttl; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 76798e8057f7..53c4764dc1ed 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,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 */ #include @@ -1251,8 +1251,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - u16 sc = le16_to_cpu(hdr->seq_ctrl); - u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; + u16 mpdu_seq_num = ieee80211_get_sn(hdr); u16 head_seq_num, buf_size; int index; bool ret = true; From 676259100cf3a81dd2d47918b36edb237986b9df Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:04:57 +0100 Subject: [PATCH 0918/2255] wifi: mac80211: implement MLO multicast deduplication If the vif is an MLD then it may receive multicast from different links, and should drop those frames according to the SN. Implement that. Link: https://msgid.link/20240129200456.693b77d14b44.I491846f2bea0058c14eab6422962c10bfae9b675@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 5 +++++ net/mac80211/ieee80211_i.h | 4 +++- net/mac80211/mlme.c | 3 +++ net/mac80211/rx.c | 22 ++++++++++++++++++++-- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b9367d5f04c4..e9078143b822 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -191,6 +191,11 @@ static inline bool ieee80211_sn_less(u16 sn1, u16 sn2) return ((sn1 - sn2) & IEEE80211_SN_MASK) > (IEEE80211_SN_MODULO >> 1); } +static inline bool ieee80211_sn_less_eq(u16 sn1, u16 sn2) +{ + return ((sn2 - sn1) & IEEE80211_SN_MASK) <= (IEEE80211_SN_MODULO >> 1); +} + static inline u16 ieee80211_sn_add(u16 sn1, u16 sn2) { return (sn1 + sn2) & IEEE80211_SN_MASK; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 534cac3fc8df..46b517cf47ea 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007-2010 Johannes Berg * Copyright 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef IEEE80211_I_H @@ -523,6 +523,8 @@ struct ieee80211_if_managed { unsigned int flags; + u16 mcast_seq_last; + bool status_acked; bool status_received; __le16 status_fc; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4eaf5c10efdb..35dda5982854 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3351,6 +3351,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->neg_ttlm_timeout_work); ieee80211_vif_set_links(sdata, 0, 0); + + ifmgd->mcast_seq_last = IEEE80211_SN_MODULO; } static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) @@ -7512,6 +7514,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) spin_lock_init(&ifmgd->teardown_lock); ifmgd->teardown_skb = NULL; ifmgd->orig_teardown_skb = NULL; + ifmgd->mcast_seq_last = IEEE80211_SN_MODULO; } static void ieee80211_recalc_smps_work(struct wiphy *wiphy, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 53c4764dc1ed..9902ea69af0a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1434,13 +1434,31 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (ieee80211_is_ctl(hdr->frame_control) || - ieee80211_is_any_nullfunc(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1)) + ieee80211_is_any_nullfunc(hdr->frame_control)) return RX_CONTINUE; if (!rx->sta) return RX_CONTINUE; + if (unlikely(is_multicast_ether_addr(hdr->addr1))) { + struct ieee80211_sub_if_data *sdata = rx->sdata; + u16 sn = ieee80211_get_sn(hdr); + + if (!ieee80211_is_data_present(hdr->frame_control)) + return RX_CONTINUE; + + if (!ieee80211_vif_is_mld(&sdata->vif) || + sdata->vif.type != NL80211_IFTYPE_STATION) + return RX_CONTINUE; + + if (sdata->u.mgd.mcast_seq_last != IEEE80211_SN_MODULO && + ieee80211_sn_less_eq(sn, sdata->u.mgd.mcast_seq_last)) + return RX_DROP_U_DUP; + + sdata->u.mgd.mcast_seq_last = sn; + return RX_CONTINUE; + } + if (unlikely(ieee80211_has_retry(hdr->frame_control) && rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) { I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount); From 3552a22880eed3e834a33d02aec6800974bb42b4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:06:53 +0100 Subject: [PATCH 0919/2255] wifi: mac80211: disambiguate element parsing errors Let the element parsing function return what kind of error was encountered, as a bitmap, even if nothing currently checks for which specific error it was, we'll use it later. Link: https://msgid.link/20240129200652.1a69f2a31ec7.I55b86561d64e7ef1504c73f6f2813c33030c8136@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 11 +++- net/mac80211/util.c | 108 ++++++++++++++++++++++++------------- 2 files changed, 81 insertions(+), 38 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 46b517cf47ea..f5fe659a1efd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1666,6 +1666,13 @@ struct ieee80211_csa_ie { u32 max_switch_time; }; +enum ieee80211_elems_parse_error { + IEEE80211_PARSE_ERR_INVALID_END = BIT(0), + IEEE80211_PARSE_ERR_DUP_ELEM = BIT(1), + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE = BIT(2), + IEEE80211_PARSE_ERR_UNEXPECTED_ELEM = BIT(3), +}; + /* Parsed Information Elements */ struct ieee802_11_elems { const u8 *ie_start; @@ -1776,8 +1783,8 @@ struct ieee802_11_elems { struct ieee80211_mle_per_sta_profile *prof; size_t sta_prof_len; - /* whether a parse error occurred while retrieving these elements */ - bool parse_error; + /* whether/which parse error occurred while retrieving these elements */ + u8 parse_error; /* * scratch buffer that can be used for various element parsing related diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5108dbaa9360..c1fa762f0cba 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1063,7 +1063,7 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, for_each_element(elem, params->start, params->len) { const struct element *subelem; - bool elem_parse_failed; + u8 elem_parse_failed; u8 id = elem->id; u8 elen = elem->datalen; const u8 *pos = elem->data; @@ -1119,7 +1119,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, * that if the content gets bigger it might be needed more than once */ if (test_bit(id, seen_elems)) { - elems->parse_error = true; + elems->parse_error |= + IEEE80211_PARSE_ERR_DUP_ELEM; continue; } break; @@ -1128,19 +1129,21 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (calc_crc && id < 64 && (params->filter & (1ULL << id))) crc = crc32_be(crc, pos - 2, elen + 2); - elem_parse_failed = false; + elem_parse_failed = 0; switch (id) { case WLAN_EID_LINK_ID: if (elen + 2 < sizeof(struct ieee80211_tdls_lnkie)) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->lnk_id = (void *)(pos - 2); break; case WLAN_EID_CHAN_SWITCH_TIMING: if (elen < sizeof(struct ieee80211_ch_switch_timing)) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->ch_sw_timing = (void *)pos; @@ -1161,14 +1164,16 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= 1) elems->ds_params = pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_TIM: if (elen >= sizeof(struct ieee80211_tim_ie)) { elems->tim = (void *)pos; elems->tim_len = elen; } else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_VENDOR_SPECIFIC: if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && @@ -1198,7 +1203,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= 1) elems->erp_info = pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_EXT_SUPP_RATES: elems->ext_supp_rates = pos; @@ -1210,7 +1216,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= sizeof(struct ieee80211_ht_cap)) elems->ht_cap_elem = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_HT_OPERATION: if (params->mode < IEEE80211_CONN_MODE_HT) @@ -1218,7 +1225,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= sizeof(struct ieee80211_ht_operation)) elems->ht_operation = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_VHT_CAPABILITY: if (params->mode < IEEE80211_CONN_MODE_VHT) @@ -1226,7 +1234,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= sizeof(struct ieee80211_vht_cap)) elems->vht_cap_elem = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_VHT_OPERATION: if (params->mode < IEEE80211_CONN_MODE_VHT) @@ -1237,7 +1246,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, crc = crc32_be(crc, pos - 2, elen + 2); break; } - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_OPMODE_NOTIF: if (params->mode < IEEE80211_CONN_MODE_VHT) @@ -1248,7 +1258,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, crc = crc32_be(crc, pos - 2, elen + 2); break; } - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_MESH_ID: elems->mesh_id = pos; @@ -1258,7 +1269,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= sizeof(struct ieee80211_meshconf_ie)) elems->mesh_config = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_PEER_MGMT: elems->peering = pos; @@ -1284,18 +1296,21 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= sizeof(struct ieee80211_rann_ie)) elems->rann = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_CHANNEL_SWITCH: if (elen != sizeof(struct ieee80211_channel_sw_ie)) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->ch_switch_ie = (void *)pos; break; case WLAN_EID_EXT_CHANSWITCH_ANN: if (elen != sizeof(struct ieee80211_ext_chansw_ie)) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->ext_chansw_ie = (void *)pos; @@ -1304,7 +1319,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (params->mode < IEEE80211_CONN_MODE_HT) break; if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->sec_chan_offs = (void *)pos; @@ -1312,7 +1328,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, case WLAN_EID_CHAN_SWITCH_PARAM: if (elen < sizeof(*elems->mesh_chansw_params_ie)) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->mesh_chansw_params_ie = (void *)pos; @@ -1320,9 +1337,16 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: if (params->mode < IEEE80211_CONN_MODE_VHT) break; - if (!params->action || - elen < sizeof(*elems->wide_bw_chansw_ie)) { - elem_parse_failed = true; + + if (!params->action) { + elem_parse_failed = + IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; + break; + } + + if (elen < sizeof(*elems->wide_bw_chansw_ie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->wide_bw_chansw_ie = (void *)pos; @@ -1331,7 +1355,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (params->mode < IEEE80211_CONN_MODE_VHT) break; if (params->action) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; break; } /* @@ -1345,7 +1370,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->wide_bw_chansw_ie = (void *)subelem->data; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; } if (params->mode < IEEE80211_CONN_MODE_EHT) @@ -1361,7 +1387,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, edatalen)) elems->bandwidth_indication = edata; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; } break; case WLAN_EID_COUNTRY: @@ -1370,7 +1397,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, break; case WLAN_EID_PWR_CONSTRAINT: if (elen != 1) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->pwr_constr_elem = pos; @@ -1382,7 +1410,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, * tag (0x00). */ if (elen < 4) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } @@ -1391,7 +1420,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, break; if (elen != 6) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } @@ -1402,7 +1432,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, break; case WLAN_EID_ADDBA_EXT: if (elen < sizeof(struct ieee80211_addba_ext_ie)) { - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; } elems->addba_ext_ie = (void *)pos; @@ -1411,7 +1442,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= sizeof(struct ieee80211_timeout_interval_ie)) elems->timeout_int = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_BSS_MAX_IDLE_PERIOD: if (elen >= sizeof(*elems->max_idle_period_ie)) @@ -1444,7 +1476,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen >= sizeof(*elems->s1g_capab)) elems->s1g_capab = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_S1G_OPERATION: if (params->mode != IEEE80211_CONN_MODE_S1G) @@ -1452,7 +1485,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen == sizeof(*elems->s1g_oper)) elems->s1g_oper = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_S1G_BCN_COMPAT: if (params->mode != IEEE80211_CONN_MODE_S1G) @@ -1460,7 +1494,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen == sizeof(*elems->s1g_bcn_compat)) elems->s1g_bcn_compat = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_AID_RESPONSE: if (params->mode != IEEE80211_CONN_MODE_S1G) @@ -1468,20 +1503,21 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, if (elen == sizeof(struct ieee80211_aid_response_ie)) elems->aid_resp = (void *)pos; else - elem_parse_failed = true; + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; default: break; } if (elem_parse_failed) - elems->parse_error = true; + elems->parse_error |= elem_parse_failed; else __set_bit(id, seen_elems); } if (!for_each_element_completed(elem, params->start, params->len)) - elems->parse_error = true; + elems->parse_error |= IEEE80211_PARSE_ERR_INVALID_END; return crc; } From a57944d1ee8bf29cbdf7d6b8e9579d88bf912c3e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:06:54 +0100 Subject: [PATCH 0920/2255] wifi: mac80211: disallow basic multi-link element in per-STA profile There really shouldn't be a basic multi-link element in any per-STA profile in an association response, it's not clear what that would really mean. Refuse connecting in this case since the AP isn't following the spec. Link: https://msgid.link/20240129200652.23f1e3b337f1.Idd2e43cdbfe3ba15b3e9b8aeb54c8115587177a0@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 3 ++- net/mac80211/util.c | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f5fe659a1efd..e11297b4dc63 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1671,6 +1671,7 @@ enum ieee80211_elems_parse_error { IEEE80211_PARSE_ERR_DUP_ELEM = BIT(1), IEEE80211_PARSE_ERR_BAD_ELEM_SIZE = BIT(2), IEEE80211_PARSE_ERR_UNEXPECTED_ELEM = BIT(3), + IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC = BIT(4), }; /* Parsed Information Elements */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 35dda5982854..9a0331d914d3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4304,7 +4304,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, link->u.mgd.bss_param_ch_cnt = ieee80211_mle_get_bss_param_ch_cnt(elems->ml_basic); } - } else if (!elems->prof || + } else if (elems->parse_error & IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC || + !elems->prof || !(elems->prof->control & prof_bss_param_ch_present)) { ret = false; goto out; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c1fa762f0cba..d85a9c5cde26 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1012,6 +1012,11 @@ ieee80211_parse_extension_element(u32 *crc, switch (le16_get_bits(mle->control, IEEE80211_ML_CONTROL_TYPE)) { case IEEE80211_ML_CONTROL_TYPE_BASIC: + if (elems->ml_basic) { + elems->parse_error |= + IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC; + break; + } elems->ml_basic_elem = (void *)elem; elems->ml_basic = data; elems->ml_basic_len = len; From 90233160d761e4ea56c7ac30e36fdaec73b3bdc4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:27 +0100 Subject: [PATCH 0921/2255] wifi: mac80211: simplify HE/EHT element length functions We don't need to pass the iftype there, we already have it in the sdata. Simplify this code. Link: https://msgid.link/20240129202041.5890eb1d4184.Ibce7e5abcc7887630da03ac2263d8004ec541418@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 4 ++-- net/mac80211/mesh.c | 8 +++----- net/mac80211/mesh_plink.c | 8 +++----- net/mac80211/util.c | 15 ++++++++------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e11297b4dc63..44400ce9a0b1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2502,7 +2502,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, u32 cap); u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, const struct cfg80211_chan_def *chandef); -u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype); +u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata); u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, const struct ieee80211_sta_he_cap *he_cap, u8 *pos, u8 *end); @@ -2651,7 +2651,7 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache); void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache); -u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype); +u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata); u8 *ieee80211_ie_build_eht_cap(u8 *pos, const struct ieee80211_sta_he_cap *he_cap, const struct ieee80211_sta_eht_cap *eht_cap, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index e06d9ed2d31b..9fd209e4ca19 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2018 - 2023 Intel Corporation + * Copyright (C) 2018 - 2024 Intel Corporation * Authors: Luis Carlos Cobo * Javier Cardona */ @@ -981,10 +981,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) band = chanctx_conf->def.chan->band; rcu_read_unlock(); - ie_len_he_cap = ieee80211_ie_len_he_cap(sdata, - NL80211_IFTYPE_MESH_POINT); - ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata, - NL80211_IFTYPE_MESH_POINT); + ie_len_he_cap = ieee80211_ie_len_he_cap(sdata); + ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata); head_len = hdr_len + 2 + /* NULL SSID */ /* Channel Switch Announcement */ diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e3aad60f68ab..7ba0f01805a4 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2019, 2021-2023 Intel Corporation + * Copyright (C) 2019, 2021-2024 Intel Corporation * Author: Luis Carlos Cobo */ #include @@ -226,10 +226,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot); int err = -ENOMEM; - ie_len_he_cap = ieee80211_ie_len_he_cap(sdata, - NL80211_IFTYPE_MESH_POINT); - ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata, - NL80211_IFTYPE_MESH_POINT); + ie_len_he_cap = ieee80211_ie_len_he_cap(sdata); + ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata); skb = dev_alloc_skb(local->tx_headroom + hdr_len + 2 + /* capability info */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d85a9c5cde26..e9a7978d47d4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3272,7 +3272,8 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, return pos; } -u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype) +/* this may return more than ieee80211_ie_build_he_cap() will need */ +u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata) { const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_supported_band *sband; @@ -3282,7 +3283,7 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype) if (!sband) return 0; - he_cap = ieee80211_get_he_iftype_cap(sband, iftype); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); if (!he_cap) return 0; @@ -5065,7 +5066,8 @@ u16 ieee80211_encode_usf(int listen_interval) return (u16) listen_interval; } -u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype) +/* this may return more than ieee80211_ie_build_eht_cap() will need */ +u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata) { const struct ieee80211_sta_he_cap *he_cap; const struct ieee80211_sta_eht_cap *eht_cap; @@ -5077,13 +5079,12 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype) if (!sband) return 0; - he_cap = ieee80211_get_he_iftype_cap(sband, iftype); - eht_cap = ieee80211_get_eht_iftype_cap(sband, iftype); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); if (!he_cap || !eht_cap) return 0; - is_ap = iftype == NL80211_IFTYPE_AP || - iftype == NL80211_IFTYPE_P2P_GO; + is_ap = sdata->vif.type == NL80211_IFTYPE_AP; n = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, &eht_cap->eht_cap_elem, From 6239da18d2f947523a80fb1f85f8d8a13d1726c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:28 +0100 Subject: [PATCH 0922/2255] wifi: mac80211: adjust EHT capa when lowering bandwidth If intending to associate with a lower bandwidth, remove capabilities related to 320 MHz from the EHT capabilities element. Also change the EHT MCS-NSS set accordingly: if just reducing 320->160 or similar the format doesn't change, just cut off the last bytes. If changing from higher bandwidth to 20 MHz only EHT STA, adjust the format. Note that this also requires adjusting the caller in mlme.c since the data written can now be shorter than it determined. We need to clean all that up. Since the other callers pass NULL for the conn limit, we don't need to change things there. Link: https://msgid.link/20240129202041.b5f6df108c77.I0d8ea04079c61cb3744cc88625eeaf0d4776dc2b@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 3 + net/mac80211/ieee80211_i.h | 3 +- net/mac80211/mesh.c | 3 +- net/mac80211/mlme.c | 15 +++-- net/mac80211/tdls.c | 5 +- net/mac80211/util.c | 114 ++++++++++++++++++++++++++++--------- 6 files changed, 106 insertions(+), 37 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e9078143b822..e4322238f273 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -3060,6 +3060,9 @@ ieee80211_he_spr_size(const u8 *he_spr_ie) #define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40 #define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07 +#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x08 +#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x30 +#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ 0x40 #define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78 #define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x80 diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 44400ce9a0b1..43c55ea6349c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2652,7 +2652,8 @@ void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache); void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache); u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata); -u8 *ieee80211_ie_build_eht_cap(u8 *pos, +u8 *ieee80211_ie_build_eht_cap(const struct ieee80211_conn_settings *conn, + u8 *pos, const struct ieee80211_sta_he_cap *he_cap, const struct ieee80211_sta_eht_cap *eht_cap, u8 *end, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9fd209e4ca19..000fa9484b4e 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -668,7 +668,8 @@ int mesh_add_eht_cap_ie(struct ieee80211_sub_if_data *sdata, return -ENOMEM; pos = skb_put(skb, ie_len); - ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + ie_len, false); + ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap, pos + ie_len, + false); return 0; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9a0331d914d3..bbc7894ccad0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1072,9 +1072,10 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_supported_band *sband) + struct ieee80211_supported_band *sband, + const struct ieee80211_conn_settings *conn) { - u8 *pos; + u8 *pos, *pre_eht_pos; const struct ieee80211_sta_he_cap *he_cap; const struct ieee80211_sta_eht_cap *eht_cap; u8 eht_cap_size; @@ -1097,8 +1098,11 @@ static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], eht_cap->eht_cap_elem.phy_cap_info); pos = skb_put(skb, eht_cap_size); - ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size, - false); + pre_eht_pos = pos; + pos = ieee80211_ie_build_eht_cap(conn, pos, he_cap, eht_cap, + pos + eht_cap_size, false); + /* trim excess if any */ + skb_trim(skb, skb->len - (pre_eht_pos + eht_cap_size - pos)); } static void ieee80211_assoc_add_rates(struct sk_buff *skb, @@ -1453,7 +1457,8 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, present_elems = NULL; if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_EHT) - ieee80211_add_eht_ie(sdata, skb, sband); + ieee80211_add_eht_ie(sdata, skb, sband, + &assoc_data->link[link_id].conn); if (sband->band == NL80211_BAND_S1GHZ) { ieee80211_add_aid_request_ie(sdata, skb); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 0f4aa42e070f..57673f27daf4 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -6,7 +6,7 @@ * Copyright 2014, Intel Corporation * Copyright 2014 Intel Mobile Communications GmbH * Copyright 2015 - 2016 Intel Deutschland GmbH - * Copyright (C) 2019, 2021-2023 Intel Corporation + * Copyright (C) 2019, 2021-2024 Intel Corporation */ #include @@ -604,7 +604,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], eht_cap->eht_cap_elem.phy_cap_info); pos = skb_put(skb, cap_size); - ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + cap_size, false); + ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap, + pos + cap_size, false); } /* add any remaining IEs */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e9a7978d47d4..5224c22b1afc 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2250,7 +2250,8 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE | IEEE80211_CHAN_NO_EHT)) { - pos = ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, end, + pos = ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap, + end, sdata->vif.type == NL80211_IFTYPE_AP); if (!pos) goto out_err; @@ -3294,6 +3295,24 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata) he_cap->he_cap_elem.phy_cap_info); } +static void +ieee80211_get_adjusted_he_cap(const struct ieee80211_conn_settings *conn, + const struct ieee80211_sta_he_cap *he_cap, + struct ieee80211_he_cap_elem *elem) +{ + *elem = he_cap->he_cap_elem; + + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) + elem->phy_cap_info[0] &= + ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G); + + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160) + elem->phy_cap_info[0] &= + ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G); +} + u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, const struct ieee80211_sta_he_cap *he_cap, u8 *pos, u8 *end) @@ -3307,25 +3326,11 @@ u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, conn = &ieee80211_conn_settings_unlimited; /* Make sure we have place for the IE */ - /* - * TODO: the 1 added is because this temporarily is under the EXTENSION - * IE. Get rid of it when it moves. - */ if (!he_cap) return orig_pos; /* modify on stack first to calculate 'n' and 'ie_len' correctly */ - elem = he_cap->he_cap_elem; - - if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) - elem.phy_cap_info[0] &= - ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G); - - if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160) - elem.phy_cap_info[0] &= - ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G); + ieee80211_get_adjusted_he_cap(conn, he_cap, &elem); n = ieee80211_he_mcs_nss_size(&elem); ie_len = 2 + 1 + @@ -5096,25 +5101,65 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata) return 0; } -u8 *ieee80211_ie_build_eht_cap(u8 *pos, +u8 *ieee80211_ie_build_eht_cap(const struct ieee80211_conn_settings *conn, + u8 *pos, const struct ieee80211_sta_he_cap *he_cap, const struct ieee80211_sta_eht_cap *eht_cap, - u8 *end, - bool for_ap) + u8 *end, bool for_ap) { + struct ieee80211_eht_cap_elem_fixed fixed, *out; + struct ieee80211_he_cap_elem he; u8 mcs_nss_len, ppet_len; + u8 orig_mcs_nss_len; u8 ie_len; u8 *orig_pos = pos; + if (!conn) + conn = &ieee80211_conn_settings_unlimited; + /* Make sure we have place for the IE */ if (!he_cap || !eht_cap) return orig_pos; - mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, - &eht_cap->eht_cap_elem, - for_ap); + orig_mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, + &eht_cap->eht_cap_elem, + for_ap); + + ieee80211_get_adjusted_he_cap(conn, he_cap, &he); + + fixed = eht_cap->eht_cap_elem; + + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_80) + fixed.phy_cap_info[6] &= + ~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ; + + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160) { + fixed.phy_cap_info[1] &= + ~IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK; + fixed.phy_cap_info[2] &= + ~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK; + fixed.phy_cap_info[6] &= + ~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ; + } + + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320) { + fixed.phy_cap_info[0] &= + ~IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + fixed.phy_cap_info[1] &= + ~IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK; + fixed.phy_cap_info[2] &= + ~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK; + fixed.phy_cap_info[6] &= + ~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ; + } + + if (conn->bw_limit == IEEE80211_CONN_BW_LIMIT_20) + fixed.phy_cap_info[0] &= + ~IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ; + + mcs_nss_len = ieee80211_eht_mcs_nss_size(&he, &fixed, for_ap); ppet_len = ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], - eht_cap->eht_cap_elem.phy_cap_info); + fixed.phy_cap_info); ie_len = 2 + 1 + sizeof(eht_cap->eht_cap_elem) + mcs_nss_len + ppet_len; if ((end - pos) < ie_len) @@ -5124,12 +5169,25 @@ u8 *ieee80211_ie_build_eht_cap(u8 *pos, *pos++ = ie_len - 2; *pos++ = WLAN_EID_EXT_EHT_CAPABILITY; - /* Fixed data */ - memcpy(pos, &eht_cap->eht_cap_elem, sizeof(eht_cap->eht_cap_elem)); - pos += sizeof(eht_cap->eht_cap_elem); + out = (void *)pos; + *out = fixed; + pos += sizeof(*out); - memcpy(pos, &eht_cap->eht_mcs_nss_supp, mcs_nss_len); - pos += mcs_nss_len; + if (mcs_nss_len == 4 && orig_mcs_nss_len != 4) { + /* + * If the (non-AP) STA became 20 MHz only, then convert from + * <=80 to 20-MHz-only format, where MCSes are indicated in + * the groups 0-7, 8-9, 10-11, 12-13 rather than just 0-9, + * 10-11, 12-13. Thus, use 0-9 for 0-7 and 8-9. + */ + *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs9_max_nss; + *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs9_max_nss; + *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs11_max_nss; + *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs13_max_nss; + } else { + memcpy(pos, &eht_cap->eht_mcs_nss_supp, mcs_nss_len); + pos += mcs_nss_len; + } if (ppet_len) { memcpy(pos, &eht_cap->eht_ppe_thres, ppet_len); From 06b4c8665dcff32f50153fd4cddc4b05f31569a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:29 +0100 Subject: [PATCH 0923/2255] wifi: mac80211: limit HE RU capabilities when limiting bandwidth When limiting a station's supported bandwidth while connecting, also limit various other HE capabilities according to the bandwidth needed for them. Link: https://msgid.link/20240129202041.34be99efca25.I02a695961bc6aadd37768b17c50fcdec4427d460@changeid Signed-off-by: Johannes Berg --- net/mac80211/util.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5224c22b1afc..c2fe9aece00d 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3300,17 +3300,48 @@ ieee80211_get_adjusted_he_cap(const struct ieee80211_conn_settings *conn, const struct ieee80211_sta_he_cap *he_cap, struct ieee80211_he_cap_elem *elem) { + u8 ru_limit, max_ru; + *elem = he_cap->he_cap_elem; - if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) + switch (conn->bw_limit) { + case IEEE80211_CONN_BW_LIMIT_20: + ru_limit = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242; + break; + case IEEE80211_CONN_BW_LIMIT_40: + ru_limit = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; + break; + case IEEE80211_CONN_BW_LIMIT_80: + ru_limit = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996; + break; + default: + ru_limit = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996; + break; + } + + max_ru = elem->phy_cap_info[8] & IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK; + max_ru = min(max_ru, ru_limit); + elem->phy_cap_info[8] &= ~IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK; + elem->phy_cap_info[8] |= max_ru; + + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) { elem->phy_cap_info[0] &= ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G); + elem->phy_cap_info[9] &= + ~IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM; + } - if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160) + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160) { elem->phy_cap_info[0] &= ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G); + elem->phy_cap_info[5] &= + ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; + elem->phy_cap_info[7] &= + ~(IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ); + } } u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, From 552a26b3854e12d73ab0527ee0d46454a2e650fb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:30 +0100 Subject: [PATCH 0924/2255] wifi: mac80211: rename ieee80211_ie_build_he_6ghz_cap() The term 'IE' isn't really in use in the spec, and I want to rework all of this to use SKBs as the primary method for building elements. Rename this one already. Link: https://msgid.link/20240129202041.b8064a4e73b5.I8d2f4526562029107c6414c6cda378b300b1b0b0@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 8 +++++--- net/mac80211/mesh.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/util.c | 6 +++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 43c55ea6349c..2b5d49399500 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2506,9 +2506,6 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata); u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, const struct ieee80211_sta_he_cap *he_cap, u8 *pos, u8 *end); -void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps_mode, - struct sk_buff *skb); u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef); u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef, const struct ieee80211_sta_eht_cap *eht_cap); @@ -2529,6 +2526,11 @@ void ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap); +/* element building in SKBs */ +void ieee80211_put_he_6ghz_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps_mode); + /* channel management */ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, struct cfg80211_chan_def *chandef); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 000fa9484b4e..10c7d7714ffe 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -640,7 +640,7 @@ int mesh_add_he_6ghz_cap_ie(struct ieee80211_sub_if_data *sdata, if (!iftd) return 0; - ieee80211_ie_build_he_6ghz_cap(sdata, sdata->deflink.smps_mode, skb); + ieee80211_put_he_6ghz_cap(skb, sdata, sdata->deflink.smps_mode); return 0; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bbc7894ccad0..74a6c67a94da 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1067,7 +1067,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, /* trim excess if any */ skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos)); - ieee80211_ie_build_he_6ghz_cap(sdata, smps_mode, skb); + ieee80211_put_he_6ghz_cap(skb, sdata, smps_mode); } static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c2fe9aece00d..e8de82bafeef 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3413,9 +3413,9 @@ end: return pos; } -void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps_mode, - struct sk_buff *skb) +void ieee80211_put_he_6ghz_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps_mode) { struct ieee80211_supported_band *sband; const struct ieee80211_sband_iftype_data *iftd; From e0b5ee918723dcf47d3773bc95cbcb428436f817 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:31 +0100 Subject: [PATCH 0925/2255] wifi: mac80211: tdls: use ieee80211_put_he_6ghz_cap() We don't need to use the write function here since we already have an SKB, so use ieee80211_put_he_6ghz_cap() with the SMPS mode taken from the link we're using. Link: https://msgid.link/20240129202041.6454ac78ff8c.I7152e3c27645105478c68d40ca493feb27cac6bf@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/tdls.c | 11 ++--------- net/mac80211/util.c | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2b5d49399500..f7b2381878a9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2457,7 +2457,6 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *da, const u8 *bssid, u16 stype, u16 reason, bool send_frame, u8 *frame_buf); -u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end); enum { IEEE80211_PROBE_FLAG_DIRECTED = BIT(0), diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 57673f27daf4..e6808b7660ff 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -552,7 +552,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, (action_code == WLAN_TDLS_SETUP_REQUEST || action_code == WLAN_TDLS_SETUP_RESPONSE || action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) { - __le16 he_6ghz_capa; u8 cap_size; cap_size = @@ -564,14 +563,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, pos + cap_size); /* Build HE 6Ghz capa IE from sband */ - if (sband->band == NL80211_BAND_6GHZ) { - cap_size = 2 + 1 + sizeof(struct ieee80211_he_6ghz_capa); - pos = skb_put(skb, cap_size); - he_6ghz_capa = - ieee80211_get_he_6ghz_capa_vif(sband, &sdata->vif); - pos = ieee80211_write_he_6ghz_cap(pos, he_6ghz_capa, - pos + cap_size); - } + if (sband->band == NL80211_BAND_6GHZ) + ieee80211_put_he_6ghz_cap(skb, sdata, link->smps_mode); } /* add any custom IEs that go before EHT capabilities */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e8de82bafeef..c90f338b229c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2035,7 +2035,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, } } -u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end) +static u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end) { if ((end - pos) < 5) return pos; From 147ceae2053402cbbe543944abf3a8494ef76895 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:32 +0100 Subject: [PATCH 0926/2255] wifi: mac80211: simplify adding supported rates Make this a new-style "put" function, and change the parameters to pass more information directly, this makes it usable also for the MLME code. Link: https://msgid.link/20240129202041.f604a03bd728.I8c798ea45b8479ac9982e77d0378af11a09ccdaf@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 10 ++-- net/mac80211/mesh.c | 20 ++++--- net/mac80211/mesh_plink.c | 16 ++++-- net/mac80211/mlme.c | 53 ++++-------------- net/mac80211/tdls.c | 4 +- net/mac80211/util.c | 109 +++++++++++++------------------------ 6 files changed, 79 insertions(+), 133 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f7b2381878a9..b69f081e1c1f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2511,12 +2511,6 @@ u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef, int ieee80211_parse_bitrates(enum nl80211_chan_width width, const struct ieee80211_supported_band *sband, const u8 *srates, int srates_len, u32 *rates); -int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic, - enum nl80211_band band); -int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic, - enum nl80211_band band); u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); void ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta_s1g_cap *caps, @@ -2526,6 +2520,10 @@ void ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata, u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap); /* element building in SKBs */ +int ieee80211_put_srates_elem(struct sk_buff *skb, + const struct ieee80211_supported_band *sband, + u32 basic_rates, u32 rate_flags, u32 masked_rates, + u8 element_id); void ieee80211_put_he_6ghz_cap(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode smps_mode); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 10c7d7714ffe..7e860486c6bc 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -968,19 +968,19 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) int head_len, tail_len; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - struct ieee80211_chanctx_conf *chanctx_conf; struct mesh_csa_settings *csa; - enum nl80211_band band; + const struct ieee80211_supported_band *sband; u8 ie_len_he_cap, ie_len_eht_cap; u8 *pos; struct ieee80211_sub_if_data *sdata; int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon); + u32 rate_flags; sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); - band = chanctx_conf->def.chan->band; - rcu_read_unlock(); + + sband = ieee80211_get_sband(sdata); + rate_flags = + ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper); ie_len_he_cap = ieee80211_ie_len_he_cap(sdata); ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata); @@ -1107,7 +1107,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) } rcu_read_unlock(); - if (ieee80211_add_srates_ie(sdata, skb, true, band) || + if (ieee80211_put_srates_elem(skb, sband, + sdata->vif.bss_conf.basic_rates, + rate_flags, 0, WLAN_EID_SUPP_RATES) || mesh_add_ds_params_ie(sdata, skb)) goto out_free; @@ -1118,7 +1120,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) skb_trim(skb, 0); bcn->tail = bcn->head + bcn->head_len; - if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) || + if (ieee80211_put_srates_elem(skb, sband, + sdata->vif.bss_conf.basic_rates, + rate_flags, 0, WLAN_EID_EXT_SUPP_RATES) || mesh_add_rsn_ie(sdata, skb) || mesh_add_ht_cap_ie(sdata, skb) || mesh_add_ht_oper_ie(sdata, skb) || diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 7ba0f01805a4..8f2b492a9fe9 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -264,14 +264,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, if (action != WLAN_SP_MESH_PEERING_CLOSE) { struct ieee80211_supported_band *sband; - enum nl80211_band band; + u32 rate_flags, basic_rates; sband = ieee80211_get_sband(sdata); if (!sband) { err = -EINVAL; goto free; } - band = sband->band; /* capability info */ pos = skb_put_zero(skb, 2); @@ -280,8 +279,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2); put_unaligned_le16(sta->sta.aid, pos); } - if (ieee80211_add_srates_ie(sdata, skb, true, band) || - ieee80211_add_ext_srates_ie(sdata, skb, true, band) || + + rate_flags = + ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper); + basic_rates = sdata->vif.bss_conf.basic_rates; + + if (ieee80211_put_srates_elem(skb, sband, basic_rates, + rate_flags, 0, + WLAN_EID_SUPP_RATES) || + ieee80211_put_srates_elem(skb, sband, basic_rates, + rate_flags, 0, + WLAN_EID_EXT_SUPP_RATES) || mesh_add_rsn_ie(sdata, skb) || mesh_add_meshid_ie(sdata, skb) || mesh_add_meshconf_ie(sdata, skb)) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 74a6c67a94da..d807a904419c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1110,10 +1110,7 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb, struct ieee80211_supported_band *sband, struct ieee80211_mgd_assoc_data *assoc_data) { - unsigned int rates_len, supp_rates_len; - u32 rates = 0; - int i, count; - u8 *pos; + u32 rates; if (assoc_data->supp_rates_len) { /* @@ -1122,53 +1119,23 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb, * in the association request (e.g. D-Link DAP 1353 in * b-only mode)... */ - rates_len = ieee80211_parse_bitrates(width, sband, - assoc_data->supp_rates, - assoc_data->supp_rates_len, - &rates); + ieee80211_parse_bitrates(width, sband, + assoc_data->supp_rates, + assoc_data->supp_rates_len, + &rates); } else { /* * In case AP not provide any supported rates information * before association, we send information element(s) with * all rates that we support. */ - rates_len = sband->n_bitrates; - for (i = 0; i < sband->n_bitrates; i++) - rates |= BIT(i); + rates = ~0; } - supp_rates_len = rates_len; - if (supp_rates_len > 8) - supp_rates_len = 8; - - pos = skb_put(skb, supp_rates_len + 2); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = supp_rates_len; - - count = 0; - for (i = 0; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5); - *pos++ = (u8)rate; - if (++count == 8) - break; - } - } - - if (rates_len > count) { - pos = skb_put(skb, rates_len - count + 2); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates_len - count; - - for (i++; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate; - - rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5); - *pos++ = (u8)rate; - } - } - } + ieee80211_put_srates_elem(skb, sband, 0, 0, ~rates, + WLAN_EID_SUPP_RATES); + ieee80211_put_srates_elem(skb, sband, 0, 0, ~rates, + WLAN_EID_EXT_SUPP_RATES); } static size_t ieee80211_add_before_ht_elems(struct sk_buff *skb, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index e6808b7660ff..edbd3fd8a737 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -382,8 +382,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, if (WARN_ON_ONCE(!sband)) return; - ieee80211_add_srates_ie(sdata, skb, false, sband->band); - ieee80211_add_ext_srates_ie(sdata, skb, false, sband->band); + ieee80211_put_srates_elem(skb, sband, 0, 0, 0, WLAN_EID_SUPP_RATES); + ieee80211_put_srates_elem(skb, sband, 0, 0, 0, WLAN_EID_EXT_SUPP_RATES); ieee80211_tdls_add_supp_channels(sdata, skb); /* add any custom IEs that go before Extended Capabilities */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c90f338b229c..3888ad3b052f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -4091,93 +4091,62 @@ int ieee80211_parse_bitrates(enum nl80211_chan_width width, return count; } -int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic, - enum nl80211_band band) +int ieee80211_put_srates_elem(struct sk_buff *skb, + const struct ieee80211_supported_band *sband, + u32 basic_rates, u32 rate_flags, u32 masked_rates, + u8 element_id) { - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; - int rate; - u8 i, rates, *pos; - u32 basic_rates = sdata->vif.bss_conf.basic_rates; - u32 rate_flags; + u8 i, rates, skip; - 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++) { if ((rate_flags & sband->bitrates[i].flags) != rate_flags) continue; + if (masked_rates & BIT(i)) + continue; rates++; } - if (rates > 8) - rates = 8; + + if (element_id == WLAN_EID_SUPP_RATES) { + rates = min_t(u8, rates, 8); + skip = 0; + } else { + skip = 8; + if (rates <= skip) + return 0; + rates -= skip; + } if (skb_tailroom(skb) < rates + 2) - return -ENOMEM; + return -ENOBUFS; + + skb_put_u8(skb, element_id); + skb_put_u8(skb, rates); + + for (i = 0; i < sband->n_bitrates && rates; i++) { + int rate; + u8 basic; - pos = skb_put(skb, rates + 2); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = rates; - for (i = 0; i < rates; i++) { - u8 basic = 0; if ((rate_flags & sband->bitrates[i].flags) != rate_flags) continue; - - if (need_basic && basic_rates & BIT(i)) - basic = 0x80; - rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5); - *pos++ = basic | (u8) rate; - } - - return 0; -} - -int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic, - enum nl80211_band band) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; - int rate; - u8 i, exrates, *pos; - u32 basic_rates = sdata->vif.bss_conf.basic_rates; - u32 rate_flags; - - 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++) { - if ((rate_flags & sband->bitrates[i].flags) != rate_flags) + if (masked_rates & BIT(i)) continue; - exrates++; - } - if (exrates > 8) - exrates -= 8; - else - exrates = 0; - - if (skb_tailroom(skb) < exrates + 2) - return -ENOMEM; - - if (exrates) { - pos = skb_put(skb, exrates + 2); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = exrates; - for (i = 8; i < sband->n_bitrates; i++) { - u8 basic = 0; - if ((rate_flags & sband->bitrates[i].flags) - != rate_flags) - continue; - if (need_basic && basic_rates & BIT(i)) - basic = 0x80; - rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5); - *pos++ = basic | (u8) rate; + if (skip > 0) { + skip--; + continue; } + + basic = basic_rates & BIT(i) ? 0x80 : 0; + + rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5); + skb_put_u8(skb, basic | (u8)rate); + rates--; } + + WARN(rates > 0, "rates confused: rates:%d, element:%d\n", + rates, element_id); + return 0; } From 07095d167749d49de876613b3567a246d86135a1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:33 +0100 Subject: [PATCH 0927/2255] wifi: mac80211: start building elements in SKBs The building of elements is really mess, and really the only reason we're not doing it in SKBs in the first place is that the scan code in ieee80211_build_preq_ies() doesn't. Convert ieee80211_build_preq_ies() to use an SKB internally so that we can gradually convert other things to ..._put_*() style interfaces. Link: https://msgid.link/20240129202041.c3a8e3c2cc99.I9d9920858c30ae5154719783933de0d7bc2a2cb9@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 7 +- net/mac80211/scan.c | 14 +- net/mac80211/util.c | 357 +++++++++++++++++++------------------ 3 files changed, 191 insertions(+), 187 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b69f081e1c1f..fde8c0b67125 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2517,16 +2517,15 @@ void ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap); /* element building in SKBs */ int ieee80211_put_srates_elem(struct sk_buff *skb, const struct ieee80211_supported_band *sband, u32 basic_rates, u32 rate_flags, u32 masked_rates, u8 element_id); -void ieee80211_put_he_6ghz_cap(struct sk_buff *skb, - struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps_mode); +int ieee80211_put_he_6ghz_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps_mode); /* channel management */ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 6dedbbba153a..bca2a259fda6 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -400,6 +400,8 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_sub_if_data *sdata) req->ie, req->ie_len, bands_used, req->rates, &chandef, flags); + if (ielen < 0) + return false; local->hw_scan_req->req.ie_len = ielen; local->hw_scan_req->req.no_cck = req->no_cck; ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr); @@ -1322,10 +1324,12 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, ieee80211_prepare_scan_chandef(&chandef); - ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz, - &sched_scan_ies, req->ie, - req->ie_len, bands_used, rate_masks, &chandef, - flags); + ret = ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz, + &sched_scan_ies, req->ie, + req->ie_len, bands_used, rate_masks, + &chandef, flags); + if (ret < 0) + goto error; ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); if (ret == 0) { @@ -1333,8 +1337,8 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, rcu_assign_pointer(local->sched_scan_req, req); } +error: kfree(ie); - out: if (ret) { /* Clean in case of failure after HW restart or upon resume. */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3888ad3b052f..ea863d78061e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2035,37 +2035,36 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, } } -static u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end) +static int ieee80211_put_s1g_cap(struct sk_buff *skb, + struct ieee80211_sta_s1g_cap *s1g_cap) { - if ((end - pos) < 5) - return pos; + if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_s1g_cap)) + return -ENOBUFS; - *pos++ = WLAN_EID_EXTENSION; - *pos++ = 1 + sizeof(cap); - *pos++ = WLAN_EID_EXT_HE_6GHZ_CAPA; - memcpy(pos, &cap, sizeof(cap)); + skb_put_u8(skb, WLAN_EID_S1G_CAPABILITIES); + skb_put_u8(skb, sizeof(struct ieee80211_s1g_cap)); - return pos + 2; + skb_put_data(skb, &s1g_cap->cap, sizeof(s1g_cap->cap)); + skb_put_data(skb, &s1g_cap->nss_mcs, sizeof(s1g_cap->nss_mcs)); + + return 0; } -static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, - u8 *buffer, size_t buffer_len, - const u8 *ie, size_t ie_len, - enum nl80211_band band, - u32 rate_mask, - struct cfg80211_chan_def *chandef, - size_t *offset, u32 flags) +static int ieee80211_put_preq_ies_band(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + const u8 *ie, size_t ie_len, + size_t *offset, + enum nl80211_band band, + u32 rate_mask, + struct cfg80211_chan_def *chandef, + u32 flags) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; const struct ieee80211_sta_he_cap *he_cap; const struct ieee80211_sta_eht_cap *eht_cap; - u8 *pos = buffer, *end = buffer + buffer_len; + int i, err; size_t noffset; - int supp_rates_len, i; - u8 rates[32]; - int num_rates; - int ext_rates_len; u32 rate_flags; bool have_80mhz = false; @@ -2078,32 +2077,13 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, rate_flags = ieee80211_chandef_rate_flags(chandef); /* For direct scan add S1G IE and consider its override bits */ - if (band == NL80211_BAND_S1GHZ) { - if (end - pos < 2 + sizeof(struct ieee80211_s1g_cap)) - goto out_err; - pos = ieee80211_ie_build_s1g_cap(pos, &sband->s1g_cap); - goto done; - } + if (band == NL80211_BAND_S1GHZ) + return ieee80211_put_s1g_cap(skb, &sband->s1g_cap); - num_rates = 0; - for (i = 0; i < sband->n_bitrates; i++) { - if ((BIT(i) & rate_mask) == 0) - continue; /* skip rate */ - if ((rate_flags & sband->bitrates[i].flags) != rate_flags) - continue; - - rates[num_rates++] = - (u8) DIV_ROUND_UP(sband->bitrates[i].bitrate, 5); - } - - supp_rates_len = min_t(int, num_rates, 8); - - if (end - pos < 2 + supp_rates_len) - goto out_err; - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = supp_rates_len; - memcpy(pos, rates, supp_rates_len); - pos += supp_rates_len; + err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, 0, + WLAN_EID_SUPP_RATES); + if (err) + return err; /* insert "request information" if in custom IEs */ if (ie && ie_len) { @@ -2116,34 +2096,28 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, before_extrates, ARRAY_SIZE(before_extrates), *offset); - if (end - pos < noffset - *offset) - goto out_err; - memcpy(pos, ie + *offset, noffset - *offset); - pos += noffset - *offset; + if (skb_tailroom(skb) < noffset - *offset) + return -ENOBUFS; + skb_put_data(skb, ie + *offset, noffset - *offset); *offset = noffset; } - ext_rates_len = num_rates - supp_rates_len; - if (ext_rates_len > 0) { - if (end - pos < 2 + ext_rates_len) - goto out_err; - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = ext_rates_len; - memcpy(pos, rates + supp_rates_len, ext_rates_len); - pos += ext_rates_len; - } + err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, 0, + WLAN_EID_EXT_SUPP_RATES); + if (err) + return err; if (chandef->chan && sband->band == NL80211_BAND_2GHZ) { - if (end - pos < 3) - goto out_err; - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = ieee80211_frequency_to_channel( - chandef->chan->center_freq); + if (skb_tailroom(skb) < 3) + return -ENOBUFS; + skb_put_u8(skb, WLAN_EID_DS_PARAMS); + skb_put_u8(skb, 1); + skb_put_u8(skb, + ieee80211_frequency_to_channel(chandef->chan->center_freq)); } if (flags & IEEE80211_PROBE_FLAG_MIN_CONTENT) - goto done; + return 0; /* insert custom IEs that go before HT */ if (ie && ie_len) { @@ -2158,18 +2132,21 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, noffset = ieee80211_ie_split(ie, ie_len, before_ht, ARRAY_SIZE(before_ht), *offset); - if (end - pos < noffset - *offset) - goto out_err; - memcpy(pos, ie + *offset, noffset - *offset); - pos += noffset - *offset; + if (skb_tailroom(skb) < noffset - *offset) + return -ENOBUFS; + skb_put_data(skb, ie + *offset, noffset - *offset); *offset = noffset; } if (sband->ht_cap.ht_supported) { - if (end - pos < 2 + sizeof(struct ieee80211_ht_cap)) - goto out_err; - pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, - sband->ht_cap.cap); + u8 *pos; + + if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) + return -ENOBUFS; + + pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap)); + ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, + sband->ht_cap.cap); } /* insert custom IEs that go before VHT */ @@ -2190,10 +2167,9 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, noffset = ieee80211_ie_split(ie, ie_len, before_vht, ARRAY_SIZE(before_vht), *offset); - if (end - pos < noffset - *offset) - goto out_err; - memcpy(pos, ie + *offset, noffset - *offset); - pos += noffset - *offset; + if (skb_tailroom(skb) < noffset - *offset) + return -ENOBUFS; + skb_put_data(skb, ie + *offset, noffset - *offset); *offset = noffset; } @@ -2208,10 +2184,14 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, } if (sband->vht_cap.vht_supported && have_80mhz) { - if (end - pos < 2 + sizeof(struct ieee80211_vht_cap)) - goto out_err; - pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, - sband->vht_cap.cap); + u8 *pos; + + if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap)) + return -ENOBUFS; + + pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap)); + ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, + sband->vht_cap.cap); } /* insert custom IEs that go before HE */ @@ -2228,10 +2208,9 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, noffset = ieee80211_ie_split(ie, ie_len, before_he, ARRAY_SIZE(before_he), *offset); - if (end - pos < noffset - *offset) - goto out_err; - memcpy(pos, ie + *offset, noffset - *offset); - pos += noffset - *offset; + if (skb_tailroom(skb) < noffset - *offset) + return -ENOBUFS; + skb_put_data(skb, ie + *offset, noffset - *offset); *offset = noffset; } @@ -2239,9 +2218,13 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, if (he_cap && cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE)) { + u8 *pos = skb_tail_pointer(skb); + u8 *end = pos + skb_tailroom(skb); + pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, end); if (!pos) - goto out_err; + return -ENOBUFS; + skb_put(skb, pos - skb_tail_pointer(skb)); } eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); @@ -2250,42 +2233,72 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE | IEEE80211_CHAN_NO_EHT)) { + u8 *pos = skb_tail_pointer(skb); + u8 *end = pos + skb_tailroom(skb); + pos = ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap, end, sdata->vif.type == NL80211_IFTYPE_AP); if (!pos) - goto out_err; + return -ENOBUFS; + skb_put(skb, pos - skb_tail_pointer(skb)); } - if (cfg80211_any_usable_channels(local->hw.wiphy, - BIT(NL80211_BAND_6GHZ), - IEEE80211_CHAN_NO_HE)) { - struct ieee80211_supported_band *sband6; - - sband6 = local->hw.wiphy->bands[NL80211_BAND_6GHZ]; - he_cap = ieee80211_get_he_iftype_cap_vif(sband6, &sdata->vif); - - if (he_cap) { - enum nl80211_iftype iftype = - ieee80211_vif_type_p2p(&sdata->vif); - __le16 cap = ieee80211_get_he_6ghz_capa(sband6, iftype); - - pos = ieee80211_write_he_6ghz_cap(pos, cap, end); - } - } + err = ieee80211_put_he_6ghz_cap(skb, sdata, IEEE80211_SMPS_OFF); + if (err) + return err; /* * If adding more here, adjust code in main.c * that calculates local->scan_ies_len. */ - return pos - buffer; - out_err: - WARN_ONCE(1, "not enough space for preq IEs\n"); - done: - return pos - buffer; + return 0; } +static int ieee80211_put_preq_ies(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_scan_ies *ie_desc, + const u8 *ie, size_t ie_len, + u8 bands_used, u32 *rate_masks, + struct cfg80211_chan_def *chandef, + u32 flags) +{ + size_t custom_ie_offset = 0; + int i, err; + + memset(ie_desc, 0, sizeof(*ie_desc)); + + for (i = 0; i < NUM_NL80211_BANDS; i++) { + if (bands_used & BIT(i)) { + ie_desc->ies[i] = skb_tail_pointer(skb); + err = ieee80211_put_preq_ies_band(skb, sdata, + ie, ie_len, + &custom_ie_offset, + i, rate_masks[i], + chandef, flags); + if (err) + return err; + ie_desc->len[i] = skb_tail_pointer(skb) - + ie_desc->ies[i]; + } + } + + /* add any remaining custom IEs */ + if (ie && ie_len) { + if (WARN_ONCE(skb_tailroom(skb) < ie_len - custom_ie_offset, + "not enough space for preq custom IEs\n")) + return -ENOBUFS; + ie_desc->common_ies = skb_tail_pointer(skb); + skb_put_data(skb, ie + custom_ie_offset, + ie_len - custom_ie_offset); + ie_desc->common_ie_len = skb_tail_pointer(skb) - + ie_desc->common_ies; + } + + return 0; +}; + int ieee80211_build_preq_ies(struct ieee80211_sub_if_data *sdata, u8 *buffer, size_t buffer_len, struct ieee80211_scan_ies *ie_desc, @@ -2294,41 +2307,43 @@ int ieee80211_build_preq_ies(struct ieee80211_sub_if_data *sdata, u8 *buffer, struct cfg80211_chan_def *chandef, u32 flags) { - size_t pos = 0, old_pos = 0, custom_ie_offset = 0; - int i; + struct sk_buff *skb = alloc_skb(buffer_len, GFP_KERNEL); + uintptr_t offs; + int ret, i; + u8 *start; - memset(ie_desc, 0, sizeof(*ie_desc)); + if (!skb) + return -ENOMEM; + start = skb_tail_pointer(skb); + memset(start, 0, skb_tailroom(skb)); + ret = ieee80211_put_preq_ies(skb, sdata, ie_desc, ie, ie_len, + bands_used, rate_masks, chandef, + flags); + if (ret < 0) { + goto out; + } + + if (skb->len > buffer_len) { + ret = -ENOBUFS; + goto out; + } + + memcpy(buffer, start, skb->len); + + /* adjust ie_desc for copy */ for (i = 0; i < NUM_NL80211_BANDS; i++) { - if (bands_used & BIT(i)) { - pos += ieee80211_build_preq_ies_band(sdata, - buffer + pos, - buffer_len - pos, - ie, ie_len, i, - rate_masks[i], - chandef, - &custom_ie_offset, - flags); - ie_desc->ies[i] = buffer + old_pos; - ie_desc->len[i] = pos - old_pos; - old_pos = pos; - } + offs = ie_desc->ies[i] - start; + ie_desc->ies[i] = buffer + offs; } + offs = ie_desc->common_ies - start; + ie_desc->common_ies = buffer + offs; - /* add any remaining custom IEs */ - if (ie && ie_len) { - if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset, - "not enough space for preq custom IEs\n")) - return pos; - memcpy(buffer + pos, ie + custom_ie_offset, - ie_len - custom_ie_offset); - ie_desc->common_ies = buffer + pos; - ie_desc->common_ie_len = ie_len - custom_ie_offset; - pos += ie_len - custom_ie_offset; - } - - return pos; -}; + ret = skb->len; +out: + consume_skb(skb); + return ret; +} struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, const u8 *src, const u8 *dst, @@ -2342,7 +2357,6 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, struct cfg80211_chan_def chandef; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - int ies_len; u32 rate_masks[NUM_NL80211_BANDS] = {}; struct ieee80211_scan_ies dummy_ie_desc; @@ -2363,11 +2377,9 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, return NULL; rate_masks[chan->band] = ratemask; - ies_len = ieee80211_build_preq_ies(sdata, skb_tail_pointer(skb), - skb_tailroom(skb), &dummy_ie_desc, - ie, ie_len, BIT(chan->band), - rate_masks, &chandef, flags); - skb_put(skb, ies_len); + ieee80211_put_preq_ies(skb, sdata, &dummy_ie_desc, + ie, ie_len, BIT(chan->band), + rate_masks, &chandef, flags); if (dst) { mgmt = (struct ieee80211_mgmt *) skb->data; @@ -3202,21 +3214,6 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) return pos; } -u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap) -{ - *pos++ = WLAN_EID_S1G_CAPABILITIES; - *pos++ = sizeof(struct ieee80211_s1g_cap); - memset(pos, 0, sizeof(struct ieee80211_s1g_cap)); - - memcpy(pos, &s1g_cap->cap, sizeof(s1g_cap->cap)); - pos += sizeof(s1g_cap->cap); - - memcpy(pos, &s1g_cap->nss_mcs, sizeof(s1g_cap->nss_mcs)); - pos += sizeof(s1g_cap->nss_mcs); - - return pos; -} - u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, u16 cap) { @@ -3413,33 +3410,32 @@ end: return pos; } -void ieee80211_put_he_6ghz_cap(struct sk_buff *skb, - struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps_mode) +int ieee80211_put_he_6ghz_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps_mode) { struct ieee80211_supported_band *sband; const struct ieee80211_sband_iftype_data *iftd; enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif); - u8 *pos; - u16 cap; + __le16 cap; if (!cfg80211_any_usable_channels(sdata->local->hw.wiphy, BIT(NL80211_BAND_6GHZ), IEEE80211_CHAN_NO_HE)) - return; + return 0; sband = sdata->local->hw.wiphy->bands[NL80211_BAND_6GHZ]; iftd = ieee80211_get_sband_iftype_data(sband, iftype); if (!iftd) - return; + return 0; /* Check for device HE 6 GHz capability before adding element */ if (!iftd->he_6ghz_capa.capa) - return; + return 0; - cap = le16_to_cpu(iftd->he_6ghz_capa.capa); - cap &= ~IEEE80211_HE_6GHZ_CAP_SM_PS; + cap = iftd->he_6ghz_capa.capa; + cap &= cpu_to_le16(~IEEE80211_HE_6GHZ_CAP_SM_PS); switch (smps_mode) { case IEEE80211_SMPS_AUTOMATIC: @@ -3447,22 +3443,27 @@ void ieee80211_put_he_6ghz_cap(struct sk_buff *skb, WARN_ON(1); fallthrough; case IEEE80211_SMPS_OFF: - cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_DISABLED, - IEEE80211_HE_6GHZ_CAP_SM_PS); + cap |= le16_encode_bits(WLAN_HT_CAP_SM_PS_DISABLED, + IEEE80211_HE_6GHZ_CAP_SM_PS); break; case IEEE80211_SMPS_STATIC: - cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_STATIC, - IEEE80211_HE_6GHZ_CAP_SM_PS); + cap |= le16_encode_bits(WLAN_HT_CAP_SM_PS_STATIC, + IEEE80211_HE_6GHZ_CAP_SM_PS); break; case IEEE80211_SMPS_DYNAMIC: - cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_DYNAMIC, - IEEE80211_HE_6GHZ_CAP_SM_PS); + cap |= le16_encode_bits(WLAN_HT_CAP_SM_PS_DYNAMIC, + IEEE80211_HE_6GHZ_CAP_SM_PS); break; } - pos = skb_put(skb, 2 + 1 + sizeof(cap)); - ieee80211_write_he_6ghz_cap(pos, cpu_to_le16(cap), - pos + 2 + 1 + sizeof(cap)); + if (skb_tailroom(skb) < 2 + 1 + sizeof(cap)) + return -ENOBUFS; + + skb_put_u8(skb, WLAN_EID_EXTENSION); + skb_put_u8(skb, 1 + sizeof(cap)); + skb_put_u8(skb, WLAN_EID_EXT_HE_6GHZ_CAPA); + skb_put_data(skb, &cap, sizeof(cap)); + return 0; } u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, From 9d0480a7c05b6482195acafbc5f4f3b4a1cc2b8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:34 +0100 Subject: [PATCH 0928/2255] wifi: mac80211: move element parsing to a new file This code got really big, move it to a new file. Pure code move. Link: https://msgid.link/20240129202041.7f27f7c895e4.I0adfc28bd656a4d44c2bf47966277eecf56cbaa0@changeid Signed-off-by: Johannes Berg --- net/mac80211/Makefile | 2 +- net/mac80211/parse.c | 926 ++++++++++++++++++++++++++++++++++++++++++ net/mac80211/util.c | 891 ---------------------------------------- 3 files changed, 927 insertions(+), 892 deletions(-) create mode 100644 net/mac80211/parse.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 4406b4f8f3b9..a33884967f21 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -29,7 +29,7 @@ mac80211-y := \ spectmgmt.o \ tx.o \ key.o \ - util.o \ + util.o parse.o \ wme.o \ chan.o \ trace.o mlme.o \ diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c new file mode 100644 index 000000000000..196a882e4c19 --- /dev/null +++ b/net/mac80211/parse.c @@ -0,0 +1,926 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018-2024 Intel Corporation + * + * element parsing for mac80211 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211_i.h" +#include "driver-ops.h" +#include "rate.h" +#include "mesh.h" +#include "wme.h" +#include "led.h" +#include "wep.h" + +static void +ieee80211_parse_extension_element(u32 *crc, + const struct element *elem, + struct ieee802_11_elems *elems, + struct ieee80211_elems_parse_params *params) +{ + const void *data = elem->data + 1; + bool calc_crc = false; + u8 len; + + if (!elem->datalen) + return; + + len = elem->datalen - 1; + + switch (elem->data[0]) { + case WLAN_EID_EXT_HE_MU_EDCA: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; + calc_crc = true; + if (len >= sizeof(*elems->mu_edca_param_set)) + elems->mu_edca_param_set = data; + break; + case WLAN_EID_EXT_HE_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; + if (ieee80211_he_capa_size_ok(data, len)) { + elems->he_cap = data; + elems->he_cap_len = len; + } + break; + case WLAN_EID_EXT_HE_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; + calc_crc = true; + if (len >= sizeof(*elems->he_operation) && + len >= ieee80211_he_oper_size(data) - 1) + elems->he_operation = data; + break; + case WLAN_EID_EXT_UORA: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; + if (len >= 1) + elems->uora_element = data; + break; + case WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME: + if (len == 3) + elems->max_channel_switch_time = data; + break; + case WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION: + if (len >= sizeof(*elems->mbssid_config_ie)) + elems->mbssid_config_ie = data; + break; + case WLAN_EID_EXT_HE_SPR: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; + if (len >= sizeof(*elems->he_spr) && + len >= ieee80211_he_spr_size(data)) + elems->he_spr = data; + break; + case WLAN_EID_EXT_HE_6GHZ_CAPA: + if (params->mode < IEEE80211_CONN_MODE_HE) + break; + if (len >= sizeof(*elems->he_6ghz_capa)) + elems->he_6ghz_capa = data; + break; + case WLAN_EID_EXT_EHT_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; + if (ieee80211_eht_capa_size_ok(elems->he_cap, + data, len, + params->from_ap)) { + elems->eht_cap = data; + elems->eht_cap_len = len; + } + break; + case WLAN_EID_EXT_EHT_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; + if (ieee80211_eht_oper_size_ok(data, len)) + elems->eht_operation = data; + calc_crc = true; + break; + case WLAN_EID_EXT_EHT_MULTI_LINK: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; + calc_crc = true; + + if (ieee80211_mle_size_ok(data, len)) { + const struct ieee80211_multi_link_elem *mle = + (void *)data; + + switch (le16_get_bits(mle->control, + IEEE80211_ML_CONTROL_TYPE)) { + case IEEE80211_ML_CONTROL_TYPE_BASIC: + if (elems->ml_basic) { + elems->parse_error |= + IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC; + break; + } + elems->ml_basic_elem = (void *)elem; + elems->ml_basic = data; + elems->ml_basic_len = len; + break; + case IEEE80211_ML_CONTROL_TYPE_RECONF: + elems->ml_reconf_elem = (void *)elem; + elems->ml_reconf = data; + elems->ml_reconf_len = len; + break; + default: + break; + } + } + break; + case WLAN_EID_EXT_BANDWIDTH_INDICATION: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; + if (ieee80211_bandwidth_indication_size_ok(data, len)) + elems->bandwidth_indication = data; + calc_crc = true; + break; + case WLAN_EID_EXT_TID_TO_LINK_MAPPING: + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; + calc_crc = true; + if (ieee80211_tid_to_link_map_size_ok(data, len) && + elems->ttlm_num < ARRAY_SIZE(elems->ttlm)) { + elems->ttlm[elems->ttlm_num] = (void *)data; + elems->ttlm_num++; + } + break; + } + + if (crc && calc_crc) + *crc = crc32_be(*crc, (void *)elem, elem->datalen + 2); +} + +static u32 +_ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, + struct ieee802_11_elems *elems, + const struct element *check_inherit) +{ + const struct element *elem; + bool calc_crc = params->filter != 0; + DECLARE_BITMAP(seen_elems, 256); + u32 crc = params->crc; + + bitmap_zero(seen_elems, 256); + + for_each_element(elem, params->start, params->len) { + const struct element *subelem; + u8 elem_parse_failed; + u8 id = elem->id; + u8 elen = elem->datalen; + const u8 *pos = elem->data; + + if (check_inherit && + !cfg80211_is_element_inherited(elem, + check_inherit)) + continue; + + switch (id) { + case WLAN_EID_SSID: + case WLAN_EID_SUPP_RATES: + case WLAN_EID_FH_PARAMS: + case WLAN_EID_DS_PARAMS: + case WLAN_EID_CF_PARAMS: + case WLAN_EID_TIM: + case WLAN_EID_IBSS_PARAMS: + case WLAN_EID_CHALLENGE: + case WLAN_EID_RSN: + case WLAN_EID_ERP_INFO: + case WLAN_EID_EXT_SUPP_RATES: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_HT_OPERATION: + case WLAN_EID_VHT_CAPABILITY: + case WLAN_EID_VHT_OPERATION: + case WLAN_EID_MESH_ID: + case WLAN_EID_MESH_CONFIG: + case WLAN_EID_PEER_MGMT: + case WLAN_EID_PREQ: + case WLAN_EID_PREP: + case WLAN_EID_PERR: + case WLAN_EID_RANN: + case WLAN_EID_CHANNEL_SWITCH: + case WLAN_EID_EXT_CHANSWITCH_ANN: + case WLAN_EID_COUNTRY: + case WLAN_EID_PWR_CONSTRAINT: + case WLAN_EID_TIMEOUT_INTERVAL: + case WLAN_EID_SECONDARY_CHANNEL_OFFSET: + case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: + case WLAN_EID_CHAN_SWITCH_PARAM: + case WLAN_EID_EXT_CAPABILITY: + case WLAN_EID_CHAN_SWITCH_TIMING: + case WLAN_EID_LINK_ID: + case WLAN_EID_BSS_MAX_IDLE_PERIOD: + case WLAN_EID_RSNX: + case WLAN_EID_S1G_BCN_COMPAT: + case WLAN_EID_S1G_CAPABILITIES: + case WLAN_EID_S1G_OPERATION: + case WLAN_EID_AID_RESPONSE: + case WLAN_EID_S1G_SHORT_BCN_INTERVAL: + /* + * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible + * that if the content gets bigger it might be needed more than once + */ + if (test_bit(id, seen_elems)) { + elems->parse_error |= + IEEE80211_PARSE_ERR_DUP_ELEM; + continue; + } + break; + } + + if (calc_crc && id < 64 && (params->filter & (1ULL << id))) + crc = crc32_be(crc, pos - 2, elen + 2); + + elem_parse_failed = 0; + + switch (id) { + case WLAN_EID_LINK_ID: + if (elen + 2 < sizeof(struct ieee80211_tdls_lnkie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->lnk_id = (void *)(pos - 2); + break; + case WLAN_EID_CHAN_SWITCH_TIMING: + if (elen < sizeof(struct ieee80211_ch_switch_timing)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->ch_sw_timing = (void *)pos; + break; + case WLAN_EID_EXT_CAPABILITY: + elems->ext_capab = pos; + elems->ext_capab_len = elen; + break; + case WLAN_EID_SSID: + elems->ssid = pos; + elems->ssid_len = elen; + break; + case WLAN_EID_SUPP_RATES: + elems->supp_rates = pos; + elems->supp_rates_len = elen; + break; + case WLAN_EID_DS_PARAMS: + if (elen >= 1) + elems->ds_params = pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_TIM: + if (elen >= sizeof(struct ieee80211_tim_ie)) { + elems->tim = (void *)pos; + elems->tim_len = elen; + } else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_VENDOR_SPECIFIC: + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && + pos[2] == 0xf2) { + /* Microsoft OUI (00:50:F2) */ + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + + if (elen >= 5 && pos[3] == 2) { + /* OUI Type 2 - WMM IE */ + if (pos[4] == 0) { + elems->wmm_info = pos; + elems->wmm_info_len = elen; + } else if (pos[4] == 1) { + elems->wmm_param = pos; + elems->wmm_param_len = elen; + } + } + } + break; + case WLAN_EID_RSN: + elems->rsn = pos; + elems->rsn_len = elen; + break; + case WLAN_EID_ERP_INFO: + if (elen >= 1) + elems->erp_info = pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_EXT_SUPP_RATES: + elems->ext_supp_rates = pos; + elems->ext_supp_rates_len = elen; + break; + case WLAN_EID_HT_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_HT) + break; + if (elen >= sizeof(struct ieee80211_ht_cap)) + elems->ht_cap_elem = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_HT_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_HT) + break; + if (elen >= sizeof(struct ieee80211_ht_operation)) + elems->ht_operation = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_VHT_CAPABILITY: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; + if (elen >= sizeof(struct ieee80211_vht_cap)) + elems->vht_cap_elem = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_VHT_OPERATION: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; + if (elen >= sizeof(struct ieee80211_vht_operation)) { + elems->vht_operation = (void *)pos; + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + break; + } + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_OPMODE_NOTIF: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; + if (elen > 0) { + elems->opmode_notif = pos; + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + break; + } + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_MESH_ID: + elems->mesh_id = pos; + elems->mesh_id_len = elen; + break; + case WLAN_EID_MESH_CONFIG: + if (elen >= sizeof(struct ieee80211_meshconf_ie)) + elems->mesh_config = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_PEER_MGMT: + elems->peering = pos; + elems->peering_len = elen; + break; + case WLAN_EID_MESH_AWAKE_WINDOW: + if (elen >= 2) + elems->awake_window = (void *)pos; + break; + case WLAN_EID_PREQ: + elems->preq = pos; + elems->preq_len = elen; + break; + case WLAN_EID_PREP: + elems->prep = pos; + elems->prep_len = elen; + break; + case WLAN_EID_PERR: + elems->perr = pos; + elems->perr_len = elen; + break; + case WLAN_EID_RANN: + if (elen >= sizeof(struct ieee80211_rann_ie)) + elems->rann = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_CHANNEL_SWITCH: + if (elen != sizeof(struct ieee80211_channel_sw_ie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->ch_switch_ie = (void *)pos; + break; + case WLAN_EID_EXT_CHANSWITCH_ANN: + if (elen != sizeof(struct ieee80211_ext_chansw_ie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->ext_chansw_ie = (void *)pos; + break; + case WLAN_EID_SECONDARY_CHANNEL_OFFSET: + if (params->mode < IEEE80211_CONN_MODE_HT) + break; + if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->sec_chan_offs = (void *)pos; + break; + case WLAN_EID_CHAN_SWITCH_PARAM: + if (elen < + sizeof(*elems->mesh_chansw_params_ie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->mesh_chansw_params_ie = (void *)pos; + break; + case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; + + if (!params->action) { + elem_parse_failed = + IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; + break; + } + + if (elen < sizeof(*elems->wide_bw_chansw_ie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->wide_bw_chansw_ie = (void *)pos; + break; + case WLAN_EID_CHANNEL_SWITCH_WRAPPER: + if (params->mode < IEEE80211_CONN_MODE_VHT) + break; + if (params->action) { + elem_parse_failed = + IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; + break; + } + /* + * This is a bit tricky, but as we only care about + * a few elements, parse them out manually. + */ + subelem = cfg80211_find_elem(WLAN_EID_WIDE_BW_CHANNEL_SWITCH, + pos, elen); + if (subelem) { + if (subelem->datalen >= sizeof(*elems->wide_bw_chansw_ie)) + elems->wide_bw_chansw_ie = + (void *)subelem->data; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + } + + if (params->mode < IEEE80211_CONN_MODE_EHT) + break; + + subelem = cfg80211_find_ext_elem(WLAN_EID_EXT_BANDWIDTH_INDICATION, + pos, elen); + if (subelem) { + const void *edata = subelem->data + 1; + u8 edatalen = subelem->datalen - 1; + + if (ieee80211_bandwidth_indication_size_ok(edata, + edatalen)) + elems->bandwidth_indication = edata; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + } + break; + case WLAN_EID_COUNTRY: + elems->country_elem = pos; + elems->country_elem_len = elen; + break; + case WLAN_EID_PWR_CONSTRAINT: + if (elen != 1) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->pwr_constr_elem = pos; + break; + case WLAN_EID_CISCO_VENDOR_SPECIFIC: + /* Lots of different options exist, but we only care + * about the Dynamic Transmit Power Control element. + * First check for the Cisco OUI, then for the DTPC + * tag (0x00). + */ + if (elen < 4) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + + if (pos[0] != 0x00 || pos[1] != 0x40 || + pos[2] != 0x96 || pos[3] != 0x00) + break; + + if (elen != 6) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + + elems->cisco_dtpc_elem = pos; + break; + case WLAN_EID_ADDBA_EXT: + if (elen < sizeof(struct ieee80211_addba_ext_ie)) { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + } + elems->addba_ext_ie = (void *)pos; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + if (elen >= sizeof(struct ieee80211_timeout_interval_ie)) + elems->timeout_int = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_BSS_MAX_IDLE_PERIOD: + if (elen >= sizeof(*elems->max_idle_period_ie)) + elems->max_idle_period_ie = (void *)pos; + break; + case WLAN_EID_RSNX: + elems->rsnx = pos; + elems->rsnx_len = elen; + break; + case WLAN_EID_TX_POWER_ENVELOPE: + if (elen < 1 || + elen > sizeof(struct ieee80211_tx_pwr_env)) + break; + + if (elems->tx_pwr_env_num >= ARRAY_SIZE(elems->tx_pwr_env)) + break; + + elems->tx_pwr_env[elems->tx_pwr_env_num] = (void *)pos; + elems->tx_pwr_env_len[elems->tx_pwr_env_num] = elen; + elems->tx_pwr_env_num++; + break; + case WLAN_EID_EXTENSION: + ieee80211_parse_extension_element(calc_crc ? + &crc : NULL, + elem, elems, params); + break; + case WLAN_EID_S1G_CAPABILITIES: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; + if (elen >= sizeof(*elems->s1g_capab)) + elems->s1g_capab = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_S1G_OPERATION: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; + if (elen == sizeof(*elems->s1g_oper)) + elems->s1g_oper = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_S1G_BCN_COMPAT: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; + if (elen == sizeof(*elems->s1g_bcn_compat)) + elems->s1g_bcn_compat = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + case WLAN_EID_AID_RESPONSE: + if (params->mode != IEEE80211_CONN_MODE_S1G) + break; + if (elen == sizeof(struct ieee80211_aid_response_ie)) + elems->aid_resp = (void *)pos; + else + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + break; + default: + break; + } + + if (elem_parse_failed) + elems->parse_error |= elem_parse_failed; + else + __set_bit(id, seen_elems); + } + + if (!for_each_element_completed(elem, params->start, params->len)) + elems->parse_error |= IEEE80211_PARSE_ERR_INVALID_END; + + return crc; +} + +static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, + struct ieee802_11_elems *elems, + struct cfg80211_bss *bss, + u8 *nontransmitted_profile) +{ + const struct element *elem, *sub; + size_t profile_len = 0; + bool found = false; + + if (!bss || !bss->transmitted_bss) + return profile_len; + + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) { + if (elem->datalen < 2) + continue; + if (elem->data[0] < 1 || elem->data[0] > 8) + continue; + + for_each_element(sub, elem->data + 1, elem->datalen - 1) { + u8 new_bssid[ETH_ALEN]; + const u8 *index; + + if (sub->id != 0 || sub->datalen < 4) { + /* not a valid BSS profile */ + continue; + } + + if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP || + sub->data[1] != 2) { + /* The first element of the + * Nontransmitted BSSID Profile is not + * the Nontransmitted BSSID Capability + * element. + */ + continue; + } + + memset(nontransmitted_profile, 0, len); + profile_len = cfg80211_merge_profile(start, len, + elem, + sub, + nontransmitted_profile, + len); + + /* found a Nontransmitted BSSID Profile */ + index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, + nontransmitted_profile, + profile_len); + if (!index || index[1] < 1 || index[2] == 0) { + /* Invalid MBSSID Index element */ + continue; + } + + cfg80211_gen_new_bssid(bss->transmitted_bss->bssid, + elem->data[0], + index[2], + new_bssid); + if (ether_addr_equal(new_bssid, bss->bssid)) { + found = true; + elems->bssid_index_len = index[1]; + elems->bssid_index = (void *)&index[2]; + break; + } + } + } + + return found ? profile_len : 0; +} + +static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, + u8 link_id) +{ + const struct ieee80211_multi_link_elem *ml = elems->ml_basic; + ssize_t ml_len = elems->ml_basic_len; + const struct element *sub; + + if (!ml || !ml_len) + return; + + if (le16_get_bits(ml->control, IEEE80211_ML_CONTROL_TYPE) != + IEEE80211_ML_CONTROL_TYPE_BASIC) + return; + + for_each_mle_subelement(sub, (u8 *)ml, ml_len) { + struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; + ssize_t sta_prof_len; + u16 control; + + if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) + continue; + + if (!ieee80211_mle_basic_sta_prof_size_ok(sub->data, + sub->datalen)) + return; + + control = le16_to_cpu(prof->control); + + if (link_id != u16_get_bits(control, + IEEE80211_MLE_STA_CONTROL_LINK_ID)) + continue; + + if (!(control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE)) + return; + + /* the sub element can be fragmented */ + sta_prof_len = + cfg80211_defragment_element(sub, + (u8 *)ml, ml_len, + elems->scratch_pos, + elems->scratch + + elems->scratch_len - + elems->scratch_pos, + IEEE80211_MLE_SUBELEM_FRAGMENT); + + if (sta_prof_len < 0) + return; + + elems->prof = (void *)elems->scratch_pos; + elems->sta_prof_len = sta_prof_len; + elems->scratch_pos += sta_prof_len; + + return; + } +} + +static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, + struct ieee80211_elems_parse_params *params) +{ + struct ieee80211_mle_per_sta_profile *prof; + struct ieee80211_elems_parse_params sub = { + .mode = params->mode, + .action = params->action, + .from_ap = params->from_ap, + .link_id = -1, + }; + ssize_t ml_len = elems->ml_basic_len; + const struct element *non_inherit = NULL; + const u8 *end; + + if (params->link_id == -1) + return; + + ml_len = cfg80211_defragment_element(elems->ml_basic_elem, + elems->ie_start, + elems->total_len, + elems->scratch_pos, + elems->scratch + + elems->scratch_len - + elems->scratch_pos, + WLAN_EID_FRAGMENT); + + if (ml_len < 0) + return; + + elems->ml_basic = (const void *)elems->scratch_pos; + elems->ml_basic_len = ml_len; + + ieee80211_mle_get_sta_prof(elems, params->link_id); + prof = elems->prof; + + if (!prof) + return; + + /* check if we have the 4 bytes for the fixed part in assoc response */ + if (elems->sta_prof_len < sizeof(*prof) + prof->sta_info_len - 1 + 4) { + elems->prof = NULL; + elems->sta_prof_len = 0; + return; + } + + /* + * Skip the capability information and the status code that are expected + * as part of the station profile in association response frames. Note + * the -1 is because the 'sta_info_len' is accounted to as part of the + * per-STA profile, but not part of the 'u8 variable[]' portion. + */ + sub.start = prof->variable + prof->sta_info_len - 1 + 4; + end = (const u8 *)prof + elems->sta_prof_len; + sub.len = end - sub.start; + + non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, + sub.start, sub.len); + _ieee802_11_parse_elems_full(&sub, elems, non_inherit); +} + +struct ieee802_11_elems * +ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) +{ + struct ieee802_11_elems *elems; + const struct element *non_inherit = NULL; + u8 *nontransmitted_profile; + int nontransmitted_profile_len = 0; + size_t scratch_len = 3 * params->len; + + elems = kzalloc(struct_size(elems, scratch, scratch_len), GFP_ATOMIC); + if (!elems) + return NULL; + elems->ie_start = params->start; + elems->total_len = params->len; + elems->scratch_len = scratch_len; + elems->scratch_pos = elems->scratch; + + nontransmitted_profile = elems->scratch_pos; + nontransmitted_profile_len = + ieee802_11_find_bssid_profile(params->start, params->len, + elems, params->bss, + nontransmitted_profile); + elems->scratch_pos += nontransmitted_profile_len; + elems->scratch_len -= nontransmitted_profile_len; + non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, + nontransmitted_profile, + nontransmitted_profile_len); + + elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit); + + /* Override with nontransmitted profile, if found */ + if (nontransmitted_profile_len) { + struct ieee80211_elems_parse_params sub = { + .mode = params->mode, + .start = nontransmitted_profile, + .len = nontransmitted_profile_len, + .action = params->action, + .link_id = params->link_id, + }; + + _ieee802_11_parse_elems_full(&sub, elems, NULL); + } + + ieee80211_mle_parse_link(elems, params); + + if (elems->tim && !elems->parse_error) { + const struct ieee80211_tim_ie *tim_ie = elems->tim; + + elems->dtim_period = tim_ie->dtim_period; + elems->dtim_count = tim_ie->dtim_count; + } + + /* Override DTIM period and count if needed */ + if (elems->bssid_index && + elems->bssid_index_len >= + offsetofend(struct ieee80211_bssid_index, dtim_period)) + elems->dtim_period = elems->bssid_index->dtim_period; + + if (elems->bssid_index && + elems->bssid_index_len >= + offsetofend(struct ieee80211_bssid_index, dtim_count)) + elems->dtim_count = elems->bssid_index->dtim_count; + + return elems; +} +EXPORT_SYMBOL_IF_KUNIT(ieee802_11_parse_elems_full); + +int ieee80211_parse_bitrates(enum nl80211_chan_width width, + const struct ieee80211_supported_band *sband, + const u8 *srates, int srates_len, u32 *rates) +{ + u32 rate_flags = ieee80211_chanwidth_rate_flags(width); + struct ieee80211_rate *br; + int brate, rate, i, j, count = 0; + + *rates = 0; + + for (i = 0; i < srates_len; i++) { + rate = srates[i] & 0x7f; + + for (j = 0; j < sband->n_bitrates; j++) { + br = &sband->bitrates[j]; + if ((rate_flags & br->flags) != rate_flags) + continue; + + brate = DIV_ROUND_UP(br->bitrate, 5); + if (brate == rate) { + *rates |= BIT(j); + count++; + break; + } + } + } + return count; +} diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ea863d78061e..c675ac59d2bb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -917,868 +917,6 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_queue_delayed_work); -static void -ieee80211_parse_extension_element(u32 *crc, - const struct element *elem, - struct ieee802_11_elems *elems, - struct ieee80211_elems_parse_params *params) -{ - const void *data = elem->data + 1; - bool calc_crc = false; - u8 len; - - if (!elem->datalen) - return; - - len = elem->datalen - 1; - - switch (elem->data[0]) { - case WLAN_EID_EXT_HE_MU_EDCA: - if (params->mode < IEEE80211_CONN_MODE_HE) - break; - calc_crc = true; - if (len >= sizeof(*elems->mu_edca_param_set)) - elems->mu_edca_param_set = data; - break; - case WLAN_EID_EXT_HE_CAPABILITY: - if (params->mode < IEEE80211_CONN_MODE_HE) - break; - if (ieee80211_he_capa_size_ok(data, len)) { - elems->he_cap = data; - elems->he_cap_len = len; - } - break; - case WLAN_EID_EXT_HE_OPERATION: - if (params->mode < IEEE80211_CONN_MODE_HE) - break; - calc_crc = true; - if (len >= sizeof(*elems->he_operation) && - len >= ieee80211_he_oper_size(data) - 1) - elems->he_operation = data; - break; - case WLAN_EID_EXT_UORA: - if (params->mode < IEEE80211_CONN_MODE_HE) - break; - if (len >= 1) - elems->uora_element = data; - break; - case WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME: - if (len == 3) - elems->max_channel_switch_time = data; - break; - case WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION: - if (len >= sizeof(*elems->mbssid_config_ie)) - elems->mbssid_config_ie = data; - break; - case WLAN_EID_EXT_HE_SPR: - if (params->mode < IEEE80211_CONN_MODE_HE) - break; - if (len >= sizeof(*elems->he_spr) && - len >= ieee80211_he_spr_size(data)) - elems->he_spr = data; - break; - case WLAN_EID_EXT_HE_6GHZ_CAPA: - if (params->mode < IEEE80211_CONN_MODE_HE) - break; - if (len >= sizeof(*elems->he_6ghz_capa)) - elems->he_6ghz_capa = data; - break; - case WLAN_EID_EXT_EHT_CAPABILITY: - if (params->mode < IEEE80211_CONN_MODE_EHT) - break; - if (ieee80211_eht_capa_size_ok(elems->he_cap, - data, len, - params->from_ap)) { - elems->eht_cap = data; - elems->eht_cap_len = len; - } - break; - case WLAN_EID_EXT_EHT_OPERATION: - if (params->mode < IEEE80211_CONN_MODE_EHT) - break; - if (ieee80211_eht_oper_size_ok(data, len)) - elems->eht_operation = data; - calc_crc = true; - break; - case WLAN_EID_EXT_EHT_MULTI_LINK: - if (params->mode < IEEE80211_CONN_MODE_EHT) - break; - calc_crc = true; - - if (ieee80211_mle_size_ok(data, len)) { - const struct ieee80211_multi_link_elem *mle = - (void *)data; - - switch (le16_get_bits(mle->control, - IEEE80211_ML_CONTROL_TYPE)) { - case IEEE80211_ML_CONTROL_TYPE_BASIC: - if (elems->ml_basic) { - elems->parse_error |= - IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC; - break; - } - elems->ml_basic_elem = (void *)elem; - elems->ml_basic = data; - elems->ml_basic_len = len; - break; - case IEEE80211_ML_CONTROL_TYPE_RECONF: - elems->ml_reconf_elem = (void *)elem; - elems->ml_reconf = data; - elems->ml_reconf_len = len; - break; - default: - break; - } - } - break; - case WLAN_EID_EXT_BANDWIDTH_INDICATION: - if (params->mode < IEEE80211_CONN_MODE_EHT) - break; - if (ieee80211_bandwidth_indication_size_ok(data, len)) - elems->bandwidth_indication = data; - calc_crc = true; - break; - case WLAN_EID_EXT_TID_TO_LINK_MAPPING: - if (params->mode < IEEE80211_CONN_MODE_EHT) - break; - calc_crc = true; - if (ieee80211_tid_to_link_map_size_ok(data, len) && - elems->ttlm_num < ARRAY_SIZE(elems->ttlm)) { - elems->ttlm[elems->ttlm_num] = (void *)data; - elems->ttlm_num++; - } - break; - } - - if (crc && calc_crc) - *crc = crc32_be(*crc, (void *)elem, elem->datalen + 2); -} - -static u32 -_ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, - struct ieee802_11_elems *elems, - const struct element *check_inherit) -{ - const struct element *elem; - bool calc_crc = params->filter != 0; - DECLARE_BITMAP(seen_elems, 256); - u32 crc = params->crc; - - bitmap_zero(seen_elems, 256); - - for_each_element(elem, params->start, params->len) { - const struct element *subelem; - u8 elem_parse_failed; - u8 id = elem->id; - u8 elen = elem->datalen; - const u8 *pos = elem->data; - - if (check_inherit && - !cfg80211_is_element_inherited(elem, - check_inherit)) - continue; - - switch (id) { - case WLAN_EID_SSID: - case WLAN_EID_SUPP_RATES: - case WLAN_EID_FH_PARAMS: - case WLAN_EID_DS_PARAMS: - case WLAN_EID_CF_PARAMS: - case WLAN_EID_TIM: - case WLAN_EID_IBSS_PARAMS: - case WLAN_EID_CHALLENGE: - case WLAN_EID_RSN: - case WLAN_EID_ERP_INFO: - case WLAN_EID_EXT_SUPP_RATES: - case WLAN_EID_HT_CAPABILITY: - case WLAN_EID_HT_OPERATION: - case WLAN_EID_VHT_CAPABILITY: - case WLAN_EID_VHT_OPERATION: - case WLAN_EID_MESH_ID: - case WLAN_EID_MESH_CONFIG: - case WLAN_EID_PEER_MGMT: - case WLAN_EID_PREQ: - case WLAN_EID_PREP: - case WLAN_EID_PERR: - case WLAN_EID_RANN: - case WLAN_EID_CHANNEL_SWITCH: - case WLAN_EID_EXT_CHANSWITCH_ANN: - case WLAN_EID_COUNTRY: - case WLAN_EID_PWR_CONSTRAINT: - case WLAN_EID_TIMEOUT_INTERVAL: - case WLAN_EID_SECONDARY_CHANNEL_OFFSET: - case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: - case WLAN_EID_CHAN_SWITCH_PARAM: - case WLAN_EID_EXT_CAPABILITY: - case WLAN_EID_CHAN_SWITCH_TIMING: - case WLAN_EID_LINK_ID: - case WLAN_EID_BSS_MAX_IDLE_PERIOD: - case WLAN_EID_RSNX: - case WLAN_EID_S1G_BCN_COMPAT: - case WLAN_EID_S1G_CAPABILITIES: - case WLAN_EID_S1G_OPERATION: - case WLAN_EID_AID_RESPONSE: - case WLAN_EID_S1G_SHORT_BCN_INTERVAL: - /* - * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible - * that if the content gets bigger it might be needed more than once - */ - if (test_bit(id, seen_elems)) { - elems->parse_error |= - IEEE80211_PARSE_ERR_DUP_ELEM; - continue; - } - break; - } - - if (calc_crc && id < 64 && (params->filter & (1ULL << id))) - crc = crc32_be(crc, pos - 2, elen + 2); - - elem_parse_failed = 0; - - switch (id) { - case WLAN_EID_LINK_ID: - if (elen + 2 < sizeof(struct ieee80211_tdls_lnkie)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->lnk_id = (void *)(pos - 2); - break; - case WLAN_EID_CHAN_SWITCH_TIMING: - if (elen < sizeof(struct ieee80211_ch_switch_timing)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->ch_sw_timing = (void *)pos; - break; - case WLAN_EID_EXT_CAPABILITY: - elems->ext_capab = pos; - elems->ext_capab_len = elen; - break; - case WLAN_EID_SSID: - elems->ssid = pos; - elems->ssid_len = elen; - break; - case WLAN_EID_SUPP_RATES: - elems->supp_rates = pos; - elems->supp_rates_len = elen; - break; - case WLAN_EID_DS_PARAMS: - if (elen >= 1) - elems->ds_params = pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_TIM: - if (elen >= sizeof(struct ieee80211_tim_ie)) { - elems->tim = (void *)pos; - elems->tim_len = elen; - } else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_VENDOR_SPECIFIC: - if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && - pos[2] == 0xf2) { - /* Microsoft OUI (00:50:F2) */ - - if (calc_crc) - crc = crc32_be(crc, pos - 2, elen + 2); - - if (elen >= 5 && pos[3] == 2) { - /* OUI Type 2 - WMM IE */ - if (pos[4] == 0) { - elems->wmm_info = pos; - elems->wmm_info_len = elen; - } else if (pos[4] == 1) { - elems->wmm_param = pos; - elems->wmm_param_len = elen; - } - } - } - break; - case WLAN_EID_RSN: - elems->rsn = pos; - elems->rsn_len = elen; - break; - case WLAN_EID_ERP_INFO: - if (elen >= 1) - elems->erp_info = pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_EXT_SUPP_RATES: - elems->ext_supp_rates = pos; - elems->ext_supp_rates_len = elen; - break; - case WLAN_EID_HT_CAPABILITY: - if (params->mode < IEEE80211_CONN_MODE_HT) - break; - if (elen >= sizeof(struct ieee80211_ht_cap)) - elems->ht_cap_elem = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_HT_OPERATION: - if (params->mode < IEEE80211_CONN_MODE_HT) - break; - if (elen >= sizeof(struct ieee80211_ht_operation)) - elems->ht_operation = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_VHT_CAPABILITY: - if (params->mode < IEEE80211_CONN_MODE_VHT) - break; - if (elen >= sizeof(struct ieee80211_vht_cap)) - elems->vht_cap_elem = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_VHT_OPERATION: - if (params->mode < IEEE80211_CONN_MODE_VHT) - break; - if (elen >= sizeof(struct ieee80211_vht_operation)) { - elems->vht_operation = (void *)pos; - if (calc_crc) - crc = crc32_be(crc, pos - 2, elen + 2); - break; - } - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_OPMODE_NOTIF: - if (params->mode < IEEE80211_CONN_MODE_VHT) - break; - if (elen > 0) { - elems->opmode_notif = pos; - if (calc_crc) - crc = crc32_be(crc, pos - 2, elen + 2); - break; - } - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_MESH_ID: - elems->mesh_id = pos; - elems->mesh_id_len = elen; - break; - case WLAN_EID_MESH_CONFIG: - if (elen >= sizeof(struct ieee80211_meshconf_ie)) - elems->mesh_config = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_PEER_MGMT: - elems->peering = pos; - elems->peering_len = elen; - break; - case WLAN_EID_MESH_AWAKE_WINDOW: - if (elen >= 2) - elems->awake_window = (void *)pos; - break; - case WLAN_EID_PREQ: - elems->preq = pos; - elems->preq_len = elen; - break; - case WLAN_EID_PREP: - elems->prep = pos; - elems->prep_len = elen; - break; - case WLAN_EID_PERR: - elems->perr = pos; - elems->perr_len = elen; - break; - case WLAN_EID_RANN: - if (elen >= sizeof(struct ieee80211_rann_ie)) - elems->rann = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_CHANNEL_SWITCH: - if (elen != sizeof(struct ieee80211_channel_sw_ie)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->ch_switch_ie = (void *)pos; - break; - case WLAN_EID_EXT_CHANSWITCH_ANN: - if (elen != sizeof(struct ieee80211_ext_chansw_ie)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->ext_chansw_ie = (void *)pos; - break; - case WLAN_EID_SECONDARY_CHANNEL_OFFSET: - if (params->mode < IEEE80211_CONN_MODE_HT) - break; - if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->sec_chan_offs = (void *)pos; - break; - case WLAN_EID_CHAN_SWITCH_PARAM: - if (elen < - sizeof(*elems->mesh_chansw_params_ie)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->mesh_chansw_params_ie = (void *)pos; - break; - case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: - if (params->mode < IEEE80211_CONN_MODE_VHT) - break; - - if (!params->action) { - elem_parse_failed = - IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; - break; - } - - if (elen < sizeof(*elems->wide_bw_chansw_ie)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->wide_bw_chansw_ie = (void *)pos; - break; - case WLAN_EID_CHANNEL_SWITCH_WRAPPER: - if (params->mode < IEEE80211_CONN_MODE_VHT) - break; - if (params->action) { - elem_parse_failed = - IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; - break; - } - /* - * This is a bit tricky, but as we only care about - * a few elements, parse them out manually. - */ - subelem = cfg80211_find_elem(WLAN_EID_WIDE_BW_CHANNEL_SWITCH, - pos, elen); - if (subelem) { - if (subelem->datalen >= sizeof(*elems->wide_bw_chansw_ie)) - elems->wide_bw_chansw_ie = - (void *)subelem->data; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - } - - if (params->mode < IEEE80211_CONN_MODE_EHT) - break; - - subelem = cfg80211_find_ext_elem(WLAN_EID_EXT_BANDWIDTH_INDICATION, - pos, elen); - if (subelem) { - const void *edata = subelem->data + 1; - u8 edatalen = subelem->datalen - 1; - - if (ieee80211_bandwidth_indication_size_ok(edata, - edatalen)) - elems->bandwidth_indication = edata; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - } - break; - case WLAN_EID_COUNTRY: - elems->country_elem = pos; - elems->country_elem_len = elen; - break; - case WLAN_EID_PWR_CONSTRAINT: - if (elen != 1) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->pwr_constr_elem = pos; - break; - case WLAN_EID_CISCO_VENDOR_SPECIFIC: - /* Lots of different options exist, but we only care - * about the Dynamic Transmit Power Control element. - * First check for the Cisco OUI, then for the DTPC - * tag (0x00). - */ - if (elen < 4) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - - if (pos[0] != 0x00 || pos[1] != 0x40 || - pos[2] != 0x96 || pos[3] != 0x00) - break; - - if (elen != 6) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - - if (calc_crc) - crc = crc32_be(crc, pos - 2, elen + 2); - - elems->cisco_dtpc_elem = pos; - break; - case WLAN_EID_ADDBA_EXT: - if (elen < sizeof(struct ieee80211_addba_ext_ie)) { - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - } - elems->addba_ext_ie = (void *)pos; - break; - case WLAN_EID_TIMEOUT_INTERVAL: - if (elen >= sizeof(struct ieee80211_timeout_interval_ie)) - elems->timeout_int = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_BSS_MAX_IDLE_PERIOD: - if (elen >= sizeof(*elems->max_idle_period_ie)) - elems->max_idle_period_ie = (void *)pos; - break; - case WLAN_EID_RSNX: - elems->rsnx = pos; - elems->rsnx_len = elen; - break; - case WLAN_EID_TX_POWER_ENVELOPE: - if (elen < 1 || - elen > sizeof(struct ieee80211_tx_pwr_env)) - break; - - if (elems->tx_pwr_env_num >= ARRAY_SIZE(elems->tx_pwr_env)) - break; - - elems->tx_pwr_env[elems->tx_pwr_env_num] = (void *)pos; - elems->tx_pwr_env_len[elems->tx_pwr_env_num] = elen; - elems->tx_pwr_env_num++; - break; - case WLAN_EID_EXTENSION: - ieee80211_parse_extension_element(calc_crc ? - &crc : NULL, - elem, elems, params); - break; - case WLAN_EID_S1G_CAPABILITIES: - if (params->mode != IEEE80211_CONN_MODE_S1G) - break; - if (elen >= sizeof(*elems->s1g_capab)) - elems->s1g_capab = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_S1G_OPERATION: - if (params->mode != IEEE80211_CONN_MODE_S1G) - break; - if (elen == sizeof(*elems->s1g_oper)) - elems->s1g_oper = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_S1G_BCN_COMPAT: - if (params->mode != IEEE80211_CONN_MODE_S1G) - break; - if (elen == sizeof(*elems->s1g_bcn_compat)) - elems->s1g_bcn_compat = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - case WLAN_EID_AID_RESPONSE: - if (params->mode != IEEE80211_CONN_MODE_S1G) - break; - if (elen == sizeof(struct ieee80211_aid_response_ie)) - elems->aid_resp = (void *)pos; - else - elem_parse_failed = - IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; - break; - default: - break; - } - - if (elem_parse_failed) - elems->parse_error |= elem_parse_failed; - else - __set_bit(id, seen_elems); - } - - if (!for_each_element_completed(elem, params->start, params->len)) - elems->parse_error |= IEEE80211_PARSE_ERR_INVALID_END; - - return crc; -} - -static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, - struct ieee802_11_elems *elems, - struct cfg80211_bss *bss, - u8 *nontransmitted_profile) -{ - const struct element *elem, *sub; - size_t profile_len = 0; - bool found = false; - - if (!bss || !bss->transmitted_bss) - return profile_len; - - for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) { - if (elem->datalen < 2) - continue; - if (elem->data[0] < 1 || elem->data[0] > 8) - continue; - - for_each_element(sub, elem->data + 1, elem->datalen - 1) { - u8 new_bssid[ETH_ALEN]; - const u8 *index; - - if (sub->id != 0 || sub->datalen < 4) { - /* not a valid BSS profile */ - continue; - } - - if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP || - sub->data[1] != 2) { - /* The first element of the - * Nontransmitted BSSID Profile is not - * the Nontransmitted BSSID Capability - * element. - */ - continue; - } - - memset(nontransmitted_profile, 0, len); - profile_len = cfg80211_merge_profile(start, len, - elem, - sub, - nontransmitted_profile, - len); - - /* found a Nontransmitted BSSID Profile */ - index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, - nontransmitted_profile, - profile_len); - if (!index || index[1] < 1 || index[2] == 0) { - /* Invalid MBSSID Index element */ - continue; - } - - cfg80211_gen_new_bssid(bss->transmitted_bss->bssid, - elem->data[0], - index[2], - new_bssid); - if (ether_addr_equal(new_bssid, bss->bssid)) { - found = true; - elems->bssid_index_len = index[1]; - elems->bssid_index = (void *)&index[2]; - break; - } - } - } - - return found ? profile_len : 0; -} - -static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, - u8 link_id) -{ - const struct ieee80211_multi_link_elem *ml = elems->ml_basic; - ssize_t ml_len = elems->ml_basic_len; - const struct element *sub; - - if (!ml || !ml_len) - return; - - if (le16_get_bits(ml->control, IEEE80211_ML_CONTROL_TYPE) != - IEEE80211_ML_CONTROL_TYPE_BASIC) - return; - - for_each_mle_subelement(sub, (u8 *)ml, ml_len) { - struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; - ssize_t sta_prof_len; - u16 control; - - if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) - continue; - - if (!ieee80211_mle_basic_sta_prof_size_ok(sub->data, - sub->datalen)) - return; - - control = le16_to_cpu(prof->control); - - if (link_id != u16_get_bits(control, - IEEE80211_MLE_STA_CONTROL_LINK_ID)) - continue; - - if (!(control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE)) - return; - - /* the sub element can be fragmented */ - sta_prof_len = - cfg80211_defragment_element(sub, - (u8 *)ml, ml_len, - elems->scratch_pos, - elems->scratch + - elems->scratch_len - - elems->scratch_pos, - IEEE80211_MLE_SUBELEM_FRAGMENT); - - if (sta_prof_len < 0) - return; - - elems->prof = (void *)elems->scratch_pos; - elems->sta_prof_len = sta_prof_len; - elems->scratch_pos += sta_prof_len; - - return; - } -} - -static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, - struct ieee80211_elems_parse_params *params) -{ - struct ieee80211_mle_per_sta_profile *prof; - struct ieee80211_elems_parse_params sub = { - .mode = params->mode, - .action = params->action, - .from_ap = params->from_ap, - .link_id = -1, - }; - ssize_t ml_len = elems->ml_basic_len; - const struct element *non_inherit = NULL; - const u8 *end; - - if (params->link_id == -1) - return; - - ml_len = cfg80211_defragment_element(elems->ml_basic_elem, - elems->ie_start, - elems->total_len, - elems->scratch_pos, - elems->scratch + - elems->scratch_len - - elems->scratch_pos, - WLAN_EID_FRAGMENT); - - if (ml_len < 0) - return; - - elems->ml_basic = (const void *)elems->scratch_pos; - elems->ml_basic_len = ml_len; - - ieee80211_mle_get_sta_prof(elems, params->link_id); - prof = elems->prof; - - if (!prof) - return; - - /* check if we have the 4 bytes for the fixed part in assoc response */ - if (elems->sta_prof_len < sizeof(*prof) + prof->sta_info_len - 1 + 4) { - elems->prof = NULL; - elems->sta_prof_len = 0; - return; - } - - /* - * Skip the capability information and the status code that are expected - * as part of the station profile in association response frames. Note - * the -1 is because the 'sta_info_len' is accounted to as part of the - * per-STA profile, but not part of the 'u8 variable[]' portion. - */ - sub.start = prof->variable + prof->sta_info_len - 1 + 4; - end = (const u8 *)prof + elems->sta_prof_len; - sub.len = end - sub.start; - - non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, - sub.start, sub.len); - _ieee802_11_parse_elems_full(&sub, elems, non_inherit); -} - -struct ieee802_11_elems * -ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) -{ - struct ieee802_11_elems *elems; - const struct element *non_inherit = NULL; - u8 *nontransmitted_profile; - int nontransmitted_profile_len = 0; - size_t scratch_len = 3 * params->len; - - elems = kzalloc(struct_size(elems, scratch, scratch_len), GFP_ATOMIC); - if (!elems) - return NULL; - elems->ie_start = params->start; - elems->total_len = params->len; - elems->scratch_len = scratch_len; - elems->scratch_pos = elems->scratch; - - nontransmitted_profile = elems->scratch_pos; - nontransmitted_profile_len = - ieee802_11_find_bssid_profile(params->start, params->len, - elems, params->bss, - nontransmitted_profile); - elems->scratch_pos += nontransmitted_profile_len; - elems->scratch_len -= nontransmitted_profile_len; - non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, - nontransmitted_profile, - nontransmitted_profile_len); - - elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit); - - /* Override with nontransmitted profile, if found */ - if (nontransmitted_profile_len) { - struct ieee80211_elems_parse_params sub = { - .mode = params->mode, - .start = nontransmitted_profile, - .len = nontransmitted_profile_len, - .action = params->action, - .link_id = params->link_id, - }; - - _ieee802_11_parse_elems_full(&sub, elems, NULL); - } - - ieee80211_mle_parse_link(elems, params); - - if (elems->tim && !elems->parse_error) { - const struct ieee80211_tim_ie *tim_ie = elems->tim; - - elems->dtim_period = tim_ie->dtim_period; - elems->dtim_count = tim_ie->dtim_count; - } - - /* Override DTIM period and count if needed */ - if (elems->bssid_index && - elems->bssid_index_len >= - offsetofend(struct ieee80211_bssid_index, dtim_period)) - elems->dtim_period = elems->bssid_index->dtim_period; - - if (elems->bssid_index && - elems->bssid_index_len >= - offsetofend(struct ieee80211_bssid_index, dtim_count)) - elems->dtim_count = elems->bssid_index->dtim_count; - - return elems; -} -EXPORT_SYMBOL_IF_KUNIT(ieee802_11_parse_elems_full); - void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, struct ieee80211_tx_queue_params *qparam, int ac) @@ -4063,35 +3201,6 @@ bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper, return true; } -int ieee80211_parse_bitrates(enum nl80211_chan_width width, - const struct ieee80211_supported_band *sband, - const u8 *srates, int srates_len, u32 *rates) -{ - u32 rate_flags = ieee80211_chanwidth_rate_flags(width); - struct ieee80211_rate *br; - int brate, rate, i, j, count = 0; - - *rates = 0; - - for (i = 0; i < srates_len; i++) { - rate = srates[i] & 0x7f; - - for (j = 0; j < sband->n_bitrates; j++) { - br = &sband->bitrates[j]; - if ((rate_flags & br->flags) != rate_flags) - continue; - - brate = DIV_ROUND_UP(br->bitrate, 5); - if (brate == rate) { - *rates |= BIT(j); - count++; - break; - } - } - } - return count; -} - int ieee80211_put_srates_elem(struct sk_buff *skb, const struct ieee80211_supported_band *sband, u32 basic_rates, u32 rate_flags, u32 masked_rates, From 28aa895bb0b324ed4a0cb441e5fbb882befb5e1c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:35 +0100 Subject: [PATCH 0929/2255] wifi: mac80211: convert ieee80211_ie_build_he_cap() to SKB use Convert ieee80211_ie_build_he_cap() to the SKB-put function style, renaming it to ieee80211_put_he_cap(). Link: https://msgid.link/20240129202041.e6ef888980d9.Ied9e014314b5d27611e693e3d4cb63bdc8d7de17@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 7 ++--- net/mac80211/mesh.c | 15 ++--------- net/mac80211/mlme.c | 37 +++----------------------- net/mac80211/tdls.c | 17 +++--------- net/mac80211/util.c | 54 +++++++++++++++++--------------------- 5 files changed, 37 insertions(+), 93 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index fde8c0b67125..de0fdbd366c5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2502,9 +2502,6 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, const struct cfg80211_chan_def *chandef); u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata); -u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, - const struct ieee80211_sta_he_cap *he_cap, - u8 *pos, u8 *end); u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef); u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef, const struct ieee80211_sta_eht_cap *eht_cap); @@ -2523,6 +2520,10 @@ int ieee80211_put_srates_elem(struct sk_buff *skb, const struct ieee80211_supported_band *sband, u32 basic_rates, u32 rate_flags, u32 masked_rates, u8 element_id); +int ieee80211_put_he_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + const struct ieee80211_supported_band *sband, + const struct ieee80211_conn_settings *conn); int ieee80211_put_he_6ghz_cap(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode smps_mode); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 7e860486c6bc..cb217657c42e 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -567,29 +567,18 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, u8 ie_len) { - const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_supported_band *sband; - u8 *pos; sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; - he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); - - if (!he_cap || - sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + if (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) - return -ENOMEM; - - pos = skb_put(skb, ie_len); - ieee80211_ie_build_he_cap(NULL, he_cap, pos, pos + ie_len); - - return 0; + return ieee80211_put_he_cap(skb, sdata, sband, NULL); } int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d807a904419c..de3d0e08ca2a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1038,38 +1038,6 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, return mu_mimo_owner; } -/* This function determines HE capability flags for the association - * and builds the IE. - */ -static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_supported_band *sband, - enum ieee80211_smps_mode smps_mode, - const struct ieee80211_conn_settings *conn) -{ - u8 *pos, *pre_he_pos; - const struct ieee80211_sta_he_cap *he_cap; - u8 he_cap_size; - - he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); - if (WARN_ON(!he_cap)) - return; - - /* get a max size estimate */ - he_cap_size = - 2 + 1 + sizeof(he_cap->he_cap_elem) + - ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) + - ieee80211_he_ppe_size(he_cap->ppe_thres[0], - he_cap->he_cap_elem.phy_cap_info); - pos = skb_put(skb, he_cap_size); - pre_he_pos = pos; - pos = ieee80211_ie_build_he_cap(conn, he_cap, pos, pos + he_cap_size); - /* trim excess if any */ - skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos)); - - ieee80211_put_he_6ghz_cap(skb, sdata, smps_mode); -} - static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_supported_band *sband, @@ -1403,9 +1371,10 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, offset); if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_HE) { - ieee80211_add_he_ie(sdata, skb, sband, smps_mode, - &assoc_data->link[link_id].conn); + ieee80211_put_he_cap(skb, sdata, sband, + &assoc_data->link[link_id].conn); ADD_PRESENT_EXT_ELEM(WLAN_EID_EXT_HE_CAPABILITY); + ieee80211_put_he_6ghz_cap(skb, sdata, smps_mode); } /* diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index edbd3fd8a737..3f9c2b2771c6 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -548,19 +548,10 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, } /* build the HE-cap from sband */ - if (he_cap && - (action_code == WLAN_TDLS_SETUP_REQUEST || - action_code == WLAN_TDLS_SETUP_RESPONSE || - action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) { - u8 cap_size; - - cap_size = - 2 + 1 + sizeof(he_cap->he_cap_elem) + - ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) + - ieee80211_he_ppe_size(he_cap->ppe_thres[0], - he_cap->he_cap_elem.phy_cap_info); - pos = skb_put(skb, cap_size); - pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, pos + cap_size); + if (action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE || + action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { + ieee80211_put_he_cap(skb, sdata, sband, NULL); /* Build HE 6Ghz capa IE from sband */ if (sband->band == NL80211_BAND_6GHZ) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c675ac59d2bb..4dcb62e9d4c6 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1352,19 +1352,14 @@ static int ieee80211_put_preq_ies_band(struct sk_buff *skb, *offset = noffset; } - he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); - if (he_cap && - cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), + if (cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE)) { - u8 *pos = skb_tail_pointer(skb); - u8 *end = pos + skb_tailroom(skb); - - pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, end); - if (!pos) - return -ENOBUFS; - skb_put(skb, pos - skb_tail_pointer(skb)); + err = ieee80211_put_he_cap(skb, sdata, sband, NULL); + if (err) + return err; } + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); if (eht_cap && @@ -2408,7 +2403,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, return pos; } -/* this may return more than ieee80211_ie_build_he_cap() will need */ +/* this may return more than ieee80211_put_he_6ghz_cap() will need */ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata) { const struct ieee80211_sta_he_cap *he_cap; @@ -2479,21 +2474,23 @@ ieee80211_get_adjusted_he_cap(const struct ieee80211_conn_settings *conn, } } -u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, - const struct ieee80211_sta_he_cap *he_cap, - u8 *pos, u8 *end) +int ieee80211_put_he_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + const struct ieee80211_supported_band *sband, + const struct ieee80211_conn_settings *conn) { + const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_he_cap_elem elem; + u8 *len; u8 n; u8 ie_len; - u8 *orig_pos = pos; if (!conn) conn = &ieee80211_conn_settings_unlimited; - /* Make sure we have place for the IE */ + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); if (!he_cap) - return orig_pos; + return 0; /* modify on stack first to calculate 'n' and 'ie_len' correctly */ ieee80211_get_adjusted_he_cap(conn, he_cap, &elem); @@ -2504,19 +2501,17 @@ u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, ieee80211_he_ppe_size(he_cap->ppe_thres[0], he_cap->he_cap_elem.phy_cap_info); - if ((end - pos) < ie_len) - return orig_pos; + if (skb_tailroom(skb) < ie_len) + return -ENOBUFS; - *pos++ = WLAN_EID_EXTENSION; - pos++; /* We'll set the size later below */ - *pos++ = WLAN_EID_EXT_HE_CAPABILITY; + skb_put_u8(skb, WLAN_EID_EXTENSION); + len = skb_put(skb, 1); /* We'll set the size later below */ + skb_put_u8(skb, WLAN_EID_EXT_HE_CAPABILITY); /* Fixed data */ - memcpy(pos, &elem, sizeof(elem)); - pos += sizeof(elem); + skb_put_data(skb, &elem, sizeof(elem)); - memcpy(pos, &he_cap->he_mcs_nss_supp, n); - pos += n; + skb_put_data(skb, &he_cap->he_mcs_nss_supp, n); /* Check if PPE Threshold should be present */ if ((he_cap->he_cap_elem.phy_cap_info[6] & @@ -2540,12 +2535,11 @@ u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn, n = DIV_ROUND_UP(n, 8); /* Copy PPE Thresholds */ - memcpy(pos, &he_cap->ppe_thres, n); - pos += n; + skb_put_data(skb, &he_cap->ppe_thres, n); end: - orig_pos[1] = (pos - orig_pos) - 2; - return pos; + *len = skb_tail_pointer(skb) - len - 1; + return 0; } int ieee80211_put_he_6ghz_cap(struct sk_buff *skb, From ea8af8be4232a3f476d8659319cab794be44e73b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:19:36 +0100 Subject: [PATCH 0930/2255] wifi: mac80211: convert ieee80211_ie_build_eht_cap() to SKB use Convert ieee80211_ie_build_eht_cap() to the SKB-put function style, renaming it to ieee80211_put_eht_cap(). Link: https://msgid.link/20240129202041.ece9769e3c94.Ibd17bea6311f0c7ba56f6c1803fa3208abaaebb9@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 10 ++--- net/mac80211/mesh.c | 17 +-------- net/mac80211/mlme.c | 39 +------------------- net/mac80211/tdls.c | 20 ++-------- net/mac80211/util.c | 75 +++++++++++++++----------------------- 5 files changed, 42 insertions(+), 119 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index de0fdbd366c5..f3edb1a148a7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2527,6 +2527,10 @@ int ieee80211_put_he_cap(struct sk_buff *skb, int ieee80211_put_he_6ghz_cap(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode smps_mode); +int ieee80211_put_eht_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + const struct ieee80211_supported_band *sband, + const struct ieee80211_conn_settings *conn); /* channel management */ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, @@ -2651,12 +2655,6 @@ void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache); void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache); u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata); -u8 *ieee80211_ie_build_eht_cap(const struct ieee80211_conn_settings *conn, - u8 *pos, - const struct ieee80211_sta_he_cap *he_cap, - const struct ieee80211_sta_eht_cap *eht_cap, - u8 *end, - bool for_ap); void ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index cb217657c42e..49f79512c144 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -636,31 +636,18 @@ int mesh_add_he_6ghz_cap_ie(struct ieee80211_sub_if_data *sdata, int mesh_add_eht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, u8 ie_len) { - const struct ieee80211_sta_he_cap *he_cap; - const struct ieee80211_sta_eht_cap *eht_cap; struct ieee80211_supported_band *sband; - u8 *pos; sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; - 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.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + if (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) - return -ENOMEM; - - pos = skb_put(skb, ie_len); - ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap, pos + ie_len, - false); - - return 0; + return ieee80211_put_eht_cap(skb, sdata, sband, NULL); } int mesh_add_eht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index de3d0e08ca2a..dd97f402a624 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1038,41 +1038,6 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, return mu_mimo_owner; } -static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_supported_band *sband, - const struct ieee80211_conn_settings *conn) -{ - u8 *pos, *pre_eht_pos; - const struct ieee80211_sta_he_cap *he_cap; - const struct ieee80211_sta_eht_cap *eht_cap; - u8 eht_cap_size; - - he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); - eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); - - /* - * EHT capabilities element is only added if the HE capabilities element - * was added so assume that 'he_cap' is valid and don't check it. - */ - if (WARN_ON(!he_cap || !eht_cap)) - return; - - eht_cap_size = - 2 + 1 + sizeof(eht_cap->eht_cap_elem) + - ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, - &eht_cap->eht_cap_elem, - false) + - ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], - eht_cap->eht_cap_elem.phy_cap_info); - pos = skb_put(skb, eht_cap_size); - pre_eht_pos = pos; - pos = ieee80211_ie_build_eht_cap(conn, pos, he_cap, eht_cap, - pos + eht_cap_size, false); - /* trim excess if any */ - skb_trim(skb, skb->len - (pre_eht_pos + eht_cap_size - pos)); -} - static void ieee80211_assoc_add_rates(struct sk_buff *skb, enum nl80211_chan_width width, struct ieee80211_supported_band *sband, @@ -1393,8 +1358,8 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, present_elems = NULL; if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_EHT) - ieee80211_add_eht_ie(sdata, skb, sband, - &assoc_data->link[link_id].conn); + ieee80211_put_eht_cap(skb, sdata, sband, + &assoc_data->link[link_id].conn); if (sband->band == NL80211_BAND_S1GHZ) { ieee80211_add_aid_request_ie(sdata, skb); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 3f9c2b2771c6..42d9c06cbb84 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -575,22 +575,10 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, } /* build the EHT-cap from sband */ - if (he_cap && eht_cap && - (action_code == WLAN_TDLS_SETUP_REQUEST || - action_code == WLAN_TDLS_SETUP_RESPONSE || - action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) { - u8 cap_size; - - cap_size = - 2 + 1 + sizeof(eht_cap->eht_cap_elem) + - ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, - &eht_cap->eht_cap_elem, false) + - ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], - eht_cap->eht_cap_elem.phy_cap_info); - pos = skb_put(skb, cap_size); - ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap, - pos + cap_size, false); - } + if (action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE || + action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) + ieee80211_put_eht_cap(skb, sdata, sband, NULL); /* add any remaining IEs */ if (extra_ies_len) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4dcb62e9d4c6..627bd5a8bda5 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1199,8 +1199,6 @@ static int ieee80211_put_preq_ies_band(struct sk_buff *skb, { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - const struct ieee80211_sta_he_cap *he_cap; - const struct ieee80211_sta_eht_cap *eht_cap; int i, err; size_t noffset; u32 rate_flags; @@ -1359,22 +1357,12 @@ static int ieee80211_put_preq_ies_band(struct sk_buff *skb, return err; } - he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); - eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); - - if (eht_cap && - cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), + if (cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE | IEEE80211_CHAN_NO_EHT)) { - u8 *pos = skb_tail_pointer(skb); - u8 *end = pos + skb_tailroom(skb); - - pos = ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap, - end, - sdata->vif.type == NL80211_IFTYPE_AP); - if (!pos) - return -ENOBUFS; - skb_put(skb, pos - skb_tail_pointer(skb)); + err = ieee80211_put_eht_cap(skb, sdata, sband, NULL); + if (err) + return err; } err = ieee80211_put_he_6ghz_cap(skb, sdata, IEEE80211_SMPS_OFF); @@ -4175,7 +4163,7 @@ u16 ieee80211_encode_usf(int listen_interval) return (u16) listen_interval; } -/* this may return more than ieee80211_ie_build_eht_cap() will need */ +/* this may return more than ieee80211_put_eht_cap() will need */ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata) { const struct ieee80211_sta_he_cap *he_cap; @@ -4205,25 +4193,28 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata) return 0; } -u8 *ieee80211_ie_build_eht_cap(const struct ieee80211_conn_settings *conn, - u8 *pos, - const struct ieee80211_sta_he_cap *he_cap, - const struct ieee80211_sta_eht_cap *eht_cap, - u8 *end, bool for_ap) +int ieee80211_put_eht_cap(struct sk_buff *skb, + struct ieee80211_sub_if_data *sdata, + const struct ieee80211_supported_band *sband, + const struct ieee80211_conn_settings *conn) { - struct ieee80211_eht_cap_elem_fixed fixed, *out; + const struct ieee80211_sta_he_cap *he_cap = + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + const struct ieee80211_sta_eht_cap *eht_cap = + ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); + bool for_ap = sdata->vif.type == NL80211_IFTYPE_AP; + struct ieee80211_eht_cap_elem_fixed fixed; struct ieee80211_he_cap_elem he; u8 mcs_nss_len, ppet_len; u8 orig_mcs_nss_len; u8 ie_len; - u8 *orig_pos = pos; if (!conn) conn = &ieee80211_conn_settings_unlimited; /* Make sure we have place for the IE */ if (!he_cap || !eht_cap) - return orig_pos; + return 0; orig_mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, &eht_cap->eht_cap_elem, @@ -4266,16 +4257,13 @@ u8 *ieee80211_ie_build_eht_cap(const struct ieee80211_conn_settings *conn, fixed.phy_cap_info); ie_len = 2 + 1 + sizeof(eht_cap->eht_cap_elem) + mcs_nss_len + ppet_len; - if ((end - pos) < ie_len) - return orig_pos; + if (skb_tailroom(skb) < ie_len) + return -ENOBUFS; - *pos++ = WLAN_EID_EXTENSION; - *pos++ = ie_len - 2; - *pos++ = WLAN_EID_EXT_EHT_CAPABILITY; - - out = (void *)pos; - *out = fixed; - pos += sizeof(*out); + skb_put_u8(skb, WLAN_EID_EXTENSION); + skb_put_u8(skb, ie_len - 2); + skb_put_u8(skb, WLAN_EID_EXT_EHT_CAPABILITY); + skb_put_data(skb, &fixed, sizeof(fixed)); if (mcs_nss_len == 4 && orig_mcs_nss_len != 4) { /* @@ -4284,21 +4272,18 @@ u8 *ieee80211_ie_build_eht_cap(const struct ieee80211_conn_settings *conn, * the groups 0-7, 8-9, 10-11, 12-13 rather than just 0-9, * 10-11, 12-13. Thus, use 0-9 for 0-7 and 8-9. */ - *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs9_max_nss; - *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs9_max_nss; - *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs11_max_nss; - *pos++ = eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs13_max_nss; + skb_put_u8(skb, eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs9_max_nss); + skb_put_u8(skb, eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs9_max_nss); + skb_put_u8(skb, eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs11_max_nss); + skb_put_u8(skb, eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_mcs13_max_nss); } else { - memcpy(pos, &eht_cap->eht_mcs_nss_supp, mcs_nss_len); - pos += mcs_nss_len; + skb_put_data(skb, &eht_cap->eht_mcs_nss_supp, mcs_nss_len); } - if (ppet_len) { - memcpy(pos, &eht_cap->eht_ppe_thres, ppet_len); - pos += ppet_len; - } + if (ppet_len) + skb_put_data(skb, &eht_cap->eht_ppe_thres, ppet_len); - return pos; + return 0; } const char *ieee80211_conn_mode_str(enum ieee80211_conn_mode mode) From 55167a3eed53ce8b40d5bf2a3e0be4e15d2eba57 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:35:45 +0100 Subject: [PATCH 0931/2255] wifi: mac80211: allow CSA to same channel This could be used e.g. for temporarily sending quiet (mode=1 in CSA/ECSA), or updating bandwidth. This is also useful for testing, since it's something that an AP may do and the client needs to be prepared. Simply allow it. Link: https://msgid.link/20240129203544.ef7258d5790d.Idafe22e41621757458d4960659b9621853f7104d@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2ddaf0037952..17b445491881 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3876,10 +3876,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (sdata->wdev.cac_started) return -EBUSY; - if (cfg80211_chandef_identical(&chanreq.oper, - &sdata->vif.bss_conf.chanreq.oper)) - return -EINVAL; - if (chanreq.oper.punctured && !sdata->vif.bss_conf.eht_support) return -EINVAL; From 91cdcbbcde1092da5225cfb05c88961658a34353 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 16:49:11 +0100 Subject: [PATCH 0932/2255] wifi: mac80211: clarify vif handling in TX dequeue The vif pointer at least looks like it can actually be NULL in some cases such as the monitor-mode vif, causing static checkers to complain with the immediate derefence. In these cases the sta pointer will also be NULL, but clarify it in the code anyway. Link: https://msgid.link/20240131164910.60066625a239.Idfb6a5a9876f9f631eae760055e1c4018259a971@changeid Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f57f7963ca37..098b32947c2b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3953,7 +3953,8 @@ begin: ieee80211_free_txskb(&local->hw, skb); goto begin; } else { - vif = NULL; + info->control.vif = NULL; + return skb; } break; case NL80211_IFTYPE_AP_VLAN: From 03145a1d5d38eb1fe79d3bc01d37bf4f28076796 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 13:45:55 +0100 Subject: [PATCH 0933/2255] wifi: mac80211: add missing kernel-doc for fast_tx_check This was added earlier, add kernel-doc for it. Link: https://msgid.link/20240206134555.6354b0ac8610.Ib90d3651834c556b73697388f59bd396a1f6f9b0@changeid Signed-off-by: Johannes Berg --- net/mac80211/mesh.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index ad8469293d71..d913ce7ba72e 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation * Authors: Luis Carlos Cobo * Javier Cardona */ @@ -94,6 +94,7 @@ enum mesh_deferred_task_flags { * @is_root: the destination station of this path is a root node * @is_gate: the destination station of this path is a mesh gate * @path_change_count: the number of path changes to destination + * @fast_tx_check: timestamp of last fast-xmit enable attempt * * * The dst address is unique in the mesh path table. Since the mesh_path is From 84d3776ef71df5ef3631021536d6b04e2383ebc8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 13:45:56 +0100 Subject: [PATCH 0934/2255] 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(-) 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 From 37c37096ad80bfa38ab427f33f58124e043fa2fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Feb 2024 11:59:20 +0100 Subject: [PATCH 0935/2255] wifi: mac80211: don't use sband->band early Some drivers may (notably mt76 does) not set up sband->band before registering, and cfg80211 will fill it in later. But since the HT/HE capability check mac80211 required it to be initialized already, otherwise failing things. This really isn't necessary though since the code is iterating the list of bands, and has the 'band' variable available. Fix it to not require the sband->band to be initialized already. Fixes: f04d2c247e04 ("wifi: mac80211: disallow drivers with HT wider than HE") Reported-by: Bert Karwatzki Debugged-by: Bert Karwatzki Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218466 Link: https://msgid.link/20240207115920.43cbedffb5c3.I4968e12275a3f95926e3f3ccae81e50f23fe4d4d@changeid Signed-off-by: Johannes Berg --- net/mac80211/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 879abe216a3e..4eaea0a9975b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1259,7 +1259,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) supp_he = supp_he || iftd->he_cap.has_he; supp_eht = supp_eht || iftd->eht_cap.has_eht; - if (sband->band == NL80211_BAND_2GHZ) + if (band == NL80211_BAND_2GHZ) he_40_mhz_cap = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; else From f29a8be886f5dd12b97624a87d6c46e2cf8d1821 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 6 Feb 2024 16:08:52 +0300 Subject: [PATCH 0936/2255] 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(-) 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) From 68de13028b94572fc570b7eb1e0e2de1d751fe7e Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Fri, 22 Dec 2023 09:09:13 +0800 Subject: [PATCH 0937/2255] wifi: cfg80211: Add utility for converting op_class into chandef This utility is used in STA CSA handling. The op_class in the ECSA Element can be converted into chandef. Co-developed-by: Money Wang Signed-off-by: Michael-CY Lee Link: https://msgid.link/20231222010914.6521-2-michael-cy.lee@mediatek.com Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 13 ++++++++ net/wireless/util.c | 76 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index cb5e34d640cd..e27ed2307cdb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -8774,6 +8774,19 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev, bool ieee80211_operating_class_to_band(u8 operating_class, enum nl80211_band *band); +/** + * ieee80211_operating_class_to_chandef - convert operating class to chandef + * + * @operating_class: the operating class to convert + * @chan: the ieee80211_channel to convert + * @chandef: a pointer to the resulting chandef + * + * Returns %true if the conversion was successful, %false otherwise. + */ +bool ieee80211_operating_class_to_chandef(u8 operating_class, + struct ieee80211_channel *chan, + struct cfg80211_chan_def *chandef); + /** * ieee80211_chandef_to_operating_class - convert chandef to operation class * diff --git a/net/wireless/util.c b/net/wireless/util.c index d1ce3bee2797..379f742fd741 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -2073,6 +2073,82 @@ bool ieee80211_operating_class_to_band(u8 operating_class, } EXPORT_SYMBOL(ieee80211_operating_class_to_band); +bool ieee80211_operating_class_to_chandef(u8 operating_class, + struct ieee80211_channel *chan, + struct cfg80211_chan_def *chandef) +{ + u32 control_freq, offset = 0; + enum nl80211_band band; + + if (!ieee80211_operating_class_to_band(operating_class, &band) || + !chan || band != chan->band) + return false; + + control_freq = chan->center_freq; + chandef->chan = chan; + + if (control_freq >= 5955) + offset = control_freq - 5955; + else if (control_freq >= 5745) + offset = control_freq - 5745; + else if (control_freq >= 5180) + offset = control_freq - 5180; + offset /= 20; + + switch (operating_class) { + case 81: /* 2 GHz band; 20 MHz; channels 1..13 */ + case 82: /* 2 GHz band; 20 MHz; channel 14 */ + case 115: /* 5 GHz band; 20 MHz; channels 36,40,44,48 */ + case 118: /* 5 GHz band; 20 MHz; channels 52,56,60,64 */ + case 121: /* 5 GHz band; 20 MHz; channels 100..144 */ + case 124: /* 5 GHz band; 20 MHz; channels 149,153,157,161 */ + case 125: /* 5 GHz band; 20 MHz; channels 149..177 */ + case 131: /* 6 GHz band; 20 MHz; channels 1..233*/ + case 136: /* 6 GHz band; 20 MHz; channel 2 */ + chandef->center_freq1 = control_freq; + chandef->width = NL80211_CHAN_WIDTH_20; + return true; + case 83: /* 2 GHz band; 40 MHz; channels 1..9 */ + case 116: /* 5 GHz band; 40 MHz; channels 36,44 */ + case 119: /* 5 GHz band; 40 MHz; channels 52,60 */ + case 122: /* 5 GHz band; 40 MHz; channels 100,108,116,124,132,140 */ + case 126: /* 5 GHz band; 40 MHz; channels 149,157,165,173 */ + chandef->center_freq1 = control_freq + 10; + chandef->width = NL80211_CHAN_WIDTH_40; + return true; + case 84: /* 2 GHz band; 40 MHz; channels 5..13 */ + case 117: /* 5 GHz band; 40 MHz; channels 40,48 */ + case 120: /* 5 GHz band; 40 MHz; channels 56,64 */ + case 123: /* 5 GHz band; 40 MHz; channels 104,112,120,128,136,144 */ + case 127: /* 5 GHz band; 40 MHz; channels 153,161,169,177 */ + chandef->center_freq1 = control_freq - 10; + chandef->width = NL80211_CHAN_WIDTH_40; + return true; + case 132: /* 6 GHz band; 40 MHz; channels 1,5,..,229*/ + chandef->center_freq1 = control_freq + 10 - (offset & 1) * 20; + chandef->width = NL80211_CHAN_WIDTH_40; + return true; + case 128: /* 5 GHz band; 80 MHz; channels 36..64,100..144,149..177 */ + case 133: /* 6 GHz band; 80 MHz; channels 1,5,..,229 */ + chandef->center_freq1 = control_freq + 30 - (offset & 3) * 20; + chandef->width = NL80211_CHAN_WIDTH_80; + return true; + case 129: /* 5 GHz band; 160 MHz; channels 36..64,100..144,149..177 */ + case 134: /* 6 GHz band; 160 MHz; channels 1,5,..,229 */ + chandef->center_freq1 = control_freq + 70 - (offset & 7) * 20; + chandef->width = NL80211_CHAN_WIDTH_160; + return true; + case 130: /* 5 GHz band; 80+80 MHz; channels 36..64,100..144,149..177 */ + case 135: /* 6 GHz band; 80+80 MHz; channels 1,5,..,229 */ + /* The center_freq2 of 80+80 MHz is unknown */ + case 137: /* 6 GHz band; 320 MHz; channels 1,5,..,229 */ + /* 320-1 or 320-2 channelization is unknown */ + default: + return false; + } +} +EXPORT_SYMBOL(ieee80211_operating_class_to_chandef); + bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, u8 *op_class) { From 21c3f8f95554feff9bed15703e89adbe582e0383 Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Fri, 22 Dec 2023 09:09:14 +0800 Subject: [PATCH 0938/2255] wifi: mac80211: refactor STA CSA parsing flows The new Wi-Fi Standard (IEEE Std 802.11-2020 9.4.2.160) specifies that the Wide Bandwidth Channel Switch (WBCS) Element subfields have the same definitions as VHT operation information if the operating band is not S1G. The problem comes when the BSS is in 6 GHz band, the STA parses the WBCS Element by ieee80211_chandef_vht_oper(), which checks the capabilities for HT/VHT mode, not HE/EHT mode. This patch refactors STA CSA parsing flow so that the corresponding capabilities can be checked. Also, it adds the way to use op_class in ECSA Element to build a new chandef. In summary, the new steps for STA to handle CSA event are: 1. build the new chandef from one of the CSA-related (Sub)Elements in following order, - Bandwidth Indication (Sub)Element - Wide Bandwidth Channel Switch (Sub)Element - Operating class in Extended Channel Switch Announcement Element - Channel Switch Announcement Element 2. convert the new chandef into operation information according to the operating band in order to check if the new chandef fits STA's capabilities. 3. downgrade the bandwidth until current bandwidth is not disabled. Co-developed-by: Money Wang Signed-off-by: Michael-CY Lee Link: https://msgid.link/20231222010914.6521-3-michael-cy.lee@mediatek.com [rebase on top of the changes with struct ieee80211_conn_settings, prefer leXY_encode_bits()] Signed-off-by: Johannes Berg --- net/mac80211/spectmgmt.c | 306 ++++++++++++++++++++++++++++++++------- 1 file changed, 252 insertions(+), 54 deletions(-) diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 2b0bf2a1a877..327c74e296e2 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -19,6 +19,205 @@ #include "sta_info.h" #include "wme.h" +static bool +wbcs_elem_to_chandef(const struct ieee80211_wide_bw_chansw_ie *wbcs_elem, + struct cfg80211_chan_def *chandef) +{ + u8 ccfs0 = wbcs_elem->new_center_freq_seg0; + u8 ccfs1 = wbcs_elem->new_center_freq_seg1; + u32 cf0 = ieee80211_channel_to_frequency(ccfs0, chandef->chan->band); + u32 cf1 = ieee80211_channel_to_frequency(ccfs1, chandef->chan->band); + + switch (wbcs_elem->new_channel_width) { + case IEEE80211_VHT_CHANWIDTH_160MHZ: + /* deprecated encoding */ + chandef->width = NL80211_CHAN_WIDTH_160; + chandef->center_freq1 = cf0; + break; + case IEEE80211_VHT_CHANWIDTH_80P80MHZ: + /* deprecated encoding */ + chandef->width = NL80211_CHAN_WIDTH_80P80; + chandef->center_freq1 = cf0; + chandef->center_freq2 = cf1; + break; + case IEEE80211_VHT_CHANWIDTH_80MHZ: + chandef->width = NL80211_CHAN_WIDTH_80; + chandef->center_freq1 = cf0; + + if (ccfs1) { + u8 diff = abs(ccfs0 - ccfs1); + + if (diff == 8) { + chandef->width = NL80211_CHAN_WIDTH_160; + chandef->center_freq1 = cf1; + } else if (diff > 8) { + chandef->width = NL80211_CHAN_WIDTH_80P80; + chandef->center_freq2 = cf1; + } + } + break; + case IEEE80211_VHT_CHANWIDTH_USE_HT: + default: + /* If the WBCS Element is present, new channel bandwidth is + * at least 40 MHz. + */ + chandef->width = NL80211_CHAN_WIDTH_40; + chandef->center_freq1 = cf0; + break; + } + + return cfg80211_chandef_valid(chandef); +} + +static void +validate_chandef_by_ht_vht_oper(struct ieee80211_sub_if_data *sdata, + struct ieee80211_conn_settings *conn, + u32 vht_cap_info, + struct cfg80211_chan_def *chandef) +{ + u32 control_freq, center_freq1, center_freq2; + enum nl80211_chan_width chan_width; + struct ieee80211_ht_operation ht_oper; + struct ieee80211_vht_operation vht_oper; + + if (conn->mode < IEEE80211_CONN_MODE_HT || + conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) { + chandef->chan = NULL; + return; + } + + control_freq = chandef->chan->center_freq; + center_freq1 = chandef->center_freq1; + center_freq2 = chandef->center_freq2; + chan_width = chandef->width; + + ht_oper.primary_chan = ieee80211_frequency_to_channel(control_freq); + if (control_freq != center_freq1) + ht_oper.ht_param = control_freq > center_freq1 ? + IEEE80211_HT_PARAM_CHA_SEC_BELOW : + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + else + ht_oper.ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; + + ieee80211_chandef_ht_oper(&ht_oper, chandef); + + if (conn->mode < IEEE80211_CONN_MODE_VHT) + return; + + vht_oper.center_freq_seg0_idx = + ieee80211_frequency_to_channel(center_freq1); + vht_oper.center_freq_seg1_idx = center_freq2 ? + ieee80211_frequency_to_channel(center_freq2) : 0; + + switch (chan_width) { + case NL80211_CHAN_WIDTH_320: + WARN_ON(1); + break; + case NL80211_CHAN_WIDTH_160: + vht_oper.chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; + vht_oper.center_freq_seg1_idx = vht_oper.center_freq_seg0_idx; + vht_oper.center_freq_seg0_idx += + control_freq < center_freq1 ? -8 : 8; + break; + case NL80211_CHAN_WIDTH_80P80: + vht_oper.chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; + break; + case NL80211_CHAN_WIDTH_80: + vht_oper.chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; + break; + default: + vht_oper.chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT; + break; + } + + ht_oper.operation_mode = + le16_encode_bits(vht_oper.center_freq_seg1_idx, + IEEE80211_HT_OP_MODE_CCFS2_MASK); + + if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, + &vht_oper, &ht_oper, chandef)) + chandef->chan = NULL; +} + +static void +validate_chandef_by_6ghz_he_eht_oper(struct ieee80211_sub_if_data *sdata, + struct ieee80211_conn_settings *conn, + struct cfg80211_chan_def *chandef) +{ + struct ieee80211_local *local = sdata->local; + u32 control_freq, center_freq1, center_freq2; + enum nl80211_chan_width chan_width; + struct { + struct ieee80211_he_operation _oper; + struct ieee80211_he_6ghz_oper _6ghz_oper; + } __packed he; + struct { + struct ieee80211_eht_operation _oper; + struct ieee80211_eht_operation_info _oper_info; + } __packed eht; + + if (conn->mode < IEEE80211_CONN_MODE_HE) { + chandef->chan = NULL; + return; + } + + control_freq = chandef->chan->center_freq; + center_freq1 = chandef->center_freq1; + center_freq2 = chandef->center_freq2; + chan_width = chandef->width; + + he._oper.he_oper_params = + le32_encode_bits(1, IEEE80211_HE_OPERATION_6GHZ_OP_INFO); + he._6ghz_oper.primary = + ieee80211_frequency_to_channel(control_freq); + he._6ghz_oper.ccfs0 = ieee80211_frequency_to_channel(center_freq1); + he._6ghz_oper.ccfs1 = center_freq2 ? + ieee80211_frequency_to_channel(center_freq2) : 0; + + switch (chan_width) { + case NL80211_CHAN_WIDTH_320: + he._6ghz_oper.ccfs1 = he._6ghz_oper.ccfs0; + he._6ghz_oper.ccfs0 += control_freq < center_freq1 ? -16 : 16; + he._6ghz_oper.control = IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ; + break; + case NL80211_CHAN_WIDTH_160: + he._6ghz_oper.ccfs1 = he._6ghz_oper.ccfs0; + he._6ghz_oper.ccfs0 += control_freq < center_freq1 ? -8 : 8; + fallthrough; + case NL80211_CHAN_WIDTH_80P80: + he._6ghz_oper.control = + IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ; + break; + case NL80211_CHAN_WIDTH_80: + he._6ghz_oper.control = + IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ; + break; + case NL80211_CHAN_WIDTH_40: + he._6ghz_oper.control = + IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ; + break; + default: + he._6ghz_oper.control = + IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ; + break; + } + + if (conn->mode < IEEE80211_CONN_MODE_EHT) { + if (!ieee80211_chandef_he_6ghz_oper(local, &he._oper, + NULL, chandef)) + chandef->chan = NULL; + } else { + eht._oper.params = IEEE80211_EHT_OPER_INFO_PRESENT; + eht._oper_info.control = he._6ghz_oper.control; + eht._oper_info.ccfs0 = he._6ghz_oper.ccfs0; + eht._oper_info.ccfs1 = he._6ghz_oper.ccfs1; + + if (!ieee80211_chandef_he_6ghz_oper(local, &he._oper, + &eht._oper, chandef)) + chandef->chan = NULL; + } +} + int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, enum nl80211_band current_band, @@ -29,12 +228,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, { enum nl80211_band new_band = current_band; int new_freq; - u8 new_chan_no; + u8 new_chan_no = 0, new_op_class = 0; struct ieee80211_channel *new_chan; - struct cfg80211_chan_def new_vht_chandef = {}; + struct cfg80211_chan_def new_chandef = {}; const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; const struct ieee80211_bandwidth_indication *bwi; + const struct ieee80211_ext_chansw_ie *ext_chansw_elem; int secondary_channel_offset = -1; memset(csa_ie, 0, sizeof(*csa_ie)); @@ -42,6 +242,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, sec_chan_offs = elems->sec_chan_offs; wide_bw_chansw_ie = elems->wide_bw_chansw_ie; bwi = elems->bandwidth_indication; + ext_chansw_elem = elems->ext_chansw_ie; if (conn->mode < IEEE80211_CONN_MODE_HT || conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) { @@ -52,26 +253,30 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, if (conn->mode < IEEE80211_CONN_MODE_VHT) wide_bw_chansw_ie = NULL; - if (elems->ext_chansw_ie) { - if (!ieee80211_operating_class_to_band( - elems->ext_chansw_ie->new_operating_class, - &new_band)) { - sdata_info(sdata, - "cannot understand ECSA IE operating class, %d, ignoring\n", - elems->ext_chansw_ie->new_operating_class); + if (ext_chansw_elem) { + new_op_class = ext_chansw_elem->new_operating_class; + + if (!ieee80211_operating_class_to_band(new_op_class, &new_band)) { + new_op_class = 0; + sdata_info(sdata, "cannot understand ECSA IE operating class, %d, ignoring\n", + ext_chansw_elem->new_operating_class); + } else { + new_chan_no = ext_chansw_elem->new_ch_num; + csa_ie->count = ext_chansw_elem->count; + csa_ie->mode = ext_chansw_elem->mode; } - new_chan_no = elems->ext_chansw_ie->new_ch_num; - csa_ie->count = elems->ext_chansw_ie->count; - csa_ie->mode = elems->ext_chansw_ie->mode; - } else if (elems->ch_switch_ie) { + } + + if (!new_op_class && elems->ch_switch_ie) { new_chan_no = elems->ch_switch_ie->new_ch_num; csa_ie->count = elems->ch_switch_ie->count; csa_ie->mode = elems->ch_switch_ie->mode; - } else { - /* nothing here we understand */ - return 1; } + /* nothing here we understand */ + if (!new_chan_no) + return 1; + /* Mesh Channel Switch Parameters Element */ if (elems->mesh_chansw_params_ie) { csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl; @@ -135,55 +340,48 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, break; } + /* parse one of the Elements to build a new chandef */ + memset(&new_chandef, 0, sizeof(new_chandef)); + new_chandef.chan = new_chan; if (bwi) { /* start with the CSA one */ - new_vht_chandef = csa_ie->chanreq.oper; + new_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) { - u8 new_seg1 = wide_bw_chansw_ie->new_center_freq_seg1; - struct ieee80211_vht_operation vht_oper = { - .chan_width = - wide_bw_chansw_ie->new_channel_width, - .center_freq_seg0_idx = - wide_bw_chansw_ie->new_center_freq_seg0, - .center_freq_seg1_idx = new_seg1, - /* .basic_mcs_set doesn't matter */ - }; - struct ieee80211_ht_operation ht_oper = { - .operation_mode = - cpu_to_le16(new_seg1 << - IEEE80211_HT_OP_MODE_CCFS2_SHIFT), - }; - - /* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT, - * to the previously parsed chandef - */ - new_vht_chandef = csa_ie->chanreq.oper; - - /* ignore if parsing fails */ - if (!ieee80211_chandef_vht_oper(&sdata->local->hw, - vht_cap_info, - &vht_oper, &ht_oper, - &new_vht_chandef)) - new_vht_chandef.chan = NULL; - - if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160 && - (new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80 || - new_vht_chandef.width == NL80211_CHAN_WIDTH_160)) - ieee80211_chandef_downgrade(&new_vht_chandef, NULL); + ieee80211_chandef_eht_oper(&bwi->info, &new_chandef); + } else if (!wide_bw_chansw_ie || !wbcs_elem_to_chandef(wide_bw_chansw_ie, + &new_chandef)) { + if (!ieee80211_operating_class_to_chandef(new_op_class, new_chan, + &new_chandef)) + new_chandef = csa_ie->chanreq.oper; } - /* if VHT data is there validate & use it */ - if (new_vht_chandef.chan) { - if (!cfg80211_chandef_compatible(&new_vht_chandef, + /* check if the new chandef fits the capabilities */ + if (new_band == NL80211_BAND_6GHZ) + validate_chandef_by_6ghz_he_eht_oper(sdata, conn, &new_chandef); + else + validate_chandef_by_ht_vht_oper(sdata, conn, vht_cap_info, + &new_chandef); + + /* if data is there validate the bandwidth & use it */ + if (new_chandef.chan) { + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320 && + new_chandef.width == NL80211_CHAN_WIDTH_320) + ieee80211_chandef_downgrade(&new_chandef, NULL); + + if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160 && + (new_chandef.width == NL80211_CHAN_WIDTH_80P80 || + new_chandef.width == NL80211_CHAN_WIDTH_160)) + ieee80211_chandef_downgrade(&new_chandef, NULL); + + if (!cfg80211_chandef_compatible(&new_chandef, &csa_ie->chanreq.oper)) { sdata_info(sdata, "BSS %pM: CSA has inconsistent channel data, disconnecting\n", bssid); return -EINVAL; } - csa_ie->chanreq.oper = new_vht_chandef; + + csa_ie->chanreq.oper = new_chandef; } if (elems->max_channel_switch_time) From 4ace04c0bdbde3b028ec0a5a3be2471cdb1efb67 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 30 Jan 2024 19:39:14 +0530 Subject: [PATCH 0939/2255] wifi: cfg80211: send link id in channel_switch ops Currently, during channel switch, no link id information is passed down. In order to support channel switch during Multi Link Operation, it is required to pass link id as well. Add changes to pass link id in the channel_switch cfg80211_ops. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240130140918.1172387-2-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 +++ net/wireless/nl80211.c | 1 + net/wireless/trace.h | 7 +++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e27ed2307cdb..d4c83ea3213d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1543,6 +1543,8 @@ 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 + * @link_id: defines the link on which channel switch is expected during + * MLO. 0 in case of non-MLO. */ struct cfg80211_csa_settings { struct cfg80211_chan_def chandef; @@ -1555,6 +1557,7 @@ struct cfg80211_csa_settings { bool radar_required; bool block_tx; u8 count; + u8 link_id; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b533412ad1e0..e1106ae35e21 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10222,6 +10222,7 @@ skip_beacons: if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) params.block_tx = true; + params.link_id = link_id; err = rdev_channel_switch(rdev, dev, ¶ms); free: diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ae5e585b6863..194ea2471717 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2332,6 +2332,7 @@ TRACE_EVENT(rdev_channel_switch, __field(u8, count) __dynamic_array(u16, bcn_ofs, params->n_counter_offsets_beacon) __dynamic_array(u16, pres_ofs, params->n_counter_offsets_presp) + __field(u8, link_id) ), TP_fast_assign( WIPHY_ASSIGN; @@ -2349,11 +2350,13 @@ TRACE_EVENT(rdev_channel_switch, memcpy(__get_dynamic_array(pres_ofs), params->counter_offsets_presp, params->n_counter_offsets_presp * sizeof(u16)); + __entry->link_id = params->link_id; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT - ", block_tx: %d, count: %u, radar_required: %d", + ", block_tx: %d, count: %u, radar_required: %d, link_id: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, - __entry->block_tx, __entry->count, __entry->radar_required) + __entry->block_tx, __entry->count, __entry->radar_required, + __entry->link_id) ); TRACE_EVENT(rdev_set_qos_map, From 480e7048aa0bbf0a79a976cdfa0195fd157da902 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 30 Jan 2024 19:39:15 +0530 Subject: [PATCH 0940/2255] 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(-) 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); } From a3a637a6c07189fab06a06c1f435331da652383b Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 30 Jan 2024 19:39:16 +0530 Subject: [PATCH 0941/2255] wifi: mac80211: handle set csa/after_csa beacon on per link basis In order to support CSA with MLO, there is a need to handle the functions ieee80211_set_csa_beacon() and ieee80211_set_after_csa_beacon() on a per link basis. Implement this by making the function argument accept the the link data instead of the sdata. Currently, deflink would only be passed. Proper link data will be passed in a subsequent patch. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240130140918.1172387-4-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 17b445491881..0c0f418c3652 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3590,20 +3590,21 @@ void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_t } EXPORT_SYMBOL(ieee80211_channel_switch_disconnect); -static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, +static int ieee80211_set_after_csa_beacon(struct ieee80211_link_data *link_data, u64 *changed) { + struct ieee80211_sub_if_data *sdata = link_data->sdata; int err; switch (sdata->vif.type) { case NL80211_IFTYPE_AP: - if (!sdata->deflink.u.ap.next_beacon) + if (!link_data->u.ap.next_beacon) return -EINVAL; - err = ieee80211_assign_beacon(sdata, &sdata->deflink, - sdata->deflink.u.ap.next_beacon, + err = ieee80211_assign_beacon(sdata, link_data, + link_data->u.ap.next_beacon, NULL, NULL, changed); - ieee80211_free_next_beacon(&sdata->deflink); + ieee80211_free_next_beacon(link_data); if (err < 0) return err; @@ -3662,7 +3663,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) sdata->vif.bss_conf.csa_active = false; - err = ieee80211_set_after_csa_beacon(sdata, &changed); + err = ieee80211_set_after_csa_beacon(&sdata->deflink, &changed); if (err) return err; @@ -3714,18 +3715,19 @@ void ieee80211_csa_finalize_work(struct wiphy *wiphy, struct wiphy_work *work) ieee80211_csa_finalize(link); } -static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, +static int ieee80211_set_csa_beacon(struct ieee80211_link_data *link_data, struct cfg80211_csa_settings *params, u64 *changed) { + struct ieee80211_sub_if_data *sdata = link_data->sdata; struct ieee80211_csa_settings csa = {}; int err; switch (sdata->vif.type) { case NL80211_IFTYPE_AP: - sdata->deflink.u.ap.next_beacon = + link_data->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after); - if (!sdata->deflink.u.ap.next_beacon) + if (!link_data->u.ap.next_beacon) return -ENOMEM; /* @@ -3751,7 +3753,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, IEEE80211_MAX_CNTDWN_COUNTERS_NUM) || (params->n_counter_offsets_presp > IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) { - ieee80211_free_next_beacon(&sdata->deflink); + ieee80211_free_next_beacon(link_data); return -EINVAL; } @@ -3761,11 +3763,11 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, csa.n_counter_offsets_presp = params->n_counter_offsets_presp; csa.count = params->count; - err = ieee80211_assign_beacon(sdata, &sdata->deflink, + err = ieee80211_assign_beacon(sdata, link_data, ¶ms->beacon_csa, &csa, NULL, changed); if (err < 0) { - ieee80211_free_next_beacon(&sdata->deflink); + ieee80211_free_next_beacon(link_data); return err; } @@ -3925,7 +3927,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (sdata->vif.bss_conf.color_change_active) ieee80211_color_change_abort(sdata); - err = ieee80211_set_csa_beacon(sdata, params, &changed); + err = ieee80211_set_csa_beacon(&sdata->deflink, params, &changed); if (err) { ieee80211_link_unreserve_chanctx(&sdata->deflink); goto out; From 1a96bb4e8a7953a7cf8e277c4eea29907bb5a140 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 30 Jan 2024 19:39:17 +0530 Subject: [PATCH 0942/2255] wifi: mac80211: start and finalize channel switch on link basis Add changes to start a channel switch as well as finalize it on link basis in order to support CSA with MLO as well. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240130140918.1172387-5-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 59 +++++++++++++++++++++++++++------------------ net/mac80211/link.c | 2 ++ 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0c0f418c3652..d30a64cf95cd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3633,6 +3633,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) { struct ieee80211_sub_if_data *sdata = link_data->sdata; struct ieee80211_local *local = sdata->local; + struct ieee80211_bss_conf *link_conf = link_data->conf; u64 changed = 0; int err; @@ -3654,16 +3655,16 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) if (link_data->reserved_ready) return 0; - return ieee80211_link_use_reserved_context(&sdata->deflink); + return ieee80211_link_use_reserved_context(link_data); } - if (!cfg80211_chandef_identical(&link_data->conf->chanreq.oper, + if (!cfg80211_chandef_identical(&link_conf->chanreq.oper, &link_data->csa_chanreq.oper)) return -EINVAL; - sdata->vif.bss_conf.csa_active = false; + link_conf->csa_active = false; - err = ieee80211_set_after_csa_beacon(&sdata->deflink, &changed); + err = ieee80211_set_after_csa_beacon(link_data, &changed); if (err) return err; @@ -3690,7 +3691,8 @@ static void ieee80211_csa_finalize(struct ieee80211_link_data *link_data) struct ieee80211_sub_if_data *sdata = link_data->sdata; if (__ieee80211_csa_finalize(link_data)) { - sdata_info(sdata, "failed to finalize CSA, disconnecting\n"); + sdata_info(sdata, "failed to finalize CSA on link %d, disconnecting\n", + link_data->link_id); cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev, GFP_KERNEL); } @@ -3867,7 +3869,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel_switch ch_switch; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; + struct ieee80211_bss_conf *link_conf; + struct ieee80211_link_data *link_data; u64 changed = 0; + u8 link_id = params->link_id; int err; lockdep_assert_wiphy(local->hw.wiphy); @@ -3878,15 +3883,23 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (sdata->wdev.cac_started) return -EBUSY; - if (chanreq.oper.punctured && !sdata->vif.bss_conf.eht_support) + if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS)) + return -EINVAL; + + link_data = wiphy_dereference(wiphy, sdata->link[link_id]); + if (!link_data) + return -ENOLINK; + + link_conf = link_data->conf; + + if (chanreq.oper.punctured && !link_conf->eht_support) return -EINVAL; /* don't allow another channel switch if one is already active. */ - if (sdata->vif.bss_conf.csa_active) + if (link_conf->csa_active) return -EBUSY; - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, - lockdep_is_held(&local->hw.wiphy->mtx)); + conf = wiphy_dereference(wiphy, link_conf->chanctx_conf); if (!conf) { err = -EBUSY; goto out; @@ -3910,7 +3923,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (err) goto out; - err = ieee80211_link_reserve_chanctx(&sdata->deflink, &chanreq, + err = ieee80211_link_reserve_chanctx(link_data, &chanreq, chanctx->mode, params->radar_required); if (err) @@ -3919,40 +3932,38 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, /* if reservation is invalid then this will fail */ err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); if (err) { - ieee80211_link_unreserve_chanctx(&sdata->deflink); + ieee80211_link_unreserve_chanctx(link_data); goto out; } /* if there is a color change in progress, abort it */ - if (sdata->vif.bss_conf.color_change_active) + if (link_conf->color_change_active) ieee80211_color_change_abort(sdata); - err = ieee80211_set_csa_beacon(&sdata->deflink, params, &changed); + err = ieee80211_set_csa_beacon(link_data, params, &changed); if (err) { - ieee80211_link_unreserve_chanctx(&sdata->deflink); + ieee80211_link_unreserve_chanctx(link_data); goto out; } - sdata->deflink.csa_chanreq = chanreq; - sdata->deflink.csa_block_tx = params->block_tx; - sdata->vif.bss_conf.csa_active = true; + link_data->csa_chanreq = chanreq; + link_data->csa_block_tx = params->block_tx; + link_conf->csa_active = true; - if (sdata->deflink.csa_block_tx) + if (link_data->csa_block_tx) ieee80211_stop_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); cfg80211_ch_switch_started_notify(sdata->dev, - &sdata->deflink.csa_chanreq.oper, 0, + &link_data->csa_chanreq.oper, 0, params->count, params->block_tx); if (changed) { - ieee80211_link_info_change_notify(sdata, &sdata->deflink, - changed); - drv_channel_switch_beacon(sdata, - &sdata->deflink.csa_chanreq.oper); + ieee80211_link_info_change_notify(sdata, link_data, changed); + drv_channel_switch_beacon(sdata, &link_data->csa_chanreq.oper); } else { /* if the beacon didn't change, we can finalize immediately */ - ieee80211_csa_finalize(&sdata->deflink); + ieee80211_csa_finalize(link_data); } out: diff --git a/net/mac80211/link.c b/net/mac80211/link.c index 4f19d6479bef..87a413374ece 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -73,6 +73,8 @@ void ieee80211_link_stop(struct ieee80211_link_data *link) ieee80211_mgd_stop_link(link); cancel_delayed_work_sync(&link->color_collision_detect_work); + wiphy_work_cancel(link->sdata->local->hw.wiphy, + &link->csa_finalize_work); ieee80211_link_release_channel(link); } From 04ada8599c35ecb2cf16c94eb118d227630d06ee Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 30 Jan 2024 19:39:18 +0530 Subject: [PATCH 0943/2255] 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 ++-- .../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 +- .../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(-) 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(); } From 80b0c88033ff8a9a0d6817ccdeebd512bef06cc0 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:04 +0200 Subject: [PATCH 0944/2255] 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(+) 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"), + }, + }, {} }; From a20ac99b5f5ee768866b42d28138d90d89158042 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:05 +0200 Subject: [PATCH 0945/2255] 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(-) 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, From 3d801a7591824aa29fdb0774e0881890d4a773f1 Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Mon, 5 Feb 2024 00:06:06 +0200 Subject: [PATCH 0946/2255] 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 +++-- .../net/wireless/intel/iwlwifi/fw/api/power.h | 40 +++++++++++++++++-- .../wireless/intel/iwlwifi/fw/regulatory.c | 20 ++++++---- .../wireless/intel/iwlwifi/fw/regulatory.h | 9 ++++- .../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(-) 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 { From e047e0e3cc8b647eecf6ce644d5dacba44700d94 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:07 +0200 Subject: [PATCH 0947/2255] 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(-) 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; From f94c24386d04ec242207bdbdc59ccb1b0b3cfc3c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:08 +0200 Subject: [PATCH 0948/2255] 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 --- .../wireless/intel/iwlwifi/mvm/debugfs-vif.c | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) 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) { - rcu_read_unlock(); - mutex_unlock(&mvm->mutex); - return -EINVAL; - } - - phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv]; - rcu_read_unlock(); mvm->dbgfs_rx_phyinfo = value; - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def, - chanctx_conf->rx_chains_static, - chanctx_conf->rx_chains_dynamic); + 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(); + + phy_ctxt = mvmvif->link[link_id]->phy_ctxt; + if (!phy_ctxt) + continue; + + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, + chains_static, chains_dynamic); + } + mutex_unlock(&mvm->mutex); return ret ?: count; From 814cdd7c37525133e54c667ca3cae6461ded93dd Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:09 +0200 Subject: [PATCH 0949/2255] 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 +++++- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 2 +- .../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(-) 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); From 83f57c936b6e210d517fb5fa526895234bc974e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:10 +0200 Subject: [PATCH 0950/2255] 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(-) 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); From 318b3fac347cc307b39412cd8133488a83cd73a9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:11 +0200 Subject: [PATCH 0951/2255] 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(-) 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; } From 449619744df11873f4b4e534502e1f10653b57ce Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 5 Feb 2024 00:06:12 +0200 Subject: [PATCH 0952/2255] 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(+) 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; From f51d6431824f0afb9f73d68971d154c47c26b86a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:13 +0200 Subject: [PATCH 0953/2255] 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(-) 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 */ From f863afbd301ef2a29364316dd14a73699d0bc673 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:17 +0200 Subject: [PATCH 0954/2255] 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(-) 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; From 8b720901d97d45d477121a406cb120cee6291b55 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Tue, 6 Feb 2024 13:57:03 +0200 Subject: [PATCH 0955/2255] 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(+) 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 From 4d951e265c116c38862dcb1f59af5803762d4048 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 5 Feb 2024 00:06:15 +0200 Subject: [PATCH 0956/2255] 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(-) 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; From f4eedfd88b62819bedad7d92571febef9093bc72 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:01 +0200 Subject: [PATCH 0957/2255] 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(-) 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: From 87f690f5a9030a694dbf9d794ee940998118a195 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:02 +0200 Subject: [PATCH 0958/2255] 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(-) 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, From 0dd2b42c2c096e39da4c35927db4ed1f6c587bea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:03 +0200 Subject: [PATCH 0959/2255] 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 --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) 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); From 74f4cd71070538bd9a8b6686fc53e7b77d510afa Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:04 +0200 Subject: [PATCH 0960/2255] 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(-) 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) { From 556c7cd721b5262579ba1710c3b4e7ffdb5573ac Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:05 +0200 Subject: [PATCH 0961/2255] 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(-) 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; From b7acc059a728b591f1a27da0bfd460b0513fda7d Mon Sep 17 00:00:00 2001 From: Daniel Amosi Date: Mon, 5 Feb 2024 21:21:07 +0200 Subject: [PATCH 0962/2255] 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(-) 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) From f05ef3497f260d0ab75aed45205bfe90beb3bd90 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:09 +0200 Subject: [PATCH 0963/2255] 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(-) 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; From 066425b6c8d25d9b8d6cf49e6d0910d8cb2d06fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:10 +0200 Subject: [PATCH 0964/2255] 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(-) 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; From 1b3741ea4089ff7e87ea722004c0dc54adcbdf25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:11 +0200 Subject: [PATCH 0965/2255] 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(+) 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; From c4302c0f2dd31cd071ae8d49370b49bd78a22a9b Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:12 +0200 Subject: [PATCH 0966/2255] 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(-) 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; } From 0c1c91604f3e3fc41f4d77dcfc3753860a9a32c9 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:13 +0200 Subject: [PATCH 0967/2255] 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(+) 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); } } From 2e0e766bd8a7f14f10c3e70b8203c4c1e6d9ec76 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:14 +0200 Subject: [PATCH 0968/2255] 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(-) 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, From c82a950f63a32c3148db1c6e4a3bd7140a11a95d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:15 +0200 Subject: [PATCH 0969/2255] 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(-) 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 */ From 38a3241f2f7d6e863c71cd6f5fabf2a000d89c9f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:05 +0200 Subject: [PATCH 0970/2255] 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(-) 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); } From e35f316bce9e5733c9826120c1838f4c447b2c4c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 6 Feb 2024 18:02:06 +0200 Subject: [PATCH 0971/2255] 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 --- .../net/wireless/intel/iwlwifi/mvm/mld-key.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) 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) From ff04f78ce38d79bdbf6b1fd276a6a2d035e21951 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 6 Feb 2024 18:02:07 +0200 Subject: [PATCH 0972/2255] 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(-) 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. From 5f4e0994996fa08d57711b5b247a0cb3085ec66a Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Tue, 6 Feb 2024 18:02:08 +0200 Subject: [PATCH 0973/2255] 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 +++++++++++++++++-- .../net/wireless/intel/iwlwifi/iwl-config.h | 8 +++- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 15 +++++++- 3 files changed, 55 insertions(+), 6 deletions(-) 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); From d5bd4041cd70faf26fc9a54bd6f172537bbe77f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:09 +0200 Subject: [PATCH 0974/2255] 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(-) 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; From 87f5b5f2c036cdf1ed2269b1d11f005b9bd0b2dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:10 +0200 Subject: [PATCH 0975/2255] 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 --- .../wireless/intel/iwlwifi/mvm/debugfs-vif.c | 6 ++-- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 18 ++++++------ .../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++-- .../net/wireless/intel/iwlwifi/mvm/power.c | 29 ++++++++----------- 5 files changed, 27 insertions(+), 34 deletions(-) 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) From ae6d30a715210de16682369269cb6c25134ddbe2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:11 +0200 Subject: [PATCH 0976/2255] 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(-) 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) { From dbc396244a5e1ce51e90abd3acc98de707445d6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:13 +0200 Subject: [PATCH 0977/2255] 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(-) 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); } /* From 4dbc306e0736685c5298073bed19cbf9f4b4cb92 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:14 +0200 Subject: [PATCH 0978/2255] 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(-) 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); From b9a395f0f7af66fe8224450481b99d4f83b57207 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 8 Feb 2024 14:24:21 +0800 Subject: [PATCH 0979/2255] bpf, btf: Fix return value of register_btf_id_dtor_kfuncs The same as __register_btf_kfunc_id_set(), to let the modules with stripped btf section loaded, this patch changes the return value of register_btf_id_dtor_kfuncs() too from -ENOENT to 0 when btf is NULL. Signed-off-by: Geliang Tang Link: https://lore.kernel.org/r/eab65586d7fb0e72f2707d3747c7d4a5d60c823f.1707373307.git.tanggeliang@kylinos.cn Signed-off-by: Martin KaFai Lau --- kernel/bpf/btf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index f7725cb6e564..16eb937eca46 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -8219,10 +8219,8 @@ int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_c pr_err("missing vmlinux BTF, cannot register dtor kfuncs\n"); return -ENOENT; } - if (owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)) { - pr_err("missing module BTF, cannot register dtor kfuncs\n"); - return -ENOENT; - } + if (owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)) + pr_warn("missing module BTF, cannot register dtor kfuncs\n"); return 0; } if (IS_ERR(btf)) From 9e60b0e02550aaf5f2301e49353641a5e3701674 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 8 Feb 2024 14:24:22 +0800 Subject: [PATCH 0980/2255] bpf, btf: Add check_btf_kconfigs helper This patch extracts duplicate code on error path when btf_get_module_btf() returns NULL from the functions __register_btf_kfunc_id_set() and register_btf_id_dtor_kfuncs() into a new helper named check_btf_kconfigs() to check CONFIG_DEBUG_INFO_BTF and CONFIG_DEBUG_INFO_BTF_MODULES in it. Signed-off-by: Geliang Tang Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/fa5537fc55f1e4d0bfd686598c81b7ab9dbd82b7.1707373307.git.tanggeliang@kylinos.cn Signed-off-by: Martin KaFai Lau --- kernel/bpf/btf.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 16eb937eca46..61e51cf0a995 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -7738,6 +7738,17 @@ static struct btf *btf_get_module_btf(const struct module *module) return btf; } +static int check_btf_kconfigs(const struct module *module, const char *feature) +{ + if (!module && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) { + pr_err("missing vmlinux BTF, cannot register %s\n", feature); + return -ENOENT; + } + if (module && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)) + pr_warn("missing module BTF, cannot register %s\n", feature); + return 0; +} + BPF_CALL_4(bpf_btf_find_by_name_kind, char *, name, int, name_sz, u32, kind, int, flags) { struct btf *btf = NULL; @@ -8098,15 +8109,8 @@ static int __register_btf_kfunc_id_set(enum btf_kfunc_hook hook, int ret, i; btf = btf_get_module_btf(kset->owner); - if (!btf) { - if (!kset->owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) { - pr_err("missing vmlinux BTF, cannot register kfuncs\n"); - return -ENOENT; - } - if (kset->owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)) - pr_warn("missing module BTF, cannot register kfuncs\n"); - return 0; - } + if (!btf) + return check_btf_kconfigs(kset->owner, "kfunc"); if (IS_ERR(btf)) return PTR_ERR(btf); @@ -8214,15 +8218,8 @@ int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_c int ret; btf = btf_get_module_btf(owner); - if (!btf) { - if (!owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) { - pr_err("missing vmlinux BTF, cannot register dtor kfuncs\n"); - return -ENOENT; - } - if (owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)) - pr_warn("missing module BTF, cannot register dtor kfuncs\n"); - return 0; - } + if (!btf) + return check_btf_kconfigs(owner, "dtor kfuncs"); if (IS_ERR(btf)) return PTR_ERR(btf); From 947e56f82fd783a1ec1c9359b20b5699d09cae14 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 8 Feb 2024 14:24:23 +0800 Subject: [PATCH 0981/2255] bpf, btf: Check btf for register_bpf_struct_ops Similar to the handling in the functions __register_btf_kfunc_id_set() and register_btf_id_dtor_kfuncs(), this patch uses the newly added helper check_btf_kconfigs() to handle module with its btf section stripped. While at it, the patch also adds the missed IS_ERR() check to fix the commit f6be98d19985 ("bpf, net: switch to dynamic registration") Fixes: f6be98d19985 ("bpf, net: switch to dynamic registration") Signed-off-by: Geliang Tang Link: https://lore.kernel.org/r/69082b9835463fe36f9e354bddf2d0a97df39c2b.1707373307.git.tanggeliang@kylinos.cn Signed-off-by: Martin KaFai Lau --- kernel/bpf/btf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 61e51cf0a995..8e06d29961f1 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -8882,7 +8882,9 @@ int __register_bpf_struct_ops(struct bpf_struct_ops *st_ops) btf = btf_get_module_btf(st_ops->owner); if (!btf) - return -EINVAL; + return check_btf_kconfigs(st_ops->owner, "struct_ops"); + if (IS_ERR(btf)) + return PTR_ERR(btf); log = kzalloc(sizeof(*log), GFP_KERNEL | __GFP_NOWARN); if (!log) { From 4bea747f3fbec33c16d369b2f51e55981d7c78d0 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 6 Feb 2024 08:16:54 -0800 Subject: [PATCH 0982/2255] net/sun3_82586: Avoid reading past buffer in debug output Since NUM_XMIT_BUFFS is always 1, building m68k with sun3_defconfig and -Warraybounds, this build warning is visible[1]: drivers/net/ethernet/i825xx/sun3_82586.c: In function 'sun3_82586_timeout': drivers/net/ethernet/i825xx/sun3_82586.c:990:122: warning: array subscript 1 is above array bounds of 'volatile struct transmit_cmd_struct *[1]' [-Warray-bounds=] 990 | printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status)); | ~~~~~~~~~~~~^~~ ... drivers/net/ethernet/i825xx/sun3_82586.c:156:46: note: while referencing 'xmit_cmds' 156 | volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; Avoid accessing index 1 since it doesn't exist. Link: https://github.com/KSPP/linux/issues/325 [1] Cc: Sam Creasey Signed-off-by: Kees Cook Reviewed-by: Simon Horman Tested-by: Simon Horman # build-tested Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20240206161651.work.876-kees@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/i825xx/sun3_82586.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/i825xx/sun3_82586.c b/drivers/net/ethernet/i825xx/sun3_82586.c index 5e27470c6b1e..f2d4669c81cf 100644 --- a/drivers/net/ethernet/i825xx/sun3_82586.c +++ b/drivers/net/ethernet/i825xx/sun3_82586.c @@ -987,7 +987,7 @@ static void sun3_82586_timeout(struct net_device *dev, unsigned int txqueue) { #ifdef DEBUG printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus); - printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status)); + printk("%s: command-stats: %04x\n", dev->name, swab16(p->xmit_cmds[0]->cmd_status)); printk("%s: check, whether you set the right interrupt number!\n",dev->name); #endif sun3_82586_close(dev); From ef61f5528fca6c3bbb2f8bc002fd1949c9d1f9b9 Mon Sep 17 00:00:00 2001 From: Sagi Maimon Date: Mon, 5 Feb 2024 17:30:46 +0200 Subject: [PATCH 0983/2255] ptp: ocp: add Adva timecard support Adding support for the Adva timecard. The card uses different drivers to provide access to the firmware SPI flash (Altera based). Other parts of the code are the same and could be reused. Signed-off-by: Sagi Maimon Reviewed-by: Vadim Fedorenko Link: https://lore.kernel.org/r/20240205153046.3642-1-maimon.sagi@gmail.com Signed-off-by: Jakub Kicinski --- drivers/ptp/ptp_ocp.c | 302 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 293 insertions(+), 9 deletions(-) diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 9507681e0d12..6506cfb89aa9 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -34,6 +34,9 @@ #define PCI_VENDOR_ID_OROLIA 0x1ad7 #define PCI_DEVICE_ID_OROLIA_ARTCARD 0xa000 +#define PCI_VENDOR_ID_ADVA 0xad5a +#define PCI_DEVICE_ID_ADVA_TIMECARD 0x0400 + static struct class timecard_class = { .name = "timecard", }; @@ -63,6 +66,13 @@ struct ocp_reg { u32 status_drift; }; +struct ptp_ocp_servo_conf { + u32 servo_offset_p; + u32 servo_offset_i; + u32 servo_drift_p; + u32 servo_drift_i; +}; + #define OCP_CTRL_ENABLE BIT(0) #define OCP_CTRL_ADJUST_TIME BIT(1) #define OCP_CTRL_ADJUST_OFFSET BIT(2) @@ -397,10 +407,14 @@ static int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr); static int ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r); +static int ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r); + static const struct ocp_attr_group fb_timecard_groups[]; static const struct ocp_attr_group art_timecard_groups[]; +static const struct ocp_attr_group adva_timecard_groups[]; + struct ptp_ocp_eeprom_map { u16 off; u16 len; @@ -700,6 +714,12 @@ static struct ocp_resource ocp_fb_resource[] = { }, { .setup = ptp_ocp_fb_board_init, + .extra = &(struct ptp_ocp_servo_conf) { + .servo_offset_p = 0x2000, + .servo_offset_i = 0x1000, + .servo_drift_p = 0, + .servo_drift_i = 0, + }, }, { } }; @@ -831,6 +851,170 @@ static struct ocp_resource ocp_art_resource[] = { }, { .setup = ptp_ocp_art_board_init, + .extra = &(struct ptp_ocp_servo_conf) { + .servo_offset_p = 0x2000, + .servo_offset_i = 0x1000, + .servo_drift_p = 0, + .servo_drift_i = 0, + }, + }, + { } +}; + +static struct ocp_resource ocp_adva_resource[] = { + { + OCP_MEM_RESOURCE(reg), + .offset = 0x01000000, .size = 0x10000, + }, + { + OCP_EXT_RESOURCE(ts0), + .offset = 0x01010000, .size = 0x10000, .irq_vec = 1, + .extra = &(struct ptp_ocp_ext_info) { + .index = 0, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_EXT_RESOURCE(ts1), + .offset = 0x01020000, .size = 0x10000, .irq_vec = 2, + .extra = &(struct ptp_ocp_ext_info) { + .index = 1, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_EXT_RESOURCE(ts2), + .offset = 0x01060000, .size = 0x10000, .irq_vec = 6, + .extra = &(struct ptp_ocp_ext_info) { + .index = 2, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + /* Timestamp for PHC and/or PPS generator */ + { + OCP_EXT_RESOURCE(pps), + .offset = 0x010C0000, .size = 0x10000, .irq_vec = 0, + .extra = &(struct ptp_ocp_ext_info) { + .index = 5, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_EXT_RESOURCE(signal_out[0]), + .offset = 0x010D0000, .size = 0x10000, .irq_vec = 11, + .extra = &(struct ptp_ocp_ext_info) { + .index = 1, + .irq_fcn = ptp_ocp_signal_irq, + .enable = ptp_ocp_signal_enable, + }, + }, + { + OCP_EXT_RESOURCE(signal_out[1]), + .offset = 0x010E0000, .size = 0x10000, .irq_vec = 12, + .extra = &(struct ptp_ocp_ext_info) { + .index = 2, + .irq_fcn = ptp_ocp_signal_irq, + .enable = ptp_ocp_signal_enable, + }, + }, + { + OCP_MEM_RESOURCE(pps_to_ext), + .offset = 0x01030000, .size = 0x10000, + }, + { + OCP_MEM_RESOURCE(pps_to_clk), + .offset = 0x01040000, .size = 0x10000, + }, + { + OCP_MEM_RESOURCE(tod), + .offset = 0x01050000, .size = 0x10000, + }, + { + OCP_MEM_RESOURCE(image), + .offset = 0x00020000, .size = 0x1000, + }, + { + OCP_MEM_RESOURCE(pps_select), + .offset = 0x00130000, .size = 0x1000, + }, + { + OCP_MEM_RESOURCE(sma_map1), + .offset = 0x00140000, .size = 0x1000, + }, + { + OCP_MEM_RESOURCE(sma_map2), + .offset = 0x00220000, .size = 0x1000, + }, + { + OCP_SERIAL_RESOURCE(gnss_port), + .offset = 0x00160000 + 0x1000, .irq_vec = 3, + .extra = &(struct ptp_ocp_serial_port) { + .baud = 9600, + }, + }, + { + OCP_SERIAL_RESOURCE(mac_port), + .offset = 0x00180000 + 0x1000, .irq_vec = 5, + .extra = &(struct ptp_ocp_serial_port) { + .baud = 115200, + }, + }, + { + OCP_MEM_RESOURCE(freq_in[0]), + .offset = 0x01200000, .size = 0x10000, + }, + { + OCP_MEM_RESOURCE(freq_in[1]), + .offset = 0x01210000, .size = 0x10000, + }, + { + OCP_SPI_RESOURCE(spi_flash), + .offset = 0x00310400, .size = 0x10000, .irq_vec = 9, + .extra = &(struct ptp_ocp_flash_info) { + .name = "spi_altera", .pci_offset = 0, + .data_size = sizeof(struct altera_spi_platform_data), + .data = &(struct altera_spi_platform_data) { + .num_chipselect = 1, + .num_devices = 1, + .devices = &(struct spi_board_info) { + .modalias = "spi-nor", + }, + }, + }, + }, + { + OCP_I2C_RESOURCE(i2c_ctrl), + .offset = 0x150000, .size = 0x100, .irq_vec = 7, + .extra = &(struct ptp_ocp_i2c_info) { + .name = "ocores-i2c", + .fixed_rate = 50000000, + .data_size = sizeof(struct ocores_i2c_platform_data), + .data = &(struct ocores_i2c_platform_data) { + .clock_khz = 50000, + .bus_khz = 100, + .reg_io_width = 4, // 32-bit/4-byte + .reg_shift = 2, // 32-bit addressing + .num_devices = 2, + .devices = (struct i2c_board_info[]) { + { I2C_BOARD_INFO("24c02", 0x50) }, + { I2C_BOARD_INFO("24mac402", 0x58), + .platform_data = "mac" }, + }, + }, + }, + }, + { + .setup = ptp_ocp_adva_board_init, + .extra = &(struct ptp_ocp_servo_conf) { + .servo_offset_p = 0xc000, + .servo_offset_i = 0x1000, + .servo_drift_p = 0, + .servo_drift_i = 0, + }, }, { } }; @@ -839,6 +1023,7 @@ static const struct pci_device_id ptp_ocp_pcidev_id[] = { { PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) }, { PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) }, { PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) }, + { PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) }, { } }; MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id); @@ -917,6 +1102,30 @@ static const struct ocp_selector ptp_ocp_art_sma_out[] = { { } }; +static const struct ocp_selector ptp_ocp_adva_sma_in[] = { + { .name = "10Mhz", .value = 0x0000, .frequency = 10000000}, + { .name = "PPS1", .value = 0x0001, .frequency = 1 }, + { .name = "PPS2", .value = 0x0002, .frequency = 1 }, + { .name = "TS1", .value = 0x0004, .frequency = 0 }, + { .name = "TS2", .value = 0x0008, .frequency = 0 }, + { .name = "FREQ1", .value = 0x0100, .frequency = 0 }, + { .name = "FREQ2", .value = 0x0200, .frequency = 0 }, + { .name = "None", .value = SMA_DISABLE, .frequency = 0 }, + { } +}; + +static const struct ocp_selector ptp_ocp_adva_sma_out[] = { + { .name = "10Mhz", .value = 0x0000, .frequency = 10000000}, + { .name = "PHC", .value = 0x0001, .frequency = 1 }, + { .name = "MAC", .value = 0x0002, .frequency = 1 }, + { .name = "GNSS1", .value = 0x0004, .frequency = 1 }, + { .name = "GEN1", .value = 0x0040 }, + { .name = "GEN2", .value = 0x0080 }, + { .name = "GND", .value = 0x2000 }, + { .name = "VCC", .value = 0x4000 }, + { } +}; + struct ocp_sma_op { const struct ocp_selector *tbl[2]; void (*init)(struct ptp_ocp *bp); @@ -1363,7 +1572,7 @@ ptp_ocp_estimate_pci_timing(struct ptp_ocp *bp) } static int -ptp_ocp_init_clock(struct ptp_ocp *bp) +ptp_ocp_init_clock(struct ptp_ocp *bp, struct ptp_ocp_servo_conf *servo_conf) { struct timespec64 ts; u32 ctrl; @@ -1371,12 +1580,11 @@ ptp_ocp_init_clock(struct ptp_ocp *bp) ctrl = OCP_CTRL_ENABLE; iowrite32(ctrl, &bp->reg->ctrl); - /* NO DRIFT Correction */ - /* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */ - iowrite32(0x2000, &bp->reg->servo_offset_p); - iowrite32(0x1000, &bp->reg->servo_offset_i); - iowrite32(0, &bp->reg->servo_drift_p); - iowrite32(0, &bp->reg->servo_drift_i); + /* servo configuration */ + iowrite32(servo_conf->servo_offset_p, &bp->reg->servo_offset_p); + iowrite32(servo_conf->servo_offset_i, &bp->reg->servo_offset_i); + iowrite32(servo_conf->servo_drift_p, &bp->reg->servo_drift_p); + iowrite32(servo_conf->servo_drift_p, &bp->reg->servo_drift_i); /* latch servo values */ ctrl |= OCP_CTRL_ADJUST_SERVO; @@ -2348,6 +2556,14 @@ static const struct ocp_sma_op ocp_fb_sma_op = { .set_output = ptp_ocp_sma_fb_set_output, }; +static const struct ocp_sma_op ocp_adva_sma_op = { + .tbl = { ptp_ocp_adva_sma_in, ptp_ocp_adva_sma_out }, + .init = ptp_ocp_sma_fb_init, + .get = ptp_ocp_sma_fb_get, + .set_inputs = ptp_ocp_sma_fb_set_inputs, + .set_output = ptp_ocp_sma_fb_set_output, +}; + static int ptp_ocp_set_pins(struct ptp_ocp *bp) { @@ -2427,7 +2643,7 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r) return err; ptp_ocp_sma_init(bp); - return ptp_ocp_init_clock(bp); + return ptp_ocp_init_clock(bp, r->extra); } static bool @@ -2589,7 +2805,44 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r) if (err) return err; - return ptp_ocp_init_clock(bp); + return ptp_ocp_init_clock(bp, r->extra); +} + +/* ADVA specific board initializers; last "resource" registered. */ +static int +ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r) +{ + int err; + u32 version; + + bp->flash_start = 0xA00000; + bp->eeprom_map = fb_eeprom_map; + bp->sma_op = &ocp_adva_sma_op; + + version = ioread32(&bp->image->version); + /* if lower 16 bits are empty, this is the fw loader. */ + if ((version & 0xffff) == 0) { + version = version >> 16; + bp->fw_loader = true; + } + bp->fw_tag = 3; + bp->fw_version = version & 0xffff; + bp->fw_cap = OCP_CAP_BASIC | OCP_CAP_SIGNAL | OCP_CAP_FREQ; + + ptp_ocp_tod_init(bp); + ptp_ocp_nmea_out_init(bp); + ptp_ocp_signal_init(bp); + + err = ptp_ocp_attr_group_add(bp, adva_timecard_groups); + if (err) + return err; + + err = ptp_ocp_set_pins(bp); + if (err) + return err; + ptp_ocp_sma_init(bp); + + return ptp_ocp_init_clock(bp, r->extra); } static ssize_t @@ -3564,6 +3817,37 @@ static const struct ocp_attr_group art_timecard_groups[] = { { }, }; +static struct attribute *adva_timecard_attrs[] = { + &dev_attr_serialnum.attr, + &dev_attr_gnss_sync.attr, + &dev_attr_clock_source.attr, + &dev_attr_available_clock_sources.attr, + &dev_attr_sma1.attr, + &dev_attr_sma2.attr, + &dev_attr_sma3.attr, + &dev_attr_sma4.attr, + &dev_attr_available_sma_inputs.attr, + &dev_attr_available_sma_outputs.attr, + &dev_attr_clock_status_drift.attr, + &dev_attr_clock_status_offset.attr, + &dev_attr_ts_window_adjust.attr, + &dev_attr_tod_correction.attr, + NULL, +}; + +static const struct attribute_group adva_timecard_group = { + .attrs = adva_timecard_attrs, +}; + +static const struct ocp_attr_group adva_timecard_groups[] = { + { .cap = OCP_CAP_BASIC, .group = &adva_timecard_group }, + { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal0_group }, + { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal1_group }, + { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq0_group }, + { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq1_group }, + { }, +}; + static void gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit, const char *def) From a2e520643be18cf69ec06558f3409f6c6559dce1 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 6 Feb 2024 13:25:27 +0200 Subject: [PATCH 0984/2255] net: dsa: b53: unexport and move b53_eee_enable_set() After commit f86ad77faf24 ("net: dsa: bcm_sf2: Utilize b53_{enable, disable}_port"), bcm_sf2.c no longer calls b53_eee_enable_set(), and all its callers are in b53_common.c. We also need to move it, because it is called within b53_common.c before its definition, and we want to avoid forward declarations. Signed-off-by: Vladimir Oltean Reviewed-by: Simon Horman Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20240206112527.4132299-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 28 +++++++++++++--------------- drivers/net/dsa/b53/b53_priv.h | 1 - 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 9e4c9bd6abcc..b2eeff04f4c8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -559,6 +559,19 @@ static void b53_port_set_learning(struct b53_device *dev, int port, b53_write16(dev, B53_CTRL_PAGE, B53_DIS_LEARNING, reg); } +static void b53_eee_enable_set(struct dsa_switch *ds, int port, bool enable) +{ + struct b53_device *dev = ds->priv; + u16 reg; + + b53_read16(dev, B53_EEE_PAGE, B53_EEE_EN_CTRL, ®); + if (enable) + reg |= BIT(port); + else + reg &= ~BIT(port); + b53_write16(dev, B53_EEE_PAGE, B53_EEE_EN_CTRL, reg); +} + int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) { struct b53_device *dev = ds->priv; @@ -2193,21 +2206,6 @@ void b53_mirror_del(struct dsa_switch *ds, int port, } EXPORT_SYMBOL(b53_mirror_del); -void b53_eee_enable_set(struct dsa_switch *ds, int port, bool enable) -{ - struct b53_device *dev = ds->priv; - u16 reg; - - b53_read16(dev, B53_EEE_PAGE, B53_EEE_EN_CTRL, ®); - if (enable) - reg |= BIT(port); - else - reg &= ~BIT(port); - b53_write16(dev, B53_EEE_PAGE, B53_EEE_EN_CTRL, reg); -} -EXPORT_SYMBOL(b53_eee_enable_set); - - /* Returns 0 if EEE was not enabled, or 1 otherwise */ int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy) diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index c26a03755e83..c13a907947f1 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -395,7 +395,6 @@ void b53_mirror_del(struct dsa_switch *ds, int port, int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy); void b53_disable_port(struct dsa_switch *ds, int port); void b53_brcm_hdr_setup(struct dsa_switch *ds, int port); -void b53_eee_enable_set(struct dsa_switch *ds, int port, bool enable); int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy); int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); From 83acbb9d0716c7f787d248ca982f4a4a895aef65 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 6 Feb 2024 13:29:26 +0200 Subject: [PATCH 0985/2255] net: dsa: remove "inline" from dsa_user_netpoll_send_skb() The convention is to not use "inline" functions in C files, and let the compiler decide whether to inline or not. Signed-off-by: Vladimir Oltean Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240206112927.4134375-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- net/dsa/user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/dsa/user.c b/net/dsa/user.c index ba2e53b5e16a..5d666dfb317d 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -875,8 +875,8 @@ static int dsa_user_port_obj_del(struct net_device *dev, const void *ctx, return err; } -static inline netdev_tx_t dsa_user_netpoll_send_skb(struct net_device *dev, - struct sk_buff *skb) +static netdev_tx_t dsa_user_netpoll_send_skb(struct net_device *dev, + struct sk_buff *skb) { #ifdef CONFIG_NET_POLL_CONTROLLER struct dsa_user_priv *p = netdev_priv(dev); From 36f75f74dc07c6c38c87bdb39be814cfa951b6dd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 6 Feb 2024 13:29:27 +0200 Subject: [PATCH 0986/2255] net: dsa: tag_sja1105: remove "inline" keyword The convention is to not use the "inline" keyword for functions in C files, but to let the compiler choose. Signed-off-by: Vladimir Oltean Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240206112927.4134375-2-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- net/dsa/tag_sja1105.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index 2717e9d7b612..1aba1d05c27a 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -75,7 +75,7 @@ sja1105_tagger_private(struct dsa_switch *ds) } /* Similar to is_link_local_ether_addr(hdr->h_dest) but also covers PTP */ -static inline bool sja1105_is_link_local(const struct sk_buff *skb) +static bool sja1105_is_link_local(const struct sk_buff *skb) { const struct ethhdr *hdr = eth_hdr(skb); u64 dmac = ether_addr_to_u64(hdr->h_dest); @@ -121,7 +121,7 @@ static void sja1105_meta_unpack(const struct sk_buff *skb, packing(buf + 7, &meta->switch_id, 7, 0, 1, UNPACK, 0); } -static inline bool sja1105_is_meta_frame(const struct sk_buff *skb) +static bool sja1105_is_meta_frame(const struct sk_buff *skb) { const struct ethhdr *hdr = eth_hdr(skb); u64 smac = ether_addr_to_u64(hdr->h_source); From e084a1c1dff6172887eb5a71e697745e3f5855be Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 5 Feb 2024 21:36:43 +0000 Subject: [PATCH 0987/2255] xirc2ps_cs: remove redundant assignment to variable okay, clean up freespace The variable okay is being initialized with a value that is never read, it is being re-assigned later on. The initialization is redundant and can be removed. Also clean up assignment to variable freespace using an assignment and mask operation. Cleans up clang scan build warning: drivers/net/ethernet/xircom/xirc2ps_cs.c:1244:5: warning: Value stored to 'okay' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240205213643.1850420-1-colin.i.king@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xircom/xirc2ps_cs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c index 9f505cf02d96..e9bc38fd2025 100644 --- a/drivers/net/ethernet/xircom/xirc2ps_cs.c +++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c @@ -1240,9 +1240,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); SelectPage(0); PutWord(XIRCREG0_TRS, (u_short)pktlen+2); - freespace = GetWord(XIRCREG0_TSO); - okay = freespace & 0x8000; - freespace &= 0x7fff; + freespace = GetWord(XIRCREG0_TSO) & 0x7fff; /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */ okay = pktlen +2 < freespace; pr_debug("%s: avail. tx space=%u%s\n", From 5c80e62a2ac595fad3756d09689c6267e34ce9ff Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 5 Feb 2024 21:55:30 +0000 Subject: [PATCH 0988/2255] qed: remove duplicated assignment to variable opaque_fid Variable opaque_fid is being assigned twice with the same value in two identical statements. Remove the redundant first assignment. Cleans up clang scan build warning: drivers/net/ethernet/qlogic/qed/qed_rdma.c:1796:2: warning: Value stored to 'opaque_fid' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240205215530.1851115-1-colin.i.king@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/qlogic/qed/qed_rdma.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index 5a5dbbb8d8aa..9a1660a12c57 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -1793,8 +1793,6 @@ qed_rdma_create_srq(void *rdma_cxt, if (rc) goto err; - opaque_fid = p_hwfn->hw_info.opaque_fid; - opaque_fid = p_hwfn->hw_info.opaque_fid; init_data.opaque_fid = opaque_fid; init_data.comp_mode = QED_SPQ_MODE_EBLOCK; From 6fb5dfee274cfbb97646dc4d94fb8e2fd9e33001 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Feb 2024 17:47:35 +0100 Subject: [PATCH 0989/2255] bnxt: convert EEE handling to use linkmode bitmaps Convert EEE handling to use linkmode bitmaps. This prepares for removing the legacy bitmaps from struct ethtool_keee. No functional change intended. When replacing _bnxt_fw_to_ethtool_adv_spds() with _bnxt_fw_to_linkmode(), remove the fw_pause argument because it's always passed as 0. Note: There's a discussion on whether the underlying implementation is correct, but it's independent of this mechanical conversion w/o functional change. Signed-off-by: Heiner Kallweit Reviewed-by: Michael Chan Link: https://lore.kernel.org/r/9123bf18-a0d0-404e-a7c4-d6c466b4c5e8@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 21 +++--- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 65 ++++++++----------- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 4 +- 3 files changed, 40 insertions(+), 50 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index fde32b32fa81..8fe8a73ffa7e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10624,7 +10624,7 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) struct ethtool_keee *eee = &bp->eee; u16 fw_speeds = le16_to_cpu(resp->supported_speeds_eee_mode); - eee->supported_u32 = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); + _bnxt_fw_to_linkmode(eee->supported, fw_speeds); bp->lpi_tmr_lo = le32_to_cpu(resp->tx_lpi_timer_low) & PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_LOW_MASK; bp->lpi_tmr_hi = le32_to_cpu(resp->valid_tx_lpi_timer_high) & @@ -10775,8 +10775,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) eee->eee_active = 1; fw_speeds = le16_to_cpu( resp->link_partner_adv_eee_link_speed_mask); - eee->lp_advertised_u32 = - _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); + _bnxt_fw_to_linkmode(eee->lp_advertised, fw_speeds); } /* Pull initial EEE config */ @@ -10786,8 +10785,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) eee->eee_enabled = 1; fw_speeds = le16_to_cpu(resp->adv_eee_link_speed_mask); - eee->advertised_u32 = - _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); + _bnxt_fw_to_linkmode(eee->advertised, fw_speeds); if (resp->eee_config_phy_addr & PORT_PHY_QCFG_RESP_EEE_CONFIG_EEE_TX_LPI) { @@ -10969,7 +10967,7 @@ static void bnxt_hwrm_set_eee(struct bnxt *bp, flags |= PORT_PHY_CFG_REQ_FLAGS_EEE_TX_LPI_DISABLE; req->flags |= cpu_to_le32(flags); - eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised_u32); + eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised); req->eee_link_speed_mask = cpu_to_le16(eee_speeds); req->tx_lpi_timer = cpu_to_le32(eee->tx_lpi_timer); } else { @@ -11329,15 +11327,18 @@ static bool bnxt_eee_config_ok(struct bnxt *bp) return true; if (eee->eee_enabled) { - u32 advertising = - _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); + __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp); + + _bnxt_fw_to_linkmode(advertising, link_info->advertising); if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { eee->eee_enabled = 0; return false; } - if (eee->advertised_u32 & ~advertising) { - eee->advertised_u32 = advertising & eee->supported_u32; + if (linkmode_andnot(tmp, eee->advertised, advertising)) { + linkmode_and(eee->advertised, advertising, + eee->supported); return false; } } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 481b835a7703..482ce88b1563 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1751,31 +1751,21 @@ static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } -u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) +/* TODO: support 25GB, 40GB, 50GB with different cable type */ +void _bnxt_fw_to_linkmode(unsigned long *mode, u16 fw_speeds) { - u32 speed_mask = 0; + linkmode_zero(mode); - /* TODO: support 25GB, 40GB, 50GB with different cable type */ - /* set the advertised speeds */ if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) - speed_mask |= ADVERTISED_100baseT_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mode); if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) - speed_mask |= ADVERTISED_1000baseT_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mode); if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) - speed_mask |= ADVERTISED_2500baseX_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, mode); if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) - speed_mask |= ADVERTISED_10000baseT_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, mode); if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) - speed_mask |= ADVERTISED_40000baseCR4_Full; - - if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH) - speed_mask |= ADVERTISED_Pause; - else if (fw_pause & BNXT_LINK_PAUSE_TX) - speed_mask |= ADVERTISED_Asym_Pause; - else if (fw_pause & BNXT_LINK_PAUSE_RX) - speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; - - return speed_mask; + linkmode_set_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, mode); } enum bnxt_media_type { @@ -2643,23 +2633,22 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) return 0; } -u16 bnxt_get_fw_auto_link_speeds(u32 advertising) +u16 bnxt_get_fw_auto_link_speeds(const unsigned long *mode) { u16 fw_speed_mask = 0; - /* only support autoneg at speed 100, 1000, and 10000 */ - if (advertising & (ADVERTISED_100baseT_Full | - ADVERTISED_100baseT_Half)) { + if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mode) || + linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, mode)) fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; - } - if (advertising & (ADVERTISED_1000baseT_Full | - ADVERTISED_1000baseT_Half)) { + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mode) || + linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, mode)) fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; - } - if (advertising & ADVERTISED_10000baseT_Full) + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, mode)) fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; - if (advertising & ADVERTISED_40000baseCR4_Full) + if (linkmode_test_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, mode)) fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; return fw_speed_mask; @@ -3886,10 +3875,11 @@ static int bnxt_set_eeprom(struct net_device *dev, static int bnxt_set_eee(struct net_device *dev, struct ethtool_keee *edata) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp); struct bnxt *bp = netdev_priv(dev); struct ethtool_keee *eee = &bp->eee; struct bnxt_link_info *link_info = &bp->link_info; - u32 advertising; int rc = 0; if (!BNXT_PHY_CFG_ABLE(bp)) @@ -3899,7 +3889,7 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_keee *edata) return -EOPNOTSUPP; mutex_lock(&bp->link_lock); - advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); + _bnxt_fw_to_linkmode(advertising, link_info->advertising); if (!edata->eee_enabled) goto eee_ok; @@ -3919,16 +3909,15 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_keee *edata) edata->tx_lpi_timer = eee->tx_lpi_timer; } } - if (!edata->advertised_u32) { - edata->advertised_u32 = advertising & eee->supported_u32; - } else if (edata->advertised_u32 & ~advertising) { - netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", - edata->advertised_u32, advertising); + if (linkmode_empty(edata->advertised)) { + linkmode_and(edata->advertised, advertising, eee->supported); + } else if (linkmode_andnot(tmp, edata->advertised, advertising)) { + netdev_warn(dev, "EEE advertised must be a subset of autoneg advertised speeds\n"); rc = -EINVAL; goto eee_exit; } - eee->advertised_u32 = edata->advertised_u32; + linkmode_copy(eee->advertised, edata->advertised); eee->tx_lpi_enabled = edata->tx_lpi_enabled; eee->tx_lpi_timer = edata->tx_lpi_timer; eee_ok: @@ -3954,12 +3943,12 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_keee *edata) /* Preserve tx_lpi_timer so that the last value will be used * by default when it is re-enabled. */ - edata->advertised_u32 = 0; + linkmode_zero(edata->advertised); edata->tx_lpi_enabled = 0; } if (!bp->eee.eee_active) - edata->lp_advertised_u32 = 0; + linkmode_zero(edata->lp_advertised); return 0; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index a8ecef8ab82c..0ea0f4a36a04 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -46,9 +46,9 @@ struct bnxt_led_cfg { extern const struct ethtool_ops bnxt_ethtool_ops; u32 bnxt_get_rxfh_indir_size(struct net_device *dev); -u32 _bnxt_fw_to_ethtool_adv_spds(u16, u8); +void _bnxt_fw_to_linkmode(unsigned long *mode, u16 fw_speeds); u32 bnxt_fw_to_ethtool_speed(u16); -u16 bnxt_get_fw_auto_link_speeds(u32); +u16 bnxt_get_fw_auto_link_speeds(const unsigned long *mode); int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, struct hwrm_nvm_get_dev_info_output *nvm_dev_info); int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, From 0e0939c0adf90a3233392e2a9650290b1ad8068c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Feb 2024 16:53:18 +0000 Subject: [PATCH 0990/2255] net-procfs: use xarray iterator to implement /proc/net/dev In commit 759ab1edb56c ("net: store netdevs in an xarray") Jakub added net->dev_by_index to map ifindex to netdevices. We can get rid of the old hash table (net->dev_index_head), one patch at a time, if performance is acceptable. This patch removes unpleasant code to something more readable. As a bonus, /proc/net/dev gets netdevices sorted by their ifindex. Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20240207165318.3814525-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/core/net-procfs.c | 48 +++++++------------------------------------ 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c index 09f7ed1a04e8..2e4e96d30ee1 100644 --- a/net/core/net-procfs.c +++ b/net/core/net-procfs.c @@ -6,49 +6,18 @@ #include "dev.h" -#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1) - -#define get_bucket(x) ((x) >> BUCKET_SPACE) -#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1)) -#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o)) - -static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos) +static void *dev_seq_from_index(struct seq_file *seq, loff_t *pos) { - struct net *net = seq_file_net(seq); + unsigned long ifindex = *pos; struct net_device *dev; - struct hlist_head *h; - unsigned int count = 0, offset = get_offset(*pos); - h = &net->dev_index_head[get_bucket(*pos)]; - hlist_for_each_entry_rcu(dev, h, index_hlist) { - if (++count == offset) - return dev; + for_each_netdev_dump(seq_file_net(seq), dev, ifindex) { + *pos = dev->ifindex; + return dev; } - return NULL; } -static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos) -{ - struct net_device *dev; - unsigned int bucket; - - do { - dev = dev_from_same_bucket(seq, pos); - if (dev) - return dev; - - bucket = get_bucket(*pos) + 1; - *pos = set_bucket_offset(bucket, 1); - } while (bucket < NETDEV_HASHENTRIES); - - return NULL; -} - -/* - * This is invoked by the /proc filesystem handler to display a device - * in detail. - */ static void *dev_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) { @@ -56,16 +25,13 @@ static void *dev_seq_start(struct seq_file *seq, loff_t *pos) if (!*pos) return SEQ_START_TOKEN; - if (get_bucket(*pos) >= NETDEV_HASHENTRIES) - return NULL; - - return dev_from_bucket(seq, pos); + return dev_seq_from_index(seq, pos); } static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; - return dev_from_bucket(seq, pos); + return dev_seq_from_index(seq, pos); } static void dev_seq_stop(struct seq_file *seq, void *v) From a6c15d7ff29c1986fcf2df5c1ecb96dec835826f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 6 Feb 2024 11:50:49 +0000 Subject: [PATCH 0991/2255] netxen_nic: remove redundant assignment to variable capability The variable capability is being assigned a value that is never read and is being re-assigned later. The assignment is redundant and can be removed. Also remove empty line before assignment to capability. Cleans up clang scan build warning: drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c:1189:2: warning: Value stored to 'capability' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240206115049.1879389-1-colin.i.king@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 35ec9aab3dc7..51fa880eaf6c 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -1186,7 +1186,6 @@ static int netxen_p3_has_mn(struct netxen_adapter *adapter) { u32 capability, flashed_ver; - capability = 0; /* NX2031 always had MN */ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) @@ -1197,7 +1196,6 @@ netxen_p3_has_mn(struct netxen_adapter *adapter) flashed_ver = NETXEN_DECODE_VERSION(flashed_ver); if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { - capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); if (capability & NX_PEG_TUNE_MN_PRESENT) return 1; From c2da9408579d52fdf9b0ec494534d6ac66d4511e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 7 Feb 2024 09:28:37 +0000 Subject: [PATCH 0992/2255] ravb: Add Rx checksum offload support for GbEth TOE has hardware support for calculating IP header and TCP/UDP/ICMP checksum for both IPv4 and IPv6. Add Rx checksum offload supported by TOE for IPv4 and TCP/UDP protocols. For Rx, the 4-byte result of checksum calculation is attached to the Ethernet frames.First 2-bytes is result of IPv4 header checksum and next 2-bytes is TCP/UDP/ICMP checksum. If a frame does not have checksum error, 0x0000 is attached as checksum calculation result. For unsupported frames 0xFFFF is attached as checksum calculation result. In case of an IPv6 packet, IPv4 checksum is always set to 0xFFFF. We can test this functionality by the below commands ethtool -K eth0 rx on --> to turn on Rx checksum offload ethtool -K eth0 rx off --> to turn off Rx checksum offload Signed-off-by: Biju Das Reviewed-by: Sergey Shtylyov Link: https://lore.kernel.org/r/20240207092838.160627-2-biju.das.jz@bp.renesas.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/ravb.h | 19 ++++- drivers/net/ethernet/renesas/ravb_main.c | 92 +++++++++++++++++++++++- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 268ccfafe7aa..b98677c7c8e1 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -205,7 +205,10 @@ enum ravb_reg { TLFRCR = 0x0758, RFCR = 0x0760, MAFCR = 0x0778, - CSR0 = 0x0800, /* RZ/G2L only */ + + /* TOE registers (RZ/G2L only) */ + CSR0 = 0x0800, + CSR2 = 0x0808, }; @@ -978,6 +981,20 @@ enum CSR0_BIT { CSR0_RPE = 0x00000020, }; +enum CSR2_BIT { + CSR2_RIP4 = 0x00000001, + CSR2_RTCP4 = 0x00000010, + CSR2_RUDP4 = 0x00000020, + CSR2_RICMP4 = 0x00000040, + CSR2_RTCP6 = 0x00100000, + CSR2_RUDP6 = 0x00200000, + CSR2_RICMP6 = 0x00400000, + CSR2_RHOP = 0x01000000, + CSR2_RROUT = 0x02000000, + CSR2_RAHD = 0x04000000, + CSR2_RDHD = 0x08000000, +}; + #define DBAT_ENTRY_NUM 22 #define RX_QUEUE_OFFSET 4 #define NUM_RX_QUEUE 2 diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 9521cd054274..3e0c7977f2f8 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -512,6 +512,24 @@ error: return -ENOMEM; } +static void ravb_csum_init_gbeth(struct net_device *ndev) +{ + if (!(ndev->features & NETIF_F_RXCSUM)) + goto done; + + ravb_write(ndev, 0, CSR0); + if (ravb_wait(ndev, CSR0, CSR0_RPE, 0)) { + netdev_err(ndev, "Timeout enabling hardware checksum\n"); + ndev->features &= ~NETIF_F_RXCSUM; + } else { + ravb_write(ndev, CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4, + CSR2); + } + +done: + ravb_write(ndev, CSR0_TPE | CSR0_RPE, CSR0); +} + static void ravb_emac_init_gbeth(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); @@ -543,7 +561,8 @@ static void ravb_emac_init_gbeth(struct net_device *ndev) /* E-MAC status register clear */ ravb_write(ndev, ECSR_ICD | ECSR_LCHNG | ECSR_PFRI, ECSR); - ravb_write(ndev, CSR0_TPE | CSR0_RPE, CSR0); + + ravb_csum_init_gbeth(ndev); /* E-MAC interrupt enable register */ ravb_write(ndev, ECSIPR_ICDIP, ECSIPR); @@ -724,6 +743,30 @@ static void ravb_get_tx_tstamp(struct net_device *ndev) } } +static void ravb_rx_csum_gbeth(struct sk_buff *skb) +{ + __wsum csum_ip_hdr, csum_proto; + u8 *hw_csum; + + /* The hardware checksum status is contained in sizeof(__sum16) * 2 = 4 + * bytes appended to packet data. First 2 bytes is ip header checksum + * and last 2 bytes is protocol checksum. + */ + if (unlikely(skb->len < sizeof(__sum16) * 2)) + return; + + hw_csum = skb_tail_pointer(skb) - sizeof(__sum16); + csum_proto = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum)); + + hw_csum -= sizeof(__sum16); + csum_ip_hdr = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum)); + skb_trim(skb, skb->len - 2 * sizeof(__sum16)); + + /* TODO: IPV6 Rx checksum */ + if (skb->protocol == htons(ETH_P_IP) && !csum_ip_hdr && !csum_proto) + skb->ip_summed = CHECKSUM_UNNECESSARY; +} + static void ravb_rx_csum(struct sk_buff *skb) { u8 *hw_csum; @@ -809,6 +852,8 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) skb = ravb_get_skb_gbeth(ndev, entry, desc); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); + if (ndev->features & NETIF_F_RXCSUM) + ravb_rx_csum_gbeth(skb); napi_gro_receive(&priv->napi[q], skb); stats->rx_packets++; stats->rx_bytes += pkt_len; @@ -836,6 +881,8 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) dev_kfree_skb(skb); priv->rx_1st_skb->protocol = eth_type_trans(priv->rx_1st_skb, ndev); + if (ndev->features & NETIF_F_RXCSUM) + ravb_rx_csum_gbeth(skb); napi_gro_receive(&priv->napi[q], priv->rx_1st_skb); stats->rx_packets++; @@ -2389,11 +2436,48 @@ static void ravb_set_rx_csum(struct net_device *ndev, bool enable) spin_unlock_irqrestore(&priv->lock, flags); } +static int ravb_endisable_csum_gbeth(struct net_device *ndev, enum ravb_reg reg, + u32 val, u32 mask) +{ + u32 csr0 = CSR0_TPE | CSR0_RPE; + int ret; + + ravb_write(ndev, csr0 & ~mask, CSR0); + ret = ravb_wait(ndev, CSR0, mask, 0); + if (!ret) + ravb_write(ndev, val, reg); + + ravb_write(ndev, csr0, CSR0); + + return ret; +} + static int ravb_set_features_gbeth(struct net_device *ndev, netdev_features_t features) { - /* Place holder */ - return 0; + netdev_features_t changed = ndev->features ^ features; + struct ravb_private *priv = netdev_priv(ndev); + unsigned long flags; + int ret = 0; + u32 val; + + spin_lock_irqsave(&priv->lock, flags); + if (changed & NETIF_F_RXCSUM) { + if (features & NETIF_F_RXCSUM) + val = CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4; + else + val = 0; + + ret = ravb_endisable_csum_gbeth(ndev, CSR2, val, CSR0_RPE); + if (ret) + goto done; + } + + ndev->features = features; +done: + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; } static int ravb_set_features_rcar(struct net_device *ndev, @@ -2573,6 +2657,8 @@ static const struct ravb_hw_info gbeth_hw_info = { .emac_init = ravb_emac_init_gbeth, .gstrings_stats = ravb_gstrings_stats_gbeth, .gstrings_size = sizeof(ravb_gstrings_stats_gbeth), + .net_hw_features = NETIF_F_RXCSUM, + .net_features = NETIF_F_RXCSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats_gbeth), .max_rx_len = ALIGN(GBETH_RX_BUFF_MAX, RAVB_ALIGN), .tccr_mask = TCCR_TSRQ0, From 6c8e2803ef36d3c0c20c7019a19c668c3b0ac1d1 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 7 Feb 2024 09:28:38 +0000 Subject: [PATCH 0993/2255] ravb: Add Tx checksum offload support for GbEth TOE has hardware support for calculating IP header and TCP/UDP/ICMP checksum for both IPv4 and IPv6. Add Tx checksum offload supported by TOE for IPv4 and TCP/UDP. For Tx, the result of checksum calculation is set to the checksum field of each IPv4 Header/TCP/UDP/ICMP of ethernet frames. For the unsupported frames, those fields are not changed. If a transmission frame is an UDPv4 frame and its checksum value in the UDP header field is 0x0000, TOE does not calculate checksum for UDP part of this frame as it is optional function as per standards. We can test this functionality by the below commands ethtool -K eth0 tx on --> to turn on Tx checksum offload ethtool -K eth0 tx off --> to turn off Tx checksum offload Signed-off-by: Biju Das Reviewed-by: Sergey Shtylyov Link: https://lore.kernel.org/r/20240207092838.160627-3-biju.das.jz@bp.renesas.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/ravb.h | 15 +++++ drivers/net/ethernet/renesas/ravb_main.c | 71 +++++++++++++++++++++--- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index b98677c7c8e1..35e642fc4b2a 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -208,6 +208,7 @@ enum ravb_reg { /* TOE registers (RZ/G2L only) */ CSR0 = 0x0800, + CSR1 = 0x0804, CSR2 = 0x0808, }; @@ -981,6 +982,20 @@ enum CSR0_BIT { CSR0_RPE = 0x00000020, }; +enum CSR1_BIT { + CSR1_TIP4 = 0x00000001, + CSR1_TTCP4 = 0x00000010, + CSR1_TUDP4 = 0x00000020, + CSR1_TICMP4 = 0x00000040, + CSR1_TTCP6 = 0x00100000, + CSR1_TUDP6 = 0x00200000, + CSR1_TICMP6 = 0x00400000, + CSR1_THOP = 0x01000000, + CSR1_TROUT = 0x02000000, + CSR1_TAHD = 0x04000000, + CSR1_TDHD = 0x08000000, +}; + enum CSR2_BIT { CSR2_RIP4 = 0x00000001, CSR2_RTCP4 = 0x00000010, diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 3e0c7977f2f8..f9a1e9038dbf 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "ravb.h" @@ -514,16 +515,28 @@ error: static void ravb_csum_init_gbeth(struct net_device *ndev) { - if (!(ndev->features & NETIF_F_RXCSUM)) + bool tx_enable = ndev->features & NETIF_F_HW_CSUM; + bool rx_enable = ndev->features & NETIF_F_RXCSUM; + + if (!(tx_enable || rx_enable)) goto done; ravb_write(ndev, 0, CSR0); - if (ravb_wait(ndev, CSR0, CSR0_RPE, 0)) { + if (ravb_wait(ndev, CSR0, CSR0_TPE | CSR0_RPE, 0)) { netdev_err(ndev, "Timeout enabling hardware checksum\n"); - ndev->features &= ~NETIF_F_RXCSUM; + + if (tx_enable) + ndev->features &= ~NETIF_F_HW_CSUM; + + if (rx_enable) + ndev->features &= ~NETIF_F_RXCSUM; } else { - ravb_write(ndev, CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4, - CSR2); + if (tx_enable) + ravb_write(ndev, CSR1_TIP4 | CSR1_TTCP4 | CSR1_TUDP4, CSR1); + + if (rx_enable) + ravb_write(ndev, CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4, + CSR2); } done: @@ -2053,6 +2066,36 @@ out_unlock: rtnl_unlock(); } +static bool ravb_can_tx_csum_gbeth(struct sk_buff *skb) +{ + struct iphdr *ip = ip_hdr(skb); + + /* TODO: Need to add support for VLAN tag 802.1Q */ + if (skb_vlan_tag_present(skb)) + return false; + + /* TODO: Need to add hardware checksum for IPv6 */ + if (skb->protocol != htons(ETH_P_IP)) + return false; + + switch (ip->protocol) { + case IPPROTO_TCP: + break; + case IPPROTO_UDP: + /* If the checksum value in the UDP header field is 0, TOE does + * not calculate checksum for UDP part of this frame as it is + * optional function as per standards. + */ + if (udp_hdr(skb)->check == 0) + return false; + break; + default: + return false; + } + + return true; +} + /* Packet transmit function for Ethernet AVB */ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) { @@ -2068,6 +2111,9 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) u32 entry; u32 len; + if (skb->ip_summed == CHECKSUM_PARTIAL && !ravb_can_tx_csum_gbeth(skb)) + skb_checksum_help(skb); + spin_lock_irqsave(&priv->lock, flags); if (priv->cur_tx[q] - priv->dirty_tx[q] > (priv->num_tx_ring[q] - 1) * num_tx_desc) { @@ -2473,6 +2519,17 @@ static int ravb_set_features_gbeth(struct net_device *ndev, goto done; } + if (changed & NETIF_F_HW_CSUM) { + if (features & NETIF_F_HW_CSUM) + val = CSR1_TIP4 | CSR1_TTCP4 | CSR1_TUDP4; + else + val = 0; + + ret = ravb_endisable_csum_gbeth(ndev, CSR1, val, CSR0_TPE); + if (ret) + goto done; + } + ndev->features = features; done: spin_unlock_irqrestore(&priv->lock, flags); @@ -2657,8 +2714,8 @@ static const struct ravb_hw_info gbeth_hw_info = { .emac_init = ravb_emac_init_gbeth, .gstrings_stats = ravb_gstrings_stats_gbeth, .gstrings_size = sizeof(ravb_gstrings_stats_gbeth), - .net_hw_features = NETIF_F_RXCSUM, - .net_features = NETIF_F_RXCSUM, + .net_hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM, + .net_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats_gbeth), .max_rx_len = ALIGN(GBETH_RX_BUFF_MAX, RAVB_ALIGN), .tccr_mask = TCCR_TSRQ0, From e7689879d14ee730085c2f5974003c2d0ebbebc6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Feb 2024 15:35:14 +0000 Subject: [PATCH 0994/2255] ethtool: do not use rtnl in ethnl_default_dumpit() for_each_netdev_dump() can be used with RCU protection, no need for rtnl if we are going to use dev_hold()/dev_put(). Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20240207153514.3640952-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ethtool/netlink.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index fe3553f60bf3..bd04f28d5cf4 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -477,11 +477,7 @@ out: return ret; } -/* Default ->dumpit() handler for GET requests. Device iteration copied from - * rtnl_dump_ifinfo(); we have to be more careful about device hashtable - * persistence as we cannot guarantee to hold RTNL lock through the whole - * function as rtnetnlink does. - */ +/* Default ->dumpit() handler for GET requests. */ static int ethnl_default_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { @@ -490,14 +486,14 @@ static int ethnl_default_dumpit(struct sk_buff *skb, struct net_device *dev; int ret = 0; - rtnl_lock(); + rcu_read_lock(); for_each_netdev_dump(net, dev, ctx->pos_ifindex) { dev_hold(dev); - rtnl_unlock(); + rcu_read_unlock(); ret = ethnl_default_dump_one(skb, dev, ctx, genl_info_dump(cb)); - rtnl_lock(); + rcu_read_lock(); dev_put(dev); if (ret < 0 && ret != -EOPNOTSUPP) { @@ -507,7 +503,7 @@ static int ethnl_default_dumpit(struct sk_buff *skb, } ret = 0; } - rtnl_unlock(); + rcu_read_unlock(); return ret; } From 1476de6d2b578673e20fb4cf654ff61cf2782873 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 30 Jan 2024 16:14:11 +0800 Subject: [PATCH 0995/2255] xfrm: Simplify the allocation of slab caches in xfrm_policy_init commit 0a31bd5f2bbb ("KMEM_CACHE(): simplify slab cache creation") introduces a new macro. Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_policy.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b4850a8f14ad..53b7ce4a4db0 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -4163,10 +4163,7 @@ static int __net_init xfrm_policy_init(struct net *net) int dir, err; if (net_eq(net, &init_net)) { - xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", - sizeof(struct xfrm_dst), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL); + xfrm_dst_cache = KMEM_CACHE(xfrm_dst, SLAB_HWCACHE_ALIGN | SLAB_PANIC); err = rhashtable_init(&xfrm_policy_inexact_table, &xfrm_pol_inexact_params); BUG_ON(err); From d4655db0a1e11eeacc55c44c81121c83b087982e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 9 Feb 2024 08:04:23 +0100 Subject: [PATCH 0996/2255] wifi: cfg80211: fix kernel-doc for cfg80211_chandef_primary This was still referring to cfg80211_chandef_primary_freq(), fix it. Reported-by: Stephen Rothwell Fixes: b82730bf57b5 ("wifi: cfg80211/mac80211: move puncturing into chandef") Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d4c83ea3213d..f52f989a54ad 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1053,7 +1053,7 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef); /** - * cfg80211_chandef_primary_freq - calculate primary 40/80/160 MHz freq + * cfg80211_chandef_primary - 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 From 602ad3b4dd578631a250edb03f36f8e5f911ec1a Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:32 -0800 Subject: [PATCH 0997/2255] net: netconsole: cleanup formatting lints Address checkpatch lint suggestions in preparation for later changes Signed-off-by: Matthew Wood Reviewed-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 6e14ba5e06c8..93fc3b509706 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -49,7 +49,7 @@ static char config[MAX_PARAM_LENGTH]; module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]"); -static bool oops_only = false; +static bool oops_only; module_param(oops_only, bool, 0600); MODULE_PARM_DESC(oops_only, "Only log oops messages"); @@ -501,6 +501,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, if (strnchr(buf, count, ':')) { const char *end; + if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) { if (*end && *end != '\n') { pr_err("invalid IPv6 address at: <%c>\n", *end); @@ -510,9 +511,9 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, } else goto out_unlock; } else { - if (!nt->np.ipv6) { + if (!nt->np.ipv6) nt->np.local_ip.ip = in_aton(buf); - } else + else goto out_unlock; } @@ -537,6 +538,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, if (strnchr(buf, count, ':')) { const char *end; + if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) { if (*end && *end != '\n') { pr_err("invalid IPv6 address at: <%c>\n", *end); @@ -546,9 +548,9 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, } else goto out_unlock; } else { - if (!nt->np.ipv6) { + if (!nt->np.ipv6) nt->np.remote_ip.ip = in_aton(buf); - } else + else goto out_unlock; } @@ -781,6 +783,7 @@ restart: spin_unlock_irqrestore(&target_list_lock, flags); if (stopped) { const char *msg = "had an event"; + switch (event) { case NETDEV_UNREGISTER: msg = "unregistered"; From bd9c69a36efd863ac915caa0f9e6dd57be0dde3e Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:33 -0800 Subject: [PATCH 0998/2255] net: netconsole: move netconsole_target config_item to config_group In order to support a nested userdata config_group in later patches, use a config_group for netconsole_target instead of a config_item. It's a no-op functionality-wise, since config_group maintains all features of a config_item via the cg_item member. Signed-off-by: Matthew Wood Reviewed-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 58 +++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 93fc3b509706..12bfb7eaae7f 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -79,7 +79,7 @@ static struct console netconsole_ext; /** * struct netconsole_target - Represents a configured netconsole target. * @list: Links this target into the target_list. - * @item: Links us into the configfs subsystem hierarchy. + * @group: Links us into the configfs subsystem hierarchy. * @enabled: On / off knob to enable / disable target. * Visible from userspace (read-write). * We maintain a strict 1:1 correspondence between this and @@ -102,7 +102,7 @@ static struct console netconsole_ext; struct netconsole_target { struct list_head list; #ifdef CONFIG_NETCONSOLE_DYNAMIC - struct config_item item; + struct config_group group; #endif bool enabled; bool extended; @@ -134,14 +134,14 @@ static void __exit dynamic_netconsole_exit(void) */ static void netconsole_target_get(struct netconsole_target *nt) { - if (config_item_name(&nt->item)) - config_item_get(&nt->item); + if (config_item_name(&nt->group.cg_item)) + config_group_get(&nt->group); } static void netconsole_target_put(struct netconsole_target *nt) { - if (config_item_name(&nt->item)) - config_item_put(&nt->item); + if (config_item_name(&nt->group.cg_item)) + config_group_put(&nt->group); } #else /* !CONFIG_NETCONSOLE_DYNAMIC */ @@ -221,9 +221,13 @@ static struct netconsole_target *alloc_and_init(void) static struct netconsole_target *to_target(struct config_item *item) { - return item ? - container_of(item, struct netconsole_target, item) : - NULL; + struct config_group *cfg_group; + + cfg_group = to_config_group(item); + if (!cfg_group) + return NULL; + return container_of(to_config_group(item), + struct netconsole_target, group); } /* @@ -370,7 +374,7 @@ static ssize_t release_store(struct config_item *item, const char *buf, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); err = -EINVAL; goto out_unlock; } @@ -398,7 +402,7 @@ static ssize_t extended_store(struct config_item *item, const char *buf, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); err = -EINVAL; goto out_unlock; } @@ -425,7 +429,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); mutex_unlock(&dynamic_netconsole_mutex); return -EINVAL; } @@ -450,7 +454,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); goto out_unlock; } @@ -473,7 +477,7 @@ static ssize_t remote_port_store(struct config_item *item, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); goto out_unlock; } @@ -495,7 +499,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); goto out_unlock; } @@ -532,7 +536,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); goto out_unlock; } @@ -570,7 +574,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf, mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", - config_item_name(&nt->item)); + config_item_name(&nt->group.cg_item)); goto out_unlock; } @@ -638,7 +642,7 @@ static struct netconsole_target *find_cmdline_target(const char *name) spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { - if (!strcmp(nt->item.ci_name, name)) { + if (!strcmp(nt->group.cg_item.ci_name, name)) { ret = nt; break; } @@ -652,8 +656,8 @@ static struct netconsole_target *find_cmdline_target(const char *name) * Group operations and type for netconsole_subsys. */ -static struct config_item *make_netconsole_target(struct config_group *group, - const char *name) +static struct config_group *make_netconsole_target(struct config_group *group, + const char *name) { struct netconsole_target *nt; unsigned long flags; @@ -666,7 +670,7 @@ static struct config_item *make_netconsole_target(struct config_group *group, strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) { nt = find_cmdline_target(name); if (nt) - return &nt->item; + return &nt->group; } nt = alloc_and_init(); @@ -674,14 +678,14 @@ static struct config_item *make_netconsole_target(struct config_group *group, return ERR_PTR(-ENOMEM); /* Initialize the config_item member */ - config_item_init_type_name(&nt->item, name, &netconsole_target_type); + config_group_init_type_name(&nt->group, name, &netconsole_target_type); /* Adding, but it is disabled */ spin_lock_irqsave(&target_list_lock, flags); list_add(&nt->list, &target_list); spin_unlock_irqrestore(&target_list_lock, flags); - return &nt->item; + return &nt->group; } static void drop_netconsole_target(struct config_group *group, @@ -701,11 +705,11 @@ static void drop_netconsole_target(struct config_group *group, if (nt->enabled) netpoll_cleanup(&nt->np); - config_item_put(&nt->item); + config_item_put(&nt->group.cg_item); } static struct configfs_group_operations netconsole_subsys_group_ops = { - .make_item = make_netconsole_target, + .make_group = make_netconsole_target, .drop_item = drop_netconsole_target, }; @@ -731,8 +735,8 @@ static void populate_configfs_item(struct netconsole_target *nt, snprintf(target_name, sizeof(target_name), "%s%d", NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count); - config_item_init_type_name(&nt->item, target_name, - &netconsole_target_type); + config_group_init_type_name(&nt->group, target_name, + &netconsole_target_type); } #endif /* CONFIG_NETCONSOLE_DYNAMIC */ From ae001dc67907618423fd15bbab2014308c00ad0b Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:34 -0800 Subject: [PATCH 0999/2255] net: netconsole: move newline trimming to function Move newline trimming logic from `dev_name_store()` to a new function (trim_newline()) for shared use in netconsole.c Signed-off-by: Matthew Wood Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 12bfb7eaae7f..e6c3b15fe95d 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -230,6 +230,16 @@ static struct netconsole_target *to_target(struct config_item *item) struct netconsole_target, group); } +/* Get rid of possible trailing newline, returning the new length */ +static void trim_newline(char *s, size_t maxlen) +{ + size_t len; + + len = strnlen(s, maxlen); + if (s[len - 1] == '\n') + s[len - 1] = '\0'; +} + /* * Attribute operations for netconsole_target. */ @@ -424,7 +434,6 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, size_t count) { struct netconsole_target *nt = to_target(item); - size_t len; mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { @@ -435,11 +444,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, } strscpy(nt->np.dev_name, buf, IFNAMSIZ); - - /* Get rid of possible trailing newline from echo(1) */ - len = strnlen(nt->np.dev_name, IFNAMSIZ); - if (nt->np.dev_name[len - 1] == '\n') - nt->np.dev_name[len - 1] = '\0'; + trim_newline(nt->np.dev_name, IFNAMSIZ); mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); From aa7b608d69ea9dfd65ef3694b22a2017d54e3d5b Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:35 -0800 Subject: [PATCH 1000/2255] net: netconsole: add docs for appending netconsole user data Add a new User Data section to the netconsole docs to describe the appending of user data capability (for netconsole dynamic configuration) with usage and netconsole output examples. Co-developed-by: Breno Leitao Signed-off-by: Breno Leitao Signed-off-by: Matthew Wood Signed-off-by: David S. Miller --- Documentation/networking/netconsole.rst | 66 +++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst index 390730a74332..b28c525e5d1e 100644 --- a/Documentation/networking/netconsole.rst +++ b/Documentation/networking/netconsole.rst @@ -15,6 +15,8 @@ Extended console support by Tejun Heo , May 1 2015 Release prepend support by Breno Leitao , Jul 7 2023 +Userdata append support by Matthew Wood , Jan 22 2024 + Please send bug reports to Matt Mackall Satyam Sharma , and Cong Wang @@ -171,6 +173,70 @@ You can modify these targets in runtime by creating the following targets:: cat cmdline1/remote_ip 10.0.0.3 +Append User Data +---------------- + +Custom user data can be appended to the end of messages with netconsole +dynamic configuration enabled. User data entries can be modified without +changing the "enabled" attribute of a target. + +Directories (keys) under `userdata` are limited to 54 character length, and +data in `userdata//value` are limited to 200 bytes:: + + cd /sys/kernel/config/netconsole && mkdir cmdline0 + cd cmdline0 + mkdir userdata/foo + echo bar > userdata/foo/value + mkdir userdata/qux + echo baz > userdata/qux/value + +Messages will now include this additional user data:: + + echo "This is a message" > /dev/kmsg + +Sends:: + + 12,607,22085407756,-;This is a message + foo=bar + qux=baz + +Preview the userdata that will be appended with:: + + cd /sys/kernel/config/netconsole/cmdline0/userdata + for f in `ls userdata`; do echo $f=$(cat userdata/$f/value); done + +If a `userdata` entry is created but no data is written to the `value` file, +the entry will be omitted from netconsole messages:: + + cd /sys/kernel/config/netconsole && mkdir cmdline0 + cd cmdline0 + mkdir userdata/foo + echo bar > userdata/foo/value + mkdir userdata/qux + +The `qux` key is omitted since it has no value:: + + echo "This is a message" > /dev/kmsg + 12,607,22085407756,-;This is a message + foo=bar + +Delete `userdata` entries with `rmdir`:: + + rmdir /sys/kernel/config/netconsole/cmdline0/userdata/qux + +.. warning:: + When writing strings to user data values, input is broken up per line in + configfs store calls and this can cause confusing behavior:: + + mkdir userdata/testing + printf "val1\nval2" > userdata/testing/value + # userdata store value is called twice, first with "val1\n" then "val2" + # so "val2" is stored, being the last value stored + cat userdata/testing/value + val2 + + It is recommended to not write user data values with newlines. + Extended console: ================= From 8a6d5fec6c7f952d66ad362c249100d040a21e3f Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:36 -0800 Subject: [PATCH 1001/2255] net: netconsole: add a userdata config_group member to netconsole_target Create configfs machinery for netconsole userdata appending, which depends on CONFIG_NETCONSOLE_DYNAMIC (for configfs interface). Add a userdata config_group to netconsole_target for managing userdata entries as a tree under the netconsole configfs subsystem. Directory names created under the userdata directory become userdatum keys; the userdatum value is the content of the value file. Include the minimum-viable-changes for userdata configfs config_group. init_target_config_group() ties in the complete configfs machinery to avoid unused func/variable errors during build. Initializing the netconsole_target->group is moved to init_target_config_group, which will also init and add the userdata config_group. Each userdatum entry has a limit of 256 bytes (54 for the key/directory, 200 for the value, and 2 for '=' and '\n' characters), which is enforced by the configfs functions for updating the userdata config_group. When a new netconsole_target is created, initialize the userdata config_group and add it as a default group for netconsole_target config_group, allowing the userdata configfs sub-tree to be presented in the netconsole configfs tree under the userdata directory. Co-developed-by: Breno Leitao Signed-off-by: Breno Leitao Signed-off-by: Matthew Wood Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 147 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 5 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e6c3b15fe95d..3618b9ebcce4 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -43,6 +43,10 @@ MODULE_DESCRIPTION("Console driver for network interfaces"); MODULE_LICENSE("GPL"); #define MAX_PARAM_LENGTH 256 +#define MAX_USERDATA_NAME_LENGTH 54 +#define MAX_USERDATA_VALUE_LENGTH 200 +#define MAX_USERDATA_ENTRY_LENGTH 256 +#define MAX_USERDATA_ITEMS 16 #define MAX_PRINT_CHUNK 1000 static char config[MAX_PARAM_LENGTH]; @@ -80,6 +84,7 @@ static struct console netconsole_ext; * struct netconsole_target - Represents a configured netconsole target. * @list: Links this target into the target_list. * @group: Links us into the configfs subsystem hierarchy. + * @userdata_group: Links to the userdata configfs hierarchy * @enabled: On / off knob to enable / disable target. * Visible from userspace (read-write). * We maintain a strict 1:1 correspondence between this and @@ -103,6 +108,7 @@ struct netconsole_target { struct list_head list; #ifdef CONFIG_NETCONSOLE_DYNAMIC struct config_group group; + struct config_group userdata_group; #endif bool enabled; bool extended; @@ -215,6 +221,10 @@ static struct netconsole_target *alloc_and_init(void) * | remote_ip * | local_mac * | remote_mac + * | userdata/ + * | / + * | value + * | ... * | * /... */ @@ -596,6 +606,123 @@ out_unlock: return -EINVAL; } +struct userdatum { + struct config_item item; + char value[MAX_USERDATA_VALUE_LENGTH]; +}; + +static struct userdatum *to_userdatum(struct config_item *item) +{ + return container_of(item, struct userdatum, item); +} + +struct userdata { + struct config_group group; +}; + +static struct userdata *to_userdata(struct config_item *item) +{ + return container_of(to_config_group(item), struct userdata, group); +} + +static struct netconsole_target *userdata_to_target(struct userdata *ud) +{ + struct config_group *netconsole_group; + + netconsole_group = to_config_group(ud->group.cg_item.ci_parent); + return to_target(&netconsole_group->cg_item); +} + +static ssize_t userdatum_value_show(struct config_item *item, char *buf) +{ + return sysfs_emit(buf, "%s\n", &(to_userdatum(item)->value[0])); +} + +static ssize_t userdatum_value_store(struct config_item *item, const char *buf, + size_t count) +{ + struct userdatum *udm = to_userdatum(item); + int ret; + + if (count > MAX_USERDATA_VALUE_LENGTH) + return -EMSGSIZE; + + mutex_lock(&dynamic_netconsole_mutex); + + ret = strscpy(udm->value, buf, sizeof(udm->value)); + if (ret < 0) + goto out_unlock; + trim_newline(udm->value, sizeof(udm->value)); + + mutex_unlock(&dynamic_netconsole_mutex); + return count; +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return ret; +} + +CONFIGFS_ATTR(userdatum_, value); + +static struct configfs_attribute *userdatum_attrs[] = { + &userdatum_attr_value, + NULL, +}; + +static void userdatum_release(struct config_item *item) +{ + kfree(to_userdatum(item)); +} + +static struct configfs_item_operations userdatum_ops = { + .release = userdatum_release, +}; + +static const struct config_item_type userdatum_type = { + .ct_item_ops = &userdatum_ops, + .ct_attrs = userdatum_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_item *userdatum_make_item(struct config_group *group, + const char *name) +{ + struct netconsole_target *nt; + struct userdatum *udm; + struct userdata *ud; + size_t child_count; + + if (strlen(name) > MAX_USERDATA_NAME_LENGTH) + return ERR_PTR(-ENAMETOOLONG); + + ud = to_userdata(&group->cg_item); + nt = userdata_to_target(ud); + child_count = list_count_nodes(&nt->userdata_group.cg_children); + if (child_count >= MAX_USERDATA_ITEMS) + return ERR_PTR(-ENOSPC); + + udm = kzalloc(sizeof(*udm), GFP_KERNEL); + if (!udm) + return ERR_PTR(-ENOMEM); + + config_item_init_type_name(&udm->item, name, &userdatum_type); + return &udm->item; +} + +static struct configfs_attribute *userdata_attrs[] = { + NULL, +}; + +static struct configfs_group_operations userdata_ops = { + .make_item = userdatum_make_item, +}; + +static struct config_item_type userdata_type = { + .ct_item_ops = &userdatum_ops, + .ct_group_ops = &userdata_ops, + .ct_attrs = userdata_attrs, + .ct_owner = THIS_MODULE, +}; + CONFIGFS_ATTR(, enabled); CONFIGFS_ATTR(, extended); CONFIGFS_ATTR(, dev_name); @@ -640,6 +767,15 @@ static const struct config_item_type netconsole_target_type = { .ct_owner = THIS_MODULE, }; +static void init_target_config_group(struct netconsole_target *nt, + const char *name) +{ + config_group_init_type_name(&nt->group, name, &netconsole_target_type); + config_group_init_type_name(&nt->userdata_group, "userdata", + &userdata_type); + configfs_add_default_group(&nt->userdata_group, &nt->group); +} + static struct netconsole_target *find_cmdline_target(const char *name) { struct netconsole_target *nt, *ret = NULL; @@ -674,16 +810,18 @@ static struct config_group *make_netconsole_target(struct config_group *group, if (!strncmp(name, NETCONSOLE_PARAM_TARGET_PREFIX, strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) { nt = find_cmdline_target(name); - if (nt) + if (nt) { + init_target_config_group(nt, name); return &nt->group; + } } nt = alloc_and_init(); if (!nt) return ERR_PTR(-ENOMEM); - /* Initialize the config_item member */ - config_group_init_type_name(&nt->group, name, &netconsole_target_type); + /* Initialize the config_group member */ + init_target_config_group(nt, name); /* Adding, but it is disabled */ spin_lock_irqsave(&target_list_lock, flags); @@ -740,8 +878,7 @@ static void populate_configfs_item(struct netconsole_target *nt, snprintf(target_name, sizeof(target_name), "%s%d", NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count); - config_group_init_type_name(&nt->group, target_name, - &netconsole_target_type); + init_target_config_group(nt, target_name); } #endif /* CONFIG_NETCONSOLE_DYNAMIC */ From df03f830d099f0811281a222aefdd9d400fa0b72 Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:37 -0800 Subject: [PATCH 1002/2255] net: netconsole: cache userdata formatted string in netconsole_target Store a formatted string for userdata that will be appended to netconsole messages. The string has a capacity of 4KB, as calculated by the userdatum entry length of 256 bytes and a max of 16 userdata entries. Update the stored netconsole_target->userdata_complete string with the new formatted userdata values when a userdatum is created, edited, or removed. Each userdata entry contains a trailing newline, which will be formatted as such in netconsole messages:: 6.7.0-rc8-virtme,12,500,1646292204,-;test release=foo something=bar 6.7.0-rc8-virtme,12,500,1646292204,-;another test release=foo something=bar Enforcement of MAX_USERDATA_ITEMS is done in userdatum_make_item; update_userdata will not check for this case but will skip any userdata children over the limit of MAX_USERDATA_ITEMs. If a userdata entry/dir is created but no value is provided, that entry will be skipped. This is in part because update_userdata() can't be called in userdatum_make_item() since the item will not have been added to the userdata config_group children yet. To preserve the experience of adding an empty userdata that doesn't show up in the netconsole messages, purposefully skip empty userdata items even when update_userdata() can be called. Co-developed-by: Breno Leitao Signed-off-by: Breno Leitao Signed-off-by: Matthew Wood Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 3618b9ebcce4..e4d6ba0b50ef 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -85,6 +85,8 @@ static struct console netconsole_ext; * @list: Links this target into the target_list. * @group: Links us into the configfs subsystem hierarchy. * @userdata_group: Links to the userdata configfs hierarchy + * @userdata_complete: Cached, formatted string of append + * @userdata_length: String length of userdata_complete * @enabled: On / off knob to enable / disable target. * Visible from userspace (read-write). * We maintain a strict 1:1 correspondence between this and @@ -109,6 +111,8 @@ struct netconsole_target { #ifdef CONFIG_NETCONSOLE_DYNAMIC struct config_group group; struct config_group userdata_group; + char userdata_complete[MAX_USERDATA_ENTRY_LENGTH * MAX_USERDATA_ITEMS]; + size_t userdata_length; #endif bool enabled; bool extended; @@ -638,10 +642,48 @@ static ssize_t userdatum_value_show(struct config_item *item, char *buf) return sysfs_emit(buf, "%s\n", &(to_userdatum(item)->value[0])); } +static void update_userdata(struct netconsole_target *nt) +{ + int complete_idx = 0, child_count = 0; + struct list_head *entry; + + /* Clear the current string in case the last userdatum was deleted */ + nt->userdata_length = 0; + nt->userdata_complete[0] = 0; + + list_for_each(entry, &nt->userdata_group.cg_children) { + struct userdatum *udm_item; + struct config_item *item; + + if (child_count >= MAX_USERDATA_ITEMS) + break; + child_count++; + + item = container_of(entry, struct config_item, ci_entry); + udm_item = to_userdatum(item); + + /* Skip userdata with no value set */ + if (strnlen(udm_item->value, MAX_USERDATA_VALUE_LENGTH) == 0) + continue; + + /* This doesn't overflow userdata_complete since it will write + * one entry length (1/MAX_USERDATA_ITEMS long), entry count is + * checked to not exceed MAX items with child_count above + */ + complete_idx += scnprintf(&nt->userdata_complete[complete_idx], + MAX_USERDATA_ENTRY_LENGTH, "%s=%s\n", + item->ci_name, udm_item->value); + } + nt->userdata_length = strnlen(nt->userdata_complete, + sizeof(nt->userdata_complete)); +} + static ssize_t userdatum_value_store(struct config_item *item, const char *buf, size_t count) { struct userdatum *udm = to_userdatum(item); + struct netconsole_target *nt; + struct userdata *ud; int ret; if (count > MAX_USERDATA_VALUE_LENGTH) @@ -654,6 +696,10 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, goto out_unlock; trim_newline(udm->value, sizeof(udm->value)); + ud = to_userdata(item->ci_parent); + nt = userdata_to_target(ud); + update_userdata(nt); + mutex_unlock(&dynamic_netconsole_mutex); return count; out_unlock: @@ -708,12 +754,27 @@ static struct config_item *userdatum_make_item(struct config_group *group, return &udm->item; } +static void userdatum_drop(struct config_group *group, struct config_item *item) +{ + struct netconsole_target *nt; + struct userdata *ud; + + ud = to_userdata(&group->cg_item); + nt = userdata_to_target(ud); + + mutex_lock(&dynamic_netconsole_mutex); + update_userdata(nt); + config_item_put(item); + mutex_unlock(&dynamic_netconsole_mutex); +} + static struct configfs_attribute *userdata_attrs[] = { NULL, }; static struct configfs_group_operations userdata_ops = { .make_item = userdatum_make_item, + .drop_item = userdatum_drop, }; static struct config_item_type userdata_type = { From b4ab4f2c0ff5f6b5aeccd71c5caeef2cbcfea47d Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:38 -0800 Subject: [PATCH 1003/2255] net: netconsole: append userdata to netconsole messages Append userdata to outgoing unfragmented (<1000 bytes) netconsole messages. When sending messages the userdata string is already formatted and stored in netconsole_target->userdata_complete. Always write the outgoing message to buf, so userdata can be appended in a standard fashion. This is a change from only using buf when the release needs to be prepended to the message. Co-developed-by: Breno Leitao Signed-off-by: Breno Leitao Signed-off-by: Matthew Wood Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e4d6ba0b50ef..d53bb1172336 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -1034,19 +1034,34 @@ static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg, const char *msg_ready = msg; const char *release; int release_len = 0; + int userdata_len = 0; + char *userdata = NULL; + +#ifdef CONFIG_NETCONSOLE_DYNAMIC + userdata = nt->userdata_complete; + userdata_len = nt->userdata_length; +#endif if (nt->release) { release = init_utsname()->release; release_len = strlen(release) + 1; } - if (msg_len + release_len <= MAX_PRINT_CHUNK) { + if (msg_len + release_len + userdata_len <= MAX_PRINT_CHUNK) { /* No fragmentation needed */ if (nt->release) { scnprintf(buf, MAX_PRINT_CHUNK, "%s,%s", release, msg); msg_len += release_len; - msg_ready = buf; + } else { + memcpy(buf, msg, msg_len); } + + if (userdata) + msg_len += scnprintf(&buf[msg_len], + MAX_PRINT_CHUNK - msg_len, + "%s", userdata); + + msg_ready = buf; netpoll_send_udp(&nt->np, msg_ready, msg_len); return; } From 1ec9daf950936c2a1c591596e83c09ce2eb12ade Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Sun, 4 Feb 2024 15:27:39 -0800 Subject: [PATCH 1004/2255] net: netconsole: append userdata to fragmented netconsole messages Regardless of whether the original message body or formatted userdata exceeds the MAX_PRINT_CHUNK, append userdata to the netconsole message starting with the first chunk that has available space after writing the body. Co-developed-by: Breno Leitao Signed-off-by: Breno Leitao Signed-off-by: Matthew Wood Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 44 +++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index d53bb1172336..0de108a1c0c8 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -1085,24 +1085,48 @@ static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg, memcpy(buf + release_len, header, header_len); header_len += release_len; - while (offset < body_len) { + while (offset < body_len + userdata_len) { int this_header = header_len; - int this_chunk; + int this_offset = 0; + int this_chunk = 0; this_header += scnprintf(buf + this_header, sizeof(buf) - this_header, - ",ncfrag=%d/%d;", offset, body_len); + ",ncfrag=%d/%d;", offset, + body_len + userdata_len); - this_chunk = min(body_len - offset, - MAX_PRINT_CHUNK - this_header); - if (WARN_ON_ONCE(this_chunk <= 0)) - return; + /* Not all body data has been written yet */ + if (offset < body_len) { + this_chunk = min(body_len - offset, + MAX_PRINT_CHUNK - this_header); + if (WARN_ON_ONCE(this_chunk <= 0)) + return; + memcpy(buf + this_header, body + offset, this_chunk); + this_offset += this_chunk; + } + /* Body is fully written and there is pending userdata to write, + * append userdata in this chunk + */ + if (offset + this_offset >= body_len && + offset + this_offset < userdata_len + body_len) { + int sent_userdata = (offset + this_offset) - body_len; + int preceding_bytes = this_chunk + this_header; - memcpy(buf + this_header, body + offset, this_chunk); + if (WARN_ON_ONCE(sent_userdata < 0)) + return; - netpoll_send_udp(&nt->np, buf, this_header + this_chunk); + this_chunk = min(userdata_len - sent_userdata, + MAX_PRINT_CHUNK - preceding_bytes); + if (WARN_ON_ONCE(this_chunk <= 0)) + return; + memcpy(buf + this_header + this_offset, + userdata + sent_userdata, + this_chunk); + this_offset += this_chunk; + } - offset += this_chunk; + netpoll_send_udp(&nt->np, buf, this_header + this_offset); + offset += this_offset; } } From e3caf184107a4e2e196528b98b218ddc41e4cb8c Mon Sep 17 00:00:00 2001 From: Jinjian Song Date: Mon, 5 Feb 2024 18:22:27 +0800 Subject: [PATCH 1005/2255] wwan: core: Add WWAN fastboot port type Add a new WWAN port that connects to the device fastboot protocol interface. Signed-off-by: Jinjian Song Signed-off-by: David S. Miller --- drivers/net/wwan/wwan_core.c | 4 ++++ include/linux/wwan.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index 72e01e550a16..2ed20b20e7fc 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -328,6 +328,10 @@ static const struct { .name = "XMMRPC", .devsuf = "xmmrpc", }, + [WWAN_PORT_FASTBOOT] = { + .name = "FASTBOOT", + .devsuf = "fastboot", + }, }; static ssize_t type_show(struct device *dev, struct device_attribute *attr, diff --git a/include/linux/wwan.h b/include/linux/wwan.h index 01fa15506286..170fdee6339c 100644 --- a/include/linux/wwan.h +++ b/include/linux/wwan.h @@ -16,6 +16,7 @@ * @WWAN_PORT_QCDM: Qcom Modem diagnostic interface * @WWAN_PORT_FIREHOSE: XML based command protocol * @WWAN_PORT_XMMRPC: Control protocol for Intel XMM modems + * @WWAN_PORT_FASTBOOT: Fastboot protocol control * * @WWAN_PORT_MAX: Highest supported port types * @WWAN_PORT_UNKNOWN: Special value to indicate an unknown port type @@ -28,6 +29,7 @@ enum wwan_port_type { WWAN_PORT_QCDM, WWAN_PORT_FIREHOSE, WWAN_PORT_XMMRPC, + WWAN_PORT_FASTBOOT, /* Add new port types above this line */ From 409c38d4f156740bf3165fd6ceae4fa6425eebf4 Mon Sep 17 00:00:00 2001 From: Jinjian Song Date: Mon, 5 Feb 2024 18:22:28 +0800 Subject: [PATCH 1006/2255] net: wwan: t7xx: Add sysfs attribute for device state machine Add support for userspace to get/set the device mode, device's state machine changes between (unknown/ready/reset/fastboot). Get the device state mode: - 'cat /sys/bus/pci/devices/${bdf}/t7xx_mode' Set the device state mode: - reset(cold reset): 'echo reset > /sys/bus/pci/devices/${bdf}/t7xx_mode' - fastboot: 'echo fastboot_switching > /sys/bus/pci/devices/${bdf}/t7xx_mode' Reload driver to get the new device state after setting operation. Signed-off-by: Jinjian Song Signed-off-by: David S. Miller --- .../networking/device_drivers/wwan/t7xx.rst | 28 +++++ drivers/net/wwan/t7xx/t7xx_modem_ops.c | 6 ++ drivers/net/wwan/t7xx/t7xx_modem_ops.h | 1 + drivers/net/wwan/t7xx/t7xx_pci.c | 101 +++++++++++++++++- drivers/net/wwan/t7xx/t7xx_pci.h | 14 ++- drivers/net/wwan/t7xx/t7xx_state_monitor.c | 1 + 6 files changed, 145 insertions(+), 6 deletions(-) diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst index dd5b731957ca..8429b9927341 100644 --- a/Documentation/networking/device_drivers/wwan/t7xx.rst +++ b/Documentation/networking/device_drivers/wwan/t7xx.rst @@ -39,6 +39,34 @@ command and receive response: - open the AT control channel using a UART tool or a special user tool +Sysfs +===== +The driver provides sysfs interfaces to userspace. + +t7xx_mode +--------- +The sysfs interface provides userspace with access to the device mode, this interface +supports read and write operations. + +Device mode: + +- ``unknown`` represents that device in unknown status +- ``ready`` represents that device in ready status +- ``reset`` represents that device in reset status +- ``fastboot_switching`` represents that device in fastboot switching status +- ``fastboot_download`` represents that device in fastboot download status +- ``fastboot_dump`` represents that device in fastboot dump status + +Read from userspace to get the current device mode. + +:: + $ cat /sys/bus/pci/devices/${bdf}/t7xx_mode + +Write from userspace to set the device mode. + +:: + $ echo fastboot_switching > /sys/bus/pci/devices/${bdf}/t7xx_mode + Management application development ================================== The driver and userspace interfaces are described below. The MBIM protocol is diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c index 24e7d491468e..ca262d2961ed 100644 --- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c +++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c @@ -177,6 +177,11 @@ int t7xx_acpi_fldr_func(struct t7xx_pci_dev *t7xx_dev) return t7xx_acpi_reset(t7xx_dev, "_RST"); } +int t7xx_acpi_pldr_func(struct t7xx_pci_dev *t7xx_dev) +{ + return t7xx_acpi_reset(t7xx_dev, "MRST._RST"); +} + static void t7xx_reset_device_via_pmic(struct t7xx_pci_dev *t7xx_dev) { u32 val; @@ -192,6 +197,7 @@ static irqreturn_t t7xx_rgu_isr_thread(int irq, void *data) { struct t7xx_pci_dev *t7xx_dev = data; + t7xx_mode_update(t7xx_dev, T7XX_RESET); msleep(RGU_RESET_DELAY_MS); t7xx_reset_device_via_pmic(t7xx_dev); return IRQ_HANDLED; diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.h b/drivers/net/wwan/t7xx/t7xx_modem_ops.h index abe633cf7adc..b39e945a92e0 100644 --- a/drivers/net/wwan/t7xx/t7xx_modem_ops.h +++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.h @@ -85,6 +85,7 @@ int t7xx_md_init(struct t7xx_pci_dev *t7xx_dev); void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev); void t7xx_clear_rgu_irq(struct t7xx_pci_dev *t7xx_dev); int t7xx_acpi_fldr_func(struct t7xx_pci_dev *t7xx_dev); +int t7xx_acpi_pldr_func(struct t7xx_pci_dev *t7xx_dev); int t7xx_pci_mhccif_isr(struct t7xx_pci_dev *t7xx_dev); #endif /* __T7XX_MODEM_OPS_H__ */ diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index 91256e005b84..f99eb21cb8cc 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -52,6 +52,81 @@ #define PM_RESOURCE_POLL_TIMEOUT_US 10000 #define PM_RESOURCE_POLL_STEP_US 100 +static const char * const t7xx_mode_names[] = { + [T7XX_UNKNOWN] = "unknown", + [T7XX_READY] = "ready", + [T7XX_RESET] = "reset", + [T7XX_FASTBOOT_SWITCHING] = "fastboot_switching", + [T7XX_FASTBOOT_DOWNLOAD] = "fastboot_download", + [T7XX_FASTBOOT_DUMP] = "fastboot_dump", +}; + +static_assert(ARRAY_SIZE(t7xx_mode_names) == T7XX_MODE_LAST); + +static ssize_t t7xx_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct t7xx_pci_dev *t7xx_dev; + struct pci_dev *pdev; + int index = 0; + + pdev = to_pci_dev(dev); + t7xx_dev = pci_get_drvdata(pdev); + if (!t7xx_dev) + return -ENODEV; + + index = sysfs_match_string(t7xx_mode_names, buf); + if (index == T7XX_FASTBOOT_SWITCHING) { + WRITE_ONCE(t7xx_dev->mode, T7XX_FASTBOOT_SWITCHING); + } else if (index == T7XX_RESET) { + WRITE_ONCE(t7xx_dev->mode, T7XX_RESET); + t7xx_acpi_pldr_func(t7xx_dev); + } + + return count; +}; + +static ssize_t t7xx_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + enum t7xx_mode mode = T7XX_UNKNOWN; + struct t7xx_pci_dev *t7xx_dev; + struct pci_dev *pdev; + + pdev = to_pci_dev(dev); + t7xx_dev = pci_get_drvdata(pdev); + if (!t7xx_dev) + return -ENODEV; + + mode = READ_ONCE(t7xx_dev->mode); + if (mode < T7XX_MODE_LAST) + return sysfs_emit(buf, "%s\n", t7xx_mode_names[mode]); + + return sysfs_emit(buf, "%s\n", t7xx_mode_names[T7XX_UNKNOWN]); +} + +static DEVICE_ATTR_RW(t7xx_mode); + +static struct attribute *t7xx_mode_attr[] = { + &dev_attr_t7xx_mode.attr, + NULL +}; + +static const struct attribute_group t7xx_mode_attribute_group = { + .attrs = t7xx_mode_attr, +}; + +void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode) +{ + if (!t7xx_dev) + return; + + WRITE_ONCE(t7xx_dev->mode, mode); + sysfs_notify(&t7xx_dev->pdev->dev.kobj, NULL, "t7xx_mode"); +} + enum t7xx_pm_state { MTK_PM_EXCEPTION, MTK_PM_INIT, /* Device initialized, but handshake not completed */ @@ -279,7 +354,8 @@ static int __t7xx_pci_pm_suspend(struct pci_dev *pdev) int ret; t7xx_dev = pci_get_drvdata(pdev); - if (atomic_read(&t7xx_dev->md_pm_state) <= MTK_PM_INIT) { + if (atomic_read(&t7xx_dev->md_pm_state) <= MTK_PM_INIT || + READ_ONCE(t7xx_dev->mode) != T7XX_READY) { dev_err(&pdev->dev, "[PM] Exiting suspend, modem in invalid state\n"); return -EFAULT; } @@ -729,16 +805,28 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) t7xx_pcie_mac_interrupts_dis(t7xx_dev); + ret = sysfs_create_group(&t7xx_dev->pdev->dev.kobj, + &t7xx_mode_attribute_group); + if (ret) + goto err_md_exit; + ret = t7xx_interrupt_init(t7xx_dev); - if (ret) { - t7xx_md_exit(t7xx_dev); - return ret; - } + if (ret) + goto err_remove_group; + t7xx_pcie_mac_set_int(t7xx_dev, MHCCIF_INT); t7xx_pcie_mac_interrupts_en(t7xx_dev); return 0; + +err_remove_group: + sysfs_remove_group(&t7xx_dev->pdev->dev.kobj, + &t7xx_mode_attribute_group); + +err_md_exit: + t7xx_md_exit(t7xx_dev); + return ret; } static void t7xx_pci_remove(struct pci_dev *pdev) @@ -747,6 +835,9 @@ static void t7xx_pci_remove(struct pci_dev *pdev) int i; t7xx_dev = pci_get_drvdata(pdev); + + sysfs_remove_group(&t7xx_dev->pdev->dev.kobj, + &t7xx_mode_attribute_group); t7xx_md_exit(t7xx_dev); for (i = 0; i < EXT_INT_NUM; i++) { diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h index f08f1ab74469..49a11586d8d8 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.h +++ b/drivers/net/wwan/t7xx/t7xx_pci.h @@ -43,6 +43,16 @@ struct t7xx_addr_base { typedef irqreturn_t (*t7xx_intr_callback)(int irq, void *param); +enum t7xx_mode { + T7XX_UNKNOWN, + T7XX_READY, + T7XX_RESET, + T7XX_FASTBOOT_SWITCHING, + T7XX_FASTBOOT_DOWNLOAD, + T7XX_FASTBOOT_DUMP, + T7XX_MODE_LAST, /* must always be last */ +}; + /* struct t7xx_pci_dev - MTK device context structure * @intr_handler: array of handler function for request_threaded_irq * @intr_thread: array of thread_fn for request_threaded_irq @@ -59,6 +69,7 @@ typedef irqreturn_t (*t7xx_intr_callback)(int irq, void *param); * @md_pm_lock: protects PCIe sleep lock * @sleep_disable_count: PCIe L1.2 lock counter * @sleep_lock_acquire: indicates that sleep has been disabled + * @mode: indicates the device mode */ struct t7xx_pci_dev { t7xx_intr_callback intr_handler[EXT_INT_NUM]; @@ -82,6 +93,7 @@ struct t7xx_pci_dev { #ifdef CONFIG_WWAN_DEBUGFS struct dentry *debugfs_dir; #endif + u32 mode; }; enum t7xx_pm_id { @@ -120,5 +132,5 @@ int t7xx_pci_pm_entity_register(struct t7xx_pci_dev *t7xx_dev, struct md_pm_enti int t7xx_pci_pm_entity_unregister(struct t7xx_pci_dev *t7xx_dev, struct md_pm_entity *pm_entity); void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev); void t7xx_pci_pm_exp_detected(struct t7xx_pci_dev *t7xx_dev); - +void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode); #endif /* __T7XX_PCI_H__ */ diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c index 0bc97430211b..c5d46f45fa62 100644 --- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c +++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c @@ -272,6 +272,7 @@ static void fsm_routine_ready(struct t7xx_fsm_ctl *ctl) ctl->curr_state = FSM_STATE_READY; t7xx_fsm_broadcast_ready_state(ctl); + t7xx_mode_update(md->t7xx_dev, T7XX_READY); t7xx_md_event_notify(md, FSM_READY); } From d27553c14f06f4db61cb9ddaf88e8d4df91d740c Mon Sep 17 00:00:00 2001 From: Jinjian Song Date: Mon, 5 Feb 2024 18:22:29 +0800 Subject: [PATCH 1007/2255] net: wwan: t7xx: Infrastructure for early port configuration To support cases such as FW update or Core dump, the t7xx device is capable of signaling the host that a special port needs to be created before the handshake phase. Adds the infrastructure required to create the early ports which also requires a different configuration of CLDMA queues. Base on the v5 patch version of follow series: 'net: wwan: t7xx: fw flashing & coredump support' (https://patchwork.kernel.org/project/netdevbpf/patch/3777bb382f4b0395cb594a602c5c79dbab86c9e0.1674307425.git.m.chetan.kumar@linux.intel.com/) Signed-off-by: Jinjian Song Signed-off-by: David S. Miller --- drivers/net/wwan/t7xx/t7xx_hif_cldma.c | 47 +++++--- drivers/net/wwan/t7xx/t7xx_hif_cldma.h | 18 ++- drivers/net/wwan/t7xx/t7xx_modem_ops.c | 8 +- drivers/net/wwan/t7xx/t7xx_pci.c | 2 +- drivers/net/wwan/t7xx/t7xx_port.h | 4 + drivers/net/wwan/t7xx/t7xx_port_proxy.c | 109 ++++++++++++++--- drivers/net/wwan/t7xx/t7xx_port_proxy.h | 10 ++ drivers/net/wwan/t7xx/t7xx_port_wwan.c | 5 +- drivers/net/wwan/t7xx/t7xx_reg.h | 24 +++- drivers/net/wwan/t7xx/t7xx_state_monitor.c | 129 +++++++++++++++++---- drivers/net/wwan/t7xx/t7xx_state_monitor.h | 1 + 11 files changed, 293 insertions(+), 64 deletions(-) diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c index cc70360364b7..abc41a7089fa 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c @@ -57,8 +57,6 @@ #define CHECK_Q_STOP_TIMEOUT_US 1000000 #define CHECK_Q_STOP_STEP_US 10000 -#define CLDMA_JUMBO_BUFF_SZ (63 * 1024 + sizeof(struct ccci_header)) - static void md_cd_queue_struct_reset(struct cldma_queue *queue, struct cldma_ctrl *md_ctrl, enum mtk_txrx tx_rx, unsigned int index) { @@ -161,7 +159,7 @@ static int t7xx_cldma_gpd_rx_from_q(struct cldma_queue *queue, int budget, bool skb_reset_tail_pointer(skb); skb_put(skb, le16_to_cpu(gpd->data_buff_len)); - ret = md_ctrl->recv_skb(queue, skb); + ret = queue->recv_skb(queue, skb); /* Break processing, will try again later */ if (ret < 0) return ret; @@ -897,13 +895,13 @@ static void t7xx_cldma_hw_start_send(struct cldma_ctrl *md_ctrl, int qno, /** * t7xx_cldma_set_recv_skb() - Set the callback to handle RX packets. - * @md_ctrl: CLDMA context structure. + * @queue: CLDMA queue. * @recv_skb: Receiving skb callback. */ -void t7xx_cldma_set_recv_skb(struct cldma_ctrl *md_ctrl, +void t7xx_cldma_set_recv_skb(struct cldma_queue *queue, int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb)) { - md_ctrl->recv_skb = recv_skb; + queue->recv_skb = recv_skb; } /** @@ -993,6 +991,28 @@ allow_sleep: return ret; } +static void t7xx_cldma_adjust_config(struct cldma_ctrl *md_ctrl, enum cldma_cfg cfg_id) +{ + int qno; + + for (qno = 0; qno < CLDMA_RXQ_NUM; qno++) { + md_ctrl->rx_ring[qno].pkt_size = CLDMA_SHARED_Q_BUFF_SZ; + t7xx_cldma_set_recv_skb(&md_ctrl->rxq[qno], t7xx_port_proxy_recv_skb); + } + + md_ctrl->rx_ring[CLDMA_RXQ_NUM - 1].pkt_size = CLDMA_JUMBO_BUFF_SZ; + + for (qno = 0; qno < CLDMA_TXQ_NUM; qno++) + md_ctrl->tx_ring[qno].pkt_size = CLDMA_SHARED_Q_BUFF_SZ; + + if (cfg_id == CLDMA_DEDICATED_Q_CFG) { + md_ctrl->tx_ring[CLDMA_Q_IDX_DUMP].pkt_size = CLDMA_DEDICATED_Q_BUFF_SZ; + md_ctrl->rx_ring[CLDMA_Q_IDX_DUMP].pkt_size = CLDMA_DEDICATED_Q_BUFF_SZ; + t7xx_cldma_set_recv_skb(&md_ctrl->rxq[CLDMA_Q_IDX_DUMP], + t7xx_port_proxy_recv_skb_from_dedicated_queue); + } +} + static int t7xx_cldma_late_init(struct cldma_ctrl *md_ctrl) { char dma_pool_name[32]; @@ -1018,16 +1038,9 @@ static int t7xx_cldma_late_init(struct cldma_ctrl *md_ctrl) dev_err(md_ctrl->dev, "control TX ring init fail\n"); goto err_free_tx_ring; } - - md_ctrl->tx_ring[i].pkt_size = CLDMA_MTU; } for (j = 0; j < CLDMA_RXQ_NUM; j++) { - md_ctrl->rx_ring[j].pkt_size = CLDMA_MTU; - - if (j == CLDMA_RXQ_NUM - 1) - md_ctrl->rx_ring[j].pkt_size = CLDMA_JUMBO_BUFF_SZ; - ret = t7xx_cldma_rx_ring_init(md_ctrl, &md_ctrl->rx_ring[j]); if (ret) { dev_err(md_ctrl->dev, "Control RX ring init fail\n"); @@ -1094,6 +1107,7 @@ int t7xx_cldma_alloc(enum cldma_id hif_id, struct t7xx_pci_dev *t7xx_dev) { struct device *dev = &t7xx_dev->pdev->dev; struct cldma_ctrl *md_ctrl; + int qno; md_ctrl = devm_kzalloc(dev, sizeof(*md_ctrl), GFP_KERNEL); if (!md_ctrl) @@ -1102,7 +1116,9 @@ int t7xx_cldma_alloc(enum cldma_id hif_id, struct t7xx_pci_dev *t7xx_dev) md_ctrl->t7xx_dev = t7xx_dev; md_ctrl->dev = dev; md_ctrl->hif_id = hif_id; - md_ctrl->recv_skb = t7xx_cldma_default_recv_skb; + for (qno = 0; qno < CLDMA_RXQ_NUM; qno++) + md_ctrl->rxq[qno].recv_skb = t7xx_cldma_default_recv_skb; + t7xx_hw_info_init(md_ctrl); t7xx_dev->md->md_ctrl[hif_id] = md_ctrl; return 0; @@ -1332,9 +1348,10 @@ err_workqueue: return -ENOMEM; } -void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl) +void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl, enum cldma_cfg cfg_id) { t7xx_cldma_late_release(md_ctrl); + t7xx_cldma_adjust_config(md_ctrl, cfg_id); t7xx_cldma_late_init(md_ctrl); } diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.h b/drivers/net/wwan/t7xx/t7xx_hif_cldma.h index 4410bac6993a..f2d9941be9c8 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.h +++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.h @@ -31,6 +31,10 @@ #include "t7xx_cldma.h" #include "t7xx_pci.h" +#define CLDMA_JUMBO_BUFF_SZ (63 * 1024 + sizeof(struct ccci_header)) +#define CLDMA_SHARED_Q_BUFF_SZ 3584 +#define CLDMA_DEDICATED_Q_BUFF_SZ 2048 + /** * enum cldma_id - Identifiers for CLDMA HW units. * @CLDMA_ID_MD: Modem control channel. @@ -55,6 +59,11 @@ struct cldma_gpd { __le16 not_used2; }; +enum cldma_cfg { + CLDMA_SHARED_Q_CFG, + CLDMA_DEDICATED_Q_CFG, +}; + struct cldma_request { struct cldma_gpd *gpd; /* Virtual address for CPU */ dma_addr_t gpd_addr; /* Physical address for DMA */ @@ -82,6 +91,7 @@ struct cldma_queue { wait_queue_head_t req_wq; /* Only for TX */ struct workqueue_struct *worker; struct work_struct cldma_work; + int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb); }; struct cldma_ctrl { @@ -101,24 +111,22 @@ struct cldma_ctrl { struct md_pm_entity *pm_entity; struct t7xx_cldma_hw hw_info; bool is_late_init; - int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb); }; +#define CLDMA_Q_IDX_DUMP 1 #define GPD_FLAGS_HWO BIT(0) #define GPD_FLAGS_IOC BIT(7) #define GPD_DMAPOOL_ALIGN 16 -#define CLDMA_MTU 3584 /* 3.5kB */ - int t7xx_cldma_alloc(enum cldma_id hif_id, struct t7xx_pci_dev *t7xx_dev); void t7xx_cldma_hif_hw_init(struct cldma_ctrl *md_ctrl); int t7xx_cldma_init(struct cldma_ctrl *md_ctrl); void t7xx_cldma_exit(struct cldma_ctrl *md_ctrl); -void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl); +void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl, enum cldma_cfg cfg_id); void t7xx_cldma_start(struct cldma_ctrl *md_ctrl); int t7xx_cldma_stop(struct cldma_ctrl *md_ctrl); void t7xx_cldma_reset(struct cldma_ctrl *md_ctrl); -void t7xx_cldma_set_recv_skb(struct cldma_ctrl *md_ctrl, +void t7xx_cldma_set_recv_skb(struct cldma_queue *queue, int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb)); int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb); void t7xx_cldma_stop_all_qs(struct cldma_ctrl *md_ctrl, enum mtk_txrx tx_rx); diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c index ca262d2961ed..8d864d4ed77f 100644 --- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c +++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c @@ -535,7 +535,7 @@ static void t7xx_md_hk_wq(struct work_struct *work) /* Clear the HS2 EXIT event appended in core_reset() */ t7xx_fsm_clr_event(ctl, FSM_EVENT_MD_HS2_EXIT); - t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_MD]); + t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_MD], CLDMA_SHARED_Q_CFG); t7xx_cldma_start(md->md_ctrl[CLDMA_ID_MD]); t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_FOR_HS2); md->core_md.handshake_ongoing = true; @@ -550,7 +550,7 @@ static void t7xx_ap_hk_wq(struct work_struct *work) /* Clear the HS2 EXIT event appended in t7xx_core_reset(). */ t7xx_fsm_clr_event(ctl, FSM_EVENT_AP_HS2_EXIT); t7xx_cldma_stop(md->md_ctrl[CLDMA_ID_AP]); - t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_AP]); + t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_AP], CLDMA_SHARED_Q_CFG); t7xx_cldma_start(md->md_ctrl[CLDMA_ID_AP]); md->core_ap.handshake_ongoing = true; t7xx_core_hk_handler(md, &md->core_ap, ctl, FSM_EVENT_AP_HS2, FSM_EVENT_AP_HS2_EXIT); @@ -764,6 +764,7 @@ err_destroy_hswq: void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev) { + enum t7xx_mode mode = READ_ONCE(t7xx_dev->mode); struct t7xx_modem *md = t7xx_dev->md; t7xx_pcie_mac_clear_int(t7xx_dev, SAP_RGU_INT); @@ -771,7 +772,8 @@ void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev) if (!md->md_init_finish) return; - t7xx_fsm_append_cmd(md->fsm_ctl, FSM_CMD_PRE_STOP, FSM_CMD_FLAG_WAIT_FOR_COMPLETION); + if (mode != T7XX_RESET && mode != T7XX_UNKNOWN) + t7xx_fsm_append_cmd(md->fsm_ctl, FSM_CMD_PRE_STOP, FSM_CMD_FLAG_WAIT_FOR_COMPLETION); t7xx_port_proxy_uninit(md->port_prox); t7xx_cldma_exit(md->md_ctrl[CLDMA_ID_AP]); t7xx_cldma_exit(md->md_ctrl[CLDMA_ID_MD]); diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index f99eb21cb8cc..e0b1e7a616ca 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -183,7 +183,7 @@ static int t7xx_pci_pm_init(struct t7xx_pci_dev *t7xx_dev) pm_runtime_set_autosuspend_delay(&pdev->dev, PM_AUTOSUSPEND_MS); pm_runtime_use_autosuspend(&pdev->dev); - return t7xx_wait_pm_config(t7xx_dev); + return 0; } void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev) diff --git a/drivers/net/wwan/t7xx/t7xx_port.h b/drivers/net/wwan/t7xx/t7xx_port.h index 4ae8a00a8532..f74d3bab810d 100644 --- a/drivers/net/wwan/t7xx/t7xx_port.h +++ b/drivers/net/wwan/t7xx/t7xx_port.h @@ -75,6 +75,8 @@ enum port_ch { PORT_CH_DSS6_TX = 0x20df, PORT_CH_DSS7_RX = 0x20e0, PORT_CH_DSS7_TX = 0x20e1, + + PORT_CH_UNIMPORTANT = 0xffff, }; struct t7xx_port; @@ -135,11 +137,13 @@ struct t7xx_port { }; }; +int t7xx_get_port_mtu(struct t7xx_port *port); struct sk_buff *t7xx_port_alloc_skb(int payload); struct sk_buff *t7xx_ctrl_alloc_skb(int payload); int t7xx_port_enqueue_skb(struct t7xx_port *port, struct sk_buff *skb); int t7xx_port_send_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int pkt_header, unsigned int ex_msg); +int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb); int t7xx_port_send_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg, unsigned int ex_msg); diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c index 274846d39fbf..e53a152faee4 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c @@ -48,6 +48,9 @@ i < (proxy)->port_count; \ i++, (p) = &(proxy)->ports[i]) +#define T7XX_MAX_POSSIBLE_PORTS_NUM \ + (max(ARRAY_SIZE(t7xx_port_conf), ARRAY_SIZE(t7xx_early_port_conf))) + static const struct t7xx_port_conf t7xx_port_conf[] = { { .tx_ch = PORT_CH_UART2_TX, @@ -100,6 +103,18 @@ static const struct t7xx_port_conf t7xx_port_conf[] = { }, }; +static const struct t7xx_port_conf t7xx_early_port_conf[] = { + { + .tx_ch = PORT_CH_UNIMPORTANT, + .rx_ch = PORT_CH_UNIMPORTANT, + .txq_index = CLDMA_Q_IDX_DUMP, + .rxq_index = CLDMA_Q_IDX_DUMP, + .txq_exp_index = CLDMA_Q_IDX_DUMP, + .rxq_exp_index = CLDMA_Q_IDX_DUMP, + .path_id = CLDMA_ID_AP, + }, +}; + static struct t7xx_port *t7xx_proxy_get_port_by_ch(struct port_proxy *port_prox, enum port_ch ch) { const struct t7xx_port_conf *port_conf; @@ -214,7 +229,17 @@ int t7xx_port_enqueue_skb(struct t7xx_port *port, struct sk_buff *skb) return 0; } -static int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb) +int t7xx_get_port_mtu(struct t7xx_port *port) +{ + enum cldma_id path_id = port->port_conf->path_id; + int tx_qno = t7xx_port_get_queue_no(port); + struct cldma_ctrl *md_ctrl; + + md_ctrl = port->t7xx_dev->md->md_ctrl[path_id]; + return md_ctrl->tx_ring[tx_qno].pkt_size; +} + +int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb) { enum cldma_id path_id = port->port_conf->path_id; struct cldma_ctrl *md_ctrl; @@ -329,6 +354,39 @@ static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox) } } +/** + * t7xx_port_proxy_recv_skb_from_dedicated_queue() - Dispatch early port received skb. + * @queue: CLDMA queue. + * @skb: Socket buffer. + * + * Return: + ** 0 - Packet consumed. + ** -ERROR - Failed to process skb. + */ +int t7xx_port_proxy_recv_skb_from_dedicated_queue(struct cldma_queue *queue, struct sk_buff *skb) +{ + struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev; + struct port_proxy *port_prox = t7xx_dev->md->port_prox; + const struct t7xx_port_conf *port_conf; + struct t7xx_port *port; + int ret; + + port = &port_prox->ports[0]; + if (WARN_ON_ONCE(port->port_conf->rxq_index != queue->index)) { + dev_kfree_skb_any(skb); + return -EINVAL; + } + + port_conf = port->port_conf; + ret = port_conf->ops->recv_skb(port, skb); + if (ret < 0 && ret != -ENOBUFS) { + dev_err(port->dev, "drop on RX ch %d, %d\n", port_conf->rx_ch, ret); + dev_kfree_skb_any(skb); + } + + return ret; +} + static struct t7xx_port *t7xx_port_proxy_find_port(struct t7xx_pci_dev *t7xx_dev, struct cldma_queue *queue, u16 channel) { @@ -359,7 +417,7 @@ static struct t7xx_port *t7xx_port_proxy_find_port(struct t7xx_pci_dev *t7xx_dev ** 0 - Packet consumed. ** -ERROR - Failed to process skb. */ -static int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb) +int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb) { struct ccci_header *ccci_h = (struct ccci_header *)skb->data; struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev; @@ -444,33 +502,54 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md) spin_lock_init(&port->port_update_lock); port->chan_enable = false; - if (port_conf->ops->init) + if (port_conf->ops && port_conf->ops->init) port_conf->ops->init(port); } t7xx_proxy_setup_ch_mapping(port_prox); } -static int t7xx_proxy_alloc(struct t7xx_modem *md) +void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id) { - unsigned int port_count = ARRAY_SIZE(t7xx_port_conf); - struct device *dev = &md->t7xx_dev->pdev->dev; - struct port_proxy *port_prox; + struct port_proxy *port_prox = md->port_prox; + const struct t7xx_port_conf *port_conf; + u32 port_count; int i; - port_prox = devm_kzalloc(dev, sizeof(*port_prox) + sizeof(struct t7xx_port) * port_count, + t7xx_port_proxy_uninit(port_prox); + + if (cfg_id == PORT_CFG_ID_EARLY) { + port_conf = t7xx_early_port_conf; + port_count = ARRAY_SIZE(t7xx_early_port_conf); + } else { + port_conf = t7xx_port_conf; + port_count = ARRAY_SIZE(t7xx_port_conf); + } + + for (i = 0; i < port_count; i++) + port_prox->ports[i].port_conf = &port_conf[i]; + + port_prox->cfg_id = cfg_id; + port_prox->port_count = port_count; + + t7xx_proxy_init_all_ports(md); +} + +static int t7xx_proxy_alloc(struct t7xx_modem *md) +{ + struct device *dev = &md->t7xx_dev->pdev->dev; + struct port_proxy *port_prox; + + port_prox = devm_kzalloc(dev, sizeof(*port_prox) + + sizeof(struct t7xx_port) * T7XX_MAX_POSSIBLE_PORTS_NUM, GFP_KERNEL); if (!port_prox) return -ENOMEM; md->port_prox = port_prox; port_prox->dev = dev; + t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_EARLY); - for (i = 0; i < port_count; i++) - port_prox->ports[i].port_conf = &t7xx_port_conf[i]; - - port_prox->port_count = port_count; - t7xx_proxy_init_all_ports(md); return 0; } @@ -492,8 +571,6 @@ int t7xx_port_proxy_init(struct t7xx_modem *md) if (ret) return ret; - t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_AP], t7xx_port_proxy_recv_skb); - t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_MD], t7xx_port_proxy_recv_skb); return 0; } @@ -505,7 +582,7 @@ void t7xx_port_proxy_uninit(struct port_proxy *port_prox) for_each_proxy_port(i, port, port_prox) { const struct t7xx_port_conf *port_conf = port->port_conf; - if (port_conf->ops->uninit) + if (port_conf->ops && port_conf->ops->uninit) port_conf->ops->uninit(port); } } diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h index 81d059fbc0fb..7f5706811445 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h @@ -31,11 +31,18 @@ #define RX_QUEUE_MAXLEN 32 #define CTRL_QUEUE_MAXLEN 16 +enum port_cfg_id { + PORT_CFG_ID_INVALID, + PORT_CFG_ID_NORMAL, + PORT_CFG_ID_EARLY, +}; + struct port_proxy { int port_count; struct list_head rx_ch_ports[PORT_CH_ID_MASK + 1]; struct list_head queue_ports[CLDMA_NUM][MTK_QUEUES]; struct device *dev; + enum port_cfg_id cfg_id; struct t7xx_port ports[]; }; @@ -98,5 +105,8 @@ void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg); int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id, bool en_flag); +void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id); +int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb); +int t7xx_port_proxy_recv_skb_from_dedicated_queue(struct cldma_queue *queue, struct sk_buff *skb); #endif /* __T7XX_PORT_PROXY_H__ */ diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c index 17389c8f6600..ddc20ddfa734 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c +++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c @@ -152,14 +152,15 @@ static int t7xx_port_wwan_disable_chl(struct t7xx_port *port) static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state) { const struct t7xx_port_conf *port_conf = port->port_conf; - unsigned int header_len = sizeof(struct ccci_header); + unsigned int header_len = sizeof(struct ccci_header), mtu; struct wwan_port_caps caps; if (state != MD_STATE_READY) return; if (!port->wwan.wwan_port) { - caps.frag_len = CLDMA_MTU - header_len; + mtu = t7xx_get_port_mtu(port); + caps.frag_len = mtu - header_len; caps.headroom_len = header_len; port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type, &wwan_ops, &caps, port); diff --git a/drivers/net/wwan/t7xx/t7xx_reg.h b/drivers/net/wwan/t7xx/t7xx_reg.h index c41d7d094c08..9c7dc72ac6f6 100644 --- a/drivers/net/wwan/t7xx/t7xx_reg.h +++ b/drivers/net/wwan/t7xx/t7xx_reg.h @@ -101,11 +101,33 @@ enum t7xx_pm_resume_state { PM_RESUME_REG_STATE_L2_EXP, }; +enum host_event_e { + HOST_EVENT_INIT = 0, + FASTBOOT_DL_NOTIFY = 0x3, +}; + #define T7XX_PCIE_MISC_DEV_STATUS 0x0d1c #define MISC_STAGE_MASK GENMASK(2, 0) #define MISC_RESET_TYPE_PLDR BIT(26) #define MISC_RESET_TYPE_FLDR BIT(27) -#define LINUX_STAGE 4 +#define MISC_RESET_TYPE_PLDR BIT(26) +#define MISC_LK_EVENT_MASK GENMASK(11, 8) +#define HOST_EVENT_MASK GENMASK(31, 28) + +enum lk_event_id { + LK_EVENT_NORMAL = 0, + LK_EVENT_CREATE_PD_PORT = 1, + LK_EVENT_CREATE_POST_DL_PORT = 2, + LK_EVENT_RESET = 7, +}; + +enum t7xx_device_stage { + T7XX_DEV_STAGE_INIT = 0, + T7XX_DEV_STAGE_BROM_PRE = 1, + T7XX_DEV_STAGE_BROM_POST = 2, + T7XX_DEV_STAGE_LK = 3, + T7XX_DEV_STAGE_LINUX = 4, +}; #define T7XX_PCIE_RESOURCE_STATUS 0x0d28 #define T7XX_PCIE_RESOURCE_STS_MSK GENMASK(4, 0) diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c index c5d46f45fa62..038377fed102 100644 --- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c +++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c @@ -47,6 +47,13 @@ #define FSM_MD_EX_PASS_TIMEOUT_MS 45000 #define FSM_CMD_TIMEOUT_MS 2000 +#define wait_for_expected_dev_stage(status) \ + read_poll_timeout(ioread32, status, \ + ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LINUX) || \ + ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LK), 100000, \ + 20000000, false, IREG_BASE(md->t7xx_dev) + \ + T7XX_PCIE_MISC_DEV_STATUS) + void t7xx_fsm_notifier_register(struct t7xx_modem *md, struct t7xx_fsm_notifier *notifier) { struct t7xx_fsm_ctl *ctl = md->fsm_ctl; @@ -206,6 +213,51 @@ static void fsm_routine_exception(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comm fsm_finish_command(ctl, cmd, 0); } +static void t7xx_host_event_notify(struct t7xx_modem *md, unsigned int event_id) +{ + u32 value; + + value = ioread32(IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS); + value &= ~HOST_EVENT_MASK; + value |= FIELD_PREP(HOST_EVENT_MASK, event_id); + iowrite32(value, IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS); +} + +static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int status) +{ + struct t7xx_modem *md = ctl->md; + struct cldma_ctrl *md_ctrl; + enum lk_event_id lk_event; + struct device *dev; + + dev = &md->t7xx_dev->pdev->dev; + lk_event = FIELD_GET(MISC_LK_EVENT_MASK, status); + switch (lk_event) { + case LK_EVENT_NORMAL: + case LK_EVENT_RESET: + break; + + case LK_EVENT_CREATE_PD_PORT: + case LK_EVENT_CREATE_POST_DL_PORT: + md_ctrl = md->md_ctrl[CLDMA_ID_AP]; + t7xx_cldma_hif_hw_init(md_ctrl); + t7xx_cldma_stop(md_ctrl); + t7xx_cldma_switch_cfg(md_ctrl, CLDMA_DEDICATED_Q_CFG); + + t7xx_cldma_start(md_ctrl); + + if (lk_event == LK_EVENT_CREATE_POST_DL_PORT) + t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DOWNLOAD); + else + t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DUMP); + break; + + default: + dev_err(dev, "Invalid LK event %d\n", lk_event); + break; + } +} + static int fsm_stopped_handler(struct t7xx_fsm_ctl *ctl) { ctl->curr_state = FSM_STATE_STOPPED; @@ -226,8 +278,9 @@ static void fsm_routine_stopped(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comman static void fsm_routine_stopping(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd) { - struct t7xx_pci_dev *t7xx_dev; - struct cldma_ctrl *md_ctrl; + struct cldma_ctrl *md_ctrl = ctl->md->md_ctrl[CLDMA_ID_MD]; + struct t7xx_pci_dev *t7xx_dev = ctl->md->t7xx_dev; + enum t7xx_mode mode = READ_ONCE(t7xx_dev->mode); int err; if (ctl->curr_state == FSM_STATE_STOPPED || ctl->curr_state == FSM_STATE_STOPPING) { @@ -235,18 +288,20 @@ static void fsm_routine_stopping(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comma return; } - md_ctrl = ctl->md->md_ctrl[CLDMA_ID_MD]; - t7xx_dev = ctl->md->t7xx_dev; - ctl->curr_state = FSM_STATE_STOPPING; t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_TO_STOP); t7xx_cldma_stop(md_ctrl); - if (!ctl->md->rgu_irq_asserted) { - t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DRM_DISABLE_AP); - /* Wait for the DRM disable to take effect */ - msleep(FSM_DRM_DISABLE_DELAY_MS); + if (mode == T7XX_FASTBOOT_SWITCHING) + t7xx_host_event_notify(ctl->md, FASTBOOT_DL_NOTIFY); + t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DRM_DISABLE_AP); + /* Wait for the DRM disable to take effect */ + msleep(FSM_DRM_DISABLE_DELAY_MS); + + if (mode == T7XX_FASTBOOT_SWITCHING) { + t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET); + } else { err = t7xx_acpi_fldr_func(t7xx_dev); if (err) t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET); @@ -318,7 +373,8 @@ static int fsm_routine_starting(struct t7xx_fsm_ctl *ctl) static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd) { struct t7xx_modem *md = ctl->md; - u32 dev_status; + struct device *dev; + u32 status; int ret; if (!md) @@ -330,23 +386,53 @@ static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command return; } + dev = &md->t7xx_dev->pdev->dev; ctl->curr_state = FSM_STATE_PRE_START; t7xx_md_event_notify(md, FSM_PRE_START); - ret = read_poll_timeout(ioread32, dev_status, - (dev_status & MISC_STAGE_MASK) == LINUX_STAGE, 20000, 2000000, - false, IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS); - if (ret) { - struct device *dev = &md->t7xx_dev->pdev->dev; + ret = wait_for_expected_dev_stage(status); - fsm_finish_command(ctl, cmd, -ETIMEDOUT); - dev_err(dev, "Invalid device status 0x%lx\n", dev_status & MISC_STAGE_MASK); - return; + if (ret) { + dev_err(dev, "read poll timeout %d\n", ret); + goto finish_command; } - t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]); - t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]); - fsm_finish_command(ctl, cmd, fsm_routine_starting(ctl)); + if (status != ctl->status || cmd->flag != 0) { + u32 stage = FIELD_GET(MISC_STAGE_MASK, status); + + switch (stage) { + case T7XX_DEV_STAGE_INIT: + case T7XX_DEV_STAGE_BROM_PRE: + case T7XX_DEV_STAGE_BROM_POST: + dev_dbg(dev, "BROM_STAGE Entered\n"); + ret = t7xx_fsm_append_cmd(ctl, FSM_CMD_START, 0); + break; + + case T7XX_DEV_STAGE_LK: + dev_dbg(dev, "LK_STAGE Entered\n"); + t7xx_lk_stage_event_handling(ctl, status); + break; + + case T7XX_DEV_STAGE_LINUX: + dev_dbg(dev, "LINUX_STAGE Entered\n"); + t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM | + D2H_INT_ASYNC_MD_HK | D2H_INT_ASYNC_AP_HK); + if (cmd->flag == 0) + break; + t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]); + t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]); + t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_NORMAL); + ret = fsm_routine_starting(ctl); + break; + + default: + break; + } + ctl->status = status; + } + +finish_command: + fsm_finish_command(ctl, cmd, ret); } static int fsm_main_thread(void *data) @@ -518,6 +604,7 @@ void t7xx_fsm_reset(struct t7xx_modem *md) fsm_flush_event_cmd_qs(ctl); ctl->curr_state = FSM_STATE_STOPPED; ctl->exp_flg = false; + ctl->status = T7XX_DEV_STAGE_INIT; } int t7xx_fsm_init(struct t7xx_modem *md) diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.h b/drivers/net/wwan/t7xx/t7xx_state_monitor.h index b0b3662ae6d7..7b0a9baf488c 100644 --- a/drivers/net/wwan/t7xx/t7xx_state_monitor.h +++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.h @@ -96,6 +96,7 @@ struct t7xx_fsm_ctl { bool exp_flg; spinlock_t notifier_lock; /* Protects notifier list */ struct list_head notifier_list; + u32 status; /* Device boot stage */ }; struct t7xx_fsm_event { From 2dac6381c3da50d4b2525fd0514e41e8041ad974 Mon Sep 17 00:00:00 2001 From: Jinjian Song Date: Mon, 5 Feb 2024 18:22:30 +0800 Subject: [PATCH 1008/2255] net: wwan: t7xx: Add fastboot WWAN port On early detection of wwan device in fastboot mode, driver sets up CLDMA0 HW tx/rx queues for raw data transfer and then create fastboot port to userspace. Application can use this port to flash firmware and collect core dump by fastboot protocol commands. E.g., flash firmware through fastboot port: - "download:%08x": write data to memory with the download size. - "flash:%s": write the previously downloaded image to the named partition. - "reboot": reboot the device. Link: https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/README.md Signed-off-by: Jinjian Song Signed-off-by: David S. Miller --- .../networking/device_drivers/wwan/t7xx.rst | 18 +++ drivers/net/wwan/t7xx/t7xx_port_proxy.c | 3 + drivers/net/wwan/t7xx/t7xx_port_wwan.c | 116 ++++++++++++++---- drivers/net/wwan/t7xx/t7xx_state_monitor.c | 4 + 4 files changed, 115 insertions(+), 26 deletions(-) diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst index 8429b9927341..f346f5f85f15 100644 --- a/Documentation/networking/device_drivers/wwan/t7xx.rst +++ b/Documentation/networking/device_drivers/wwan/t7xx.rst @@ -125,6 +125,20 @@ The driver exposes an AT port by implementing AT WWAN Port. The userspace end of the control port is a /dev/wwan0at0 character device. Application shall use this interface to issue AT commands. +fastboot port userspace ABI +--------------------------- + +/dev/wwan0fastboot0 character device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The driver exposes a fastboot protocol interface by implementing +fastboot WWAN Port. The userspace end of the fastboot channel pipe is a +/dev/wwan0fastboot0 character device. Application shall use this interface for +fastboot protocol communication. + +Please note that driver needs to be reloaded to export /dev/wwan0fastboot0 +port, because device needs a cold reset after enter ``fastboot_switching`` +mode. + The MediaTek's T700 modem supports the 3GPP TS 27.007 [4] specification. References @@ -146,3 +160,7 @@ speak the Mobile Interface Broadband Model (MBIM) protocol"* [4] *Specification # 27.007 - 3GPP* - https://www.3gpp.org/DynaReport/27007.htm + +[5] *fastboot "a mechanism for communicating with bootloaders"* + +- https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/README.md diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c index e53a152faee4..8f5e01705af2 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c @@ -112,6 +112,9 @@ static const struct t7xx_port_conf t7xx_early_port_conf[] = { .txq_exp_index = CLDMA_Q_IDX_DUMP, .rxq_exp_index = CLDMA_Q_IDX_DUMP, .path_id = CLDMA_ID_AP, + .ops = &wwan_sub_port_ops, + .name = "fastboot", + .port_type = WWAN_PORT_FASTBOOT, }, }; diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c index ddc20ddfa734..4b23ba693f3f 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c +++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2021, MediaTek Inc. * Copyright (c) 2021-2022, Intel Corporation. + * Copyright (c) 2024, Fibocom Wireless Inc. * * Authors: * Amir Hanania @@ -15,6 +16,7 @@ * Chiranjeevi Rapolu * Eliot Lee * Sreehari Kancharla + * Jinjian Song */ #include @@ -33,7 +35,7 @@ #include "t7xx_port_proxy.h" #include "t7xx_state_monitor.h" -static int t7xx_port_ctrl_start(struct wwan_port *port) +static int t7xx_port_wwan_start(struct wwan_port *port) { struct t7xx_port *port_mtk = wwan_port_get_drvdata(port); @@ -44,30 +46,60 @@ static int t7xx_port_ctrl_start(struct wwan_port *port) return 0; } -static void t7xx_port_ctrl_stop(struct wwan_port *port) +static void t7xx_port_wwan_stop(struct wwan_port *port) { struct t7xx_port *port_mtk = wwan_port_get_drvdata(port); atomic_dec(&port_mtk->usage_cnt); } -static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) +static int t7xx_port_fastboot_tx(struct t7xx_port *port, struct sk_buff *skb) +{ + struct sk_buff *cur = skb, *tx_skb; + size_t actual, len, offset = 0; + int txq_mtu; + int ret; + + txq_mtu = t7xx_get_port_mtu(port); + if (txq_mtu < 0) + return -EINVAL; + + actual = cur->len; + while (actual) { + len = min_t(size_t, actual, txq_mtu); + tx_skb = __dev_alloc_skb(len, GFP_KERNEL); + if (!tx_skb) + return -ENOMEM; + + skb_put_data(tx_skb, cur->data + offset, len); + + ret = t7xx_port_send_raw_skb(port, tx_skb); + if (ret) { + dev_kfree_skb(tx_skb); + dev_err(port->dev, "Write error on fastboot port, %d\n", ret); + break; + } + offset += len; + actual -= len; + } + + dev_kfree_skb(skb); + return 0; +} + +static int t7xx_port_ctrl_tx(struct t7xx_port *port, struct sk_buff *skb) { - struct t7xx_port *port_private = wwan_port_get_drvdata(port); const struct t7xx_port_conf *port_conf; struct sk_buff *cur = skb, *cloned; struct t7xx_fsm_ctl *ctl; enum md_state md_state; int cnt = 0, ret; - if (!port_private->chan_enable) - return -EINVAL; - - port_conf = port_private->port_conf; - ctl = port_private->t7xx_dev->md->fsm_ctl; + port_conf = port->port_conf; + ctl = port->t7xx_dev->md->fsm_ctl; md_state = t7xx_fsm_get_md_state(ctl); if (md_state == MD_STATE_WAITING_FOR_HS1 || md_state == MD_STATE_WAITING_FOR_HS2) { - dev_warn(port_private->dev, "Cannot write to %s port when md_state=%d\n", + dev_warn(port->dev, "Cannot write to %s port when md_state=%d\n", port_conf->name, md_state); return -ENODEV; } @@ -75,10 +107,10 @@ static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) while (cur) { cloned = skb_clone(cur, GFP_KERNEL); cloned->len = skb_headlen(cur); - ret = t7xx_port_send_skb(port_private, cloned, 0, 0); + ret = t7xx_port_send_skb(port, cloned, 0, 0); if (ret) { dev_kfree_skb(cloned); - dev_err(port_private->dev, "Write error on %s port, %d\n", + dev_err(port->dev, "Write error on %s port, %d\n", port_conf->name, ret); return cnt ? cnt + ret : ret; } @@ -93,14 +125,53 @@ static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) return 0; } +static int t7xx_port_wwan_tx(struct wwan_port *port, struct sk_buff *skb) +{ + struct t7xx_port *port_private = wwan_port_get_drvdata(port); + const struct t7xx_port_conf *port_conf = port_private->port_conf; + int ret; + + if (!port_private->chan_enable) + return -EINVAL; + + if (port_conf->port_type != WWAN_PORT_FASTBOOT) + ret = t7xx_port_ctrl_tx(port_private, skb); + else + ret = t7xx_port_fastboot_tx(port_private, skb); + + return ret; +} + static const struct wwan_port_ops wwan_ops = { - .start = t7xx_port_ctrl_start, - .stop = t7xx_port_ctrl_stop, - .tx = t7xx_port_ctrl_tx, + .start = t7xx_port_wwan_start, + .stop = t7xx_port_wwan_stop, + .tx = t7xx_port_wwan_tx, }; +static void t7xx_port_wwan_create(struct t7xx_port *port) +{ + const struct t7xx_port_conf *port_conf = port->port_conf; + unsigned int header_len = sizeof(struct ccci_header), mtu; + struct wwan_port_caps caps; + + if (!port->wwan.wwan_port) { + mtu = t7xx_get_port_mtu(port); + caps.frag_len = mtu - header_len; + caps.headroom_len = header_len; + port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type, + &wwan_ops, &caps, port); + if (IS_ERR(port->wwan.wwan_port)) + dev_err(port->dev, "Unable to create WWAN port %s", port_conf->name); + } +} + static int t7xx_port_wwan_init(struct t7xx_port *port) { + const struct t7xx_port_conf *port_conf = port->port_conf; + + if (port_conf->port_type == WWAN_PORT_FASTBOOT) + t7xx_port_wwan_create(port); + port->rx_length_th = RX_QUEUE_MAXLEN; return 0; } @@ -152,21 +223,14 @@ static int t7xx_port_wwan_disable_chl(struct t7xx_port *port) static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state) { const struct t7xx_port_conf *port_conf = port->port_conf; - unsigned int header_len = sizeof(struct ccci_header), mtu; - struct wwan_port_caps caps; + + if (port_conf->port_type == WWAN_PORT_FASTBOOT) + return; if (state != MD_STATE_READY) return; - if (!port->wwan.wwan_port) { - mtu = t7xx_get_port_mtu(port); - caps.frag_len = mtu - header_len; - caps.headroom_len = header_len; - port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type, - &wwan_ops, &caps, port); - if (IS_ERR(port->wwan.wwan_port)) - dev_err(port->dev, "Unable to create WWWAN port %s", port_conf->name); - } + t7xx_port_wwan_create(port); } struct port_ops wwan_sub_port_ops = { diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c index 038377fed102..9889ca4621cf 100644 --- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c +++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c @@ -229,6 +229,7 @@ static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int struct cldma_ctrl *md_ctrl; enum lk_event_id lk_event; struct device *dev; + struct t7xx_port *port; dev = &md->t7xx_dev->pdev->dev; lk_event = FIELD_GET(MISC_LK_EVENT_MASK, status); @@ -244,6 +245,9 @@ static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int t7xx_cldma_stop(md_ctrl); t7xx_cldma_switch_cfg(md_ctrl, CLDMA_DEDICATED_Q_CFG); + port = &ctl->md->port_prox->ports[0]; + port->port_conf->ops->enable_chl(port); + t7xx_cldma_start(md_ctrl); if (lk_event == LK_EVENT_CREATE_POST_DL_PORT) From f0ddf15f0a74c27eb4b2271a90e69948acc3fa2c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 8 Feb 2024 18:55:38 +0200 Subject: [PATCH 1009/2255] selftests: forwarding: Add missing multicast routing config entries The two tests that make use of multicast routig (router.sh and router_multicast.sh) are currently failing in the netdev CI because the kernel is missing multicast routing support. Fix by adding the required config entries. Fixes: 6d4efada3b82 ("selftests: forwarding: Add multicast routing test") Signed-off-by: Ido Schimmel Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240208165538.1303021-1-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/config | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/config b/tools/testing/selftests/net/forwarding/config index ba2343514582..8d7a1a004b7c 100644 --- a/tools/testing/selftests/net/forwarding/config +++ b/tools/testing/selftests/net/forwarding/config @@ -9,6 +9,13 @@ CONFIG_CGROUP_BPF=y CONFIG_DUMMY=m CONFIG_IPV6=y CONFIG_IPV6_GRE=m +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y CONFIG_MACVLAN=m CONFIG_NET_ACT_CT=m CONFIG_NET_ACT_MIRRED=m From 4a49c88ea5651a77f7b2292ca7d7e2c16e2feac6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 5 Feb 2024 14:22:32 +0100 Subject: [PATCH 1010/2255] ethernet: wiznet: Use devm_platform_get_and_ioremap_resource() in w5300_hw_probe() A wrapper function is available since the commit 890cc39a8799 ("drivers: provide devm_platform_get_and_ioremap_resource()"). Thus reuse existing functionality instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://lore.kernel.org/r/46f64db3-3f8f-4c6c-8d70-38daeefccac1@web.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wiznet/w5300.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c index 3318b50a5911..f165616f36fe 100644 --- a/drivers/net/ethernet/wiznet/w5300.c +++ b/drivers/net/ethernet/wiznet/w5300.c @@ -539,8 +539,7 @@ static int w5300_hw_probe(struct platform_device *pdev) eth_hw_addr_random(ndev); } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, mem); + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); From 709990df5ed0e7f2aec6cd386a17bd8c1454f7fb Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 5 Feb 2024 14:44:20 +0100 Subject: [PATCH 1011/2255] net: emaclite: Use devm_platform_get_and_ioremap_resource() in xemaclite_of_probe() A wrapper function is available since the commit 890cc39a8799 ("drivers: provide devm_platform_get_and_ioremap_resource()"). Thus reuse existing functionality instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://lore.kernel.org/r/f87065d0-e398-4ffa-bfa4-9ff99d73f206@web.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xilinx/xilinx_emaclite.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 765aa516aada..940452d0a4d2 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -1114,8 +1114,7 @@ static int xemaclite_of_probe(struct platform_device *ofdev) ndev->irq = rc; - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); - lp->base_addr = devm_ioremap_resource(&ofdev->dev, res); + lp->base_addr = devm_platform_get_and_ioremap_resource(ofdev, 0, &res); if (IS_ERR(lp->base_addr)) { rc = PTR_ERR(lp->base_addr); goto error; From f51470c5c4a08d3e69f7c7891633b960aa6fe678 Mon Sep 17 00:00:00 2001 From: Victor Nogueira Date: Thu, 1 Feb 2024 23:07:26 -0300 Subject: [PATCH 1012/2255] selftests: tc-testing: add mirred to block tdc tests Add 8 new mirred tdc tests that target mirred to block: - Add mirred mirror to egress block action - Add mirred mirror to ingress block action - Add mirred redirect to egress block action - Add mirred redirect to ingress block action - Try to add mirred action with both dev and block - Try to add mirred action without specifying neither dev nor block - Replace mirred redirect to dev action with redirect to block - Replace mirred redirect to block action with mirror to dev Signed-off-by: Victor Nogueira Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20240202020726.529170-1-victor@mojatatu.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/actions/mirred.json | 396 ++++++++++++++++++ 1 file changed, 396 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json index b53d12909962..795cf1ce8af0 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json @@ -649,5 +649,401 @@ "teardown": [ "$TC actions flush action mirred" ] + }, + { + "id": "456d", + "name": "Add mirred mirror to egress block action", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 egress_block 21 clsact", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action mirred egress mirror index 1 blockid 21", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action mirred index 1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "mirred", + "mirred_action": "mirror", + "direction": "egress", + "to_blockid": 21, + "control_action": { + "type": "pipe" + }, + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 egress_block 21 clsact", + "$TC actions flush action mirred" + ] + }, + { + "id": "2358", + "name": "Add mirred mirror to ingress block action", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 ingress_block 21 clsact", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror index 1 blockid 21", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action mirred index 1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "mirred", + "mirred_action": "mirror", + "direction": "ingress", + "to_blockid": 21, + "control_action": { + "type": "pipe" + }, + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress_block 21 clsact", + "$TC actions flush action mirred" + ] + }, + { + "id": "fdb1", + "name": "Add mirred redirect to egress block action", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 ingress_block 21 clsact", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action mirred egress redirect index 1 blockid 21", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action mirred index 1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "mirred", + "mirred_action": "redirect", + "direction": "egress", + "to_blockid": 21, + "control_action": { + "type": "stolen" + }, + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress_block 21 clsact", + "$TC actions flush action mirred" + ] + }, + { + "id": "20cc", + "name": "Add mirred redirect to ingress block action", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 ingress_block 21 clsact", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress redirect index 1 blockid 21", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action mirred index 1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "mirred", + "mirred_action": "redirect", + "direction": "ingress", + "to_blockid": 21, + "control_action": { + "type": "stolen" + }, + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress_block 21 clsact", + "$TC actions flush action mirred" + ] + }, + { + "id": "e739", + "name": "Try to add mirred action with both dev and block", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 ingress_block 21 clsact", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress redirect index 1 blockid 21 dev $DEV1", + "expExitCode": "255", + "verifyCmd": "$TC -j actions list action mirred", + "matchJSON": [], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress_block 21 clsact", + "$TC actions flush action mirred" + ] + }, + { + "id": "2f47", + "name": "Try to add mirred action without specifying neither dev nor block", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 ingress_block 21 clsact", + 0 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress redirect index 1", + "expExitCode": "255", + "verifyCmd": "$TC -j actions list action mirred", + "matchJSON": [], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress_block 21 clsact", + "$TC actions flush action mirred" + ] + }, + { + "id": "3188", + "name": "Replace mirred redirect to dev action with redirect to block", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 ingress_block 21 clsact", + 0 + ], + [ + "$TC actions add action mirred ingress redirect index 1 dev $DEV1", + 0 + ] + ], + "cmdUnderTest": "$TC actions replace action mirred egress redirect index 1 blockid 21", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action mirred index 1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "mirred", + "mirred_action": "redirect", + "direction": "egress", + "to_blockid": 21, + "control_action": { + "type": "stolen" + }, + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress_block 21 clsact", + "$TC actions flush action mirred" + ] + }, + { + "id": "83cc", + "name": "Replace mirred redirect to block action with mirror to dev", + "category": [ + "actions", + "mirred" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ], + [ + "$TC qdisc add dev $DEV1 ingress_block 21 clsact", + 0 + ], + [ + "$TC actions add action mirred egress redirect index 1 blockid 21", + 0 + ] + ], + "cmdUnderTest": "$TC actions replace action mirred ingress mirror index 1 dev lo", + "expExitCode": "0", + "verifyCmd": "$TC -j actions get action mirred index 1", + "matchJSON": [ + { + "total acts": 0 + }, + { + "actions": [ + { + "order": 1, + "kind": "mirred", + "mirred_action": "mirror", + "direction": "ingress", + "to_dev": "lo", + "control_action": { + "type": "pipe" + }, + "index": 1, + "ref": 1, + "bind": 0, + "not_in_hw": true + } + ] + } + ], + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress_block 21 clsact", + "$TC actions flush action mirred" + ] } ] From f42822f22b1c5f72c7e3497d9683f379ab0c5fe4 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 5 Feb 2024 14:31:50 -0800 Subject: [PATCH 1013/2255] bnxt_en: Use firmware provided maximum filter counts. While individual filter structures are allocated as needed, there is an array to keep track of the software filter IDs that we allocate ahead of time. Rather than relying on a fixed maximum filter count to allocate this array, get the maximum from the firmware when available. Move these filter related maximum counts queried from the firmware to the bnxt_hw_resc struct. If the firmware is not providing these maximum counts, fall back to the hard-coded constant. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Michal Swiatkowski Link: https://lore.kernel.org/r/20240205223202.25341-2-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 26 ++++++++++++------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 13 +++++----- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 4 +-- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 8fe8a73ffa7e..aa3a7dccd202 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4840,7 +4840,7 @@ static int bnxt_alloc_ntp_fltrs(struct bnxt *bp) INIT_HLIST_HEAD(&bp->ntp_fltr_hash_tbl[i]); bp->ntp_fltr_count = 0; - bp->ntp_fltr_bmap = bitmap_zalloc(BNXT_MAX_FLTR, GFP_KERNEL); + bp->ntp_fltr_bmap = bitmap_zalloc(bp->max_fltr, GFP_KERNEL); if (!bp->ntp_fltr_bmap) rc = -ENOMEM; @@ -5480,7 +5480,7 @@ static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr, int bit_id; bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, - BNXT_MAX_FLTR, 0); + bp->max_fltr, 0); if (bit_id < 0) return -ENOMEM; fltr->base.sw_id = (u16)bit_id; @@ -8709,6 +8709,13 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp) hw_resc->max_vnics = le16_to_cpu(resp->max_vnics); hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx); + hw_resc->max_encap_records = le32_to_cpu(resp->max_encap_records); + hw_resc->max_decap_records = le32_to_cpu(resp->max_decap_records); + hw_resc->max_tx_em_flows = le32_to_cpu(resp->max_tx_em_flows); + hw_resc->max_tx_wm_flows = le32_to_cpu(resp->max_tx_wm_flows); + hw_resc->max_rx_em_flows = le32_to_cpu(resp->max_rx_em_flows); + hw_resc->max_rx_wm_flows = le32_to_cpu(resp->max_rx_wm_flows); + if (BNXT_PF(bp)) { struct bnxt_pf_info *pf = &bp->pf; @@ -8717,12 +8724,6 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp) memcpy(pf->mac_addr, resp->mac_address, ETH_ALEN); pf->first_vf_id = le16_to_cpu(resp->first_vf_id); pf->max_vfs = le16_to_cpu(resp->max_vfs); - pf->max_encap_records = le32_to_cpu(resp->max_encap_records); - pf->max_decap_records = le32_to_cpu(resp->max_decap_records); - pf->max_tx_em_flows = le32_to_cpu(resp->max_tx_em_flows); - pf->max_tx_wm_flows = le32_to_cpu(resp->max_tx_wm_flows); - pf->max_rx_em_flows = le32_to_cpu(resp->max_rx_em_flows); - pf->max_rx_wm_flows = le32_to_cpu(resp->max_rx_wm_flows); bp->flags &= ~BNXT_FLAG_WOL_CAP; if (flags & FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED) bp->flags |= BNXT_FLAG_WOL_CAP; @@ -13900,7 +13901,7 @@ int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, int bit_id; spin_lock_bh(&bp->ntp_fltr_lock); - bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, BNXT_MAX_FLTR, 0); + bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, bp->max_fltr, 0); if (bit_id < 0) { spin_unlock_bh(&bp->ntp_fltr_lock); return -ENOMEM; @@ -14670,6 +14671,7 @@ void bnxt_print_device_info(struct bnxt *bp) static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct bnxt_hw_resc *hw_resc; struct net_device *dev; struct bnxt *bp; int rc, max_irqs; @@ -14828,6 +14830,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err_pci_clean; + hw_resc = &bp->hw_resc; + bp->max_fltr = hw_resc->max_rx_em_flows + hw_resc->max_rx_wm_flows + + BNXT_L2_FLTR_MAX_FLTR; + /* Older firmware may not report these filters properly */ + if (bp->max_fltr < BNXT_MAX_FLTR) + bp->max_fltr = BNXT_MAX_FLTR; bnxt_init_l2_fltr_tbl(bp); bnxt_set_rx_skb_mode(bp, false); bnxt_set_tpa_flags(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index b2cb3e77559d..4bd1cf01d99e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1281,6 +1281,12 @@ struct bnxt_hw_resc { u16 max_nqs; u16 max_irqs; u16 resv_irqs; + u32 max_encap_records; + u32 max_decap_records; + u32 max_tx_em_flows; + u32 max_tx_wm_flows; + u32 max_rx_em_flows; + u32 max_rx_wm_flows; }; #if defined(CONFIG_BNXT_SRIOV) @@ -1315,12 +1321,6 @@ struct bnxt_pf_info { u16 active_vfs; u16 registered_vfs; u16 max_vfs; - u32 max_encap_records; - u32 max_decap_records; - u32 max_tx_em_flows; - u32 max_tx_wm_flows; - u32 max_rx_em_flows; - u32 max_rx_wm_flows; unsigned long *vf_event_bmap; u16 hwrm_cmd_req_pages; u8 vf_resv_strategy; @@ -2428,6 +2428,7 @@ struct bnxt { unsigned long *ntp_fltr_bmap; int ntp_fltr_count; + int max_fltr; #define BNXT_L2_FLTR_MAX_FLTR 1024 #define BNXT_L2_FLTR_HASH_SIZE 32 diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 482ce88b1563..0effa87187ee 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1077,7 +1077,7 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) struct flow_keys *fkeys; int rc = -EINVAL; - if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR) + if (fs->location >= bp->max_fltr) return rc; rcu_read_lock(); @@ -1521,7 +1521,7 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, case ETHTOOL_GRXCLSRLCNT: cmd->rule_cnt = bp->ntp_fltr_count; - cmd->data = BNXT_NTP_FLTR_MAX_FLTR | RX_CLS_LOC_SPECIAL; + cmd->data = bp->max_fltr | RX_CLS_LOC_SPECIAL; break; case ETHTOOL_GRXCLSRLALL: From e462998abc6280ac093ca18e312d2a8ccc0df64b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 5 Feb 2024 14:31:51 -0800 Subject: [PATCH 1014/2255] bnxt_en: Add ethtool -N support for ether filters. Add ETHTOOL_SRXCLSRLINS and ETHTOOL_SRXCLSRLDEL support for inserting and deleting L2 ether filter rules. Destination MAC address and optional VLAN are supported for each filter entry. This is currently only supported on older BCM573XX and BCM574XX chips only. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-3-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 34 +++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 69 ++++++++++++++++++- 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index aa3a7dccd202..b9670debb990 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5519,6 +5519,40 @@ static struct bnxt_l2_filter *bnxt_alloc_l2_filter(struct bnxt *bp, return fltr; } +struct bnxt_l2_filter *bnxt_alloc_new_l2_filter(struct bnxt *bp, + struct bnxt_l2_key *key, + u16 flags) +{ + struct bnxt_l2_filter *fltr; + u32 idx; + int rc; + + idx = jhash2(&key->filter_key, BNXT_L2_KEY_SIZE, bp->hash_seed) & + BNXT_L2_FLTR_HASH_MASK; + spin_lock_bh(&bp->ntp_fltr_lock); + fltr = __bnxt_lookup_l2_filter(bp, key, idx); + if (fltr) { + fltr = ERR_PTR(-EEXIST); + goto l2_filter_exit; + } + fltr = kzalloc(sizeof(*fltr), GFP_ATOMIC); + if (!fltr) { + fltr = ERR_PTR(-ENOMEM); + goto l2_filter_exit; + } + fltr->base.flags = flags; + rc = bnxt_init_l2_filter(bp, fltr, key, idx); + if (rc) { + spin_unlock_bh(&bp->ntp_fltr_lock); + bnxt_del_l2_filter(bp, fltr); + return ERR_PTR(rc); + } + +l2_filter_exit: + spin_unlock_bh(&bp->ntp_fltr_lock); + return fltr; +} + static u16 bnxt_vf_target_id(struct bnxt_pf_info *pf, u16 vf_idx) { #ifdef CONFIG_BNXT_SRIOV diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 4bd1cf01d99e..21721b8748bc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2646,6 +2646,9 @@ int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size, bool async_only); int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp); void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr); +struct bnxt_l2_filter *bnxt_alloc_new_l2_filter(struct bnxt *bp, + struct bnxt_l2_key *key, + u16 flags); int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 0effa87187ee..4ed1f9f77236 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1152,6 +1152,58 @@ fltr_err: return rc; } +static int bnxt_add_l2_cls_rule(struct bnxt *bp, + struct ethtool_rx_flow_spec *fs) +{ + u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie); + u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); + struct ethhdr *h_ether = &fs->h_u.ether_spec; + struct ethhdr *m_ether = &fs->m_u.ether_spec; + struct bnxt_l2_filter *fltr; + struct bnxt_l2_key key; + u16 vnic_id; + u8 flags; + int rc; + + if (BNXT_CHIP_P5_PLUS(bp)) + return -EOPNOTSUPP; + + if (!is_broadcast_ether_addr(m_ether->h_dest)) + return -EINVAL; + ether_addr_copy(key.dst_mac_addr, h_ether->h_dest); + key.vlan = 0; + if (fs->flow_type & FLOW_EXT) { + struct ethtool_flow_ext *m_ext = &fs->m_ext; + struct ethtool_flow_ext *h_ext = &fs->h_ext; + + if (m_ext->vlan_tci != htons(0xfff) || !h_ext->vlan_tci) + return -EINVAL; + key.vlan = ntohs(h_ext->vlan_tci); + } + + if (vf) { + flags = BNXT_ACT_FUNC_DST; + vnic_id = 0xffff; + vf--; + } else { + flags = BNXT_ACT_RING_DST; + vnic_id = bp->vnic_info[ring + 1].fw_vnic_id; + } + fltr = bnxt_alloc_new_l2_filter(bp, &key, flags); + if (IS_ERR(fltr)) + return PTR_ERR(fltr); + + fltr->base.fw_vnic_id = vnic_id; + fltr->base.rxq = ring; + fltr->base.vf_idx = vf; + rc = bnxt_hwrm_l2_filter_alloc(bp, fltr); + if (rc) + bnxt_del_l2_filter(bp, fltr); + else + fs->location = fltr->base.sw_id; + return rc; +} + #define IPV4_ALL_MASK ((__force __be32)~0) #define L4_PORT_ALL_MASK ((__force __be16)~0) @@ -1335,7 +1387,7 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) return -EINVAL; flow_type &= ~FLOW_EXT; if (flow_type == ETHER_FLOW) - rc = -EOPNOTSUPP; + rc = bnxt_add_l2_cls_rule(bp, fs); else rc = bnxt_add_ntuple_cls_rule(bp, fs); return rc; @@ -1346,11 +1398,22 @@ static int bnxt_srxclsrldel(struct bnxt *bp, struct ethtool_rxnfc *cmd) struct ethtool_rx_flow_spec *fs = &cmd->fs; struct bnxt_filter_base *fltr_base; struct bnxt_ntuple_filter *fltr; + u32 id = fs->location; rcu_read_lock(); + fltr_base = bnxt_get_one_fltr_rcu(bp, bp->l2_fltr_hash_tbl, + BNXT_L2_FLTR_HASH_SIZE, id); + if (fltr_base) { + struct bnxt_l2_filter *l2_fltr; + + l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base); + rcu_read_unlock(); + bnxt_hwrm_l2_filter_free(bp, l2_fltr); + bnxt_del_l2_filter(bp, l2_fltr); + return 0; + } fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl, - BNXT_NTP_FLTR_HASH_SIZE, - fs->location); + BNXT_NTP_FLTR_HASH_SIZE, id); if (!fltr_base) { rcu_read_unlock(); return -ENOENT; From 7c8036fb71ce56ca6ce6f3f271fcbaa58e8512ae Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 5 Feb 2024 14:31:52 -0800 Subject: [PATCH 1015/2255] bnxt_en: Support ethtool -n to display ether filters. Implement ETHTOOL_GRXCLSRULE for the user defined ether filters. Use the common functions to walk the L2 filter hash table. Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Michal Swiatkowski Link: https://lore.kernel.org/r/20240205223202.25341-4-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 38 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b9670debb990..2bc907548707 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5484,6 +5484,7 @@ static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr, if (bit_id < 0) return -ENOMEM; fltr->base.sw_id = (u16)bit_id; + bp->ntp_fltr_count++; } head = &bp->l2_fltr_hash_tbl[idx]; hlist_add_head_rcu(&fltr->base.hash, head); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 4ed1f9f77236..0165065c743f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1058,11 +1058,17 @@ static struct bnxt_filter_base *bnxt_get_one_fltr_rcu(struct bnxt *bp, static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, u32 *rule_locs) { + u32 count; + cmd->data = bp->ntp_fltr_count; rcu_read_lock(); + count = bnxt_get_all_fltr_ids_rcu(bp, bp->l2_fltr_hash_tbl, + BNXT_L2_FLTR_HASH_SIZE, rule_locs, 0, + cmd->rule_cnt); cmd->rule_cnt = bnxt_get_all_fltr_ids_rcu(bp, bp->ntp_fltr_hash_tbl, BNXT_NTP_FLTR_HASH_SIZE, - rule_locs, 0, cmd->rule_cnt); + rule_locs, count, + cmd->rule_cnt); rcu_read_unlock(); return 0; @@ -1081,6 +1087,36 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) return rc; rcu_read_lock(); + fltr_base = bnxt_get_one_fltr_rcu(bp, bp->l2_fltr_hash_tbl, + BNXT_L2_FLTR_HASH_SIZE, + fs->location); + if (fltr_base) { + struct ethhdr *h_ether = &fs->h_u.ether_spec; + struct ethhdr *m_ether = &fs->m_u.ether_spec; + struct bnxt_l2_filter *l2_fltr; + struct bnxt_l2_key *l2_key; + + l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base); + l2_key = &l2_fltr->l2_key; + fs->flow_type = ETHER_FLOW; + ether_addr_copy(h_ether->h_dest, l2_key->dst_mac_addr); + eth_broadcast_addr(m_ether->h_dest); + if (l2_key->vlan) { + struct ethtool_flow_ext *m_ext = &fs->m_ext; + struct ethtool_flow_ext *h_ext = &fs->h_ext; + + fs->flow_type |= FLOW_EXT; + m_ext->vlan_tci = htons(0xfff); + h_ext->vlan_tci = htons(l2_key->vlan); + } + if (fltr_base->flags & BNXT_ACT_RING_DST) + fs->ring_cookie = fltr_base->rxq; + if (fltr_base->flags & BNXT_ACT_FUNC_DST) + fs->ring_cookie = (u64)(fltr_base->vf_idx + 1) << + ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF; + rcu_read_unlock(); + return 0; + } fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl, BNXT_NTP_FLTR_HASH_SIZE, fs->location); From c8d129c437f62738e8a750f75cb4896a2d0fea60 Mon Sep 17 00:00:00 2001 From: Edwin Peer Date: Mon, 5 Feb 2024 14:31:53 -0800 Subject: [PATCH 1016/2255] bnxt_en: implement fully specified 5-tuple masks Support subfield masking for IP addresses and ports. Previously, only entire fields could be included or excluded in NTUPLE filters. Reviewed-by: Pavan Chebbi Signed-off-by: Edwin Peer Signed-off-by: Michael Chan Reviewed-by: Michal Swiatkowski Link: https://lore.kernel.org/r/20240205223202.25341-5-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 141 ++++++++++------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 19 +-- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 142 +++++------------- 3 files changed, 134 insertions(+), 168 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 2bc907548707..0d65d4574045 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -246,6 +246,49 @@ static const u16 bnxt_async_events_arr[] = { static struct workqueue_struct *bnxt_pf_wq; +#define BNXT_IPV6_MASK_ALL {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}} +#define BNXT_IPV6_MASK_NONE {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}} + +const struct bnxt_flow_masks BNXT_FLOW_MASK_NONE = { + .ports = { + .src = 0, + .dst = 0, + }, + .addrs = { + .v6addrs = { + .src = BNXT_IPV6_MASK_NONE, + .dst = BNXT_IPV6_MASK_NONE, + }, + }, +}; + +const struct bnxt_flow_masks BNXT_FLOW_IPV6_MASK_ALL = { + .ports = { + .src = cpu_to_be16(0xffff), + .dst = cpu_to_be16(0xffff), + }, + .addrs = { + .v6addrs = { + .src = BNXT_IPV6_MASK_ALL, + .dst = BNXT_IPV6_MASK_ALL, + }, + }, +}; + +const struct bnxt_flow_masks BNXT_FLOW_IPV4_MASK_ALL = { + .ports = { + .src = cpu_to_be16(0xffff), + .dst = cpu_to_be16(0xffff), + }, + .addrs = { + .v4addrs = { + .src = cpu_to_be32(0xffffffff), + .dst = cpu_to_be32(0xffffffff), + }, + }, +}; + static bool bnxt_vf_pciid(enum board_idx idx) { return (idx == NETXTREME_C_VF || idx == NETXTREME_E_VF || @@ -5690,6 +5733,7 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, { struct hwrm_cfa_ntuple_filter_alloc_output *resp; struct hwrm_cfa_ntuple_filter_alloc_input *req; + struct bnxt_flow_masks *masks = &fltr->fmasks; struct flow_keys *keys = &fltr->fkeys; struct bnxt_l2_filter *l2_fltr; struct bnxt_vnic_info *vnic; @@ -5722,25 +5766,15 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, req->ethertype = htons(ETH_P_IPV6); req->ip_addr_type = CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV6; - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { - *(struct in6_addr *)&req->src_ipaddr[0] = - keys->addrs.v6addrs.src; - bnxt_fill_ipv6_mask(req->src_ipaddr_mask); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { - *(struct in6_addr *)&req->dst_ipaddr[0] = - keys->addrs.v6addrs.dst; - bnxt_fill_ipv6_mask(req->dst_ipaddr_mask); - } + *(struct in6_addr *)&req->src_ipaddr[0] = keys->addrs.v6addrs.src; + *(struct in6_addr *)&req->src_ipaddr_mask[0] = masks->addrs.v6addrs.src; + *(struct in6_addr *)&req->dst_ipaddr[0] = keys->addrs.v6addrs.dst; + *(struct in6_addr *)&req->dst_ipaddr_mask[0] = masks->addrs.v6addrs.dst; } else { - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { - req->src_ipaddr[0] = keys->addrs.v4addrs.src; - req->src_ipaddr_mask[0] = cpu_to_be32(0xffffffff); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { - req->dst_ipaddr[0] = keys->addrs.v4addrs.dst; - req->dst_ipaddr_mask[0] = cpu_to_be32(0xffffffff); - } + req->src_ipaddr[0] = keys->addrs.v4addrs.src; + req->src_ipaddr_mask[0] = masks->addrs.v4addrs.src; + req->dst_ipaddr[0] = keys->addrs.v4addrs.dst; + req->dst_ipaddr_mask[0] = masks->addrs.v4addrs.dst; } if (keys->control.flags & FLOW_DIS_ENCAPSULATION) { req->enables |= cpu_to_le32(BNXT_NTP_TUNNEL_FLTR_FLAG); @@ -5748,14 +5782,10 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL; } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) { - req->src_port = keys->ports.src; - req->src_port_mask = cpu_to_be16(0xffff); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) { - req->dst_port = keys->ports.dst; - req->dst_port_mask = cpu_to_be16(0xffff); - } + req->src_port = keys->ports.src; + req->src_port_mask = masks->ports.src; + req->dst_port = keys->ports.dst; + req->dst_port_mask = masks->ports.dst; resp = hwrm_req_hold(bp, req); rc = hwrm_req_send(bp, req); @@ -13956,45 +13986,39 @@ int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, struct bnxt_ntuple_filter *f2) { + struct bnxt_flow_masks *masks1 = &f1->fmasks; + struct bnxt_flow_masks *masks2 = &f2->fmasks; struct flow_keys *keys1 = &f1->fkeys; struct flow_keys *keys2 = &f2->fkeys; - if (f1->ntuple_flags != f2->ntuple_flags) - return false; - if (keys1->basic.n_proto != keys2->basic.n_proto || keys1->basic.ip_proto != keys2->basic.ip_proto) return false; if (keys1->basic.n_proto == htons(ETH_P_IP)) { - if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) && - keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src) || - ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) && - keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst)) + if (keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src || + masks1->addrs.v4addrs.src != masks2->addrs.v4addrs.src || + keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst || + masks1->addrs.v4addrs.dst != masks2->addrs.v4addrs.dst) return false; } else { - if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) && - memcmp(&keys1->addrs.v6addrs.src, - &keys2->addrs.v6addrs.src, - sizeof(keys1->addrs.v6addrs.src))) || - ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) && - memcmp(&keys1->addrs.v6addrs.dst, - &keys2->addrs.v6addrs.dst, - sizeof(keys1->addrs.v6addrs.dst)))) + if (!ipv6_addr_equal(&keys1->addrs.v6addrs.src, + &keys2->addrs.v6addrs.src) || + !ipv6_addr_equal(&masks1->addrs.v6addrs.src, + &masks2->addrs.v6addrs.src) || + !ipv6_addr_equal(&keys1->addrs.v6addrs.dst, + &keys2->addrs.v6addrs.dst) || + !ipv6_addr_equal(&masks1->addrs.v6addrs.dst, + &masks2->addrs.v6addrs.dst)) return false; } - if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) && - keys1->ports.src != keys2->ports.src) || - ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) && - keys1->ports.dst != keys2->ports.dst)) - return false; - - if (keys1->control.flags == keys2->control.flags && - f1->l2_fltr == f2->l2_fltr) - return true; - - return false; + return keys1->ports.src == keys2->ports.src && + masks1->ports.src == masks2->ports.src && + keys1->ports.dst == keys2->ports.dst && + masks1->ports.dst == masks2->ports.dst && + keys1->control.flags == keys2->control.flags && + f1->l2_fltr == f2->l2_fltr; } struct bnxt_ntuple_filter * @@ -14059,10 +14083,13 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, rc = -EPROTONOSUPPORT; goto err_free; } - if (fkeys->basic.n_proto == htons(ETH_P_IPV6) && - bp->hwrm_spec_code < 0x10601) { - rc = -EPROTONOSUPPORT; - goto err_free; + new_fltr->fmasks = BNXT_FLOW_IPV4_MASK_ALL; + if (fkeys->basic.n_proto == htons(ETH_P_IPV6)) { + if (bp->hwrm_spec_code < 0x10601) { + rc = -EPROTONOSUPPORT; + goto err_free; + } + new_fltr->fmasks = BNXT_FLOW_IPV6_MASK_ALL; } flags = fkeys->control.flags; if (((flags & FLOW_DIS_ENCAPSULATION) && @@ -14070,9 +14097,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, rc = -EPROTONOSUPPORT; goto err_free; } - new_fltr->l2_fltr = l2_fltr; - new_fltr->ntuple_flags = BNXT_NTUPLE_MATCH_ALL; idx = bnxt_get_ntp_filter_idx(bp, fkeys, skb); rcu_read_lock(); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 21721b8748bc..aae180fa63b7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1355,19 +1355,20 @@ struct bnxt_filter_base { struct rcu_head rcu; }; +struct bnxt_flow_masks { + struct flow_dissector_key_ports ports; + struct flow_dissector_key_addrs addrs; +}; + +extern const struct bnxt_flow_masks BNXT_FLOW_MASK_NONE; +extern const struct bnxt_flow_masks BNXT_FLOW_IPV6_MASK_ALL; +extern const struct bnxt_flow_masks BNXT_FLOW_IPV4_MASK_ALL; + struct bnxt_ntuple_filter { struct bnxt_filter_base base; struct flow_keys fkeys; + struct bnxt_flow_masks fmasks; struct bnxt_l2_filter *l2_fltr; - u32 ntuple_flags; -#define BNXT_NTUPLE_MATCH_SRC_IP 1 -#define BNXT_NTUPLE_MATCH_DST_IP 2 -#define BNXT_NTUPLE_MATCH_SRC_PORT 4 -#define BNXT_NTUPLE_MATCH_DST_PORT 8 -#define BNXT_NTUPLE_MATCH_ALL (BNXT_NTUPLE_MATCH_SRC_IP | \ - BNXT_NTUPLE_MATCH_DST_IP | \ - BNXT_NTUPLE_MATCH_SRC_PORT | \ - BNXT_NTUPLE_MATCH_DST_PORT) u32 flow_id; }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 0165065c743f..408a086f62ae 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1080,6 +1080,7 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) (struct ethtool_rx_flow_spec *)&cmd->fs; struct bnxt_filter_base *fltr_base; struct bnxt_ntuple_filter *fltr; + struct bnxt_flow_masks *fmasks; struct flow_keys *fkeys; int rc = -EINVAL; @@ -1127,6 +1128,7 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base); fkeys = &fltr->fkeys; + fmasks = &fltr->fmasks; if (fkeys->basic.n_proto == htons(ETH_P_IP)) { if (fkeys->basic.ip_proto == IPPROTO_TCP) fs->flow_type = TCP_V4_FLOW; @@ -1135,22 +1137,14 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) else goto fltr_err; - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { - fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; - fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { - fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; - fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) { - fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; - fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) { - fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; - fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); - } + fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; + fs->m_u.tcp_ip4_spec.ip4src = fmasks->addrs.v4addrs.src; + fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; + fs->m_u.tcp_ip4_spec.ip4dst = fmasks->addrs.v4addrs.dst; + fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; + fs->m_u.tcp_ip4_spec.psrc = fmasks->ports.src; + fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; + fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst; } else { if (fkeys->basic.ip_proto == IPPROTO_TCP) fs->flow_type = TCP_V6_FLOW; @@ -1159,24 +1153,18 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) else goto fltr_err; - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { - *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = - fkeys->addrs.v6addrs.src; - bnxt_fill_ipv6_mask(fs->m_u.tcp_ip6_spec.ip6src); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { - *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = - fkeys->addrs.v6addrs.dst; - bnxt_fill_ipv6_mask(fs->m_u.tcp_ip6_spec.ip6dst); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) { - fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; - fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); - } - if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) { - fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; - fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); - } + *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = + fkeys->addrs.v6addrs.src; + *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6src[0] = + fmasks->addrs.v6addrs.src; + *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = + fkeys->addrs.v6addrs.dst; + *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6dst[0] = + fmasks->addrs.v6addrs.dst; + fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; + fs->m_u.tcp_ip6_spec.psrc = fmasks->ports.src; + fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; + fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst; } fs->ring_cookie = fltr->base.rxq; @@ -1240,19 +1228,6 @@ static int bnxt_add_l2_cls_rule(struct bnxt *bp, return rc; } -#define IPV4_ALL_MASK ((__force __be32)~0) -#define L4_PORT_ALL_MASK ((__force __be16)~0) - -static bool ipv6_mask_is_full(__be32 mask[4]) -{ - return (mask[0] & mask[1] & mask[2] & mask[3]) == IPV4_ALL_MASK; -} - -static bool ipv6_mask_is_zero(__be32 mask[4]) -{ - return !(mask[0] | mask[1] | mask[2] | mask[3]); -} - static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, struct ethtool_rx_flow_spec *fs) { @@ -1260,6 +1235,7 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie); struct bnxt_ntuple_filter *new_fltr, *fltr; struct bnxt_l2_filter *l2_fltr; + struct bnxt_flow_masks *fmasks; u32 flow_type = fs->flow_type; struct flow_keys *fkeys; u32 idx; @@ -1278,6 +1254,7 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, l2_fltr = bp->vnic_info[0].l2_filters[0]; atomic_inc(&l2_fltr->refcnt); new_fltr->l2_fltr = l2_fltr; + fmasks = &new_fltr->fmasks; fkeys = &new_fltr->fkeys; rc = -EOPNOTSUPP; @@ -1291,32 +1268,14 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, if (flow_type == UDP_V4_FLOW) fkeys->basic.ip_proto = IPPROTO_UDP; fkeys->basic.n_proto = htons(ETH_P_IP); - - if (ip_mask->ip4src == IPV4_ALL_MASK) { - fkeys->addrs.v4addrs.src = ip_spec->ip4src; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_IP; - } else if (ip_mask->ip4src) { - goto ntuple_err; - } - if (ip_mask->ip4dst == IPV4_ALL_MASK) { - fkeys->addrs.v4addrs.dst = ip_spec->ip4dst; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_IP; - } else if (ip_mask->ip4dst) { - goto ntuple_err; - } - - if (ip_mask->psrc == L4_PORT_ALL_MASK) { - fkeys->ports.src = ip_spec->psrc; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_PORT; - } else if (ip_mask->psrc) { - goto ntuple_err; - } - if (ip_mask->pdst == L4_PORT_ALL_MASK) { - fkeys->ports.dst = ip_spec->pdst; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_PORT; - } else if (ip_mask->pdst) { - goto ntuple_err; - } + fkeys->addrs.v4addrs.src = ip_spec->ip4src; + fmasks->addrs.v4addrs.src = ip_mask->ip4src; + fkeys->addrs.v4addrs.dst = ip_spec->ip4dst; + fmasks->addrs.v4addrs.dst = ip_mask->ip4dst; + fkeys->ports.src = ip_spec->psrc; + fmasks->ports.src = ip_mask->psrc; + fkeys->ports.dst = ip_spec->pdst; + fmasks->ports.dst = ip_mask->pdst; break; } case TCP_V6_FLOW: @@ -1329,40 +1288,21 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, fkeys->basic.ip_proto = IPPROTO_UDP; fkeys->basic.n_proto = htons(ETH_P_IPV6); - if (ipv6_mask_is_full(ip_mask->ip6src)) { - fkeys->addrs.v6addrs.src = - *(struct in6_addr *)&ip_spec->ip6src; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_IP; - } else if (!ipv6_mask_is_zero(ip_mask->ip6src)) { - goto ntuple_err; - } - if (ipv6_mask_is_full(ip_mask->ip6dst)) { - fkeys->addrs.v6addrs.dst = - *(struct in6_addr *)&ip_spec->ip6dst; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_IP; - } else if (!ipv6_mask_is_zero(ip_mask->ip6dst)) { - goto ntuple_err; - } - - if (ip_mask->psrc == L4_PORT_ALL_MASK) { - fkeys->ports.src = ip_spec->psrc; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_PORT; - } else if (ip_mask->psrc) { - goto ntuple_err; - } - if (ip_mask->pdst == L4_PORT_ALL_MASK) { - fkeys->ports.dst = ip_spec->pdst; - new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_PORT; - } else if (ip_mask->pdst) { - goto ntuple_err; - } + fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src; + fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src; + fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst; + fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst; + fkeys->ports.src = ip_spec->psrc; + fmasks->ports.src = ip_mask->psrc; + fkeys->ports.dst = ip_spec->pdst; + fmasks->ports.dst = ip_mask->pdst; break; } default: rc = -EOPNOTSUPP; goto ntuple_err; } - if (!new_fltr->ntuple_flags) + if (!memcmp(&BNXT_FLOW_MASK_NONE, fmasks, sizeof(*fmasks))) goto ntuple_err; idx = bnxt_get_ntp_filter_idx(bp, fkeys, NULL); From 9ba0e56199e3e31357ae18daec8b025fe96f26b6 Mon Sep 17 00:00:00 2001 From: Vikas Gupta Date: Mon, 5 Feb 2024 14:31:54 -0800 Subject: [PATCH 1017/2255] bnxt_en: Enhance ethtool ntuple support for ip flows besides TCP/UDP Enable flow type ipv4/ipv6 1) for protocols ICMPV4 and ICMPV6. 2) for wildcard match. Wildcard matches to TCP/UDP/ICMP. Note that, IPPROTO_RAW(255) i.e. a reserved protocol considered for a wildcard. Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Vikas Gupta Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-6-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 + drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 124 +++++++++++++++--- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 2 + 4 files changed, 113 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0d65d4574045..027e3601d761 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8891,6 +8891,10 @@ static int bnxt_hwrm_cfa_adv_flow_mgnt_qcaps(struct bnxt *bp) CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V2_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2; + if (flags & + CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED) + bp->fw_cap |= BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO; + hwrm_cfa_adv_qcaps_exit: hwrm_req_drop(bp, req); return rc; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index aae180fa63b7..16f18c70c7bb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2302,6 +2302,7 @@ struct bnxt { #define BNXT_FW_CAP_PRE_RESV_VNICS BIT_ULL(35) #define BNXT_FW_CAP_BACKING_STORE_V2 BIT_ULL(36) #define BNXT_FW_CAP_VNIC_TUNNEL_TPA BIT_ULL(37) + #define BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO BIT_ULL(38) u32 fw_dbg_cap; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 408a086f62ae..5a100aeb2b78 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1130,28 +1130,50 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fkeys = &fltr->fkeys; fmasks = &fltr->fmasks; if (fkeys->basic.n_proto == htons(ETH_P_IP)) { - if (fkeys->basic.ip_proto == IPPROTO_TCP) + if (fkeys->basic.ip_proto == IPPROTO_ICMP || + fkeys->basic.ip_proto == IPPROTO_RAW) { + fs->flow_type = IP_USER_FLOW; + fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; + if (fkeys->basic.ip_proto == IPPROTO_ICMP) + fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP; + else + fs->h_u.usr_ip4_spec.proto = IPPROTO_RAW; + fs->m_u.usr_ip4_spec.proto = BNXT_IP_PROTO_FULL_MASK; + } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { fs->flow_type = TCP_V4_FLOW; - else if (fkeys->basic.ip_proto == IPPROTO_UDP) + } else if (fkeys->basic.ip_proto == IPPROTO_UDP) { fs->flow_type = UDP_V4_FLOW; - else + } else { goto fltr_err; + } fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; fs->m_u.tcp_ip4_spec.ip4src = fmasks->addrs.v4addrs.src; fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; fs->m_u.tcp_ip4_spec.ip4dst = fmasks->addrs.v4addrs.dst; - fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; - fs->m_u.tcp_ip4_spec.psrc = fmasks->ports.src; - fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; - fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst; + if (fs->flow_type == TCP_V4_FLOW || + fs->flow_type == UDP_V4_FLOW) { + fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; + fs->m_u.tcp_ip4_spec.psrc = fmasks->ports.src; + fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; + fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst; + } } else { - if (fkeys->basic.ip_proto == IPPROTO_TCP) + if (fkeys->basic.ip_proto == IPPROTO_ICMPV6 || + fkeys->basic.ip_proto == IPPROTO_RAW) { + fs->flow_type = IPV6_USER_FLOW; + if (fkeys->basic.ip_proto == IPPROTO_ICMPV6) + fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6; + else + fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_RAW; + fs->m_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_FULL_MASK; + } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { fs->flow_type = TCP_V6_FLOW; - else if (fkeys->basic.ip_proto == IPPROTO_UDP) + } else if (fkeys->basic.ip_proto == IPPROTO_UDP) { fs->flow_type = UDP_V6_FLOW; - else + } else { goto fltr_err; + } *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = fkeys->addrs.v6addrs.src; @@ -1161,10 +1183,13 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fkeys->addrs.v6addrs.dst; *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6dst[0] = fmasks->addrs.v6addrs.dst; - fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; - fs->m_u.tcp_ip6_spec.psrc = fmasks->ports.src; - fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; - fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst; + if (fs->flow_type == TCP_V6_FLOW || + fs->flow_type == UDP_V6_FLOW) { + fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; + fs->m_u.tcp_ip6_spec.psrc = fmasks->ports.src; + fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; + fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst; + } } fs->ring_cookie = fltr->base.rxq; @@ -1228,6 +1253,28 @@ static int bnxt_add_l2_cls_rule(struct bnxt *bp, return rc; } +static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec, + struct ethtool_usrip4_spec *ip_mask) +{ + if (ip_mask->l4_4_bytes || ip_mask->tos || + ip_spec->ip_ver != ETH_RX_NFC_IP4 || + ip_mask->proto != BNXT_IP_PROTO_FULL_MASK || + (ip_spec->proto != IPPROTO_RAW && ip_spec->proto != IPPROTO_ICMP)) + return false; + return true; +} + +static bool bnxt_verify_ntuple_ip6_flow(struct ethtool_usrip6_spec *ip_spec, + struct ethtool_usrip6_spec *ip_mask) +{ + if (ip_mask->l4_4_bytes || ip_mask->tclass || + ip_mask->l4_proto != BNXT_IP_PROTO_FULL_MASK || + (ip_spec->l4_proto != IPPROTO_RAW && + ip_spec->l4_proto != IPPROTO_ICMPV6)) + return false; + return true; +} + static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, struct ethtool_rx_flow_spec *fs) { @@ -1247,6 +1294,18 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, if ((flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf) return -EOPNOTSUPP; + if (flow_type == IP_USER_FLOW) { + if (!bnxt_verify_ntuple_ip4_flow(&fs->h_u.usr_ip4_spec, + &fs->m_u.usr_ip4_spec)) + return -EOPNOTSUPP; + } + + if (flow_type == IPV6_USER_FLOW) { + if (!bnxt_verify_ntuple_ip6_flow(&fs->h_u.usr_ip6_spec, + &fs->m_u.usr_ip6_spec)) + return -EOPNOTSUPP; + } + new_fltr = kzalloc(sizeof(*new_fltr), GFP_KERNEL); if (!new_fltr) return -ENOMEM; @@ -1259,6 +1318,18 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, rc = -EOPNOTSUPP; switch (flow_type) { + case IP_USER_FLOW: { + struct ethtool_usrip4_spec *ip_spec = &fs->h_u.usr_ip4_spec; + struct ethtool_usrip4_spec *ip_mask = &fs->m_u.usr_ip4_spec; + + fkeys->basic.ip_proto = ip_spec->proto; + fkeys->basic.n_proto = htons(ETH_P_IP); + fkeys->addrs.v4addrs.src = ip_spec->ip4src; + fmasks->addrs.v4addrs.src = ip_mask->ip4src; + fkeys->addrs.v4addrs.dst = ip_spec->ip4dst; + fmasks->addrs.v4addrs.dst = ip_mask->ip4dst; + break; + } case TCP_V4_FLOW: case UDP_V4_FLOW: { struct ethtool_tcpip4_spec *ip_spec = &fs->h_u.tcp_ip4_spec; @@ -1278,6 +1349,18 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, fmasks->ports.dst = ip_mask->pdst; break; } + case IPV6_USER_FLOW: { + struct ethtool_usrip6_spec *ip_spec = &fs->h_u.usr_ip6_spec; + struct ethtool_usrip6_spec *ip_mask = &fs->m_u.usr_ip6_spec; + + fkeys->basic.ip_proto = ip_spec->l4_proto; + fkeys->basic.n_proto = htons(ETH_P_IPV6); + fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src; + fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src; + fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst; + fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst; + break; + } case TCP_V6_FLOW: case UDP_V6_FLOW: { struct ethtool_tcpip6_spec *ip_spec = &fs->h_u.tcp_ip6_spec; @@ -1349,6 +1432,15 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) if (fs->location != RX_CLS_LOC_ANY) return -EINVAL; + flow_type = fs->flow_type; + if ((flow_type == IP_USER_FLOW || + flow_type == IPV6_USER_FLOW) && + !(bp->fw_cap & BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO)) + return -EOPNOTSUPP; + if (flow_type & (FLOW_MAC_EXT | FLOW_RSS)) + return -EINVAL; + flow_type &= ~FLOW_EXT; + ring = ethtool_get_flow_spec_ring(fs->ring_cookie); vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); if (BNXT_VF(bp) && vf) @@ -1358,10 +1450,6 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) if (!vf && ring >= bp->rx_nr_rings) return -EINVAL; - flow_type = fs->flow_type; - if (flow_type & (FLOW_MAC_EXT | FLOW_RSS)) - return -EINVAL; - flow_type &= ~FLOW_EXT; if (flow_type == ETHER_FLOW) rc = bnxt_add_l2_cls_rule(bp, fs); else diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index 0ea0f4a36a04..e2ee030237d4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -43,6 +43,8 @@ struct bnxt_led_cfg { #define BNXT_PXP_REG_LEN 0x3110 +#define BNXT_IP_PROTO_FULL_MASK 0xFF + extern const struct ethtool_ops bnxt_ethtool_ops; u32 bnxt_get_rxfh_indir_size(struct net_device *dev); From 7efd79c0e6893f74cd3150bfebe54e3054541702 Mon Sep 17 00:00:00 2001 From: Vikas Gupta Date: Mon, 5 Feb 2024 14:31:55 -0800 Subject: [PATCH 1018/2255] bnxt_en: Add drop action support for ntuple Add drop action for protocols TCP/UDP/ICMP 1) Drop action for TCP/UDP is supported via flow type tcp4/udp4/tcp6/udp6. 2) Drop action for ICMPV4/ICMPV6/wildcard is supported via flow type ipv4/ipv6. Reviewed-by: Andy Gospodarek Signed-off-by: Vikas Gupta Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-7-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++-- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 13 +++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 027e3601d761..0ebe6a27a31e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5747,8 +5747,9 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, l2_fltr = fltr->l2_fltr; req->l2_filter_id = l2_fltr->base.filter_id; - - if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) { + if (fltr->base.flags & BNXT_ACT_DROP) { + flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DROP; + } else if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) { flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX; req->dst_id = cpu_to_le16(fltr->base.rxq); } else { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 5a100aeb2b78..57fef0fc21d8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1192,7 +1192,10 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) } } - fs->ring_cookie = fltr->base.rxq; + if (fltr->base.flags & BNXT_ACT_DROP) + fs->ring_cookie = RX_CLS_FLOW_DISC; + else + fs->ring_cookie = fltr->base.rxq; rc = 0; fltr_err: @@ -1398,8 +1401,11 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, } rcu_read_unlock(); - new_fltr->base.rxq = ring; new_fltr->base.flags = BNXT_ACT_NO_AGING; + if (fs->ring_cookie == RX_CLS_FLOW_DISC) + new_fltr->base.flags |= BNXT_ACT_DROP; + else + new_fltr->base.rxq = ring; __set_bit(BNXT_FLTR_VALID, &new_fltr->base.state); rc = bnxt_insert_ntp_filter(bp, new_fltr, idx); if (!rc) { @@ -1441,6 +1447,9 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) return -EINVAL; flow_type &= ~FLOW_EXT; + if (fs->ring_cookie == RX_CLS_FLOW_DISC && flow_type != ETHER_FLOW) + return bnxt_add_ntuple_cls_rule(bp, fs); + ring = ethtool_get_flow_spec_ring(fs->ring_cookie); vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); if (BNXT_VF(bp) && vf) From be40b4e9cac8b8f376f3669becf2a3c147d5b05b Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Mon, 5 Feb 2024 14:31:56 -0800 Subject: [PATCH 1019/2255] bnxt_en: Add separate function to delete the filter structure Since we are going to do filter deletion at multiple places in the upcoming patches, add a function that does the deletion. Future patches add more code into this function. Since we are passing the address of the filter base to free the entire filter structure, add a comment to make sure that the base is always at the beginning of the structure. Reviewed-by: Andy Gospodarek Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-8-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 22 ++++++++++++---------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 ++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0ebe6a27a31e..9fb9c5f4ecbd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4841,6 +4841,16 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) } } +static void bnxt_del_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr) +{ + hlist_del(&fltr->hash); + if (fltr->flags) { + clear_bit(fltr->sw_id, bp->ntp_fltr_bmap); + bp->ntp_fltr_count--; + } + kfree(fltr); +} + static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) { int i; @@ -4858,10 +4868,7 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) bnxt_del_l2_filter(bp, fltr->l2_fltr); if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST)) continue; - hlist_del(&fltr->base.hash); - clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); - bp->ntp_fltr_count--; - kfree(fltr); + bnxt_del_fltr(bp, &fltr->base); } } if (!all) @@ -4904,12 +4911,7 @@ static void bnxt_free_l2_filters(struct bnxt *bp, bool all) hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST)) continue; - hlist_del(&fltr->base.hash); - if (fltr->base.flags) { - clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); - bp->ntp_fltr_count--; - } - kfree(fltr); + bnxt_del_fltr(bp, &fltr->base); } } } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 16f18c70c7bb..d070e3ac9739 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1365,6 +1365,7 @@ extern const struct bnxt_flow_masks BNXT_FLOW_IPV6_MASK_ALL; extern const struct bnxt_flow_masks BNXT_FLOW_IPV4_MASK_ALL; struct bnxt_ntuple_filter { + /* base filter must be the first member */ struct bnxt_filter_base base; struct flow_keys fkeys; struct bnxt_flow_masks fmasks; @@ -1395,6 +1396,7 @@ struct bnxt_ipv6_tuple { #define BNXT_L2_KEY_SIZE (sizeof(struct bnxt_l2_key) / 4) struct bnxt_l2_filter { + /* base filter must be the first member */ struct bnxt_filter_base base; struct bnxt_l2_key l2_key; atomic_t refcnt; From 8336a974f37df3c5512f11c88fc96e122f1f7482 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Mon, 5 Feb 2024 14:31:57 -0800 Subject: [PATCH 1020/2255] bnxt_en: Save user configured filters in a lookup list Driver needs to maintain a lookup list of all the user configured filters. This is required in order to reconfigure these filters upon interface toggle. We can look up this list to follow the order with which they should be re-applied. Reviewed-by: Andy Gospodarek Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-9-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 23 +++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 5 +++++ 2 files changed, 28 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9fb9c5f4ecbd..a93c35350b4d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4841,9 +4841,26 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) } } +void bnxt_insert_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr) +{ + u8 type = fltr->type, flags = fltr->flags; + + INIT_LIST_HEAD(&fltr->list); + if ((type == BNXT_FLTR_TYPE_L2 && flags & BNXT_ACT_RING_DST) || + (type == BNXT_FLTR_TYPE_NTUPLE && flags & BNXT_ACT_NO_AGING)) + list_add_tail(&fltr->list, &bp->usr_fltr_list); +} + +void bnxt_del_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr) +{ + if (!list_empty(&fltr->list)) + list_del_init(&fltr->list); +} + static void bnxt_del_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr) { hlist_del(&fltr->hash); + bnxt_del_one_usr_fltr(bp, fltr); if (fltr->flags) { clear_bit(fltr->sw_id, bp->ntp_fltr_bmap); bp->ntp_fltr_count--; @@ -5387,6 +5404,7 @@ void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr) return; } hlist_del_rcu(&fltr->base.hash); + bnxt_del_one_usr_fltr(bp, &fltr->base); if (fltr->base.flags) { clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); bp->ntp_fltr_count--; @@ -5533,6 +5551,7 @@ static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr, } head = &bp->l2_fltr_hash_tbl[idx]; hlist_add_head_rcu(&fltr->base.hash, head); + bnxt_insert_usr_fltr(bp, &fltr->base); set_bit(BNXT_FLTR_INSERTED, &fltr->base.state); atomic_set(&fltr->refcnt, 1); return 0; @@ -13985,6 +14004,7 @@ int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, head = &bp->ntp_fltr_hash_tbl[idx]; hlist_add_head_rcu(&fltr->base.hash, head); set_bit(BNXT_FLTR_INSERTED, &fltr->base.state); + bnxt_insert_usr_fltr(bp, &fltr->base); bp->ntp_fltr_count++; spin_unlock_bh(&bp->ntp_fltr_lock); return 0; @@ -14139,6 +14159,7 @@ void bnxt_del_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr) return; } hlist_del_rcu(&fltr->base.hash); + bnxt_del_one_usr_fltr(bp, &fltr->base); bp->ntp_fltr_count--; spin_unlock_bh(&bp->ntp_fltr_lock); bnxt_del_l2_filter(bp, fltr->l2_fltr); @@ -14955,6 +14976,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err_dl; + INIT_LIST_HEAD(&bp->usr_fltr_list); + rc = register_netdev(dev); if (rc) goto init_err_cleanup; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index d070e3ac9739..a6b6db1546cc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1334,6 +1334,7 @@ struct bnxt_pf_info { struct bnxt_filter_base { struct hlist_node hash; + struct list_head list; __le64 filter_id; u8 type; #define BNXT_FLTR_TYPE_NTUPLE 1 @@ -2442,6 +2443,8 @@ struct bnxt { u32 hash_seed; u64 toeplitz_prefix; + struct list_head usr_fltr_list; + /* To protect link related settings during link changes and * ethtool settings changes. */ @@ -2646,6 +2649,8 @@ u32 bnxt_fw_health_readl(struct bnxt *bp, int reg_idx); void bnxt_set_tpa_flags(struct bnxt *bp); void bnxt_set_ring_params(struct bnxt *); int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode); +void bnxt_insert_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr); +void bnxt_del_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr); int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size, bool async_only); int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp); From 25041467d0934f7a458a7efc59697c38d9525a40 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Mon, 5 Feb 2024 14:31:58 -0800 Subject: [PATCH 1021/2255] bnxt_en: Retain user configured filters when closing Driver should not free user created filters from its memory when closing since we are going to reconfigure them when we open again. If the "all" parameter is false, do not free user configured filters in bnxt_free_ntp_fltrs() and bnxt_free_l2_filters(). Reviewed-by: Andy Gospodarek Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-10-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a93c35350b4d..ff8d2a6d860c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4883,7 +4883,8 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) head = &bp->ntp_fltr_hash_tbl[i]; hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { bnxt_del_l2_filter(bp, fltr->l2_fltr); - if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST)) + if (!all && ((fltr->base.flags & BNXT_ACT_FUNC_DST) || + !list_empty(&fltr->base.list))) continue; bnxt_del_fltr(bp, &fltr->base); } @@ -4926,7 +4927,8 @@ static void bnxt_free_l2_filters(struct bnxt *bp, bool all) head = &bp->l2_fltr_hash_tbl[i]; hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { - if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST)) + if (!all && ((fltr->base.flags & BNXT_ACT_FUNC_DST) || + !list_empty(&fltr->base.list))) continue; bnxt_del_fltr(bp, &fltr->base); } @@ -5851,7 +5853,8 @@ static void bnxt_hwrm_clear_vnic_filter(struct bnxt *bp) struct bnxt_l2_filter *fltr = vnic->l2_filters[j]; bnxt_hwrm_l2_filter_free(bp, fltr); - bnxt_del_l2_filter(bp, fltr); + if (list_empty(&fltr->base.list)) + bnxt_del_l2_filter(bp, fltr); } vnic->uc_filter_count = 0; } From 44af4b622a3d0a7c509f77ccb0689d3ca18da5cc Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Mon, 5 Feb 2024 14:31:59 -0800 Subject: [PATCH 1022/2255] bnxt_en: Restore all the user created L2 and ntuple filters Walk the usr_fltr_list and call firmware to add these filters when we open the NIC. This will restore all user created filters after reset. Reviewed-by: Andy Gospodarek Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-11-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 40 +++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index ff8d2a6d860c..d6fd37347f5a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5853,8 +5853,7 @@ static void bnxt_hwrm_clear_vnic_filter(struct bnxt *bp) struct bnxt_l2_filter *fltr = vnic->l2_filters[j]; bnxt_hwrm_l2_filter_free(bp, fltr); - if (list_empty(&fltr->base.list)) - bnxt_del_l2_filter(bp, fltr); + bnxt_del_l2_filter(bp, fltr); } vnic->uc_filter_count = 0; } @@ -11538,6 +11537,42 @@ static int bnxt_reinit_after_abort(struct bnxt *bp) return rc; } +static void bnxt_cfg_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr) +{ + struct bnxt_ntuple_filter *ntp_fltr; + struct bnxt_l2_filter *l2_fltr; + + if (list_empty(&fltr->list)) + return; + + if (fltr->type == BNXT_FLTR_TYPE_NTUPLE) { + ntp_fltr = container_of(fltr, struct bnxt_ntuple_filter, base); + l2_fltr = bp->vnic_info[0].l2_filters[0]; + atomic_inc(&l2_fltr->refcnt); + ntp_fltr->l2_fltr = l2_fltr; + if (bnxt_hwrm_cfa_ntuple_filter_alloc(bp, ntp_fltr)) { + bnxt_del_ntp_filter(bp, ntp_fltr); + netdev_err(bp->dev, "restoring previously configured ntuple filter id %d failed\n", + fltr->sw_id); + } + } else if (fltr->type == BNXT_FLTR_TYPE_L2) { + l2_fltr = container_of(fltr, struct bnxt_l2_filter, base); + if (bnxt_hwrm_l2_filter_alloc(bp, l2_fltr)) { + bnxt_del_l2_filter(bp, l2_fltr); + netdev_err(bp->dev, "restoring previously configured l2 filter id %d failed\n", + fltr->sw_id); + } + } +} + +static void bnxt_cfg_usr_fltrs(struct bnxt *bp) +{ + struct bnxt_filter_base *usr_fltr, *tmp; + + list_for_each_entry_safe(usr_fltr, tmp, &bp->usr_fltr_list, list) + bnxt_cfg_one_usr_fltr(bp, usr_fltr); +} + static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) { int rc = 0; @@ -11624,6 +11659,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) bnxt_vf_reps_open(bp); bnxt_ptp_init_rtc(bp, true); bnxt_ptp_cfg_tstamp_filters(bp); + bnxt_cfg_usr_fltrs(bp); return 0; open_err_irq: From 5de1fce3369564ca6b9eed339838c51ec6290270 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Mon, 5 Feb 2024 14:32:00 -0800 Subject: [PATCH 1023/2255] bnxt_en: Add support for user configured RSS key Store the user configured or generated Toeplitz key in bp->rss_hash_key. The key stays constant across ifdown/ifup unless updated by the user. Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-12-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 18 ++++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 ++++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 6 ++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d6fd37347f5a..b66002171e36 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4246,9 +4246,23 @@ static void bnxt_init_vnics(struct bnxt *bp) u8 *key = (void *)vnic->rss_hash_key; int k; + if (!bp->rss_hash_key_valid && + !bp->rss_hash_key_updated) { + get_random_bytes(bp->rss_hash_key, + HW_HASH_KEY_SIZE); + bp->rss_hash_key_updated = true; + } + + memcpy(vnic->rss_hash_key, bp->rss_hash_key, + HW_HASH_KEY_SIZE); + + if (!bp->rss_hash_key_updated) + continue; + + bp->rss_hash_key_updated = false; + bp->rss_hash_key_valid = true; + bp->toeplitz_prefix = 0; - get_random_bytes(vnic->rss_hash_key, - HW_HASH_KEY_SIZE); for (k = 0; k < 8; k++) { bp->toeplitz_prefix <<= 8; bp->toeplitz_prefix |= key[k]; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index a6b6db1546cc..28091889615b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2222,6 +2222,10 @@ struct bnxt { #define BNXT_RSS_CAP_NEW_RSS_CAP BIT(2) #define BNXT_RSS_CAP_RSS_TCAM BIT(3) + u8 rss_hash_key[HW_HASH_KEY_SIZE]; + u8 rss_hash_key_valid:1; + u8 rss_hash_key_updated:1; + u16 max_mtu; u8 max_tc; u8 max_lltc; /* lossless TCs */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 57fef0fc21d8..af6e5ab54284 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1755,8 +1755,10 @@ static int bnxt_set_rxfh(struct net_device *dev, if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; - if (rxfh->key) - return -EOPNOTSUPP; + if (rxfh->key) { + memcpy(bp->rss_hash_key, rxfh->key, HW_HASH_KEY_SIZE); + bp->rss_hash_key_updated = true; + } if (rxfh->indir) { u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); From 1018319f949ced15a66364bddf1fab08ed54817f Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Mon, 5 Feb 2024 14:32:01 -0800 Subject: [PATCH 1024/2255] bnxt_en: Invalidate user filters when needed The cached user filters slated to be reapplied need to be cleared if configured MAC changes, RSS key changes, number of rings changes, or ntuple is disabled. Reviewed-by: Andy Gospodarek Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-13-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 ++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b66002171e36..dfadf5d3ea18 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4871,6 +4871,17 @@ void bnxt_del_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr) list_del_init(&fltr->list); } +void bnxt_clear_usr_fltrs(struct bnxt *bp, bool all) +{ + struct bnxt_filter_base *usr_fltr, *tmp; + + list_for_each_entry_safe(usr_fltr, tmp, &bp->usr_fltr_list, list) { + if (!all && usr_fltr->type == BNXT_FLTR_TYPE_L2) + continue; + bnxt_del_one_usr_fltr(bp, usr_fltr); + } +} + static void bnxt_del_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr) { hlist_del(&fltr->hash); @@ -12415,6 +12426,8 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features) if (features & NETIF_F_NTUPLE) flags |= BNXT_FLAG_RFS; + else + bnxt_clear_usr_fltrs(bp, true); changes = flags ^ bp->flags; if (changes & BNXT_FLAG_TPA) { @@ -13912,6 +13925,7 @@ static int bnxt_change_mac_addr(struct net_device *dev, void *p) return rc; eth_hw_addr_set(dev, addr->sa_data); + bnxt_clear_usr_fltrs(bp, true); if (netif_running(dev)) { bnxt_close_nic(bp, false, false); rc = bnxt_open_nic(bp, false, false); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 28091889615b..2b2f051ee085 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2655,6 +2655,7 @@ void bnxt_set_ring_params(struct bnxt *); int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode); void bnxt_insert_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr); void bnxt_del_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr); +void bnxt_clear_usr_fltrs(struct bnxt *bp, bool all); int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size, bool async_only); int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index af6e5ab54284..a8c6d5dd057c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -968,6 +968,7 @@ static int bnxt_set_channels(struct net_device *dev, return -EINVAL; } + bnxt_clear_usr_fltrs(bp, true); if (netif_running(dev)) { if (BNXT_PF(bp)) { /* TODO CHIMP_FW: Send message to all VF's @@ -1769,7 +1770,7 @@ static int bnxt_set_rxfh(struct net_device *dev, if (pad) memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); } - + bnxt_clear_usr_fltrs(bp, false); if (netif_running(bp->dev)) { bnxt_close_nic(bp, false, false); rc = bnxt_open_nic(bp, false, false); From 0c36211bac9b03de2e010597303b930211068caa Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Mon, 5 Feb 2024 14:32:02 -0800 Subject: [PATCH 1025/2255] bnxt_en: Add RSS support for IPSEC headers IPSec uses two distinct protocols, Authentication Header (AH) and Encapsulating Security Payload (ESP). Add support to configure RSS based on AH and ESP headers. This functionality will be enabled based on the capabilities indicated by the firmware in HWRM_VNIC_QCAPS. Signed-off-by: Ajit Khaparde Signed-off-by: Michael Chan Link: https://lore.kernel.org/r/20240205223202.25341-14-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 15 ++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 34 +++++++++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index dfadf5d3ea18..6f415425dc14 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6099,10 +6099,13 @@ static void __bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req, struct bnxt_vnic_info *vnic) { - if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { bnxt_fill_hw_rss_tbl_p5(bp, vnic); - else + if (bp->flags & BNXT_FLAG_CHIP_P7) + req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT; + } else { bnxt_fill_hw_rss_tbl(bp, vnic); + } if (bp->rss_hash_delta) { req->hash_type = cpu_to_le32(bp->rss_hash_delta); @@ -6465,6 +6468,14 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) } if (flags & VNIC_QCAPS_RESP_FLAGS_HW_TUNNEL_TPA_CAP) bp->fw_cap |= BNXT_FW_CAP_VNIC_TUNNEL_TPA; + if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV4_CAP) + bp->rss_cap |= BNXT_RSS_CAP_AH_V4_RSS_CAP; + if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV6_CAP) + bp->rss_cap |= BNXT_RSS_CAP_AH_V6_RSS_CAP; + if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV4_CAP) + bp->rss_cap |= BNXT_RSS_CAP_ESP_V4_RSS_CAP; + if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP) + bp->rss_cap |= BNXT_RSS_CAP_ESP_V6_RSS_CAP; } hwrm_req_drop(bp, req); return rc; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 2b2f051ee085..60bdd0673ec8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2221,6 +2221,10 @@ struct bnxt { #define BNXT_RSS_CAP_UDP_RSS_CAP BIT(1) #define BNXT_RSS_CAP_NEW_RSS_CAP BIT(2) #define BNXT_RSS_CAP_RSS_TCAM BIT(3) +#define BNXT_RSS_CAP_AH_V4_RSS_CAP BIT(4) +#define BNXT_RSS_CAP_AH_V6_RSS_CAP BIT(5) +#define BNXT_RSS_CAP_ESP_V4_RSS_CAP BIT(6) +#define BNXT_RSS_CAP_ESP_V6_RSS_CAP BIT(7) u8 rss_hash_key[HW_HASH_KEY_SIZE]; u8 rss_hash_key_valid:1; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index a8c6d5dd057c..dfb5944683f8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1533,8 +1533,14 @@ static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) cmd->data |= RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3; fallthrough; - case SCTP_V4_FLOW: case AH_ESP_V4_FLOW: + if (bp->rss_hash_cfg & + (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 | + VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4)) + cmd->data |= RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + fallthrough; + case SCTP_V4_FLOW: case AH_V4_FLOW: case ESP_V4_FLOW: case IPV4_FLOW: @@ -1552,8 +1558,14 @@ static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) cmd->data |= RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3; fallthrough; - case SCTP_V6_FLOW: case AH_ESP_V6_FLOW: + if (bp->rss_hash_cfg & + (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 | + VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6)) + cmd->data |= RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + fallthrough; + case SCTP_V6_FLOW: case AH_V6_FLOW: case ESP_V6_FLOW: case IPV6_FLOW: @@ -1600,6 +1612,24 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; if (tuple == 4) rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; + } else if (cmd->flow_type == AH_ESP_V4_FLOW) { + if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V4_RSS_CAP) || + !(bp->rss_cap & BNXT_RSS_CAP_ESP_V4_RSS_CAP))) + return -EINVAL; + rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 | + VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4); + if (tuple == 4) + rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 | + VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4; + } else if (cmd->flow_type == AH_ESP_V6_FLOW) { + if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V6_RSS_CAP) || + !(bp->rss_cap & BNXT_RSS_CAP_ESP_V6_RSS_CAP))) + return -EINVAL; + rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 | + VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6); + if (tuple == 4) + rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 | + VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6; } else if (tuple == 4) { return -EINVAL; } From 876e32473d1dd61cb58ece9965c3b3ea3ab307ab Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 7 Feb 2024 10:42:45 +0100 Subject: [PATCH 1026/2255] selftests: net: include forwarding lib The altnames test uses the forwarding/lib.sh and that dependency currently causes failures when running the test after install: make -C tools/testing/selftests/ TARGETS=net install ./tools/testing/selftests/kselftest_install/run_kselftest.sh \ -t net:altnames.sh # ... # ./altnames.sh: line 8: ./forwarding/lib.sh: No such file or directory # RTNETLINK answers: Operation not permitted # ./altnames.sh: line 73: tests_run: command not found # ./altnames.sh: line 65: pre_cleanup: command not found Address the issue leveraging the TEST_INCLUDES infrastructure provided by commit 2a0683be5b4c ("selftests: Introduce Makefile variable to list shared bash scripts") Signed-off-by: Paolo Abeni Link: https://lore.kernel.org/r/f7b1e9d468224cbc136d304362315499fe39848f.1707298927.git.pabeni@redhat.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 211753756bde..7b6918d5f4af 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -97,6 +97,8 @@ TEST_PROGS += vlan_hw_filter.sh TEST_FILES := settings TEST_FILES += in_netns.sh lib.sh net_helper.sh setup_loopback.sh setup_veth.sh +TEST_INCLUDES := forwarding/lib.sh + include ../lib.mk $(OUTPUT)/reuseport_bpf_numa: LDLIBS += -lnuma From 4c49b6824a607af4760fac4f5c0b9954ab902cef Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Feb 2024 08:16:40 +0100 Subject: [PATCH 1027/2255] r8169: improve checking for valid LED modes After 3a2746320403 ("leds: trigger: netdev: Display only supported link speed attribute") the check for valid link modes can be simplified. In addition factor it out, so that it can be re-used by the upcoming LED support for RTL8125. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/8876a9f4-7a2d-48c3-8eae-0d834f5c27c5@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_leds.c | 38 ++++++++++++----------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_leds.c b/drivers/net/ethernet/realtek/r8169_leds.c index f082bd7d6194..78078eca3c43 100644 --- a/drivers/net/ethernet/realtek/r8169_leds.c +++ b/drivers/net/ethernet/realtek/r8169_leds.c @@ -20,11 +20,6 @@ #define RTL8168_NUM_LEDS 3 -#define RTL8168_SUPPORTED_MODES \ - (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \ - BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \ - BIT(TRIGGER_NETDEV_TX)) - struct r8169_led_classdev { struct led_classdev led; struct net_device *ndev; @@ -33,28 +28,35 @@ struct r8169_led_classdev { #define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) +static bool r8169_trigger_mode_is_valid(unsigned long flags) +{ + bool rx, tx; + + if (flags & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) + return false; + if (flags & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) + return false; + + rx = flags & BIT(TRIGGER_NETDEV_RX); + tx = flags & BIT(TRIGGER_NETDEV_TX); + + return rx == tx; +} + static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, unsigned long flags) { struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); struct rtl8169_private *tp = netdev_priv(ldev->ndev); int shift = ldev->index * 4; - bool rx, tx; - if (flags & ~RTL8168_SUPPORTED_MODES) - goto nosupp; - - rx = flags & BIT(TRIGGER_NETDEV_RX); - tx = flags & BIT(TRIGGER_NETDEV_TX); - if (rx != tx) - goto nosupp; + if (!r8169_trigger_mode_is_valid(flags)) { + /* Switch LED off to indicate that mode isn't supported */ + rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); + return -EOPNOTSUPP; + } return 0; - -nosupp: - /* Switch LED off to indicate that mode isn't supported */ - rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); - return -EOPNOTSUPP; } static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, From 1c96a63af5c4fcb0e900e036bccf83c2763e036b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Feb 2024 17:35:28 +0100 Subject: [PATCH 1028/2255] bnx2x: convert EEE handling to use linkmode bitmaps Convert EEE handling to use linkmode bitmaps. This prepares for removing the legacy bitmaps from struct ethtool_keee. No functional change intended. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/948562fb-c5d8-4912-8b88-bec56238732a@gmail.com Signed-off-by: Jakub Kicinski --- .../ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 5f0e1759d078..58956ed8f531 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -2081,28 +2081,25 @@ static const char bnx2x_private_arr[BNX2X_PRI_FLAG_LEN][ETH_GSTRING_LEN] = { "Storage only interface" }; -static u32 bnx2x_eee_to_adv(u32 eee_adv) +static void bnx2x_eee_to_linkmode(unsigned long *mode, u32 eee_adv) { - u32 modes = 0; - if (eee_adv & SHMEM_EEE_100M_ADV) - modes |= ADVERTISED_100baseT_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mode); if (eee_adv & SHMEM_EEE_1G_ADV) - modes |= ADVERTISED_1000baseT_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mode); if (eee_adv & SHMEM_EEE_10G_ADV) - modes |= ADVERTISED_10000baseT_Full; - - return modes; + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, mode); } -static u32 bnx2x_adv_to_eee(u32 modes, u32 shift) +static u32 bnx2x_linkmode_to_eee(const unsigned long *mode, u32 shift) { u32 eee_adv = 0; - if (modes & ADVERTISED_100baseT_Full) + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mode)) eee_adv |= SHMEM_EEE_100M_ADV; - if (modes & ADVERTISED_1000baseT_Full) + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mode)) eee_adv |= SHMEM_EEE_1G_ADV; - if (modes & ADVERTISED_10000baseT_Full) + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, mode)) eee_adv |= SHMEM_EEE_10G_ADV; return eee_adv << shift; @@ -2120,16 +2117,17 @@ static int bnx2x_get_eee(struct net_device *dev, struct ethtool_keee *edata) eee_cfg = bp->link_vars.eee_status; - edata->supported_u32 = - bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_SUPPORTED_MASK) >> - SHMEM_EEE_SUPPORTED_SHIFT); + bnx2x_eee_to_linkmode(edata->supported, + (eee_cfg & SHMEM_EEE_SUPPORTED_MASK) >> + SHMEM_EEE_SUPPORTED_SHIFT); - edata->advertised_u32 = - bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_ADV_STATUS_MASK) >> - SHMEM_EEE_ADV_STATUS_SHIFT); - edata->lp_advertised_u32 = - bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_LP_ADV_STATUS_MASK) >> - SHMEM_EEE_LP_ADV_STATUS_SHIFT); + bnx2x_eee_to_linkmode(edata->advertised, + (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK) >> + SHMEM_EEE_ADV_STATUS_SHIFT); + + bnx2x_eee_to_linkmode(edata->lp_advertised, + (eee_cfg & SHMEM_EEE_LP_ADV_STATUS_MASK) >> + SHMEM_EEE_LP_ADV_STATUS_SHIFT); /* SHMEM value is in 16u units --> Convert to 1u units. */ edata->tx_lpi_timer = (eee_cfg & SHMEM_EEE_TIMER_MASK) << 4; @@ -2162,8 +2160,8 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_keee *edata) return -EOPNOTSUPP; } - advertised = bnx2x_adv_to_eee(edata->advertised_u32, - SHMEM_EEE_ADV_STATUS_SHIFT); + advertised = bnx2x_linkmode_to_eee(edata->advertised, + SHMEM_EEE_ADV_STATUS_SHIFT); if ((advertised != (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK))) { DP(BNX2X_MSG_ETHTOOL, "Direct manipulation of EEE advertisement is not supported\n"); From 32b803334f0b0abc07be72d257a6b04c6b9aaced Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Feb 2024 17:41:19 +0100 Subject: [PATCH 1029/2255] net: atlantic: convert EEE handling to use linkmode bitmaps Convert EEE handling to use linkmode bitmaps. This prepares for removing the legacy bitmaps from struct ethtool_keee. No functional change intended. Reviewed-by: Andrew Lunn Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/c5a61d57-d2b0-427f-93b3-fcf7721165f3@gmail.com Signed-off-by: Jakub Kicinski --- .../ethernet/aquantia/atlantic/aq_ethtool.c | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 0bd1a0a1ae6a..a2606ee3b0a5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -15,6 +15,7 @@ #include "aq_macsec.h" #include "aq_main.h" +#include #include static void aq_ethtool_get_regs(struct net_device *ndev, @@ -681,20 +682,16 @@ static int aq_ethtool_get_ts_info(struct net_device *ndev, return 0; } -static u32 eee_mask_to_ethtool_mask(u32 speed) +static void eee_mask_to_ethtool_mask(unsigned long *mode, u32 speed) { - u32 rate = 0; - if (speed & AQ_NIC_RATE_EEE_10G) - rate |= SUPPORTED_10000baseT_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, mode); if (speed & AQ_NIC_RATE_EEE_1G) - rate |= SUPPORTED_1000baseT_Full; + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mode); if (speed & AQ_NIC_RATE_EEE_100M) - rate |= SUPPORTED_100baseT_Full; - - return rate; + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mode); } static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_keee *eee) @@ -713,14 +710,14 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_keee *eee) if (err < 0) return err; - eee->supported_u32 = eee_mask_to_ethtool_mask(supported_rates); + eee_mask_to_ethtool_mask(eee->supported, supported_rates); if (aq_nic->aq_nic_cfg.eee_speeds) - eee->advertised_u32 = eee->supported_u32; + linkmode_copy(eee->advertised, eee->supported); - eee->lp_advertised_u32 = eee_mask_to_ethtool_mask(rate); + eee_mask_to_ethtool_mask(eee->lp_advertised, rate); - eee->eee_enabled = !!eee->advertised_u32; + eee->eee_enabled = !linkmode_empty(eee->advertised); eee->tx_lpi_enabled = eee->eee_enabled; if ((supported_rates & rate) & AQ_NIC_RATE_EEE_MSK) From d45f5fa8b4aeaf24d2d5911cb459aeb74bada52c Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 7 Feb 2024 21:35:22 +0100 Subject: [PATCH 1030/2255] selftests: udpgso: Pull up network setup into shell script udpgso regression test configures routing and device MTU directly through uAPI (Netlink, ioctl) to do its job. While there is nothing wrong with it, it takes more effort than doing it from shell. Looking forward, we would like to extend the udpgso regression tests to cover the EIO corner case [1], once it gets addressed. That will require a dummy device and device feature manipulation to set it up. Which means more Netlink code. So, in preparation, pull out network configuration into the shell script part of the test, so it is easily extendable in the future. Also, because it now easy to setup routing, add a second local IPv6 address. Because the second address is not managed by the kernel, we can "replace" the corresponding local route with a reduced-MTU one. This unblocks the disabled "ipv6 connected" test case. Add a similar setup for IPv4 for symmetry. [1] https://lore.kernel.org/netdev/87jzqsld6q.fsf@cloudflare.com/ Reviewed-by: Willem de Bruijn Signed-off-by: Jakub Sitnicki Link: https://lore.kernel.org/r/20240207-jakub-krn-635-v3-1-3dfa3da8a7d3@cloudflare.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/udpgso.c | 134 ++------------------------ tools/testing/selftests/net/udpgso.sh | 49 ++++++++-- 2 files changed, 47 insertions(+), 136 deletions(-) diff --git a/tools/testing/selftests/net/udpgso.c b/tools/testing/selftests/net/udpgso.c index 7badaf215de2..1d975bf52af3 100644 --- a/tools/testing/selftests/net/udpgso.c +++ b/tools/testing/selftests/net/udpgso.c @@ -56,7 +56,6 @@ static bool cfg_do_msgmore; static bool cfg_do_setsockopt; static int cfg_specific_test_id = -1; -static const char cfg_ifname[] = "lo"; static unsigned short cfg_port = 9000; static char buf[ETH_MAX_MTU]; @@ -69,8 +68,13 @@ struct testcase { int r_len_last; /* recv(): size of last non-mss dgram, if any */ }; -const struct in6_addr addr6 = IN6ADDR_LOOPBACK_INIT; -const struct in_addr addr4 = { .s_addr = __constant_htonl(INADDR_LOOPBACK + 2) }; +const struct in6_addr addr6 = { + { { 0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } }, /* fd00::1 */ +}; + +const struct in_addr addr4 = { + __constant_htonl(0x0a000001), /* 10.0.0.1 */ +}; struct testcase testcases_v4[] = { { @@ -274,48 +278,6 @@ struct testcase testcases_v6[] = { } }; -static unsigned int get_device_mtu(int fd, const char *ifname) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - - strcpy(ifr.ifr_name, ifname); - - if (ioctl(fd, SIOCGIFMTU, &ifr)) - error(1, errno, "ioctl get mtu"); - - return ifr.ifr_mtu; -} - -static void __set_device_mtu(int fd, const char *ifname, unsigned int mtu) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - - ifr.ifr_mtu = mtu; - strcpy(ifr.ifr_name, ifname); - - if (ioctl(fd, SIOCSIFMTU, &ifr)) - error(1, errno, "ioctl set mtu"); -} - -static void set_device_mtu(int fd, int mtu) -{ - int val; - - val = get_device_mtu(fd, cfg_ifname); - fprintf(stderr, "device mtu (orig): %u\n", val); - - __set_device_mtu(fd, cfg_ifname, mtu); - val = get_device_mtu(fd, cfg_ifname); - if (val != mtu) - error(1, 0, "unable to set device mtu to %u\n", val); - - fprintf(stderr, "device mtu (test): %u\n", val); -} - static void set_pmtu_discover(int fd, bool is_ipv4) { int level, name, val; @@ -354,81 +316,6 @@ static unsigned int get_path_mtu(int fd, bool is_ipv4) return mtu; } -/* very wordy version of system("ip route add dev lo mtu 1500 127.0.0.3/32") */ -static void set_route_mtu(int mtu, bool is_ipv4) -{ - struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; - struct nlmsghdr *nh; - struct rtattr *rta; - struct rtmsg *rt; - char data[NLMSG_ALIGN(sizeof(*nh)) + - NLMSG_ALIGN(sizeof(*rt)) + - NLMSG_ALIGN(RTA_LENGTH(sizeof(addr6))) + - NLMSG_ALIGN(RTA_LENGTH(sizeof(int))) + - NLMSG_ALIGN(RTA_LENGTH(0) + RTA_LENGTH(sizeof(int)))]; - int fd, ret, alen, off = 0; - - alen = is_ipv4 ? sizeof(addr4) : sizeof(addr6); - - fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) - error(1, errno, "socket netlink"); - - memset(data, 0, sizeof(data)); - - nh = (void *)data; - nh->nlmsg_type = RTM_NEWROUTE; - nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; - off += NLMSG_ALIGN(sizeof(*nh)); - - rt = (void *)(data + off); - rt->rtm_family = is_ipv4 ? AF_INET : AF_INET6; - rt->rtm_table = RT_TABLE_MAIN; - rt->rtm_dst_len = alen << 3; - rt->rtm_protocol = RTPROT_BOOT; - rt->rtm_scope = RT_SCOPE_UNIVERSE; - rt->rtm_type = RTN_UNICAST; - off += NLMSG_ALIGN(sizeof(*rt)); - - rta = (void *)(data + off); - rta->rta_type = RTA_DST; - rta->rta_len = RTA_LENGTH(alen); - if (is_ipv4) - memcpy(RTA_DATA(rta), &addr4, alen); - else - memcpy(RTA_DATA(rta), &addr6, alen); - off += NLMSG_ALIGN(rta->rta_len); - - rta = (void *)(data + off); - rta->rta_type = RTA_OIF; - rta->rta_len = RTA_LENGTH(sizeof(int)); - *((int *)(RTA_DATA(rta))) = 1; //if_nametoindex("lo"); - off += NLMSG_ALIGN(rta->rta_len); - - /* MTU is a subtype in a metrics type */ - rta = (void *)(data + off); - rta->rta_type = RTA_METRICS; - rta->rta_len = RTA_LENGTH(0) + RTA_LENGTH(sizeof(int)); - off += NLMSG_ALIGN(rta->rta_len); - - /* now fill MTU subtype. Note that it fits within above rta_len */ - rta = (void *)(((char *) rta) + RTA_LENGTH(0)); - rta->rta_type = RTAX_MTU; - rta->rta_len = RTA_LENGTH(sizeof(int)); - *((int *)(RTA_DATA(rta))) = mtu; - - nh->nlmsg_len = off; - - ret = sendto(fd, data, off, 0, (void *)&nladdr, sizeof(nladdr)); - if (ret != off) - error(1, errno, "send netlink: %uB != %uB\n", ret, off); - - if (close(fd)) - error(1, errno, "close netlink"); - - fprintf(stderr, "route mtu (test): %u\n", mtu); -} - static bool __send_one(int fd, struct msghdr *msg, int flags) { int ret; @@ -591,15 +478,10 @@ static void run_test(struct sockaddr *addr, socklen_t alen) /* Do not fragment these datagrams: only succeed if GSO works */ set_pmtu_discover(fdt, addr->sa_family == AF_INET); - if (cfg_do_connectionless) { - set_device_mtu(fdt, CONST_MTU_TEST); + if (cfg_do_connectionless) run_all(fdt, fdr, addr, alen); - } if (cfg_do_connected) { - set_device_mtu(fdt, CONST_MTU_TEST + 100); - set_route_mtu(CONST_MTU_TEST, addr->sa_family == AF_INET); - if (connect(fdt, addr, alen)) error(1, errno, "connect"); diff --git a/tools/testing/selftests/net/udpgso.sh b/tools/testing/selftests/net/udpgso.sh index fec24f584fe9..6c63178086b0 100755 --- a/tools/testing/selftests/net/udpgso.sh +++ b/tools/testing/selftests/net/udpgso.sh @@ -3,27 +3,56 @@ # # Run a series of udpgso regression tests +set -o errexit +set -o nounset + +setup_loopback() { + ip addr add dev lo 10.0.0.1/32 + ip addr add dev lo fd00::1/128 nodad noprefixroute +} + +test_dev_mtu() { + setup_loopback + # Reduce loopback MTU + ip link set dev lo mtu 1500 +} + +test_route_mtu() { + setup_loopback + # Remove default local routes + ip route del local 10.0.0.1/32 table local dev lo + ip route del local fd00::1/128 table local dev lo + # Install local routes with reduced MTU + ip route add local 10.0.0.1/32 table local dev lo mtu 1500 + ip route add local fd00::1/128 table local dev lo mtu 1500 +} + +if [ "$#" -gt 0 ]; then + "$1" + shift 2 # pop "test_*" arg and "--" delimiter + exec "$@" +fi + echo "ipv4 cmsg" -./in_netns.sh ./udpgso -4 -C +./in_netns.sh "$0" test_dev_mtu -- ./udpgso -4 -C echo "ipv4 setsockopt" -./in_netns.sh ./udpgso -4 -C -s +./in_netns.sh "$0" test_dev_mtu -- ./udpgso -4 -C -s echo "ipv6 cmsg" -./in_netns.sh ./udpgso -6 -C +./in_netns.sh "$0" test_dev_mtu -- ./udpgso -6 -C echo "ipv6 setsockopt" -./in_netns.sh ./udpgso -6 -C -s +./in_netns.sh "$0" test_dev_mtu -- ./udpgso -6 -C -s echo "ipv4 connected" -./in_netns.sh ./udpgso -4 -c +./in_netns.sh "$0" test_route_mtu -- ./udpgso -4 -c -# blocked on 2nd loopback address -# echo "ipv6 connected" -# ./in_netns.sh ./udpgso -6 -c +echo "ipv6 connected" +./in_netns.sh "$0" test_route_mtu -- ./udpgso -6 -c echo "ipv4 msg_more" -./in_netns.sh ./udpgso -4 -C -m +./in_netns.sh "$0" test_dev_mtu -- ./udpgso -4 -C -m echo "ipv6 msg_more" -./in_netns.sh ./udpgso -6 -C -m +./in_netns.sh "$0" test_dev_mtu -- ./udpgso -6 -C -m From b63cc73341e076961d564a74cc3d29b2fd444079 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 8 Feb 2024 07:59:18 +0100 Subject: [PATCH 1031/2255] net: phy: realtek: use generic MDIO helpers to simplify the code Use generic MDIO helpers to simplify the code. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/422ae70f-7305-45fd-ab3e-0dd604b9fd6c@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 962df2b83070..481c79fbd6eb 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -680,14 +680,7 @@ static int rtl822x_config_aneg(struct phy_device *phydev) int ret = 0; if (phydev->autoneg == AUTONEG_ENABLE) { - u16 adv = 0; - - if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, - phydev->advertising)) - adv |= MDIO_AN_10GBT_CTRL_ADV2_5G; - if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, - phydev->advertising)) - adv |= MDIO_AN_10GBT_CTRL_ADV5G; + u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, MDIO_AN_10GBT_CTRL_ADV2_5G | @@ -710,15 +703,8 @@ static int rtl822x_read_status(struct phy_device *phydev) if (lpadv < 0) return lpadv; - linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, - phydev->lp_advertising, - lpadv & MDIO_AN_10GBT_STAT_LP10G); - linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, - phydev->lp_advertising, - lpadv & MDIO_AN_10GBT_STAT_LP5G); - linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, - phydev->lp_advertising, - lpadv & MDIO_AN_10GBT_STAT_LP2_5G); + mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, + lpadv); } ret = genphy_read_status(phydev); From 8453c88c7a150a5ae52382b0bfda00a4b0a643ef Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:04 +0100 Subject: [PATCH 1032/2255] dt-bindings: net: document ethernet PHY package nodes Document ethernet PHY package nodes used to describe PHY shipped in bundle of 2-5 PHY. The special node describe a container of PHY that share common properties. This is a generic schema and PHY package should create specialized version with the required additional shared properties. Example are PHY packages that have some regs only in one PHY of the package and will affect every other PHY in the package, for example related to PHY interface mode calibration or global PHY mode selection. The PHY package node MUST declare the base address used by the PHY driver for global configuration by calculating the offsets of the global PHY based on the base address of the PHY package. Each reg of the PHYs defined in the PHY package node is absolute and describe the real address of the Ethernet PHY on the bus. Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- .../bindings/net/ethernet-phy-package.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/ethernet-phy-package.yaml diff --git a/Documentation/devicetree/bindings/net/ethernet-phy-package.yaml b/Documentation/devicetree/bindings/net/ethernet-phy-package.yaml new file mode 100644 index 000000000000..e567101e6f38 --- /dev/null +++ b/Documentation/devicetree/bindings/net/ethernet-phy-package.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/ethernet-phy-package.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ethernet PHY Package Common Properties + +maintainers: + - Christian Marangi + +description: + PHY packages are multi-port Ethernet PHY of the same family + and each Ethernet PHY is affected by the global configuration + of the PHY package. + + Each reg of the PHYs defined in the PHY package node is + absolute and describe the real address of the Ethernet PHY on + the MDIO bus. + +properties: + $nodename: + pattern: "^ethernet-phy-package@[a-f0-9]+$" + + reg: + minimum: 0 + maximum: 31 + description: + The base ID number for the PHY package. + Commonly the ID of the first PHY in the PHY package. + + Some PHY in the PHY package might be not defined but + still occupy ID on the device (just not attached to + anything) hence the PHY package reg might correspond + to a not attached PHY (offset 0). + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + ^ethernet-phy@[a-f0-9]+$: + $ref: ethernet-phy.yaml# + +required: + - reg + - '#address-cells' + - '#size-cells' + +additionalProperties: true From 385ef48f468696d6d172eb367656a3466fa0408d Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:05 +0100 Subject: [PATCH 1033/2255] net: phy: add support for scanning PHY in PHY packages nodes Add support for scanning PHY in PHY package nodes. PHY packages nodes are just container for actual PHY on the MDIO bus. Their PHY address defined in the PHY package node are absolute and reflect the address on the MDIO bus. mdio_bus.c and of_mdio.c is updated to now support and parse also PHY package subnode by checking if the node name match "ethernet-phy-package". As PHY package reg is mandatory and each PHY in the PHY package must have a reg, every invalid PHY Package node is ignored and will be skipped by the autoscan fallback. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/mdio/of_mdio.c | 79 +++++++++++++++++++++++++++----------- drivers/net/phy/mdio_bus.c | 44 +++++++++++++++++---- 2 files changed, 92 insertions(+), 31 deletions(-) diff --git a/drivers/net/mdio/of_mdio.c b/drivers/net/mdio/of_mdio.c index 64ebcb6d235c..08e607f62e10 100644 --- a/drivers/net/mdio/of_mdio.c +++ b/drivers/net/mdio/of_mdio.c @@ -139,6 +139,53 @@ bool of_mdiobus_child_is_phy(struct device_node *child) } EXPORT_SYMBOL(of_mdiobus_child_is_phy); +static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np, + bool *scanphys) +{ + struct device_node *child; + int addr, rc = 0; + + /* Loop over the child nodes and register a phy_device for each phy */ + for_each_available_child_of_node(np, child) { + if (of_node_name_eq(child, "ethernet-phy-package")) { + /* Ignore invalid ethernet-phy-package node */ + if (!of_property_present(child, "reg")) + continue; + + rc = __of_mdiobus_parse_phys(mdio, child, NULL); + if (rc && rc != -ENODEV) + goto exit; + + continue; + } + + addr = of_mdio_parse_addr(&mdio->dev, child); + if (addr < 0) { + /* Skip scanning for invalid ethernet-phy-package node */ + if (scanphys) + *scanphys = true; + continue; + } + + if (of_mdiobus_child_is_phy(child)) + rc = of_mdiobus_register_phy(mdio, child, addr); + else + rc = of_mdiobus_register_device(mdio, child, addr); + + if (rc == -ENODEV) + dev_err(&mdio->dev, + "MDIO device at address %d is missing.\n", + addr); + else if (rc) + goto exit; + } + + return 0; +exit: + of_node_put(child); + return rc; +} + /** * __of_mdiobus_register - Register mii_bus and create PHYs from the device tree * @mdio: pointer to mii_bus structure @@ -180,33 +227,18 @@ int __of_mdiobus_register(struct mii_bus *mdio, struct device_node *np, return rc; /* Loop over the child nodes and register a phy_device for each phy */ - for_each_available_child_of_node(np, child) { - addr = of_mdio_parse_addr(&mdio->dev, child); - if (addr < 0) { - scanphys = true; - continue; - } - - if (of_mdiobus_child_is_phy(child)) - rc = of_mdiobus_register_phy(mdio, child, addr); - else - rc = of_mdiobus_register_device(mdio, child, addr); - - if (rc == -ENODEV) - dev_err(&mdio->dev, - "MDIO device at address %d is missing.\n", - addr); - else if (rc) - goto unregister; - } + rc = __of_mdiobus_parse_phys(mdio, np, &scanphys); + if (rc) + goto unregister; if (!scanphys) return 0; /* auto scan for PHYs with empty reg property */ for_each_available_child_of_node(np, child) { - /* Skip PHYs with reg property set */ - if (of_property_present(child, "reg")) + /* Skip PHYs with reg property set or ethernet-phy-package node */ + if (of_property_present(child, "reg") || + of_node_name_eq(child, "ethernet-phy-package")) continue; for (addr = 0; addr < PHY_MAX_ADDR; addr++) { @@ -227,15 +259,16 @@ int __of_mdiobus_register(struct mii_bus *mdio, struct device_node *np, if (!rc) break; if (rc != -ENODEV) - goto unregister; + goto put_unregister; } } } return 0; -unregister: +put_unregister: of_node_put(child); +unregister: mdiobus_unregister(mdio); return rc; } diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index afbad1ad8683..08624f073014 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -459,19 +459,34 @@ EXPORT_SYMBOL(of_mdio_find_bus); * found, set the of_node pointer for the mdio device. This allows * auto-probed phy devices to be supplied with information passed in * via DT. + * If a PHY package is found, PHY is searched also there. */ -static void of_mdiobus_link_mdiodev(struct mii_bus *bus, - struct mdio_device *mdiodev) +static int of_mdiobus_find_phy(struct device *dev, struct mdio_device *mdiodev, + struct device_node *np) { - struct device *dev = &mdiodev->dev; struct device_node *child; - if (dev->of_node || !bus->dev.of_node) - return; - - for_each_available_child_of_node(bus->dev.of_node, child) { + for_each_available_child_of_node(np, child) { int addr; + if (of_node_name_eq(child, "ethernet-phy-package")) { + /* Validate PHY package reg presence */ + if (!of_property_present(child, "reg")) { + of_node_put(child); + return -EINVAL; + } + + if (!of_mdiobus_find_phy(dev, mdiodev, child)) { + /* The refcount for the PHY package will be + * incremented later when PHY join the Package. + */ + of_node_put(child); + return 0; + } + + continue; + } + addr = of_mdio_parse_addr(dev, child); if (addr < 0) continue; @@ -481,9 +496,22 @@ static void of_mdiobus_link_mdiodev(struct mii_bus *bus, /* The refcount on "child" is passed to the mdio * device. Do _not_ use of_node_put(child) here. */ - return; + return 0; } } + + return -ENODEV; +} + +static void of_mdiobus_link_mdiodev(struct mii_bus *bus, + struct mdio_device *mdiodev) +{ + struct device *dev = &mdiodev->dev; + + if (dev->of_node || !bus->dev.of_node) + return; + + of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node); } #else /* !IS_ENABLED(CONFIG_OF_MDIO) */ static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio, From 471e8fd3afcef5a9f9089f0bd21965ad9ba35c91 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:06 +0100 Subject: [PATCH 1034/2255] net: phy: add devm/of_phy_package_join helper Add devm/of_phy_package_join helper to join PHYs in a PHY package. These are variant of the manual phy_package_join with the difference that these will use DT nodes to derive the base_addr instead of manually passing an hardcoded value. An additional value is added in phy_package_shared, "np" to reference the PHY package node pointer in specific PHY driver probe_once and config_init_once functions to make use of additional specific properties defined in the PHY package node in DT. The np value is filled only with of_phy_package_join if a valid PHY package node is found. A valid PHY package node must have the node name set to "ethernet-phy-package". Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 96 ++++++++++++++++++++++++++++++++++++ include/linux/phy.h | 6 +++ 2 files changed, 102 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2e7d5bfb338e..71d48152e8d5 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1712,6 +1712,7 @@ int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size) shared->priv_size = priv_size; } shared->base_addr = base_addr; + shared->np = NULL; refcount_set(&shared->refcnt, 1); bus->shared[base_addr] = shared; } else { @@ -1734,6 +1735,63 @@ err_unlock: } EXPORT_SYMBOL_GPL(phy_package_join); +/** + * of_phy_package_join - join a common PHY group in PHY package + * @phydev: target phy_device struct + * @priv_size: if non-zero allocate this amount of bytes for private data + * + * This is a variant of phy_package_join for PHY package defined in DT. + * + * The parent node of the @phydev is checked as a valid PHY package node + * structure (by matching the node name "ethernet-phy-package") and the + * base_addr for the PHY package is passed to phy_package_join. + * + * With this configuration the shared struct will also have the np value + * filled to use additional DT defined properties in PHY specific + * probe_once and config_init_once PHY package OPs. + * + * Returns < 0 on error, 0 on success. Esp. calling phy_package_join() + * with the same cookie but a different priv_size is an error. Or a parent + * node is not detected or is not valid or doesn't match the expected node + * name for PHY package. + */ +int of_phy_package_join(struct phy_device *phydev, size_t priv_size) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct device_node *package_node; + u32 base_addr; + int ret; + + if (!node) + return -EINVAL; + + package_node = of_get_parent(node); + if (!package_node) + return -EINVAL; + + if (!of_node_name_eq(package_node, "ethernet-phy-package")) { + ret = -EINVAL; + goto exit; + } + + if (of_property_read_u32(package_node, "reg", &base_addr)) { + ret = -EINVAL; + goto exit; + } + + ret = phy_package_join(phydev, base_addr, priv_size); + if (ret) + goto exit; + + phydev->shared->np = package_node; + + return 0; +exit: + of_node_put(package_node); + return ret; +} +EXPORT_SYMBOL_GPL(of_phy_package_join); + /** * phy_package_leave - leave a common PHY group * @phydev: target phy_device struct @@ -1750,6 +1808,10 @@ void phy_package_leave(struct phy_device *phydev) if (!shared) return; + /* Decrease the node refcount on leave if present */ + if (shared->np) + of_node_put(shared->np); + if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) { bus->shared[shared->base_addr] = NULL; mutex_unlock(&bus->shared_lock); @@ -1802,6 +1864,40 @@ int devm_phy_package_join(struct device *dev, struct phy_device *phydev, } EXPORT_SYMBOL_GPL(devm_phy_package_join); +/** + * devm_of_phy_package_join - resource managed of_phy_package_join() + * @dev: device that is registering this PHY package + * @phydev: target phy_device struct + * @priv_size: if non-zero allocate this amount of bytes for private data + * + * Managed of_phy_package_join(). Shared storage fetched by this function, + * phy_package_leave() is automatically called on driver detach. See + * of_phy_package_join() for more information. + */ +int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev, + size_t priv_size) +{ + struct phy_device **ptr; + int ret; + + ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = of_phy_package_join(phydev, priv_size); + + if (!ret) { + *ptr = phydev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_of_phy_package_join); + /** * phy_detach - detach a PHY device from its network device * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index fd8dbea9b4d9..cbd49418b819 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -329,6 +329,7 @@ struct mdio_bus_stats { * struct phy_package_shared - Shared information in PHY packages * @base_addr: Base PHY address of PHY package used to combine PHYs * in one package and for offset calculation of phy_package_read/write + * @np: Pointer to the Device Node if PHY package defined in DT * @refcnt: Number of PHYs connected to this shared data * @flags: Initialization of PHY package * @priv_size: Size of the shared private data @priv @@ -340,6 +341,8 @@ struct mdio_bus_stats { */ struct phy_package_shared { u8 base_addr; + /* With PHY package defined in DT this points to the PHY package node */ + struct device_node *np; refcount_t refcnt; unsigned long flags; size_t priv_size; @@ -2000,9 +2003,12 @@ int phy_ethtool_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *cmd); int phy_ethtool_nway_reset(struct net_device *ndev); int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size); +int of_phy_package_join(struct phy_device *phydev, size_t priv_size); void phy_package_leave(struct phy_device *phydev); int devm_phy_package_join(struct device *dev, struct phy_device *phydev, int base_addr, size_t priv_size); +int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev, + size_t priv_size); int __init mdio_bus_init(void); void mdio_bus_exit(void); From 737eb75a815f9c08dcbb6631db57f4f4b0540a5b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:07 +0100 Subject: [PATCH 1035/2255] net: phy: qcom: move more function to shared library Move more function to shared library in preparation for introduction of new PHY Family qca807x that will make use of both functions from at803x and qca808x as it's a transition PHY with some implementation of at803x and some from the new qca808x. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/qcom/at803x.c | 35 ----- drivers/net/phy/qcom/qca808x.c | 205 ---------------------------- drivers/net/phy/qcom/qcom-phy-lib.c | 193 ++++++++++++++++++++++++++ drivers/net/phy/qcom/qcom.h | 51 +++++++ 4 files changed, 244 insertions(+), 240 deletions(-) diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 36b70e88394e..3e3ee4c1d4bc 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -504,41 +504,6 @@ static void at803x_link_change_notify(struct phy_device *phydev) } } -static int at803x_read_status(struct phy_device *phydev) -{ - struct at803x_ss_mask ss_mask = { 0 }; - int err, old_link = phydev->link; - - /* Update the link, but return if there was an error */ - err = genphy_update_link(phydev); - if (err) - return err; - - /* why bother the PHY if nothing can have changed */ - if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) - return 0; - - phydev->speed = SPEED_UNKNOWN; - phydev->duplex = DUPLEX_UNKNOWN; - phydev->pause = 0; - phydev->asym_pause = 0; - - err = genphy_read_lpa(phydev); - if (err < 0) - return err; - - ss_mask.speed_mask = AT803X_SS_SPEED_MASK; - ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK); - err = at803x_read_specific_status(phydev, ss_mask); - if (err < 0) - return err; - - if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) - phy_resolve_aneg_pause(phydev); - - return 0; -} - static int at803x_config_aneg(struct phy_device *phydev) { struct at803x_priv *priv = phydev->priv; diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index d88e04278fc4..8377325f157e 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -2,7 +2,6 @@ #include #include -#include #include "qcom.h" @@ -63,55 +62,6 @@ #define QCA808X_DBG_AN_TEST 0xb #define QCA808X_HIBERNATION_EN BIT(15) -#define QCA808X_CDT_ENABLE_TEST BIT(15) -#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) -#define QCA808X_CDT_STATUS BIT(11) -#define QCA808X_CDT_LENGTH_UNIT BIT(10) - -#define QCA808X_MMD3_CDT_STATUS 0x8064 -#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 -#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 -#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 -#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 -#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) -#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) - -#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) -#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) -#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) -#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) - -#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) -#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) -#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) -#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) -#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) - -#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) -#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) -#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) -#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) - -/* NORMAL are MDI with type set to 0 */ -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI1) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI1) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI2) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI2) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI3) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI3) - -/* Added for reference of existence but should be handled by wait_for_completion already */ -#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) - #define QCA808X_MMD7_LED_GLOBAL 0x8073 #define QCA808X_LED_BLINK_1 GENMASK(11, 6) #define QCA808X_LED_BLINK_2 GENMASK(5, 0) @@ -406,86 +356,6 @@ static int qca808x_soft_reset(struct phy_device *phydev) return ret; } -static bool qca808x_cdt_fault_length_valid(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: - return true; - default: - return false; - } -} - -static int qca808x_cable_test_result_trans(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_NORMAL: - return ETHTOOL_A_CABLE_RESULT_CODE_OK; - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: - return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; - case QCA808X_CDT_STATUS_STAT_FAIL: - default: - return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; - } -} - -static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, - int result) -{ - int val; - u32 cdt_length_reg = 0; - - switch (pair) { - case ETHTOOL_A_CABLE_PAIR_A: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; - break; - case ETHTOOL_A_CABLE_PAIR_B: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; - break; - case ETHTOOL_A_CABLE_PAIR_C: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; - break; - case ETHTOOL_A_CABLE_PAIR_D: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; - break; - default: - return -EINVAL; - } - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); - if (val < 0) - return val; - - if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); - else - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); - - return at803x_cdt_fault_length(val); -} - static int qca808x_cable_test_start(struct phy_device *phydev) { int ret; @@ -527,81 +397,6 @@ static int qca808x_cable_test_start(struct phy_device *phydev) return 0; } -static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, - u16 status) -{ - int length, result; - u16 pair_code; - - switch (pair) { - case ETHTOOL_A_CABLE_PAIR_A: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); - break; - case ETHTOOL_A_CABLE_PAIR_B: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); - break; - case ETHTOOL_A_CABLE_PAIR_C: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); - break; - case ETHTOOL_A_CABLE_PAIR_D: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); - break; - default: - return -EINVAL; - } - - result = qca808x_cable_test_result_trans(pair_code); - ethnl_cable_test_result(phydev, pair, result); - - if (qca808x_cdt_fault_length_valid(pair_code)) { - length = qca808x_cdt_fault_length(phydev, pair, result); - ethnl_cable_test_fault_length(phydev, pair, length); - } - - return 0; -} - -static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) -{ - int ret, val; - - *finished = false; - - val = QCA808X_CDT_ENABLE_TEST | - QCA808X_CDT_LENGTH_UNIT; - ret = at803x_cdt_start(phydev, val); - if (ret) - return ret; - - ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); - if (ret) - return ret; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); - if (val < 0) - return val; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); - if (ret) - return ret; - - *finished = true; - - return 0; -} - static int qca808x_get_features(struct phy_device *phydev) { int ret; diff --git a/drivers/net/phy/qcom/qcom-phy-lib.c b/drivers/net/phy/qcom/qcom-phy-lib.c index e0295d4b4a51..786bfc39912c 100644 --- a/drivers/net/phy/qcom/qcom-phy-lib.c +++ b/drivers/net/phy/qcom/qcom-phy-lib.c @@ -5,6 +5,7 @@ #include #include +#include #include "qcom.h" @@ -311,6 +312,42 @@ int at803x_prepare_config_aneg(struct phy_device *phydev) } EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg); +int at803x_read_status(struct phy_device *phydev) +{ + struct at803x_ss_mask ss_mask = { 0 }; + int err, old_link = phydev->link; + + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + /* why bother the PHY if nothing can have changed */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + err = genphy_read_lpa(phydev); + if (err < 0) + return err; + + ss_mask.speed_mask = AT803X_SS_SPEED_MASK; + ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK); + err = at803x_read_specific_status(phydev, ss_mask); + if (err < 0) + return err; + + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) + phy_resolve_aneg_pause(phydev); + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_read_status); + static int at803x_get_downshift(struct phy_device *phydev, u8 *d) { int val; @@ -427,3 +464,159 @@ int at803x_cdt_wait_for_completion(struct phy_device *phydev, return ret < 0 ? ret : 0; } EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion); + +static bool qca808x_cdt_fault_length_valid(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return true; + default: + return false; + } +} + +static int qca808x_cable_test_result_trans(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_NORMAL: + return ETHTOOL_A_CABLE_RESULT_CODE_OK; + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; + case QCA808X_CDT_STATUS_STAT_FAIL: + default: + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } +} + +static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, + int result) +{ + int val; + u32 cdt_length_reg = 0; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; + break; + case ETHTOOL_A_CABLE_PAIR_B: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; + break; + case ETHTOOL_A_CABLE_PAIR_C: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; + break; + case ETHTOOL_A_CABLE_PAIR_D: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; + break; + default: + return -EINVAL; + } + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); + if (val < 0) + return val; + + if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); + else + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); + + return at803x_cdt_fault_length(val); +} + +static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, + u16 status) +{ + int length, result; + u16 pair_code; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); + break; + case ETHTOOL_A_CABLE_PAIR_B: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); + break; + case ETHTOOL_A_CABLE_PAIR_C: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); + break; + case ETHTOOL_A_CABLE_PAIR_D: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); + break; + default: + return -EINVAL; + } + + result = qca808x_cable_test_result_trans(pair_code); + ethnl_cable_test_result(phydev, pair, result); + + if (qca808x_cdt_fault_length_valid(pair_code)) { + length = qca808x_cdt_fault_length(phydev, pair, result); + ethnl_cable_test_fault_length(phydev, pair, length); + } + + return 0; +} + +int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) +{ + int ret, val; + + *finished = false; + + val = QCA808X_CDT_ENABLE_TEST | + QCA808X_CDT_LENGTH_UNIT; + ret = at803x_cdt_start(phydev, val); + if (ret) + return ret; + + ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); + if (ret) + return ret; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); + if (val < 0) + return val; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); + if (ret) + return ret; + + *finished = true; + + return 0; +} +EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status); diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h index c127d8f50f0f..dc259bbf0678 100644 --- a/drivers/net/phy/qcom/qcom.h +++ b/drivers/net/phy/qcom/qcom.h @@ -54,6 +54,55 @@ #define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) #define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) +#define QCA808X_CDT_ENABLE_TEST BIT(15) +#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) +#define QCA808X_CDT_STATUS BIT(11) +#define QCA808X_CDT_LENGTH_UNIT BIT(10) + +#define QCA808X_MMD3_CDT_STATUS 0x8064 +#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 +#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 +#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 +#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 +#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) +#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) + +#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) +#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) +#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) +#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) + +#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) +#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) +#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) +#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) +#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) + +#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) +#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) +#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) +#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) + +/* NORMAL are MDI with type set to 0 */ +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI3) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI3) + +/* Added for reference of existence but should be handled by wait_for_completion already */ +#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) + #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A @@ -110,6 +159,7 @@ int at803x_read_specific_status(struct phy_device *phydev, struct at803x_ss_mask ss_mask); int at803x_config_mdix(struct phy_device *phydev, u8 ctrl); int at803x_prepare_config_aneg(struct phy_device *phydev); +int at803x_read_status(struct phy_device *phydev); int at803x_get_tunable(struct phy_device *phydev, struct ethtool_tunable *tuna, void *data); int at803x_set_tunable(struct phy_device *phydev, @@ -118,3 +168,4 @@ int at803x_cdt_fault_length(int dt); int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start); int at803x_cdt_wait_for_completion(struct phy_device *phydev, u32 cdt_en); +int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished); From dd87eaa137870bfc7aab38953384768bf1c87a3f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:08 +0100 Subject: [PATCH 1036/2255] dt-bindings: net: Document Qcom QCA807x PHY package Document Qcom QCA807x PHY package. Qualcomm QCA807X Ethernet PHY is PHY package of 2 or 5 IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and 1000BASE-T PHY-s. Document the required property to make the PHY package correctly configure and work. Signed-off-by: Christian Marangi Reviewed-by: Conor Dooley Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../devicetree/bindings/net/qcom,qca807x.yaml | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/qcom,qca807x.yaml diff --git a/Documentation/devicetree/bindings/net/qcom,qca807x.yaml b/Documentation/devicetree/bindings/net/qcom,qca807x.yaml new file mode 100644 index 000000000000..7290024024f5 --- /dev/null +++ b/Documentation/devicetree/bindings/net/qcom,qca807x.yaml @@ -0,0 +1,184 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/qcom,qca807x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QCA807x Ethernet PHY + +maintainers: + - Christian Marangi + - Robert Marko + +description: | + Qualcomm QCA8072/5 Ethernet PHY is PHY package of 2 or 5 + IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and + 1000BASE-T PHY-s. + + They feature 2 SerDes, one for PSGMII or QSGMII connection with + MAC, while second one is SGMII for connection to MAC or fiber. + + Both models have a combo port that supports 1000BASE-X and + 100BASE-FX fiber. + + Each PHY inside of QCA807x series has 4 digitally controlled + output only pins that natively drive LED-s for up to 2 attached + LEDs. Some vendor also use these 4 output for GPIO usage without + attaching LEDs. + + Note that output pins can be set to drive LEDs OR GPIO, mixed + definition are not accepted. + +$ref: ethernet-phy-package.yaml# + +properties: + compatible: + enum: + - qcom,qca8072-package + - qcom,qca8075-package + + qcom,package-mode: + description: | + PHY package can be configured in 3 mode following this table: + + First Serdes mode Second Serdes mode + Option 1 PSGMII for copper Disabled + ports 0-4 + Option 2 PSGMII for copper 1000BASE-X / 100BASE-FX + ports 0-4 + Option 3 QSGMII for copper SGMII for + ports 0-3 copper port 4 + + PSGMII mode (option 1 or 2) is configured dynamically based on + the presence of a connected SFP device. + $ref: /schemas/types.yaml#/definitions/string + enum: + - qsgmii + - psgmii + default: psgmii + + qcom,tx-drive-strength-milliwatt: + description: set the TX Amplifier value in mv. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [140, 160, 180, 200, 220, + 240, 260, 280, 300, 320, + 400, 500, 600] + default: 600 + +patternProperties: + ^ethernet-phy@[a-f0-9]+$: + $ref: ethernet-phy.yaml# + + properties: + qcom,dac-full-amplitude: + description: + Set Analog MDI driver amplitude to FULL. + + With this not defined, amplitude is set to DSP. + (amplitude is adjusted based on cable length) + + With this enabled and qcom,dac-full-bias-current + and qcom,dac-disable-bias-current-tweak disabled, + bias current is half. + type: boolean + + qcom,dac-full-bias-current: + description: + Set Analog MDI driver bias current to FULL. + + With this not defined, bias current is set to DSP. + (bias current is adjusted based on cable length) + + Actual bias current might be different with + qcom,dac-disable-bias-current-tweak disabled. + type: boolean + + qcom,dac-disable-bias-current-tweak: + description: | + Set Analog MDI driver bias current to disable tweak + to bias current. + + With this not defined, bias current tweak are enabled + by default. + + With this enabled the following tweak are NOT applied: + - With both FULL amplitude and FULL bias current: bias current + is set to half. + - With only DSP amplitude: bias current is set to half and + is set to 1/4 with cable < 10m. + - With DSP bias current (included both DSP amplitude and + DSP bias current): bias current is half the detected current + with cable < 10m. + type: boolean + + gpio-controller: true + + '#gpio-cells': + const: 2 + + if: + required: + - gpio-controller + then: + properties: + leds: false + + unevaluatedProperties: false + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-phy-package@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,qca8075-package"; + reg = <0>; + + qcom,package-mode = "qsgmii"; + + ethernet-phy@0 { + reg = <0>; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_LAN; + default-state = "keep"; + }; + }; + }; + + ethernet-phy@1 { + reg = <1>; + }; + + ethernet-phy@2 { + reg = <2>; + + gpio-controller; + #gpio-cells = <2>; + }; + + ethernet-phy@3 { + reg = <3>; + }; + + ethernet-phy@4 { + reg = <4>; + }; + }; + }; From 9b1d5e055508393561e26bd1720f4c2639b03b1a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:09 +0100 Subject: [PATCH 1037/2255] net: phy: provide whether link has changed in c37_read_status Some PHY driver might require additional regs call after genphy_c37_read_status() is called. Expand genphy_c37_read_status to provide a bool wheather the link has changed or not to permit PHY driver to skip additional regs call if nothing has changed. Every user of genphy_c37_read_status() is updated with the new additional bool. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 3 ++- drivers/net/phy/phy_device.c | 11 +++++++++-- drivers/net/phy/qcom/at803x.c | 3 ++- include/linux/phy.h | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 312a8bb35d78..370e4ed45098 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -665,10 +665,11 @@ static int bcm54616s_config_aneg(struct phy_device *phydev) static int bcm54616s_read_status(struct phy_device *phydev) { struct bcm54616s_phy_priv *priv = phydev->priv; + bool changed; int err; if (priv->mode_1000bx_en) - err = genphy_c37_read_status(phydev); + err = genphy_c37_read_status(phydev, &changed); else err = genphy_read_status(phydev); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 71d48152e8d5..9f37c0bfbf8d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2621,12 +2621,15 @@ EXPORT_SYMBOL(genphy_read_status); /** * genphy_c37_read_status - check the link status and update current link state * @phydev: target phy_device struct + * @changed: pointer where to store if link changed * * Description: Check the link, then figure out the current state * by comparing what we advertise with what the link partner * advertises. This function is for Clause 37 1000Base-X mode. + * + * If link has changed, @changed is set to true, false otherwise. */ -int genphy_c37_read_status(struct phy_device *phydev) +int genphy_c37_read_status(struct phy_device *phydev, bool *changed) { int lpa, err, old_link = phydev->link; @@ -2636,9 +2639,13 @@ int genphy_c37_read_status(struct phy_device *phydev) return err; /* why bother the PHY if nothing can have changed */ - if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) { + *changed = false; return 0; + } + /* Signal link has changed */ + *changed = true; phydev->duplex = DUPLEX_UNKNOWN; phydev->pause = 0; phydev->asym_pause = 0; diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 3e3ee4c1d4bc..4717c59d51d0 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -912,9 +912,10 @@ static int at8031_config_intr(struct phy_device *phydev) static int at8031_read_status(struct phy_device *phydev) { struct at803x_priv *priv = phydev->priv; + bool changed; if (priv->is_1000basex) - return genphy_c37_read_status(phydev); + return genphy_c37_read_status(phydev, &changed); return at803x_read_status(phydev); } diff --git a/include/linux/phy.h b/include/linux/phy.h index cbd49418b819..2249cdb5957a 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1876,7 +1876,7 @@ int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, /* Clause 37 */ int genphy_c37_config_aneg(struct phy_device *phydev); -int genphy_c37_read_status(struct phy_device *phydev); +int genphy_c37_read_status(struct phy_device *phydev, bool *changed); /* Clause 45 PHY */ int genphy_c45_restart_aneg(struct phy_device *phydev); From d1cb613efbd3cd7d0c000167816beb3f248f5eb8 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Tue, 6 Feb 2024 18:31:10 +0100 Subject: [PATCH 1038/2255] net: phy: qcom: add support for QCA807x PHY Family This adds driver for the Qualcomm QCA8072 and QCA8075 PHY-s. They are 2 or 5 port IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and 1000BASE-T PHY-s. They feature 2 SerDes, one for PSGMII or QSGMII connection with MAC, while second one is SGMII for connection to MAC or fiber. Both models have a combo port that supports 1000BASE-X and 100BASE-FX fiber. PHY package can be configured in 3 mode following this table: First Serdes mode Second Serdes mode Option 1 PSGMII for copper Disabled ports 0-4 Option 2 PSGMII for copper 1000BASE-X / 100BASE-FX ports 0-4 Option 3 QSGMII for copper SGMII for ports 0-3 copper port 4 Each PHY inside of QCA807x series has 4 digitally controlled output only pins that natively drive LED-s. But some vendors used these to driver generic LED-s controlled by userspace, so lets enable registering each PHY as GPIO controller and add driver for it. These are commonly used in Qualcomm IPQ40xx, IPQ60xx and IPQ807x boards. Co-developed-by: Christian Marangi Signed-off-by: Robert Marko Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/qcom/Kconfig | 8 + drivers/net/phy/qcom/Makefile | 1 + drivers/net/phy/qcom/qca807x.c | 597 +++++++++++++++++++++++++++++++++ 3 files changed, 606 insertions(+) create mode 100644 drivers/net/phy/qcom/qca807x.c diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig index 80db24deb689..570626cc8e14 100644 --- a/drivers/net/phy/qcom/Kconfig +++ b/drivers/net/phy/qcom/Kconfig @@ -20,3 +20,11 @@ config QCA808X_PHY select QCOM_NET_PHYLIB help Currently supports the QCA8081 model + +config QCA807X_PHY + tristate "Qualcomm QCA807x PHYs" + select QCOM_NET_PHYLIB + depends on OF_MDIO + help + Currently supports the Qualcomm QCA8072, QCA8075 and the PSGMII + control PHY. diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile index 0362d7ed47be..f24fb550babd 100644 --- a/drivers/net/phy/qcom/Makefile +++ b/drivers/net/phy/qcom/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o obj-$(CONFIG_AT803X_PHY) += at803x.o obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o obj-$(CONFIG_QCA808X_PHY) += qca808x.o +obj-$(CONFIG_QCA807X_PHY) += qca807x.o diff --git a/drivers/net/phy/qcom/qca807x.c b/drivers/net/phy/qcom/qca807x.c new file mode 100644 index 000000000000..43fc9cddd975 --- /dev/null +++ b/drivers/net/phy/qcom/qca807x.c @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Sartura Ltd. + * + * Author: Robert Marko + * Christian Marangi + * + * Qualcomm QCA8072 and QCA8075 PHY driver + */ + +#include +#include +#include +#include +#include +#include + +#include "qcom.h" + +#define QCA807X_CHIP_CONFIGURATION 0x1f +#define QCA807X_BT_BX_REG_SEL BIT(15) +#define QCA807X_BT_BX_REG_SEL_FIBER 0 +#define QCA807X_BT_BX_REG_SEL_COPPER 1 +#define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0) +#define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4 +#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3 +#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0 + +#define QCA807X_MEDIA_SELECT_STATUS 0x1a +#define QCA807X_MEDIA_DETECTED_COPPER BIT(5) +#define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4) +#define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3) + +#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e +#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0) + +#define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a +#define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0) +/* List of tweaks enabled by this bit: + * - With both FULL amplitude and FULL bias current: bias current + * is set to half. + * - With only DSP amplitude: bias current is set to half and + * is set to 1/4 with cable < 10m. + * - With DSP bias current (included both DSP amplitude and + * DSP bias current): bias current is half the detected current + * with cable < 10m. + */ +#define QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK BIT(2) +#define QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT BIT(1) +#define QCA807X_CONTROL_DAC_DSP_AMPLITUDE BIT(0) + +#define QCA807X_MMD7_LED_100N_1 0x8074 +#define QCA807X_MMD7_LED_100N_2 0x8075 +#define QCA807X_MMD7_LED_1000N_1 0x8076 +#define QCA807X_MMD7_LED_1000N_2 0x8077 + +#define QCA807X_MMD7_LED_CTRL(x) (0x8074 + ((x) * 2)) +#define QCA807X_MMD7_LED_FORCE_CTRL(x) (0x8075 + ((x) * 2)) + +#define QCA807X_GPIO_FORCE_EN BIT(15) +#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13) + +#define QCA807X_FUNCTION_CONTROL 0x10 +#define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5) +#define QCA807X_FC_MDI_CROSSOVER_AUTO 3 +#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1 +#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0 + +/* PQSGMII Analog PHY specific */ +#define PQSGMII_CTRL_REG 0x0 +#define PQSGMII_ANALOG_SW_RESET BIT(6) +#define PQSGMII_DRIVE_CONTROL_1 0xb +#define PQSGMII_TX_DRIVER_MASK GENMASK(7, 4) +#define PQSGMII_TX_DRIVER_140MV 0x0 +#define PQSGMII_TX_DRIVER_160MV 0x1 +#define PQSGMII_TX_DRIVER_180MV 0x2 +#define PQSGMII_TX_DRIVER_200MV 0x3 +#define PQSGMII_TX_DRIVER_220MV 0x4 +#define PQSGMII_TX_DRIVER_240MV 0x5 +#define PQSGMII_TX_DRIVER_260MV 0x6 +#define PQSGMII_TX_DRIVER_280MV 0x7 +#define PQSGMII_TX_DRIVER_300MV 0x8 +#define PQSGMII_TX_DRIVER_320MV 0x9 +#define PQSGMII_TX_DRIVER_400MV 0xa +#define PQSGMII_TX_DRIVER_500MV 0xb +#define PQSGMII_TX_DRIVER_600MV 0xc +#define PQSGMII_MODE_CTRL 0x6d +#define PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0) +#define PQSGMII_MMD3_SERDES_CONTROL 0x805a + +#define PHY_ID_QCA8072 0x004dd0b2 +#define PHY_ID_QCA8075 0x004dd0b1 + +#define QCA807X_COMBO_ADDR_OFFSET 4 +#define QCA807X_PQSGMII_ADDR_OFFSET 5 +#define SERDES_RESET_SLEEP 100 + +enum qca807x_global_phy { + QCA807X_COMBO_ADDR = 4, + QCA807X_PQSGMII_ADDR = 5, +}; + +struct qca807x_shared_priv { + unsigned int package_mode; + u32 tx_drive_strength; +}; + +struct qca807x_gpio_priv { + struct phy_device *phy; +}; + +struct qca807x_priv { + bool dac_full_amplitude; + bool dac_full_bias_current; + bool dac_disable_bias_current_tweak; +}; + +static int qca807x_cable_test_start(struct phy_device *phydev) +{ + /* we do all the (time consuming) work later */ + return 0; +} + +#ifdef CONFIG_GPIOLIB +static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + return GPIO_LINE_DIRECTION_OUT; +} + +static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct qca807x_gpio_priv *priv = gpiochip_get_data(gc); + u16 reg; + int val; + + reg = QCA807X_MMD7_LED_FORCE_CTRL(offset); + val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg); + + return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val); +} + +static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct qca807x_gpio_priv *priv = gpiochip_get_data(gc); + u16 reg; + int val; + + reg = QCA807X_MMD7_LED_FORCE_CTRL(offset); + + val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg); + val &= ~QCA807X_GPIO_FORCE_MODE_MASK; + val |= QCA807X_GPIO_FORCE_EN; + val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value); + + phy_write_mmd(priv->phy, MDIO_MMD_AN, reg, val); +} + +static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value) +{ + qca807x_gpio_set(gc, offset, value); + + return 0; +} + +static int qca807x_gpio(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct qca807x_gpio_priv *priv; + struct gpio_chip *gc; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->phy = phydev; + + gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + gc->label = dev_name(dev); + gc->base = -1; + gc->ngpio = 2; + gc->parent = dev; + gc->owner = THIS_MODULE; + gc->can_sleep = true; + gc->get_direction = qca807x_gpio_get_direction; + gc->direction_output = qca807x_gpio_dir_out; + gc->get = qca807x_gpio_get; + gc->set = qca807x_gpio_set; + + return devm_gpiochip_add_data(dev, gc, priv); +} +#endif + +static int qca807x_read_fiber_status(struct phy_device *phydev) +{ + bool changed; + int ss, err; + + err = genphy_c37_read_status(phydev, &changed); + if (err || !changed) + return err; + + /* Read the QCA807x PHY-Specific Status register fiber page, + * which indicates the speed and duplex that the PHY is actually + * using, irrespective of whether we are in autoneg mode or not. + */ + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); + if (ss < 0) + return ss; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { + switch (FIELD_GET(AT803X_SS_SPEED_MASK, ss)) { + case AT803X_SS_SPEED_100: + phydev->speed = SPEED_100; + break; + case AT803X_SS_SPEED_1000: + phydev->speed = SPEED_1000; + break; + } + + if (ss & AT803X_SS_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + } + + return 0; +} + +static int qca807x_read_status(struct phy_device *phydev) +{ + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { + switch (phydev->port) { + case PORT_FIBRE: + return qca807x_read_fiber_status(phydev); + case PORT_TP: + return at803x_read_status(phydev); + default: + return -EINVAL; + } + } + + return at803x_read_status(phydev); +} + +static int qca807x_phy_package_probe_once(struct phy_device *phydev) +{ + struct phy_package_shared *shared = phydev->shared; + struct qca807x_shared_priv *priv = shared->priv; + unsigned int tx_drive_strength; + const char *package_mode_name; + + /* Default to 600mw if not defined */ + if (of_property_read_u32(shared->np, "qcom,tx-drive-strength-milliwatt", + &tx_drive_strength)) + tx_drive_strength = 600; + + switch (tx_drive_strength) { + case 140: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_140MV; + break; + case 160: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_160MV; + break; + case 180: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_180MV; + break; + case 200: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_200MV; + break; + case 220: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_220MV; + break; + case 240: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_240MV; + break; + case 260: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_260MV; + break; + case 280: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_280MV; + break; + case 300: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_300MV; + break; + case 320: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_320MV; + break; + case 400: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_400MV; + break; + case 500: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_500MV; + break; + case 600: + priv->tx_drive_strength = PQSGMII_TX_DRIVER_600MV; + break; + default: + return -EINVAL; + } + + priv->package_mode = PHY_INTERFACE_MODE_NA; + if (!of_property_read_string(shared->np, "qcom,package-mode", + &package_mode_name)) { + if (!strcasecmp(package_mode_name, + phy_modes(PHY_INTERFACE_MODE_PSGMII))) + priv->package_mode = PHY_INTERFACE_MODE_PSGMII; + else if (!strcasecmp(package_mode_name, + phy_modes(PHY_INTERFACE_MODE_QSGMII))) + priv->package_mode = PHY_INTERFACE_MODE_QSGMII; + else + return -EINVAL; + } + + return 0; +} + +static int qca807x_phy_package_config_init_once(struct phy_device *phydev) +{ + struct phy_package_shared *shared = phydev->shared; + struct qca807x_shared_priv *priv = shared->priv; + int val, ret; + + phy_lock_mdio_bus(phydev); + + /* Set correct PHY package mode */ + val = __phy_package_read(phydev, QCA807X_COMBO_ADDR, + QCA807X_CHIP_CONFIGURATION); + val &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK; + /* package_mode can be QSGMII or PSGMII and we validate + * this in probe_once. + * With package_mode to NA, we default to PSGMII. + */ + switch (priv->package_mode) { + case PHY_INTERFACE_MODE_QSGMII: + val |= QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII; + break; + case PHY_INTERFACE_MODE_PSGMII: + default: + val |= QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER; + } + ret = __phy_package_write(phydev, QCA807X_COMBO_ADDR, + QCA807X_CHIP_CONFIGURATION, val); + if (ret) + goto exit; + + /* After mode change Serdes reset is required */ + val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR, + PQSGMII_CTRL_REG); + val &= ~PQSGMII_ANALOG_SW_RESET; + ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR, + PQSGMII_CTRL_REG, val); + if (ret) + goto exit; + + msleep(SERDES_RESET_SLEEP); + + val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR, + PQSGMII_CTRL_REG); + val |= PQSGMII_ANALOG_SW_RESET; + ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR, + PQSGMII_CTRL_REG, val); + if (ret) + goto exit; + + /* Workaround to enable AZ transmitting ability */ + val = __phy_package_read_mmd(phydev, QCA807X_PQSGMII_ADDR, + MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL); + val &= ~PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK; + ret = __phy_package_write_mmd(phydev, QCA807X_PQSGMII_ADDR, + MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL, val); + if (ret) + goto exit; + + /* Set PQSGMII TX AMP strength */ + val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR, + PQSGMII_DRIVE_CONTROL_1); + val &= ~PQSGMII_TX_DRIVER_MASK; + val |= FIELD_PREP(PQSGMII_TX_DRIVER_MASK, priv->tx_drive_strength); + ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR, + PQSGMII_DRIVE_CONTROL_1, val); + if (ret) + goto exit; + + /* Prevent PSGMII going into hibernation via PSGMII self test */ + val = __phy_package_read_mmd(phydev, QCA807X_COMBO_ADDR, + MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL); + val &= ~BIT(1); + ret = __phy_package_write_mmd(phydev, QCA807X_COMBO_ADDR, + MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL, val); + +exit: + phy_unlock_mdio_bus(phydev); + + return ret; +} + +static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) +{ + struct phy_device *phydev = upstream; + __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; + phy_interface_t iface; + int ret; + DECLARE_PHY_INTERFACE_MASK(interfaces); + + sfp_parse_support(phydev->sfp_bus, id, support, interfaces); + iface = sfp_select_interface(phydev->sfp_bus, support); + + dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface)); + + switch (iface) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_100BASEX: + /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */ + ret = phy_modify(phydev, + QCA807X_CHIP_CONFIGURATION, + QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK, + QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER); + /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */ + ret = phy_set_bits_mmd(phydev, + MDIO_MMD_AN, + QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION, + QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN); + /* Select fiber page */ + ret = phy_clear_bits(phydev, + QCA807X_CHIP_CONFIGURATION, + QCA807X_BT_BX_REG_SEL); + + phydev->port = PORT_FIBRE; + break; + default: + dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n"); + return -EINVAL; + } + + return ret; +} + +static void qca807x_sfp_remove(void *upstream) +{ + struct phy_device *phydev = upstream; + + /* Select copper page */ + phy_set_bits(phydev, + QCA807X_CHIP_CONFIGURATION, + QCA807X_BT_BX_REG_SEL); + + phydev->port = PORT_TP; +} + +static const struct sfp_upstream_ops qca807x_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, + .module_insert = qca807x_sfp_insert, + .module_remove = qca807x_sfp_remove, +}; + +static int qca807x_probe(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct qca807x_shared_priv *shared_priv; + struct device *dev = &phydev->mdio.dev; + struct phy_package_shared *shared; + struct qca807x_priv *priv; + int ret; + + ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv)); + if (ret) + return ret; + + if (phy_package_probe_once(phydev)) { + ret = qca807x_phy_package_probe_once(phydev); + if (ret) + return ret; + } + + shared = phydev->shared; + shared_priv = shared->priv; + + /* Make sure PHY follow PHY package mode if enforced */ + if (shared_priv->package_mode != PHY_INTERFACE_MODE_NA && + phydev->interface != shared_priv->package_mode) + return -EINVAL; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dac_full_amplitude = of_property_read_bool(node, "qcom,dac-full-amplitude"); + priv->dac_full_bias_current = of_property_read_bool(node, "qcom,dac-full-bias-current"); + priv->dac_disable_bias_current_tweak = of_property_read_bool(node, + "qcom,dac-disable-bias-current-tweak"); + + if (IS_ENABLED(CONFIG_GPIOLIB)) { + /* Do not register a GPIO controller unless flagged for it */ + if (of_property_read_bool(node, "gpio-controller")) { + ret = qca807x_gpio(phydev); + if (ret) + return ret; + } + } + + /* Attach SFP bus on combo port*/ + if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { + ret = phy_sfp_probe(phydev, &qca807x_sfp_ops); + if (ret) + return ret; + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising); + } + + phydev->priv = priv; + + return 0; +} + +static int qca807x_config_init(struct phy_device *phydev) +{ + struct qca807x_priv *priv = phydev->priv; + u16 control_dac; + int ret; + + if (phy_package_init_once(phydev)) { + ret = qca807x_phy_package_config_init_once(phydev); + if (ret) + return ret; + } + + control_dac = phy_read_mmd(phydev, MDIO_MMD_AN, + QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH); + control_dac &= ~QCA807X_CONTROL_DAC_MASK; + if (!priv->dac_full_amplitude) + control_dac |= QCA807X_CONTROL_DAC_DSP_AMPLITUDE; + if (!priv->dac_full_amplitude) + control_dac |= QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT; + if (!priv->dac_disable_bias_current_tweak) + control_dac |= QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK; + return phy_write_mmd(phydev, MDIO_MMD_AN, + QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH, + control_dac); +} + +static struct phy_driver qca807x_drivers[] = { + { + PHY_ID_MATCH_EXACT(PHY_ID_QCA8072), + .name = "Qualcomm QCA8072", + .flags = PHY_POLL_CABLE_TEST, + /* PHY_GBIT_FEATURES */ + .probe = qca807x_probe, + .config_init = qca807x_config_init, + .read_status = qca807x_read_status, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .soft_reset = genphy_soft_reset, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .resume = genphy_resume, + .suspend = genphy_suspend, + .cable_test_start = qca807x_cable_test_start, + .cable_test_get_status = qca808x_cable_test_get_status, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_QCA8075), + .name = "Qualcomm QCA8075", + .flags = PHY_POLL_CABLE_TEST, + /* PHY_GBIT_FEATURES */ + .probe = qca807x_probe, + .config_init = qca807x_config_init, + .read_status = qca807x_read_status, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .soft_reset = genphy_soft_reset, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .resume = genphy_resume, + .suspend = genphy_suspend, + .cable_test_start = qca807x_cable_test_start, + .cable_test_get_status = qca808x_cable_test_get_status, + }, +}; +module_phy_driver(qca807x_drivers); + +static struct mdio_device_id __maybe_unused qca807x_tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) }, + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) }, + { } +}; + +MODULE_AUTHOR("Robert Marko "); +MODULE_AUTHOR("Christian Marangi "); +MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver"); +MODULE_DEVICE_TABLE(mdio, qca807x_tbl); +MODULE_LICENSE("GPL"); From ee9d9807bee0e6af8ca2a4db6f0d1dc0e5b41f44 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:11 +0100 Subject: [PATCH 1039/2255] net: phy: qcom: move common qca808x LED define to shared header The LED implementation of qca808x and qca807x is the same but qca807x supports also Fiber port and have different hw control bits for Fiber port. In preparation for qca807x introduction, move all the common define to shared header. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/qcom/qca808x.c | 65 ---------------------------------- drivers/net/phy/qcom/qcom.h | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 8377325f157e..f1edff6b6bfc 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -62,29 +62,6 @@ #define QCA808X_DBG_AN_TEST 0xb #define QCA808X_HIBERNATION_EN BIT(15) -#define QCA808X_MMD7_LED_GLOBAL 0x8073 -#define QCA808X_LED_BLINK_1 GENMASK(11, 6) -#define QCA808X_LED_BLINK_2 GENMASK(5, 0) -/* Values are the same for both BLINK_1 and BLINK_2 */ -#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) -#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) -#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) -#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) -#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) -#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) -#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) -#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) -#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) -#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) -#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) -#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) -#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) -#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) -#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) -#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) -#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) -#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) - #define QCA808X_MMD7_LED2_CTRL 0x8074 #define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075 #define QCA808X_MMD7_LED1_CTRL 0x8076 @@ -92,51 +69,9 @@ #define QCA808X_MMD7_LED0_CTRL 0x8078 #define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2)) -/* LED hw control pattern is the same for every LED */ -#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) -#define QCA808X_LED_SPEED2500_ON BIT(15) -#define QCA808X_LED_SPEED2500_BLINK BIT(14) -/* Follow blink trigger even if duplex or speed condition doesn't match */ -#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) -#define QCA808X_LED_FULL_DUPLEX_ON BIT(12) -#define QCA808X_LED_HALF_DUPLEX_ON BIT(11) -#define QCA808X_LED_TX_BLINK BIT(10) -#define QCA808X_LED_RX_BLINK BIT(9) -#define QCA808X_LED_TX_ON_10MS BIT(8) -#define QCA808X_LED_RX_ON_10MS BIT(7) -#define QCA808X_LED_SPEED1000_ON BIT(6) -#define QCA808X_LED_SPEED100_ON BIT(5) -#define QCA808X_LED_SPEED10_ON BIT(4) -#define QCA808X_LED_COLLISION_BLINK BIT(3) -#define QCA808X_LED_SPEED1000_BLINK BIT(2) -#define QCA808X_LED_SPEED100_BLINK BIT(1) -#define QCA808X_LED_SPEED10_BLINK BIT(0) - #define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079 #define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2)) -/* LED force ctrl is the same for every LED - * No documentation exist for this, not even internal one - * with NDA as QCOM gives only info about configuring - * hw control pattern rules and doesn't indicate any way - * to force the LED to specific mode. - * These define comes from reverse and testing and maybe - * lack of some info or some info are not entirely correct. - * For the basic LED control and hw control these finding - * are enough to support LED control in all the required APIs. - * - * On doing some comparison with implementation with qca807x, - * it was found that it's 1:1 equal to it and confirms all the - * reverse done. It was also found further specification with the - * force mode and the blink modes. - */ -#define QCA808X_LED_FORCE_EN BIT(15) -#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) -#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) -#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) -#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) -#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) - #define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a /* QSDK sets by default 0x46 to this reg that sets BIT 6 for * LED to active high. It's not clear what BIT 3 and BIT 4 does. diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h index dc259bbf0678..9e24997c355f 100644 --- a/drivers/net/phy/qcom/qcom.h +++ b/drivers/net/phy/qcom/qcom.h @@ -103,6 +103,71 @@ /* Added for reference of existence but should be handled by wait_for_completion already */ #define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) +#define QCA808X_MMD7_LED_GLOBAL 0x8073 +#define QCA808X_LED_BLINK_1 GENMASK(11, 6) +#define QCA808X_LED_BLINK_2 GENMASK(5, 0) +/* Values are the same for both BLINK_1 and BLINK_2 */ +#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) +#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) +#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) +#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) +#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) +#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) +#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) +#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) +#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) +#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) +#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) +#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) +#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) +#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) +#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) +#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) +#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) +#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) + +/* LED hw control pattern is the same for every LED */ +#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) +#define QCA808X_LED_SPEED2500_ON BIT(15) +#define QCA808X_LED_SPEED2500_BLINK BIT(14) +/* Follow blink trigger even if duplex or speed condition doesn't match */ +#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) +#define QCA808X_LED_FULL_DUPLEX_ON BIT(12) +#define QCA808X_LED_HALF_DUPLEX_ON BIT(11) +#define QCA808X_LED_TX_BLINK BIT(10) +#define QCA808X_LED_RX_BLINK BIT(9) +#define QCA808X_LED_TX_ON_10MS BIT(8) +#define QCA808X_LED_RX_ON_10MS BIT(7) +#define QCA808X_LED_SPEED1000_ON BIT(6) +#define QCA808X_LED_SPEED100_ON BIT(5) +#define QCA808X_LED_SPEED10_ON BIT(4) +#define QCA808X_LED_COLLISION_BLINK BIT(3) +#define QCA808X_LED_SPEED1000_BLINK BIT(2) +#define QCA808X_LED_SPEED100_BLINK BIT(1) +#define QCA808X_LED_SPEED10_BLINK BIT(0) + +/* LED force ctrl is the same for every LED + * No documentation exist for this, not even internal one + * with NDA as QCOM gives only info about configuring + * hw control pattern rules and doesn't indicate any way + * to force the LED to specific mode. + * These define comes from reverse and testing and maybe + * lack of some info or some info are not entirely correct. + * For the basic LED control and hw control these finding + * are enough to support LED control in all the required APIs. + * + * On doing some comparison with implementation with qca807x, + * it was found that it's 1:1 equal to it and confirms all the + * reverse done. It was also found further specification with the + * force mode and the blink modes. + */ +#define QCA808X_LED_FORCE_EN BIT(15) +#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) +#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) +#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) +#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) +#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) + #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A From 47b930d0dd437af927145dba50a2e2ea1ba97c67 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:12 +0100 Subject: [PATCH 1040/2255] net: phy: qcom: generalize some qca808x LED functions Generalize some qca808x LED functions in preparation for qca807x LED support. The LED implementation of qca808x and qca807x is the same but qca807x supports also Fiber port and have different hw control bits for Fiber port. To limit code duplication introduce micro functions that takes reg instead of LED index to tweak all the supported LED modes. Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/net/phy/qcom/qca808x.c | 38 +++----------------- drivers/net/phy/qcom/qcom-phy-lib.c | 54 +++++++++++++++++++++++++++++ drivers/net/phy/qcom/qcom.h | 7 ++++ 3 files changed, 65 insertions(+), 34 deletions(-) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index f1edff6b6bfc..2acf852fb4de 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -437,9 +437,7 @@ static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index) return -EINVAL; reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_FORCE_EN); + return qca808x_led_reg_hw_control_enable(phydev, reg); } static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index, @@ -480,16 +478,12 @@ static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index, static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index) { u16 reg; - int val; if (index > 2) return false; reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); - - return !(val & QCA808X_LED_FORCE_EN); + return qca808x_led_reg_hw_control_status(phydev, reg); } static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index, @@ -557,44 +551,20 @@ static int qca808x_led_brightness_set(struct phy_device *phydev, } reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, - QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON : - QCA808X_LED_FORCE_OFF)); + return qca808x_led_reg_brightness_set(phydev, reg, value); } static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, unsigned long *delay_on, unsigned long *delay_off) { - int ret; u16 reg; if (index > 2) return -EINVAL; reg = QCA808X_MMD7_LED_FORCE_CTRL(index); - - /* Set blink to 50% off, 50% on at 4Hz by default */ - ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, - QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, - QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); - if (ret) - return ret; - - /* We use BLINK_1 for normal blinking */ - ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); - if (ret) - return ret; - - /* We set blink to 4Hz, aka 250ms */ - *delay_on = 250 / 2; - *delay_off = 250 / 2; - - return 0; + return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off); } static int qca808x_led_polarity_set(struct phy_device *phydev, int index, diff --git a/drivers/net/phy/qcom/qcom-phy-lib.c b/drivers/net/phy/qcom/qcom-phy-lib.c index 786bfc39912c..d28815ef56bb 100644 --- a/drivers/net/phy/qcom/qcom-phy-lib.c +++ b/drivers/net/phy/qcom/qcom-phy-lib.c @@ -620,3 +620,57 @@ int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) return 0; } EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status); + +int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg) +{ + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN); +} +EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_enable); + +bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + return !(val & QCA808X_LED_FORCE_EN); +} +EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_status); + +int qca808x_led_reg_brightness_set(struct phy_device *phydev, + u16 reg, enum led_brightness value) +{ + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON : + QCA808X_LED_FORCE_OFF)); +} +EXPORT_SYMBOL_GPL(qca808x_led_reg_brightness_set); + +int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg, + unsigned long *delay_on, + unsigned long *delay_off) +{ + int ret; + + /* Set blink to 50% off, 50% on at 4Hz by default */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, + QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, + QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); + if (ret) + return ret; + + /* We use BLINK_1 for normal blinking */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); + if (ret) + return ret; + + /* We set blink to 4Hz, aka 250ms */ + *delay_on = 250 / 2; + *delay_off = 250 / 2; + + return 0; +} +EXPORT_SYMBOL_GPL(qca808x_led_reg_blink_set); diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h index 9e24997c355f..4bb541728846 100644 --- a/drivers/net/phy/qcom/qcom.h +++ b/drivers/net/phy/qcom/qcom.h @@ -234,3 +234,10 @@ int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start); int at803x_cdt_wait_for_completion(struct phy_device *phydev, u32 cdt_en); int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished); +int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg); +bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg); +int qca808x_led_reg_brightness_set(struct phy_device *phydev, + u16 reg, enum led_brightness value); +int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg, + unsigned long *delay_on, + unsigned long *delay_off); From f508a226b517a6a8afd78a317de46bc83e3e3d51 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 6 Feb 2024 18:31:13 +0100 Subject: [PATCH 1041/2255] net: phy: qca807x: add support for configurable LED QCA8072/5 have up to 2 LEDs attached for PHY. LEDs can be configured to be ON/hw blink or be set to HW control. Hw blink mode is set to blink at 4Hz or 250ms. PHY can support both copper (TP) or fiber (FIBRE) kind and supports different HW control modes based on the port type. HW control modes supported for netdev trigger for copper ports are: - LINK_10 - LINK_100 - LINK_1000 - TX - RX - FULL_DUPLEX - HALF_DUPLEX HW control modes supported for netdev trigger for fiber ports are: - LINK_100 - LINK_1000 - TX - RX - FULL_DUPLEX - HALF_DUPLEX LED support conflicts with GPIO controller feature and must be disabled if gpio-controller is used for the PHY. Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/net/phy/qcom/qca807x.c | 256 ++++++++++++++++++++++++++++++++- 1 file changed, 254 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/qcom/qca807x.c b/drivers/net/phy/qcom/qca807x.c index 43fc9cddd975..01815f947060 100644 --- a/drivers/net/phy/qcom/qca807x.c +++ b/drivers/net/phy/qcom/qca807x.c @@ -57,8 +57,18 @@ #define QCA807X_MMD7_LED_CTRL(x) (0x8074 + ((x) * 2)) #define QCA807X_MMD7_LED_FORCE_CTRL(x) (0x8075 + ((x) * 2)) -#define QCA807X_GPIO_FORCE_EN BIT(15) -#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13) +/* LED hw control pattern for fiber port */ +#define QCA807X_LED_FIBER_PATTERN_MASK GENMASK(11, 1) +#define QCA807X_LED_FIBER_TXACT_BLK_EN BIT(10) +#define QCA807X_LED_FIBER_RXACT_BLK_EN BIT(9) +#define QCA807X_LED_FIBER_FDX_ON_EN BIT(6) +#define QCA807X_LED_FIBER_HDX_ON_EN BIT(5) +#define QCA807X_LED_FIBER_1000BX_ON_EN BIT(2) +#define QCA807X_LED_FIBER_100FX_ON_EN BIT(1) + +/* Some device repurpose the LED as GPIO out */ +#define QCA807X_GPIO_FORCE_EN QCA808X_LED_FORCE_EN +#define QCA807X_GPIO_FORCE_MODE_MASK QCA808X_LED_FORCE_MODE_MASK #define QCA807X_FUNCTION_CONTROL 0x10 #define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5) @@ -121,6 +131,233 @@ static int qca807x_cable_test_start(struct phy_device *phydev) return 0; } +static int qca807x_led_parse_netdev(struct phy_device *phydev, unsigned long rules, + u16 *offload_trigger) +{ + /* Parsing specific to netdev trigger */ + switch (phydev->port) { + case PORT_TP: + if (test_bit(TRIGGER_NETDEV_TX, &rules)) + *offload_trigger |= QCA808X_LED_TX_BLINK; + if (test_bit(TRIGGER_NETDEV_RX, &rules)) + *offload_trigger |= QCA808X_LED_RX_BLINK; + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + *offload_trigger |= QCA808X_LED_SPEED10_ON; + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + *offload_trigger |= QCA808X_LED_SPEED100_ON; + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + *offload_trigger |= QCA808X_LED_SPEED1000_ON; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON; + break; + case PORT_FIBRE: + if (test_bit(TRIGGER_NETDEV_TX, &rules)) + *offload_trigger |= QCA807X_LED_FIBER_TXACT_BLK_EN; + if (test_bit(TRIGGER_NETDEV_RX, &rules)) + *offload_trigger |= QCA807X_LED_FIBER_RXACT_BLK_EN; + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + *offload_trigger |= QCA807X_LED_FIBER_100FX_ON_EN; + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + *offload_trigger |= QCA807X_LED_FIBER_1000BX_ON_EN; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) + *offload_trigger |= QCA807X_LED_FIBER_HDX_ON_EN; + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) + *offload_trigger |= QCA807X_LED_FIBER_FDX_ON_EN; + break; + default: + return -EOPNOTSUPP; + } + + if (rules && !*offload_trigger) + return -EOPNOTSUPP; + + return 0; +} + +static int qca807x_led_hw_control_enable(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 1) + return -EINVAL; + + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); + return qca808x_led_reg_hw_control_enable(phydev, reg); +} + +static int qca807x_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 offload_trigger = 0; + + if (index > 1) + return -EINVAL; + + return qca807x_led_parse_netdev(phydev, rules, &offload_trigger); +} + +static int qca807x_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 reg, mask, offload_trigger = 0; + int ret; + + if (index > 1) + return -EINVAL; + + ret = qca807x_led_parse_netdev(phydev, rules, &offload_trigger); + if (ret) + return ret; + + ret = qca807x_led_hw_control_enable(phydev, index); + if (ret) + return ret; + + switch (phydev->port) { + case PORT_TP: + reg = QCA807X_MMD7_LED_CTRL(index); + mask = QCA808X_LED_PATTERN_MASK; + break; + case PORT_FIBRE: + /* HW control pattern bits are in LED FORCE reg */ + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); + mask = QCA807X_LED_FIBER_PATTERN_MASK; + break; + default: + return -EINVAL; + } + + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, mask, + offload_trigger); +} + +static bool qca807x_led_hw_control_status(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 1) + return false; + + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); + return qca808x_led_reg_hw_control_status(phydev, reg); +} + +static int qca807x_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + u16 reg; + int val; + + if (index > 1) + return -EINVAL; + + /* Check if we have hw control enabled */ + if (qca807x_led_hw_control_status(phydev, index)) + return -EINVAL; + + /* Parsing specific to netdev trigger */ + switch (phydev->port) { + case PORT_TP: + reg = QCA807X_MMD7_LED_CTRL(index); + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + if (val & QCA808X_LED_TX_BLINK) + set_bit(TRIGGER_NETDEV_TX, rules); + if (val & QCA808X_LED_RX_BLINK) + set_bit(TRIGGER_NETDEV_RX, rules); + if (val & QCA808X_LED_SPEED10_ON) + set_bit(TRIGGER_NETDEV_LINK_10, rules); + if (val & QCA808X_LED_SPEED100_ON) + set_bit(TRIGGER_NETDEV_LINK_100, rules); + if (val & QCA808X_LED_SPEED1000_ON) + set_bit(TRIGGER_NETDEV_LINK_1000, rules); + if (val & QCA808X_LED_HALF_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); + if (val & QCA808X_LED_FULL_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); + break; + case PORT_FIBRE: + /* HW control pattern bits are in LED FORCE reg */ + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + if (val & QCA807X_LED_FIBER_TXACT_BLK_EN) + set_bit(TRIGGER_NETDEV_TX, rules); + if (val & QCA807X_LED_FIBER_RXACT_BLK_EN) + set_bit(TRIGGER_NETDEV_RX, rules); + if (val & QCA807X_LED_FIBER_100FX_ON_EN) + set_bit(TRIGGER_NETDEV_LINK_100, rules); + if (val & QCA807X_LED_FIBER_1000BX_ON_EN) + set_bit(TRIGGER_NETDEV_LINK_1000, rules); + if (val & QCA807X_LED_FIBER_HDX_ON_EN) + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); + if (val & QCA807X_LED_FIBER_FDX_ON_EN) + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int qca807x_led_hw_control_reset(struct phy_device *phydev, u8 index) +{ + u16 reg, mask; + + if (index > 1) + return -EINVAL; + + switch (phydev->port) { + case PORT_TP: + reg = QCA807X_MMD7_LED_CTRL(index); + mask = QCA808X_LED_PATTERN_MASK; + break; + case PORT_FIBRE: + /* HW control pattern bits are in LED FORCE reg */ + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); + mask = QCA807X_LED_FIBER_PATTERN_MASK; + break; + default: + return -EINVAL; + } + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, mask); +} + +static int qca807x_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + u16 reg; + int ret; + + if (index > 1) + return -EINVAL; + + /* If we are setting off the LED reset any hw control rule */ + if (!value) { + ret = qca807x_led_hw_control_reset(phydev, index); + if (ret) + return ret; + } + + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); + return qca808x_led_reg_brightness_set(phydev, reg, value); +} + +static int qca807x_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) +{ + u16 reg; + + if (index > 1) + return -EINVAL; + + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); + return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off); +} + #ifdef CONFIG_GPIOLIB static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { @@ -496,6 +733,16 @@ static int qca807x_probe(struct phy_device *phydev) "qcom,dac-disable-bias-current-tweak"); if (IS_ENABLED(CONFIG_GPIOLIB)) { + /* Make sure we don't have mixed leds node and gpio-controller + * to prevent registering leds and having gpio-controller usage + * conflicting with them. + */ + if (of_find_property(node, "leds", NULL) && + of_find_property(node, "gpio-controller", NULL)) { + phydev_err(phydev, "Invalid property detected. LEDs and gpio-controller are mutually exclusive."); + return -EINVAL; + } + /* Do not register a GPIO controller unless flagged for it */ if (of_property_read_bool(node, "gpio-controller")) { ret = qca807x_gpio(phydev); @@ -580,6 +827,11 @@ static struct phy_driver qca807x_drivers[] = { .suspend = genphy_suspend, .cable_test_start = qca807x_cable_test_start, .cable_test_get_status = qca808x_cable_test_get_status, + .led_brightness_set = qca807x_led_brightness_set, + .led_blink_set = qca807x_led_blink_set, + .led_hw_is_supported = qca807x_led_hw_is_supported, + .led_hw_control_set = qca807x_led_hw_control_set, + .led_hw_control_get = qca807x_led_hw_control_get, }, }; module_phy_driver(qca807x_drivers); From 68bc61c26cacf152baf905786b5949769700f40d Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Wed, 7 Feb 2024 13:26:17 +0100 Subject: [PATCH 1042/2255] bpf: Allow compiler to inline most of bpf_local_storage_lookup() In various performance profiles of kernels with BPF programs attached, bpf_local_storage_lookup() appears as a significant portion of CPU cycles spent. To enable the compiler generate more optimal code, turn bpf_local_storage_lookup() into a static inline function, where only the cache insertion code path is outlined Notably, outlining cache insertion helps avoid bloating callers by duplicating setting up calls to raw_spin_{lock,unlock}_irqsave() (on architectures which do not inline spin_lock/unlock, such as x86), which would cause the compiler produce worse code by deciding to outline otherwise inlinable functions. The call overhead is neutral, because we make 2 calls either way: either calling raw_spin_lock_irqsave() and raw_spin_unlock_irqsave(); or call __bpf_local_storage_insert_cache(), which calls raw_spin_lock_irqsave(), followed by a tail-call to raw_spin_unlock_irqsave() where the compiler can perform TCO and (in optimized uninstrumented builds) turns it into a plain jump. The call to __bpf_local_storage_insert_cache() can be elided entirely if cacheit_lockit is a false constant expression. Based on results from './benchs/run_bench_local_storage.sh' (21 trials, reboot between each trial; x86 defconfig + BPF, clang 16) this produces improvements in throughput and latency in the majority of cases, with an average (geomean) improvement of 8%: +---- Hashmap Control -------------------- | | + num keys: 10 | : | | +-+ hashmap (control) sequential get +----------------------+---------------------- | +- hits throughput | 14.789 M ops/s | 14.745 M ops/s ( ~ ) | +- hits latency | 67.679 ns/op | 67.879 ns/op ( ~ ) | +- important_hits throughput | 14.789 M ops/s | 14.745 M ops/s ( ~ ) | | + num keys: 1000 | : | | +-+ hashmap (control) sequential get +----------------------+---------------------- | +- hits throughput | 12.233 M ops/s | 12.170 M ops/s ( ~ ) | +- hits latency | 81.754 ns/op | 82.185 ns/op ( ~ ) | +- important_hits throughput | 12.233 M ops/s | 12.170 M ops/s ( ~ ) | | + num keys: 10000 | : | | +-+ hashmap (control) sequential get +----------------------+---------------------- | +- hits throughput | 7.220 M ops/s | 7.204 M ops/s ( ~ ) | +- hits latency | 138.522 ns/op | 138.842 ns/op ( ~ ) | +- important_hits throughput | 7.220 M ops/s | 7.204 M ops/s ( ~ ) | | + num keys: 100000 | : | | +-+ hashmap (control) sequential get +----------------------+---------------------- | +- hits throughput | 5.061 M ops/s | 5.165 M ops/s (+2.1%) | +- hits latency | 198.483 ns/op | 194.270 ns/op (-2.1%) | +- important_hits throughput | 5.061 M ops/s | 5.165 M ops/s (+2.1%) | | + num keys: 4194304 | : | | +-+ hashmap (control) sequential get +----------------------+---------------------- | +- hits throughput | 2.864 M ops/s | 2.882 M ops/s ( ~ ) | +- hits latency | 365.220 ns/op | 361.418 ns/op (-1.0%) | +- important_hits throughput | 2.864 M ops/s | 2.882 M ops/s ( ~ ) | +---- Local Storage ---------------------- | | + num_maps: 1 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 33.005 M ops/s | 39.068 M ops/s (+18.4%) | +- hits latency | 30.300 ns/op | 25.598 ns/op (-15.5%) | +- important_hits throughput | 33.005 M ops/s | 39.068 M ops/s (+18.4%) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 37.151 M ops/s | 44.926 M ops/s (+20.9%) | +- hits latency | 26.919 ns/op | 22.259 ns/op (-17.3%) | +- important_hits throughput | 37.151 M ops/s | 44.926 M ops/s (+20.9%) | | + num_maps: 10 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 32.288 M ops/s | 38.099 M ops/s (+18.0%) | +- hits latency | 30.972 ns/op | 26.248 ns/op (-15.3%) | +- important_hits throughput | 3.229 M ops/s | 3.810 M ops/s (+18.0%) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 34.473 M ops/s | 41.145 M ops/s (+19.4%) | +- hits latency | 29.010 ns/op | 24.307 ns/op (-16.2%) | +- important_hits throughput | 12.312 M ops/s | 14.695 M ops/s (+19.4%) | | + num_maps: 16 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 32.524 M ops/s | 38.341 M ops/s (+17.9%) | +- hits latency | 30.748 ns/op | 26.083 ns/op (-15.2%) | +- important_hits throughput | 2.033 M ops/s | 2.396 M ops/s (+17.9%) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 34.575 M ops/s | 41.338 M ops/s (+19.6%) | +- hits latency | 28.925 ns/op | 24.193 ns/op (-16.4%) | +- important_hits throughput | 11.001 M ops/s | 13.153 M ops/s (+19.6%) | | + num_maps: 17 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 28.861 M ops/s | 32.756 M ops/s (+13.5%) | +- hits latency | 34.649 ns/op | 30.530 ns/op (-11.9%) | +- important_hits throughput | 1.700 M ops/s | 1.929 M ops/s (+13.5%) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 31.529 M ops/s | 36.110 M ops/s (+14.5%) | +- hits latency | 31.719 ns/op | 27.697 ns/op (-12.7%) | +- important_hits throughput | 9.598 M ops/s | 10.993 M ops/s (+14.5%) | | + num_maps: 24 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 18.602 M ops/s | 19.937 M ops/s (+7.2%) | +- hits latency | 53.767 ns/op | 50.166 ns/op (-6.7%) | +- important_hits throughput | 0.776 M ops/s | 0.831 M ops/s (+7.2%) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 21.718 M ops/s | 23.332 M ops/s (+7.4%) | +- hits latency | 46.047 ns/op | 42.865 ns/op (-6.9%) | +- important_hits throughput | 6.110 M ops/s | 6.564 M ops/s (+7.4%) | | + num_maps: 32 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 14.118 M ops/s | 14.626 M ops/s (+3.6%) | +- hits latency | 70.856 ns/op | 68.381 ns/op (-3.5%) | +- important_hits throughput | 0.442 M ops/s | 0.458 M ops/s (+3.6%) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 17.111 M ops/s | 17.906 M ops/s (+4.6%) | +- hits latency | 58.451 ns/op | 55.865 ns/op (-4.4%) | +- important_hits throughput | 4.776 M ops/s | 4.998 M ops/s (+4.6%) | | + num_maps: 100 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 5.281 M ops/s | 5.528 M ops/s (+4.7%) | +- hits latency | 192.398 ns/op | 183.059 ns/op (-4.9%) | +- important_hits throughput | 0.053 M ops/s | 0.055 M ops/s (+4.9%) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 6.265 M ops/s | 6.498 M ops/s (+3.7%) | +- hits latency | 161.436 ns/op | 152.877 ns/op (-5.3%) | +- important_hits throughput | 1.636 M ops/s | 1.697 M ops/s (+3.7%) | | + num_maps: 1000 | : | | +-+ local_storage cache sequential get +----------------------+---------------------- | +- hits throughput | 0.355 M ops/s | 0.354 M ops/s ( ~ ) | +- hits latency | 2826.538 ns/op | 2827.139 ns/op ( ~ ) | +- important_hits throughput | 0.000 M ops/s | 0.000 M ops/s ( ~ ) | : | : | | +-+ local_storage cache interleaved get +----------------------+---------------------- | +- hits throughput | 0.404 M ops/s | 0.403 M ops/s ( ~ ) | +- hits latency | 2481.190 ns/op | 2487.555 ns/op ( ~ ) | +- important_hits throughput | 0.102 M ops/s | 0.101 M ops/s ( ~ ) The on_lookup test in {cgrp,task}_ls_recursion.c is removed because the bpf_local_storage_lookup is no longer traceable and adding tracepoint will make the compiler generate worse code: https://lore.kernel.org/bpf/ZcJmok64Xqv6l4ZS@elver.google.com/ Signed-off-by: Marco Elver Cc: Martin KaFai Lau Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240207122626.3508658-1-elver@google.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf_local_storage.h | 30 ++++++++++- kernel/bpf/bpf_local_storage.c | 52 +++++-------------- .../bpf/prog_tests/task_local_storage.c | 6 --- .../selftests/bpf/progs/cgrp_ls_recursion.c | 26 ---------- .../selftests/bpf/progs/task_ls_recursion.c | 17 ------ 5 files changed, 41 insertions(+), 90 deletions(-) diff --git a/include/linux/bpf_local_storage.h b/include/linux/bpf_local_storage.h index 173ec7f43ed1..dcddb0aef7d8 100644 --- a/include/linux/bpf_local_storage.h +++ b/include/linux/bpf_local_storage.h @@ -129,10 +129,36 @@ bpf_local_storage_map_alloc(union bpf_attr *attr, struct bpf_local_storage_cache *cache, bool bpf_ma); -struct bpf_local_storage_data * +void __bpf_local_storage_insert_cache(struct bpf_local_storage *local_storage, + struct bpf_local_storage_map *smap, + struct bpf_local_storage_elem *selem); +/* If cacheit_lockit is false, this lookup function is lockless */ +static inline struct bpf_local_storage_data * bpf_local_storage_lookup(struct bpf_local_storage *local_storage, struct bpf_local_storage_map *smap, - bool cacheit_lockit); + bool cacheit_lockit) +{ + struct bpf_local_storage_data *sdata; + struct bpf_local_storage_elem *selem; + + /* Fast path (cache hit) */ + sdata = rcu_dereference_check(local_storage->cache[smap->cache_idx], + bpf_rcu_lock_held()); + if (sdata && rcu_access_pointer(sdata->smap) == smap) + return sdata; + + /* Slow path (cache miss) */ + hlist_for_each_entry_rcu(selem, &local_storage->list, snode, + rcu_read_lock_trace_held()) + if (rcu_access_pointer(SDATA(selem)->smap) == smap) + break; + + if (!selem) + return NULL; + if (cacheit_lockit) + __bpf_local_storage_insert_cache(local_storage, smap, selem); + return SDATA(selem); +} void bpf_local_storage_destroy(struct bpf_local_storage *local_storage); diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c index 146824cc9689..bdea1a459153 100644 --- a/kernel/bpf/bpf_local_storage.c +++ b/kernel/bpf/bpf_local_storage.c @@ -414,47 +414,21 @@ void bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now) bpf_selem_unlink_storage(selem, reuse_now); } -/* If cacheit_lockit is false, this lookup function is lockless */ -struct bpf_local_storage_data * -bpf_local_storage_lookup(struct bpf_local_storage *local_storage, - struct bpf_local_storage_map *smap, - bool cacheit_lockit) +void __bpf_local_storage_insert_cache(struct bpf_local_storage *local_storage, + struct bpf_local_storage_map *smap, + struct bpf_local_storage_elem *selem) { - struct bpf_local_storage_data *sdata; - struct bpf_local_storage_elem *selem; + unsigned long flags; - /* Fast path (cache hit) */ - sdata = rcu_dereference_check(local_storage->cache[smap->cache_idx], - bpf_rcu_lock_held()); - if (sdata && rcu_access_pointer(sdata->smap) == smap) - return sdata; - - /* Slow path (cache miss) */ - hlist_for_each_entry_rcu(selem, &local_storage->list, snode, - rcu_read_lock_trace_held()) - if (rcu_access_pointer(SDATA(selem)->smap) == smap) - break; - - if (!selem) - return NULL; - - sdata = SDATA(selem); - if (cacheit_lockit) { - unsigned long flags; - - /* spinlock is needed to avoid racing with the - * parallel delete. Otherwise, publishing an already - * deleted sdata to the cache will become a use-after-free - * problem in the next bpf_local_storage_lookup(). - */ - raw_spin_lock_irqsave(&local_storage->lock, flags); - if (selem_linked_to_storage(selem)) - rcu_assign_pointer(local_storage->cache[smap->cache_idx], - sdata); - raw_spin_unlock_irqrestore(&local_storage->lock, flags); - } - - return sdata; + /* spinlock is needed to avoid racing with the + * parallel delete. Otherwise, publishing an already + * deleted sdata to the cache will become a use-after-free + * problem in the next bpf_local_storage_lookup(). + */ + raw_spin_lock_irqsave(&local_storage->lock, flags); + if (selem_linked_to_storage(selem)) + rcu_assign_pointer(local_storage->cache[smap->cache_idx], SDATA(selem)); + raw_spin_unlock_irqrestore(&local_storage->lock, flags); } static int check_flags(const struct bpf_local_storage_data *old_sdata, diff --git a/tools/testing/selftests/bpf/prog_tests/task_local_storage.c b/tools/testing/selftests/bpf/prog_tests/task_local_storage.c index ea8537c54413..c33c05161a9e 100644 --- a/tools/testing/selftests/bpf/prog_tests/task_local_storage.c +++ b/tools/testing/selftests/bpf/prog_tests/task_local_storage.c @@ -117,12 +117,6 @@ static void test_recursion(void) ASSERT_OK(err, "lookup map_b"); ASSERT_EQ(value, 100, "map_b value"); - prog_fd = bpf_program__fd(skel->progs.on_lookup); - memset(&info, 0, sizeof(info)); - err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len); - ASSERT_OK(err, "get prog info"); - ASSERT_GT(info.recursion_misses, 0, "on_lookup prog recursion"); - prog_fd = bpf_program__fd(skel->progs.on_update); memset(&info, 0, sizeof(info)); err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len); diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c b/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c index 610c2427fd93..3500e4b69ebe 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c @@ -27,32 +27,6 @@ bool is_cgroup1 = 0; struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; void bpf_cgroup_release(struct cgroup *cgrp) __ksym; -static void __on_lookup(struct cgroup *cgrp) -{ - bpf_cgrp_storage_delete(&map_a, cgrp); - bpf_cgrp_storage_delete(&map_b, cgrp); -} - -SEC("fentry/bpf_local_storage_lookup") -int BPF_PROG(on_lookup) -{ - struct task_struct *task = bpf_get_current_task_btf(); - struct cgroup *cgrp; - - if (is_cgroup1) { - cgrp = bpf_task_get_cgroup1(task, target_hid); - if (!cgrp) - return 0; - - __on_lookup(cgrp); - bpf_cgroup_release(cgrp); - return 0; - } - - __on_lookup(task->cgroups->dfl_cgrp); - return 0; -} - static void __on_update(struct cgroup *cgrp) { long *ptr; diff --git a/tools/testing/selftests/bpf/progs/task_ls_recursion.c b/tools/testing/selftests/bpf/progs/task_ls_recursion.c index 4542dc683b44..f1853c38aada 100644 --- a/tools/testing/selftests/bpf/progs/task_ls_recursion.c +++ b/tools/testing/selftests/bpf/progs/task_ls_recursion.c @@ -27,23 +27,6 @@ struct { __type(value, long); } map_b SEC(".maps"); -SEC("fentry/bpf_local_storage_lookup") -int BPF_PROG(on_lookup) -{ - struct task_struct *task = bpf_get_current_task_btf(); - - if (!test_pid || task->pid != test_pid) - return 0; - - /* The bpf_task_storage_delete will call - * bpf_local_storage_lookup. The prog->active will - * stop the recursion. - */ - bpf_task_storage_delete(&map_a, task); - bpf_task_storage_delete(&map_b, task); - return 0; -} - SEC("fentry/bpf_local_storage_update") int BPF_PROG(on_update) { From cb7dd712189f2fe5eb34ac2f904e28283f055cae Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:33 -0800 Subject: [PATCH 1043/2255] octeon_ep_vf: Add driver framework and device initialization Add driver framework and device setup and initialization for Octeon PCI Endpoint NIC VF. Add implementation to load module, initialize, register network device, cleanup and unload module. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../device_drivers/ethernet/index.rst | 1 + .../ethernet/marvell/octeon_ep_vf.rst | 24 + drivers/net/ethernet/marvell/Kconfig | 1 + drivers/net/ethernet/marvell/Makefile | 1 + .../net/ethernet/marvell/octeon_ep_vf/Kconfig | 19 + .../ethernet/marvell/octeon_ep_vf/Makefile | 9 + .../marvell/octeon_ep_vf/octep_vf_cn9k.c | 157 ++++++ .../marvell/octeon_ep_vf/octep_vf_cnxk.c | 158 ++++++ .../marvell/octeon_ep_vf/octep_vf_config.h | 160 ++++++ .../marvell/octeon_ep_vf/octep_vf_main.c | 516 ++++++++++++++++++ .../marvell/octeon_ep_vf/octep_vf_main.h | 331 +++++++++++ .../marvell/octeon_ep_vf/octep_vf_mbox.c | 96 ++++ .../marvell/octeon_ep_vf/octep_vf_mbox.h | 25 + .../marvell/octeon_ep_vf/octep_vf_regs_cn9k.h | 154 ++++++ .../marvell/octeon_ep_vf/octep_vf_regs_cnxk.h | 162 ++++++ .../marvell/octeon_ep_vf/octep_vf_rx.c | 42 ++ .../marvell/octeon_ep_vf/octep_vf_rx.h | 224 ++++++++ .../marvell/octeon_ep_vf/octep_vf_tx.c | 43 ++ .../marvell/octeon_ep_vf/octep_vf_tx.h | 276 ++++++++++ 19 files changed, 2399 insertions(+) create mode 100644 Documentation/networking/device_drivers/ethernet/marvell/octeon_ep_vf.rst create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/Makefile create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_config.h create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cn9k.h create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cnxk.h create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.h create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.h diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst index 43de285b8a92..6932d8c043c2 100644 --- a/Documentation/networking/device_drivers/ethernet/index.rst +++ b/Documentation/networking/device_drivers/ethernet/index.rst @@ -42,6 +42,7 @@ Contents: intel/ice marvell/octeontx2 marvell/octeon_ep + marvell/octeon_ep_vf mellanox/mlx5/index microsoft/netvsc neterion/s2io diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep_vf.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep_vf.rst new file mode 100644 index 000000000000..603133d0b92f --- /dev/null +++ b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep_vf.rst @@ -0,0 +1,24 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +======================================================================= +Linux kernel networking driver for Marvell's Octeon PCI Endpoint NIC VF +======================================================================= + +Network driver for Marvell's Octeon PCI EndPoint NIC VF. +Copyright (c) 2020 Marvell International Ltd. + +Overview +======== +This driver implements networking functionality of Marvell's Octeon PCI +EndPoint NIC VF. + +Supported Devices +================= +Currently, this driver support following devices: + * Network controller: Cavium, Inc. Device b203 + * Network controller: Cavium, Inc. Device b403 + * Network controller: Cavium, Inc. Device b103 + * Network controller: Cavium, Inc. Device b903 + * Network controller: Cavium, Inc. Device ba03 + * Network controller: Cavium, Inc. Device bc03 + * Network controller: Cavium, Inc. Device bd03 diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index 884d64114bff..837295fecd17 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -180,6 +180,7 @@ config SKY2_DEBUG source "drivers/net/ethernet/marvell/octeontx2/Kconfig" source "drivers/net/ethernet/marvell/octeon_ep/Kconfig" +source "drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig" source "drivers/net/ethernet/marvell/prestera/Kconfig" endif # NET_VENDOR_MARVELL diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile index ceba4aa4f026..a399defe25fd 100644 --- a/drivers/net/ethernet/marvell/Makefile +++ b/drivers/net/ethernet/marvell/Makefile @@ -12,5 +12,6 @@ obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o obj-y += octeon_ep/ +obj-y += octeon_ep_vf/ obj-y += octeontx2/ obj-y += prestera/ diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig b/drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig new file mode 100644 index 000000000000..dbd1267bda0c --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Marvell's Octeon PCI Endpoint NIC VF Driver Configuration +# + +config OCTEON_EP_VF + tristate "Marvell Octeon PCI Endpoint NIC VF Driver" + depends on 64BIT + depends on PCI + help + This driver supports networking functionality of Marvell's + Octeon PCI Endpoint NIC VF. + + To know the list of devices supported by this driver, refer + documentation in + . + + To compile this drivers as a module, choose M here. Name of the + module is octeon_ep_vf. diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/Makefile b/drivers/net/ethernet/marvell/octeon_ep_vf/Makefile new file mode 100644 index 000000000000..694eb9b46e99 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Network driver for Marvell's Octeon PCI Endpoint NIC VF +# + +obj-$(CONFIG_OCTEON_EP_VF) += octeon_ep_vf.o + +octeon_ep_vf-y := octep_vf_main.o octep_vf_cn9k.o octep_vf_cnxk.o \ + octep_vf_tx.o octep_vf_rx.o octep_vf_mbox.o diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c new file mode 100644 index 000000000000..c24ef2265205 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#include +#include +#include + +#include "octep_vf_config.h" +#include "octep_vf_main.h" +#include "octep_vf_regs_cn9k.h" + +/* Reset all hardware Tx/Rx queues */ +static void octep_vf_reset_io_queues_cn93(struct octep_vf_device *oct) +{ +} + +/* Initialize configuration limits and initial active config */ +static void octep_vf_init_config_cn93_vf(struct octep_vf_device *oct) +{ + struct octep_vf_config *conf = oct->conf; + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(0)); + conf->ring_cfg.max_io_rings = (reg_val >> CN93_VF_R_IN_CTL_RPVF_POS) & + CN93_VF_R_IN_CTL_RPVF_MASK; + conf->ring_cfg.active_io_rings = conf->ring_cfg.max_io_rings; + + conf->iq.num_descs = OCTEP_VF_IQ_MAX_DESCRIPTORS; + conf->iq.instr_type = OCTEP_VF_64BYTE_INSTR; + conf->iq.db_min = OCTEP_VF_DB_MIN; + conf->iq.intr_threshold = OCTEP_VF_IQ_INTR_THRESHOLD; + + conf->oq.num_descs = OCTEP_VF_OQ_MAX_DESCRIPTORS; + conf->oq.buf_size = OCTEP_VF_OQ_BUF_SIZE; + conf->oq.refill_threshold = OCTEP_VF_OQ_REFILL_THRESHOLD; + conf->oq.oq_intr_pkt = OCTEP_VF_OQ_INTR_PKT_THRESHOLD; + conf->oq.oq_intr_time = OCTEP_VF_OQ_INTR_TIME_THRESHOLD; + + conf->msix_cfg.ioq_msix = conf->ring_cfg.active_io_rings; +} + +/* Setup registers for a hardware Tx Queue */ +static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no) +{ +} + +/* Setup registers for a hardware Rx Queue */ +static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) +{ +} + +/* Setup registers for a VF mailbox */ +static void octep_vf_setup_mbox_regs_cn93(struct octep_vf_device *oct, int q_no) +{ +} + +/* Tx/Rx queue interrupt handler */ +static irqreturn_t octep_vf_ioq_intr_handler_cn93(void *data) +{ + return IRQ_HANDLED; +} + +/* Re-initialize Octeon hardware registers */ +static void octep_vf_reinit_regs_cn93(struct octep_vf_device *oct) +{ +} + +/* Enable all interrupts */ +static void octep_vf_enable_interrupts_cn93(struct octep_vf_device *oct) +{ +} + +/* Disable all interrupts */ +static void octep_vf_disable_interrupts_cn93(struct octep_vf_device *oct) +{ +} + +/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ +static u32 octep_vf_update_iq_read_index_cn93(struct octep_vf_iq *iq) +{ + return 0; +} + +/* Enable a hardware Tx Queue */ +static void octep_vf_enable_iq_cn93(struct octep_vf_device *oct, int iq_no) +{ +} + +/* Enable a hardware Rx Queue */ +static void octep_vf_enable_oq_cn93(struct octep_vf_device *oct, int oq_no) +{ +} + +/* Enable all hardware Tx/Rx Queues assigned to VF */ +static void octep_vf_enable_io_queues_cn93(struct octep_vf_device *oct) +{ +} + +/* Disable a hardware Tx Queue assigned to VF */ +static void octep_vf_disable_iq_cn93(struct octep_vf_device *oct, int iq_no) +{ +} + +/* Disable a hardware Rx Queue assigned to VF */ +static void octep_vf_disable_oq_cn93(struct octep_vf_device *oct, int oq_no) +{ +} + +/* Disable all hardware Tx/Rx Queues assigned to VF */ +static void octep_vf_disable_io_queues_cn93(struct octep_vf_device *oct) +{ +} + +/* Dump hardware registers (including Tx/Rx queues) for debugging. */ +static void octep_vf_dump_registers_cn93(struct octep_vf_device *oct) +{ +} + +/** + * octep_vf_device_setup_cn93() - Setup Octeon device. + * + * @oct: Octeon device private data structure. + * + * - initialize hardware operations. + * - get target side pcie port number for the device. + * - set initial configuration and max limits. + */ +void octep_vf_device_setup_cn93(struct octep_vf_device *oct) +{ + oct->hw_ops.setup_iq_regs = octep_vf_setup_iq_regs_cn93; + oct->hw_ops.setup_oq_regs = octep_vf_setup_oq_regs_cn93; + oct->hw_ops.setup_mbox_regs = octep_vf_setup_mbox_regs_cn93; + + oct->hw_ops.ioq_intr_handler = octep_vf_ioq_intr_handler_cn93; + oct->hw_ops.reinit_regs = octep_vf_reinit_regs_cn93; + + oct->hw_ops.enable_interrupts = octep_vf_enable_interrupts_cn93; + oct->hw_ops.disable_interrupts = octep_vf_disable_interrupts_cn93; + + oct->hw_ops.update_iq_read_idx = octep_vf_update_iq_read_index_cn93; + + oct->hw_ops.enable_iq = octep_vf_enable_iq_cn93; + oct->hw_ops.enable_oq = octep_vf_enable_oq_cn93; + oct->hw_ops.enable_io_queues = octep_vf_enable_io_queues_cn93; + + oct->hw_ops.disable_iq = octep_vf_disable_iq_cn93; + oct->hw_ops.disable_oq = octep_vf_disable_oq_cn93; + oct->hw_ops.disable_io_queues = octep_vf_disable_io_queues_cn93; + oct->hw_ops.reset_io_queues = octep_vf_reset_io_queues_cn93; + + oct->hw_ops.dump_registers = octep_vf_dump_registers_cn93; + octep_vf_init_config_cn93_vf(oct); +} diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c new file mode 100644 index 000000000000..af07a4a6edc5 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#include +#include +#include + +#include "octep_vf_config.h" +#include "octep_vf_main.h" +#include "octep_vf_regs_cnxk.h" + +/* Reset all hardware Tx/Rx queues */ +static void octep_vf_reset_io_queues_cnxk(struct octep_vf_device *oct) +{ +} + +/* Initialize configuration limits and initial active config */ +static void octep_vf_init_config_cnxk_vf(struct octep_vf_device *oct) +{ + struct octep_vf_config *conf = oct->conf; + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(0)); + conf->ring_cfg.max_io_rings = (reg_val >> CNXK_VF_R_IN_CTL_RPVF_POS) & + CNXK_VF_R_IN_CTL_RPVF_MASK; + conf->ring_cfg.active_io_rings = conf->ring_cfg.max_io_rings; + + conf->iq.num_descs = OCTEP_VF_IQ_MAX_DESCRIPTORS; + conf->iq.instr_type = OCTEP_VF_64BYTE_INSTR; + conf->iq.db_min = OCTEP_VF_DB_MIN; + conf->iq.intr_threshold = OCTEP_VF_IQ_INTR_THRESHOLD; + + conf->oq.num_descs = OCTEP_VF_OQ_MAX_DESCRIPTORS; + conf->oq.buf_size = OCTEP_VF_OQ_BUF_SIZE; + conf->oq.refill_threshold = OCTEP_VF_OQ_REFILL_THRESHOLD; + conf->oq.oq_intr_pkt = OCTEP_VF_OQ_INTR_PKT_THRESHOLD; + conf->oq.oq_intr_time = OCTEP_VF_OQ_INTR_TIME_THRESHOLD; + conf->oq.wmark = OCTEP_VF_OQ_WMARK_MIN; + + conf->msix_cfg.ioq_msix = conf->ring_cfg.active_io_rings; +} + +/* Setup registers for a hardware Tx Queue */ +static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no) +{ +} + +/* Setup registers for a hardware Rx Queue */ +static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) +{ +} + +/* Setup registers for a VF mailbox */ +static void octep_vf_setup_mbox_regs_cnxk(struct octep_vf_device *oct, int q_no) +{ +} + +/* Tx/Rx queue interrupt handler */ +static irqreturn_t octep_vf_ioq_intr_handler_cnxk(void *data) +{ + return IRQ_HANDLED; +} + +/* Re-initialize Octeon hardware registers */ +static void octep_vf_reinit_regs_cnxk(struct octep_vf_device *oct) +{ +} + +/* Enable all interrupts */ +static void octep_vf_enable_interrupts_cnxk(struct octep_vf_device *oct) +{ +} + +/* Disable all interrupts */ +static void octep_vf_disable_interrupts_cnxk(struct octep_vf_device *oct) +{ +} + +/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ +static u32 octep_vf_update_iq_read_index_cnxk(struct octep_vf_iq *iq) +{ + return 0; +} + +/* Enable a hardware Tx Queue */ +static void octep_vf_enable_iq_cnxk(struct octep_vf_device *oct, int iq_no) +{ +} + +/* Enable a hardware Rx Queue */ +static void octep_vf_enable_oq_cnxk(struct octep_vf_device *oct, int oq_no) +{ +} + +/* Enable all hardware Tx/Rx Queues assigned to VF */ +static void octep_vf_enable_io_queues_cnxk(struct octep_vf_device *oct) +{ +} + +/* Disable a hardware Tx Queue assigned to VF */ +static void octep_vf_disable_iq_cnxk(struct octep_vf_device *oct, int iq_no) +{ +} + +/* Disable a hardware Rx Queue assigned to VF */ +static void octep_vf_disable_oq_cnxk(struct octep_vf_device *oct, int oq_no) +{ +} + +/* Disable all hardware Tx/Rx Queues assigned to VF */ +static void octep_vf_disable_io_queues_cnxk(struct octep_vf_device *oct) +{ +} + +/* Dump hardware registers (including Tx/Rx queues) for debugging. */ +static void octep_vf_dump_registers_cnxk(struct octep_vf_device *oct) +{ +} + +/** + * octep_vf_device_setup_cnxk() - Setup Octeon device. + * + * @oct: Octeon device private data structure. + * + * - initialize hardware operations. + * - get target side pcie port number for the device. + * - set initial configuration and max limits. + */ +void octep_vf_device_setup_cnxk(struct octep_vf_device *oct) +{ + oct->hw_ops.setup_iq_regs = octep_vf_setup_iq_regs_cnxk; + oct->hw_ops.setup_oq_regs = octep_vf_setup_oq_regs_cnxk; + oct->hw_ops.setup_mbox_regs = octep_vf_setup_mbox_regs_cnxk; + + oct->hw_ops.ioq_intr_handler = octep_vf_ioq_intr_handler_cnxk; + oct->hw_ops.reinit_regs = octep_vf_reinit_regs_cnxk; + + oct->hw_ops.enable_interrupts = octep_vf_enable_interrupts_cnxk; + oct->hw_ops.disable_interrupts = octep_vf_disable_interrupts_cnxk; + + oct->hw_ops.update_iq_read_idx = octep_vf_update_iq_read_index_cnxk; + + oct->hw_ops.enable_iq = octep_vf_enable_iq_cnxk; + oct->hw_ops.enable_oq = octep_vf_enable_oq_cnxk; + oct->hw_ops.enable_io_queues = octep_vf_enable_io_queues_cnxk; + + oct->hw_ops.disable_iq = octep_vf_disable_iq_cnxk; + oct->hw_ops.disable_oq = octep_vf_disable_oq_cnxk; + oct->hw_ops.disable_io_queues = octep_vf_disable_io_queues_cnxk; + oct->hw_ops.reset_io_queues = octep_vf_reset_io_queues_cnxk; + + oct->hw_ops.dump_registers = octep_vf_dump_registers_cnxk; + octep_vf_init_config_cnxk_vf(oct); +} diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_config.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_config.h new file mode 100644 index 000000000000..e03a647b0110 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_config.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#ifndef _OCTEP_VF_CONFIG_H_ +#define _OCTEP_VF_CONFIG_H_ + +/* Tx instruction types by length */ +#define OCTEP_VF_32BYTE_INSTR 32 +#define OCTEP_VF_64BYTE_INSTR 64 + +/* Tx Queue: maximum descriptors per ring */ +#define OCTEP_VF_IQ_MAX_DESCRIPTORS 1024 +/* Minimum input (Tx) requests to be enqueued to ring doorbell */ +#define OCTEP_VF_DB_MIN 8 +/* Packet threshold for Tx queue interrupt */ +#define OCTEP_VF_IQ_INTR_THRESHOLD 0x0 + +/* Minimum watermark for backpressure */ +#define OCTEP_VF_OQ_WMARK_MIN 256 + +/* Rx Queue: maximum descriptors per ring */ +#define OCTEP_VF_OQ_MAX_DESCRIPTORS 1024 + +/* Rx buffer size: Use page size buffers. + * Build skb from allocated page buffer once the packet is received. + * When a gathered packet is received, make head page as skb head and + * page buffers in consecutive Rx descriptors as fragments. + */ +#define OCTEP_VF_OQ_BUF_SIZE (SKB_WITH_OVERHEAD(PAGE_SIZE)) +#define OCTEP_VF_OQ_PKTS_PER_INTR 128 +#define OCTEP_VF_OQ_REFILL_THRESHOLD (OCTEP_VF_OQ_MAX_DESCRIPTORS / 4) + +#define OCTEP_VF_OQ_INTR_PKT_THRESHOLD 1 +#define OCTEP_VF_OQ_INTR_TIME_THRESHOLD 10 + +#define OCTEP_VF_MSIX_NAME_SIZE (IFNAMSIZ + 32) + +/* Tx Queue wake threshold + * wakeup a stopped Tx queue if minimum 2 descriptors are available. + * Even a skb with fragments consume only one Tx queue descriptor entry. + */ +#define OCTEP_VF_WAKE_QUEUE_THRESHOLD 2 + +/* Minimum MTU supported by Octeon network interface */ +#define OCTEP_VF_MIN_MTU ETH_MIN_MTU +/* Maximum MTU supported by Octeon interface*/ +#define OCTEP_VF_MAX_MTU (10000 - (ETH_HLEN + ETH_FCS_LEN)) +/* Default MTU */ +#define OCTEP_VF_DEFAULT_MTU 1500 + +/* Macros to get octeon config params */ +#define CFG_GET_IQ_CFG(cfg) ((cfg)->iq) +#define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs) +#define CFG_GET_IQ_INSTR_TYPE(cfg) ((cfg)->iq.instr_type) +#define CFG_GET_IQ_INSTR_SIZE(cfg) (64) +#define CFG_GET_IQ_DB_MIN(cfg) ((cfg)->iq.db_min) +#define CFG_GET_IQ_INTR_THRESHOLD(cfg) ((cfg)->iq.intr_threshold) + +#define CFG_GET_OQ_NUM_DESC(cfg) ((cfg)->oq.num_descs) +#define CFG_GET_OQ_BUF_SIZE(cfg) ((cfg)->oq.buf_size) +#define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold) +#define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt) +#define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time) +#define CFG_GET_OQ_WMARK(cfg) ((cfg)->oq.wmark) + +#define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->ring_cfg.active_io_rings) +#define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->ring_cfg.max_io_rings) + +#define CFG_GET_CORE_TICS_PER_US(cfg) ((cfg)->core_cfg.core_tics_per_us) +#define CFG_GET_COPROC_TICS_PER_US(cfg) ((cfg)->core_cfg.coproc_tics_per_us) + +#define CFG_GET_IOQ_MSIX(cfg) ((cfg)->msix_cfg.ioq_msix) + +/* Hardware Tx Queue configuration. */ +struct octep_vf_iq_config { + /* Size of the Input queue (number of commands) */ + u16 num_descs; + + /* Command size - 32 or 64 bytes */ + u16 instr_type; + + /* Minimum number of commands pending to be posted to Octeon before driver + * hits the Input queue doorbell. + */ + u16 db_min; + + /* Trigger the IQ interrupt when processed cmd count reaches + * this level. + */ + u32 intr_threshold; +}; + +/* Hardware Rx Queue configuration. */ +struct octep_vf_oq_config { + /* Size of Output queue (number of descriptors) */ + u16 num_descs; + + /* Size of buffer in this Output queue. */ + u16 buf_size; + + /* The number of buffers that were consumed during packet processing + * by the driver on this Output queue before the driver attempts to + * replenish the descriptor ring with new buffers. + */ + u16 refill_threshold; + + /* Interrupt Coalescing (Packet Count). Octeon will interrupt the host + * only if it sent as many packets as specified by this field. + * The driver usually does not use packet count interrupt coalescing. + */ + u32 oq_intr_pkt; + + /* Interrupt Coalescing (Time Interval). Octeon will interrupt the host + * if at least one packet was sent in the time interval specified by + * this field. The driver uses time interval interrupt coalescing by + * default. The time is specified in microseconds. + */ + u32 oq_intr_time; + + /* Water mark for backpressure. + * Output queue sends backpressure signal to source when + * free buffer count falls below wmark. + */ + u32 wmark; +}; + +/* Tx/Rx configuration */ +struct octep_vf_ring_config { + /* Max number of IOQs */ + u16 max_io_rings; + + /* Number of active IOQs */ + u16 active_io_rings; +}; + +/* Octeon MSI-x config. */ +struct octep_vf_msix_config { + /* Number of IOQ interrupts */ + u16 ioq_msix; +}; + +/* Data Structure to hold configuration limits and active config */ +struct octep_vf_config { + /* Input Queue attributes. */ + struct octep_vf_iq_config iq; + + /* Output Queue attributes. */ + struct octep_vf_oq_config oq; + + /* MSI-X interrupt config */ + struct octep_vf_msix_config msix_cfg; + + /* NIC VF ring Configuration */ + struct octep_vf_ring_config ring_cfg; +}; +#endif /* _OCTEP_VF_CONFIG_H_ */ diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c new file mode 100644 index 000000000000..2ade88698f65 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "octep_vf_config.h" +#include "octep_vf_main.h" + +struct workqueue_struct *octep_vf_wq; + +/* Supported Devices */ +static const struct pci_device_id octep_vf_pci_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN93_VF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF95N_VF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN98_VF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KA_VF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KA_VF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KB_VF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KB_VF)}, + {0, }, +}; +MODULE_DEVICE_TABLE(pci, octep_vf_pci_id_tbl); + +MODULE_AUTHOR("Veerasenareddy Burru "); +MODULE_DESCRIPTION(OCTEP_VF_DRV_STRING); +MODULE_LICENSE("GPL"); + +static void octep_vf_link_up(struct net_device *netdev) +{ + netif_carrier_on(netdev); + netif_tx_start_all_queues(netdev); +} + +static void octep_vf_set_rx_state(struct octep_vf_device *oct, bool up) +{ + int err; + + err = octep_vf_mbox_set_rx_state(oct, up); + if (err) + netdev_err(oct->netdev, "Set Rx state to %d failed with err:%d\n", up, err); +} + +static int octep_vf_get_link_status(struct octep_vf_device *oct) +{ + int err; + + err = octep_vf_mbox_get_link_status(oct, &oct->link_info.oper_up); + if (err) + netdev_err(oct->netdev, "Get link status failed with err:%d\n", err); + return oct->link_info.oper_up; +} + +static void octep_vf_set_link_status(struct octep_vf_device *oct, bool up) +{ + int err; + + err = octep_vf_mbox_set_link_status(oct, up); + if (err) { + netdev_err(oct->netdev, "Set link status to %d failed with err:%d\n", up, err); + return; + } + oct->link_info.oper_up = up; +} + +/** + * octep_vf_open() - start the octeon network device. + * + * @netdev: pointer to kernel network device. + * + * setup Tx/Rx queues, interrupts and enable hardware operation of Tx/Rx queues + * and interrupts.. + * + * Return: 0, on successfully setting up device and bring it up. + * -1, on any error. + */ +static int octep_vf_open(struct net_device *netdev) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + int err, ret; + + netdev_info(netdev, "Starting netdev ...\n"); + netif_carrier_off(netdev); + + oct->hw_ops.reset_io_queues(oct); + + if (octep_vf_setup_iqs(oct)) + goto setup_iq_err; + if (octep_vf_setup_oqs(oct)) + goto setup_oq_err; + + err = netif_set_real_num_tx_queues(netdev, oct->num_oqs); + if (err) + goto set_queues_err; + err = netif_set_real_num_rx_queues(netdev, oct->num_iqs); + if (err) + goto set_queues_err; + + oct->link_info.admin_up = 1; + octep_vf_set_rx_state(oct, true); + + ret = octep_vf_get_link_status(oct); + if (!ret) + octep_vf_set_link_status(oct, true); + + /* Enable the input and output queues for this Octeon device */ + oct->hw_ops.enable_io_queues(oct); + + /* Enable Octeon device interrupts */ + oct->hw_ops.enable_interrupts(oct); + + octep_vf_oq_dbell_init(oct); + + ret = octep_vf_get_link_status(oct); + if (ret) + octep_vf_link_up(netdev); + + return 0; + +set_queues_err: + octep_vf_free_oqs(oct); +setup_oq_err: + octep_vf_free_iqs(oct); +setup_iq_err: + return -1; +} + +/** + * octep_vf_stop() - stop the octeon network device. + * + * @netdev: pointer to kernel network device. + * + * stop the device Tx/Rx operations, bring down the link and + * free up all resources allocated for Tx/Rx queues and interrupts. + */ +static int octep_vf_stop(struct net_device *netdev) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + + netdev_info(netdev, "Stopping the device ...\n"); + + /* Stop Tx from stack */ + netif_carrier_off(netdev); + netif_tx_disable(netdev); + + octep_vf_set_link_status(oct, false); + octep_vf_set_rx_state(oct, false); + + oct->link_info.admin_up = 0; + oct->link_info.oper_up = 0; + + oct->hw_ops.disable_interrupts(oct); + + octep_vf_clean_iqs(oct); + + oct->hw_ops.disable_io_queues(oct); + oct->hw_ops.reset_io_queues(oct); + octep_vf_free_oqs(oct); + octep_vf_free_iqs(oct); + netdev_info(netdev, "Device stopped !!\n"); + return 0; +} + +/** + * octep_vf_start_xmit() - Enqueue packet to Octoen hardware Tx Queue. + * + * @skb: packet skbuff pointer. + * @netdev: kernel network device. + * + * Return: NETDEV_TX_BUSY, if Tx Queue is full. + * NETDEV_TX_OK, if successfully enqueued to hardware Tx queue. + */ +static netdev_tx_t octep_vf_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + return NETDEV_TX_OK; +} + +/** + * octep_vf_tx_timeout_task - work queue task to Handle Tx queue timeout. + * + * @work: pointer to Tx queue timeout work_struct + * + * Stop and start the device so that it frees up all queue resources + * and restarts the queues, that potentially clears a Tx queue timeout + * condition. + **/ +static void octep_vf_tx_timeout_task(struct work_struct *work) +{ + struct octep_vf_device *oct = container_of(work, struct octep_vf_device, + tx_timeout_task); + struct net_device *netdev = oct->netdev; + + rtnl_lock(); + if (netif_running(netdev)) { + octep_vf_stop(netdev); + octep_vf_open(netdev); + } + rtnl_unlock(); + netdev_put(netdev, NULL); +} + +/** + * octep_vf_tx_timeout() - Handle Tx Queue timeout. + * + * @netdev: pointer to kernel network device. + * @txqueue: Timed out Tx queue number. + * + * Schedule a work to handle Tx queue timeout. + */ +static void octep_vf_tx_timeout(struct net_device *netdev, unsigned int txqueue) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + + netdev_hold(netdev, NULL, GFP_ATOMIC); + schedule_work(&oct->tx_timeout_task); +} + +static const struct net_device_ops octep_vf_netdev_ops = { + .ndo_open = octep_vf_open, + .ndo_stop = octep_vf_stop, + .ndo_start_xmit = octep_vf_start_xmit, + .ndo_tx_timeout = octep_vf_tx_timeout, +}; + +static const char *octep_vf_devid_to_str(struct octep_vf_device *oct) +{ + switch (oct->chip_id) { + case OCTEP_PCI_DEVICE_ID_CN93_VF: + return "CN93XX"; + case OCTEP_PCI_DEVICE_ID_CNF95N_VF: + return "CNF95N"; + case OCTEP_PCI_DEVICE_ID_CN10KA_VF: + return "CN10KA"; + case OCTEP_PCI_DEVICE_ID_CNF10KA_VF: + return "CNF10KA"; + case OCTEP_PCI_DEVICE_ID_CNF10KB_VF: + return "CNF10KB"; + case OCTEP_PCI_DEVICE_ID_CN10KB_VF: + return "CN10KB"; + default: + return "Unsupported"; + } +} + +/** + * octep_vf_device_setup() - Setup Octeon Device. + * + * @oct: Octeon device private data structure. + * + * Setup Octeon device hardware operations, configuration, etc ... + */ +int octep_vf_device_setup(struct octep_vf_device *oct) +{ + struct pci_dev *pdev = oct->pdev; + + /* allocate memory for oct->conf */ + oct->conf = kzalloc(sizeof(*oct->conf), GFP_KERNEL); + if (!oct->conf) + return -ENOMEM; + + /* Map BAR region 0 */ + oct->mmio.hw_addr = ioremap(pci_resource_start(oct->pdev, 0), + pci_resource_len(oct->pdev, 0)); + if (!oct->mmio.hw_addr) { + dev_err(&pdev->dev, + "Failed to remap BAR0; start=0x%llx len=0x%llx\n", + pci_resource_start(oct->pdev, 0), + pci_resource_len(oct->pdev, 0)); + goto ioremap_err; + } + oct->mmio.mapped = 1; + + oct->chip_id = pdev->device; + oct->rev_id = pdev->revision; + dev_info(&pdev->dev, "chip_id = 0x%x\n", pdev->device); + + switch (oct->chip_id) { + case OCTEP_PCI_DEVICE_ID_CN93_VF: + case OCTEP_PCI_DEVICE_ID_CNF95N_VF: + case OCTEP_PCI_DEVICE_ID_CN98_VF: + dev_info(&pdev->dev, "Setting up OCTEON %s VF PASS%d.%d\n", + octep_vf_devid_to_str(oct), OCTEP_VF_MAJOR_REV(oct), + OCTEP_VF_MINOR_REV(oct)); + octep_vf_device_setup_cn93(oct); + break; + case OCTEP_PCI_DEVICE_ID_CNF10KA_VF: + case OCTEP_PCI_DEVICE_ID_CN10KA_VF: + case OCTEP_PCI_DEVICE_ID_CNF10KB_VF: + case OCTEP_PCI_DEVICE_ID_CN10KB_VF: + dev_info(&pdev->dev, "Setting up OCTEON %s VF PASS%d.%d\n", + octep_vf_devid_to_str(oct), OCTEP_VF_MAJOR_REV(oct), + OCTEP_VF_MINOR_REV(oct)); + octep_vf_device_setup_cnxk(oct); + break; + default: + dev_err(&pdev->dev, "Unsupported device\n"); + goto unsupported_dev; + } + + return 0; + +unsupported_dev: + iounmap(oct->mmio.hw_addr); +ioremap_err: + kfree(oct->conf); + return -EOPNOTSUPP; +} + +/** + * octep_vf_device_cleanup() - Cleanup Octeon Device. + * + * @oct: Octeon device private data structure. + * + * Cleanup Octeon device allocated resources. + */ +static void octep_vf_device_cleanup(struct octep_vf_device *oct) +{ + dev_info(&oct->pdev->dev, "Cleaning up Octeon Device ...\n"); + + if (oct->mmio.mapped) + iounmap(oct->mmio.hw_addr); + + kfree(oct->conf); + oct->conf = NULL; +} + +static int octep_vf_get_mac_addr(struct octep_vf_device *oct, u8 *addr) +{ + return octep_vf_mbox_get_mac_addr(oct, addr); +} + +/** + * octep_vf_probe() - Octeon PCI device probe handler. + * + * @pdev: PCI device structure. + * @ent: entry in Octeon PCI device ID table. + * + * Initializes and enables the Octeon PCI device for network operations. + * Initializes Octeon private data structure and registers a network device. + */ +static int octep_vf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct octep_vf_device *octep_vf_dev; + struct net_device *netdev; + int err; + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable PCI device\n"); + return err; + } + + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "Failed to set DMA mask !!\n"); + goto disable_pci_device; + } + + err = pci_request_mem_regions(pdev, OCTEP_VF_DRV_NAME); + if (err) { + dev_err(&pdev->dev, "Failed to map PCI memory regions\n"); + goto disable_pci_device; + } + + pci_set_master(pdev); + + netdev = alloc_etherdev_mq(sizeof(struct octep_vf_device), + OCTEP_VF_MAX_QUEUES); + if (!netdev) { + dev_err(&pdev->dev, "Failed to allocate netdev\n"); + err = -ENOMEM; + goto mem_regions_release; + } + SET_NETDEV_DEV(netdev, &pdev->dev); + + octep_vf_dev = netdev_priv(netdev); + octep_vf_dev->netdev = netdev; + octep_vf_dev->pdev = pdev; + octep_vf_dev->dev = &pdev->dev; + pci_set_drvdata(pdev, octep_vf_dev); + + err = octep_vf_device_setup(octep_vf_dev); + if (err) { + dev_err(&pdev->dev, "Device setup failed\n"); + goto netdevice_free; + } + INIT_WORK(&octep_vf_dev->tx_timeout_task, octep_vf_tx_timeout_task); + + netdev->netdev_ops = &octep_vf_netdev_ops; + netif_carrier_off(netdev); + + if (octep_vf_setup_mbox(octep_vf_dev)) { + dev_err(&pdev->dev, "VF Mailbox setup failed\n"); + err = -ENOMEM; + goto device_cleanup; + } + + if (octep_vf_mbox_version_check(octep_vf_dev)) { + dev_err(&pdev->dev, "PF VF Mailbox version mismatch\n"); + err = -EINVAL; + goto delete_mbox; + } + + netdev->hw_features = NETIF_F_SG; + netdev->min_mtu = OCTEP_VF_MIN_MTU; + netdev->max_mtu = OCTEP_VF_MAX_MTU; + netdev->mtu = OCTEP_VF_DEFAULT_MTU; + + netdev->features |= netdev->hw_features; + octep_vf_get_mac_addr(octep_vf_dev, octep_vf_dev->mac_addr); + eth_hw_addr_set(netdev, octep_vf_dev->mac_addr); + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "Failed to register netdev\n"); + goto delete_mbox; + } + dev_info(&pdev->dev, "Device probe successful\n"); + return 0; + +delete_mbox: + octep_vf_delete_mbox(octep_vf_dev); +device_cleanup: + octep_vf_device_cleanup(octep_vf_dev); +netdevice_free: + free_netdev(netdev); +mem_regions_release: + pci_release_mem_regions(pdev); +disable_pci_device: + pci_disable_device(pdev); + dev_err(&pdev->dev, "Device probe failed\n"); + return err; +} + +/** + * octep_vf_remove() - Remove Octeon PCI device from driver control. + * + * @pdev: PCI device structure of the Octeon device. + * + * Cleanup all resources allocated for the Octeon device. + * Unregister from network device and disable the PCI device. + */ +static void octep_vf_remove(struct pci_dev *pdev) +{ + struct octep_vf_device *oct = pci_get_drvdata(pdev); + struct net_device *netdev; + + if (!oct) + return; + + octep_vf_mbox_dev_remove(oct); + cancel_work_sync(&oct->tx_timeout_task); + netdev = oct->netdev; + if (netdev->reg_state == NETREG_REGISTERED) + unregister_netdev(netdev); + octep_vf_delete_mbox(oct); + octep_vf_device_cleanup(oct); + pci_release_mem_regions(pdev); + free_netdev(netdev); + pci_disable_device(pdev); +} + +static struct pci_driver octep_vf_driver = { + .name = OCTEP_VF_DRV_NAME, + .id_table = octep_vf_pci_id_tbl, + .probe = octep_vf_probe, + .remove = octep_vf_remove, +}; + +/** + * octep_vf_init_module() - Module initialization. + * + * create common resource for the driver and register PCI driver. + */ +static int __init octep_vf_init_module(void) +{ + int ret; + + pr_info("%s: Loading %s ...\n", OCTEP_VF_DRV_NAME, OCTEP_VF_DRV_STRING); + + ret = pci_register_driver(&octep_vf_driver); + if (ret < 0) { + pr_err("%s: Failed to register PCI driver; err=%d\n", + OCTEP_VF_DRV_NAME, ret); + return ret; + } + + return ret; +} + +/** + * octep_vf_exit_module() - Module exit routine. + * + * unregister the driver with PCI subsystem and cleanup common resources. + */ +static void __exit octep_vf_exit_module(void) +{ + pr_info("%s: Unloading ...\n", OCTEP_VF_DRV_NAME); + + pci_unregister_driver(&octep_vf_driver); + + pr_info("%s: Unloading complete\n", OCTEP_VF_DRV_NAME); +} + +module_init(octep_vf_init_module); +module_exit(octep_vf_exit_module); diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h new file mode 100644 index 000000000000..4359e0e585ec --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h @@ -0,0 +1,331 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#ifndef _OCTEP_VF_MAIN_H_ +#define _OCTEP_VF_MAIN_H_ + +#include "octep_vf_tx.h" +#include "octep_vf_rx.h" +#include "octep_vf_mbox.h" + +#define OCTEP_VF_DRV_NAME "octeon_ep_vf" +#define OCTEP_VF_DRV_STRING "Marvell Octeon EndPoint NIC VF Driver" + +#define OCTEP_PCI_DEVICE_ID_CN93_VF 0xB203 //93xx VF +#define OCTEP_PCI_DEVICE_ID_CNF95N_VF 0xB403 //95N VF +#define OCTEP_PCI_DEVICE_ID_CN98_VF 0xB103 +#define OCTEP_PCI_DEVICE_ID_CN10KA_VF 0xB903 +#define OCTEP_PCI_DEVICE_ID_CNF10KA_VF 0xBA03 +#define OCTEP_PCI_DEVICE_ID_CNF10KB_VF 0xBC03 +#define OCTEP_PCI_DEVICE_ID_CN10KB_VF 0xBD03 + +#define OCTEP_VF_MAX_QUEUES 63 +#define OCTEP_VF_MAX_IQ OCTEP_VF_MAX_QUEUES +#define OCTEP_VF_MAX_OQ OCTEP_VF_MAX_QUEUES + +#define OCTEP_VF_MAX_MSIX_VECTORS OCTEP_VF_MAX_OQ + +#define OCTEP_VF_IQ_INTR_RESEND_BIT 59 +#define OCTEP_VF_OQ_INTR_RESEND_BIT 59 + +#define IQ_INSTR_PENDING(iq) ({ typeof(iq) iq__ = (iq); \ + ((iq__)->host_write_index - (iq__)->flush_index) & \ + (iq__)->ring_size_mask; \ + }) +#define IQ_INSTR_SPACE(iq) ({ typeof(iq) iq_ = (iq); \ + (iq_)->max_count - IQ_INSTR_PENDING(iq_); \ + }) + +/* PCI address space mapping information. + * Each of the 3 address spaces given by BAR0, BAR2 and BAR4 of + * Octeon gets mapped to different physical address spaces in + * the kernel. + */ +struct octep_vf_mmio { + /* The physical address to which the PCI address space is mapped. */ + u8 __iomem *hw_addr; + + /* Flag indicating the mapping was successful. */ + int mapped; +}; + +struct octep_vf_hw_ops { + void (*setup_iq_regs)(struct octep_vf_device *oct, int q); + void (*setup_oq_regs)(struct octep_vf_device *oct, int q); + void (*setup_mbox_regs)(struct octep_vf_device *oct, int mbox); + + irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector); + irqreturn_t (*ioq_intr_handler)(void *ioq_vector); + void (*reinit_regs)(struct octep_vf_device *oct); + u32 (*update_iq_read_idx)(struct octep_vf_iq *iq); + + void (*enable_interrupts)(struct octep_vf_device *oct); + void (*disable_interrupts)(struct octep_vf_device *oct); + + void (*enable_io_queues)(struct octep_vf_device *oct); + void (*disable_io_queues)(struct octep_vf_device *oct); + void (*enable_iq)(struct octep_vf_device *oct, int q); + void (*disable_iq)(struct octep_vf_device *oct, int q); + void (*enable_oq)(struct octep_vf_device *oct, int q); + void (*disable_oq)(struct octep_vf_device *oct, int q); + void (*reset_io_queues)(struct octep_vf_device *oct); + void (*dump_registers)(struct octep_vf_device *oct); +}; + +/* Octeon mailbox data */ +struct octep_vf_mbox_data { + /* Holds the offset of received data via mailbox. */ + u32 data_index; + + /* Holds the received data via mailbox. */ + u8 recv_data[OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE]; +}; + +/* wrappers around work structs */ +struct octep_vf_mbox_wk { + struct work_struct work; + void *ctxptr; +}; + +/* Octeon device mailbox */ +struct octep_vf_mbox { + /* A mutex to protect access to this q_mbox. */ + struct mutex lock; + + u32 state; + + /* SLI_MAC_PF_MBOX_INT for PF, SLI_PKT_MBOX_INT for VF. */ + u8 __iomem *mbox_int_reg; + + /* SLI_PKT_PF_VF_MBOX_SIG(0) for PF, + * SLI_PKT_PF_VF_MBOX_SIG(1) for VF. + */ + u8 __iomem *mbox_write_reg; + + /* SLI_PKT_PF_VF_MBOX_SIG(1) for PF, + * SLI_PKT_PF_VF_MBOX_SIG(0) for VF. + */ + u8 __iomem *mbox_read_reg; + + /* Octeon mailbox data */ + struct octep_vf_mbox_data mbox_data; + + /* Octeon mailbox work handler to process Mbox messages */ + struct octep_vf_mbox_wk wk; +}; + +/* Tx/Rx queue vector per interrupt. */ +struct octep_vf_ioq_vector { + char name[OCTEP_VF_MSIX_NAME_SIZE]; + struct napi_struct napi; + struct octep_vf_device *octep_vf_dev; + struct octep_vf_iq *iq; + struct octep_vf_oq *oq; + cpumask_t affinity_mask; +}; + +/* Octeon hardware/firmware offload capability flags. */ +#define OCTEP_VF_CAP_TX_CHECKSUM BIT(0) +#define OCTEP_VF_CAP_RX_CHECKSUM BIT(1) +#define OCTEP_VF_CAP_TSO BIT(2) + +/* Link modes */ +enum octep_vf_link_mode_bit_indices { + OCTEP_VF_LINK_MODE_10GBASE_T = 0, + OCTEP_VF_LINK_MODE_10GBASE_R, + OCTEP_VF_LINK_MODE_10GBASE_CR, + OCTEP_VF_LINK_MODE_10GBASE_KR, + OCTEP_VF_LINK_MODE_10GBASE_LR, + OCTEP_VF_LINK_MODE_10GBASE_SR, + OCTEP_VF_LINK_MODE_25GBASE_CR, + OCTEP_VF_LINK_MODE_25GBASE_KR, + OCTEP_VF_LINK_MODE_25GBASE_SR, + OCTEP_VF_LINK_MODE_40GBASE_CR4, + OCTEP_VF_LINK_MODE_40GBASE_KR4, + OCTEP_VF_LINK_MODE_40GBASE_LR4, + OCTEP_VF_LINK_MODE_40GBASE_SR4, + OCTEP_VF_LINK_MODE_50GBASE_CR2, + OCTEP_VF_LINK_MODE_50GBASE_KR2, + OCTEP_VF_LINK_MODE_50GBASE_SR2, + OCTEP_VF_LINK_MODE_50GBASE_CR, + OCTEP_VF_LINK_MODE_50GBASE_KR, + OCTEP_VF_LINK_MODE_50GBASE_LR, + OCTEP_VF_LINK_MODE_50GBASE_SR, + OCTEP_VF_LINK_MODE_100GBASE_CR4, + OCTEP_VF_LINK_MODE_100GBASE_KR4, + OCTEP_VF_LINK_MODE_100GBASE_LR4, + OCTEP_VF_LINK_MODE_100GBASE_SR4, + OCTEP_VF_LINK_MODE_NBITS +}; + +/* Hardware interface link state information. */ +struct octep_vf_iface_link_info { + /* Bitmap of Supported link speeds/modes. */ + u64 supported_modes; + + /* Bitmap of Advertised link speeds/modes. */ + u64 advertised_modes; + + /* Negotiated link speed in Mbps. */ + u32 speed; + + /* MTU */ + u16 mtu; + + /* Autonegotiation state. */ +#define OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED BIT(0) +#define OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED BIT(1) + u8 autoneg; + + /* Pause frames setting. */ +#define OCTEP_VF_LINK_MODE_PAUSE_SUPPORTED BIT(0) +#define OCTEP_VF_LINK_MODE_PAUSE_ADVERTISED BIT(1) + u8 pause; + + /* Admin state of the link (ifconfig up/down */ + u8 admin_up; + + /* Operational state of the link: physical link is up down */ + u8 oper_up; +}; + +/* Hardware interface stats information. */ +struct octep_vf_iface_rxtx_stats { + /* Hardware Interface Rx statistics */ + struct octep_vf_iface_rx_stats iface_rx_stats; + + /* Hardware Interface Tx statistics */ + struct octep_vf_iface_tx_stats iface_tx_stats; +}; + +struct octep_vf_fw_info { + /* pkind value to be used in every Tx hardware descriptor */ + u8 pkind; + /* front size data */ + u8 fsz; + /* supported rx offloads OCTEP_VF_RX_OFFLOAD_* */ + u16 rx_ol_flags; + /* supported tx offloads OCTEP_VF_TX_OFFLOAD_* */ + u16 tx_ol_flags; +}; + +/* The Octeon device specific private data structure. + * Each Octeon device has this structure to represent all its components. + */ +struct octep_vf_device { + struct octep_vf_config *conf; + + /* Octeon Chip type. */ + u16 chip_id; + u16 rev_id; + + /* Device capabilities enabled */ + u64 caps_enabled; + /* Device capabilities supported */ + u64 caps_supported; + + /* Pointer to basic Linux device */ + struct device *dev; + /* Linux PCI device pointer */ + struct pci_dev *pdev; + /* Netdev corresponding to the Octeon device */ + struct net_device *netdev; + + /* memory mapped io range */ + struct octep_vf_mmio mmio; + + /* MAC address */ + u8 mac_addr[ETH_ALEN]; + + /* Tx queues (IQ: Instruction Queue) */ + u16 num_iqs; + /* Pointers to Octeon Tx queues */ + struct octep_vf_iq *iq[OCTEP_VF_MAX_IQ]; + + /* Rx queues (OQ: Output Queue) */ + u16 num_oqs; + /* Pointers to Octeon Rx queues */ + struct octep_vf_oq *oq[OCTEP_VF_MAX_OQ]; + + /* Hardware port number of the PCIe interface */ + u16 pcie_port; + + /* Hardware operations */ + struct octep_vf_hw_ops hw_ops; + + /* IRQ info */ + u16 num_irqs; + u16 num_non_ioq_irqs; + char *non_ioq_irq_names; + struct msix_entry *msix_entries; + /* IOq information of it's corresponding MSI-X interrupt. */ + struct octep_vf_ioq_vector *ioq_vector[OCTEP_VF_MAX_QUEUES]; + + /* Hardware Interface Tx statistics */ + struct octep_vf_iface_tx_stats iface_tx_stats; + /* Hardware Interface Rx statistics */ + struct octep_vf_iface_rx_stats iface_rx_stats; + + /* Hardware Interface Link info like supported modes, aneg support */ + struct octep_vf_iface_link_info link_info; + + /* Mailbox to talk to VFs */ + struct octep_vf_mbox *mbox; + + /* Work entry to handle Tx timeout */ + struct work_struct tx_timeout_task; + + /* offset for iface stats */ + u32 ctrl_mbox_ifstats_offset; + + /* Negotiated Mbox version */ + u32 mbox_neg_ver; + + /* firmware info */ + struct octep_vf_fw_info fw_info; +}; + +static inline u16 OCTEP_VF_MAJOR_REV(struct octep_vf_device *oct) +{ + u16 rev = (oct->rev_id & 0xC) >> 2; + + return (rev == 0) ? 1 : rev; +} + +static inline u16 OCTEP_VF_MINOR_REV(struct octep_vf_device *oct) +{ + return (oct->rev_id & 0x3); +} + +/* Octeon CSR read/write access APIs */ +#define octep_vf_write_csr(octep_vf_dev, reg_off, value) \ + writel(value, (octep_vf_dev)->mmio.hw_addr + (reg_off)) + +#define octep_vf_write_csr64(octep_vf_dev, reg_off, val64) \ + writeq(val64, (octep_vf_dev)->mmio.hw_addr + (reg_off)) + +#define octep_vf_read_csr(octep_vf_dev, reg_off) \ + readl((octep_vf_dev)->mmio.hw_addr + (reg_off)) + +#define octep_vf_read_csr64(octep_vf_dev, reg_off) \ + readq((octep_vf_dev)->mmio.hw_addr + (reg_off)) + +extern struct workqueue_struct *octep_vf_wq; + +int octep_vf_device_setup(struct octep_vf_device *oct); +int octep_vf_setup_iqs(struct octep_vf_device *oct); +void octep_vf_free_iqs(struct octep_vf_device *oct); +void octep_vf_clean_iqs(struct octep_vf_device *oct); +int octep_vf_setup_oqs(struct octep_vf_device *oct); +void octep_vf_free_oqs(struct octep_vf_device *oct); +void octep_vf_oq_dbell_init(struct octep_vf_device *oct); +void octep_vf_device_setup_cn93(struct octep_vf_device *oct); +void octep_vf_device_setup_cnxk(struct octep_vf_device *oct); +int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget); +int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget); +void octep_vf_mbox_work(struct work_struct *work); +#endif /* _OCTEP_VF_MAIN_H_ */ diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c new file mode 100644 index 000000000000..1c1fe293fc50 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ +#include +#include +#include +#include "octep_vf_config.h" +#include "octep_vf_main.h" + +int octep_vf_setup_mbox(struct octep_vf_device *oct) +{ + int ring = 0; + + oct->mbox = vzalloc(sizeof(*oct->mbox)); + if (!oct->mbox) + return -1; + + mutex_init(&oct->mbox->lock); + + oct->hw_ops.setup_mbox_regs(oct, ring); + INIT_WORK(&oct->mbox->wk.work, octep_vf_mbox_work); + oct->mbox->wk.ctxptr = oct; + dev_info(&oct->pdev->dev, "setup vf mbox successfully\n"); + return 0; +} + +void octep_vf_delete_mbox(struct octep_vf_device *oct) +{ + if (oct->mbox) { + if (work_pending(&oct->mbox->wk.work)) + cancel_work_sync(&oct->mbox->wk.work); + + mutex_destroy(&oct->mbox->lock); + vfree(oct->mbox); + oct->mbox = NULL; + dev_info(&oct->pdev->dev, "Deleted vf mbox successfully\n"); + } +} + +int octep_vf_mbox_version_check(struct octep_vf_device *oct) +{ + return 0; +} + +void octep_vf_mbox_work(struct work_struct *work) +{ +} + +int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu) +{ + return 0; +} + +int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr) +{ + return 0; +} + +int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr) +{ + return 0; +} + +int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state) +{ + return 0; +} + +int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status) +{ + return 0; +} + +int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up) +{ + return 0; +} + +int octep_vf_mbox_dev_remove(struct octep_vf_device *oct) +{ + return 0; +} + +int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct) +{ + return 0; +} + +int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads, + u16 rx_offloads) +{ + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h new file mode 100644 index 000000000000..14f4fb19445b --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ +#ifndef _OCTEP_VF_MBOX_H_ +#define _OCTEP_VF_MBOX_H_ + +#define OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE 256 + +int octep_vf_setup_mbox(struct octep_vf_device *oct); +void octep_vf_delete_mbox(struct octep_vf_device *oct); +int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu); +int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr); +int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr); +int octep_vf_mbox_version_check(struct octep_vf_device *oct); +int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state); +int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status); +int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up); +int octep_vf_mbox_dev_remove(struct octep_vf_device *oct); +int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct); +int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads, u16 rx_offloads); + +#endif diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cn9k.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cn9k.h new file mode 100644 index 000000000000..25e2a876ebba --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cn9k.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ +#ifndef _OCTEP_VF_REGS_CN9K_H_ +#define _OCTEP_VF_REGS_CN9K_H_ + +/*############################ RST #########################*/ +#define CN93_VF_CONFIG_XPANSION_BAR 0x38 +#define CN93_VF_CONFIG_PCIE_CAP 0x70 +#define CN93_VF_CONFIG_PCIE_DEVCAP 0x74 +#define CN93_VF_CONFIG_PCIE_DEVCTL 0x78 +#define CN93_VF_CONFIG_PCIE_LINKCAP 0x7C +#define CN93_VF_CONFIG_PCIE_LINKCTL 0x80 +#define CN93_VF_CONFIG_PCIE_SLOTCAP 0x84 +#define CN93_VF_CONFIG_PCIE_SLOTCTL 0x88 + +#define CN93_VF_RING_OFFSET BIT_ULL(17) + +/*###################### RING IN REGISTERS #########################*/ +#define CN93_VF_SDP_R_IN_CONTROL_START 0x10000 +#define CN93_VF_SDP_R_IN_ENABLE_START 0x10010 +#define CN93_VF_SDP_R_IN_INSTR_BADDR_START 0x10020 +#define CN93_VF_SDP_R_IN_INSTR_RSIZE_START 0x10030 +#define CN93_VF_SDP_R_IN_INSTR_DBELL_START 0x10040 +#define CN93_VF_SDP_R_IN_CNTS_START 0x10050 +#define CN93_VF_SDP_R_IN_INT_LEVELS_START 0x10060 +#define CN93_VF_SDP_R_IN_PKT_CNT_START 0x10080 +#define CN93_VF_SDP_R_IN_BYTE_CNT_START 0x10090 + +#define CN93_VF_SDP_R_IN_CONTROL(ring) \ + (CN93_VF_SDP_R_IN_CONTROL_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_ENABLE(ring) \ + (CN93_VF_SDP_R_IN_ENABLE_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_INSTR_BADDR(ring) \ + (CN93_VF_SDP_R_IN_INSTR_BADDR_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_INSTR_RSIZE(ring) \ + (CN93_VF_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_INSTR_DBELL(ring) \ + (CN93_VF_SDP_R_IN_INSTR_DBELL_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_CNTS(ring) \ + (CN93_VF_SDP_R_IN_CNTS_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_INT_LEVELS(ring) \ + (CN93_VF_SDP_R_IN_INT_LEVELS_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_PKT_CNT(ring) \ + (CN93_VF_SDP_R_IN_PKT_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_IN_BYTE_CNT(ring) \ + (CN93_VF_SDP_R_IN_BYTE_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) + +/*------------------ R_IN Masks ----------------*/ + +/** Rings per Virtual Function **/ +#define CN93_VF_R_IN_CTL_RPVF_MASK (0xF) +#define CN93_VF_R_IN_CTL_RPVF_POS (48) + +/* Number of instructions to be read in one MAC read request. + * setting to Max value(4) + **/ +#define CN93_VF_R_IN_CTL_IDLE BIT_ULL(28) +#define CN93_VF_R_IN_CTL_RDSIZE (0x3ULL << 25) +#define CN93_VF_R_IN_CTL_IS_64B BIT_ULL(24) +#define CN93_VF_R_IN_CTL_D_NSR BIT_ULL(8) +#define CN93_VF_R_IN_CTL_D_ESR BIT_ULL(6) +#define CN93_VF_R_IN_CTL_D_ROR BIT_ULL(5) +#define CN93_VF_R_IN_CTL_NSR BIT_ULL(3) +#define CN93_VF_R_IN_CTL_ESR BIT_ULL(1) +#define CN93_VF_R_IN_CTL_ROR BIT_ULL(0) + +#define CN93_VF_R_IN_CTL_MASK (CN93_VF_R_IN_CTL_RDSIZE | CN93_VF_R_IN_CTL_IS_64B) + +/*###################### RING OUT REGISTERS #########################*/ +#define CN93_VF_SDP_R_OUT_CNTS_START 0x10100 +#define CN93_VF_SDP_R_OUT_INT_LEVELS_START 0x10110 +#define CN93_VF_SDP_R_OUT_SLIST_BADDR_START 0x10120 +#define CN93_VF_SDP_R_OUT_SLIST_RSIZE_START 0x10130 +#define CN93_VF_SDP_R_OUT_SLIST_DBELL_START 0x10140 +#define CN93_VF_SDP_R_OUT_CONTROL_START 0x10150 +#define CN93_VF_SDP_R_OUT_ENABLE_START 0x10160 +#define CN93_VF_SDP_R_OUT_PKT_CNT_START 0x10180 +#define CN93_VF_SDP_R_OUT_BYTE_CNT_START 0x10190 + +#define CN93_VF_SDP_R_OUT_CONTROL(ring) \ + (CN93_VF_SDP_R_OUT_CONTROL_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_ENABLE(ring) \ + (CN93_VF_SDP_R_OUT_ENABLE_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_SLIST_BADDR(ring) \ + (CN93_VF_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_SLIST_RSIZE(ring) \ + (CN93_VF_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_SLIST_DBELL(ring) \ + (CN93_VF_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_CNTS(ring) \ + (CN93_VF_SDP_R_OUT_CNTS_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_INT_LEVELS(ring) \ + (CN93_VF_SDP_R_OUT_INT_LEVELS_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_PKT_CNT(ring) \ + (CN93_VF_SDP_R_OUT_PKT_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_OUT_BYTE_CNT(ring) \ + (CN93_VF_SDP_R_OUT_BYTE_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) + +/*------------------ R_OUT Masks ----------------*/ +#define CN93_VF_R_OUT_INT_LEVELS_BMODE BIT_ULL(63) +#define CN93_VF_R_OUT_INT_LEVELS_TIMET (32) + +#define CN93_VF_R_OUT_CTL_IDLE BIT_ULL(40) +#define CN93_VF_R_OUT_CTL_ES_I BIT_ULL(34) +#define CN93_VF_R_OUT_CTL_NSR_I BIT_ULL(33) +#define CN93_VF_R_OUT_CTL_ROR_I BIT_ULL(32) +#define CN93_VF_R_OUT_CTL_ES_D BIT_ULL(30) +#define CN93_VF_R_OUT_CTL_NSR_D BIT_ULL(29) +#define CN93_VF_R_OUT_CTL_ROR_D BIT_ULL(28) +#define CN93_VF_R_OUT_CTL_ES_P BIT_ULL(26) +#define CN93_VF_R_OUT_CTL_NSR_P BIT_ULL(25) +#define CN93_VF_R_OUT_CTL_ROR_P BIT_ULL(24) +#define CN93_VF_R_OUT_CTL_IMODE BIT_ULL(23) + +/* ##################### Mail Box Registers ########################## */ +/* SDP PF to VF Mailbox Data Register */ +#define CN93_VF_SDP_R_MBOX_PF_VF_DATA_START 0x10210 +/* SDP Packet PF to VF Mailbox Interrupt Register */ +#define CN93_VF_SDP_R_MBOX_PF_VF_INT_START 0x10220 +/* SDP VF to PF Mailbox Data Register */ +#define CN93_VF_SDP_R_MBOX_VF_PF_DATA_START 0x10230 + +#define CN93_VF_SDP_R_MBOX_PF_VF_INT_ENAB BIT_ULL(1) +#define CN93_VF_SDP_R_MBOX_PF_VF_INT_STATUS BIT_ULL(0) + +#define CN93_VF_SDP_R_MBOX_PF_VF_DATA(ring) \ + (CN93_VF_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_MBOX_PF_VF_INT(ring) \ + (CN93_VF_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CN93_VF_RING_OFFSET)) + +#define CN93_VF_SDP_R_MBOX_VF_PF_DATA(ring) \ + (CN93_VF_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CN93_VF_RING_OFFSET)) +#endif /* _OCTEP_VF_REGS_CN9K_H_ */ diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cnxk.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cnxk.h new file mode 100644 index 000000000000..2e156745ef64 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_regs_cnxk.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ +#ifndef _OCTEP_VF_REGS_CNXK_H_ +#define _OCTEP_VF_REGS_CNXK_H_ + +/*############################ RST #########################*/ +#define CNXK_VF_CONFIG_XPANSION_BAR 0x38 +#define CNXK_VF_CONFIG_PCIE_CAP 0x70 +#define CNXK_VF_CONFIG_PCIE_DEVCAP 0x74 +#define CNXK_VF_CONFIG_PCIE_DEVCTL 0x78 +#define CNXK_VF_CONFIG_PCIE_LINKCAP 0x7C +#define CNXK_VF_CONFIG_PCIE_LINKCTL 0x80 +#define CNXK_VF_CONFIG_PCIE_SLOTCAP 0x84 +#define CNXK_VF_CONFIG_PCIE_SLOTCTL 0x88 + +#define CNXK_VF_RING_OFFSET (0x1ULL << 17) + +/*###################### RING IN REGISTERS #########################*/ +#define CNXK_VF_SDP_R_IN_CONTROL_START 0x10000 +#define CNXK_VF_SDP_R_IN_ENABLE_START 0x10010 +#define CNXK_VF_SDP_R_IN_INSTR_BADDR_START 0x10020 +#define CNXK_VF_SDP_R_IN_INSTR_RSIZE_START 0x10030 +#define CNXK_VF_SDP_R_IN_INSTR_DBELL_START 0x10040 +#define CNXK_VF_SDP_R_IN_CNTS_START 0x10050 +#define CNXK_VF_SDP_R_IN_INT_LEVELS_START 0x10060 +#define CNXK_VF_SDP_R_IN_PKT_CNT_START 0x10080 +#define CNXK_VF_SDP_R_IN_BYTE_CNT_START 0x10090 +#define CNXK_VF_SDP_R_ERR_TYPE_START 0x10400 + +#define CNXK_VF_SDP_R_ERR_TYPE(ring) \ + (CNXK_VF_SDP_R_ERR_TYPE_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_CONTROL(ring) \ + (CNXK_VF_SDP_R_IN_CONTROL_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_ENABLE(ring) \ + (CNXK_VF_SDP_R_IN_ENABLE_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_INSTR_BADDR(ring) \ + (CNXK_VF_SDP_R_IN_INSTR_BADDR_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_INSTR_RSIZE(ring) \ + (CNXK_VF_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_INSTR_DBELL(ring) \ + (CNXK_VF_SDP_R_IN_INSTR_DBELL_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_CNTS(ring) \ + (CNXK_VF_SDP_R_IN_CNTS_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_INT_LEVELS(ring) \ + (CNXK_VF_SDP_R_IN_INT_LEVELS_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_PKT_CNT(ring) \ + (CNXK_VF_SDP_R_IN_PKT_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_IN_BYTE_CNT(ring) \ + (CNXK_VF_SDP_R_IN_BYTE_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) + +/*------------------ R_IN Masks ----------------*/ + +/** Rings per Virtual Function **/ +#define CNXK_VF_R_IN_CTL_RPVF_MASK (0xF) +#define CNXK_VF_R_IN_CTL_RPVF_POS (48) + +/* Number of instructions to be read in one MAC read request. + * setting to Max value(4) + **/ +#define CNXK_VF_R_IN_CTL_IDLE (0x1ULL << 28) +#define CNXK_VF_R_IN_CTL_RDSIZE (0x3ULL << 25) +#define CNXK_VF_R_IN_CTL_IS_64B (0x1ULL << 24) +#define CNXK_VF_R_IN_CTL_D_NSR (0x1ULL << 8) +#define CNXK_VF_R_IN_CTL_D_ESR (0x1ULL << 6) +#define CNXK_VF_R_IN_CTL_D_ROR (0x1ULL << 5) +#define CNXK_VF_R_IN_CTL_NSR (0x1ULL << 3) +#define CNXK_VF_R_IN_CTL_ESR (0x1ULL << 1) +#define CNXK_VF_R_IN_CTL_ROR (0x1ULL << 0) + +#define CNXK_VF_R_IN_CTL_MASK (CNXK_VF_R_IN_CTL_RDSIZE | CNXK_VF_R_IN_CTL_IS_64B) + +/*###################### RING OUT REGISTERS #########################*/ +#define CNXK_VF_SDP_R_OUT_CNTS_START 0x10100 +#define CNXK_VF_SDP_R_OUT_INT_LEVELS_START 0x10110 +#define CNXK_VF_SDP_R_OUT_SLIST_BADDR_START 0x10120 +#define CNXK_VF_SDP_R_OUT_SLIST_RSIZE_START 0x10130 +#define CNXK_VF_SDP_R_OUT_SLIST_DBELL_START 0x10140 +#define CNXK_VF_SDP_R_OUT_CONTROL_START 0x10150 +#define CNXK_VF_SDP_R_OUT_WMARK_START 0x10160 +#define CNXK_VF_SDP_R_OUT_ENABLE_START 0x10170 +#define CNXK_VF_SDP_R_OUT_PKT_CNT_START 0x10180 +#define CNXK_VF_SDP_R_OUT_BYTE_CNT_START 0x10190 + +#define CNXK_VF_SDP_R_OUT_CONTROL(ring) \ + (CNXK_VF_SDP_R_OUT_CONTROL_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_ENABLE(ring) \ + (CNXK_VF_SDP_R_OUT_ENABLE_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_SLIST_BADDR(ring) \ + (CNXK_VF_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_SLIST_RSIZE(ring) \ + (CNXK_VF_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_SLIST_DBELL(ring) \ + (CNXK_VF_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_WMARK(ring) \ + (CNXK_VF_SDP_R_OUT_WMARK_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_CNTS(ring) \ + (CNXK_VF_SDP_R_OUT_CNTS_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_INT_LEVELS(ring) \ + (CNXK_VF_SDP_R_OUT_INT_LEVELS_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_PKT_CNT(ring) \ + (CNXK_VF_SDP_R_OUT_PKT_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_OUT_BYTE_CNT(ring) \ + (CNXK_VF_SDP_R_OUT_BYTE_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) + +/*------------------ R_OUT Masks ----------------*/ +#define CNXK_VF_R_OUT_INT_LEVELS_BMODE BIT_ULL(63) +#define CNXK_VF_R_OUT_INT_LEVELS_TIMET (32) + +#define CNXK_VF_R_OUT_CTL_IDLE BIT_ULL(40) +#define CNXK_VF_R_OUT_CTL_ES_I BIT_ULL(34) +#define CNXK_VF_R_OUT_CTL_NSR_I BIT_ULL(33) +#define CNXK_VF_R_OUT_CTL_ROR_I BIT_ULL(32) +#define CNXK_VF_R_OUT_CTL_ES_D BIT_ULL(30) +#define CNXK_VF_R_OUT_CTL_NSR_D BIT_ULL(29) +#define CNXK_VF_R_OUT_CTL_ROR_D BIT_ULL(28) +#define CNXK_VF_R_OUT_CTL_ES_P BIT_ULL(26) +#define CNXK_VF_R_OUT_CTL_NSR_P BIT_ULL(25) +#define CNXK_VF_R_OUT_CTL_ROR_P BIT_ULL(24) +#define CNXK_VF_R_OUT_CTL_IMODE BIT_ULL(23) + +/* ##################### Mail Box Registers ########################## */ +/* SDP PF to VF Mailbox Data Register */ +#define CNXK_VF_SDP_R_MBOX_PF_VF_DATA_START 0x10210 +/* SDP Packet PF to VF Mailbox Interrupt Register */ +#define CNXK_VF_SDP_R_MBOX_PF_VF_INT_START 0x10220 +/* SDP VF to PF Mailbox Data Register */ +#define CNXK_VF_SDP_R_MBOX_VF_PF_DATA_START 0x10230 + +#define CNXK_VF_SDP_R_MBOX_PF_VF_INT_ENAB BIT_ULL(1) +#define CNXK_VF_SDP_R_MBOX_PF_VF_INT_STATUS BIT_ULL(0) + +#define CNXK_VF_SDP_R_MBOX_PF_VF_DATA(ring) \ + (CNXK_VF_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_MBOX_PF_VF_INT(ring) \ + (CNXK_VF_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CNXK_VF_RING_OFFSET)) + +#define CNXK_VF_SDP_R_MBOX_VF_PF_DATA(ring) \ + (CNXK_VF_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CNXK_VF_RING_OFFSET)) +#endif /* _OCTEP_VF_REGS_CNXK_H_ */ diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c new file mode 100644 index 000000000000..4f1a8157ce39 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#include +#include + +#include "octep_vf_config.h" +#include "octep_vf_main.h" + +/** + * octep_vf_setup_oqs() - setup resources for all Rx queues. + * + * @oct: Octeon device private data structure. + */ +int octep_vf_setup_oqs(struct octep_vf_device *oct) +{ + return -1; +} + +/** + * octep_vf_oq_dbell_init() - Initialize Rx queue doorbell. + * + * @oct: Octeon device private data structure. + * + * Write number of descriptors to Rx queue doorbell register. + */ +void octep_vf_oq_dbell_init(struct octep_vf_device *oct) +{ +} + +/** + * octep_vf_free_oqs() - Free resources of all Rx queues. + * + * @oct: Octeon device private data structure. + */ +void octep_vf_free_oqs(struct octep_vf_device *oct) +{ +} diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.h new file mode 100644 index 000000000000..fe46838b5200 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#ifndef _OCTEP_VF_RX_H_ +#define _OCTEP_VF_RX_H_ + +/* struct octep_vf_oq_desc_hw - Octeon Hardware OQ descriptor format. + * + * The descriptor ring is made of descriptors which have 2 64-bit values: + * + * @buffer_ptr: DMA address of the skb->data + * @info_ptr: DMA address of host memory, used to update pkt count by hw. + * This is currently unused to save pci writes. + */ +struct octep_vf_oq_desc_hw { + dma_addr_t buffer_ptr; + u64 info_ptr; +}; + +static_assert(sizeof(struct octep_vf_oq_desc_hw) == 16); + +#define OCTEP_VF_OQ_DESC_SIZE (sizeof(struct octep_vf_oq_desc_hw)) + +/* Rx offload flags */ +#define OCTEP_VF_RX_OFFLOAD_VLAN_STRIP BIT(0) +#define OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM BIT(1) +#define OCTEP_VF_RX_OFFLOAD_UDP_CKSUM BIT(2) +#define OCTEP_VF_RX_OFFLOAD_TCP_CKSUM BIT(3) + +#define OCTEP_VF_RX_OFFLOAD_CKSUM (OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_VF_RX_OFFLOAD_UDP_CKSUM | \ + OCTEP_VF_RX_OFFLOAD_TCP_CKSUM) + +#define OCTEP_VF_RX_IP_CSUM(flags) ((flags) & \ + (OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_VF_RX_OFFLOAD_TCP_CKSUM | \ + OCTEP_VF_RX_OFFLOAD_UDP_CKSUM)) + +/* bit 0 is vlan strip */ +#define OCTEP_VF_RX_CSUM_IP_VERIFIED BIT(1) +#define OCTEP_VF_RX_CSUM_L4_VERIFIED BIT(2) + +#define OCTEP_VF_RX_CSUM_VERIFIED(flags) ((flags) & \ + (OCTEP_VF_RX_CSUM_L4_VERIFIED | \ + OCTEP_VF_RX_CSUM_IP_VERIFIED)) + +/* Extended Response Header in packet data received from Hardware. + * Includes metadata like checksum status. + * this is valid only if hardware/firmware published support for this. + * This is at offset 0 of packet data (skb->data). + */ +struct octep_vf_oq_resp_hw_ext { + /* Reserved. */ + u64 rsvd:48; + + /* rx offload flags */ + u16 rx_ol_flags; +}; + +static_assert(sizeof(struct octep_vf_oq_resp_hw_ext) == 8); + +#define OCTEP_VF_OQ_RESP_HW_EXT_SIZE (sizeof(struct octep_vf_oq_resp_hw_ext)) + +/* Length of Rx packet DMA'ed by Octeon to Host. + * this is in bigendian; so need to be converted to cpu endian. + * Octeon writes this at the beginning of Rx buffer (skb->data). + */ +struct octep_vf_oq_resp_hw { + /* The Length of the packet. */ + __be64 length; +}; + +static_assert(sizeof(struct octep_vf_oq_resp_hw) == 8); + +#define OCTEP_VF_OQ_RESP_HW_SIZE (sizeof(struct octep_vf_oq_resp_hw)) + +/* Pointer to data buffer. + * Driver keeps a pointer to the data buffer that it made available to + * the Octeon device. Since the descriptor ring keeps physical (bus) + * addresses, this field is required for the driver to keep track of + * the virtual address pointers. The fields are operated by + * OS-dependent routines. + */ +struct octep_vf_rx_buffer { + struct page *page; + + /* length from rx hardware descriptor after converting to cpu endian */ + u64 len; +}; + +#define OCTEP_VF_OQ_RECVBUF_SIZE (sizeof(struct octep_vf_rx_buffer)) + +/* Output Queue statistics. Each output queue has four stats fields. */ +struct octep_vf_oq_stats { + /* Number of packets received from the Device. */ + u64 packets; + + /* Number of bytes received from the Device. */ + u64 bytes; + + /* Number of times failed to allocate buffers. */ + u64 alloc_failures; +}; + +#define OCTEP_VF_OQ_STATS_SIZE (sizeof(struct octep_vf_oq_stats)) + +/* Hardware interface Rx statistics */ +struct octep_vf_iface_rx_stats { + /* Received packets */ + u64 pkts; + + /* Octets of received packets */ + u64 octets; + + /* Received PAUSE and Control packets */ + u64 pause_pkts; + + /* Received PAUSE and Control octets */ + u64 pause_octets; + + /* Filtered DMAC0 packets */ + u64 dmac0_pkts; + + /* Filtered DMAC0 octets */ + u64 dmac0_octets; + + /* Packets dropped due to RX FIFO full */ + u64 dropped_pkts_fifo_full; + + /* Octets dropped due to RX FIFO full */ + u64 dropped_octets_fifo_full; + + /* Error packets */ + u64 err_pkts; + + /* Filtered DMAC1 packets */ + u64 dmac1_pkts; + + /* Filtered DMAC1 octets */ + u64 dmac1_octets; + + /* NCSI-bound packets dropped */ + u64 ncsi_dropped_pkts; + + /* NCSI-bound octets dropped */ + u64 ncsi_dropped_octets; + + /* Multicast packets received. */ + u64 mcast_pkts; + + /* Broadcast packets received. */ + u64 bcast_pkts; + +}; + +/* The Descriptor Ring Output Queue structure. + * This structure has all the information required to implement a + * Octeon OQ. + */ +struct octep_vf_oq { + u32 q_no; + + struct octep_vf_device *octep_vf_dev; + struct net_device *netdev; + struct device *dev; + + struct napi_struct *napi; + + /* The receive buffer list. This list has the virtual addresses + * of the buffers. + */ + struct octep_vf_rx_buffer *buff_info; + + /* Pointer to the mapped packet credit register. + * Host writes number of info/buffer ptrs available to this register + */ + u8 __iomem *pkts_credit_reg; + + /* Pointer to the mapped packet sent register. + * Octeon writes the number of packets DMA'ed to host memory + * in this register. + */ + u8 __iomem *pkts_sent_reg; + + /* Statistics for this OQ. */ + struct octep_vf_oq_stats stats; + + /* Packets pending to be processed */ + u32 pkts_pending; + u32 last_pkt_count; + + /* Index in the ring where the driver should read the next packet */ + u32 host_read_idx; + + /* Number of descriptors in this ring. */ + u32 max_count; + u32 ring_size_mask; + + /* The number of descriptors pending refill. */ + u32 refill_count; + + /* Index in the ring where the driver will refill the + * descriptor's buffer + */ + u32 host_refill_idx; + u32 refill_threshold; + + /* The size of each buffer pointed by the buffer pointer. */ + u32 buffer_size; + u32 max_single_buffer_size; + + /* The 8B aligned descriptor ring starts at this address. */ + struct octep_vf_oq_desc_hw *desc_ring; + + /* DMA mapped address of the OQ descriptor ring. */ + dma_addr_t desc_ring_dma; +}; + +#define OCTEP_VF_OQ_SIZE (sizeof(struct octep_vf_oq)) +#endif /* _OCTEP_VF_RX_H_ */ diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c new file mode 100644 index 000000000000..232ba479ecf6 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#include +#include + +#include "octep_vf_config.h" +#include "octep_vf_main.h" + +/** + * octep_vf_clean_iqs() - Clean Tx queues to shutdown the device. + * + * @oct: Octeon device private data structure. + * + * Free the buffers in Tx queue descriptors pending completion and + * reset queue indices + */ +void octep_vf_clean_iqs(struct octep_vf_device *oct) +{ +} + +/** + * octep_vf_setup_iqs() - setup resources for all Tx queues. + * + * @oct: Octeon device private data structure. + */ +int octep_vf_setup_iqs(struct octep_vf_device *oct) +{ + return -1; +} + +/** + * octep_vf_free_iqs() - Free resources of all Tx queues. + * + * @oct: Octeon device private data structure. + */ +void octep_vf_free_iqs(struct octep_vf_device *oct) +{ +} diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.h new file mode 100644 index 000000000000..f338b975103c --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.h @@ -0,0 +1,276 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#ifndef _OCTEP_VF_TX_H_ +#define _OCTEP_VF_TX_H_ + +#define IQ_SEND_OK 0 +#define IQ_SEND_STOP 1 +#define IQ_SEND_FAILED -1 + +#define TX_BUFTYPE_NONE 0 +#define TX_BUFTYPE_NET 1 +#define TX_BUFTYPE_NET_SG 2 +#define NUM_TX_BUFTYPES 3 + +/* Hardware format for Scatter/Gather list + * + * 63 48|47 32|31 16|15 0 + * ----------------------------------------- + * | Len 0 | Len 1 | Len 2 | Len 3 | + * ----------------------------------------- + * | Ptr 0 | + * ----------------------------------------- + * | Ptr 1 | + * ----------------------------------------- + * | Ptr 2 | + * ----------------------------------------- + * | Ptr 3 | + * ----------------------------------------- + */ +struct octep_vf_tx_sglist_desc { + u16 len[4]; + dma_addr_t dma_ptr[4]; +}; + +static_assert(sizeof(struct octep_vf_tx_sglist_desc) == 40); + +/* Each Scatter/Gather entry sent to hardwar hold four pointers. + * So, number of entries required is (MAX_SKB_FRAGS + 1)/4, where '+1' + * is for main skb which also goes as a gather buffer to Octeon hardware. + * To allocate sufficient SGLIST entries for a packet with max fragments, + * align by adding 3 before calcuating max SGLIST entries per packet. + */ +#define OCTEP_VF_SGLIST_ENTRIES_PER_PKT ((MAX_SKB_FRAGS + 1 + 3) / 4) +#define OCTEP_VF_SGLIST_SIZE_PER_PKT \ + (OCTEP_VF_SGLIST_ENTRIES_PER_PKT * sizeof(struct octep_vf_tx_sglist_desc)) + +struct octep_vf_tx_buffer { + struct sk_buff *skb; + dma_addr_t dma; + struct octep_vf_tx_sglist_desc *sglist; + dma_addr_t sglist_dma; + u8 gather; +}; + +#define OCTEP_VF_IQ_TXBUFF_INFO_SIZE (sizeof(struct octep_vf_tx_buffer)) + +/* VF Hardware interface Tx statistics */ +struct octep_vf_iface_tx_stats { + /* Total frames sent on the interface */ + u64 pkts; + + /* Total octets sent on the interface */ + u64 octs; + + /* Packets sent to a broadcast DMAC */ + u64 bcst; + + /* Packets sent to the multicast DMAC */ + u64 mcst; + + /* Packets dropped */ + u64 dropped; + + /* Reserved */ + u64 reserved[13]; +}; + +/* VF Input Queue statistics */ +struct octep_vf_iq_stats { + /* Instructions posted to this queue. */ + u64 instr_posted; + + /* Instructions copied by hardware for processing. */ + u64 instr_completed; + + /* Instructions that could not be processed. */ + u64 instr_dropped; + + /* Bytes sent through this queue. */ + u64 bytes_sent; + + /* Gather entries sent through this queue. */ + u64 sgentry_sent; + + /* Number of transmit failures due to TX_BUSY */ + u64 tx_busy; + + /* Number of times the queue is restarted */ + u64 restart_cnt; +}; + +/* The instruction (input) queue. + * The input queue is used to post raw (instruction) mode data or packet + * data to Octeon device from the host. Each input queue (up to 4) for + * a Octeon device has one such structure to represent it. + */ +struct octep_vf_iq { + u32 q_no; + + struct octep_vf_device *octep_vf_dev; + struct net_device *netdev; + struct device *dev; + struct netdev_queue *netdev_q; + + /* Index in input ring where driver should write the next packet */ + u16 host_write_index; + + /* Index in input ring where Octeon is expected to read next packet */ + u16 octep_vf_read_index; + + /* This index aids in finding the window in the queue where Octeon + * has read the commands. + */ + u16 flush_index; + + /* Statistics for this input queue. */ + struct octep_vf_iq_stats stats; + + /* Pointer to the Virtual Base addr of the input ring. */ + struct octep_vf_tx_desc_hw *desc_ring; + + /* DMA mapped base address of the input descriptor ring. */ + dma_addr_t desc_ring_dma; + + /* Info of Tx buffers pending completion. */ + struct octep_vf_tx_buffer *buff_info; + + /* Base pointer to Scatter/Gather lists for all ring descriptors. */ + struct octep_vf_tx_sglist_desc *sglist; + + /* DMA mapped addr of Scatter Gather Lists */ + dma_addr_t sglist_dma; + + /* Octeon doorbell register for the ring. */ + u8 __iomem *doorbell_reg; + + /* Octeon instruction count register for this ring. */ + u8 __iomem *inst_cnt_reg; + + /* interrupt level register for this ring */ + u8 __iomem *intr_lvl_reg; + + /* Maximum no. of instructions in this queue. */ + u32 max_count; + u32 ring_size_mask; + + u32 pkt_in_done; + u32 pkts_processed; + + u32 status; + + /* Number of instructions pending to be posted to Octeon. */ + u32 fill_cnt; + + /* The max. number of instructions that can be held pending by the + * driver before ringing doorbell. + */ + u32 fill_threshold; +}; + +/* Hardware Tx Instruction Header */ +struct octep_vf_instr_hdr { + /* Data Len */ + u64 tlen:16; + + /* Reserved */ + u64 rsvd:20; + + /* PKIND for SDP */ + u64 pkind:6; + + /* Front Data size */ + u64 fsz:6; + + /* No. of entries in gather list */ + u64 gsz:14; + + /* Gather indicator 1=gather*/ + u64 gather:1; + + /* Reserved3 */ + u64 reserved3:1; +}; + +static_assert(sizeof(struct octep_vf_instr_hdr) == 8); + +/* Tx offload flags */ +#define OCTEP_VF_TX_OFFLOAD_VLAN_INSERT BIT(0) +#define OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM BIT(1) +#define OCTEP_VF_TX_OFFLOAD_UDP_CKSUM BIT(2) +#define OCTEP_VF_TX_OFFLOAD_TCP_CKSUM BIT(3) +#define OCTEP_VF_TX_OFFLOAD_SCTP_CKSUM BIT(4) +#define OCTEP_VF_TX_OFFLOAD_TCP_TSO BIT(5) +#define OCTEP_VF_TX_OFFLOAD_UDP_TSO BIT(6) + +#define OCTEP_VF_TX_OFFLOAD_CKSUM (OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_VF_TX_OFFLOAD_UDP_CKSUM | \ + OCTEP_VF_TX_OFFLOAD_TCP_CKSUM) + +#define OCTEP_VF_TX_OFFLOAD_TSO (OCTEP_VF_TX_OFFLOAD_TCP_TSO | \ + OCTEP_VF_TX_OFFLOAD_UDP_TSO) + +#define OCTEP_VF_TX_IP_CSUM(flags) ((flags) & \ + (OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM | \ + OCTEP_VF_TX_OFFLOAD_TCP_CKSUM | \ + OCTEP_VF_TX_OFFLOAD_UDP_CKSUM)) + +#define OCTEP_VF_TX_TSO(flags) ((flags) & \ + (OCTEP_VF_TX_OFFLOAD_TCP_TSO | \ + OCTEP_VF_TX_OFFLOAD_UDP_TSO)) + +struct tx_mdata { + /* offload flags */ + u16 ol_flags; + + /* gso size */ + u16 gso_size; + + /* gso flags */ + u16 gso_segs; + + /* reserved */ + u16 rsvd1; + + /* reserved */ + u64 rsvd2; +}; + +static_assert(sizeof(struct tx_mdata) == 16); + +/* 64-byte Tx instruction format. + * Format of instruction for a 64-byte mode input queue. + * + * only first 16-bytes (dptr and ih) are mandatory; rest are optional + * and filled by the driver based on firmware/hardware capabilities. + * These optional headers together called Front Data and its size is + * described by ih->fsz. + */ +struct octep_vf_tx_desc_hw { + /* Pointer where the input data is available. */ + u64 dptr; + + /* Instruction Header. */ + union { + struct octep_vf_instr_hdr ih; + u64 ih64; + }; + + union { + u64 txm64[2]; + struct tx_mdata txm; + }; + + /* Additional headers available in a 64-byte instruction. */ + u64 exhdr[4]; +}; + +static_assert(sizeof(struct octep_vf_tx_desc_hw) == 64); + +#define OCTEP_VF_IQ_DESC_SIZE (sizeof(struct octep_vf_tx_desc_hw)) +#endif /* _OCTEP_VF_TX_H_ */ From 2c0c32c72be29fba0bbd535308038b49caaf4fc1 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:34 -0800 Subject: [PATCH 1044/2255] octeon_ep_vf: add hardware configuration APIs Implement hardware resource init and shutdown helper APIs, like hardware Tx/Rx queue init/enable/disable/reset. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../marvell/octeon_ep_vf/octep_vf_cn9k.c | 334 ++++++++++++++++- .../marvell/octeon_ep_vf/octep_vf_cnxk.c | 344 +++++++++++++++++- 2 files changed, 676 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c index c24ef2265205..88937fce75f1 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c @@ -13,9 +13,123 @@ #include "octep_vf_main.h" #include "octep_vf_regs_cn9k.h" +/* Dump useful hardware IQ/OQ CSRs for debug purpose */ +static void cn93_vf_dump_q_regs(struct octep_vf_device *oct, int qno) +{ + struct device *dev = &oct->pdev->dev; + + dev_info(dev, "IQ-%d register dump\n", qno); + dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_INSTR_DBELL(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(qno))); + dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_CONTROL(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(qno))); + dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_ENABLE(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(qno))); + dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_INSTR_BADDR(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(qno))); + dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_INSTR_RSIZE(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(qno))); + dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_CNTS(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CNTS(qno))); + dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_INT_LEVELS(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(qno))); + dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_PKT_CNT(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_PKT_CNT(qno))); + dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_IN_BYTE_CNT(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_BYTE_CNT(qno))); + + dev_info(dev, "OQ-%d register dump\n", qno); + dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_SLIST_DBELL(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(qno))); + dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_CONTROL(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(qno))); + dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_ENABLE(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(qno))); + dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_SLIST_BADDR(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_BADDR(qno))); + dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_SLIST_RSIZE(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_RSIZE(qno))); + dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_CNTS(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CNTS(qno))); + dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_INT_LEVELS(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(qno))); + dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_PKT_CNT(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_PKT_CNT(qno))); + dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n", + qno, CN93_VF_SDP_R_OUT_BYTE_CNT(qno), + octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_BYTE_CNT(qno))); +} + +/* Reset Hardware Tx queue */ +static void cn93_vf_reset_iq(struct octep_vf_device *oct, int q_no) +{ + u64 val = ULL(0); + + dev_dbg(&oct->pdev->dev, "Reset VF IQ-%d\n", q_no); + + /* Disable the Tx/Instruction Ring */ + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(q_no), val); + + /* clear the Instruction Ring packet/byte counts and doorbell CSRs */ + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q_no), val); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_PKT_CNT(q_no), val); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_BYTE_CNT(q_no), val); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(q_no), val); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(q_no), val); + + val = GENMASK_ULL(31, 0); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(q_no), val); + + val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CNTS(q_no)); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_CNTS(q_no), + val & GENMASK_ULL(31, 0)); +} + +/* Reset Hardware Rx queue */ +static void cn93_vf_reset_oq(struct octep_vf_device *oct, int q_no) +{ + u64 val = ULL(0); + + /* Disable Output (Rx) Ring */ + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(q_no), val); + + /* Clear count CSRs */ + val = octep_vf_read_csr(oct, CN93_VF_SDP_R_OUT_CNTS(q_no)); + octep_vf_write_csr(oct, CN93_VF_SDP_R_OUT_CNTS(q_no), val); + + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_PKT_CNT(q_no), GENMASK_ULL(35, 0)); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(q_no), GENMASK_ULL(31, 0)); +} + /* Reset all hardware Tx/Rx queues */ static void octep_vf_reset_io_queues_cn93(struct octep_vf_device *oct) { + struct pci_dev *pdev = oct->pdev; + int q; + + dev_dbg(&pdev->dev, "Reset OCTEP_CN93 VF IO Queues\n"); + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + cn93_vf_reset_iq(oct, q); + cn93_vf_reset_oq(oct, q); + } } /* Initialize configuration limits and initial active config */ @@ -46,78 +160,296 @@ static void octep_vf_init_config_cn93_vf(struct octep_vf_device *oct) /* Setup registers for a hardware Tx Queue */ static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no) { + struct octep_vf_iq *iq = oct->iq[iq_no]; + u32 reset_instr_cnt; + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no)); + + /* wait for IDLE to set to 1 */ + if (!(reg_val & CN93_VF_R_IN_CTL_IDLE)) { + do { + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no)); + } while (!(reg_val & CN93_VF_R_IN_CTL_IDLE)); + } + reg_val |= CN93_VF_R_IN_CTL_RDSIZE; + reg_val |= CN93_VF_R_IN_CTL_IS_64B; + reg_val |= CN93_VF_R_IN_CTL_ESR; + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no), reg_val); + + /* Write the start of the input queue's ring and its size */ + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(iq_no), iq->desc_ring_dma); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(iq_no), iq->max_count); + + /* Remember the doorbell & instruction count register addr for this queue */ + iq->doorbell_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no); + iq->inst_cnt_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_CNTS(iq_no); + iq->intr_lvl_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_INT_LEVELS(iq_no); + + /* Store the current instruction counter (used in flush_iq calculation) */ + reset_instr_cnt = readl(iq->inst_cnt_reg); + writel(reset_instr_cnt, iq->inst_cnt_reg); + + /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */ + reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & GENMASK_ULL(31, 0); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); } /* Setup registers for a hardware Rx Queue */ static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) { + struct octep_vf_oq *oq = oct->oq[oq_no]; + u32 time_threshold = 0; + u64 oq_ctl = ULL(0); + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no)); + + /* wait for IDLE to set to 1 */ + if (!(reg_val & CN93_VF_R_OUT_CTL_IDLE)) { + do { + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CN93_VF_R_OUT_CTL_IDLE)); + } + + reg_val &= ~(CN93_VF_R_OUT_CTL_IMODE); + reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_P); + reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_P); + reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_I); + reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_I); + reg_val &= ~(CN93_VF_R_OUT_CTL_ES_I); + reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_D); + reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_D); + reg_val &= ~(CN93_VF_R_OUT_CTL_ES_D); + reg_val |= (CN93_VF_R_OUT_CTL_ES_P); + + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no), reg_val); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count); + + oq_ctl = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no)); + oq_ctl &= ~GENMASK_ULL(22, 0); //clear the ISIZE and BSIZE (22-0) + oq_ctl |= (oq->buffer_size & GENMASK_ULL(15, 0)); //populate the BSIZE (15-0) + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no), oq_ctl); + + /* Get the mapped address of the pkt_sent and pkts_credit regs */ + oq->pkts_sent_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_OUT_CNTS(oq_no); + oq->pkts_credit_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_OUT_SLIST_DBELL(oq_no); + + time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); + reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); } /* Setup registers for a VF mailbox */ static void octep_vf_setup_mbox_regs_cn93(struct octep_vf_device *oct, int q_no) { + struct octep_vf_mbox *mbox = oct->mbox; + + /* PF to VF DATA reg. VF reads from this reg */ + mbox->mbox_read_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_PF_VF_DATA(q_no); + + /* VF mbox interrupt reg */ + mbox->mbox_int_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_PF_VF_INT(q_no); + + /* VF to PF DATA reg. VF writes into this reg */ + mbox->mbox_write_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_VF_PF_DATA(q_no); +} + +/* Mailbox Interrupt handler */ +static void cn93_handle_vf_mbox_intr(struct octep_vf_device *oct) +{ + if (oct->mbox) + schedule_work(&oct->mbox->wk.work); + else + dev_err(&oct->pdev->dev, "cannot schedule work on invalid mbox\n"); } /* Tx/Rx queue interrupt handler */ static irqreturn_t octep_vf_ioq_intr_handler_cn93(void *data) { + struct octep_vf_ioq_vector *vector = data; + struct octep_vf_device *oct; + struct octep_vf_oq *oq; + u64 reg_val; + + oct = vector->octep_vf_dev; + oq = vector->oq; + /* Mailbox interrupt arrives along with interrupt of tx/rx ring pair 0 */ + if (oq->q_no == 0) { + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0)); + if (reg_val & CN93_VF_SDP_R_MBOX_PF_VF_INT_STATUS) { + cn93_handle_vf_mbox_intr(oct); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), reg_val); + } + } + napi_schedule_irqoff(oq->napi); return IRQ_HANDLED; } /* Re-initialize Octeon hardware registers */ static void octep_vf_reinit_regs_cn93(struct octep_vf_device *oct) { + u32 i; + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + oct->hw_ops.setup_iq_regs(oct, i); + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + oct->hw_ops.setup_oq_regs(oct, i); + + oct->hw_ops.enable_interrupts(oct); + oct->hw_ops.enable_io_queues(oct); + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); } /* Enable all interrupts */ static void octep_vf_enable_interrupts_cn93(struct octep_vf_device *oct) { + int num_rings, q; + u64 reg_val; + + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + for (q = 0; q < num_rings; q++) { + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q), reg_val); + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); + } + /* Enable PF to VF mbox interrupt by setting 2nd bit*/ + octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), + CN93_VF_SDP_R_MBOX_PF_VF_INT_ENAB); } /* Disable all interrupts */ static void octep_vf_disable_interrupts_cn93(struct octep_vf_device *oct) { + int num_rings, q; + u64 reg_val; + + /* Disable PF to VF mbox interrupt by setting 2nd bit*/ + if (oct->mbox) + octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), 0x0); + + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + for (q = 0; q < num_rings; q++) { + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q)); + reg_val &= ~BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q), reg_val); + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q)); + reg_val &= ~BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); + } } /* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ static u32 octep_vf_update_iq_read_index_cn93(struct octep_vf_iq *iq) { - return 0; + u32 pkt_in_done = readl(iq->inst_cnt_reg); + u32 last_done, new_idx; + + last_done = pkt_in_done - iq->pkt_in_done; + iq->pkt_in_done = pkt_in_done; + + new_idx = (iq->octep_vf_read_index + last_done) % iq->max_count; + + return new_idx; } /* Enable a hardware Tx Queue */ static void octep_vf_enable_iq_cn93(struct octep_vf_device *oct, int iq_no) { + u64 loop = HZ; + u64 reg_val; + + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no), GENMASK_ULL(31, 0)); + + while (octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no)) && + loop--) { + schedule_timeout_interruptible(1); + } + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no)); + reg_val |= ULL(1); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no), reg_val); } /* Enable a hardware Rx Queue */ static void octep_vf_enable_oq_cn93(struct octep_vf_device *oct, int oq_no) { + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); + + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(oq_no), GENMASK_ULL(31, 0)); + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no)); + reg_val |= ULL(1); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); } /* Enable all hardware Tx/Rx Queues assigned to VF */ static void octep_vf_enable_io_queues_cn93(struct octep_vf_device *oct) { + u8 q; + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + octep_vf_enable_iq_cn93(oct, q); + octep_vf_enable_oq_cn93(oct, q); + } } /* Disable a hardware Tx Queue assigned to VF */ static void octep_vf_disable_iq_cn93(struct octep_vf_device *oct, int iq_no) { + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no)); + reg_val &= ~ULL(1); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no), reg_val); } /* Disable a hardware Rx Queue assigned to VF */ static void octep_vf_disable_oq_cn93(struct octep_vf_device *oct, int oq_no) { + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no)); + reg_val &= ~ULL(1); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); } /* Disable all hardware Tx/Rx Queues assigned to VF */ static void octep_vf_disable_io_queues_cn93(struct octep_vf_device *oct) { + int q; + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + octep_vf_disable_iq_cn93(oct, q); + octep_vf_disable_oq_cn93(oct, q); + } } /* Dump hardware registers (including Tx/Rx queues) for debugging. */ static void octep_vf_dump_registers_cn93(struct octep_vf_device *oct) { + u8 num_rings, q; + + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + for (q = 0; q < num_rings; q++) + cn93_vf_dump_q_regs(oct, q); } /** diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c index af07a4a6edc5..1f79dfad42c6 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c @@ -13,9 +13,125 @@ #include "octep_vf_main.h" #include "octep_vf_regs_cnxk.h" +/* Dump useful hardware IQ/OQ CSRs for debug purpose */ +static void cnxk_vf_dump_q_regs(struct octep_vf_device *oct, int qno) +{ + struct device *dev = &oct->pdev->dev; + + dev_info(dev, "IQ-%d register dump\n", qno); + dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_INSTR_DBELL(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(qno))); + dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_CONTROL(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(qno))); + dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_ENABLE(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(qno))); + dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_INSTR_BADDR(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(qno))); + dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_INSTR_RSIZE(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(qno))); + dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_CNTS(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(qno))); + dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_INT_LEVELS(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(qno))); + dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_PKT_CNT(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_PKT_CNT(qno))); + dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_IN_BYTE_CNT(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_BYTE_CNT(qno))); + + dev_info(dev, "OQ-%d register dump\n", qno); + dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_SLIST_DBELL(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(qno))); + dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_CONTROL(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(qno))); + dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_ENABLE(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(qno))); + dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_SLIST_BADDR(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(qno))); + dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(qno))); + dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_CNTS(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CNTS(qno))); + dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_INT_LEVELS(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(qno))); + dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_PKT_CNT(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_PKT_CNT(qno))); + dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_OUT_BYTE_CNT(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_BYTE_CNT(qno))); + dev_info(dev, "R[%d]_ERR_TYPE[0x%llx]: 0x%016llx\n", + qno, CNXK_VF_SDP_R_ERR_TYPE(qno), + octep_vf_read_csr64(oct, CNXK_VF_SDP_R_ERR_TYPE(qno))); +} + +/* Reset Hardware Tx queue */ +static void cnxk_vf_reset_iq(struct octep_vf_device *oct, int q_no) +{ + u64 val = ULL(0); + + dev_dbg(&oct->pdev->dev, "Reset VF IQ-%d\n", q_no); + + /* Disable the Tx/Instruction Ring */ + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(q_no), val); + + /* clear the Instruction Ring packet/byte counts and doorbell CSRs */ + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q_no), val); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_PKT_CNT(q_no), val); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_BYTE_CNT(q_no), val); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(q_no), val); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(q_no), val); + + val = GENMASK_ULL(31, 0); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(q_no), val); + + val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(q_no)); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(q_no), val & GENMASK_ULL(31, 0)); +} + +/* Reset Hardware Rx queue */ +static void cnxk_vf_reset_oq(struct octep_vf_device *oct, int q_no) +{ + u64 val = ULL(0); + + /* Disable Output (Rx) Ring */ + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(q_no), val); + + /* Clear count CSRs */ + val = octep_vf_read_csr(oct, CNXK_VF_SDP_R_OUT_CNTS(q_no)); + octep_vf_write_csr(oct, CNXK_VF_SDP_R_OUT_CNTS(q_no), val); + + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_PKT_CNT(q_no), GENMASK_ULL(35, 0)); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(q_no), GENMASK_ULL(31, 0)); +} + /* Reset all hardware Tx/Rx queues */ static void octep_vf_reset_io_queues_cnxk(struct octep_vf_device *oct) { + struct pci_dev *pdev = oct->pdev; + int q; + + dev_dbg(&pdev->dev, "Reset OCTEP_CNXK VF IO Queues\n"); + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + cnxk_vf_reset_iq(oct, q); + cnxk_vf_reset_oq(oct, q); + } } /* Initialize configuration limits and initial active config */ @@ -47,78 +163,304 @@ static void octep_vf_init_config_cnxk_vf(struct octep_vf_device *oct) /* Setup registers for a hardware Tx Queue */ static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no) { + struct octep_vf_iq *iq = oct->iq[iq_no]; + u32 reset_instr_cnt; + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no)); + + /* wait for IDLE to set to 1 */ + if (!(reg_val & CNXK_VF_R_IN_CTL_IDLE)) { + do { + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no)); + } while (!(reg_val & CNXK_VF_R_IN_CTL_IDLE)); + } + reg_val |= CNXK_VF_R_IN_CTL_RDSIZE; + reg_val |= CNXK_VF_R_IN_CTL_IS_64B; + reg_val |= CNXK_VF_R_IN_CTL_ESR; + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no), reg_val); + + /* Write the start of the input queue's ring and its size */ + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(iq_no), iq->desc_ring_dma); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(iq_no), iq->max_count); + + /* Remember the doorbell & instruction count register addr for this queue */ + iq->doorbell_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no); + iq->inst_cnt_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_CNTS(iq_no); + iq->intr_lvl_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no); + + /* Store the current instruction counter (used in flush_iq calculation) */ + reset_instr_cnt = readl(iq->inst_cnt_reg); + writel(reset_instr_cnt, iq->inst_cnt_reg); + + /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */ + reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & GENMASK_ULL(31, 0); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); } /* Setup registers for a hardware Rx Queue */ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) { + struct octep_vf_oq *oq = oct->oq[oq_no]; + u32 time_threshold = 0; + u64 oq_ctl = ULL(0); + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + + /* wait for IDLE to set to 1 */ + if (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)) { + do { + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)); + } + + reg_val &= ~(CNXK_VF_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_P); + reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_P); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_I); + reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_I); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ES_I); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_D); + reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_D); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ES_D); + reg_val |= (CNXK_VF_R_OUT_CTL_ES_P); + + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), reg_val); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count); + + oq_ctl = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + /* Clear the ISIZE and BSIZE (22-0) */ + oq_ctl &= ~GENMASK_ULL(22, 0); + /* Populate the BSIZE (15-0) */ + oq_ctl |= (oq->buffer_size & GENMASK_ULL(15, 0)); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), oq_ctl); + + /* Get the mapped address of the pkt_sent and pkts_credit regs */ + oq->pkts_sent_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_OUT_CNTS(oq_no); + oq->pkts_credit_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_OUT_SLIST_DBELL(oq_no); + + time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); + reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); + + /* set watermark for backpressure */ + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no)); + reg_val &= ~GENMASK_ULL(31, 0); + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), reg_val); } /* Setup registers for a VF mailbox */ static void octep_vf_setup_mbox_regs_cnxk(struct octep_vf_device *oct, int q_no) { + struct octep_vf_mbox *mbox = oct->mbox; + + /* PF to VF DATA reg. VF reads from this reg */ + mbox->mbox_read_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_PF_VF_DATA(q_no); + + /* VF mbox interrupt reg */ + mbox->mbox_int_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_PF_VF_INT(q_no); + + /* VF to PF DATA reg. VF writes into this reg */ + mbox->mbox_write_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_VF_PF_DATA(q_no); +} + +/* Mailbox Interrupt handler */ +static void cnxk_handle_vf_mbox_intr(struct octep_vf_device *oct) +{ + if (oct->mbox) + schedule_work(&oct->mbox->wk.work); + else + dev_err(&oct->pdev->dev, "cannot schedule work on invalid mbox\n"); } /* Tx/Rx queue interrupt handler */ static irqreturn_t octep_vf_ioq_intr_handler_cnxk(void *data) { + struct octep_vf_ioq_vector *vector = data; + struct octep_vf_device *oct; + struct octep_vf_oq *oq; + u64 reg_val; + + oct = vector->octep_vf_dev; + oq = vector->oq; + /* Mailbox interrupt arrives along with interrupt of tx/rx ring pair 0 */ + if (oq->q_no == 0) { + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0)); + if (reg_val & CNXK_VF_SDP_R_MBOX_PF_VF_INT_STATUS) { + cnxk_handle_vf_mbox_intr(oct); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), reg_val); + } + } + napi_schedule_irqoff(oq->napi); return IRQ_HANDLED; } /* Re-initialize Octeon hardware registers */ static void octep_vf_reinit_regs_cnxk(struct octep_vf_device *oct) { + u32 i; + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + oct->hw_ops.setup_iq_regs(oct, i); + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + oct->hw_ops.setup_oq_regs(oct, i); + + oct->hw_ops.enable_interrupts(oct); + oct->hw_ops.enable_io_queues(oct); + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) + writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); } /* Enable all interrupts */ static void octep_vf_enable_interrupts_cnxk(struct octep_vf_device *oct) { + int num_rings, q; + u64 reg_val; + + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + for (q = 0; q < num_rings; q++) { + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q), reg_val); + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); + } + /* Enable PF to VF mbox interrupt by setting 2nd bit*/ + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), + CNXK_VF_SDP_R_MBOX_PF_VF_INT_ENAB); } /* Disable all interrupts */ static void octep_vf_disable_interrupts_cnxk(struct octep_vf_device *oct) { + int num_rings, q; + u64 reg_val; + + /* Disable PF to VF mbox interrupt by setting 2nd bit*/ + if (oct->mbox) + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), 0x0); + + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + for (q = 0; q < num_rings; q++) { + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q)); + reg_val &= ~BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q), reg_val); + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q)); + reg_val &= ~BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); + } } /* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ static u32 octep_vf_update_iq_read_index_cnxk(struct octep_vf_iq *iq) { - return 0; + u32 pkt_in_done = readl(iq->inst_cnt_reg); + u32 last_done, new_idx; + + last_done = pkt_in_done - iq->pkt_in_done; + iq->pkt_in_done = pkt_in_done; + + new_idx = (iq->octep_vf_read_index + last_done) % iq->max_count; + + return new_idx; } /* Enable a hardware Tx Queue */ static void octep_vf_enable_iq_cnxk(struct octep_vf_device *oct, int iq_no) { + u64 loop = HZ; + u64 reg_val; + + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no), GENMASK_ULL(31, 0)); + + while (octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no)) && + loop--) { + schedule_timeout_interruptible(1); + } + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no)); + reg_val |= ULL(1); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no), reg_val); } /* Enable a hardware Rx Queue */ static void octep_vf_enable_oq_cnxk(struct octep_vf_device *oct, int oq_no) { + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no)); + reg_val |= BIT_ULL_MASK(62); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); + + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(oq_no), GENMASK_ULL(31, 0)); + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no)); + reg_val |= ULL(1); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); } /* Enable all hardware Tx/Rx Queues assigned to VF */ static void octep_vf_enable_io_queues_cnxk(struct octep_vf_device *oct) { + u8 q; + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + octep_vf_enable_iq_cnxk(oct, q); + octep_vf_enable_oq_cnxk(oct, q); + } } /* Disable a hardware Tx Queue assigned to VF */ static void octep_vf_disable_iq_cnxk(struct octep_vf_device *oct, int iq_no) { + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no)); + reg_val &= ~ULL(1); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no), reg_val); } /* Disable a hardware Rx Queue assigned to VF */ static void octep_vf_disable_oq_cnxk(struct octep_vf_device *oct, int oq_no) { + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no)); + reg_val &= ~ULL(1); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); } /* Disable all hardware Tx/Rx Queues assigned to VF */ static void octep_vf_disable_io_queues_cnxk(struct octep_vf_device *oct) { + int q; + + for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { + octep_vf_disable_iq_cnxk(oct, q); + octep_vf_disable_oq_cnxk(oct, q); + } } /* Dump hardware registers (including Tx/Rx queues) for debugging. */ static void octep_vf_dump_registers_cnxk(struct octep_vf_device *oct) { + u8 num_rings, q; + + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + for (q = 0; q < num_rings; q++) + cnxk_vf_dump_q_regs(oct, q); } /** From c5cb944ded9475bce2c4197f9c7103eab8c7c3f8 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:35 -0800 Subject: [PATCH 1045/2255] octeon_ep_vf: add VF-PF mailbox communication. Implement VF-PF mailbox to send all control commands from VF to PF and receive responses and notifications from PF to VF. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../marvell/octeon_ep_vf/octep_vf_main.c | 30 ++ .../marvell/octeon_ep_vf/octep_vf_main.h | 2 + .../marvell/octeon_ep_vf/octep_vf_mbox.c | 336 +++++++++++++++++- .../marvell/octeon_ep_vf/octep_vf_mbox.h | 143 +++++++- 4 files changed, 509 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c index 2ade88698f65..997deb5283bd 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c @@ -186,6 +186,19 @@ static netdev_tx_t octep_vf_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } +int octep_vf_get_link_info(struct octep_vf_device *oct) +{ + int ret, size; + + ret = octep_vf_mbox_bulk_read(oct, OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO, + (u8 *)&oct->link_info, &size); + if (ret) { + dev_err(&oct->pdev->dev, "Get VF link info failed via VF Mbox\n"); + return ret; + } + return 0; +} + /** * octep_vf_tx_timeout_task - work queue task to Handle Tx queue timeout. * @@ -412,11 +425,28 @@ static int octep_vf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto delete_mbox; } + if (octep_vf_mbox_get_fw_info(octep_vf_dev)) { + dev_err(&pdev->dev, "unable to get fw info\n"); + err = -EINVAL; + goto delete_mbox; + } + netdev->hw_features = NETIF_F_SG; + if (OCTEP_VF_TX_IP_CSUM(octep_vf_dev->fw_info.tx_ol_flags)) + netdev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + + if (OCTEP_VF_RX_IP_CSUM(octep_vf_dev->fw_info.rx_ol_flags)) + netdev->hw_features |= NETIF_F_RXCSUM; + netdev->min_mtu = OCTEP_VF_MIN_MTU; netdev->max_mtu = OCTEP_VF_MAX_MTU; netdev->mtu = OCTEP_VF_DEFAULT_MTU; + if (OCTEP_VF_TX_TSO(octep_vf_dev->fw_info.tx_ol_flags)) { + netdev->hw_features |= NETIF_F_TSO; + netif_set_tso_max_size(netdev, netdev->max_mtu); + } + netdev->features |= netdev->hw_features; octep_vf_get_mac_addr(octep_vf_dev, octep_vf_dev->mac_addr); eth_hw_addr_set(netdev, octep_vf_dev->mac_addr); diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h index 4359e0e585ec..5a3b545ad590 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h @@ -327,5 +327,7 @@ void octep_vf_device_setup_cn93(struct octep_vf_device *oct); void octep_vf_device_setup_cnxk(struct octep_vf_device *oct); int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget); int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget); +int octep_vf_get_link_info(struct octep_vf_device *oct); +int octep_vf_get_if_stats(struct octep_vf_device *oct); void octep_vf_mbox_work(struct work_struct *work); #endif /* _OCTEP_VF_MAIN_H_ */ diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c index 1c1fe293fc50..2eab21e43048 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c @@ -10,6 +10,15 @@ #include "octep_vf_config.h" #include "octep_vf_main.h" +/* When a new command is implemented, the below table should be updated + * with new command and it's version info. + */ +static u32 pfvf_cmd_versions[OCTEP_PFVF_MBOX_CMD_MAX] = { + [0 ... OCTEP_PFVF_MBOX_CMD_DEV_REMOVE] = OCTEP_PFVF_MBOX_VERSION_V1, + [OCTEP_PFVF_MBOX_CMD_GET_FW_INFO ... OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS] = + OCTEP_PFVF_MBOX_VERSION_V2 +}; + int octep_vf_setup_mbox(struct octep_vf_device *oct) { int ring = 0; @@ -23,6 +32,7 @@ int octep_vf_setup_mbox(struct octep_vf_device *oct) oct->hw_ops.setup_mbox_regs(oct, ring); INIT_WORK(&oct->mbox->wk.work, octep_vf_mbox_work); oct->mbox->wk.ctxptr = oct; + oct->mbox_neg_ver = OCTEP_PFVF_MBOX_VERSION_CURRENT; dev_info(&oct->pdev->dev, "setup vf mbox successfully\n"); return 0; } @@ -42,55 +52,379 @@ void octep_vf_delete_mbox(struct octep_vf_device *oct) int octep_vf_mbox_version_check(struct octep_vf_device *oct) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int ret; + + cmd.u64 = 0; + cmd.s_version.opcode = OCTEP_PFVF_MBOX_CMD_VERSION; + cmd.s_version.version = OCTEP_PFVF_MBOX_VERSION_CURRENT; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret == OCTEP_PFVF_MBOX_CMD_STATUS_NACK) { + dev_err(&oct->pdev->dev, + "VF Mbox version is incompatible with PF\n"); + return -EINVAL; + } + oct->mbox_neg_ver = (u32)rsp.s_version.version; + dev_dbg(&oct->pdev->dev, + "VF Mbox version:%u Negotiated VF version with PF:%u\n", + (u32)cmd.s_version.version, + (u32)rsp.s_version.version); return 0; } void octep_vf_mbox_work(struct work_struct *work) { + struct octep_vf_mbox_wk *wk = container_of(work, struct octep_vf_mbox_wk, work); + struct octep_vf_iface_link_info *link_info; + struct octep_vf_device *oct = NULL; + struct octep_vf_mbox *mbox = NULL; + union octep_pfvf_mbox_word *notif; + u64 pf_vf_data; + + oct = (struct octep_vf_device *)wk->ctxptr; + link_info = &oct->link_info; + mbox = oct->mbox; + pf_vf_data = readq(mbox->mbox_read_reg); + + notif = (union octep_pfvf_mbox_word *)&pf_vf_data; + + switch (notif->s.opcode) { + case OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS: + if (notif->s_link_status.status) { + link_info->oper_up = OCTEP_PFVF_LINK_STATUS_UP; + netif_carrier_on(oct->netdev); + dev_info(&oct->pdev->dev, "netif_carrier_on\n"); + } else { + link_info->oper_up = OCTEP_PFVF_LINK_STATUS_DOWN; + netif_carrier_off(oct->netdev); + dev_info(&oct->pdev->dev, "netif_carrier_off\n"); + } + break; + default: + dev_err(&oct->pdev->dev, + "Received unsupported notif %d\n", notif->s.opcode); + break; + } +} + +static int __octep_vf_mbox_send_cmd(struct octep_vf_device *oct, + union octep_pfvf_mbox_word cmd, + union octep_pfvf_mbox_word *rsp) +{ + struct octep_vf_mbox *mbox = oct->mbox; + u64 reg_val = 0ull; + int count; + + if (!mbox) + return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP; + + cmd.s.type = OCTEP_PFVF_MBOX_TYPE_CMD; + writeq(cmd.u64, mbox->mbox_write_reg); + + /* No response for notification messages */ + if (!rsp) + return 0; + + for (count = 0; count < OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT; count++) { + usleep_range(1000, 1500); + reg_val = readq(mbox->mbox_write_reg); + if (reg_val != cmd.u64) { + rsp->u64 = reg_val; + break; + } + } + if (count == OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT) { + dev_err(&oct->pdev->dev, "mbox send command timed out\n"); + return OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT; + } + if (rsp->s.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "mbox_send: Received NACK\n"); + return OCTEP_PFVF_MBOX_CMD_STATUS_NACK; + } + rsp->u64 = reg_val; + return 0; +} + +int octep_vf_mbox_send_cmd(struct octep_vf_device *oct, union octep_pfvf_mbox_word cmd, + union octep_pfvf_mbox_word *rsp) +{ + struct octep_vf_mbox *mbox = oct->mbox; + int ret; + + if (!mbox) + return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP; + mutex_lock(&mbox->lock); + if (pfvf_cmd_versions[cmd.s.opcode] > oct->mbox_neg_ver) { + dev_dbg(&oct->pdev->dev, "CMD:%d not supported in Version:%d\n", + cmd.s.opcode, oct->mbox_neg_ver); + mutex_unlock(&mbox->lock); + return -EOPNOTSUPP; + } + ret = __octep_vf_mbox_send_cmd(oct, cmd, rsp); + mutex_unlock(&mbox->lock); + return ret; +} + +int octep_vf_mbox_bulk_read(struct octep_vf_device *oct, enum octep_pfvf_mbox_opcode opcode, + u8 *data, int *size) +{ + struct octep_vf_mbox *mbox = oct->mbox; + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int data_len = 0, tmp_len = 0; + int read_cnt, i = 0, ret; + + if (!mbox) + return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP; + + mutex_lock(&mbox->lock); + cmd.u64 = 0; + cmd.s_data.opcode = opcode; + cmd.s_data.frag = 0; + /* Send cmd to read data from PF */ + ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n"); + mutex_unlock(&mbox->lock); + return ret; + } + /* PF sends the data length of requested CMD + * in ACK + */ + data_len = *((int32_t *)rsp.s_data.data); + tmp_len = data_len; + cmd.u64 = 0; + rsp.u64 = 0; + cmd.s_data.opcode = opcode; + cmd.s_data.frag = 1; + while (data_len) { + ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n"); + mutex_unlock(&mbox->lock); + mbox->mbox_data.data_index = 0; + memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE); + return ret; + } + if (data_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE) { + data_len -= OCTEP_PFVF_MBOX_MAX_DATA_SIZE; + read_cnt = OCTEP_PFVF_MBOX_MAX_DATA_SIZE; + } else { + read_cnt = data_len; + data_len = 0; + } + for (i = 0; i < read_cnt; i++) { + mbox->mbox_data.recv_data[mbox->mbox_data.data_index] = + rsp.s_data.data[i]; + mbox->mbox_data.data_index++; + } + cmd.u64 = 0; + rsp.u64 = 0; + cmd.s_data.opcode = opcode; + cmd.s_data.frag = 1; + } + memcpy(data, mbox->mbox_data.recv_data, tmp_len); + *size = tmp_len; + mbox->mbox_data.data_index = 0; + memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE); + mutex_unlock(&mbox->lock); + return 0; } int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu) { + int frame_size = mtu + ETH_HLEN + ETH_FCS_LEN; + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int ret = 0; + + if (mtu < ETH_MIN_MTU || frame_size > ETH_MAX_MTU) { + dev_err(&oct->pdev->dev, + "Failed to set MTU to %d MIN MTU:%d MAX MTU:%d\n", + mtu, ETH_MIN_MTU, ETH_MAX_MTU); + return -EINVAL; + } + + cmd.u64 = 0; + cmd.s_set_mtu.opcode = OCTEP_PFVF_MBOX_CMD_SET_MTU; + cmd.s_set_mtu.mtu = mtu; + + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "Mbox send failed; err=%d\n", ret); + return ret; + } + if (rsp.s_set_mtu.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "Received Mbox NACK from PF for MTU:%d\n", mtu); + return -EINVAL; + } + return 0; } int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int i, ret; + + cmd.u64 = 0; + cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR; + for (i = 0; i < ETH_ALEN; i++) + cmd.s_set_mac.mac_addr[i] = mac_addr[i]; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "Mbox send failed; err = %d\n", ret); + return ret; + } + if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "received NACK\n"); + return -EINVAL; + } return 0; } int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int i, ret; + + cmd.u64 = 0; + cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "get_mac: mbox send failed; err = %d\n", ret); + return ret; + } + if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "get_mac: received NACK\n"); + return -EINVAL; + } + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = rsp.s_set_mac.mac_addr[i]; return 0; } int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int ret; + + cmd.u64 = 0; + cmd.s_link_state.opcode = OCTEP_PFVF_MBOX_CMD_SET_RX_STATE; + cmd.s_link_state.state = state; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "Set Rx state via VF Mbox send failed\n"); + return ret; + } + if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "Set Rx state received NACK\n"); + return -EINVAL; + } return 0; } int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int ret; + + cmd.u64 = 0; + cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS; + cmd.s_link_status.status = status; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "Set link status via VF Mbox send failed\n"); + return ret; + } + if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "Set link status received NACK\n"); + return -EINVAL; + } return 0; } int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int ret; + + cmd.u64 = 0; + cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n"); + return ret; + } + if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "Get link status received NACK\n"); + return -EINVAL; + } + *oper_up = rsp.s_link_status.status; return 0; } int octep_vf_mbox_dev_remove(struct octep_vf_device *oct) { - return 0; + union octep_pfvf_mbox_word cmd; + int ret; + + cmd.u64 = 0; + cmd.s.opcode = OCTEP_PFVF_MBOX_CMD_DEV_REMOVE; + ret = octep_vf_mbox_send_cmd(oct, cmd, NULL); + return ret; } int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int ret; + + cmd.u64 = 0; + cmd.s_fw_info.opcode = OCTEP_PFVF_MBOX_CMD_GET_FW_INFO; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n"); + return ret; + } + if (rsp.s_fw_info.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "Get link status received NACK\n"); + return -EINVAL; + } + oct->fw_info.pkind = rsp.s_fw_info.pkind; + oct->fw_info.fsz = rsp.s_fw_info.fsz; + oct->fw_info.rx_ol_flags = rsp.s_fw_info.rx_ol_flags; + oct->fw_info.tx_ol_flags = rsp.s_fw_info.tx_ol_flags; + return 0; } int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads, u16 rx_offloads) { + union octep_pfvf_mbox_word cmd; + union octep_pfvf_mbox_word rsp; + int ret; + + cmd.u64 = 0; + cmd.s_offloads.opcode = OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS; + cmd.s_offloads.rx_ol_flags = rx_offloads; + cmd.s_offloads.tx_ol_flags = tx_offloads; + ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); + if (ret) { + dev_err(&oct->pdev->dev, "Set offloads via VF Mbox send failed\n"); + return ret; + } + if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { + dev_err(&oct->pdev->dev, "Set offloads received NACK\n"); + return -EINVAL; + } return 0; } diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h index 14f4fb19445b..9b5efad37eab 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.h @@ -7,10 +7,151 @@ #ifndef _OCTEP_VF_MBOX_H_ #define _OCTEP_VF_MBOX_H_ -#define OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE 256 +/* When a new command is implemented, VF Mbox version should be bumped. + */ +enum octep_pfvf_mbox_version { + OCTEP_PFVF_MBOX_VERSION_V0, + OCTEP_PFVF_MBOX_VERSION_V1, + OCTEP_PFVF_MBOX_VERSION_V2 +}; + +#define OCTEP_PFVF_MBOX_VERSION_CURRENT OCTEP_PFVF_MBOX_VERSION_V2 + +enum octep_pfvf_mbox_opcode { + OCTEP_PFVF_MBOX_CMD_VERSION, + OCTEP_PFVF_MBOX_CMD_SET_MTU, + OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR, + OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR, + OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO, + OCTEP_PFVF_MBOX_CMD_GET_STATS, + OCTEP_PFVF_MBOX_CMD_SET_RX_STATE, + OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS, + OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS, + OCTEP_PFVF_MBOX_CMD_GET_MTU, + OCTEP_PFVF_MBOX_CMD_DEV_REMOVE, + OCTEP_PFVF_MBOX_CMD_GET_FW_INFO, + OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS, + OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS, + OCTEP_PFVF_MBOX_CMD_MAX, +}; + +enum octep_pfvf_mbox_word_type { + OCTEP_PFVF_MBOX_TYPE_CMD, + OCTEP_PFVF_MBOX_TYPE_RSP_ACK, + OCTEP_PFVF_MBOX_TYPE_RSP_NACK, +}; + +enum octep_pfvf_mbox_cmd_status { + OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP = 1, + OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT = 2, + OCTEP_PFVF_MBOX_CMD_STATUS_NACK = 3, + OCTEP_PFVF_MBOX_CMD_STATUS_BUSY = 4, + OCTEP_PFVF_MBOX_CMD_STATUS_ERR = 5 +}; + +enum octep_pfvf_link_status { + OCTEP_PFVF_LINK_STATUS_DOWN, + OCTEP_PFVF_LINK_STATUS_UP, +}; + +enum octep_pfvf_link_speed { + OCTEP_PFVF_LINK_SPEED_NONE, + OCTEP_PFVF_LINK_SPEED_1000, + OCTEP_PFVF_LINK_SPEED_10000, + OCTEP_PFVF_LINK_SPEED_25000, + OCTEP_PFVF_LINK_SPEED_40000, + OCTEP_PFVF_LINK_SPEED_50000, + OCTEP_PFVF_LINK_SPEED_100000, + OCTEP_PFVF_LINK_SPEED_LAST, +}; + +enum octep_pfvf_link_duplex { + OCTEP_PFVF_LINK_HALF_DUPLEX, + OCTEP_PFVF_LINK_FULL_DUPLEX, +}; + +enum octep_pfvf_link_autoneg { + OCTEP_PFVF_LINK_AUTONEG, + OCTEP_PFVF_LINK_FIXED, +}; + +#define OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT 8000 +#define OCTEP_PFVF_MBOX_TIMEOUT_WAIT_UDELAY 1000 +#define OCTEP_PFVF_MBOX_MAX_RETRIES 2 +#define OCTEP_PFVF_MBOX_VERSION 0 +#define OCTEP_PFVF_MBOX_MAX_DATA_SIZE 6 +#define OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE 320 +#define OCTEP_PFVF_MBOX_MORE_FRAG_FLAG 1 + +union octep_pfvf_mbox_word { + u64 u64; + struct { + u64 opcode:8; + u64 type:2; + u64 rsvd:6; + u64 data:48; + } s; + struct { + u64 opcode:8; + u64 type:2; + u64 frag:1; + u64 rsvd:5; + u8 data[6]; + } s_data; + struct { + u64 opcode:8; + u64 type:2; + u64 rsvd:6; + u64 version:48; + } s_version; + struct { + u64 opcode:8; + u64 type:2; + u64 rsvd:6; + u8 mac_addr[6]; + } s_set_mac; + struct { + u64 opcode:8; + u64 type:2; + u64 rsvd:6; + u64 mtu:48; + } s_set_mtu; + struct { + u64 opcode:8; + u64 type:2; + u64 state:1; + u64 rsvd:53; + } s_link_state; + struct { + u64 opcode:8; + u64 type:2; + u64 status:1; + u64 rsvd:53; + } s_link_status; + struct { + u64 opcode:8; + u64 type:2; + u64 pkind:8; + u64 fsz:8; + u64 rx_ol_flags:16; + u64 tx_ol_flags:16; + u64 rsvd:6; + } s_fw_info; + struct { + u64 opcode:8; + u64 type:2; + u64 rsvd:22; + u64 rx_ol_flags:16; + u64 tx_ol_flags:16; + } s_offloads; +} __packed; int octep_vf_setup_mbox(struct octep_vf_device *oct); void octep_vf_delete_mbox(struct octep_vf_device *oct); +int octep_vf_mbox_send_cmd(struct octep_vf_device *oct, union octep_pfvf_mbox_word cmd, + union octep_pfvf_mbox_word *rsp); +int octep_vf_mbox_bulk_read(struct octep_vf_device *oct, enum octep_pfvf_mbox_opcode opcode, + u8 *data, int *size); int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu); int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr); int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr); From ca6ecb0d3c3a0f470fc31ff2a3b22e4feb3fbe73 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:36 -0800 Subject: [PATCH 1046/2255] octeon_ep_vf: add Tx/Rx ring resource setup and cleanup Implement Tx/Rx ring resource allocation and cleanup. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../marvell/octeon_ep_vf/octep_vf_rx.c | 223 +++++++++++++++++- .../marvell/octeon_ep_vf/octep_vf_tx.c | 216 +++++++++++++++++ 2 files changed, 438 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c index 4f1a8157ce39..330d6e72bc0b 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c @@ -7,10 +7,198 @@ #include #include +#include #include "octep_vf_config.h" #include "octep_vf_main.h" +static void octep_vf_oq_reset_indices(struct octep_vf_oq *oq) +{ + oq->host_read_idx = 0; + oq->host_refill_idx = 0; + oq->refill_count = 0; + oq->last_pkt_count = 0; + oq->pkts_pending = 0; +} + +/** + * octep_vf_oq_fill_ring_buffers() - fill initial receive buffers for Rx ring. + * + * @oq: Octeon Rx queue data structure. + * + * Return: 0, if successfully filled receive buffers for all descriptors. + * -ENOMEM, if failed to allocate a buffer or failed to map for DMA. + */ +static int octep_vf_oq_fill_ring_buffers(struct octep_vf_oq *oq) +{ + struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring; + struct page *page; + u32 i; + + for (i = 0; i < oq->max_count; i++) { + page = dev_alloc_page(); + if (unlikely(!page)) { + dev_err(oq->dev, "Rx buffer alloc failed\n"); + goto rx_buf_alloc_err; + } + desc_ring[i].buffer_ptr = dma_map_page(oq->dev, page, 0, + PAGE_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(oq->dev, desc_ring[i].buffer_ptr)) { + dev_err(oq->dev, + "OQ-%d buffer alloc: DMA mapping error!\n", + oq->q_no); + goto dma_map_err; + } + oq->buff_info[i].page = page; + } + + return 0; + +dma_map_err: + put_page(page); +rx_buf_alloc_err: + while (i) { + i--; + dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr, PAGE_SIZE, DMA_FROM_DEVICE); + put_page(oq->buff_info[i].page); + oq->buff_info[i].page = NULL; + } + + return -ENOMEM; +} + +/** + * octep_vf_setup_oq() - Setup a Rx queue. + * + * @oct: Octeon device private data structure. + * @q_no: Rx queue number to be setup. + * + * Allocate resources for a Rx queue. + */ +static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no) +{ + struct octep_vf_oq *oq; + u32 desc_ring_size; + + oq = vzalloc(sizeof(*oq)); + if (!oq) + goto create_oq_fail; + oct->oq[q_no] = oq; + + oq->octep_vf_dev = oct; + oq->netdev = oct->netdev; + oq->dev = &oct->pdev->dev; + oq->q_no = q_no; + oq->max_count = CFG_GET_OQ_NUM_DESC(oct->conf); + oq->ring_size_mask = oq->max_count - 1; + oq->buffer_size = CFG_GET_OQ_BUF_SIZE(oct->conf); + oq->max_single_buffer_size = oq->buffer_size - OCTEP_VF_OQ_RESP_HW_SIZE; + + /* When the hardware/firmware supports additional capabilities, + * additional header is filled-in by Octeon after length field in + * Rx packets. this header contains additional packet information. + */ + if (oct->fw_info.rx_ol_flags) + oq->max_single_buffer_size -= OCTEP_VF_OQ_RESP_HW_EXT_SIZE; + + oq->refill_threshold = CFG_GET_OQ_REFILL_THRESHOLD(oct->conf); + + desc_ring_size = oq->max_count * OCTEP_VF_OQ_DESC_SIZE; + oq->desc_ring = dma_alloc_coherent(oq->dev, desc_ring_size, + &oq->desc_ring_dma, GFP_KERNEL); + + if (unlikely(!oq->desc_ring)) { + dev_err(oq->dev, + "Failed to allocate DMA memory for OQ-%d !!\n", q_no); + goto desc_dma_alloc_err; + } + + oq->buff_info = vzalloc(oq->max_count * OCTEP_VF_OQ_RECVBUF_SIZE); + + if (unlikely(!oq->buff_info)) { + dev_err(&oct->pdev->dev, + "Failed to allocate buffer info for OQ-%d\n", q_no); + goto buf_list_err; + } + + if (octep_vf_oq_fill_ring_buffers(oq)) + goto oq_fill_buff_err; + + octep_vf_oq_reset_indices(oq); + oct->hw_ops.setup_oq_regs(oct, q_no); + oct->num_oqs++; + + return 0; + +oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +buf_list_err: + dma_free_coherent(oq->dev, desc_ring_size, + oq->desc_ring, oq->desc_ring_dma); + oq->desc_ring = NULL; +desc_dma_alloc_err: + vfree(oq); + oct->oq[q_no] = NULL; +create_oq_fail: + return -ENOMEM; +} + +/** + * octep_vf_oq_free_ring_buffers() - Free ring buffers. + * + * @oq: Octeon Rx queue data structure. + * + * Free receive buffers in unused Rx queue descriptors. + */ +static void octep_vf_oq_free_ring_buffers(struct octep_vf_oq *oq) +{ + struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring; + int i; + + if (!oq->desc_ring || !oq->buff_info) + return; + + for (i = 0; i < oq->max_count; i++) { + if (oq->buff_info[i].page) { + dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr, + PAGE_SIZE, DMA_FROM_DEVICE); + put_page(oq->buff_info[i].page); + oq->buff_info[i].page = NULL; + desc_ring[i].buffer_ptr = 0; + } + } + octep_vf_oq_reset_indices(oq); +} + +/** + * octep_vf_free_oq() - Free Rx queue resources. + * + * @oq: Octeon Rx queue data structure. + * + * Free all resources of a Rx queue. + */ +static int octep_vf_free_oq(struct octep_vf_oq *oq) +{ + struct octep_vf_device *oct = oq->octep_vf_dev; + int q_no = oq->q_no; + + octep_vf_oq_free_ring_buffers(oq); + + vfree(oq->buff_info); + + if (oq->desc_ring) + dma_free_coherent(oq->dev, + oq->max_count * OCTEP_VF_OQ_DESC_SIZE, + oq->desc_ring, oq->desc_ring_dma); + + vfree(oq); + oct->oq[q_no] = NULL; + oct->num_oqs--; + return 0; +} + /** * octep_vf_setup_oqs() - setup resources for all Rx queues. * @@ -18,7 +206,27 @@ */ int octep_vf_setup_oqs(struct octep_vf_device *oct) { - return -1; + int i, retval = 0; + + oct->num_oqs = 0; + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { + retval = octep_vf_setup_oq(oct, i); + if (retval) { + dev_err(&oct->pdev->dev, + "Failed to setup OQ(RxQ)-%d.\n", i); + goto oq_setup_err; + } + dev_dbg(&oct->pdev->dev, "Successfully setup OQ(RxQ)-%d.\n", i); + } + + return 0; + +oq_setup_err: + while (i) { + i--; + octep_vf_free_oq(oct->oq[i]); + } + return retval; } /** @@ -30,6 +238,10 @@ int octep_vf_setup_oqs(struct octep_vf_device *oct) */ void octep_vf_oq_dbell_init(struct octep_vf_device *oct) { + int i; + + for (i = 0; i < oct->num_oqs; i++) + writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); } /** @@ -39,4 +251,13 @@ void octep_vf_oq_dbell_init(struct octep_vf_device *oct) */ void octep_vf_free_oqs(struct octep_vf_device *oct) { + int i; + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { + if (!oct->oq[i]) + continue; + octep_vf_free_oq(oct->oq[i]); + dev_dbg(&oct->pdev->dev, + "Successfully freed OQ(RxQ)-%d.\n", i); + } } diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c index 232ba479ecf6..1a3e1a651dc4 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c @@ -7,10 +7,73 @@ #include #include +#include #include "octep_vf_config.h" #include "octep_vf_main.h" +/* Reset various index of Tx queue data structure. */ +static void octep_vf_iq_reset_indices(struct octep_vf_iq *iq) +{ + iq->fill_cnt = 0; + iq->host_write_index = 0; + iq->octep_vf_read_index = 0; + iq->flush_index = 0; + iq->pkts_processed = 0; + iq->pkt_in_done = 0; +} + +/** + * octep_vf_iq_free_pending() - Free Tx buffers for pending completions. + * + * @iq: Octeon Tx queue data structure. + */ +static void octep_vf_iq_free_pending(struct octep_vf_iq *iq) +{ + struct octep_vf_tx_buffer *tx_buffer; + struct skb_shared_info *shinfo; + u32 fi = iq->flush_index; + struct sk_buff *skb; + u8 frags, i; + + while (fi != iq->host_write_index) { + tx_buffer = iq->buff_info + fi; + skb = tx_buffer->skb; + + fi++; + if (unlikely(fi == iq->max_count)) + fi = 0; + + if (!tx_buffer->gather) { + dma_unmap_single(iq->dev, tx_buffer->dma, + tx_buffer->skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + continue; + } + + /* Scatter/Gather */ + shinfo = skb_shinfo(skb); + frags = shinfo->nr_frags; + + dma_unmap_single(iq->dev, + tx_buffer->sglist[0].dma_ptr[0], + tx_buffer->sglist[0].len[0], + DMA_TO_DEVICE); + + i = 1; /* entry 0 is main skb, unmapped above */ + while (frags--) { + dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], + tx_buffer->sglist[i >> 2].len[i & 3], DMA_TO_DEVICE); + i++; + } + + dev_kfree_skb_any(skb); + } + + iq->flush_index = fi; + netdev_tx_reset_queue(netdev_get_tx_queue(iq->netdev, iq->q_no)); +} + /** * octep_vf_clean_iqs() - Clean Tx queues to shutdown the device. * @@ -21,6 +84,132 @@ */ void octep_vf_clean_iqs(struct octep_vf_device *oct) { + int i; + + for (i = 0; i < oct->num_iqs; i++) { + octep_vf_iq_free_pending(oct->iq[i]); + octep_vf_iq_reset_indices(oct->iq[i]); + } +} + +/** + * octep_vf_setup_iq() - Setup a Tx queue. + * + * @oct: Octeon device private data structure. + * @q_no: Tx queue number to be setup. + * + * Allocate resources for a Tx queue. + */ +static int octep_vf_setup_iq(struct octep_vf_device *oct, int q_no) +{ + u32 desc_ring_size, buff_info_size, sglist_size; + struct octep_vf_iq *iq; + int i; + + iq = vzalloc(sizeof(*iq)); + if (!iq) + goto iq_alloc_err; + oct->iq[q_no] = iq; + + iq->octep_vf_dev = oct; + iq->netdev = oct->netdev; + iq->dev = &oct->pdev->dev; + iq->q_no = q_no; + iq->max_count = CFG_GET_IQ_NUM_DESC(oct->conf); + iq->ring_size_mask = iq->max_count - 1; + iq->fill_threshold = CFG_GET_IQ_DB_MIN(oct->conf); + iq->netdev_q = netdev_get_tx_queue(iq->netdev, q_no); + + /* Allocate memory for hardware queue descriptors */ + desc_ring_size = OCTEP_VF_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf); + iq->desc_ring = dma_alloc_coherent(iq->dev, desc_ring_size, + &iq->desc_ring_dma, GFP_KERNEL); + if (unlikely(!iq->desc_ring)) { + dev_err(iq->dev, + "Failed to allocate DMA memory for IQ-%d\n", q_no); + goto desc_dma_alloc_err; + } + + /* Allocate memory for hardware SGLIST descriptors */ + sglist_size = OCTEP_VF_SGLIST_SIZE_PER_PKT * + CFG_GET_IQ_NUM_DESC(oct->conf); + iq->sglist = dma_alloc_coherent(iq->dev, sglist_size, + &iq->sglist_dma, GFP_KERNEL); + if (unlikely(!iq->sglist)) { + dev_err(iq->dev, + "Failed to allocate DMA memory for IQ-%d SGLIST\n", + q_no); + goto sglist_alloc_err; + } + + /* allocate memory to manage Tx packets pending completion */ + buff_info_size = OCTEP_VF_IQ_TXBUFF_INFO_SIZE * iq->max_count; + iq->buff_info = vzalloc(buff_info_size); + if (!iq->buff_info) { + dev_err(iq->dev, + "Failed to allocate buff info for IQ-%d\n", q_no); + goto buff_info_err; + } + + /* Setup sglist addresses in tx_buffer entries */ + for (i = 0; i < CFG_GET_IQ_NUM_DESC(oct->conf); i++) { + struct octep_vf_tx_buffer *tx_buffer; + + tx_buffer = &iq->buff_info[i]; + tx_buffer->sglist = + &iq->sglist[i * OCTEP_VF_SGLIST_ENTRIES_PER_PKT]; + tx_buffer->sglist_dma = + iq->sglist_dma + (i * OCTEP_VF_SGLIST_SIZE_PER_PKT); + } + + octep_vf_iq_reset_indices(iq); + oct->hw_ops.setup_iq_regs(oct, q_no); + + oct->num_iqs++; + return 0; + +buff_info_err: + dma_free_coherent(iq->dev, sglist_size, iq->sglist, iq->sglist_dma); +sglist_alloc_err: + dma_free_coherent(iq->dev, desc_ring_size, + iq->desc_ring, iq->desc_ring_dma); +desc_dma_alloc_err: + vfree(iq); + oct->iq[q_no] = NULL; +iq_alloc_err: + return -1; +} + +/** + * octep_vf_free_iq() - Free Tx queue resources. + * + * @iq: Octeon Tx queue data structure. + * + * Free all the resources allocated for a Tx queue. + */ +static void octep_vf_free_iq(struct octep_vf_iq *iq) +{ + struct octep_vf_device *oct = iq->octep_vf_dev; + u64 desc_ring_size, sglist_size; + int q_no = iq->q_no; + + desc_ring_size = OCTEP_VF_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf); + + vfree(iq->buff_info); + + if (iq->desc_ring) + dma_free_coherent(iq->dev, desc_ring_size, + iq->desc_ring, iq->desc_ring_dma); + + sglist_size = OCTEP_VF_SGLIST_SIZE_PER_PKT * + CFG_GET_IQ_NUM_DESC(oct->conf); + if (iq->sglist) + dma_free_coherent(iq->dev, sglist_size, + iq->sglist, iq->sglist_dma); + + vfree(iq); + oct->iq[q_no] = NULL; + oct->num_iqs--; } /** @@ -30,6 +219,25 @@ void octep_vf_clean_iqs(struct octep_vf_device *oct) */ int octep_vf_setup_iqs(struct octep_vf_device *oct) { + int i; + + oct->num_iqs = 0; + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { + if (octep_vf_setup_iq(oct, i)) { + dev_err(&oct->pdev->dev, + "Failed to setup IQ(TxQ)-%d.\n", i); + goto iq_setup_err; + } + dev_dbg(&oct->pdev->dev, "Successfully setup IQ(TxQ)-%d.\n", i); + } + + return 0; + +iq_setup_err: + while (i) { + i--; + octep_vf_free_iq(oct->iq[i]); + } return -1; } @@ -40,4 +248,12 @@ int octep_vf_setup_iqs(struct octep_vf_device *oct) */ void octep_vf_free_iqs(struct octep_vf_device *oct) { + int i; + + for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { + octep_vf_free_iq(oct->iq[i]); + dev_dbg(&oct->pdev->dev, + "Successfully destroyed IQ(TxQ)-%d.\n", i); + } + oct->num_iqs = 0; } From c3fad23cdc069aeff8f1b22a27e8a471c1d9d517 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:37 -0800 Subject: [PATCH 1047/2255] octeon_ep_vf: add support for ndo ops Add support for ndo ops to set MAC address, change MTU, get stats. Add control path support to set MAC address, change MTU, get stats, set speed, get and set link mode. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../marvell/octeon_ep_vf/octep_vf_main.c | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c index 997deb5283bd..ca823933b9fd 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c @@ -186,6 +186,26 @@ static netdev_tx_t octep_vf_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } +int octep_vf_get_if_stats(struct octep_vf_device *oct) +{ + struct octep_vf_iface_rxtx_stats vf_stats; + int ret, size; + + memset(&vf_stats, 0, sizeof(struct octep_vf_iface_rxtx_stats)); + ret = octep_vf_mbox_bulk_read(oct, OCTEP_PFVF_MBOX_CMD_GET_STATS, + (u8 *)&vf_stats, &size); + + if (ret) + return ret; + + memcpy(&oct->iface_rx_stats, &vf_stats.iface_rx_stats, + sizeof(struct octep_vf_iface_rx_stats)); + memcpy(&oct->iface_tx_stats, &vf_stats.iface_tx_stats, + sizeof(struct octep_vf_iface_tx_stats)); + + return 0; +} + int octep_vf_get_link_info(struct octep_vf_device *oct) { int ret, size; @@ -199,6 +219,46 @@ int octep_vf_get_link_info(struct octep_vf_device *oct) return 0; } +/** + * octep_vf_get_stats64() - Get Octeon network device statistics. + * + * @netdev: kernel network device. + * @stats: pointer to stats structure to be filled in. + */ +static void octep_vf_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + u64 tx_packets, tx_bytes, rx_packets, rx_bytes; + int q; + + tx_packets = 0; + tx_bytes = 0; + rx_packets = 0; + rx_bytes = 0; + for (q = 0; q < oct->num_oqs; q++) { + struct octep_vf_iq *iq = oct->iq[q]; + struct octep_vf_oq *oq = oct->oq[q]; + + tx_packets += iq->stats.instr_completed; + tx_bytes += iq->stats.bytes_sent; + rx_packets += oq->stats.packets; + rx_bytes += oq->stats.bytes; + } + stats->tx_packets = tx_packets; + stats->tx_bytes = tx_bytes; + stats->rx_packets = rx_packets; + stats->rx_bytes = rx_bytes; + if (!octep_vf_get_if_stats(oct)) { + stats->multicast = oct->iface_rx_stats.mcast_pkts; + stats->rx_errors = oct->iface_rx_stats.err_pkts; + stats->rx_dropped = oct->iface_rx_stats.dropped_pkts_fifo_full + + oct->iface_rx_stats.err_pkts; + stats->rx_missed_errors = oct->iface_rx_stats.dropped_pkts_fifo_full; + stats->tx_dropped = oct->iface_tx_stats.dropped; + } +} + /** * octep_vf_tx_timeout_task - work queue task to Handle Tx queue timeout. * @@ -239,11 +299,85 @@ static void octep_vf_tx_timeout(struct net_device *netdev, unsigned int txqueue) schedule_work(&oct->tx_timeout_task); } +static int octep_vf_set_mac(struct net_device *netdev, void *p) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + struct sockaddr *addr = (struct sockaddr *)p; + int err; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + err = octep_vf_mbox_set_mac_addr(oct, addr->sa_data); + if (err) + return err; + + memcpy(oct->mac_addr, addr->sa_data, ETH_ALEN); + eth_hw_addr_set(netdev, addr->sa_data); + + return 0; +} + +static int octep_vf_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + struct octep_vf_iface_link_info *link_info; + int err; + + link_info = &oct->link_info; + if (link_info->mtu == new_mtu) + return 0; + + err = octep_vf_mbox_set_mtu(oct, new_mtu); + if (!err) { + oct->link_info.mtu = new_mtu; + netdev->mtu = new_mtu; + } + return err; +} + +static int octep_vf_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + u16 rx_offloads = 0, tx_offloads = 0; + int err; + + /* We only support features received from firmware */ + if ((features & netdev->hw_features) != features) + return -EINVAL; + + if (features & NETIF_F_TSO) + tx_offloads |= OCTEP_VF_TX_OFFLOAD_TSO; + + if (features & NETIF_F_TSO6) + tx_offloads |= OCTEP_VF_TX_OFFLOAD_TSO; + + if (features & NETIF_F_IP_CSUM) + tx_offloads |= OCTEP_VF_TX_OFFLOAD_CKSUM; + + if (features & NETIF_F_IPV6_CSUM) + tx_offloads |= OCTEP_VF_TX_OFFLOAD_CKSUM; + + if (features & NETIF_F_RXCSUM) + rx_offloads |= OCTEP_VF_RX_OFFLOAD_CKSUM; + + err = octep_vf_mbox_set_offloads(oct, tx_offloads, rx_offloads); + if (!err) + netdev->features = features; + + return err; +} + static const struct net_device_ops octep_vf_netdev_ops = { .ndo_open = octep_vf_open, .ndo_stop = octep_vf_stop, .ndo_start_xmit = octep_vf_start_xmit, + .ndo_get_stats64 = octep_vf_get_stats64, .ndo_tx_timeout = octep_vf_tx_timeout, + .ndo_set_mac_address = octep_vf_set_mac, + .ndo_change_mtu = octep_vf_change_mtu, + .ndo_set_features = octep_vf_set_features, }; static const char *octep_vf_devid_to_str(struct octep_vf_device *oct) From 1cd3b407977c3ab1d2ddc26cb7113e7fb1509cd1 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:38 -0800 Subject: [PATCH 1048/2255] octeon_ep_vf: add Tx/Rx processing and interrupt support Add support to enable MSI-x and register interrupts. Add support to process Tx and Rx traffic. Includes processing Tx completions and Rx refill. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../marvell/octeon_ep_vf/octep_vf_main.c | 550 ++++++++++++++++++ .../marvell/octeon_ep_vf/octep_vf_rx.c | 247 ++++++++ .../marvell/octeon_ep_vf/octep_vf_tx.c | 71 +++ 3 files changed, 868 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c index ca823933b9fd..e5d258980547 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "octep_vf_config.h" #include "octep_vf_main.h" @@ -36,6 +37,372 @@ MODULE_AUTHOR("Veerasenareddy Burru "); MODULE_DESCRIPTION(OCTEP_VF_DRV_STRING); MODULE_LICENSE("GPL"); +/** + * octep_vf_alloc_ioq_vectors() - Allocate Tx/Rx Queue interrupt info. + * + * @oct: Octeon device private data structure. + * + * Allocate resources to hold per Tx/Rx queue interrupt info. + * This is the information passed to interrupt handler, from which napi poll + * is scheduled and includes quick access to private data of Tx/Rx queue + * corresponding to the interrupt being handled. + * + * Return: 0, on successful allocation of resources for all queue interrupts. + * -1, if failed to allocate any resource. + */ +static int octep_vf_alloc_ioq_vectors(struct octep_vf_device *oct) +{ + struct octep_vf_ioq_vector *ioq_vector; + int i; + + for (i = 0; i < oct->num_oqs; i++) { + oct->ioq_vector[i] = vzalloc(sizeof(*oct->ioq_vector[i])); + if (!oct->ioq_vector[i]) + goto free_ioq_vector; + + ioq_vector = oct->ioq_vector[i]; + ioq_vector->iq = oct->iq[i]; + ioq_vector->oq = oct->oq[i]; + ioq_vector->octep_vf_dev = oct; + } + + dev_info(&oct->pdev->dev, "Allocated %d IOQ vectors\n", oct->num_oqs); + return 0; + +free_ioq_vector: + while (i) { + i--; + vfree(oct->ioq_vector[i]); + oct->ioq_vector[i] = NULL; + } + return -1; +} + +/** + * octep_vf_free_ioq_vectors() - Free Tx/Rx Queue interrupt vector info. + * + * @oct: Octeon device private data structure. + */ +static void octep_vf_free_ioq_vectors(struct octep_vf_device *oct) +{ + int i; + + for (i = 0; i < oct->num_oqs; i++) { + if (oct->ioq_vector[i]) { + vfree(oct->ioq_vector[i]); + oct->ioq_vector[i] = NULL; + } + } + netdev_info(oct->netdev, "Freed IOQ Vectors\n"); +} + +/** + * octep_vf_enable_msix_range() - enable MSI-x interrupts. + * + * @oct: Octeon device private data structure. + * + * Allocate and enable all MSI-x interrupts (queue and non-queue interrupts) + * for the Octeon device. + * + * Return: 0, on successfully enabling all MSI-x interrupts. + * -1, if failed to enable any MSI-x interrupt. + */ +static int octep_vf_enable_msix_range(struct octep_vf_device *oct) +{ + int num_msix, msix_allocated; + int i; + + /* Generic interrupts apart from input/output queues */ + //num_msix = oct->num_oqs + CFG_GET_NON_IOQ_MSIX(oct->conf); + num_msix = oct->num_oqs; + oct->msix_entries = kcalloc(num_msix, sizeof(struct msix_entry), GFP_KERNEL); + if (!oct->msix_entries) + goto msix_alloc_err; + + for (i = 0; i < num_msix; i++) + oct->msix_entries[i].entry = i; + + msix_allocated = pci_enable_msix_range(oct->pdev, oct->msix_entries, + num_msix, num_msix); + if (msix_allocated != num_msix) { + dev_err(&oct->pdev->dev, + "Failed to enable %d msix irqs; got only %d\n", + num_msix, msix_allocated); + goto enable_msix_err; + } + oct->num_irqs = msix_allocated; + dev_info(&oct->pdev->dev, "MSI-X enabled successfully\n"); + + return 0; + +enable_msix_err: + if (msix_allocated > 0) + pci_disable_msix(oct->pdev); + kfree(oct->msix_entries); + oct->msix_entries = NULL; +msix_alloc_err: + return -1; +} + +/** + * octep_vf_disable_msix() - disable MSI-x interrupts. + * + * @oct: Octeon device private data structure. + * + * Disable MSI-x on the Octeon device. + */ +static void octep_vf_disable_msix(struct octep_vf_device *oct) +{ + pci_disable_msix(oct->pdev); + kfree(oct->msix_entries); + oct->msix_entries = NULL; + dev_info(&oct->pdev->dev, "Disabled MSI-X\n"); +} + +/** + * octep_vf_ioq_intr_handler() - handler for all Tx/Rx queue interrupts. + * + * @irq: Interrupt number. + * @data: interrupt data contains pointers to Tx/Rx queue private data + * and correspong NAPI context. + * + * this is common handler for all non-queue (generic) interrupts. + */ +static irqreturn_t octep_vf_ioq_intr_handler(int irq, void *data) +{ + struct octep_vf_ioq_vector *ioq_vector = data; + struct octep_vf_device *oct = ioq_vector->octep_vf_dev; + + return oct->hw_ops.ioq_intr_handler(ioq_vector); +} + +/** + * octep_vf_request_irqs() - Register interrupt handlers. + * + * @oct: Octeon device private data structure. + * + * Register handlers for all queue and non-queue interrupts. + * + * Return: 0, on successful registration of all interrupt handlers. + * -1, on any error. + */ +static int octep_vf_request_irqs(struct octep_vf_device *oct) +{ + struct net_device *netdev = oct->netdev; + struct octep_vf_ioq_vector *ioq_vector; + struct msix_entry *msix_entry; + int ret, i; + + /* Request IRQs for Tx/Rx queues */ + for (i = 0; i < oct->num_oqs; i++) { + ioq_vector = oct->ioq_vector[i]; + msix_entry = &oct->msix_entries[i]; + + snprintf(ioq_vector->name, sizeof(ioq_vector->name), + "%s-q%d", netdev->name, i); + ret = request_irq(msix_entry->vector, + octep_vf_ioq_intr_handler, 0, + ioq_vector->name, ioq_vector); + if (ret) { + netdev_err(netdev, + "request_irq failed for Q-%d; err=%d", + i, ret); + goto ioq_irq_err; + } + + cpumask_set_cpu(i % num_online_cpus(), + &ioq_vector->affinity_mask); + irq_set_affinity_hint(msix_entry->vector, + &ioq_vector->affinity_mask); + } + + return 0; +ioq_irq_err: + while (i) { + --i; + free_irq(oct->msix_entries[i].vector, oct); + } + return -1; +} + +/** + * octep_vf_free_irqs() - free all registered interrupts. + * + * @oct: Octeon device private data structure. + * + * Free all queue and non-queue interrupts of the Octeon device. + */ +static void octep_vf_free_irqs(struct octep_vf_device *oct) +{ + int i; + + for (i = 0; i < oct->num_irqs; i++) { + irq_set_affinity_hint(oct->msix_entries[i].vector, NULL); + free_irq(oct->msix_entries[i].vector, oct->ioq_vector[i]); + } + netdev_info(oct->netdev, "IRQs freed\n"); +} + +/** + * octep_vf_setup_irqs() - setup interrupts for the Octeon device. + * + * @oct: Octeon device private data structure. + * + * Allocate data structures to hold per interrupt information, allocate/enable + * MSI-x interrupt and register interrupt handlers. + * + * Return: 0, on successful allocation and registration of all interrupts. + * -1, on any error. + */ +static int octep_vf_setup_irqs(struct octep_vf_device *oct) +{ + if (octep_vf_alloc_ioq_vectors(oct)) + goto ioq_vector_err; + + if (octep_vf_enable_msix_range(oct)) + goto enable_msix_err; + + if (octep_vf_request_irqs(oct)) + goto request_irq_err; + + return 0; + +request_irq_err: + octep_vf_disable_msix(oct); +enable_msix_err: + octep_vf_free_ioq_vectors(oct); +ioq_vector_err: + return -1; +} + +/** + * octep_vf_clean_irqs() - free all interrupts and its resources. + * + * @oct: Octeon device private data structure. + */ +static void octep_vf_clean_irqs(struct octep_vf_device *oct) +{ + octep_vf_free_irqs(oct); + octep_vf_disable_msix(oct); + octep_vf_free_ioq_vectors(oct); +} + +/** + * octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue. + * + * @iq: Octeon Tx queue data structure. + * @oq: Octeon Rx queue data structure. + */ +static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq, struct octep_vf_oq *oq) +{ + u32 pkts_pend = oq->pkts_pending; + + netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no); + if (iq->pkts_processed) { + writel(iq->pkts_processed, iq->inst_cnt_reg); + iq->pkt_in_done -= iq->pkts_processed; + iq->pkts_processed = 0; + } + if (oq->last_pkt_count - pkts_pend) { + writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg); + oq->last_pkt_count = pkts_pend; + } + + /* Flush the previous wrties before writing to RESEND bit */ + smp_wmb(); + writeq(1UL << OCTEP_VF_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg); + writeq(1UL << OCTEP_VF_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg); +} + +/** + * octep_vf_napi_poll() - NAPI poll function for Tx/Rx. + * + * @napi: pointer to napi context. + * @budget: max number of packets to be processed in single invocation. + */ +static int octep_vf_napi_poll(struct napi_struct *napi, int budget) +{ + struct octep_vf_ioq_vector *ioq_vector = + container_of(napi, struct octep_vf_ioq_vector, napi); + u32 tx_pending, rx_done; + + tx_pending = octep_vf_iq_process_completions(ioq_vector->iq, 64); + rx_done = octep_vf_oq_process_rx(ioq_vector->oq, budget); + + /* need more polling if tx completion processing is still pending or + * processed at least 'budget' number of rx packets. + */ + if (tx_pending || rx_done >= budget) + return budget; + + if (likely(napi_complete_done(napi, rx_done))) + octep_vf_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq); + + return rx_done; +} + +/** + * octep_vf_napi_add() - Add NAPI poll for all Tx/Rx queues. + * + * @oct: Octeon device private data structure. + */ +static void octep_vf_napi_add(struct octep_vf_device *oct) +{ + int i; + + for (i = 0; i < oct->num_oqs; i++) { + netdev_dbg(oct->netdev, "Adding NAPI on Q-%d\n", i); + netif_napi_add(oct->netdev, &oct->ioq_vector[i]->napi, octep_vf_napi_poll); + oct->oq[i]->napi = &oct->ioq_vector[i]->napi; + } +} + +/** + * octep_vf_napi_delete() - delete NAPI poll callback for all Tx/Rx queues. + * + * @oct: Octeon device private data structure. + */ +static void octep_vf_napi_delete(struct octep_vf_device *oct) +{ + int i; + + for (i = 0; i < oct->num_oqs; i++) { + netdev_dbg(oct->netdev, "Deleting NAPI on Q-%d\n", i); + netif_napi_del(&oct->ioq_vector[i]->napi); + oct->oq[i]->napi = NULL; + } +} + +/** + * octep_vf_napi_enable() - enable NAPI for all Tx/Rx queues. + * + * @oct: Octeon device private data structure. + */ +static void octep_vf_napi_enable(struct octep_vf_device *oct) +{ + int i; + + for (i = 0; i < oct->num_oqs; i++) { + netdev_dbg(oct->netdev, "Enabling NAPI on Q-%d\n", i); + napi_enable(&oct->ioq_vector[i]->napi); + } +} + +/** + * octep_vf_napi_disable() - disable NAPI for all Tx/Rx queues. + * + * @oct: Octeon device private data structure. + */ +static void octep_vf_napi_disable(struct octep_vf_device *oct) +{ + int i; + + for (i = 0; i < oct->num_oqs; i++) { + netdev_dbg(oct->netdev, "Disabling NAPI on Q-%d\n", i); + napi_disable(&oct->ioq_vector[i]->napi); + } +} + static void octep_vf_link_up(struct net_device *netdev) { netif_carrier_on(netdev); @@ -98,6 +465,8 @@ static int octep_vf_open(struct net_device *netdev) goto setup_iq_err; if (octep_vf_setup_oqs(oct)) goto setup_oq_err; + if (octep_vf_setup_irqs(oct)) + goto setup_irq_err; err = netif_set_real_num_tx_queues(netdev, oct->num_oqs); if (err) @@ -106,6 +475,9 @@ static int octep_vf_open(struct net_device *netdev) if (err) goto set_queues_err; + octep_vf_napi_add(oct); + octep_vf_napi_enable(oct); + oct->link_info.admin_up = 1; octep_vf_set_rx_state(oct, true); @@ -128,6 +500,10 @@ static int octep_vf_open(struct net_device *netdev) return 0; set_queues_err: + octep_vf_napi_disable(oct); + octep_vf_napi_delete(oct); + octep_vf_clean_irqs(oct); +setup_irq_err: octep_vf_free_oqs(oct); setup_oq_err: octep_vf_free_iqs(oct); @@ -160,7 +536,10 @@ static int octep_vf_stop(struct net_device *netdev) oct->link_info.oper_up = 0; oct->hw_ops.disable_interrupts(oct); + octep_vf_napi_disable(oct); + octep_vf_napi_delete(oct); + octep_vf_clean_irqs(oct); octep_vf_clean_iqs(oct); oct->hw_ops.disable_io_queues(oct); @@ -171,6 +550,39 @@ static int octep_vf_stop(struct net_device *netdev) return 0; } +/** + * octep_vf_iq_full_check() - check if a Tx queue is full. + * + * @iq: Octeon Tx queue data structure. + * + * Return: 0, if the Tx queue is not full. + * 1, if the Tx queue is full. + */ +static int octep_vf_iq_full_check(struct octep_vf_iq *iq) +{ + int ret; + + ret = netif_subqueue_maybe_stop(iq->netdev, iq->q_no, IQ_INSTR_SPACE(iq), + OCTEP_VF_WAKE_QUEUE_THRESHOLD, + OCTEP_VF_WAKE_QUEUE_THRESHOLD); + switch (ret) { + case 0: /* Stopped the queue, since IQ is full */ + return 1; + case -1: /* + * Pending updates in write index from + * iq_process_completion in other cpus + * caused queues to get re-enabled after + * being stopped + */ + iq->stats.restart_cnt++; + fallthrough; + case 1: /* Queue left enabled, since IQ is not yet full*/ + return 0; + } + + return 1; +} + /** * octep_vf_start_xmit() - Enqueue packet to Octoen hardware Tx Queue. * @@ -183,6 +595,144 @@ static int octep_vf_stop(struct net_device *netdev) static netdev_tx_t octep_vf_start_xmit(struct sk_buff *skb, struct net_device *netdev) { + struct octep_vf_device *oct = netdev_priv(netdev); + netdev_features_t feat = netdev->features; + struct octep_vf_tx_sglist_desc *sglist; + struct octep_vf_tx_buffer *tx_buffer; + struct octep_vf_tx_desc_hw *hw_desc; + struct skb_shared_info *shinfo; + struct octep_vf_instr_hdr *ih; + struct octep_vf_iq *iq; + skb_frag_t *frag; + u16 nr_frags, si; + int xmit_more; + u16 q_no, wi; + + if (skb_put_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + + q_no = skb_get_queue_mapping(skb); + if (q_no >= oct->num_iqs) { + netdev_err(netdev, "Invalid Tx skb->queue_mapping=%d\n", q_no); + q_no = q_no % oct->num_iqs; + } + + iq = oct->iq[q_no]; + + shinfo = skb_shinfo(skb); + nr_frags = shinfo->nr_frags; + + wi = iq->host_write_index; + hw_desc = &iq->desc_ring[wi]; + hw_desc->ih64 = 0; + + tx_buffer = iq->buff_info + wi; + tx_buffer->skb = skb; + + ih = &hw_desc->ih; + ih->tlen = skb->len; + ih->pkind = oct->fw_info.pkind; + ih->fsz = oct->fw_info.fsz; + ih->tlen = skb->len + ih->fsz; + + if (!nr_frags) { + tx_buffer->gather = 0; + tx_buffer->dma = dma_map_single(iq->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(iq->dev, tx_buffer->dma)) + goto dma_map_err; + hw_desc->dptr = tx_buffer->dma; + } else { + /* Scatter/Gather */ + dma_addr_t dma; + u16 len; + + sglist = tx_buffer->sglist; + + ih->gsz = nr_frags + 1; + ih->gather = 1; + tx_buffer->gather = 1; + + len = skb_headlen(skb); + dma = dma_map_single(iq->dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(iq->dev, dma)) + goto dma_map_err; + + memset(sglist, 0, OCTEP_VF_SGLIST_SIZE_PER_PKT); + sglist[0].len[3] = len; + sglist[0].dma_ptr[0] = dma; + + si = 1; /* entry 0 is main skb, mapped above */ + frag = &shinfo->frags[0]; + while (nr_frags--) { + len = skb_frag_size(frag); + dma = skb_frag_dma_map(iq->dev, frag, 0, + len, DMA_TO_DEVICE); + if (dma_mapping_error(iq->dev, dma)) + goto dma_map_sg_err; + + sglist[si >> 2].len[3 - (si & 3)] = len; + sglist[si >> 2].dma_ptr[si & 3] = dma; + + frag++; + si++; + } + hw_desc->dptr = tx_buffer->sglist_dma; + } + if (oct->fw_info.tx_ol_flags) { + if ((feat & (NETIF_F_TSO)) && (skb_is_gso(skb))) { + hw_desc->txm.ol_flags = OCTEP_VF_TX_OFFLOAD_CKSUM; + hw_desc->txm.ol_flags |= OCTEP_VF_TX_OFFLOAD_TSO; + hw_desc->txm.gso_size = skb_shinfo(skb)->gso_size; + hw_desc->txm.gso_segs = skb_shinfo(skb)->gso_segs; + } else if (feat & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { + hw_desc->txm.ol_flags = OCTEP_VF_TX_OFFLOAD_CKSUM; + } + /* due to ESR txm will be swapped by hw */ + hw_desc->txm64[0] = (__force u64)cpu_to_be64(hw_desc->txm64[0]); + } + + xmit_more = netdev_xmit_more(); + + netdev_tx_sent_queue(iq->netdev_q, skb->len); + + skb_tx_timestamp(skb); + iq->fill_cnt++; + wi++; + iq->host_write_index = wi & iq->ring_size_mask; + + /* octep_iq_full_check stops the queue and returns + * true if so, in case the queue has become full + * by inserting current packet. If so, we can + * go ahead and ring doorbell. + */ + if (!octep_vf_iq_full_check(iq) && xmit_more && + iq->fill_cnt < iq->fill_threshold) + return NETDEV_TX_OK; + + goto ring_dbell; + +dma_map_sg_err: + if (si > 0) { + dma_unmap_single(iq->dev, sglist[0].dma_ptr[0], + sglist[0].len[0], DMA_TO_DEVICE); + sglist[0].len[0] = 0; + } + while (si > 1) { + dma_unmap_page(iq->dev, sglist[si >> 2].dma_ptr[si & 3], + sglist[si >> 2].len[si & 3], DMA_TO_DEVICE); + sglist[si >> 2].len[si & 3] = 0; + si--; + } + tx_buffer->gather = 0; +dma_map_err: + dev_kfree_skb_any(skb); +ring_dbell: + /* Flush the hw descriptors before writing to doorbell */ + smp_wmb(); + writel(iq->fill_cnt, iq->doorbell_reg); + iq->stats.instr_posted += iq->fill_cnt; + iq->fill_cnt = 0; return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c index 330d6e72bc0b..82821bc28634 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c @@ -68,6 +68,50 @@ rx_buf_alloc_err: return -ENOMEM; } +/** + * octep_vf_oq_refill() - refill buffers for used Rx ring descriptors. + * + * @oct: Octeon device private data structure. + * @oq: Octeon Rx queue data structure. + * + * Return: number of descriptors successfully refilled with receive buffers. + */ +static int octep_vf_oq_refill(struct octep_vf_device *oct, struct octep_vf_oq *oq) +{ + struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring; + struct page *page; + u32 refill_idx, i; + + refill_idx = oq->host_refill_idx; + for (i = 0; i < oq->refill_count; i++) { + page = dev_alloc_page(); + if (unlikely(!page)) { + dev_err(oq->dev, "refill: rx buffer alloc failed\n"); + oq->stats.alloc_failures++; + break; + } + + desc_ring[refill_idx].buffer_ptr = dma_map_page(oq->dev, page, 0, + PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(oq->dev, desc_ring[refill_idx].buffer_ptr)) { + dev_err(oq->dev, + "OQ-%d buffer refill: DMA mapping error!\n", + oq->q_no); + put_page(page); + oq->stats.alloc_failures++; + break; + } + oq->buff_info[refill_idx].page = page; + refill_idx++; + if (refill_idx == oq->max_count) + refill_idx = 0; + } + oq->host_refill_idx = refill_idx; + oq->refill_count -= i; + + return i; +} + /** * octep_vf_setup_oq() - Setup a Rx queue. * @@ -261,3 +305,206 @@ void octep_vf_free_oqs(struct octep_vf_device *oct) "Successfully freed OQ(RxQ)-%d.\n", i); } } + +/** + * octep_vf_oq_check_hw_for_pkts() - Check for new Rx packets. + * + * @oct: Octeon device private data structure. + * @oq: Octeon Rx queue data structure. + * + * Return: packets received after previous check. + */ +static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct, + struct octep_vf_oq *oq) +{ + u32 pkt_count, new_pkts; + + pkt_count = readl(oq->pkts_sent_reg); + new_pkts = pkt_count - oq->last_pkt_count; + + /* Clear the hardware packets counter register if the rx queue is + * being processed continuously with-in a single interrupt and + * reached half its max value. + * this counter is not cleared every time read, to save write cycles. + */ + if (unlikely(pkt_count > 0xF0000000U)) { + writel(pkt_count, oq->pkts_sent_reg); + pkt_count = readl(oq->pkts_sent_reg); + new_pkts += pkt_count; + } + oq->last_pkt_count = pkt_count; + oq->pkts_pending += new_pkts; + return new_pkts; +} + +/** + * __octep_vf_oq_process_rx() - Process hardware Rx queue and push to stack. + * + * @oct: Octeon device private data structure. + * @oq: Octeon Rx queue data structure. + * @pkts_to_process: number of packets to be processed. + * + * Process the new packets in Rx queue. + * Packets larger than single Rx buffer arrive in consecutive descriptors. + * But, count returned by the API only accounts full packets, not fragments. + * + * Return: number of packets processed and pushed to stack. + */ +static int __octep_vf_oq_process_rx(struct octep_vf_device *oct, + struct octep_vf_oq *oq, u16 pkts_to_process) +{ + struct octep_vf_oq_resp_hw_ext *resp_hw_ext = NULL; + netdev_features_t feat = oq->netdev->features; + struct octep_vf_rx_buffer *buff_info; + struct octep_vf_oq_resp_hw *resp_hw; + u32 pkt, rx_bytes, desc_used; + u16 data_offset, rx_ol_flags; + struct sk_buff *skb; + u32 read_idx; + + read_idx = oq->host_read_idx; + rx_bytes = 0; + desc_used = 0; + for (pkt = 0; pkt < pkts_to_process; pkt++) { + buff_info = (struct octep_vf_rx_buffer *)&oq->buff_info[read_idx]; + dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr, + PAGE_SIZE, DMA_FROM_DEVICE); + resp_hw = page_address(buff_info->page); + buff_info->page = NULL; + + /* Swap the length field that is in Big-Endian to CPU */ + buff_info->len = be64_to_cpu(resp_hw->length); + if (oct->fw_info.rx_ol_flags) { + /* Extended response header is immediately after + * response header (resp_hw) + */ + resp_hw_ext = (struct octep_vf_oq_resp_hw_ext *) + (resp_hw + 1); + buff_info->len -= OCTEP_VF_OQ_RESP_HW_EXT_SIZE; + /* Packet Data is immediately after + * extended response header. + */ + data_offset = OCTEP_VF_OQ_RESP_HW_SIZE + + OCTEP_VF_OQ_RESP_HW_EXT_SIZE; + rx_ol_flags = resp_hw_ext->rx_ol_flags; + } else { + /* Data is immediately after + * Hardware Rx response header. + */ + data_offset = OCTEP_VF_OQ_RESP_HW_SIZE; + rx_ol_flags = 0; + } + rx_bytes += buff_info->len; + + if (buff_info->len <= oq->max_single_buffer_size) { + skb = napi_build_skb((void *)resp_hw, PAGE_SIZE); + skb_reserve(skb, data_offset); + skb_put(skb, buff_info->len); + read_idx++; + desc_used++; + if (read_idx == oq->max_count) + read_idx = 0; + } else { + struct skb_shared_info *shinfo; + u16 data_len; + + skb = napi_build_skb((void *)resp_hw, PAGE_SIZE); + skb_reserve(skb, data_offset); + /* Head fragment includes response header(s); + * subsequent fragments contains only data. + */ + skb_put(skb, oq->max_single_buffer_size); + read_idx++; + desc_used++; + if (read_idx == oq->max_count) + read_idx = 0; + + shinfo = skb_shinfo(skb); + data_len = buff_info->len - oq->max_single_buffer_size; + while (data_len) { + dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr, + PAGE_SIZE, DMA_FROM_DEVICE); + buff_info = (struct octep_vf_rx_buffer *) + &oq->buff_info[read_idx]; + if (data_len < oq->buffer_size) { + buff_info->len = data_len; + data_len = 0; + } else { + buff_info->len = oq->buffer_size; + data_len -= oq->buffer_size; + } + + skb_add_rx_frag(skb, shinfo->nr_frags, + buff_info->page, 0, + buff_info->len, + buff_info->len); + buff_info->page = NULL; + read_idx++; + desc_used++; + if (read_idx == oq->max_count) + read_idx = 0; + } + } + + skb->dev = oq->netdev; + skb->protocol = eth_type_trans(skb, skb->dev); + if (feat & NETIF_F_RXCSUM && + OCTEP_VF_RX_CSUM_VERIFIED(rx_ol_flags)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + napi_gro_receive(oq->napi, skb); + } + + oq->host_read_idx = read_idx; + oq->refill_count += desc_used; + oq->stats.packets += pkt; + oq->stats.bytes += rx_bytes; + + return pkt; +} + +/** + * octep_vf_oq_process_rx() - Process Rx queue. + * + * @oq: Octeon Rx queue data structure. + * @budget: max number of packets can be processed in one invocation. + * + * Check for newly received packets and process them. + * Keeps checking for new packets until budget is used or no new packets seen. + * + * Return: number of packets processed. + */ +int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget) +{ + u32 pkts_available, pkts_processed, total_pkts_processed; + struct octep_vf_device *oct = oq->octep_vf_dev; + + pkts_available = 0; + pkts_processed = 0; + total_pkts_processed = 0; + while (total_pkts_processed < budget) { + /* update pending count only when current one exhausted */ + if (oq->pkts_pending == 0) + octep_vf_oq_check_hw_for_pkts(oct, oq); + pkts_available = min(budget - total_pkts_processed, + oq->pkts_pending); + if (!pkts_available) + break; + + pkts_processed = __octep_vf_oq_process_rx(oct, oq, + pkts_available); + oq->pkts_pending -= pkts_processed; + total_pkts_processed += pkts_processed; + } + + if (oq->refill_count >= oq->refill_threshold) { + u32 desc_refilled = octep_vf_oq_refill(oct, oq); + + /* flush pending writes before updating credits */ + smp_wmb(); + writel(desc_refilled, oq->pkts_credit_reg); + } + + return total_pkts_processed; +} diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c index 1a3e1a651dc4..47a5c054fdb6 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_tx.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "octep_vf_config.h" #include "octep_vf_main.h" @@ -23,6 +24,76 @@ static void octep_vf_iq_reset_indices(struct octep_vf_iq *iq) iq->pkt_in_done = 0; } +/** + * octep_vf_iq_process_completions() - Process Tx queue completions. + * + * @iq: Octeon Tx queue data structure. + * @budget: max number of completions to be processed in one invocation. + */ +int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget) +{ + u32 compl_pkts, compl_bytes, compl_sg; + struct octep_vf_device *oct = iq->octep_vf_dev; + struct octep_vf_tx_buffer *tx_buffer; + struct skb_shared_info *shinfo; + u32 fi = iq->flush_index; + struct sk_buff *skb; + u8 frags, i; + + compl_pkts = 0; + compl_sg = 0; + compl_bytes = 0; + iq->octep_vf_read_index = oct->hw_ops.update_iq_read_idx(iq); + + while (likely(budget && (fi != iq->octep_vf_read_index))) { + tx_buffer = iq->buff_info + fi; + skb = tx_buffer->skb; + + fi++; + if (unlikely(fi == iq->max_count)) + fi = 0; + compl_bytes += skb->len; + compl_pkts++; + budget--; + + if (!tx_buffer->gather) { + dma_unmap_single(iq->dev, tx_buffer->dma, + tx_buffer->skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + continue; + } + + /* Scatter/Gather */ + shinfo = skb_shinfo(skb); + frags = shinfo->nr_frags; + compl_sg++; + + dma_unmap_single(iq->dev, tx_buffer->sglist[0].dma_ptr[0], + tx_buffer->sglist[0].len[3], DMA_TO_DEVICE); + + i = 1; /* entry 0 is main skb, unmapped above */ + while (frags--) { + dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], + tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE); + i++; + } + + dev_kfree_skb_any(skb); + } + + iq->pkts_processed += compl_pkts; + iq->stats.instr_completed += compl_pkts; + iq->stats.bytes_sent += compl_bytes; + iq->stats.sgentry_sent += compl_sg; + iq->flush_index = fi; + + netif_subqueue_completed_wake(iq->netdev, iq->q_no, compl_pkts, + compl_bytes, IQ_INSTR_SPACE(iq), + OCTEP_VF_WAKE_QUEUE_THRESHOLD); + + return !budget; +} + /** * octep_vf_iq_free_pending() - Free Tx buffers for pending completions. * From c92881599efb3bf7a6c29a971d4c907735b4ef8c Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:39 -0800 Subject: [PATCH 1049/2255] octeon_ep_vf: add ethtool support Add support for the following ethtool commands: ethtool -i|--driver devname ethtool devname ethtool -S|--statistics devname Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- .../ethernet/marvell/octeon_ep_vf/Makefile | 3 +- .../marvell/octeon_ep_vf/octep_vf_ethtool.c | 273 ++++++++++++++++++ .../marvell/octeon_ep_vf/octep_vf_main.c | 1 + .../marvell/octeon_ep_vf/octep_vf_main.h | 1 + 4 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/Makefile b/drivers/net/ethernet/marvell/octeon_ep_vf/Makefile index 694eb9b46e99..4a5f9fcb0b40 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/Makefile +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_OCTEON_EP_VF) += octeon_ep_vf.o octeon_ep_vf-y := octep_vf_main.o octep_vf_cn9k.o octep_vf_cnxk.o \ - octep_vf_tx.o octep_vf_rx.o octep_vf_mbox.o + octep_vf_tx.o octep_vf_rx.o octep_vf_mbox.o \ + octep_vf_ethtool.o diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c new file mode 100644 index 000000000000..a1979b45e355 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon EP (EndPoint) VF Ethernet Driver + * + * Copyright (C) 2020 Marvell. + * + */ + +#include +#include +#include + +#include "octep_vf_config.h" +#include "octep_vf_main.h" + +static const char octep_vf_gstrings_global_stats[][ETH_GSTRING_LEN] = { + "rx_alloc_errors", + "tx_busy_errors", + "tx_hw_pkts", + "tx_hw_octs", + "tx_hw_bcast", + "tx_hw_mcast", + "rx_hw_pkts", + "rx_hw_bytes", + "rx_hw_bcast", + "rx_dropped_bytes_fifo_full", +}; + +#define OCTEP_VF_GLOBAL_STATS_CNT (sizeof(octep_vf_gstrings_global_stats) / ETH_GSTRING_LEN) + +static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = { + "tx_packets_posted[Q-%u]", + "tx_packets_completed[Q-%u]", + "tx_bytes[Q-%u]", + "tx_busy[Q-%u]", +}; + +#define OCTEP_VF_TX_Q_STATS_CNT (sizeof(octep_vf_gstrings_tx_q_stats) / ETH_GSTRING_LEN) + +static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = { + "rx_packets[Q-%u]", + "rx_bytes[Q-%u]", + "rx_alloc_errors[Q-%u]", +}; + +#define OCTEP_VF_RX_Q_STATS_CNT (sizeof(octep_vf_gstrings_rx_q_stats) / ETH_GSTRING_LEN) + +static void octep_vf_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + + strscpy(info->driver, OCTEP_VF_DRV_NAME, sizeof(info->driver)); + strscpy(info->bus_info, pci_name(oct->pdev), sizeof(info->bus_info)); +} + +static void octep_vf_get_strings(struct net_device *netdev, + u32 stringset, u8 *data) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + char *strings = (char *)data; + int i, j; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) { + snprintf(strings, ETH_GSTRING_LEN, + octep_vf_gstrings_global_stats[i]); + strings += ETH_GSTRING_LEN; + } + + for (i = 0; i < num_queues; i++) { + for (j = 0; j < OCTEP_VF_TX_Q_STATS_CNT; j++) { + snprintf(strings, ETH_GSTRING_LEN, + octep_vf_gstrings_tx_q_stats[j], i); + strings += ETH_GSTRING_LEN; + } + } + + for (i = 0; i < num_queues; i++) { + for (j = 0; j < OCTEP_VF_RX_Q_STATS_CNT; j++) { + snprintf(strings, ETH_GSTRING_LEN, + octep_vf_gstrings_rx_q_stats[j], i); + strings += ETH_GSTRING_LEN; + } + } + break; + default: + break; + } +} + +static int octep_vf_get_sset_count(struct net_device *netdev, int sset) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + + switch (sset) { + case ETH_SS_STATS: + return OCTEP_VF_GLOBAL_STATS_CNT + (num_queues * + (OCTEP_VF_TX_Q_STATS_CNT + OCTEP_VF_RX_Q_STATS_CNT)); + break; + default: + return -EOPNOTSUPP; + } +} + +static void octep_vf_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + struct octep_vf_iface_tx_stats *iface_tx_stats; + struct octep_vf_iface_rx_stats *iface_rx_stats; + u64 rx_alloc_errors, tx_busy_errors; + int q, i; + + rx_alloc_errors = 0; + tx_busy_errors = 0; + + octep_vf_get_if_stats(oct); + iface_tx_stats = &oct->iface_tx_stats; + iface_rx_stats = &oct->iface_rx_stats; + + for (q = 0; q < oct->num_oqs; q++) { + struct octep_vf_iq *iq = oct->iq[q]; + struct octep_vf_oq *oq = oct->oq[q]; + + tx_busy_errors += iq->stats.tx_busy; + rx_alloc_errors += oq->stats.alloc_failures; + } + i = 0; + data[i++] = rx_alloc_errors; + data[i++] = tx_busy_errors; + data[i++] = iface_tx_stats->pkts; + data[i++] = iface_tx_stats->octs; + data[i++] = iface_tx_stats->bcst; + data[i++] = iface_tx_stats->mcst; + data[i++] = iface_rx_stats->pkts; + data[i++] = iface_rx_stats->octets; + data[i++] = iface_rx_stats->bcast_pkts; + data[i++] = iface_rx_stats->dropped_octets_fifo_full; + + /* Per Tx Queue stats */ + for (q = 0; q < oct->num_iqs; q++) { + struct octep_vf_iq *iq = oct->iq[q]; + + data[i++] = iq->stats.instr_posted; + data[i++] = iq->stats.instr_completed; + data[i++] = iq->stats.bytes_sent; + data[i++] = iq->stats.tx_busy; + } + + /* Per Rx Queue stats */ + for (q = 0; q < oct->num_oqs; q++) { + struct octep_vf_oq *oq = oct->oq[q]; + + data[i++] = oq->stats.packets; + data[i++] = oq->stats.bytes; + data[i++] = oq->stats.alloc_failures; + } +} + +#define OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(octep_vf_speeds, ksettings, name) \ +{ \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_T)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_R)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_CR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_KR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_LR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_SR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_CR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_KR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_SR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_CR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_KR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_LR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_SR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR2)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR2)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR2)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_LR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_CR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_KR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_LR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \ + if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_SR4)) \ + ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \ +} + +static int octep_vf_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct octep_vf_device *oct = netdev_priv(netdev); + struct octep_vf_iface_link_info *link_info; + u32 advertised_modes, supported_modes; + + ethtool_link_ksettings_zero_link_mode(cmd, supported); + ethtool_link_ksettings_zero_link_mode(cmd, advertising); + + octep_vf_get_link_info(oct); + + advertised_modes = oct->link_info.advertised_modes; + supported_modes = oct->link_info.supported_modes; + link_info = &oct->link_info; + + OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported); + OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising); + + if (link_info->autoneg) { + if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED) + ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); + if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED) { + ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); + cmd->base.autoneg = AUTONEG_ENABLE; + } else { + cmd->base.autoneg = AUTONEG_DISABLE; + } + } else { + cmd->base.autoneg = AUTONEG_DISABLE; + } + + cmd->base.port = PORT_FIBRE; + ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); + ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); + + if (netif_carrier_ok(netdev)) { + cmd->base.speed = link_info->speed; + cmd->base.duplex = DUPLEX_FULL; + } else { + cmd->base.speed = SPEED_UNKNOWN; + cmd->base.duplex = DUPLEX_UNKNOWN; + } + return 0; +} + +static const struct ethtool_ops octep_vf_ethtool_ops = { + .get_drvinfo = octep_vf_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_strings = octep_vf_get_strings, + .get_sset_count = octep_vf_get_sset_count, + .get_ethtool_stats = octep_vf_get_ethtool_stats, + .get_link_ksettings = octep_vf_get_link_ksettings, +}; + +void octep_vf_set_ethtool_ops(struct net_device *netdev) +{ + netdev->ethtool_ops = &octep_vf_ethtool_ops; +} diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c index e5d258980547..dd49d0b8b494 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c @@ -1095,6 +1095,7 @@ static int octep_vf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&octep_vf_dev->tx_timeout_task, octep_vf_tx_timeout_task); netdev->netdev_ops = &octep_vf_netdev_ops; + octep_vf_set_ethtool_ops(netdev); netif_carrier_off(netdev); if (octep_vf_setup_mbox(octep_vf_dev)) { diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h index 5a3b545ad590..5769f62545cd 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h @@ -327,6 +327,7 @@ void octep_vf_device_setup_cn93(struct octep_vf_device *oct); void octep_vf_device_setup_cnxk(struct octep_vf_device *oct); int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget); int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget); +void octep_vf_set_ethtool_ops(struct net_device *netdev); int octep_vf_get_link_info(struct octep_vf_device *oct); int octep_vf_get_if_stats(struct octep_vf_device *oct); void octep_vf_mbox_work(struct work_struct *work); From 90cabae2a2349fba33b5ff30ab700a328d34eeb2 Mon Sep 17 00:00:00 2001 From: Shinas Rasheed Date: Thu, 8 Feb 2024 02:18:40 -0800 Subject: [PATCH 1050/2255] octeon_ep_vf: update MAINTAINERS add MAINTAINERS for octeon_ep_vf driver. Signed-off-by: Shinas Rasheed Signed-off-by: David S. Miller --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 83e20516ebff..000ef0e46c70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13059,6 +13059,15 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/marvell/octeon_ep +MARVELL OCTEON ENDPOINT VF DRIVER +M: Veerasenareddy Burru +M: Sathesh Edara +M: Shinas Rasheed +M: Satananda Burla +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/ethernet/marvell/octeon_ep_vf + MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER M: Sunil Goutham M: Geetha sowjanya From 9c52994e32c5d8aaff13b1a13f7b35b988b02b26 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 8 Feb 2024 18:57:49 +0100 Subject: [PATCH 1051/2255] selftests: net: ignore timing errors in txtimestamp if KSFT_MACHINE_SLOW This test is time sensitive. It may fail on virtual machines and for debug builds. Similar to commit c41dfb0dfbec ("selftests/net: ignore timing errors in so_txtime if KSFT_MACHINE_SLOW"), optionally suppress failure for timing errors (only). Signed-off-by: Paolo Abeni Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/txtimestamp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/txtimestamp.c b/tools/testing/selftests/net/txtimestamp.c index 10f2fde3686b..ec60a16c9307 100644 --- a/tools/testing/selftests/net/txtimestamp.c +++ b/tools/testing/selftests/net/txtimestamp.c @@ -163,7 +163,8 @@ static void validate_timestamp(struct timespec *cur, int min_delay) if (cur64 < start64 + min_delay || cur64 > start64 + max_delay) { fprintf(stderr, "ERROR: %" PRId64 " us expected between %d and %d\n", cur64 - start64, min_delay, max_delay); - test_failed = true; + if (!getenv("KSFT_MACHINE_SLOW")) + test_failed = true; } } From 129e406e1811538c1afc9c8e97d61bb18eed3363 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 14:06:49 -0800 Subject: [PATCH 1052/2255] net/ipv6: set expires in rt6_add_dflt_router(). Pass the duration of a lifetime (in seconds) to the function rt6_add_dflt_router() so that it can properly set the expiration time. The function ndisc_router_discovery() is the only one that calls rt6_add_dflt_router(), and it will later set the expiration time for the route created by rt6_add_dflt_router(). However, there is a gap of time between calling rt6_add_dflt_router() and setting the expiration time in ndisc_router_discovery(). During this period, there is a possibility that a new route may be removed from the routing table. By setting the correct expiration time in rt6_add_dflt_router(), we can prevent this from happening. The reason for setting RTF_EXPIRES in rt6_add_dflt_router() is to start the Garbage Collection (GC) timer, as it only activates when a route with RTF_EXPIRES is added to a table. Suggested-by: David Ahern Reviewed-by: Hangbin Liu Reviewed-by: David Ahern Signed-off-by: Kui-Feng Lee Signed-off-by: David S. Miller --- include/net/ip6_route.h | 3 ++- net/ipv6/ndisc.c | 3 ++- net/ipv6/route.c | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 28b065790261..52a51c69aa9d 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -170,7 +170,8 @@ struct fib6_info *rt6_get_dflt_router(struct net *net, struct fib6_info *rt6_add_dflt_router(struct net *net, const struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref, - u32 defrtr_usr_metric); + u32 defrtr_usr_metric, + int lifetime); void rt6_purge_dflt_routers(struct net *net); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index a19999b30bc0..a68462668158 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1382,7 +1382,8 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) neigh_release(neigh); rt = rt6_add_dflt_router(net, &ipv6_hdr(skb)->saddr, - skb->dev, pref, defrtr_usr_metric); + skb->dev, pref, defrtr_usr_metric, + lifetime); if (!rt) { ND_PRINTK(0, err, "RA: %s failed to add default route\n", diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 63b4c6056582..98abba8f15cd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4355,7 +4355,8 @@ struct fib6_info *rt6_add_dflt_router(struct net *net, const struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref, - u32 defrtr_usr_metric) + u32 defrtr_usr_metric, + int lifetime) { struct fib6_config cfg = { .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT, @@ -4368,6 +4369,7 @@ struct fib6_info *rt6_add_dflt_router(struct net *net, .fc_nlinfo.portid = 0, .fc_nlinfo.nlh = NULL, .fc_nlinfo.nl_net = net, + .fc_expires = jiffies_to_clock_t(lifetime * HZ), }; cfg.fc_gateway = *gwaddr; From 60df43d3a72c5fc50ff854cca17c9935c4398794 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 14:06:50 -0800 Subject: [PATCH 1053/2255] net/ipv6: Remove unnecessary clean. The route here is newly created. It is unnecessary to call fib6_clean_expires() on it. Suggested-by: Eric Dumazet Reviewed-by: Hangbin Liu Reviewed-by: David Ahern Signed-off-by: Kui-Feng Lee Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 98abba8f15cd..dd6ff5b20918 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3765,8 +3765,6 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, if (cfg->fc_flags & RTF_EXPIRES) fib6_set_expires(rt, jiffies + clock_t_to_jiffies(cfg->fc_expires)); - else - fib6_clean_expires(rt); if (cfg->fc_protocol == RTPROT_UNSPEC) cfg->fc_protocol = RTPROT_BOOT; From 5eb902b8e7193cdcb33242af0a56502e6b5206e9 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 14:06:51 -0800 Subject: [PATCH 1054/2255] net/ipv6: Remove expired routes with a separated list of routes. FIB6 GC walks trees of fib6_tables to remove expired routes. Walking a tree can be expensive if the number of routes in a table is big, even if most of them are permanent. Checking routes in a separated list of routes having expiration will avoid this potential issue. Reviewed-by: David Ahern Signed-off-by: Kui-Feng Lee Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 46 ++++++++++++++++++++++++++++++++- net/ipv6/addrconf.c | 41 ++++++++++++++++++++++++----- net/ipv6/ip6_fib.c | 60 +++++++++++++++++++++++++++++++++++++++---- net/ipv6/ndisc.c | 10 +++++++- net/ipv6/route.c | 13 ++++++++-- 5 files changed, 154 insertions(+), 16 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 360b12e61850..323c94f1845b 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -173,6 +173,9 @@ struct fib6_info { refcount_t fib6_ref; unsigned long expires; + + struct hlist_node gc_link; + struct dst_metrics *fib6_metrics; #define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1] @@ -241,12 +244,18 @@ static inline bool fib6_requires_src(const struct fib6_info *rt) return rt->fib6_src.plen > 0; } +/* The callers should hold f6i->fib6_table->tb6_lock if a route has ever + * been added to a table before. + */ static inline void fib6_clean_expires(struct fib6_info *f6i) { f6i->fib6_flags &= ~RTF_EXPIRES; f6i->expires = 0; } +/* The callers should hold f6i->fib6_table->tb6_lock if a route has ever + * been added to a table before. + */ static inline void fib6_set_expires(struct fib6_info *f6i, unsigned long expires) { @@ -327,8 +336,10 @@ static inline bool fib6_info_hold_safe(struct fib6_info *f6i) static inline void fib6_info_release(struct fib6_info *f6i) { - if (f6i && refcount_dec_and_test(&f6i->fib6_ref)) + if (f6i && refcount_dec_and_test(&f6i->fib6_ref)) { + DEBUG_NET_WARN_ON_ONCE(!hlist_unhashed(&f6i->gc_link)); call_rcu(&f6i->rcu, fib6_info_destroy_rcu); + } } enum fib6_walk_state { @@ -382,6 +393,7 @@ struct fib6_table { struct inet_peer_base tb6_peers; unsigned int flags; unsigned int fib_seq; + struct hlist_head tb6_gc_hlist; /* GC candidates */ #define RT6_TABLE_HAS_DFLT_ROUTER BIT(0) }; @@ -498,6 +510,38 @@ void fib6_gc_cleanup(void); int fib6_init(void); +/* Add the route to the gc list if it is not already there + * + * The callers should hold f6i->fib6_table->tb6_lock. + */ +static inline void fib6_add_gc_list(struct fib6_info *f6i) +{ + /* If fib6_node is null, the f6i is not in (or removed from) the + * table. + * + * There is a gap between finding the f6i from the table and + * calling this function without the protection of the tb6_lock. + * This check makes sure the f6i is not added to the gc list when + * it is not on the table. + */ + if (!rcu_dereference_protected(f6i->fib6_node, + lockdep_is_held(&f6i->fib6_table->tb6_lock))) + return; + + if (hlist_unhashed(&f6i->gc_link)) + hlist_add_head(&f6i->gc_link, &f6i->fib6_table->tb6_gc_hlist); +} + +/* Remove the route from the gc list if it is on the list. + * + * The callers should hold f6i->fib6_table->tb6_lock. + */ +static inline void fib6_remove_gc_list(struct fib6_info *f6i) +{ + if (!hlist_unhashed(&f6i->gc_link)) + hlist_del_init(&f6i->gc_link); +} + struct ipv6_route_iter { struct seq_net_private p; struct fib6_walker w; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d63f5d063f07..0ea44563454f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1255,6 +1255,7 @@ static void cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt, bool del_peer) { + struct fib6_table *table; struct fib6_info *f6i; f6i = addrconf_get_prefix_route(del_peer ? &ifp->peer_addr : &ifp->addr, @@ -1264,8 +1265,15 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, if (del_rt) ip6_del_rt(dev_net(ifp->idev->dev), f6i, false); else { - if (!(f6i->fib6_flags & RTF_EXPIRES)) + if (!(f6i->fib6_flags & RTF_EXPIRES)) { + table = f6i->fib6_table; + spin_lock_bh(&table->tb6_lock); + fib6_set_expires(f6i, expires); + fib6_add_gc_list(f6i); + + spin_unlock_bh(&table->tb6_lock); + } fib6_info_release(f6i); } } @@ -2706,6 +2714,7 @@ EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr); void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) { struct prefix_info *pinfo; + struct fib6_table *table; __u32 valid_lft; __u32 prefered_lft; int addr_type, err; @@ -2782,11 +2791,20 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) if (valid_lft == 0) { ip6_del_rt(net, rt, false); rt = NULL; - } else if (addrconf_finite_timeout(rt_expires)) { - /* not infinity */ - fib6_set_expires(rt, jiffies + rt_expires); } else { - fib6_clean_expires(rt); + table = rt->fib6_table; + spin_lock_bh(&table->tb6_lock); + + if (addrconf_finite_timeout(rt_expires)) { + /* not infinity */ + fib6_set_expires(rt, jiffies + rt_expires); + fib6_add_gc_list(rt); + } else { + fib6_clean_expires(rt); + fib6_remove_gc_list(rt); + } + + spin_unlock_bh(&table->tb6_lock); } } else if (valid_lft) { clock_t expires = 0; @@ -4741,6 +4759,7 @@ static int modify_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, u32 flags, bool modify_peer) { + struct fib6_table *table; struct fib6_info *f6i; u32 prio; @@ -4761,10 +4780,18 @@ static int modify_prefix_route(struct inet6_ifaddr *ifp, ifp->rt_priority, ifp->idev->dev, expires, flags, GFP_KERNEL); } else { - if (!expires) + table = f6i->fib6_table; + spin_lock_bh(&table->tb6_lock); + + if (!expires) { fib6_clean_expires(f6i); - else + fib6_remove_gc_list(f6i); + } else { fib6_set_expires(f6i, expires); + fib6_add_gc_list(f6i); + } + + spin_unlock_bh(&table->tb6_lock); fib6_info_release(f6i); } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 38a0348b1d17..805bbf26b3ef 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -160,6 +160,8 @@ struct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh) INIT_LIST_HEAD(&f6i->fib6_siblings); refcount_set(&f6i->fib6_ref, 1); + INIT_HLIST_NODE(&f6i->gc_link); + return f6i; } @@ -246,6 +248,7 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id) net->ipv6.fib6_null_entry); table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; inet_peer_base_init(&table->tb6_peers); + INIT_HLIST_HEAD(&table->tb6_gc_hlist); } return table; @@ -1055,6 +1058,9 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn, lockdep_is_held(&table->tb6_lock)); } } + + fib6_clean_expires(rt); + fib6_remove_gc_list(rt); } /* @@ -1115,10 +1121,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, rt->fib6_nsiblings = 0; if (!(iter->fib6_flags & RTF_EXPIRES)) return -EEXIST; - if (!(rt->fib6_flags & RTF_EXPIRES)) + if (!(rt->fib6_flags & RTF_EXPIRES)) { fib6_clean_expires(iter); - else + fib6_remove_gc_list(iter); + } else { fib6_set_expires(iter, rt->expires); + fib6_add_gc_list(iter); + } if (rt->fib6_pmtu) fib6_metric_set(iter, RTAX_MTU, @@ -1477,6 +1486,10 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, if (rt->nh) list_add(&rt->nh_list, &rt->nh->f6i_list); __fib6_update_sernum_upto_root(rt, fib6_new_sernum(info->nl_net)); + + if (rt->fib6_flags & RTF_EXPIRES) + fib6_add_gc_list(rt); + fib6_start_gc(info->nl_net, rt); } @@ -2280,9 +2293,8 @@ static void fib6_flush_trees(struct net *net) * Garbage collection */ -static int fib6_age(struct fib6_info *rt, void *arg) +static int fib6_age(struct fib6_info *rt, struct fib6_gc_args *gc_args) { - struct fib6_gc_args *gc_args = arg; unsigned long now = jiffies; /* @@ -2307,6 +2319,42 @@ static int fib6_age(struct fib6_info *rt, void *arg) return 0; } +static void fib6_gc_table(struct net *net, + struct fib6_table *tb6, + struct fib6_gc_args *gc_args) +{ + struct fib6_info *rt; + struct hlist_node *n; + struct nl_info info = { + .nl_net = net, + .skip_notify = false, + }; + + hlist_for_each_entry_safe(rt, n, &tb6->tb6_gc_hlist, gc_link) + if (fib6_age(rt, gc_args) == -1) + fib6_del(rt, &info); +} + +static void fib6_gc_all(struct net *net, struct fib6_gc_args *gc_args) +{ + struct fib6_table *table; + struct hlist_head *head; + unsigned int h; + + rcu_read_lock(); + for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { + head = &net->ipv6.fib_table_hash[h]; + hlist_for_each_entry_rcu(table, head, tb6_hlist) { + spin_lock_bh(&table->tb6_lock); + + fib6_gc_table(net, table, gc_args); + + spin_unlock_bh(&table->tb6_lock); + } + } + rcu_read_unlock(); +} + void fib6_run_gc(unsigned long expires, struct net *net, bool force) { struct fib6_gc_args gc_args; @@ -2322,7 +2370,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force) net->ipv6.sysctl.ip6_rt_gc_interval; gc_args.more = 0; - fib6_clean_all(net, fib6_age, &gc_args); + fib6_gc_all(net, &gc_args); now = jiffies; net->ipv6.ip6_rt_last_gc = now; @@ -2382,6 +2430,7 @@ static int __net_init fib6_net_init(struct net *net) net->ipv6.fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; inet_peer_base_init(&net->ipv6.fib6_main_tbl->tb6_peers); + INIT_HLIST_HEAD(&net->ipv6.fib6_main_tbl->tb6_gc_hlist); #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl), @@ -2394,6 +2443,7 @@ static int __net_init fib6_net_init(struct net *net) net->ipv6.fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; inet_peer_base_init(&net->ipv6.fib6_local_tbl->tb6_peers); + INIT_HLIST_HEAD(&net->ipv6.fib6_local_tbl->tb6_gc_hlist); #endif fib6_tables_init(net); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index a68462668158..73cb31afe935 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1237,6 +1237,7 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) struct ndisc_options ndopts; struct fib6_info *rt = NULL; struct inet6_dev *in6_dev; + struct fib6_table *table; u32 defrtr_usr_metric; unsigned int pref = 0; __u32 old_if_flags; @@ -1410,8 +1411,15 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) inet6_rt_notify(RTM_NEWROUTE, rt, &nlinfo, NLM_F_REPLACE); } - if (rt) + if (rt) { + table = rt->fib6_table; + spin_lock_bh(&table->tb6_lock); + fib6_set_expires(rt, jiffies + (HZ * lifetime)); + fib6_add_gc_list(rt); + + spin_unlock_bh(&table->tb6_lock); + } if (in6_dev->cnf.accept_ra_min_hop_limit < 256 && ra_msg->icmph.icmp6_hop_limit) { if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) { diff --git a/net/ipv6/route.c b/net/ipv6/route.c index dd6ff5b20918..707d65bc9c0e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -931,6 +931,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, struct net *net = dev_net(dev); struct route_info *rinfo = (struct route_info *) opt; struct in6_addr prefix_buf, *prefix; + struct fib6_table *table; unsigned int pref; unsigned long lifetime; struct fib6_info *rt; @@ -989,10 +990,18 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); if (rt) { - if (!addrconf_finite_timeout(lifetime)) + table = rt->fib6_table; + spin_lock_bh(&table->tb6_lock); + + if (!addrconf_finite_timeout(lifetime)) { fib6_clean_expires(rt); - else + fib6_remove_gc_list(rt); + } else { fib6_set_expires(rt, jiffies + HZ * lifetime); + fib6_add_gc_list(rt); + } + + spin_unlock_bh(&table->tb6_lock); fib6_info_release(rt); } From 768e06a8bcab045de9eac87dd071a769119cd0fd Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 14:06:52 -0800 Subject: [PATCH 1055/2255] net/ipv6: set expires in modify_prefix_route() if RTF_EXPIRES is set. Make the decision to set or clean the expires of a route based on the RTF_EXPIRES flag, rather than the value of the "expires" argument. This patch doesn't make difference logically, but make inet6_addr_modify() and modify_prefix_route() consistent. The function inet6_addr_modify() is the only caller of modify_prefix_route(), and it passes the RTF_EXPIRES flag and an expiration value. The RTF_EXPIRES flag is turned on or off based on the value of valid_lft. The RTF_EXPIRES flag is turned on if valid_lft is a finite value (not infinite, not 0xffffffff). Even if valid_lft is 0, the RTF_EXPIRES flag remains on. The expiration value being passed is equal to the valid_lft value if the flag is on. However, if the valid_lft value is infinite, the expiration value becomes 0 and the RTF_EXPIRES flag is turned off. Despite this, modify_prefix_route() decides to set the expiration value if the received expiration value is not zero. This mixing of infinite and zero cases creates an inconsistency. Reviewed-by: Hangbin Liu Reviewed-by: David Ahern Signed-off-by: Kui-Feng Lee Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0ea44563454f..ca1b719323c0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4783,7 +4783,7 @@ static int modify_prefix_route(struct inet6_ifaddr *ifp, table = f6i->fib6_table; spin_lock_bh(&table->tb6_lock); - if (!expires) { + if (!(flags & RTF_EXPIRES)) { fib6_clean_expires(f6i); fib6_remove_gc_list(f6i); } else { From 3407df8dc2de07d6b80f28d1a19a5c24a835f69b Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 14:06:53 -0800 Subject: [PATCH 1056/2255] selftests/net: Adding test cases of replacing routes and route advertisements. Add tests of changing permanent routes to temporary routes and the reversed case to make sure GC working correctly in these cases. Add tests for the temporary routes from RA. The existing device will be deleted between tests to remove all routes associated with it, so that the earlier tests don't mess up the later ones. Reviewed-by: Hangbin Liu Reviewed-by: David Ahern Tested-by: Hangbin Liu Signed-off-by: Kui-Feng Lee Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 151 +++++++++++++++++++---- 1 file changed, 129 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index b3ecccbbfcd2..3ec1050e47a2 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -743,6 +743,43 @@ fib_notify_test() cleanup &> /dev/null } +# Create a new dummy_10 to remove all associated routes. +reset_dummy_10() +{ + $IP link del dev dummy_10 + + $IP link add dummy_10 type dummy + $IP link set dev dummy_10 up + $IP -6 address add 2001:10::1/64 dev dummy_10 +} + +check_rt_num() +{ + local expected=$1 + local num=$2 + + if [ $num -ne $expected ]; then + echo "FAIL: Expected $expected routes, got $num" + ret=1 + else + ret=0 + fi +} + +check_rt_num_clean() +{ + local expected=$1 + local num=$2 + + if [ $num -ne $expected ]; then + log_test 1 0 "expected $expected routes, got $num" + set +e + cleanup &> /dev/null + return 1 + fi + return 0 +} + fib6_gc_test() { setup @@ -751,7 +788,7 @@ fib6_gc_test() echo "Fib6 garbage collection test" set -e - EXPIRE=3 + EXPIRE=5 # Check expiration of routes every $EXPIRE seconds (GC) $NS_EXEC sysctl -wq net.ipv6.route.gc_interval=$EXPIRE @@ -763,44 +800,114 @@ fib6_gc_test() $NS_EXEC sysctl -wq net.ipv6.route.flush=1 # Temporary routes - for i in $(seq 1 1000); do + for i in $(seq 1 5); do # Expire route after $EXPIRE seconds $IP -6 route add 2001:20::$i \ via 2001:10::2 dev dummy_10 expires $EXPIRE done - sleep $(($EXPIRE * 2)) - N_EXP_SLEEP=$($IP -6 route list |grep expires|wc -l) - if [ $N_EXP_SLEEP -ne 0 ]; then - echo "FAIL: expected 0 routes with expires, got $N_EXP_SLEEP" - ret=1 - else - ret=0 - fi + sleep $(($EXPIRE * 2 + 1)) + $NS_EXEC sysctl -wq net.ipv6.route.flush=1 + check_rt_num 0 $($IP -6 route list |grep expires|wc -l) + log_test $ret 0 "ipv6 route garbage collection" + + reset_dummy_10 # Permanent routes - for i in $(seq 1 5000); do + for i in $(seq 1 5); do $IP -6 route add 2001:30::$i \ via 2001:10::2 dev dummy_10 done # Temporary routes - for i in $(seq 1 1000); do + for i in $(seq 1 5); do # Expire route after $EXPIRE seconds $IP -6 route add 2001:20::$i \ via 2001:10::2 dev dummy_10 expires $EXPIRE done - sleep $(($EXPIRE * 2)) - N_EXP_SLEEP=$($IP -6 route list |grep expires|wc -l) - if [ $N_EXP_SLEEP -ne 0 ]; then - echo "FAIL: expected 0 routes with expires," \ - "got $N_EXP_SLEEP (5000 permanent routes)" - ret=1 - else - ret=0 + sleep $(($EXPIRE * 2 + 1)) + check_rt_num 0 $($IP -6 route list |grep expires|wc -l) + log_test $ret 0 "ipv6 route garbage collection (with permanent routes)" + + reset_dummy_10 + + # Permanent routes + for i in $(seq 1 5); do + $IP -6 route add 2001:20::$i \ + via 2001:10::2 dev dummy_10 + done + # Replace with temporary routes + for i in $(seq 1 5); do + # Expire route after $EXPIRE seconds + $IP -6 route replace 2001:20::$i \ + via 2001:10::2 dev dummy_10 expires $EXPIRE + done + check_rt_num_clean 5 $($IP -6 route list |grep expires|wc -l) || return + # Wait for GC + sleep $(($EXPIRE * 2 + 1)) + $NS_EXEC sysctl -wq net.ipv6.route.flush=1 + check_rt_num 0 $($IP -6 route list |grep expires|wc -l) + log_test $ret 0 "ipv6 route garbage collection (replace with expires)" + + reset_dummy_10 + + # Temporary routes + for i in $(seq 1 5); do + # Expire route after $EXPIRE seconds + $IP -6 route add 2001:20::$i \ + via 2001:10::2 dev dummy_10 expires $EXPIRE + done + # Replace with permanent routes + for i in $(seq 1 5); do + $IP -6 route replace 2001:20::$i \ + via 2001:10::2 dev dummy_10 + done + check_rt_num_clean 0 $($IP -6 route list |grep expires|wc -l) || return + + # Wait for GC + sleep $(($EXPIRE * 2 + 1)) + + check_rt_num 5 $($IP -6 route list |grep -v expires|grep 2001:20::|wc -l) + log_test $ret 0 "ipv6 route garbage collection (replace with permanent)" + + # ra6 is required for the next test. (ipv6toolkit) + if [ ! -x "$(command -v ra6)" ]; then + echo "SKIP: ra6 not found." + set +e + cleanup &> /dev/null + return fi - set +e + # Delete dummy_10 and remove all routes + $IP link del dev dummy_10 - log_test $ret 0 "ipv6 route garbage collection" + # Create a pair of veth devices to send a RA message from one + # device to another. + $IP link add veth1 type veth peer name veth2 + $IP link set dev veth1 up + $IP link set dev veth2 up + $IP -6 address add 2001:10::1/64 dev veth1 nodad + $IP -6 address add 2001:10::2/64 dev veth2 nodad + + # Make veth1 ready to receive RA messages. + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra=2 + + # Send a RA message with a route from veth2 to veth1. + $NS_EXEC ra6 -i veth2 -d 2001:10::1 -t $EXPIRE + + # Wait for the RA message. + sleep 1 + + # systemd may mess up the test. You syould make sure that + # systemd-networkd.service and systemd-networkd.socket are stopped. + check_rt_num_clean 1 $($IP -6 route list|grep expires|wc -l) || return + + # Wait for GC + sleep $(($EXPIRE * 2 + 1)) + + $NS_EXEC sysctl -wq net.ipv6.route.flush=1 + check_rt_num 0 $($IP -6 route list |grep expires|wc -l) + log_test $ret 0 "ipv6 route garbage collection (RA message)" + + set +e cleanup &> /dev/null } From 0918c1dcd55cfe3b8f9844731dc68eee948c9f92 Mon Sep 17 00:00:00 2001 From: Abhishek Chauhan Date: Thu, 8 Feb 2024 15:11:45 -0800 Subject: [PATCH 1057/2255] net: stmmac: dwmac-qcom-ethqos: Enable TBS on all queues but 0 TSO and TBS cannot co-exist. TBS requires special descriptor to be allocated at bootup. Initialising Tx queues at probe to support TSO and TBS can help in allocating those resources at bootup. TX queues with TBS can support etf qdisc hw offload. This is similar to the patch raised by NXP commit 3b12ec8f618e ("net: stmmac: dwmac-imx: set TSO/TBS TX queues default settings") Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Abhishek Chauhan Reviewed-by: Jeff Johnson Reviewed-by: Andrew Halaney Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 31631e3f89d0..2691a250a5a7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -728,7 +728,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) struct stmmac_resources stmmac_res; struct device *dev = &pdev->dev; struct qcom_ethqos *ethqos; - int ret; + int ret, i; ret = stmmac_get_platform_resources(pdev, &stmmac_res); if (ret) @@ -822,6 +822,10 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->serdes_powerdown = qcom_ethqos_serdes_powerdown; } + /* Enable TSO on queue0 and enable TBS on rest of the queues */ + for (i = 1; i < plat_dat->tx_queues_to_use; i++) + plat_dat->tx_queues_cfg[i].tbs_en = 1; + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } From 33f4336cbd32c21717b60d013693a0bd51a27db6 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:37 -0300 Subject: [PATCH 1058/2255] net: dsa: realtek: drop cleanup from realtek_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was never used and never referenced. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Alvin Šipraga Reviewed-by: Florian Fainelli Reviewed-by: Linus Walleij Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index 790488e9c667..e9ee778665b2 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -91,7 +91,6 @@ struct realtek_ops { int (*detect)(struct realtek_priv *priv); int (*reset_chip)(struct realtek_priv *priv); int (*setup)(struct realtek_priv *priv); - void (*cleanup)(struct realtek_priv *priv); int (*get_mib_counter)(struct realtek_priv *priv, int port, struct rtl8366_mib_counter *mib, From ded3813b44fe11a3bbd2c9d7df8870e8c19a7ccd Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:38 -0300 Subject: [PATCH 1059/2255] net: dsa: realtek: introduce REALTEK_DSA namespace Create a namespace to group the exported symbols. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek-mdio.c | 1 + drivers/net/dsa/realtek/realtek-smi.c | 1 + drivers/net/dsa/realtek/rtl8365mb.c | 1 + drivers/net/dsa/realtek/rtl8366-core.c | 22 +++++++++++----------- drivers/net/dsa/realtek/rtl8366rb.c | 1 + 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index 292e6d087e8b..c2572463679f 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -288,3 +288,4 @@ mdio_module_driver(realtek_mdio_driver); MODULE_AUTHOR("Luiz Angelo Daros de Luca "); MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 755546ed8db6..668336515119 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -565,3 +565,4 @@ module_platform_driver(realtek_smi_driver); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index b072045eb154..c42ee8241ca2 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -2177,3 +2177,4 @@ EXPORT_SYMBOL_GPL(rtl8365mb_variant); MODULE_AUTHOR("Alvin Šipraga "); MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/rtl8366-core.c b/drivers/net/dsa/realtek/rtl8366-core.c index 59f98d2c8769..7c6520ba3a26 100644 --- a/drivers/net/dsa/realtek/rtl8366-core.c +++ b/drivers/net/dsa/realtek/rtl8366-core.c @@ -34,7 +34,7 @@ int rtl8366_mc_is_used(struct realtek_priv *priv, int mc_index, int *used) return 0; } -EXPORT_SYMBOL_GPL(rtl8366_mc_is_used); +EXPORT_SYMBOL_NS_GPL(rtl8366_mc_is_used, REALTEK_DSA); /** * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration @@ -187,7 +187,7 @@ int rtl8366_set_vlan(struct realtek_priv *priv, int vid, u32 member, return ret; } -EXPORT_SYMBOL_GPL(rtl8366_set_vlan); +EXPORT_SYMBOL_NS_GPL(rtl8366_set_vlan, REALTEK_DSA); int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port, unsigned int vid) @@ -217,7 +217,7 @@ int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port, return 0; } -EXPORT_SYMBOL_GPL(rtl8366_set_pvid); +EXPORT_SYMBOL_NS_GPL(rtl8366_set_pvid, REALTEK_DSA); int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable) { @@ -243,7 +243,7 @@ int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable) priv->vlan4k_enabled = enable; return 0; } -EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k); +EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan4k, REALTEK_DSA); int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable) { @@ -265,7 +265,7 @@ int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable) return ret; } -EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); +EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan, REALTEK_DSA); int rtl8366_reset_vlan(struct realtek_priv *priv) { @@ -290,7 +290,7 @@ int rtl8366_reset_vlan(struct realtek_priv *priv) return 0; } -EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); +EXPORT_SYMBOL_NS_GPL(rtl8366_reset_vlan, REALTEK_DSA); int rtl8366_vlan_add(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, @@ -345,7 +345,7 @@ int rtl8366_vlan_add(struct dsa_switch *ds, int port, return 0; } -EXPORT_SYMBOL_GPL(rtl8366_vlan_add); +EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_add, REALTEK_DSA); int rtl8366_vlan_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan) @@ -389,7 +389,7 @@ int rtl8366_vlan_del(struct dsa_switch *ds, int port, return 0; } -EXPORT_SYMBOL_GPL(rtl8366_vlan_del); +EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_del, REALTEK_DSA); void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) @@ -403,7 +403,7 @@ void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, for (i = 0; i < priv->num_mib_counters; i++) ethtool_puts(&data, priv->mib_counters[i].name); } -EXPORT_SYMBOL_GPL(rtl8366_get_strings); +EXPORT_SYMBOL_NS_GPL(rtl8366_get_strings, REALTEK_DSA); int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) { @@ -417,7 +417,7 @@ int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) return priv->num_mib_counters; } -EXPORT_SYMBOL_GPL(rtl8366_get_sset_count); +EXPORT_SYMBOL_NS_GPL(rtl8366_get_sset_count, REALTEK_DSA); void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) { @@ -441,4 +441,4 @@ void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) data[i] = mibvalue; } } -EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats); +EXPORT_SYMBOL_NS_GPL(rtl8366_get_ethtool_stats, REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index e3b6a470ca67..6661d4ba6882 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -1938,3 +1938,4 @@ EXPORT_SYMBOL_GPL(rtl8366rb_variant); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(REALTEK_DSA); From bce254b839abe67577bebdef0838796af409c229 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:39 -0300 Subject: [PATCH 1060/2255] net: dsa: realtek: convert variants into real drivers Previously, the interface modules realtek-smi and realtek-mdio served as a platform and an MDIO driver, respectively. Each interface module redundantly specified the same compatible strings for both variants and referenced symbols from the variants. Now, each variant module has been transformed into a unified driver serving both as a platform and an MDIO driver. This modification reverses the relationship between the interface and variant modules, with the variant module now utilizing symbols from the interface modules. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/Kconfig | 20 +++---- drivers/net/dsa/realtek/realtek-mdio.c | 68 +++++++++++++++--------- drivers/net/dsa/realtek/realtek-mdio.h | 48 +++++++++++++++++ drivers/net/dsa/realtek/realtek-smi.c | 73 +++++++++++++++----------- drivers/net/dsa/realtek/realtek-smi.h | 48 +++++++++++++++++ drivers/net/dsa/realtek/rtl8365mb.c | 54 ++++++++++++++++++- drivers/net/dsa/realtek/rtl8366rb.c | 54 ++++++++++++++++++- 7 files changed, 292 insertions(+), 73 deletions(-) create mode 100644 drivers/net/dsa/realtek/realtek-mdio.h create mode 100644 drivers/net/dsa/realtek/realtek-smi.h diff --git a/drivers/net/dsa/realtek/Kconfig b/drivers/net/dsa/realtek/Kconfig index 060165a85fb7..9d182fde11b4 100644 --- a/drivers/net/dsa/realtek/Kconfig +++ b/drivers/net/dsa/realtek/Kconfig @@ -16,37 +16,29 @@ menuconfig NET_DSA_REALTEK if NET_DSA_REALTEK config NET_DSA_REALTEK_MDIO - tristate "Realtek MDIO interface driver" + tristate "Realtek MDIO interface support" depends on OF - depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB - depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB - depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB help Select to enable support for registering switches configured through MDIO. config NET_DSA_REALTEK_SMI - tristate "Realtek SMI interface driver" + tristate "Realtek SMI interface support" depends on OF - depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB - depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB - depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB help Select to enable support for registering switches connected through SMI. config NET_DSA_REALTEK_RTL8365MB - tristate "Realtek RTL8365MB switch subdriver" - imply NET_DSA_REALTEK_SMI - imply NET_DSA_REALTEK_MDIO + tristate "Realtek RTL8365MB switch driver" + depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO select NET_DSA_TAG_RTL8_4 help Select to enable support for Realtek RTL8365MB-VC and RTL8367S. config NET_DSA_REALTEK_RTL8366RB - tristate "Realtek RTL8366RB switch subdriver" - imply NET_DSA_REALTEK_SMI - imply NET_DSA_REALTEK_MDIO + tristate "Realtek RTL8366RB switch driver" + depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO select NET_DSA_TAG_RTL4_A help Select to enable support for Realtek RTL8366RB. diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index c2572463679f..7c5372561587 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -25,6 +25,7 @@ #include #include "realtek.h" +#include "realtek-mdio.h" /* Read/write via mdiobus */ #define REALTEK_MDIO_CTRL0_REG 31 @@ -140,7 +141,19 @@ static const struct regmap_config realtek_mdio_nolock_regmap_config = { .disable_locking = true, }; -static int realtek_mdio_probe(struct mdio_device *mdiodev) +/** + * realtek_mdio_probe() - Probe a platform device for an MDIO-connected switch + * @mdiodev: mdio_device to probe on. + * + * This function should be used as the .probe in an mdio_driver. It + * initializes realtek_priv and read data from the device-tree node. The switch + * is hard reset if a method is provided. It checks the switch chip ID and, + * finally, a DSA switch is registered. + * + * Context: Can sleep. Takes and releases priv->map_lock. + * Return: Returns 0 on success, a negative error on failure. + */ +int realtek_mdio_probe(struct mdio_device *mdiodev) { struct realtek_priv *priv; struct device *dev = &mdiodev->dev; @@ -235,8 +248,20 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev) return 0; } +EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, REALTEK_DSA); -static void realtek_mdio_remove(struct mdio_device *mdiodev) +/** + * realtek_mdio_remove() - Remove the driver of an MDIO-connected switch + * @mdiodev: mdio_device to be removed. + * + * This function should be used as the .remove_new in an mdio_driver. First + * it unregisters the DSA switch and cleans internal data. If a method is + * provided, the hard reset is asserted to avoid traffic leakage. + * + * Context: Can sleep. + * Return: Nothing. + */ +void realtek_mdio_remove(struct mdio_device *mdiodev) { struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); @@ -249,8 +274,21 @@ static void realtek_mdio_remove(struct mdio_device *mdiodev) if (priv->reset) gpiod_set_value(priv->reset, 1); } +EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA); -static void realtek_mdio_shutdown(struct mdio_device *mdiodev) +/** + * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch + * @mdiodev: mdio_device shutting down. + * + * This function should be used as the .shutdown in an mdio_driver. It shuts + * down the DSA switch and cleans the platform driver data, to prevent + * realtek_mdio_remove() from running afterwards, which is possible if the + * parent bus implements its own .shutdown() as .remove(). + * + * Context: Can sleep. + * Return: Nothing. + */ +void realtek_mdio_shutdown(struct mdio_device *mdiodev) { struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); @@ -261,29 +299,7 @@ static void realtek_mdio_shutdown(struct mdio_device *mdiodev) dev_set_drvdata(&mdiodev->dev, NULL); } - -static const struct of_device_id realtek_mdio_of_match[] = { -#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB) - { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, }, -#endif -#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB) - { .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, }, -#endif - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, realtek_mdio_of_match); - -static struct mdio_driver realtek_mdio_driver = { - .mdiodrv.driver = { - .name = "realtek-mdio", - .of_match_table = realtek_mdio_of_match, - }, - .probe = realtek_mdio_probe, - .remove = realtek_mdio_remove, - .shutdown = realtek_mdio_shutdown, -}; - -mdio_module_driver(realtek_mdio_driver); +EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA); MODULE_AUTHOR("Luiz Angelo Daros de Luca "); MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface"); diff --git a/drivers/net/dsa/realtek/realtek-mdio.h b/drivers/net/dsa/realtek/realtek-mdio.h new file mode 100644 index 000000000000..ee70f6a5b8ff --- /dev/null +++ b/drivers/net/dsa/realtek/realtek-mdio.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _REALTEK_MDIO_H +#define _REALTEK_MDIO_H + +#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) + +static inline int realtek_mdio_driver_register(struct mdio_driver *drv) +{ + return mdio_driver_register(drv); +} + +static inline void realtek_mdio_driver_unregister(struct mdio_driver *drv) +{ + mdio_driver_unregister(drv); +} + +int realtek_mdio_probe(struct mdio_device *mdiodev); +void realtek_mdio_remove(struct mdio_device *mdiodev); +void realtek_mdio_shutdown(struct mdio_device *mdiodev); + +#else /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) */ + +static inline int realtek_mdio_driver_register(struct mdio_driver *drv) +{ + return 0; +} + +static inline void realtek_mdio_driver_unregister(struct mdio_driver *drv) +{ +} + +static inline int realtek_mdio_probe(struct mdio_device *mdiodev) +{ + return -ENOENT; +} + +static inline void realtek_mdio_remove(struct mdio_device *mdiodev) +{ +} + +static inline void realtek_mdio_shutdown(struct mdio_device *mdiodev) +{ +} + +#endif /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) */ + +#endif /* _REALTEK_MDIO_H */ diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 668336515119..2a6a884bb45e 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -40,6 +40,7 @@ #include #include "realtek.h" +#include "realtek-smi.h" #define REALTEK_SMI_ACK_RETRY_COUNT 5 @@ -408,7 +409,19 @@ err_put_node: return ret; } -static int realtek_smi_probe(struct platform_device *pdev) +/** + * realtek_smi_probe() - Probe a platform device for an SMI-connected switch + * @pdev: platform_device to probe on. + * + * This function should be used as the .probe in a platform_driver. It + * initializes realtek_priv and read data from the device-tree node. The switch + * is hard reset if a method is provided. It checks the switch chip ID and, + * finally, a DSA switch is registered. + * + * Context: Can sleep. Takes and releases priv->map_lock. + * Return: Returns 0 on success, a negative error on failure. + */ +int realtek_smi_probe(struct platform_device *pdev) { const struct realtek_variant *var; struct device *dev = &pdev->dev; @@ -505,8 +518,20 @@ static int realtek_smi_probe(struct platform_device *pdev) } return 0; } +EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); -static void realtek_smi_remove(struct platform_device *pdev) +/** + * realtek_smi_remove() - Remove the driver of a SMI-connected switch + * @pdev: platform_device to be removed. + * + * This function should be used as the .remove_new in a platform_driver. First + * it unregisters the DSA switch and cleans internal data. If a method is + * provided, the hard reset is asserted to avoid traffic leakage. + * + * Context: Can sleep. + * Return: Nothing. + */ +void realtek_smi_remove(struct platform_device *pdev) { struct realtek_priv *priv = platform_get_drvdata(pdev); @@ -521,8 +546,21 @@ static void realtek_smi_remove(struct platform_device *pdev) if (priv->reset) gpiod_set_value(priv->reset, 1); } +EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); -static void realtek_smi_shutdown(struct platform_device *pdev) +/** + * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch + * @pdev: platform_device shutting down. + * + * This function should be used as the .shutdown in a platform_driver. It shuts + * down the DSA switch and cleans the platform driver data, to prevent + * realtek_smi_remove() from running afterwards, which is possible if the + * parent bus implements its own .shutdown() as .remove(). + * + * Context: Can sleep. + * Return: Nothing. + */ +void realtek_smi_shutdown(struct platform_device *pdev) { struct realtek_priv *priv = platform_get_drvdata(pdev); @@ -533,34 +571,7 @@ static void realtek_smi_shutdown(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); } - -static const struct of_device_id realtek_smi_of_match[] = { -#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB) - { - .compatible = "realtek,rtl8366rb", - .data = &rtl8366rb_variant, - }, -#endif -#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB) - { - .compatible = "realtek,rtl8365mb", - .data = &rtl8365mb_variant, - }, -#endif - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, realtek_smi_of_match); - -static struct platform_driver realtek_smi_driver = { - .driver = { - .name = "realtek-smi", - .of_match_table = realtek_smi_of_match, - }, - .probe = realtek_smi_probe, - .remove_new = realtek_smi_remove, - .shutdown = realtek_smi_shutdown, -}; -module_platform_driver(realtek_smi_driver); +EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); diff --git a/drivers/net/dsa/realtek/realtek-smi.h b/drivers/net/dsa/realtek/realtek-smi.h new file mode 100644 index 000000000000..ea49a2edd3c8 --- /dev/null +++ b/drivers/net/dsa/realtek/realtek-smi.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _REALTEK_SMI_H +#define _REALTEK_SMI_H + +#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) + +static inline int realtek_smi_driver_register(struct platform_driver *drv) +{ + return platform_driver_register(drv); +} + +static inline void realtek_smi_driver_unregister(struct platform_driver *drv) +{ + platform_driver_unregister(drv); +} + +int realtek_smi_probe(struct platform_device *pdev); +void realtek_smi_remove(struct platform_device *pdev); +void realtek_smi_shutdown(struct platform_device *pdev); + +#else /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) */ + +static inline int realtek_smi_driver_register(struct platform_driver *drv) +{ + return 0; +} + +static inline void realtek_smi_driver_unregister(struct platform_driver *drv) +{ +} + +static inline int realtek_smi_probe(struct platform_device *pdev) +{ + return -ENOENT; +} + +static inline void realtek_smi_remove(struct platform_device *pdev) +{ +} + +static inline void realtek_smi_shutdown(struct platform_device *pdev) +{ +} + +#endif /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) */ + +#endif /* _REALTEK_SMI_H */ diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index c42ee8241ca2..e67c4562f5db 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -101,6 +101,8 @@ #include #include "realtek.h" +#include "realtek-smi.h" +#include "realtek-mdio.h" /* Family-specific data and limits */ #define RTL8365MB_PHYADDRMAX 7 @@ -2172,7 +2174,57 @@ const struct realtek_variant rtl8365mb_variant = { .cmd_write = 0xb8, .chip_data_sz = sizeof(struct rtl8365mb), }; -EXPORT_SYMBOL_GPL(rtl8365mb_variant); + +static const struct of_device_id rtl8365mb_of_match[] = { + { .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, rtl8365mb_of_match); + +static struct platform_driver rtl8365mb_smi_driver = { + .driver = { + .name = "rtl8365mb-smi", + .of_match_table = rtl8365mb_of_match, + }, + .probe = realtek_smi_probe, + .remove_new = realtek_smi_remove, + .shutdown = realtek_smi_shutdown, +}; + +static struct mdio_driver rtl8365mb_mdio_driver = { + .mdiodrv.driver = { + .name = "rtl8365mb-mdio", + .of_match_table = rtl8365mb_of_match, + }, + .probe = realtek_mdio_probe, + .remove = realtek_mdio_remove, + .shutdown = realtek_mdio_shutdown, +}; + +static int rtl8365mb_init(void) +{ + int ret; + + ret = realtek_mdio_driver_register(&rtl8365mb_mdio_driver); + if (ret) + return ret; + + ret = realtek_smi_driver_register(&rtl8365mb_smi_driver); + if (ret) { + realtek_mdio_driver_unregister(&rtl8365mb_mdio_driver); + return ret; + } + + return 0; +} +module_init(rtl8365mb_init); + +static void __exit rtl8365mb_exit(void) +{ + realtek_smi_driver_unregister(&rtl8365mb_smi_driver); + realtek_mdio_driver_unregister(&rtl8365mb_mdio_driver); +} +module_exit(rtl8365mb_exit); MODULE_AUTHOR("Alvin Šipraga "); MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch"); diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index 6661d4ba6882..747407ae8225 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -23,6 +23,8 @@ #include #include "realtek.h" +#include "realtek-smi.h" +#include "realtek-mdio.h" #define RTL8366RB_PORT_NUM_CPU 5 #define RTL8366RB_NUM_PORTS 6 @@ -1933,7 +1935,57 @@ const struct realtek_variant rtl8366rb_variant = { .cmd_write = 0xa8, .chip_data_sz = sizeof(struct rtl8366rb), }; -EXPORT_SYMBOL_GPL(rtl8366rb_variant); + +static const struct of_device_id rtl8366rb_of_match[] = { + { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, rtl8366rb_of_match); + +static struct platform_driver rtl8366rb_smi_driver = { + .driver = { + .name = "rtl8366rb-smi", + .of_match_table = rtl8366rb_of_match, + }, + .probe = realtek_smi_probe, + .remove_new = realtek_smi_remove, + .shutdown = realtek_smi_shutdown, +}; + +static struct mdio_driver rtl8366rb_mdio_driver = { + .mdiodrv.driver = { + .name = "rtl8366rb-mdio", + .of_match_table = rtl8366rb_of_match, + }, + .probe = realtek_mdio_probe, + .remove = realtek_mdio_remove, + .shutdown = realtek_mdio_shutdown, +}; + +static int rtl8366rb_init(void) +{ + int ret; + + ret = realtek_mdio_driver_register(&rtl8366rb_mdio_driver); + if (ret) + return ret; + + ret = realtek_smi_driver_register(&rtl8366rb_smi_driver); + if (ret) { + realtek_mdio_driver_unregister(&rtl8366rb_mdio_driver); + return ret; + } + + return 0; +} +module_init(rtl8366rb_init); + +static void __exit rtl8366rb_exit(void) +{ + realtek_smi_driver_unregister(&rtl8366rb_smi_driver); + realtek_mdio_driver_unregister(&rtl8366rb_mdio_driver); +} +module_exit(rtl8366rb_exit); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch"); From 4667a1db2f550d23e01ba655fce331196ead6e92 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:40 -0300 Subject: [PATCH 1061/2255] net: dsa: realtek: keep variant reference in realtek_priv Instead of copying values from the variant, we can keep a reference in realtek_priv. This is a preliminary change for sharing code betwen interfaces. It will allow to move most of the probe into a common module while still allow code specific to each interface to read variant fields. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek-mdio.c | 4 +--- drivers/net/dsa/realtek/realtek-smi.c | 10 ++++------ drivers/net/dsa/realtek/realtek.h | 5 ++--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index 7c5372561587..7be00aa2a9e7 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -196,9 +196,7 @@ int realtek_mdio_probe(struct mdio_device *mdiodev) priv->dev = &mdiodev->dev; priv->chip_data = (void *)priv + sizeof(*priv); - priv->clk_delay = var->clk_delay; - priv->cmd_read = var->cmd_read; - priv->cmd_write = var->cmd_write; + priv->variant = var; priv->ops = var->ops; priv->write_reg_noack = realtek_mdio_write; diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 2a6a884bb45e..ad3b57311015 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -46,7 +46,7 @@ static inline void realtek_smi_clk_delay(struct realtek_priv *priv) { - ndelay(priv->clk_delay); + ndelay(priv->variant->clk_delay); } static void realtek_smi_start(struct realtek_priv *priv) @@ -209,7 +209,7 @@ static int realtek_smi_read_reg(struct realtek_priv *priv, u32 addr, u32 *data) realtek_smi_start(priv); /* Send READ command */ - ret = realtek_smi_write_byte(priv, priv->cmd_read); + ret = realtek_smi_write_byte(priv, priv->variant->cmd_read); if (ret) goto out; @@ -250,7 +250,7 @@ static int realtek_smi_write_reg(struct realtek_priv *priv, realtek_smi_start(priv); /* Send WRITE command */ - ret = realtek_smi_write_byte(priv, priv->cmd_write); + ret = realtek_smi_write_byte(priv, priv->variant->cmd_write); if (ret) goto out; @@ -459,9 +459,7 @@ int realtek_smi_probe(struct platform_device *pdev) /* Link forward and backward */ priv->dev = dev; - priv->clk_delay = var->clk_delay; - priv->cmd_read = var->cmd_read; - priv->cmd_write = var->cmd_write; + priv->variant = var; priv->ops = var->ops; priv->setup_interface = realtek_smi_setup_mdio; diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index e9ee778665b2..c7d5ef99e9db 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -58,9 +58,8 @@ struct realtek_priv { struct mii_bus *bus; int mdio_addr; - unsigned int clk_delay; - u8 cmd_read; - u8 cmd_write; + const struct realtek_variant *variant; + spinlock_t lock; /* Locks around command writes */ struct dsa_switch *ds; struct irq_domain *irqdomain; From 8be040ecd94c1a9a137927d18534edfae0a9b68a Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:41 -0300 Subject: [PATCH 1062/2255] net: dsa: realtek: common rtl83xx module Some code can be shared between both interface modules (MDIO and SMI) and among variants. These interface functions migrated to a common module: - rtl83xx_lock - rtl83xx_unlock - rtl83xx_probe - rtl83xx_register_switch - rtl83xx_unregister_switch - rtl83xx_shutdown - rtl83xx_remove The reset during probe was moved to the end of the common probe. This way, we avoid a reset if anything else fails. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/Makefile | 2 + drivers/net/dsa/realtek/realtek-mdio.c | 152 +++------------- drivers/net/dsa/realtek/realtek-smi.c | 166 ++++------------- drivers/net/dsa/realtek/realtek.h | 1 + drivers/net/dsa/realtek/rtl8365mb.c | 9 +- drivers/net/dsa/realtek/rtl8366rb.c | 9 +- drivers/net/dsa/realtek/rtl83xx.c | 235 +++++++++++++++++++++++++ drivers/net/dsa/realtek/rtl83xx.h | 21 +++ 8 files changed, 322 insertions(+), 273 deletions(-) create mode 100644 drivers/net/dsa/realtek/rtl83xx.c create mode 100644 drivers/net/dsa/realtek/rtl83xx.h diff --git a/drivers/net/dsa/realtek/Makefile b/drivers/net/dsa/realtek/Makefile index 0aab57252a7c..d579127f05f7 100644 --- a/drivers/net/dsa/realtek/Makefile +++ b/drivers/net/dsa/realtek/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_NET_DSA_REALTEK) += realtek_dsa.o +realtek_dsa-objs := rtl83xx.o obj-$(CONFIG_NET_DSA_REALTEK_MDIO) += realtek-mdio.o obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o obj-$(CONFIG_NET_DSA_REALTEK_RTL8366RB) += rtl8366.o diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index 7be00aa2a9e7..90a017cbe168 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -26,6 +26,7 @@ #include "realtek.h" #include "realtek-mdio.h" +#include "rtl83xx.h" /* Read/write via mdiobus */ #define REALTEK_MDIO_CTRL0_REG 31 @@ -100,147 +101,41 @@ out_unlock: return ret; } -static void realtek_mdio_lock(void *ctx) -{ - struct realtek_priv *priv = ctx; - - mutex_lock(&priv->map_lock); -} - -static void realtek_mdio_unlock(void *ctx) -{ - struct realtek_priv *priv = ctx; - - mutex_unlock(&priv->map_lock); -} - -static const struct regmap_config realtek_mdio_regmap_config = { - .reg_bits = 10, /* A4..A0 R4..R0 */ - .val_bits = 16, - .reg_stride = 1, - /* PHY regs are at 0x8000 */ - .max_register = 0xffff, - .reg_format_endian = REGMAP_ENDIAN_BIG, +static const struct realtek_interface_info realtek_mdio_info = { .reg_read = realtek_mdio_read, .reg_write = realtek_mdio_write, - .cache_type = REGCACHE_NONE, - .lock = realtek_mdio_lock, - .unlock = realtek_mdio_unlock, -}; - -static const struct regmap_config realtek_mdio_nolock_regmap_config = { - .reg_bits = 10, /* A4..A0 R4..R0 */ - .val_bits = 16, - .reg_stride = 1, - /* PHY regs are at 0x8000 */ - .max_register = 0xffff, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .reg_read = realtek_mdio_read, - .reg_write = realtek_mdio_write, - .cache_type = REGCACHE_NONE, - .disable_locking = true, }; /** * realtek_mdio_probe() - Probe a platform device for an MDIO-connected switch * @mdiodev: mdio_device to probe on. * - * This function should be used as the .probe in an mdio_driver. It - * initializes realtek_priv and read data from the device-tree node. The switch - * is hard reset if a method is provided. It checks the switch chip ID and, - * finally, a DSA switch is registered. + * This function should be used as the .probe in an mdio_driver. After + * calling the common probe function for both interfaces, it initializes the + * values specific for MDIO-connected devices. Finally, it calls a common + * function to register the DSA switch. * * Context: Can sleep. Takes and releases priv->map_lock. * Return: Returns 0 on success, a negative error on failure. */ int realtek_mdio_probe(struct mdio_device *mdiodev) { - struct realtek_priv *priv; struct device *dev = &mdiodev->dev; - const struct realtek_variant *var; - struct regmap_config rc; - struct device_node *np; + struct realtek_priv *priv; int ret; - var = of_device_get_match_data(dev); - if (!var) - return -EINVAL; + priv = rtl83xx_probe(dev, &realtek_mdio_info); + if (IS_ERR(priv)) + return PTR_ERR(priv); - priv = devm_kzalloc(&mdiodev->dev, - size_add(sizeof(*priv), var->chip_data_sz), - GFP_KERNEL); - if (!priv) - return -ENOMEM; - - mutex_init(&priv->map_lock); - - rc = realtek_mdio_regmap_config; - rc.lock_arg = priv; - priv->map = devm_regmap_init(dev, NULL, priv, &rc); - if (IS_ERR(priv->map)) { - ret = PTR_ERR(priv->map); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - rc = realtek_mdio_nolock_regmap_config; - priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); - if (IS_ERR(priv->map_nolock)) { - ret = PTR_ERR(priv->map_nolock); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - priv->mdio_addr = mdiodev->addr; priv->bus = mdiodev->bus; - priv->dev = &mdiodev->dev; - priv->chip_data = (void *)priv + sizeof(*priv); - - priv->variant = var; - priv->ops = var->ops; - + priv->mdio_addr = mdiodev->addr; priv->write_reg_noack = realtek_mdio_write; + priv->ds_ops = priv->variant->ds_ops_mdio; - np = dev->of_node; - - dev_set_drvdata(dev, priv); - - /* TODO: if power is software controlled, set up any regulators here */ - priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); - - priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(priv->reset)) { - dev_err(dev, "failed to get RESET GPIO\n"); - return PTR_ERR(priv->reset); - } - - if (priv->reset) { - gpiod_set_value(priv->reset, 1); - dev_dbg(dev, "asserted RESET\n"); - msleep(REALTEK_HW_STOP_DELAY); - gpiod_set_value(priv->reset, 0); - msleep(REALTEK_HW_START_DELAY); - dev_dbg(dev, "deasserted RESET\n"); - } - - ret = priv->ops->detect(priv); + ret = rtl83xx_register_switch(priv); if (ret) { - dev_err(dev, "unable to detect switch\n"); - return ret; - } - - priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); - if (!priv->ds) - return -ENOMEM; - - priv->ds->dev = dev; - priv->ds->num_ports = priv->num_ports; - priv->ds->priv = priv; - priv->ds->ops = var->ds_ops_mdio; - - ret = dsa_register_switch(priv->ds); - if (ret) { - dev_err(priv->dev, "unable to register switch ret = %d\n", ret); + rtl83xx_remove(priv); return ret; } @@ -253,8 +148,7 @@ EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, REALTEK_DSA); * @mdiodev: mdio_device to be removed. * * This function should be used as the .remove_new in an mdio_driver. First - * it unregisters the DSA switch and cleans internal data. If a method is - * provided, the hard reset is asserted to avoid traffic leakage. + * it unregisters the DSA switch and then it calls the common remove function. * * Context: Can sleep. * Return: Nothing. @@ -266,11 +160,9 @@ void realtek_mdio_remove(struct mdio_device *mdiodev) if (!priv) return; - dsa_unregister_switch(priv->ds); + rtl83xx_unregister_switch(priv); - /* leave the device reset asserted */ - if (priv->reset) - gpiod_set_value(priv->reset, 1); + rtl83xx_remove(priv); } EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA); @@ -278,10 +170,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA); * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch * @mdiodev: mdio_device shutting down. * - * This function should be used as the .shutdown in an mdio_driver. It shuts - * down the DSA switch and cleans the platform driver data, to prevent - * realtek_mdio_remove() from running afterwards, which is possible if the - * parent bus implements its own .shutdown() as .remove(). + * This function should be used as the .shutdown in a platform_driver. It calls + * the common shutdown function. * * Context: Can sleep. * Return: Nothing. @@ -293,9 +183,7 @@ void realtek_mdio_shutdown(struct mdio_device *mdiodev) if (!priv) return; - dsa_switch_shutdown(priv->ds); - - dev_set_drvdata(&mdiodev->dev, NULL); + rtl83xx_shutdown(priv); } EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index ad3b57311015..d676cc44d517 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -41,6 +41,7 @@ #include "realtek.h" #include "realtek-smi.h" +#include "rtl83xx.h" #define REALTEK_SMI_ACK_RETRY_COUNT 5 @@ -311,47 +312,6 @@ static int realtek_smi_read(void *ctx, u32 reg, u32 *val) return realtek_smi_read_reg(priv, reg, val); } -static void realtek_smi_lock(void *ctx) -{ - struct realtek_priv *priv = ctx; - - mutex_lock(&priv->map_lock); -} - -static void realtek_smi_unlock(void *ctx) -{ - struct realtek_priv *priv = ctx; - - mutex_unlock(&priv->map_lock); -} - -static const struct regmap_config realtek_smi_regmap_config = { - .reg_bits = 10, /* A4..A0 R4..R0 */ - .val_bits = 16, - .reg_stride = 1, - /* PHY regs are at 0x8000 */ - .max_register = 0xffff, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .reg_read = realtek_smi_read, - .reg_write = realtek_smi_write, - .cache_type = REGCACHE_NONE, - .lock = realtek_smi_lock, - .unlock = realtek_smi_unlock, -}; - -static const struct regmap_config realtek_smi_nolock_regmap_config = { - .reg_bits = 10, /* A4..A0 R4..R0 */ - .val_bits = 16, - .reg_stride = 1, - /* PHY regs are at 0x8000 */ - .max_register = 0xffff, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .reg_read = realtek_smi_read, - .reg_write = realtek_smi_write, - .cache_type = REGCACHE_NONE, - .disable_locking = true, -}; - static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) { struct realtek_priv *priv = bus->priv; @@ -409,111 +369,56 @@ err_put_node: return ret; } +static const struct realtek_interface_info realtek_smi_info = { + .reg_read = realtek_smi_read, + .reg_write = realtek_smi_write, +}; + /** * realtek_smi_probe() - Probe a platform device for an SMI-connected switch * @pdev: platform_device to probe on. * - * This function should be used as the .probe in a platform_driver. It - * initializes realtek_priv and read data from the device-tree node. The switch - * is hard reset if a method is provided. It checks the switch chip ID and, - * finally, a DSA switch is registered. + * This function should be used as the .probe in a platform_driver. After + * calling the common probe function for both interfaces, it initializes the + * values specific for SMI-connected devices. Finally, it calls a common + * function to register the DSA switch. * * Context: Can sleep. Takes and releases priv->map_lock. * Return: Returns 0 on success, a negative error on failure. */ int realtek_smi_probe(struct platform_device *pdev) { - const struct realtek_variant *var; struct device *dev = &pdev->dev; struct realtek_priv *priv; - struct regmap_config rc; - struct device_node *np; int ret; - var = of_device_get_match_data(dev); - np = dev->of_node; - - priv = devm_kzalloc(dev, sizeof(*priv) + var->chip_data_sz, GFP_KERNEL); - if (!priv) - return -ENOMEM; - priv->chip_data = (void *)priv + sizeof(*priv); - - mutex_init(&priv->map_lock); - - rc = realtek_smi_regmap_config; - rc.lock_arg = priv; - priv->map = devm_regmap_init(dev, NULL, priv, &rc); - if (IS_ERR(priv->map)) { - ret = PTR_ERR(priv->map); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - rc = realtek_smi_nolock_regmap_config; - priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); - if (IS_ERR(priv->map_nolock)) { - ret = PTR_ERR(priv->map_nolock); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - /* Link forward and backward */ - priv->dev = dev; - priv->variant = var; - priv->ops = var->ops; - - priv->setup_interface = realtek_smi_setup_mdio; - priv->write_reg_noack = realtek_smi_write_reg_noack; - - dev_set_drvdata(dev, priv); - spin_lock_init(&priv->lock); - - /* TODO: if power is software controlled, set up any regulators here */ - - priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(priv->reset)) { - dev_err(dev, "failed to get RESET GPIO\n"); - return PTR_ERR(priv->reset); - } - if (priv->reset) { - gpiod_set_value(priv->reset, 1); - dev_dbg(dev, "asserted RESET\n"); - msleep(REALTEK_HW_STOP_DELAY); - gpiod_set_value(priv->reset, 0); - msleep(REALTEK_HW_START_DELAY); - dev_dbg(dev, "deasserted RESET\n"); - } + priv = rtl83xx_probe(dev, &realtek_smi_info); + if (IS_ERR(priv)) + return PTR_ERR(priv); /* Fetch MDIO pins */ priv->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW); - if (IS_ERR(priv->mdc)) + if (IS_ERR(priv->mdc)) { + rtl83xx_remove(priv); return PTR_ERR(priv->mdc); + } + priv->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW); - if (IS_ERR(priv->mdio)) + if (IS_ERR(priv->mdio)) { + rtl83xx_remove(priv); return PTR_ERR(priv->mdio); + } - priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); + priv->write_reg_noack = realtek_smi_write_reg_noack; + priv->setup_interface = realtek_smi_setup_mdio; + priv->ds_ops = priv->variant->ds_ops_smi; - ret = priv->ops->detect(priv); + ret = rtl83xx_register_switch(priv); if (ret) { - dev_err(dev, "unable to detect switch\n"); + rtl83xx_remove(priv); return ret; } - priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); - if (!priv->ds) - return -ENOMEM; - - priv->ds->dev = dev; - priv->ds->num_ports = priv->num_ports; - priv->ds->priv = priv; - - priv->ds->ops = var->ds_ops_smi; - ret = dsa_register_switch(priv->ds); - if (ret) { - dev_err_probe(dev, ret, "unable to register switch\n"); - return ret; - } return 0; } EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); @@ -523,8 +428,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); * @pdev: platform_device to be removed. * * This function should be used as the .remove_new in a platform_driver. First - * it unregisters the DSA switch and cleans internal data. If a method is - * provided, the hard reset is asserted to avoid traffic leakage. + * it unregisters the DSA switch and cleans internal data. Finally, it calls + * the common remove function. * * Context: Can sleep. * Return: Nothing. @@ -536,13 +441,12 @@ void realtek_smi_remove(struct platform_device *pdev) if (!priv) return; - dsa_unregister_switch(priv->ds); + rtl83xx_unregister_switch(priv); + if (priv->user_mii_bus) of_node_put(priv->user_mii_bus->dev.of_node); - /* leave the device reset asserted */ - if (priv->reset) - gpiod_set_value(priv->reset, 1); + rtl83xx_remove(priv); } EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); @@ -550,10 +454,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch * @pdev: platform_device shutting down. * - * This function should be used as the .shutdown in a platform_driver. It shuts - * down the DSA switch and cleans the platform driver data, to prevent - * realtek_smi_remove() from running afterwards, which is possible if the - * parent bus implements its own .shutdown() as .remove(). + * This function should be used as the .shutdown in a platform_driver. It calls + * the common shutdown function. * * Context: Can sleep. * Return: Nothing. @@ -565,9 +467,7 @@ void realtek_smi_shutdown(struct platform_device *pdev) if (!priv) return; - dsa_switch_shutdown(priv->ds); - - platform_set_drvdata(pdev, NULL); + rtl83xx_shutdown(priv); } EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index c7d5ef99e9db..e9e28b189509 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -62,6 +62,7 @@ struct realtek_priv { spinlock_t lock; /* Locks around command writes */ struct dsa_switch *ds; + const struct dsa_switch_ops *ds_ops; struct irq_domain *irqdomain; bool leds_disabled; diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index e67c4562f5db..60f826a5a00a 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -103,6 +103,7 @@ #include "realtek.h" #include "realtek-smi.h" #include "realtek-mdio.h" +#include "rtl83xx.h" /* Family-specific data and limits */ #define RTL8365MB_PHYADDRMAX 7 @@ -691,7 +692,7 @@ static int rtl8365mb_phy_ocp_read(struct realtek_priv *priv, int phy, u32 val; int ret; - mutex_lock(&priv->map_lock); + rtl83xx_lock(priv); ret = rtl8365mb_phy_poll_busy(priv); if (ret) @@ -724,7 +725,7 @@ static int rtl8365mb_phy_ocp_read(struct realtek_priv *priv, int phy, *data = val & 0xFFFF; out: - mutex_unlock(&priv->map_lock); + rtl83xx_unlock(priv); return ret; } @@ -735,7 +736,7 @@ static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy, u32 val; int ret; - mutex_lock(&priv->map_lock); + rtl83xx_lock(priv); ret = rtl8365mb_phy_poll_busy(priv); if (ret) @@ -766,7 +767,7 @@ static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy, goto out; out: - mutex_unlock(&priv->map_lock); + rtl83xx_unlock(priv); return 0; } diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index 747407ae8225..a0c365325b4a 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -25,6 +25,7 @@ #include "realtek.h" #include "realtek-smi.h" #include "realtek-mdio.h" +#include "rtl83xx.h" #define RTL8366RB_PORT_NUM_CPU 5 #define RTL8366RB_NUM_PORTS 6 @@ -1720,7 +1721,7 @@ static int rtl8366rb_phy_read(struct realtek_priv *priv, int phy, int regnum) if (phy > RTL8366RB_PHY_NO_MAX) return -EINVAL; - mutex_lock(&priv->map_lock); + rtl83xx_lock(priv); ret = regmap_write(priv->map_nolock, RTL8366RB_PHY_ACCESS_CTRL_REG, RTL8366RB_PHY_CTRL_READ); @@ -1748,7 +1749,7 @@ static int rtl8366rb_phy_read(struct realtek_priv *priv, int phy, int regnum) phy, regnum, reg, val); out: - mutex_unlock(&priv->map_lock); + rtl83xx_unlock(priv); return ret; } @@ -1762,7 +1763,7 @@ static int rtl8366rb_phy_write(struct realtek_priv *priv, int phy, int regnum, if (phy > RTL8366RB_PHY_NO_MAX) return -EINVAL; - mutex_lock(&priv->map_lock); + rtl83xx_lock(priv); ret = regmap_write(priv->map_nolock, RTL8366RB_PHY_ACCESS_CTRL_REG, RTL8366RB_PHY_CTRL_WRITE); @@ -1779,7 +1780,7 @@ static int rtl8366rb_phy_write(struct realtek_priv *priv, int phy, int regnum, goto out; out: - mutex_unlock(&priv->map_lock); + rtl83xx_unlock(priv); return ret; } diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c new file mode 100644 index 000000000000..0f628065f456 --- /dev/null +++ b/drivers/net/dsa/realtek/rtl83xx.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include + +#include "realtek.h" +#include "rtl83xx.h" + +/** + * rtl83xx_lock() - Locks the mutex used by regmaps + * @ctx: realtek_priv pointer + * + * This function is passed to regmap to be used as the lock function. + * It is also used externally to block regmap before executing multiple + * operations that must happen in sequence (which will use + * realtek_priv.map_nolock instead). + * + * Context: Can sleep. Holds priv->map_lock lock. + * Return: nothing + */ +void rtl83xx_lock(void *ctx) +{ + struct realtek_priv *priv = ctx; + + mutex_lock(&priv->map_lock); +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, REALTEK_DSA); + +/** + * rtl83xx_unlock() - Unlocks the mutex used by regmaps + * @ctx: realtek_priv pointer + * + * This function unlocks the lock acquired by rtl83xx_lock. + * + * Context: Releases priv->map_lock lock. + * Return: nothing + */ +void rtl83xx_unlock(void *ctx) +{ + struct realtek_priv *priv = ctx; + + mutex_unlock(&priv->map_lock); +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA); + +/** + * rtl83xx_probe() - probe a Realtek switch + * @dev: the device being probed + * @interface_info: specific management interface info. + * + * This function initializes realtek_priv and reads data from the device tree + * node. The switch is hard resetted if a method is provided. + * + * Context: Can sleep. + * Return: Pointer to the realtek_priv or ERR_PTR() in case of failure. + * + * The realtek_priv pointer does not need to be freed as it is controlled by + * devres. + */ +struct realtek_priv * +rtl83xx_probe(struct device *dev, + const struct realtek_interface_info *interface_info) +{ + const struct realtek_variant *var; + struct realtek_priv *priv; + struct regmap_config rc = { + .reg_bits = 10, /* A4..A0 R4..R0 */ + .val_bits = 16, + .reg_stride = 1, + .max_register = 0xffff, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .reg_read = interface_info->reg_read, + .reg_write = interface_info->reg_write, + .cache_type = REGCACHE_NONE, + .lock = rtl83xx_lock, + .unlock = rtl83xx_unlock, + }; + int ret; + + var = of_device_get_match_data(dev); + if (!var) + return ERR_PTR(-EINVAL); + + priv = devm_kzalloc(dev, size_add(sizeof(*priv), var->chip_data_sz), + GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + + mutex_init(&priv->map_lock); + + rc.lock_arg = priv; + priv->map = devm_regmap_init(dev, NULL, priv, &rc); + if (IS_ERR(priv->map)) { + ret = PTR_ERR(priv->map); + dev_err(dev, "regmap init failed: %d\n", ret); + return ERR_PTR(ret); + } + + rc.disable_locking = true; + priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); + if (IS_ERR(priv->map_nolock)) { + ret = PTR_ERR(priv->map_nolock); + dev_err(dev, "regmap init failed: %d\n", ret); + return ERR_PTR(ret); + } + + /* Link forward and backward */ + priv->dev = dev; + priv->variant = var; + priv->ops = var->ops; + priv->chip_data = (void *)priv + sizeof(*priv); + + spin_lock_init(&priv->lock); + + priv->leds_disabled = of_property_read_bool(dev->of_node, + "realtek,disable-leds"); + + /* TODO: if power is software controlled, set up any regulators here */ + priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(priv->reset)) { + dev_err(dev, "failed to get RESET GPIO\n"); + return ERR_CAST(priv->reset); + } + + dev_set_drvdata(dev, priv); + + if (priv->reset) { + gpiod_set_value(priv->reset, 1); + dev_dbg(dev, "asserted RESET\n"); + msleep(REALTEK_HW_STOP_DELAY); + gpiod_set_value(priv->reset, 0); + msleep(REALTEK_HW_START_DELAY); + dev_dbg(dev, "deasserted RESET\n"); + } + + return priv; +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA); + +/** + * rtl83xx_register_switch() - detects and register a switch + * @priv: realtek_priv pointer + * + * This function first checks the switch chip ID and register a DSA + * switch. + * + * Context: Can sleep. Takes and releases priv->map_lock. + * Return: 0 on success, negative value for failure. + */ +int rtl83xx_register_switch(struct realtek_priv *priv) +{ + struct dsa_switch *ds; + int ret; + + ret = priv->ops->detect(priv); + if (ret) { + dev_err_probe(priv->dev, ret, "unable to detect switch\n"); + return ret; + } + + ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL); + if (!ds) + return -ENOMEM; + + ds->priv = priv; + ds->dev = priv->dev; + ds->ops = priv->ds_ops; + ds->num_ports = priv->num_ports; + priv->ds = ds; + + ret = dsa_register_switch(ds); + if (ret) { + dev_err_probe(priv->dev, ret, "unable to register switch\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA); + +/** + * rtl83xx_unregister_switch() - unregister a switch + * @priv: realtek_priv pointer + * + * This function unregister a DSA switch. + * + * Context: Can sleep. + * Return: Nothing. + */ +void rtl83xx_unregister_switch(struct realtek_priv *priv) +{ + dsa_unregister_switch(priv->ds); +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA); + +/** + * rtl83xx_shutdown() - shutdown a switch + * @priv: realtek_priv pointer + * + * This function shuts down the DSA switch and cleans the platform driver data, + * to prevent realtek_{smi,mdio}_remove() from running afterwards, which is + * possible if the parent bus implements its own .shutdown() as .remove(). + * + * Context: Can sleep. + * Return: Nothing. + */ +void rtl83xx_shutdown(struct realtek_priv *priv) +{ + dsa_switch_shutdown(priv->ds); + + dev_set_drvdata(priv->dev, NULL); +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA); + +/** + * rtl83xx_remove() - Cleanup a realtek switch driver + * @priv: realtek_priv pointer + * + * If a method is provided, this function asserts the hard reset of the switch + * in order to avoid leaking traffic when the driver is gone. + * + * Context: Might sleep if priv->gdev->chip->can_sleep. + * Return: nothing + */ +void rtl83xx_remove(struct realtek_priv *priv) +{ + /* leave the device reset asserted */ + if (priv->reset) + gpiod_set_value(priv->reset, 1); +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); + +MODULE_AUTHOR("Luiz Angelo Daros de Luca "); +MODULE_DESCRIPTION("Realtek DSA switches common module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/realtek/rtl83xx.h b/drivers/net/dsa/realtek/rtl83xx.h new file mode 100644 index 000000000000..a8eed92bce1a --- /dev/null +++ b/drivers/net/dsa/realtek/rtl83xx.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _RTL83XX_H +#define _RTL83XX_H + +struct realtek_interface_info { + int (*reg_read)(void *ctx, u32 reg, u32 *val); + int (*reg_write)(void *ctx, u32 reg, u32 val); +}; + +void rtl83xx_lock(void *ctx); +void rtl83xx_unlock(void *ctx); +struct realtek_priv * +rtl83xx_probe(struct device *dev, + const struct realtek_interface_info *interface_info); +int rtl83xx_register_switch(struct realtek_priv *priv); +void rtl83xx_unregister_switch(struct realtek_priv *priv); +void rtl83xx_shutdown(struct realtek_priv *priv); +void rtl83xx_remove(struct realtek_priv *priv); + +#endif /* _RTL83XX_H */ From 98b75c1c149c653ad11a440636213eb070325158 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:42 -0300 Subject: [PATCH 1063/2255] net: dsa: realtek: merge rtl83xx and interface modules into realtek_dsa Since rtl83xx and realtek-{smi,mdio} are always loaded together, we can optimize resource usage by consolidating them into a single module. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/Kconfig | 4 ++-- drivers/net/dsa/realtek/Makefile | 11 +++++++++-- drivers/net/dsa/realtek/realtek-mdio.c | 5 ----- drivers/net/dsa/realtek/realtek-smi.c | 5 ----- drivers/net/dsa/realtek/rtl83xx.c | 1 + 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/realtek/Kconfig b/drivers/net/dsa/realtek/Kconfig index 9d182fde11b4..6989972eebc3 100644 --- a/drivers/net/dsa/realtek/Kconfig +++ b/drivers/net/dsa/realtek/Kconfig @@ -16,14 +16,14 @@ menuconfig NET_DSA_REALTEK if NET_DSA_REALTEK config NET_DSA_REALTEK_MDIO - tristate "Realtek MDIO interface support" + bool "Realtek MDIO interface support" depends on OF help Select to enable support for registering switches configured through MDIO. config NET_DSA_REALTEK_SMI - tristate "Realtek SMI interface support" + bool "Realtek SMI interface support" depends on OF help Select to enable support for registering switches connected diff --git a/drivers/net/dsa/realtek/Makefile b/drivers/net/dsa/realtek/Makefile index d579127f05f7..35491dc20d6d 100644 --- a/drivers/net/dsa/realtek/Makefile +++ b/drivers/net/dsa/realtek/Makefile @@ -1,8 +1,15 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_NET_DSA_REALTEK) += realtek_dsa.o realtek_dsa-objs := rtl83xx.o -obj-$(CONFIG_NET_DSA_REALTEK_MDIO) += realtek-mdio.o -obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o + +ifdef CONFIG_NET_DSA_REALTEK_MDIO +realtek_dsa-objs += realtek-mdio.o +endif + +ifdef CONFIG_NET_DSA_REALTEK_SMI +realtek_dsa-objs += realtek-smi.o +endif + obj-$(CONFIG_NET_DSA_REALTEK_RTL8366RB) += rtl8366.o rtl8366-objs := rtl8366-core.o rtl8366rb.o obj-$(CONFIG_NET_DSA_REALTEK_RTL8365MB) += rtl8365mb.o diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index 90a017cbe168..04c65452da0d 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -186,8 +186,3 @@ void realtek_mdio_shutdown(struct mdio_device *mdiodev) rtl83xx_shutdown(priv); } EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA); - -MODULE_AUTHOR("Luiz Angelo Daros de Luca "); -MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface"); -MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index d676cc44d517..10de30d3e044 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -470,8 +470,3 @@ void realtek_smi_shutdown(struct platform_device *pdev) rtl83xx_shutdown(priv); } EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); - -MODULE_AUTHOR("Linus Walleij "); -MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); -MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(REALTEK_DSA); diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c index 0f628065f456..e42139f6e685 100644 --- a/drivers/net/dsa/realtek/rtl83xx.c +++ b/drivers/net/dsa/realtek/rtl83xx.c @@ -231,5 +231,6 @@ void rtl83xx_remove(struct realtek_priv *priv) EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); MODULE_AUTHOR("Luiz Angelo Daros de Luca "); +MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Realtek DSA switches common module"); MODULE_LICENSE("GPL"); From 8685c98d45c54346caf005de69988e13c731c533 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:43 -0300 Subject: [PATCH 1064/2255] net: dsa: realtek: get internal MDIO node by name The binding docs requires for SMI-connected devices that the switch must have a child node named "mdio" and with a compatible string of "realtek,smi-mdio". Meanwile, for MDIO-connected switches, the binding docs only requires a child node named "mdio". This patch changes the driver to use the common denominator for both interfaces, looking for the MDIO node by name, ignoring the compatible string. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek-smi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 10de30d3e044..1fa8e9cb1a10 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -333,7 +333,7 @@ static int realtek_smi_setup_mdio(struct dsa_switch *ds) struct device_node *mdio_np; int ret; - mdio_np = of_get_compatible_child(priv->dev->of_node, "realtek,smi-mdio"); + mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); if (!mdio_np) { dev_err(priv->dev, "no MDIO bus node\n"); return -ENODEV; From 68c66d8d8a19088967a0ab6bb98cb5ecc80ca0be Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:44 -0300 Subject: [PATCH 1065/2255] net: dsa: realtek: clean user_mii_bus setup Remove the line assigning dev.of_node in mdio_bus as subsequent of_mdiobus_register will always overwrite it. As discussed in [1], allow the DSA core to be simplified, by not assigning ds->user_mii_bus when the MDIO bus is described in OF, as it is unnecessary. Since commit 3b73a7b8ec38 ("net: mdio_bus: add refcounting for fwnodes to mdiobus"), we can put the "mdio" node just after the MDIO bus registration. [1] https://lkml.kernel.org/netdev/20231213120656.x46fyad6ls7sqyzv@skbuf/T/#u Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek-smi.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 1fa8e9cb1a10..0c36b43cd7b3 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -331,7 +331,7 @@ static int realtek_smi_setup_mdio(struct dsa_switch *ds) { struct realtek_priv *priv = ds->priv; struct device_node *mdio_np; - int ret; + int ret = 0; mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); if (!mdio_np) { @@ -344,15 +344,14 @@ static int realtek_smi_setup_mdio(struct dsa_switch *ds) ret = -ENOMEM; goto err_put_node; } + priv->user_mii_bus->priv = priv; priv->user_mii_bus->name = "SMI user MII"; priv->user_mii_bus->read = realtek_smi_mdio_read; priv->user_mii_bus->write = realtek_smi_mdio_write; snprintf(priv->user_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); - priv->user_mii_bus->dev.of_node = mdio_np; priv->user_mii_bus->parent = priv->dev; - ds->user_mii_bus = priv->user_mii_bus; ret = devm_of_mdiobus_register(priv->dev, priv->user_mii_bus, mdio_np); if (ret) { @@ -361,8 +360,6 @@ static int realtek_smi_setup_mdio(struct dsa_switch *ds) goto err_put_node; } - return 0; - err_put_node: of_node_put(mdio_np); @@ -428,8 +425,7 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); * @pdev: platform_device to be removed. * * This function should be used as the .remove_new in a platform_driver. First - * it unregisters the DSA switch and cleans internal data. Finally, it calls - * the common remove function. + * it unregisters the DSA switch and then it calls the common remove function. * * Context: Can sleep. * Return: Nothing. @@ -443,9 +439,6 @@ void realtek_smi_remove(struct platform_device *pdev) rtl83xx_unregister_switch(priv); - if (priv->user_mii_bus) - of_node_put(priv->user_mii_bus->dev.of_node); - rtl83xx_remove(priv); } EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); From b4bd77971f3c290c4694ed710cc6967593b10bc2 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:45 -0300 Subject: [PATCH 1066/2255] net: dsa: realtek: migrate user_mii_bus setup to realtek_dsa In the user MDIO driver, despite numerous references to SMI, including its compatible string, there's nothing inherently specific about the SMI interface in the user MDIO bus. Consequently, the code has been migrated to the rtl83xx module. All references to SMI have been eliminated. The MDIO bus id was changed from Realtek- to the switch devname suffixed with :user_mii, giving more information about the bus it is referencing. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek-smi.c | 57 +--------------------- drivers/net/dsa/realtek/rtl83xx.c | 68 +++++++++++++++++++++++++++ drivers/net/dsa/realtek/rtl83xx.h | 1 + 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 0c36b43cd7b3..bf02276b74d0 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -312,60 +311,6 @@ static int realtek_smi_read(void *ctx, u32 reg, u32 *val) return realtek_smi_read_reg(priv, reg, val); } -static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) -{ - struct realtek_priv *priv = bus->priv; - - return priv->ops->phy_read(priv, addr, regnum); -} - -static int realtek_smi_mdio_write(struct mii_bus *bus, int addr, int regnum, - u16 val) -{ - struct realtek_priv *priv = bus->priv; - - return priv->ops->phy_write(priv, addr, regnum, val); -} - -static int realtek_smi_setup_mdio(struct dsa_switch *ds) -{ - struct realtek_priv *priv = ds->priv; - struct device_node *mdio_np; - int ret = 0; - - mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); - if (!mdio_np) { - dev_err(priv->dev, "no MDIO bus node\n"); - return -ENODEV; - } - - priv->user_mii_bus = devm_mdiobus_alloc(priv->dev); - if (!priv->user_mii_bus) { - ret = -ENOMEM; - goto err_put_node; - } - - priv->user_mii_bus->priv = priv; - priv->user_mii_bus->name = "SMI user MII"; - priv->user_mii_bus->read = realtek_smi_mdio_read; - priv->user_mii_bus->write = realtek_smi_mdio_write; - snprintf(priv->user_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", - ds->index); - priv->user_mii_bus->parent = priv->dev; - - ret = devm_of_mdiobus_register(priv->dev, priv->user_mii_bus, mdio_np); - if (ret) { - dev_err(priv->dev, "unable to register MDIO bus %s\n", - priv->user_mii_bus->id); - goto err_put_node; - } - -err_put_node: - of_node_put(mdio_np); - - return ret; -} - static const struct realtek_interface_info realtek_smi_info = { .reg_read = realtek_smi_read, .reg_write = realtek_smi_write, @@ -407,7 +352,7 @@ int realtek_smi_probe(struct platform_device *pdev) } priv->write_reg_noack = realtek_smi_write_reg_noack; - priv->setup_interface = realtek_smi_setup_mdio; + priv->setup_interface = rtl83xx_setup_user_mdio; priv->ds_ops = priv->variant->ds_ops_smi; ret = rtl83xx_register_switch(priv); diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c index e42139f6e685..ceb8418dfab7 100644 --- a/drivers/net/dsa/realtek/rtl83xx.c +++ b/drivers/net/dsa/realtek/rtl83xx.c @@ -2,6 +2,7 @@ #include #include +#include #include "realtek.h" #include "rtl83xx.h" @@ -43,6 +44,73 @@ void rtl83xx_unlock(void *ctx) } EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA); +static int rtl83xx_user_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct realtek_priv *priv = bus->priv; + + return priv->ops->phy_read(priv, addr, regnum); +} + +static int rtl83xx_user_mdio_write(struct mii_bus *bus, int addr, int regnum, + u16 val) +{ + struct realtek_priv *priv = bus->priv; + + return priv->ops->phy_write(priv, addr, regnum, val); +} + +/** + * rtl83xx_setup_user_mdio() - register the user mii bus driver + * @ds: DSA switch associated with this user_mii_bus + * + * Registers the MDIO bus for built-in Ethernet PHYs, and associates it with + * the mandatory 'mdio' child OF node of the switch. + * + * Context: Can sleep. + * Return: 0 on success, negative value for failure. + */ +int rtl83xx_setup_user_mdio(struct dsa_switch *ds) +{ + struct realtek_priv *priv = ds->priv; + struct device_node *mdio_np; + struct mii_bus *bus; + int ret = 0; + + mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); + if (!mdio_np) { + dev_err(priv->dev, "no MDIO bus node\n"); + return -ENODEV; + } + + bus = devm_mdiobus_alloc(priv->dev); + if (!bus) { + ret = -ENOMEM; + goto err_put_node; + } + + bus->priv = priv; + bus->name = "Realtek user MII"; + bus->read = rtl83xx_user_mdio_read; + bus->write = rtl83xx_user_mdio_write; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s:user_mii", dev_name(priv->dev)); + bus->parent = priv->dev; + + ret = devm_of_mdiobus_register(priv->dev, bus, mdio_np); + if (ret) { + dev_err(priv->dev, "unable to register MDIO bus %s\n", + bus->id); + goto err_put_node; + } + + priv->user_mii_bus = bus; + +err_put_node: + of_node_put(mdio_np); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(rtl83xx_setup_user_mdio, REALTEK_DSA); + /** * rtl83xx_probe() - probe a Realtek switch * @dev: the device being probed diff --git a/drivers/net/dsa/realtek/rtl83xx.h b/drivers/net/dsa/realtek/rtl83xx.h index a8eed92bce1a..0ddff33df6b0 100644 --- a/drivers/net/dsa/realtek/rtl83xx.h +++ b/drivers/net/dsa/realtek/rtl83xx.h @@ -10,6 +10,7 @@ struct realtek_interface_info { void rtl83xx_lock(void *ctx); void rtl83xx_unlock(void *ctx); +int rtl83xx_setup_user_mdio(struct dsa_switch *ds); struct realtek_priv * rtl83xx_probe(struct device *dev, const struct realtek_interface_info *interface_info); From bba140a566ed075304c49c52ab32c0016cab624a Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:46 -0300 Subject: [PATCH 1067/2255] net: dsa: realtek: use the same mii bus driver for both interfaces The realtek-mdio will now use this driver instead of the generic DSA driver ("dsa user smi"), which should not be used with OF[1]. With a single ds_ops for both interfaces, the ds_ops in realtek_priv is no longer necessary. Now, the realtek_variant.ds_ops can be used directly. The realtek_priv.setup_interface() has been removed as we can directly call the new common function. [1] https://lkml.kernel.org/netdev/20220630200423.tieprdu5fpabflj7@bang-olufsen.dk/T/ Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek-mdio.c | 1 - drivers/net/dsa/realtek/realtek-smi.c | 2 - drivers/net/dsa/realtek/realtek.h | 5 +-- drivers/net/dsa/realtek/rtl8365mb.c | 49 +++--------------------- drivers/net/dsa/realtek/rtl8366rb.c | 52 +++----------------------- drivers/net/dsa/realtek/rtl83xx.c | 2 +- 6 files changed, 14 insertions(+), 97 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index 04c65452da0d..04b758e5a680 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -131,7 +131,6 @@ int realtek_mdio_probe(struct mdio_device *mdiodev) priv->bus = mdiodev->bus; priv->mdio_addr = mdiodev->addr; priv->write_reg_noack = realtek_mdio_write; - priv->ds_ops = priv->variant->ds_ops_mdio; ret = rtl83xx_register_switch(priv); if (ret) { diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index bf02276b74d0..88590ae95a75 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -352,8 +352,6 @@ int realtek_smi_probe(struct platform_device *pdev) } priv->write_reg_noack = realtek_smi_write_reg_noack; - priv->setup_interface = rtl83xx_setup_user_mdio; - priv->ds_ops = priv->variant->ds_ops_smi; ret = rtl83xx_register_switch(priv); if (ret) { diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index e9e28b189509..864bb9a88f14 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -62,7 +62,6 @@ struct realtek_priv { spinlock_t lock; /* Locks around command writes */ struct dsa_switch *ds; - const struct dsa_switch_ops *ds_ops; struct irq_domain *irqdomain; bool leds_disabled; @@ -73,7 +72,6 @@ struct realtek_priv { struct rtl8366_mib_counter *mib_counters; const struct realtek_ops *ops; - int (*setup_interface)(struct dsa_switch *ds); int (*write_reg_noack)(void *ctx, u32 addr, u32 data); int vlan_enabled; @@ -115,8 +113,7 @@ struct realtek_ops { }; struct realtek_variant { - const struct dsa_switch_ops *ds_ops_smi; - const struct dsa_switch_ops *ds_ops_mdio; + const struct dsa_switch_ops *ds_ops; const struct realtek_ops *ops; unsigned int clk_delay; u8 cmd_read; diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index 60f826a5a00a..778a962727ab 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -828,17 +828,6 @@ static int rtl8365mb_phy_write(struct realtek_priv *priv, int phy, int regnum, return 0; } -static int rtl8365mb_dsa_phy_read(struct dsa_switch *ds, int phy, int regnum) -{ - return rtl8365mb_phy_read(ds->priv, phy, regnum); -} - -static int rtl8365mb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum, - u16 val) -{ - return rtl8365mb_phy_write(ds->priv, phy, regnum, val); -} - static const struct rtl8365mb_extint * rtl8365mb_get_port_extint(struct realtek_priv *priv, int port) { @@ -2017,12 +2006,10 @@ static int rtl8365mb_setup(struct dsa_switch *ds) if (ret) goto out_teardown_irq; - if (priv->setup_interface) { - ret = priv->setup_interface(ds); - if (ret) { - dev_err(priv->dev, "could not set up MDIO bus\n"); - goto out_teardown_irq; - } + ret = rtl83xx_setup_user_mdio(ds); + if (ret) { + dev_err(priv->dev, "could not set up MDIO bus\n"); + goto out_teardown_irq; } /* Start statistics counter polling */ @@ -2116,7 +2103,7 @@ static int rtl8365mb_detect(struct realtek_priv *priv) return 0; } -static const struct dsa_switch_ops rtl8365mb_switch_ops_smi = { +static const struct dsa_switch_ops rtl8365mb_switch_ops = { .get_tag_protocol = rtl8365mb_get_tag_protocol, .change_tag_protocol = rtl8365mb_change_tag_protocol, .setup = rtl8365mb_setup, @@ -2137,29 +2124,6 @@ static const struct dsa_switch_ops rtl8365mb_switch_ops_smi = { .port_max_mtu = rtl8365mb_port_max_mtu, }; -static const struct dsa_switch_ops rtl8365mb_switch_ops_mdio = { - .get_tag_protocol = rtl8365mb_get_tag_protocol, - .change_tag_protocol = rtl8365mb_change_tag_protocol, - .setup = rtl8365mb_setup, - .teardown = rtl8365mb_teardown, - .phylink_get_caps = rtl8365mb_phylink_get_caps, - .phylink_mac_config = rtl8365mb_phylink_mac_config, - .phylink_mac_link_down = rtl8365mb_phylink_mac_link_down, - .phylink_mac_link_up = rtl8365mb_phylink_mac_link_up, - .phy_read = rtl8365mb_dsa_phy_read, - .phy_write = rtl8365mb_dsa_phy_write, - .port_stp_state_set = rtl8365mb_port_stp_state_set, - .get_strings = rtl8365mb_get_strings, - .get_ethtool_stats = rtl8365mb_get_ethtool_stats, - .get_sset_count = rtl8365mb_get_sset_count, - .get_eth_phy_stats = rtl8365mb_get_phy_stats, - .get_eth_mac_stats = rtl8365mb_get_mac_stats, - .get_eth_ctrl_stats = rtl8365mb_get_ctrl_stats, - .get_stats64 = rtl8365mb_get_stats64, - .port_change_mtu = rtl8365mb_port_change_mtu, - .port_max_mtu = rtl8365mb_port_max_mtu, -}; - static const struct realtek_ops rtl8365mb_ops = { .detect = rtl8365mb_detect, .phy_read = rtl8365mb_phy_read, @@ -2167,8 +2131,7 @@ static const struct realtek_ops rtl8365mb_ops = { }; const struct realtek_variant rtl8365mb_variant = { - .ds_ops_smi = &rtl8365mb_switch_ops_smi, - .ds_ops_mdio = &rtl8365mb_switch_ops_mdio, + .ds_ops = &rtl8365mb_switch_ops, .ops = &rtl8365mb_ops, .clk_delay = 10, .cmd_read = 0xb9, diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index a0c365325b4a..54eff9cd0c03 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -1033,12 +1033,10 @@ static int rtl8366rb_setup(struct dsa_switch *ds) if (ret) dev_info(priv->dev, "no interrupt support\n"); - if (priv->setup_interface) { - ret = priv->setup_interface(ds); - if (ret) { - dev_err(priv->dev, "could not set up MDIO bus\n"); - return -ENODEV; - } + ret = rtl83xx_setup_user_mdio(ds); + if (ret) { + dev_err(priv->dev, "could not set up MDIO bus\n"); + return -ENODEV; } return 0; @@ -1785,17 +1783,6 @@ out: return ret; } -static int rtl8366rb_dsa_phy_read(struct dsa_switch *ds, int phy, int regnum) -{ - return rtl8366rb_phy_read(ds->priv, phy, regnum); -} - -static int rtl8366rb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum, - u16 val) -{ - return rtl8366rb_phy_write(ds->priv, phy, regnum, val); -} - static int rtl8366rb_reset_chip(struct realtek_priv *priv) { int timeout = 10; @@ -1861,7 +1848,7 @@ static int rtl8366rb_detect(struct realtek_priv *priv) return 0; } -static const struct dsa_switch_ops rtl8366rb_switch_ops_smi = { +static const struct dsa_switch_ops rtl8366rb_switch_ops = { .get_tag_protocol = rtl8366_get_tag_protocol, .setup = rtl8366rb_setup, .phylink_get_caps = rtl8366rb_phylink_get_caps, @@ -1885,32 +1872,6 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops_smi = { .port_max_mtu = rtl8366rb_max_mtu, }; -static const struct dsa_switch_ops rtl8366rb_switch_ops_mdio = { - .get_tag_protocol = rtl8366_get_tag_protocol, - .setup = rtl8366rb_setup, - .phy_read = rtl8366rb_dsa_phy_read, - .phy_write = rtl8366rb_dsa_phy_write, - .phylink_get_caps = rtl8366rb_phylink_get_caps, - .phylink_mac_link_up = rtl8366rb_mac_link_up, - .phylink_mac_link_down = rtl8366rb_mac_link_down, - .get_strings = rtl8366_get_strings, - .get_ethtool_stats = rtl8366_get_ethtool_stats, - .get_sset_count = rtl8366_get_sset_count, - .port_bridge_join = rtl8366rb_port_bridge_join, - .port_bridge_leave = rtl8366rb_port_bridge_leave, - .port_vlan_filtering = rtl8366rb_vlan_filtering, - .port_vlan_add = rtl8366_vlan_add, - .port_vlan_del = rtl8366_vlan_del, - .port_enable = rtl8366rb_port_enable, - .port_disable = rtl8366rb_port_disable, - .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, - .port_bridge_flags = rtl8366rb_port_bridge_flags, - .port_stp_state_set = rtl8366rb_port_stp_state_set, - .port_fast_age = rtl8366rb_port_fast_age, - .port_change_mtu = rtl8366rb_change_mtu, - .port_max_mtu = rtl8366rb_max_mtu, -}; - static const struct realtek_ops rtl8366rb_ops = { .detect = rtl8366rb_detect, .get_vlan_mc = rtl8366rb_get_vlan_mc, @@ -1928,8 +1889,7 @@ static const struct realtek_ops rtl8366rb_ops = { }; const struct realtek_variant rtl8366rb_variant = { - .ds_ops_smi = &rtl8366rb_switch_ops_smi, - .ds_ops_mdio = &rtl8366rb_switch_ops_mdio, + .ds_ops = &rtl8366rb_switch_ops, .ops = &rtl8366rb_ops, .clk_delay = 10, .cmd_read = 0xa9, diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c index ceb8418dfab7..80f2c38ae55a 100644 --- a/drivers/net/dsa/realtek/rtl83xx.c +++ b/drivers/net/dsa/realtek/rtl83xx.c @@ -232,7 +232,7 @@ int rtl83xx_register_switch(struct realtek_priv *priv) ds->priv = priv; ds->dev = priv->dev; - ds->ops = priv->ds_ops; + ds->ops = priv->variant->ds_ops; ds->num_ports = priv->num_ports; priv->ds = ds; From 9fc469b2943d9b1ff2a7800f823e7cd7a5cac0ca Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Fri, 9 Feb 2024 02:03:47 -0300 Subject: [PATCH 1068/2255] net: dsa: realtek: embed dsa_switch into realtek_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed dsa_switch within realtek_priv to eliminate the need for a second memory allocation. Suggested-by: Alvin Šipraga Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Vladimir Oltean Reviewed-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek.h | 2 +- drivers/net/dsa/realtek/rtl8365mb.c | 15 +++++++++------ drivers/net/dsa/realtek/rtl8366rb.c | 3 ++- drivers/net/dsa/realtek/rtl83xx.c | 15 +++++++-------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index 864bb9a88f14..b80bfde1ad04 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -61,7 +61,7 @@ struct realtek_priv { const struct realtek_variant *variant; spinlock_t lock; /* Locks around command writes */ - struct dsa_switch *ds; + struct dsa_switch ds; struct irq_domain *irqdomain; bool leds_disabled; diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index 778a962727ab..be56373e9473 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -870,6 +870,7 @@ static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port, { const struct rtl8365mb_extint *extint = rtl8365mb_get_port_extint(priv, port); + struct dsa_switch *ds = &priv->ds; struct device_node *dn; struct dsa_port *dp; int tx_delay = 0; @@ -880,7 +881,7 @@ static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port, if (!extint) return -ENODEV; - dp = dsa_to_port(priv->ds, port); + dp = dsa_to_port(ds, port); dn = dp->dn; /* Set the RGMII TX/RX delay @@ -1533,6 +1534,7 @@ static void rtl8365mb_get_stats64(struct dsa_switch *ds, int port, static void rtl8365mb_stats_setup(struct realtek_priv *priv) { struct rtl8365mb *mb = priv->chip_data; + struct dsa_switch *ds = &priv->ds; int i; /* Per-chip global mutex to protect MIB counter access, since doing @@ -1543,7 +1545,7 @@ static void rtl8365mb_stats_setup(struct realtek_priv *priv) for (i = 0; i < priv->num_ports; i++) { struct rtl8365mb_port *p = &mb->ports[i]; - if (dsa_is_unused_port(priv->ds, i)) + if (dsa_is_unused_port(ds, i)) continue; /* Per-port spinlock to protect the stats64 data */ @@ -1559,12 +1561,13 @@ static void rtl8365mb_stats_setup(struct realtek_priv *priv) static void rtl8365mb_stats_teardown(struct realtek_priv *priv) { struct rtl8365mb *mb = priv->chip_data; + struct dsa_switch *ds = &priv->ds; int i; for (i = 0; i < priv->num_ports; i++) { struct rtl8365mb_port *p = &mb->ports[i]; - if (dsa_is_unused_port(priv->ds, i)) + if (dsa_is_unused_port(ds, i)) continue; cancel_delayed_work_sync(&p->mib_work); @@ -1963,7 +1966,7 @@ static int rtl8365mb_setup(struct dsa_switch *ds) dev_info(priv->dev, "no interrupt support\n"); /* Configure CPU tagging */ - dsa_switch_for_each_cpu_port(cpu_dp, priv->ds) { + dsa_switch_for_each_cpu_port(cpu_dp, ds) { cpu->mask |= BIT(cpu_dp->index); if (cpu->trap_port == RTL8365MB_MAX_NUM_PORTS) @@ -1978,7 +1981,7 @@ static int rtl8365mb_setup(struct dsa_switch *ds) for (i = 0; i < priv->num_ports; i++) { struct rtl8365mb_port *p = &mb->ports[i]; - if (dsa_is_unused_port(priv->ds, i)) + if (dsa_is_unused_port(ds, i)) continue; /* Forward only to the CPU */ @@ -1995,7 +1998,7 @@ static int rtl8365mb_setup(struct dsa_switch *ds) * ports will still forward frames to the CPU despite being * administratively down by default. */ - rtl8365mb_port_stp_state_set(priv->ds, i, BR_STATE_DISABLED); + rtl8365mb_port_stp_state_set(ds, i, BR_STATE_DISABLED); /* Set up per-port private data */ p->priv = priv; diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index 54eff9cd0c03..e10ae94cf771 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -1651,6 +1651,7 @@ static int rtl8366rb_get_mc_index(struct realtek_priv *priv, int port, int *val) static int rtl8366rb_set_mc_index(struct realtek_priv *priv, int port, int index) { + struct dsa_switch *ds = &priv->ds; struct rtl8366rb *rb; bool pvid_enabled; int ret; @@ -1675,7 +1676,7 @@ static int rtl8366rb_set_mc_index(struct realtek_priv *priv, int port, int index * not drop any untagged or C-tagged frames. Make sure to update the * filtering setting. */ - if (dsa_port_is_vlan_filtering(dsa_to_port(priv->ds, port))) + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) ret = rtl8366rb_drop_untagged(priv, port, !pvid_enabled); return ret; diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c index 80f2c38ae55a..801873754df2 100644 --- a/drivers/net/dsa/realtek/rtl83xx.c +++ b/drivers/net/dsa/realtek/rtl83xx.c @@ -217,7 +217,7 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA); */ int rtl83xx_register_switch(struct realtek_priv *priv) { - struct dsa_switch *ds; + struct dsa_switch *ds = &priv->ds; int ret; ret = priv->ops->detect(priv); @@ -226,15 +226,10 @@ int rtl83xx_register_switch(struct realtek_priv *priv) return ret; } - ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL); - if (!ds) - return -ENOMEM; - ds->priv = priv; ds->dev = priv->dev; ds->ops = priv->variant->ds_ops; ds->num_ports = priv->num_ports; - priv->ds = ds; ret = dsa_register_switch(ds); if (ret) { @@ -257,7 +252,9 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA); */ void rtl83xx_unregister_switch(struct realtek_priv *priv) { - dsa_unregister_switch(priv->ds); + struct dsa_switch *ds = &priv->ds; + + dsa_unregister_switch(ds); } EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA); @@ -274,7 +271,9 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA); */ void rtl83xx_shutdown(struct realtek_priv *priv) { - dsa_switch_shutdown(priv->ds); + struct dsa_switch *ds = &priv->ds; + + dsa_switch_shutdown(ds); dev_set_drvdata(priv->dev, NULL); } From 0972d1d979ccfd2b71ef36a5a2b1ad092be21bb9 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 9 Feb 2024 07:47:39 +0100 Subject: [PATCH 1069/2255] tg3: fix bug caused by uninitialized variable The reported bug is caused by using mii_eee_cap1_mod_linkmode_t() with an uninitialized bitmap. Fix this by zero-initializing the struct containing the bitmap. Fixes: 9bc791341bc9a5c22b ("tg3: convert EEE handling to use linkmode bitmaps") Reported-by: Srikanth Aithal Tested-by: Srikanth Aithal Signed-off-by: Heiner Kallweit Reviewed-by: Pavan Chebbi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 50f674031f72..7d0a2f5f3282 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -4616,7 +4616,7 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp) static bool tg3_phy_eee_config_ok(struct tg3 *tp) { - struct ethtool_keee eee; + struct ethtool_keee eee = {}; if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) return true; From bad9d21110037fa346426566d34dcffffc166fc6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Feb 2024 12:23:36 +0100 Subject: [PATCH 1070/2255] 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(-) 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__ */ From 1963e65b3dfee3f42dcb5d40b28764ec9939792c Mon Sep 17 00:00:00 2001 From: Suraj Jaiswal Date: Fri, 9 Feb 2024 14:20:11 +0530 Subject: [PATCH 1071/2255] dt-bindings: net: qcom,ethqos: add binding doc for safety IRQ for sa8775p Add binding doc for safety IRQ. The safety IRQ will be triggered for ECC(error correction code), DPP(data path parity), FSM(finite state machine) error. Signed-off-by: Suraj Jaiswal Reviewed-by: Rob Herring Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/qcom,ethqos.yaml | 9 ++++++--- Documentation/devicetree/bindings/net/snps,dwmac.yaml | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml index 7bdb412a0185..69a337c7e345 100644 --- a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml @@ -37,12 +37,14 @@ properties: items: - description: Combined signal for various interrupt events - description: The interrupt that occurs when Rx exits the LPI state + - description: The interrupt that occurs when HW safety error triggered interrupt-names: minItems: 1 items: - const: macirq - - const: eth_lpi + - enum: [eth_lpi, sfty] + - const: sfty clocks: maxItems: 4 @@ -89,8 +91,9 @@ examples: <&gcc GCC_ETH_PTP_CLK>, <&gcc GCC_ETH_RGMII_CLK>; interrupts = , - ; - interrupt-names = "macirq", "eth_lpi"; + , + ; + interrupt-names = "macirq", "eth_lpi", "sfty"; rx-fifo-depth = <4096>; tx-fifo-depth = <4096>; diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index 90c4db178c67..6b0341a8e0ea 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -108,13 +108,15 @@ properties: - description: Combined signal for various interrupt events - description: The interrupt to manage the remote wake-up packet detection - description: The interrupt that occurs when Rx exits the LPI state + - description: The interrupt that occurs when HW safety error triggered interrupt-names: minItems: 1 items: - const: macirq - - enum: [eth_wake_irq, eth_lpi] - - const: eth_lpi + - enum: [eth_wake_irq, eth_lpi, sfty] + - enum: [eth_wake_irq, eth_lpi, sfty] + - enum: [eth_wake_irq, eth_lpi, sfty] clocks: minItems: 1 From 5c2215167d122be0ee51676188b95529380d3d22 Mon Sep 17 00:00:00 2001 From: Suraj Jaiswal Date: Fri, 9 Feb 2024 14:20:12 +0530 Subject: [PATCH 1072/2255] net: stmmac: Add driver support for common safety IRQ Add support to listen HW safety IRQ like ECC(error correction code), DPP(data path parity), FSM(finite state machine) fault in common IRQ line. Signed-off-by: Suraj Jaiswal Reviewed-by: Serge Semin Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 3 ++ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 41 ++++++++++++++++++- .../ethernet/stmicro/stmmac/stmmac_platform.c | 8 ++++ 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 07fe852001a0..a6fefe675ef1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -371,6 +371,7 @@ enum request_irq_err { REQ_IRQ_ERR_ALL, REQ_IRQ_ERR_TX, REQ_IRQ_ERR_RX, + REQ_IRQ_ERR_SFTY, REQ_IRQ_ERR_SFTY_UE, REQ_IRQ_ERR_SFTY_CE, REQ_IRQ_ERR_LPI, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index f155e4841c62..dddcaa9220cc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -31,6 +31,7 @@ struct stmmac_resources { int wol_irq; int lpi_irq; int irq; + int sfty_irq; int sfty_ce_irq; int sfty_ue_irq; int rx_irq[MTL_MAX_RX_QUEUES]; @@ -298,6 +299,7 @@ struct stmmac_priv { void __iomem *ptpaddr; void __iomem *estaddr; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; + int sfty_irq; int sfty_ce_irq; int sfty_ue_irq; int rx_irq[MTL_MAX_RX_QUEUES]; @@ -306,6 +308,7 @@ struct stmmac_priv { char int_name_mac[IFNAMSIZ + 9]; char int_name_wol[IFNAMSIZ + 9]; char int_name_lpi[IFNAMSIZ + 9]; + char int_name_sfty[IFNAMSIZ + 10]; char int_name_sfty_ce[IFNAMSIZ + 10]; char int_name_sfty_ue[IFNAMSIZ + 10]; char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14]; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5236956cc7e4..9159d93ceb03 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3597,6 +3597,10 @@ static void stmmac_free_irq(struct net_device *dev, if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) free_irq(priv->wol_irq, dev); fallthrough; + case REQ_IRQ_ERR_SFTY: + if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq) + free_irq(priv->sfty_irq, dev); + fallthrough; case REQ_IRQ_ERR_WOL: free_irq(dev->irq, dev); fallthrough; @@ -3667,6 +3671,23 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev) } } + /* Request the common Safety Feature Correctible/Uncorrectible + * Error line in case of another line is used + */ + if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq) { + int_name = priv->int_name_sfty; + sprintf(int_name, "%s:%s", dev->name, "safety"); + ret = request_irq(priv->sfty_irq, stmmac_safety_interrupt, + 0, int_name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: alloc sfty MSI %d (error: %d)\n", + __func__, priv->sfty_irq, ret); + irq_err = REQ_IRQ_ERR_SFTY; + goto irq_error; + } + } + /* Request the Safety Feature Correctible Error line in * case of another line is used */ @@ -3804,6 +3825,21 @@ static int stmmac_request_irq_single(struct net_device *dev) } } + /* Request the common Safety Feature Correctible/Uncorrectible + * Error line in case of another line is used + */ + if (priv->sfty_irq > 0 && priv->sfty_irq != dev->irq) { + ret = request_irq(priv->sfty_irq, stmmac_safety_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: ERROR: allocating the sfty IRQ %d (%d)\n", + __func__, priv->sfty_irq, ret); + irq_err = REQ_IRQ_ERR_SFTY; + goto irq_error; + } + } + return 0; irq_error: @@ -6063,8 +6099,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) if (test_bit(STMMAC_DOWN, &priv->state)) return IRQ_HANDLED; - /* Check if a fatal error happened */ - if (stmmac_safety_feat_interrupt(priv)) + /* Check ASP error if it isn't delivered via an individual IRQ */ + if (priv->sfty_irq <= 0 && stmmac_safety_feat_interrupt(priv)) return IRQ_HANDLED; /* To handle Common interrupts */ @@ -7513,6 +7549,7 @@ int stmmac_dvr_probe(struct device *device, priv->dev->irq = res->irq; priv->wol_irq = res->wol_irq; priv->lpi_irq = res->lpi_irq; + priv->sfty_irq = res->sfty_irq; priv->sfty_ce_irq = res->sfty_ce_irq; priv->sfty_ue_irq = res->sfty_ue_irq; for (i = 0; i < MTL_MAX_RX_QUEUES; i++) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 70eadc83ca68..54797edc9b38 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -743,6 +743,14 @@ int stmmac_get_platform_resources(struct platform_device *pdev, dev_info(&pdev->dev, "IRQ eth_lpi not found\n"); } + stmmac_res->sfty_irq = + platform_get_irq_byname_optional(pdev, "sfty"); + if (stmmac_res->sfty_irq < 0) { + if (stmmac_res->sfty_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_info(&pdev->dev, "IRQ sfty not found\n"); + } + stmmac_res->addr = devm_platform_ioremap_resource(pdev, 0); return PTR_ERR_OR_ZERO(stmmac_res->addr); From 17ef8efc00b34918b966388b2af0993811895a8c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Feb 2024 15:30:56 +0000 Subject: [PATCH 1073/2255] ipv6: mcast: remove one synchronize_net() barrier in ipv6_mc_down() As discussed in the past (commit 2d3916f31891 ("ipv6: fix skb drops in igmp6_event_query() and igmp6_event_report()")) I think the synchronize_net() call in ipv6_mc_down() is not needed. Under load, synchronize_net() can last between 200 usec and 5 ms. KASAN seems to agree as well. Fixes: f185de28d9ae ("mld: add new workqueues for process mld events") Signed-off-by: Eric Dumazet Cc: Taehee Yoo Cc: Cong Wang Cc: David Ahern Signed-off-by: David S. Miller --- net/ipv6/mcast.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index bc6e0a0bad3c..76ee1615ff2a 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2719,7 +2719,6 @@ void ipv6_mc_down(struct inet6_dev *idev) /* Should stop work after group drop. or we will * start work again in mld_ifc_event() */ - synchronize_net(); mld_query_stop_work(idev); mld_report_stop_work(idev); From 4cd582ffa5a9a5d58e5bac9c5e55ca8eeabffddc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Feb 2024 15:30:57 +0000 Subject: [PATCH 1074/2255] net: use synchronize_net() in dev_change_name() dev_change_name() holds RTNL, we better use synchronize_net() instead of plain synchronize_rcu(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 31f2c97d1990..7cf15d2bf78d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1239,7 +1239,7 @@ rollback: netdev_name_node_del(dev->name_node); write_unlock(&dev_base_lock); - synchronize_rcu(); + synchronize_net(); write_lock(&dev_base_lock); netdev_name_node_add(net, dev->name_node); From 48ebf6ebbc91a6e6b2c0ac1217573e81b37ef2ab Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Feb 2024 15:30:58 +0000 Subject: [PATCH 1075/2255] bridge: vlan: use synchronize_net() when holding RTNL br_vlan_flush() and nbp_vlan_flush() should use synchronize_net() instead of syncronize_rcu() to release RTNL sooner. Signed-off-by: Eric Dumazet Acked-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_vlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 15f44d026e75..9c2fffb827ab 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -841,7 +841,7 @@ void br_vlan_flush(struct net_bridge *br) vg = br_vlan_group(br); __vlan_flush(br, NULL, vg); RCU_INIT_POINTER(br->vlgrp, NULL); - synchronize_rcu(); + synchronize_net(); __vlan_group_free(vg); } @@ -1372,7 +1372,7 @@ void nbp_vlan_flush(struct net_bridge_port *port) vg = nbp_vlan_group(port); __vlan_flush(port->br, port, vg); RCU_INIT_POINTER(port->vlgrp, NULL); - synchronize_rcu(); + synchronize_net(); __vlan_group_free(vg); } From 2cd0c51e3baf7aa49e802c06cb1b2ffa9c82fbe1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Feb 2024 15:30:59 +0000 Subject: [PATCH 1076/2255] ipv4/fib: use synchronize_net() when holding RTNL tnode_free() should use synchronize_net() instead of syncronize_rcu() to release RTNL sooner. Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 3ff35f811765..0fc7ab5832d1 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -501,7 +501,7 @@ static void tnode_free(struct key_vector *tn) if (tnode_free_size >= READ_ONCE(sysctl_fib_sync_mem)) { tnode_free_size = 0; - synchronize_rcu(); + synchronize_net(); } } From 78c3253f27e579f7f3a1f5c0cb8266693a7b4f41 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Feb 2024 15:31:00 +0000 Subject: [PATCH 1077/2255] net: use synchronize_rcu_expedited in cleanup_net() cleanup_net() is calling synchronize_rcu() right before acquiring RTNL. synchronize_rcu() is much slower than synchronize_rcu_expedited(), and cleanup_net() is currently single threaded. In many workloads we want cleanup_net() to be fast, in order to free memory and various sysfs and procfs entries as fast as possible. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/net_namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 233ec0cdd011..f0540c557515 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -622,7 +622,7 @@ static void cleanup_net(struct work_struct *work) * the rcu_barrier() below isn't sufficient alone. * Also the pre_exit() and exit() methods need this barrier. */ - synchronize_rcu(); + synchronize_rcu_expedited(); rtnl_lock(); list_for_each_entry_reverse(ops, &pernet_list, list) { From 1ebb85f9c03de0b66c334de219f224159e24e549 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Feb 2024 15:31:01 +0000 Subject: [PATCH 1078/2255] netfilter: conntrack: expedite rcu in nf_conntrack_cleanup_net_list nf_conntrack_cleanup_net_list() is calling synchronize_net() while RTNL is not held. This effectively calls synchronize_rcu(). synchronize_rcu() is much slower than synchronize_rcu_expedited(), and cleanup_net() is currently single threaded. In many workloads we want cleanup_net() to be faster, in order to free memory and various sysfs and procfs entries as fast as possible. Signed-off-by: Eric Dumazet Cc: Pablo Neira Ayuso Cc: Jozsef Kadlecsik Cc: Florian Westphal Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 2e5f3864d353..90e6bd2c3000 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -2530,7 +2530,7 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) * netfilter framework. Roll on, two-stage module * delete... */ - synchronize_net(); + synchronize_rcu_expedited(); i_see_dead_people: busy = 0; list_for_each_entry(net, net_exit_list, exit_list) { From 425c33264e151578a269c9c0ab9e0fb1d616f518 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 10 Jan 2024 14:53:11 +0300 Subject: [PATCH 1079/2255] 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 --- .../net/wireless/marvell/mwifiex/debugfs.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) 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); From a8e5fefa91236fd0d51464bf8156d738f0dfab9d Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Mon, 15 Jan 2024 15:56:30 +0100 Subject: [PATCH 1080/2255] 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(-) 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; From 188045a85614433c8aa176f7899fcfb7c7183408 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:19 +0800 Subject: [PATCH 1081/2255] 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(-) 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) From 4f0beeefcce8ad1035d063a012db6cf510aa1ed1 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:20 +0800 Subject: [PATCH 1082/2255] 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(-) 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: From ab12a3bfbf775182dc86ef8f70eab487c5deb761 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:21 +0800 Subject: [PATCH 1083/2255] 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(-) 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) { From d79fa0a6d8c229435e48d239dc1f0a0f39235fc8 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:22 +0800 Subject: [PATCH 1084/2255] 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(-) 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; }; From 1ae9fbaf22ee82bb3ed47ac12ea92dbb7c51769f Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:23 +0800 Subject: [PATCH 1085/2255] 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(-) 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); From 162bf67f74c71d56889c1c938d7901cfb76e2cbd Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:24 +0800 Subject: [PATCH 1086/2255] 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(+) 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); } From c08a986344a5eb80ae3651f33d0f386cd9e97252 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Wed, 7 Feb 2024 05:07:42 +0000 Subject: [PATCH 1087/2255] 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(-) 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, From 14ddc470ba22057f7734245a6a521d764f8a7fbe Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 7 Feb 2024 02:30:33 -0800 Subject: [PATCH 1088/2255] 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(-) 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) From f20073f50dfd1e1232e44834c74db718ffd2149b Mon Sep 17 00:00:00 2001 From: Alexey Berezhok Date: Thu, 8 Feb 2024 11:51:21 +0300 Subject: [PATCH 1089/2255] 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(-) 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; From db84b758541f0925a5c8263ea0af1656fe38412f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:19 +0800 Subject: [PATCH 1090/2255] 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(-) 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, From e10cd2ddd89e8b3e61b49247067e79f7debec2f1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:20 +0800 Subject: [PATCH 1091/2255] 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(-) 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; From b6e65d18bc2e124d8ac017ad26ace0f5852fe51d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:21 +0800 Subject: [PATCH 1092/2255] 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(-) 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) From b204d2475266ad4b917419bd8c3d5cc1f75111b8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:22 +0800 Subject: [PATCH 1093/2255] 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(-) 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); From fecf6b57fbc7560ee5f6e9771ac1f2653e4cc49d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:23 +0800 Subject: [PATCH 1094/2255] 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(+) 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; } From 505b57d08f72dc67c97bf743bb33ca5c95755def Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:24 +0800 Subject: [PATCH 1095/2255] 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(+) 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) From 49ea98235ada68ee1e2cad660bbb2e8e2cd87670 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 9 Feb 2024 14:52:25 +0800 Subject: [PATCH 1096/2255] 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(-) 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, From ef95df598622a399b62b69b764682c21543b1d63 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:26 +0800 Subject: [PATCH 1097/2255] 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(-) 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); } } From 598481c6eb20b29088caa0c69085904b2ca08674 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Fri, 9 Feb 2024 14:52:27 +0800 Subject: [PATCH 1098/2255] 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(-) 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) From 5f9c264f8e0904729edb861eafbec081299237eb Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 9 Feb 2024 14:52:28 +0800 Subject: [PATCH 1099/2255] 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(-) 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, From 4ae8ac201ddb1665ad3ef96d583f73ad51415ab7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:29 +0800 Subject: [PATCH 1100/2255] 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(-) 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, From fec846fa7eddf7bb651bf88bd78c7db1410ae3b1 Mon Sep 17 00:00:00 2001 From: Nicolas Maier Date: Sat, 20 Jan 2024 09:10:18 +0100 Subject: [PATCH 1101/2255] can: bcm: add recvmsg flags for own, local and remote traffic CAN RAW sockets allow userspace to tell if a received CAN frame comes from the same socket, another socket on the same host, or another host. See commit 1e55659ce6dd ("can-raw: add msg_flags to distinguish local traffic"). However, this feature is missing in CAN BCM sockets. Add the same feature to CAN BCM sockets. When reading a received frame (opcode RX_CHANGED) using recvmsg, two flags in msg->msg_flags may be set following the previous convention (from CAN RAW), to distinguish between 'own', 'local' and 'remote' CAN traffic. Update the documentation to reflect this change. Signed-off-by: Nicolas Maier Signed-off-by: Oliver Hartkopp Link: https://lore.kernel.org/all/20240120081018.2319-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde --- Documentation/networking/can.rst | 34 ++++++++-------- net/can/bcm.c | 69 ++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 28 deletions(-) diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst index d7e1ada905b2..62519d38c58b 100644 --- a/Documentation/networking/can.rst +++ b/Documentation/networking/can.rst @@ -444,6 +444,24 @@ definitions are specified for CAN specific MTUs in include/linux/can.h: #define CANFD_MTU (sizeof(struct canfd_frame)) == 72 => CAN FD frame +Returned Message Flags +---------------------- + +When using the system call recvmsg(2) on a RAW or a BCM socket, the +msg->msg_flags field may contain the following flags: + +MSG_DONTROUTE: + set when the received frame was created on the local host. + +MSG_CONFIRM: + set when the frame was sent via the socket it is received on. + This flag can be interpreted as a 'transmission confirmation' when the + CAN driver supports the echo of frames on driver level, see + :ref:`socketcan-local-loopback1` and :ref:`socketcan-local-loopback2`. + (Note: In order to receive such messages on a RAW socket, + CAN_RAW_RECV_OWN_MSGS must be set.) + + .. _socketcan-raw-sockets: RAW Protocol Sockets with can_filters (SOCK_RAW) @@ -693,22 +711,6 @@ where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or CAN ID ranges from the incoming traffic. -RAW Socket Returned Message Flags -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When using recvmsg() call, the msg->msg_flags may contain following flags: - -MSG_DONTROUTE: - set when the received frame was created on the local host. - -MSG_CONFIRM: - set when the frame was sent via the socket it is received on. - This flag can be interpreted as a 'transmission confirmation' when the - CAN driver supports the echo of frames on driver level, see - :ref:`socketcan-local-loopback1` and :ref:`socketcan-local-loopback2`. - In order to receive such messages, CAN_RAW_RECV_OWN_MSGS must be set. - - Broadcast Manager Protocol Sockets (SOCK_DGRAM) ----------------------------------------------- diff --git a/net/can/bcm.c b/net/can/bcm.c index 9168114fc87f..27d5fcf0eac9 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -72,9 +72,11 @@ #define BCM_TIMER_SEC_MAX (400 * 24 * 60 * 60) /* use of last_frames[index].flags */ +#define RX_LOCAL 0x10 /* frame was created on the local host */ +#define RX_OWN 0x20 /* frame was sent via the socket it was received on */ #define RX_RECV 0x40 /* received data for this element */ #define RX_THR 0x80 /* element not been sent due to throttle feature */ -#define BCM_CAN_FLAGS_MASK 0x3F /* to clean private flags after usage */ +#define BCM_CAN_FLAGS_MASK 0x0F /* to clean private flags after usage */ /* get best masking value for can_rx_register() for a given single can_id */ #define REGMASK(id) ((id & CAN_EFF_FLAG) ? \ @@ -138,6 +140,16 @@ static LIST_HEAD(bcm_notifier_list); static DEFINE_SPINLOCK(bcm_notifier_lock); static struct bcm_sock *bcm_busy_notifier; +/* Return pointer to store the extra msg flags for bcm_recvmsg(). + * We use the space of one unsigned int beyond the 'struct sockaddr_can' + * in skb->cb. + */ +static inline unsigned int *bcm_flags(struct sk_buff *skb) +{ + /* return pointer after struct sockaddr_can */ + return (unsigned int *)(&((struct sockaddr_can *)skb->cb)[1]); +} + static inline struct bcm_sock *bcm_sk(const struct sock *sk) { return (struct bcm_sock *)sk; @@ -325,6 +337,7 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, struct sock *sk = op->sk; unsigned int datalen = head->nframes * op->cfsiz; int err; + unsigned int *pflags; skb = alloc_skb(sizeof(*head) + datalen, gfp_any()); if (!skb) @@ -332,6 +345,14 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, skb_put_data(skb, head, sizeof(*head)); + /* ensure space for sockaddr_can and msg flags */ + sock_skb_cb_check_size(sizeof(struct sockaddr_can) + + sizeof(unsigned int)); + + /* initialize msg flags */ + pflags = bcm_flags(skb); + *pflags = 0; + if (head->nframes) { /* CAN frames starting here */ firstframe = (struct canfd_frame *)skb_tail_pointer(skb); @@ -344,8 +365,14 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, * relevant for updates that are generated by the * BCM, where nframes is 1 */ - if (head->nframes == 1) + if (head->nframes == 1) { + if (firstframe->flags & RX_LOCAL) + *pflags |= MSG_DONTROUTE; + if (firstframe->flags & RX_OWN) + *pflags |= MSG_CONFIRM; + firstframe->flags &= BCM_CAN_FLAGS_MASK; + } } if (has_timestamp) { @@ -360,7 +387,6 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, * containing the interface index. */ - sock_skb_cb_check_size(sizeof(struct sockaddr_can)); addr = (struct sockaddr_can *)skb->cb; memset(addr, 0, sizeof(*addr)); addr->can_family = AF_CAN; @@ -444,7 +470,7 @@ static void bcm_rx_changed(struct bcm_op *op, struct canfd_frame *data) op->frames_filtered = op->frames_abs = 0; /* this element is not throttled anymore */ - data->flags &= (BCM_CAN_FLAGS_MASK|RX_RECV); + data->flags &= ~RX_THR; memset(&head, 0, sizeof(head)); head.opcode = RX_CHANGED; @@ -465,13 +491,17 @@ static void bcm_rx_changed(struct bcm_op *op, struct canfd_frame *data) */ static void bcm_rx_update_and_send(struct bcm_op *op, struct canfd_frame *lastdata, - const struct canfd_frame *rxdata) + const struct canfd_frame *rxdata, + unsigned char traffic_flags) { memcpy(lastdata, rxdata, op->cfsiz); /* mark as used and throttled by default */ lastdata->flags |= (RX_RECV|RX_THR); + /* add own/local/remote traffic flags */ + lastdata->flags |= traffic_flags; + /* throttling mode inactive ? */ if (!op->kt_ival2) { /* send RX_CHANGED to the user immediately */ @@ -508,7 +538,8 @@ rx_changed_settime: * received data stored in op->last_frames[] */ static void bcm_rx_cmp_to_index(struct bcm_op *op, unsigned int index, - const struct canfd_frame *rxdata) + const struct canfd_frame *rxdata, + unsigned char traffic_flags) { struct canfd_frame *cf = op->frames + op->cfsiz * index; struct canfd_frame *lcf = op->last_frames + op->cfsiz * index; @@ -521,7 +552,7 @@ static void bcm_rx_cmp_to_index(struct bcm_op *op, unsigned int index, if (!(lcf->flags & RX_RECV)) { /* received data for the first time => send update to user */ - bcm_rx_update_and_send(op, lcf, rxdata); + bcm_rx_update_and_send(op, lcf, rxdata, traffic_flags); return; } @@ -529,7 +560,7 @@ static void bcm_rx_cmp_to_index(struct bcm_op *op, unsigned int index, for (i = 0; i < rxdata->len; i += 8) { if ((get_u64(cf, i) & get_u64(rxdata, i)) != (get_u64(cf, i) & get_u64(lcf, i))) { - bcm_rx_update_and_send(op, lcf, rxdata); + bcm_rx_update_and_send(op, lcf, rxdata, traffic_flags); return; } } @@ -537,7 +568,7 @@ static void bcm_rx_cmp_to_index(struct bcm_op *op, unsigned int index, if (op->flags & RX_CHECK_DLC) { /* do a real check in CAN frame length */ if (rxdata->len != lcf->len) { - bcm_rx_update_and_send(op, lcf, rxdata); + bcm_rx_update_and_send(op, lcf, rxdata, traffic_flags); return; } } @@ -644,6 +675,7 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data) struct bcm_op *op = (struct bcm_op *)data; const struct canfd_frame *rxframe = (struct canfd_frame *)skb->data; unsigned int i; + unsigned char traffic_flags; if (op->can_id != rxframe->can_id) return; @@ -673,15 +705,24 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data) return; } + /* compute flags to distinguish between own/local/remote CAN traffic */ + traffic_flags = 0; + if (skb->sk) { + traffic_flags |= RX_LOCAL; + if (skb->sk == op->sk) + traffic_flags |= RX_OWN; + } + if (op->flags & RX_FILTER_ID) { /* the easiest case */ - bcm_rx_update_and_send(op, op->last_frames, rxframe); + bcm_rx_update_and_send(op, op->last_frames, rxframe, + traffic_flags); goto rx_starttimer; } if (op->nframes == 1) { /* simple compare with index 0 */ - bcm_rx_cmp_to_index(op, 0, rxframe); + bcm_rx_cmp_to_index(op, 0, rxframe, traffic_flags); goto rx_starttimer; } @@ -698,7 +739,8 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data) if ((get_u64(op->frames, 0) & get_u64(rxframe, 0)) == (get_u64(op->frames, 0) & get_u64(op->frames + op->cfsiz * i, 0))) { - bcm_rx_cmp_to_index(op, i, rxframe); + bcm_rx_cmp_to_index(op, i, rxframe, + traffic_flags); break; } } @@ -1675,6 +1717,9 @@ static int bcm_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, memcpy(msg->msg_name, skb->cb, msg->msg_namelen); } + /* assign the flags that have been recorded in bcm_send_to_user() */ + msg->msg_flags |= *(bcm_flags(skb)); + skb_free_datagram(sk, skb); return size; From e1aa35e16399d600215470411dfb56e1d6f8e017 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 8 Dec 2023 17:57:29 +0100 Subject: [PATCH 1102/2255] can: isotp: support dynamic flow control parameters The ISO15765-2 standard supports to take the PDUs communication parameters blocksize (BS) and Separation Time minimum (STmin) either from the first received flow control (FC) "static" or from every received FC "dynamic". Add a new CAN_ISOTP_DYN_FC_PARMS flag to support dynamic FC parameters. Signed-off-by: Oliver Hartkopp Link: https://lore.kernel.org/all/20231208165729.3011-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde --- include/uapi/linux/can/isotp.h | 1 + net/can/isotp.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/can/isotp.h b/include/uapi/linux/can/isotp.h index 439c982f7e81..6cde62371b6f 100644 --- a/include/uapi/linux/can/isotp.h +++ b/include/uapi/linux/can/isotp.h @@ -137,6 +137,7 @@ struct can_isotp_ll_options { #define CAN_ISOTP_WAIT_TX_DONE 0x0400 /* wait for tx completion */ #define CAN_ISOTP_SF_BROADCAST 0x0800 /* 1-to-N functional addressing */ #define CAN_ISOTP_CF_BROADCAST 0x1000 /* 1-to-N transmission w/o FC */ +#define CAN_ISOTP_DYN_FC_PARMS 0x2000 /* dynamic FC parameters BS/STmin */ /* protocol machine default values */ diff --git a/net/can/isotp.c b/net/can/isotp.c index d1c6f206f429..25bac0fafc83 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -381,8 +381,9 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae) return 1; } - /* get communication parameters only from the first FC frame */ - if (so->tx.state == ISOTP_WAIT_FIRST_FC) { + /* get static/dynamic communication params from first/every FC frame */ + if (so->tx.state == ISOTP_WAIT_FIRST_FC || + so->opt.flags & CAN_ISOTP_DYN_FC_PARMS) { so->txfc.bs = cf->data[ae + 1]; so->txfc.stmin = cf->data[ae + 2]; From 4dcd08b9676aa43782fbfa34d6a9d4e23e89ea26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=A4tje?= Date: Wed, 22 Nov 2023 17:02:10 +0100 Subject: [PATCH 1103/2255] =?UTF-8?q?MAINTAINERS:=20add=20Stefan=20M=C3=A4?= =?UTF-8?q?tje=20as=20maintainer=20for=20the=20esd=20electronics=20GmbH=20?= =?UTF-8?q?PCIe/402=20CAN=20drivers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding myself (Stefan Mätje) as a maintainer for the upcoming driver of the PCIe/402 interface card family. Signed-off-by: Stefan Mätje Link: https://lore.kernel.org/all/20231122160211.2110448-2-stefan.maetje@esd.eu Signed-off-by: Marc Kleine-Budde --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 83e20516ebff..7f3e554671c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7887,6 +7887,13 @@ S: Maintained F: include/linux/errseq.h F: lib/errseq.c +ESD CAN NETWORK DRIVERS +M: Stefan Mätje +R: socketcan@esd.eu +L: linux-can@vger.kernel.org +S: Maintained +F: drivers/net/can/esd/ + ESD CAN/USB DRIVERS M: Frank Jungclaus R: socketcan@esd.eu From 9721866f07e108f892c15ae0c03059e5221b5594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=A4tje?= Date: Wed, 22 Nov 2023 17:02:11 +0100 Subject: [PATCH 1104/2255] can: esd: add support for esd GmbH PCIe/402 CAN interface family MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the PCI based PCIe/402 CAN interface family from esd GmbH that is available with various form factors (https://esd.eu/en/products/402-series-can-interfaces). All boards utilize a FPGA based CAN controller solution developed by esd (esdACC). For more information on the esdACC see https://esd.eu/en/products/esdacc. This driver detects all available CAN interface board variants of the family but atm. operates the CAN-FD capable devices in Classic-CAN mode only! A later patch will introduce the CAN-FD functionality in this driver. Co-developed-by: Thomas Körper Signed-off-by: Thomas Körper Signed-off-by: Stefan Mätje Link: https://lore.kernel.org/all/20231122160211.2110448-3-stefan.maetje@esd.eu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/Kconfig | 1 + drivers/net/can/Makefile | 1 + drivers/net/can/esd/Kconfig | 12 + drivers/net/can/esd/Makefile | 7 + drivers/net/can/esd/esd_402_pci-core.c | 514 +++++++++++++++++ drivers/net/can/esd/esdacc.c | 764 +++++++++++++++++++++++++ drivers/net/can/esd/esdacc.h | 356 ++++++++++++ 7 files changed, 1655 insertions(+) create mode 100644 drivers/net/can/esd/Kconfig create mode 100644 drivers/net/can/esd/Makefile create mode 100644 drivers/net/can/esd/esd_402_pci-core.c create mode 100644 drivers/net/can/esd/esdacc.c create mode 100644 drivers/net/can/esd/esdacc.h diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index eb410714afc2..2da126f13641 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -218,6 +218,7 @@ config CAN_XILINXCAN source "drivers/net/can/c_can/Kconfig" source "drivers/net/can/cc770/Kconfig" source "drivers/net/can/ctucanfd/Kconfig" +source "drivers/net/can/esd/Kconfig" source "drivers/net/can/ifi_canfd/Kconfig" source "drivers/net/can/m_can/Kconfig" source "drivers/net/can/mscan/Kconfig" diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index ff8f76295d13..4669cd51e7bf 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CAN_VXCAN) += vxcan.o obj-$(CONFIG_CAN_SLCAN) += slcan/ obj-y += dev/ +obj-y += esd/ obj-y += rcar/ obj-y += spi/ obj-y += usb/ diff --git a/drivers/net/can/esd/Kconfig b/drivers/net/can/esd/Kconfig new file mode 100644 index 000000000000..54bfc366634c --- /dev/null +++ b/drivers/net/can/esd/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +config CAN_ESD_402_PCI + tristate "esd electronics gmbh CAN-PCI(e)/402 family" + depends on PCI && HAS_DMA + help + Support for C402 card family from esd electronics gmbh. + This card family is based on the ESDACC CAN controller and + available in several form factors: PCI, PCIe, PCIe Mini, + M.2 PCIe, CPCIserial, PMC, XMC (see https://esd.eu/en) + + This driver can also be built as a module. In this case the + module will be called esd_402_pci. diff --git a/drivers/net/can/esd/Makefile b/drivers/net/can/esd/Makefile new file mode 100644 index 000000000000..5dd2d470c286 --- /dev/null +++ b/drivers/net/can/esd/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for esd gmbh ESDACC controller driver +# +esd_402_pci-objs := esdacc.o esd_402_pci-core.o + +obj-$(CONFIG_CAN_ESD_402_PCI) += esd_402_pci.o diff --git a/drivers/net/can/esd/esd_402_pci-core.c b/drivers/net/can/esd/esd_402_pci-core.c new file mode 100644 index 000000000000..b7cdcffd0e45 --- /dev/null +++ b/drivers/net/can/esd/esd_402_pci-core.c @@ -0,0 +1,514 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh + * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "esdacc.h" + +#define ESD_PCI_DEVICE_ID_PCIE402 0x0402 + +#define PCI402_FPGA_VER_MIN 0x003d +#define PCI402_MAX_CORES 6 +#define PCI402_BAR 0 +#define PCI402_IO_OV_OFFS 0 +#define PCI402_IO_PCIEP_OFFS 0x10000 +#define PCI402_IO_LEN_TOTAL 0x20000 +#define PCI402_IO_LEN_CORE 0x2000 +#define PCI402_PCICFG_MSICAP 0x50 + +#define PCI402_DMA_MASK DMA_BIT_MASK(32) +#define PCI402_DMA_SIZE ALIGN(0x10000, PAGE_SIZE) + +#define PCI402_PCIEP_OF_INT_ENABLE 0x0050 +#define PCI402_PCIEP_OF_BM_ADDR_LO 0x1000 +#define PCI402_PCIEP_OF_BM_ADDR_HI 0x1004 +#define PCI402_PCIEP_OF_MSI_ADDR_LO 0x1008 +#define PCI402_PCIEP_OF_MSI_ADDR_HI 0x100c + +struct pci402_card { + /* Actually mapped io space, all other iomem derived from this */ + void __iomem *addr; + void __iomem *addr_pciep; + + void *dma_buf; + dma_addr_t dma_hnd; + + struct acc_ov ov; + struct acc_core *cores; + + bool msi_enabled; +}; + +/* The BTR register capabilities described by the can_bittiming_const structures + * below are valid since esdACC version 0x0032. + */ + +/* Used if the esdACC FPGA is built as CAN-Classic version. */ +static const struct can_bittiming_const pci402_bittiming_const = { + .name = "esd_402", + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 512, + .brp_inc = 1, +}; + +/* Used if the esdACC FPGA is built as CAN-FD version. */ +static const struct can_bittiming_const pci402_bittiming_const_canfd = { + .name = "esd_402fd", + .tseg1_min = 1, + .tseg1_max = 256, + .tseg2_min = 1, + .tseg2_max = 128, + .sjw_max = 128, + .brp_min = 1, + .brp_max = 256, + .brp_inc = 1, +}; + +static const struct net_device_ops pci402_acc_netdev_ops = { + .ndo_open = acc_open, + .ndo_stop = acc_close, + .ndo_start_xmit = acc_start_xmit, + .ndo_change_mtu = can_change_mtu, + .ndo_eth_ioctl = can_eth_ioctl_hwts, +}; + +static const struct ethtool_ops pci402_acc_ethtool_ops = { + .get_ts_info = can_ethtool_op_get_ts_info_hwts, +}; + +static irqreturn_t pci402_interrupt(int irq, void *dev_id) +{ + struct pci_dev *pdev = dev_id; + struct pci402_card *card = pci_get_drvdata(pdev); + irqreturn_t irq_status; + + irq_status = acc_card_interrupt(&card->ov, card->cores); + + return irq_status; +} + +static int pci402_set_msiconfig(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + u32 addr_lo_offs = 0; + u32 addr_lo = 0; + u32 addr_hi = 0; + u32 data = 0; + u16 csr = 0; + int err; + + /* The FPGA hard IP PCIe core implements a 64-bit MSI Capability + * Register Format + */ + err = pci_read_config_word(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_FLAGS, &csr); + if (err) + goto failed; + + err = pci_read_config_dword(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_ADDRESS_LO, + &addr_lo); + if (err) + goto failed; + err = pci_read_config_dword(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_ADDRESS_HI, + &addr_hi); + if (err) + goto failed; + + err = pci_read_config_dword(pdev, PCI402_PCICFG_MSICAP + PCI_MSI_DATA_64, + &data); + if (err) + goto failed; + + addr_lo_offs = addr_lo & 0x0000ffff; + addr_lo &= 0xffff0000; + + if (addr_hi) + addr_lo |= 1; /* To enable 64-Bit addressing in PCIe endpoint */ + + if (!(csr & PCI_MSI_FLAGS_ENABLE)) { + err = -EINVAL; + goto failed; + } + + iowrite32(addr_lo, card->addr_pciep + PCI402_PCIEP_OF_MSI_ADDR_LO); + iowrite32(addr_hi, card->addr_pciep + PCI402_PCIEP_OF_MSI_ADDR_HI); + acc_ov_write32(&card->ov, ACC_OV_OF_MSI_ADDRESSOFFSET, addr_lo_offs); + acc_ov_write32(&card->ov, ACC_OV_OF_MSI_DATA, data); + + return 0; + +failed: + pci_warn(pdev, "Error while setting MSI configuration:\n" + "CSR: 0x%.4x, addr: 0x%.8x%.8x, offs: 0x%.4x, data: 0x%.8x\n", + csr, addr_hi, addr_lo, addr_lo_offs, data); + + return err; +} + +static int pci402_init_card(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + + card->ov.addr = card->addr + PCI402_IO_OV_OFFS; + card->addr_pciep = card->addr + PCI402_IO_PCIEP_OFFS; + + acc_reset_fpga(&card->ov); + acc_init_ov(&card->ov, &pdev->dev); + + if (card->ov.version < PCI402_FPGA_VER_MIN) { + pci_err(pdev, + "esdACC version (0x%.4x) outdated, please update\n", + card->ov.version); + return -EINVAL; + } + + if (card->ov.timestamp_frequency != ACC_TS_FREQ_80MHZ) { + pci_err(pdev, + "esdACC timestamp frequency of %uHz not supported by driver. Aborted.\n", + card->ov.timestamp_frequency); + return -EINVAL; + } + + if (card->ov.active_cores > PCI402_MAX_CORES) { + pci_err(pdev, + "Card with %u active cores not supported by driver. Aborted.\n", + card->ov.active_cores); + return -EINVAL; + } + card->cores = devm_kcalloc(&pdev->dev, card->ov.active_cores, + sizeof(struct acc_core), GFP_KERNEL); + if (!card->cores) + return -ENOMEM; + + if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD) { + pci_warn(pdev, + "esdACC with CAN-FD feature detected. This driver doesn't support CAN-FD yet.\n"); + } + +#ifdef __LITTLE_ENDIAN + /* So card converts all busmastered data to LE for us: */ + acc_ov_set_bits(&card->ov, ACC_OV_OF_MODE, + ACC_OV_REG_MODE_MASK_ENDIAN_LITTLE); +#endif + + return 0; +} + +static int pci402_init_interrupt(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + int err; + + err = pci_enable_msi(pdev); + if (!err) { + err = pci402_set_msiconfig(pdev); + if (!err) { + card->msi_enabled = true; + acc_ov_set_bits(&card->ov, ACC_OV_OF_MODE, + ACC_OV_REG_MODE_MASK_MSI_ENABLE); + pci_dbg(pdev, "MSI preparation done\n"); + } + } + + err = devm_request_irq(&pdev->dev, pdev->irq, pci402_interrupt, + IRQF_SHARED, dev_name(&pdev->dev), pdev); + if (err) + goto failure_msidis; + + iowrite32(1, card->addr_pciep + PCI402_PCIEP_OF_INT_ENABLE); + + return 0; + +failure_msidis: + if (card->msi_enabled) { + acc_ov_clear_bits(&card->ov, ACC_OV_OF_MODE, + ACC_OV_REG_MODE_MASK_MSI_ENABLE); + pci_disable_msi(pdev); + card->msi_enabled = false; + } + + return err; +} + +static void pci402_finish_interrupt(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + + iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_INT_ENABLE); + devm_free_irq(&pdev->dev, pdev->irq, pdev); + + if (card->msi_enabled) { + acc_ov_clear_bits(&card->ov, ACC_OV_OF_MODE, + ACC_OV_REG_MODE_MASK_MSI_ENABLE); + pci_disable_msi(pdev); + card->msi_enabled = false; + } +} + +static int pci402_init_dma(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + int err; + + err = dma_set_coherent_mask(&pdev->dev, PCI402_DMA_MASK); + if (err) { + pci_err(pdev, "DMA set mask failed!\n"); + return err; + } + + /* The esdACC DMA engine needs the DMA buffer aligned to a 64k + * boundary. The DMA API guarantees to align the returned buffer to the + * smallest PAGE_SIZE order which is greater than or equal to the + * requested size. With PCI402_DMA_SIZE == 64kB this suffices here. + */ + card->dma_buf = dma_alloc_coherent(&pdev->dev, PCI402_DMA_SIZE, + &card->dma_hnd, GFP_KERNEL); + if (!card->dma_buf) + return -ENOMEM; + + acc_init_bm_ptr(&card->ov, card->cores, card->dma_buf); + + iowrite32(card->dma_hnd, + card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_LO); + iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_HI); + + pci_set_master(pdev); + + acc_ov_set_bits(&card->ov, ACC_OV_OF_MODE, + ACC_OV_REG_MODE_MASK_BM_ENABLE); + + return 0; +} + +static void pci402_finish_dma(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + int i; + + acc_ov_clear_bits(&card->ov, ACC_OV_OF_MODE, + ACC_OV_REG_MODE_MASK_BM_ENABLE); + + pci_clear_master(pdev); + + iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_LO); + iowrite32(0, card->addr_pciep + PCI402_PCIEP_OF_BM_ADDR_HI); + + card->ov.bmfifo.messages = NULL; + card->ov.bmfifo.irq_cnt = NULL; + for (i = 0; i < card->ov.active_cores; i++) { + struct acc_core *core = &card->cores[i]; + + core->bmfifo.messages = NULL; + core->bmfifo.irq_cnt = NULL; + } + + dma_free_coherent(&pdev->dev, PCI402_DMA_SIZE, card->dma_buf, + card->dma_hnd); + card->dma_buf = NULL; +} + +static void pci402_unregister_core(struct acc_core *core) +{ + netdev_info(core->netdev, "unregister\n"); + unregister_candev(core->netdev); + + free_candev(core->netdev); + core->netdev = NULL; +} + +static int pci402_init_cores(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + int err; + int i; + + for (i = 0; i < card->ov.active_cores; i++) { + struct acc_core *core = &card->cores[i]; + struct acc_net_priv *priv; + struct net_device *netdev; + u32 fifo_config; + + core->addr = card->ov.addr + (i + 1) * PCI402_IO_LEN_CORE; + + fifo_config = acc_read32(core, ACC_CORE_OF_TXFIFO_CONFIG); + core->tx_fifo_size = (fifo_config >> 24); + if (core->tx_fifo_size <= 1) { + pci_err(pdev, "Invalid tx_fifo_size!\n"); + err = -EINVAL; + goto failure; + } + + netdev = alloc_candev(sizeof(*priv), core->tx_fifo_size); + if (!netdev) { + err = -ENOMEM; + goto failure; + } + core->netdev = netdev; + + netdev->flags |= IFF_ECHO; + netdev->dev_port = i; + netdev->netdev_ops = &pci402_acc_netdev_ops; + netdev->ethtool_ops = &pci402_acc_ethtool_ops; + SET_NETDEV_DEV(netdev, &pdev->dev); + + priv = netdev_priv(netdev); + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_CC_LEN8_DLC; + + priv->can.clock.freq = card->ov.core_frequency; + if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD) + priv->can.bittiming_const = &pci402_bittiming_const_canfd; + else + priv->can.bittiming_const = &pci402_bittiming_const; + priv->can.do_set_bittiming = acc_set_bittiming; + priv->can.do_set_mode = acc_set_mode; + priv->can.do_get_berr_counter = acc_get_berr_counter; + + priv->core = core; + priv->ov = &card->ov; + + err = register_candev(netdev); + if (err) { + free_candev(core->netdev); + core->netdev = NULL; + goto failure; + } + + netdev_info(netdev, "registered\n"); + } + + return 0; + +failure: + for (i--; i >= 0; i--) + pci402_unregister_core(&card->cores[i]); + + return err; +} + +static void pci402_finish_cores(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + int i; + + for (i = 0; i < card->ov.active_cores; i++) + pci402_unregister_core(&card->cores[i]); +} + +static int pci402_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct pci402_card *card = NULL; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL); + if (!card) { + err = -ENOMEM; + goto failure_disable_pci; + } + + pci_set_drvdata(pdev, card); + + err = pci_request_regions(pdev, pci_name(pdev)); + if (err) + goto failure_disable_pci; + + card->addr = pci_iomap(pdev, PCI402_BAR, PCI402_IO_LEN_TOTAL); + if (!card->addr) { + err = -ENOMEM; + goto failure_release_regions; + } + + err = pci402_init_card(pdev); + if (err) + goto failure_unmap; + + err = pci402_init_dma(pdev); + if (err) + goto failure_unmap; + + err = pci402_init_interrupt(pdev); + if (err) + goto failure_finish_dma; + + err = pci402_init_cores(pdev); + if (err) + goto failure_finish_interrupt; + + return 0; + +failure_finish_interrupt: + pci402_finish_interrupt(pdev); + +failure_finish_dma: + pci402_finish_dma(pdev); + +failure_unmap: + pci_iounmap(pdev, card->addr); + +failure_release_regions: + pci_release_regions(pdev); + +failure_disable_pci: + pci_disable_device(pdev); + + return err; +} + +static void pci402_remove(struct pci_dev *pdev) +{ + struct pci402_card *card = pci_get_drvdata(pdev); + + pci402_finish_interrupt(pdev); + pci402_finish_cores(pdev); + pci402_finish_dma(pdev); + pci_iounmap(pdev, card->addr); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static const struct pci_device_id pci402_tbl[] = { + { + .vendor = PCI_VENDOR_ID_ESDGMBH, + .device = ESD_PCI_DEVICE_ID_PCIE402, + .subvendor = PCI_VENDOR_ID_ESDGMBH, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, pci402_tbl); + +static struct pci_driver pci402_driver = { + .name = KBUILD_MODNAME, + .id_table = pci402_tbl, + .probe = pci402_probe, + .remove = pci402_remove, +}; +module_pci_driver(pci402_driver); + +MODULE_DESCRIPTION("Socket-CAN driver for esd CAN 402 card family with esdACC core on PCIe"); +MODULE_AUTHOR("Thomas Körper "); +MODULE_AUTHOR("Stefan Mätje "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/can/esd/esdacc.c b/drivers/net/can/esd/esdacc.c new file mode 100644 index 000000000000..121cbbf81458 --- /dev/null +++ b/drivers/net/can/esd/esdacc.c @@ -0,0 +1,764 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh + * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh + */ + +#include "esdacc.h" + +#include +#include +#include +#include + +/* esdACC ID register layout */ +#define ACC_ID_ID_MASK GENMASK(28, 0) +#define ACC_ID_EFF_FLAG BIT(29) + +/* esdACC DLC register layout */ +#define ACC_DLC_DLC_MASK GENMASK(3, 0) +#define ACC_DLC_RTR_FLAG BIT(4) +#define ACC_DLC_TXD_FLAG BIT(5) + +/* ecc value of esdACC equals SJA1000's ECC register */ +#define ACC_ECC_SEG 0x1f +#define ACC_ECC_DIR 0x20 +#define ACC_ECC_BIT 0x00 +#define ACC_ECC_FORM 0x40 +#define ACC_ECC_STUFF 0x80 +#define ACC_ECC_MASK 0xc0 + +/* esdACC Status Register bits. Unused bits not documented. */ +#define ACC_REG_STATUS_MASK_STATUS_ES BIT(17) +#define ACC_REG_STATUS_MASK_STATUS_EP BIT(18) +#define ACC_REG_STATUS_MASK_STATUS_BS BIT(19) + +/* esdACC Overview Module BM_IRQ_Mask register related defines */ +/* Two bit wide command masks to mask or unmask a single core IRQ */ +#define ACC_BM_IRQ_UNMASK BIT(0) +#define ACC_BM_IRQ_MASK (ACC_BM_IRQ_UNMASK << 1) +/* Command to unmask all IRQ sources. Created by shifting + * and oring the two bit wide ACC_BM_IRQ_UNMASK 16 times. + */ +#define ACC_BM_IRQ_UNMASK_ALL 0x55555555U + +static void acc_resetmode_enter(struct acc_core *core) +{ + acc_set_bits(core, ACC_CORE_OF_CTRL_MODE, + ACC_REG_CONTROL_MASK_MODE_RESETMODE); + + /* Read back reset mode bit to flush PCI write posting */ + acc_resetmode_entered(core); +} + +static void acc_resetmode_leave(struct acc_core *core) +{ + acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE, + ACC_REG_CONTROL_MASK_MODE_RESETMODE); + + /* Read back reset mode bit to flush PCI write posting */ + acc_resetmode_entered(core); +} + +static void acc_txq_put(struct acc_core *core, u32 acc_id, u8 acc_dlc, + const void *data) +{ + acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1, + *((const u32 *)(data + 4))); + acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_0, + *((const u32 *)data)); + acc_write32(core, ACC_CORE_OF_TXFIFO_DLC, acc_dlc); + /* CAN id must be written at last. This write starts TX. */ + acc_write32(core, ACC_CORE_OF_TXFIFO_ID, acc_id); +} + +static u8 acc_tx_fifo_next(struct acc_core *core, u8 tx_fifo_idx) +{ + ++tx_fifo_idx; + if (tx_fifo_idx >= core->tx_fifo_size) + tx_fifo_idx = 0U; + return tx_fifo_idx; +} + +/* Convert timestamp from esdACC time stamp ticks to ns + * + * The conversion factor ts2ns from time stamp counts to ns is basically + * ts2ns = NSEC_PER_SEC / timestamp_frequency + * + * We handle here only a fixed timestamp frequency of 80MHz. The + * resulting ts2ns factor would be 12.5. + * + * At the end we multiply by 12 and add the half of the HW timestamp + * to get a multiplication by 12.5. This way any overflow is + * avoided until ktime_t itself overflows. + */ +#define ACC_TS_FACTOR (NSEC_PER_SEC / ACC_TS_FREQ_80MHZ) +#define ACC_TS_80MHZ_SHIFT 1 + +static ktime_t acc_ts2ktime(struct acc_ov *ov, u64 ts) +{ + u64 ns; + + ns = (ts * ACC_TS_FACTOR) + (ts >> ACC_TS_80MHZ_SHIFT); + + return ns_to_ktime(ns); +} + +#undef ACC_TS_FACTOR +#undef ACC_TS_80MHZ_SHIFT + +void acc_init_ov(struct acc_ov *ov, struct device *dev) +{ + u32 temp; + + temp = acc_ov_read32(ov, ACC_OV_OF_VERSION); + ov->version = temp; + ov->features = (temp >> 16); + + temp = acc_ov_read32(ov, ACC_OV_OF_INFO); + ov->total_cores = temp; + ov->active_cores = (temp >> 8); + + ov->core_frequency = acc_ov_read32(ov, ACC_OV_OF_CANCORE_FREQ); + ov->timestamp_frequency = acc_ov_read32(ov, ACC_OV_OF_TS_FREQ_LO); + + /* Depending on esdACC feature NEW_PSC enable the new prescaler + * or adjust core_frequency according to the implicit division by 2. + */ + if (ov->features & ACC_OV_REG_FEAT_MASK_NEW_PSC) { + acc_ov_set_bits(ov, ACC_OV_OF_MODE, + ACC_OV_REG_MODE_MASK_NEW_PSC_ENABLE); + } else { + ov->core_frequency /= 2; + } + + dev_dbg(dev, + "esdACC v%u, freq: %u/%u, feat/strap: 0x%x/0x%x, cores: %u/%u\n", + ov->version, ov->core_frequency, ov->timestamp_frequency, + ov->features, acc_ov_read32(ov, ACC_OV_OF_INFO) >> 16, + ov->active_cores, ov->total_cores); +} + +void acc_init_bm_ptr(struct acc_ov *ov, struct acc_core *cores, const void *mem) +{ + unsigned int u; + + /* DMA buffer layout as follows where N is the number of CAN cores + * implemented in the FPGA, i.e. N = ov->total_cores + * + * Section Layout Section size + * ---------------------------------------------- + * FIFO Card/Overview ACC_CORE_DMABUF_SIZE + * FIFO Core0 ACC_CORE_DMABUF_SIZE + * ... ... + * FIFO CoreN ACC_CORE_DMABUF_SIZE + * irq_cnt Card/Overview sizeof(u32) + * irq_cnt Core0 sizeof(u32) + * ... ... + * irq_cnt CoreN sizeof(u32) + */ + ov->bmfifo.messages = mem; + ov->bmfifo.irq_cnt = mem + (ov->total_cores + 1U) * ACC_CORE_DMABUF_SIZE; + + for (u = 0U; u < ov->active_cores; u++) { + struct acc_core *core = &cores[u]; + + core->bmfifo.messages = mem + (u + 1U) * ACC_CORE_DMABUF_SIZE; + core->bmfifo.irq_cnt = ov->bmfifo.irq_cnt + (u + 1U); + } +} + +int acc_open(struct net_device *netdev) +{ + struct acc_net_priv *priv = netdev_priv(netdev); + struct acc_core *core = priv->core; + u32 tx_fifo_status; + u32 ctrl_mode; + int err; + + /* Retry to enter RESET mode if out of sync. */ + if (priv->can.state != CAN_STATE_STOPPED) { + netdev_warn(netdev, "Entered %s() with bad can.state: %s\n", + __func__, can_get_state_str(priv->can.state)); + acc_resetmode_enter(core); + priv->can.state = CAN_STATE_STOPPED; + } + + err = open_candev(netdev); + if (err) + return err; + + ctrl_mode = ACC_REG_CONTROL_MASK_IE_RXTX | + ACC_REG_CONTROL_MASK_IE_TXERROR | + ACC_REG_CONTROL_MASK_IE_ERRWARN | + ACC_REG_CONTROL_MASK_IE_OVERRUN | + ACC_REG_CONTROL_MASK_IE_ERRPASS; + + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + ctrl_mode |= ACC_REG_CONTROL_MASK_IE_BUSERR; + + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + ctrl_mode |= ACC_REG_CONTROL_MASK_MODE_LOM; + + acc_set_bits(core, ACC_CORE_OF_CTRL_MODE, ctrl_mode); + + acc_resetmode_leave(core); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + /* Resync TX FIFO indices to HW state after (re-)start. */ + tx_fifo_status = acc_read32(core, ACC_CORE_OF_TXFIFO_STATUS); + core->tx_fifo_head = tx_fifo_status & 0xff; + core->tx_fifo_tail = (tx_fifo_status >> 8) & 0xff; + + netif_start_queue(netdev); + return 0; +} + +int acc_close(struct net_device *netdev) +{ + struct acc_net_priv *priv = netdev_priv(netdev); + struct acc_core *core = priv->core; + + acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE, + ACC_REG_CONTROL_MASK_IE_RXTX | + ACC_REG_CONTROL_MASK_IE_TXERROR | + ACC_REG_CONTROL_MASK_IE_ERRWARN | + ACC_REG_CONTROL_MASK_IE_OVERRUN | + ACC_REG_CONTROL_MASK_IE_ERRPASS | + ACC_REG_CONTROL_MASK_IE_BUSERR); + + netif_stop_queue(netdev); + acc_resetmode_enter(core); + priv->can.state = CAN_STATE_STOPPED; + + /* Mark pending TX requests to be aborted after controller restart. */ + acc_write32(core, ACC_CORE_OF_TX_ABORT_MASK, 0xffff); + + /* ACC_REG_CONTROL_MASK_MODE_LOM is only accessible in RESET mode */ + acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE, + ACC_REG_CONTROL_MASK_MODE_LOM); + + close_candev(netdev); + return 0; +} + +netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct acc_net_priv *priv = netdev_priv(netdev); + struct acc_core *core = priv->core; + struct can_frame *cf = (struct can_frame *)skb->data; + u8 tx_fifo_head = core->tx_fifo_head; + int fifo_usage; + u32 acc_id; + u8 acc_dlc; + + if (can_dropped_invalid_skb(netdev, skb)) + return NETDEV_TX_OK; + + /* Access core->tx_fifo_tail only once because it may be changed + * from the interrupt level. + */ + fifo_usage = tx_fifo_head - core->tx_fifo_tail; + if (fifo_usage < 0) + fifo_usage += core->tx_fifo_size; + + if (fifo_usage >= core->tx_fifo_size - 1) { + netdev_err(core->netdev, + "BUG: TX ring full when queue awake!\n"); + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; + } + + if (fifo_usage == core->tx_fifo_size - 2) + netif_stop_queue(netdev); + + acc_dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); + if (cf->can_id & CAN_RTR_FLAG) + acc_dlc |= ACC_DLC_RTR_FLAG; + + if (cf->can_id & CAN_EFF_FLAG) { + acc_id = cf->can_id & CAN_EFF_MASK; + acc_id |= ACC_ID_EFF_FLAG; + } else { + acc_id = cf->can_id & CAN_SFF_MASK; + } + + can_put_echo_skb(skb, netdev, core->tx_fifo_head, 0); + + core->tx_fifo_head = acc_tx_fifo_next(core, tx_fifo_head); + + acc_txq_put(core, acc_id, acc_dlc, cf->data); + + return NETDEV_TX_OK; +} + +int acc_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec) +{ + struct acc_net_priv *priv = netdev_priv(netdev); + u32 core_status = acc_read32(priv->core, ACC_CORE_OF_STATUS); + + bec->txerr = (core_status >> 8) & 0xff; + bec->rxerr = core_status & 0xff; + + return 0; +} + +int acc_set_mode(struct net_device *netdev, enum can_mode mode) +{ + struct acc_net_priv *priv = netdev_priv(netdev); + + switch (mode) { + case CAN_MODE_START: + /* Paranoid FIFO index check. */ + { + const u32 tx_fifo_status = + acc_read32(priv->core, ACC_CORE_OF_TXFIFO_STATUS); + const u8 hw_fifo_head = tx_fifo_status; + + if (hw_fifo_head != priv->core->tx_fifo_head || + hw_fifo_head != priv->core->tx_fifo_tail) { + netdev_warn(netdev, + "TX FIFO mismatch: T %2u H %2u; TFHW %#08x\n", + priv->core->tx_fifo_tail, + priv->core->tx_fifo_head, + tx_fifo_status); + } + } + acc_resetmode_leave(priv->core); + /* To leave the bus-off state the esdACC controller begins + * here a grace period where it counts 128 "idle conditions" (each + * of 11 consecutive recessive bits) on the bus as required + * by the CAN spec. + * + * During this time the TX FIFO may still contain already + * aborted "zombie" frames that are only drained from the FIFO + * at the end of the grace period. + * + * To not to interfere with this drain process we don't + * call netif_wake_queue() here. When the controller reaches + * the error-active state again, it informs us about that + * with an acc_bmmsg_errstatechange message. Then + * netif_wake_queue() is called from + * handle_core_msg_errstatechange() instead. + */ + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +int acc_set_bittiming(struct net_device *netdev) +{ + struct acc_net_priv *priv = netdev_priv(netdev); + const struct can_bittiming *bt = &priv->can.bittiming; + u32 brp; + u32 btr; + + if (priv->ov->features & ACC_OV_REG_FEAT_MASK_CANFD) { + u32 fbtr = 0; + + netdev_dbg(netdev, "bit timing: brp %u, prop %u, ph1 %u ph2 %u, sjw %u\n", + bt->brp, bt->prop_seg, + bt->phase_seg1, bt->phase_seg2, bt->sjw); + + brp = FIELD_PREP(ACC_REG_BRP_FD_MASK_BRP, bt->brp - 1); + + btr = FIELD_PREP(ACC_REG_BTR_FD_MASK_TSEG1, bt->phase_seg1 + bt->prop_seg - 1); + btr |= FIELD_PREP(ACC_REG_BTR_FD_MASK_TSEG2, bt->phase_seg2 - 1); + btr |= FIELD_PREP(ACC_REG_BTR_FD_MASK_SJW, bt->sjw - 1); + + /* Keep order of accesses to ACC_CORE_OF_BRP and ACC_CORE_OF_BTR. */ + acc_write32(priv->core, ACC_CORE_OF_BRP, brp); + acc_write32(priv->core, ACC_CORE_OF_BTR, btr); + + netdev_dbg(netdev, "esdACC: BRP %u, NBTR 0x%08x, DBTR 0x%08x", + brp, btr, fbtr); + } else { + netdev_dbg(netdev, "bit timing: brp %u, prop %u, ph1 %u ph2 %u, sjw %u\n", + bt->brp, bt->prop_seg, + bt->phase_seg1, bt->phase_seg2, bt->sjw); + + brp = FIELD_PREP(ACC_REG_BRP_CL_MASK_BRP, bt->brp - 1); + + btr = FIELD_PREP(ACC_REG_BTR_CL_MASK_TSEG1, bt->phase_seg1 + bt->prop_seg - 1); + btr |= FIELD_PREP(ACC_REG_BTR_CL_MASK_TSEG2, bt->phase_seg2 - 1); + btr |= FIELD_PREP(ACC_REG_BTR_CL_MASK_SJW, bt->sjw - 1); + + /* Keep order of accesses to ACC_CORE_OF_BRP and ACC_CORE_OF_BTR. */ + acc_write32(priv->core, ACC_CORE_OF_BRP, brp); + acc_write32(priv->core, ACC_CORE_OF_BTR, btr); + + netdev_dbg(netdev, "esdACC: BRP %u, BTR 0x%08x", brp, btr); + } + + return 0; +} + +static void handle_core_msg_rxtxdone(struct acc_core *core, + const struct acc_bmmsg_rxtxdone *msg) +{ + struct acc_net_priv *priv = netdev_priv(core->netdev); + struct net_device_stats *stats = &core->netdev->stats; + struct sk_buff *skb; + + if (msg->acc_dlc.len & ACC_DLC_TXD_FLAG) { + u8 tx_fifo_tail = core->tx_fifo_tail; + + if (core->tx_fifo_head == tx_fifo_tail) { + netdev_warn(core->netdev, + "TX interrupt, but queue is empty!?\n"); + return; + } + + /* Direct access echo skb to attach HW time stamp. */ + skb = priv->can.echo_skb[tx_fifo_tail]; + if (skb) { + skb_hwtstamps(skb)->hwtstamp = + acc_ts2ktime(priv->ov, msg->ts); + } + + stats->tx_packets++; + stats->tx_bytes += can_get_echo_skb(core->netdev, tx_fifo_tail, + NULL); + + core->tx_fifo_tail = acc_tx_fifo_next(core, tx_fifo_tail); + + netif_wake_queue(core->netdev); + + } else { + struct can_frame *cf; + + skb = alloc_can_skb(core->netdev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + + cf->can_id = msg->id & ACC_ID_ID_MASK; + if (msg->id & ACC_ID_EFF_FLAG) + cf->can_id |= CAN_EFF_FLAG; + + can_frame_set_cc_len(cf, msg->acc_dlc.len & ACC_DLC_DLC_MASK, + priv->can.ctrlmode); + + if (msg->acc_dlc.len & ACC_DLC_RTR_FLAG) { + cf->can_id |= CAN_RTR_FLAG; + } else { + memcpy(cf->data, msg->data, cf->len); + stats->rx_bytes += cf->len; + } + stats->rx_packets++; + + skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts); + + netif_rx(skb); + } +} + +static void handle_core_msg_txabort(struct acc_core *core, + const struct acc_bmmsg_txabort *msg) +{ + struct net_device_stats *stats = &core->netdev->stats; + u8 tx_fifo_tail = core->tx_fifo_tail; + u32 abort_mask = msg->abort_mask; /* u32 extend to avoid warnings later */ + + /* The abort_mask shows which frames were aborted in esdACC's FIFO. */ + while (tx_fifo_tail != core->tx_fifo_head && (abort_mask)) { + const u32 tail_mask = (1U << tx_fifo_tail); + + if (!(abort_mask & tail_mask)) + break; + abort_mask &= ~tail_mask; + + can_free_echo_skb(core->netdev, tx_fifo_tail, NULL); + stats->tx_dropped++; + stats->tx_aborted_errors++; + + tx_fifo_tail = acc_tx_fifo_next(core, tx_fifo_tail); + } + core->tx_fifo_tail = tx_fifo_tail; + if (abort_mask) + netdev_warn(core->netdev, "Unhandled aborted messages\n"); + + if (!acc_resetmode_entered(core)) + netif_wake_queue(core->netdev); +} + +static void handle_core_msg_overrun(struct acc_core *core, + const struct acc_bmmsg_overrun *msg) +{ + struct acc_net_priv *priv = netdev_priv(core->netdev); + struct net_device_stats *stats = &core->netdev->stats; + struct can_frame *cf; + struct sk_buff *skb; + + /* lost_cnt may be 0 if not supported by esdACC version */ + if (msg->lost_cnt) { + stats->rx_errors += msg->lost_cnt; + stats->rx_over_errors += msg->lost_cnt; + } else { + stats->rx_errors++; + stats->rx_over_errors++; + } + + skb = alloc_can_err_skb(core->netdev, &cf); + if (!skb) + return; + + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + + skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts); + + netif_rx(skb); +} + +static void handle_core_msg_buserr(struct acc_core *core, + const struct acc_bmmsg_buserr *msg) +{ + struct acc_net_priv *priv = netdev_priv(core->netdev); + struct net_device_stats *stats = &core->netdev->stats; + struct can_frame *cf; + struct sk_buff *skb; + const u32 reg_status = msg->reg_status; + const u8 rxerr = reg_status; + const u8 txerr = (reg_status >> 8); + u8 can_err_prot_type = 0U; + + priv->can.can_stats.bus_error++; + + /* Error occurred during transmission? */ + if (msg->ecc & ACC_ECC_DIR) { + stats->rx_errors++; + } else { + can_err_prot_type |= CAN_ERR_PROT_TX; + stats->tx_errors++; + } + /* Determine error type */ + switch (msg->ecc & ACC_ECC_MASK) { + case ACC_ECC_BIT: + can_err_prot_type |= CAN_ERR_PROT_BIT; + break; + case ACC_ECC_FORM: + can_err_prot_type |= CAN_ERR_PROT_FORM; + break; + case ACC_ECC_STUFF: + can_err_prot_type |= CAN_ERR_PROT_STUFF; + break; + default: + can_err_prot_type |= CAN_ERR_PROT_UNSPEC; + break; + } + + skb = alloc_can_err_skb(core->netdev, &cf); + if (!skb) + return; + + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR | CAN_ERR_CNT; + + /* Set protocol error type */ + cf->data[2] = can_err_prot_type; + /* Set error location */ + cf->data[3] = msg->ecc & ACC_ECC_SEG; + + /* Insert CAN TX and RX error counters. */ + cf->data[6] = txerr; + cf->data[7] = rxerr; + + skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts); + + netif_rx(skb); +} + +static void +handle_core_msg_errstatechange(struct acc_core *core, + const struct acc_bmmsg_errstatechange *msg) +{ + struct acc_net_priv *priv = netdev_priv(core->netdev); + struct can_frame *cf = NULL; + struct sk_buff *skb; + const u32 reg_status = msg->reg_status; + const u8 rxerr = reg_status; + const u8 txerr = (reg_status >> 8); + enum can_state new_state; + + if (reg_status & ACC_REG_STATUS_MASK_STATUS_BS) { + new_state = CAN_STATE_BUS_OFF; + } else if (reg_status & ACC_REG_STATUS_MASK_STATUS_EP) { + new_state = CAN_STATE_ERROR_PASSIVE; + } else if (reg_status & ACC_REG_STATUS_MASK_STATUS_ES) { + new_state = CAN_STATE_ERROR_WARNING; + } else { + new_state = CAN_STATE_ERROR_ACTIVE; + if (priv->can.state == CAN_STATE_BUS_OFF) { + /* See comment in acc_set_mode() for CAN_MODE_START */ + netif_wake_queue(core->netdev); + } + } + + skb = alloc_can_err_skb(core->netdev, &cf); + + if (new_state != priv->can.state) { + enum can_state tx_state, rx_state; + + tx_state = (txerr >= rxerr) ? + new_state : CAN_STATE_ERROR_ACTIVE; + rx_state = (rxerr >= txerr) ? + new_state : CAN_STATE_ERROR_ACTIVE; + + /* Always call can_change_state() to update the state + * even if alloc_can_err_skb() may have failed. + * can_change_state() can cope with a NULL cf pointer. + */ + can_change_state(core->netdev, cf, tx_state, rx_state); + } + + if (skb) { + cf->can_id |= CAN_ERR_CNT; + cf->data[6] = txerr; + cf->data[7] = rxerr; + + skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts); + + netif_rx(skb); + } + + if (new_state == CAN_STATE_BUS_OFF) { + acc_write32(core, ACC_CORE_OF_TX_ABORT_MASK, 0xffff); + can_bus_off(core->netdev); + } +} + +static void handle_core_interrupt(struct acc_core *core) +{ + u32 msg_fifo_head = core->bmfifo.local_irq_cnt & 0xff; + + while (core->bmfifo.msg_fifo_tail != msg_fifo_head) { + const union acc_bmmsg *msg = + &core->bmfifo.messages[core->bmfifo.msg_fifo_tail]; + + switch (msg->msg_id) { + case BM_MSG_ID_RXTXDONE: + handle_core_msg_rxtxdone(core, &msg->rxtxdone); + break; + + case BM_MSG_ID_TXABORT: + handle_core_msg_txabort(core, &msg->txabort); + break; + + case BM_MSG_ID_OVERRUN: + handle_core_msg_overrun(core, &msg->overrun); + break; + + case BM_MSG_ID_BUSERR: + handle_core_msg_buserr(core, &msg->buserr); + break; + + case BM_MSG_ID_ERRPASSIVE: + case BM_MSG_ID_ERRWARN: + handle_core_msg_errstatechange(core, + &msg->errstatechange); + break; + + default: + /* Ignore all other BM messages (like the CAN-FD messages) */ + break; + } + + core->bmfifo.msg_fifo_tail = + (core->bmfifo.msg_fifo_tail + 1) & 0xff; + } +} + +/** + * acc_card_interrupt() - handle the interrupts of an esdACC FPGA + * + * @ov: overview module structure + * @cores: array of core structures + * + * This function handles all interrupts pending for the overview module and the + * CAN cores of the esdACC FPGA. + * + * It examines for all cores (the overview module core and the CAN cores) + * the bmfifo.irq_cnt and compares it with the previously saved + * bmfifo.local_irq_cnt. An IRQ is pending if they differ. The esdACC FPGA + * updates the bmfifo.irq_cnt values by DMA. + * + * The pending interrupts are masked by writing to the IRQ mask register at + * ACC_OV_OF_BM_IRQ_MASK. This register has for each core a two bit command + * field evaluated as follows: + * + * Define, bit pattern: meaning + * 00: no action + * ACC_BM_IRQ_UNMASK, 01: unmask interrupt + * ACC_BM_IRQ_MASK, 10: mask interrupt + * 11: no action + * + * For each CAN core with a pending IRQ handle_core_interrupt() handles all + * busmaster messages from the message FIFO. The last handled message (FIFO + * index) is written to the CAN core to acknowledge its handling. + * + * Last step is to unmask all interrupts in the FPGA using + * ACC_BM_IRQ_UNMASK_ALL. + * + * Return: + * IRQ_HANDLED, if card generated an interrupt that was handled + * IRQ_NONE, if the interrupt is not ours + */ +irqreturn_t acc_card_interrupt(struct acc_ov *ov, struct acc_core *cores) +{ + u32 irqmask; + int i; + + /* First we look for whom interrupts are pending, card/overview + * or any of the cores. Two bits in irqmask are used for each; + * Each two bit field is set to ACC_BM_IRQ_MASK if an IRQ is + * pending. + */ + irqmask = 0U; + if (READ_ONCE(*ov->bmfifo.irq_cnt) != ov->bmfifo.local_irq_cnt) { + irqmask |= ACC_BM_IRQ_MASK; + ov->bmfifo.local_irq_cnt = READ_ONCE(*ov->bmfifo.irq_cnt); + } + + for (i = 0; i < ov->active_cores; i++) { + struct acc_core *core = &cores[i]; + + if (READ_ONCE(*core->bmfifo.irq_cnt) != core->bmfifo.local_irq_cnt) { + irqmask |= (ACC_BM_IRQ_MASK << (2 * (i + 1))); + core->bmfifo.local_irq_cnt = READ_ONCE(*core->bmfifo.irq_cnt); + } + } + + if (!irqmask) + return IRQ_NONE; + + /* At second we tell the card we're working on them by writing irqmask, + * call handle_{ov|core}_interrupt and then acknowledge the + * interrupts by writing irq_cnt: + */ + acc_ov_write32(ov, ACC_OV_OF_BM_IRQ_MASK, irqmask); + + if (irqmask & ACC_BM_IRQ_MASK) { + /* handle_ov_interrupt(); - no use yet. */ + acc_ov_write32(ov, ACC_OV_OF_BM_IRQ_COUNTER, + ov->bmfifo.local_irq_cnt); + } + + for (i = 0; i < ov->active_cores; i++) { + struct acc_core *core = &cores[i]; + + if (irqmask & (ACC_BM_IRQ_MASK << (2 * (i + 1)))) { + handle_core_interrupt(core); + acc_write32(core, ACC_OV_OF_BM_IRQ_COUNTER, + core->bmfifo.local_irq_cnt); + } + } + + acc_ov_write32(ov, ACC_OV_OF_BM_IRQ_MASK, ACC_BM_IRQ_UNMASK_ALL); + + return IRQ_HANDLED; +} diff --git a/drivers/net/can/esd/esdacc.h b/drivers/net/can/esd/esdacc.h new file mode 100644 index 000000000000..a70488b25d39 --- /dev/null +++ b/drivers/net/can/esd/esdacc.h @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh + * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh + */ + +#include +#include +#include +#include +#include + +#define ACC_TS_FREQ_80MHZ (80 * HZ_PER_MHZ) +#define ACC_I2C_ADDON_DETECT_DELAY_MS 10 + +/* esdACC Overview Module */ +#define ACC_OV_OF_PROBE 0x0000 +#define ACC_OV_OF_VERSION 0x0004 +#define ACC_OV_OF_INFO 0x0008 +#define ACC_OV_OF_CANCORE_FREQ 0x000c +#define ACC_OV_OF_TS_FREQ_LO 0x0010 +#define ACC_OV_OF_TS_FREQ_HI 0x0014 +#define ACC_OV_OF_IRQ_STATUS_CORES 0x0018 +#define ACC_OV_OF_TS_CURR_LO 0x001c +#define ACC_OV_OF_TS_CURR_HI 0x0020 +#define ACC_OV_OF_IRQ_STATUS 0x0028 +#define ACC_OV_OF_MODE 0x002c +#define ACC_OV_OF_BM_IRQ_COUNTER 0x0070 +#define ACC_OV_OF_BM_IRQ_MASK 0x0074 +#define ACC_OV_OF_MSI_DATA 0x0080 +#define ACC_OV_OF_MSI_ADDRESSOFFSET 0x0084 + +/* Feature flags are contained in the upper 16 bit of the version + * register at ACC_OV_OF_VERSION but only used with these masks after + * extraction into an extra variable => (xx - 16). + */ +#define ACC_OV_REG_FEAT_MASK_CANFD BIT(27 - 16) +#define ACC_OV_REG_FEAT_MASK_NEW_PSC BIT(28 - 16) + +#define ACC_OV_REG_MODE_MASK_ENDIAN_LITTLE BIT(0) +#define ACC_OV_REG_MODE_MASK_BM_ENABLE BIT(1) +#define ACC_OV_REG_MODE_MASK_MODE_LED BIT(2) +#define ACC_OV_REG_MODE_MASK_TIMER_ENABLE BIT(4) +#define ACC_OV_REG_MODE_MASK_TIMER_ONE_SHOT BIT(5) +#define ACC_OV_REG_MODE_MASK_TIMER_ABSOLUTE BIT(6) +#define ACC_OV_REG_MODE_MASK_TIMER GENMASK(6, 4) +#define ACC_OV_REG_MODE_MASK_TS_SRC GENMASK(8, 7) +#define ACC_OV_REG_MODE_MASK_I2C_ENABLE BIT(11) +#define ACC_OV_REG_MODE_MASK_MSI_ENABLE BIT(14) +#define ACC_OV_REG_MODE_MASK_NEW_PSC_ENABLE BIT(15) +#define ACC_OV_REG_MODE_MASK_FPGA_RESET BIT(31) + +/* esdACC CAN Core Module */ +#define ACC_CORE_OF_CTRL_MODE 0x0000 +#define ACC_CORE_OF_STATUS_IRQ 0x0008 +#define ACC_CORE_OF_BRP 0x000c +#define ACC_CORE_OF_BTR 0x0010 +#define ACC_CORE_OF_FBTR 0x0014 +#define ACC_CORE_OF_STATUS 0x0030 +#define ACC_CORE_OF_TXFIFO_CONFIG 0x0048 +#define ACC_CORE_OF_TXFIFO_STATUS 0x004c +#define ACC_CORE_OF_TX_STATUS_IRQ 0x0050 +#define ACC_CORE_OF_TX_ABORT_MASK 0x0054 +#define ACC_CORE_OF_BM_IRQ_COUNTER 0x0070 +#define ACC_CORE_OF_TXFIFO_ID 0x00c0 +#define ACC_CORE_OF_TXFIFO_DLC 0x00c4 +#define ACC_CORE_OF_TXFIFO_DATA_0 0x00c8 +#define ACC_CORE_OF_TXFIFO_DATA_1 0x00cc + +#define ACC_REG_CONTROL_MASK_MODE_RESETMODE BIT(0) +#define ACC_REG_CONTROL_MASK_MODE_LOM BIT(1) +#define ACC_REG_CONTROL_MASK_MODE_STM BIT(2) +#define ACC_REG_CONTROL_MASK_MODE_TRANSEN BIT(5) +#define ACC_REG_CONTROL_MASK_MODE_TS BIT(6) +#define ACC_REG_CONTROL_MASK_MODE_SCHEDULE BIT(7) + +#define ACC_REG_CONTROL_MASK_IE_RXTX BIT(8) +#define ACC_REG_CONTROL_MASK_IE_TXERROR BIT(9) +#define ACC_REG_CONTROL_MASK_IE_ERRWARN BIT(10) +#define ACC_REG_CONTROL_MASK_IE_OVERRUN BIT(11) +#define ACC_REG_CONTROL_MASK_IE_TSI BIT(12) +#define ACC_REG_CONTROL_MASK_IE_ERRPASS BIT(13) +#define ACC_REG_CONTROL_MASK_IE_ALI BIT(14) +#define ACC_REG_CONTROL_MASK_IE_BUSERR BIT(15) + +/* BRP and BTR register layout for CAN-Classic version */ +#define ACC_REG_BRP_CL_MASK_BRP GENMASK(8, 0) +#define ACC_REG_BTR_CL_MASK_TSEG1 GENMASK(3, 0) +#define ACC_REG_BTR_CL_MASK_TSEG2 GENMASK(18, 16) +#define ACC_REG_BTR_CL_MASK_SJW GENMASK(25, 24) + +/* BRP and BTR register layout for CAN-FD version */ +#define ACC_REG_BRP_FD_MASK_BRP GENMASK(7, 0) +#define ACC_REG_BTR_FD_MASK_TSEG1 GENMASK(7, 0) +#define ACC_REG_BTR_FD_MASK_TSEG2 GENMASK(22, 16) +#define ACC_REG_BTR_FD_MASK_SJW GENMASK(30, 24) + +/* 256 BM_MSGs of 32 byte size */ +#define ACC_CORE_DMAMSG_SIZE 32U +#define ACC_CORE_DMABUF_SIZE (256U * ACC_CORE_DMAMSG_SIZE) + +enum acc_bmmsg_id { + BM_MSG_ID_RXTXDONE = 0x01, + BM_MSG_ID_TXABORT = 0x02, + BM_MSG_ID_OVERRUN = 0x03, + BM_MSG_ID_BUSERR = 0x04, + BM_MSG_ID_ERRPASSIVE = 0x05, + BM_MSG_ID_ERRWARN = 0x06, + BM_MSG_ID_TIMESLICE = 0x07, + BM_MSG_ID_HWTIMER = 0x08, + BM_MSG_ID_HOTPLUG = 0x09, +}; + +/* The struct acc_bmmsg_* structure declarations that follow here provide + * access to the ring buffer of bus master messages maintained by the FPGA + * bus master engine. All bus master messages have the same size of + * ACC_CORE_DMAMSG_SIZE and a minimum alignment of ACC_CORE_DMAMSG_SIZE in + * memory. + * + * All structure members are natural aligned. Therefore we should not need + * a __packed attribute. All struct acc_bmmsg_* declarations have at least + * reserved* members to fill the structure to the full ACC_CORE_DMAMSG_SIZE. + * + * A failure of this property due padding will be detected at compile time + * by static_assert(sizeof(union acc_bmmsg) == ACC_CORE_DMAMSG_SIZE). + */ + +struct acc_bmmsg_rxtxdone { + u8 msg_id; + u8 txfifo_level; + u8 reserved1[2]; + u8 txtsfifo_level; + u8 reserved2[3]; + u32 id; + struct { + u8 len; + u8 txdfifo_idx; + u8 zeroes8; + u8 reserved; + } acc_dlc; + u8 data[CAN_MAX_DLEN]; + /* Time stamps in struct acc_ov::timestamp_frequency ticks. */ + u64 ts; +}; + +struct acc_bmmsg_txabort { + u8 msg_id; + u8 txfifo_level; + u16 abort_mask; + u8 txtsfifo_level; + u8 reserved2[1]; + u16 abort_mask_txts; + u64 ts; + u32 reserved3[4]; +}; + +struct acc_bmmsg_overrun { + u8 msg_id; + u8 txfifo_level; + u8 lost_cnt; + u8 reserved1; + u8 txtsfifo_level; + u8 reserved2[3]; + u64 ts; + u32 reserved3[4]; +}; + +struct acc_bmmsg_buserr { + u8 msg_id; + u8 txfifo_level; + u8 ecc; + u8 reserved1; + u8 txtsfifo_level; + u8 reserved2[3]; + u64 ts; + u32 reg_status; + u32 reg_btr; + u32 reserved3[2]; +}; + +struct acc_bmmsg_errstatechange { + u8 msg_id; + u8 txfifo_level; + u8 reserved1[2]; + u8 txtsfifo_level; + u8 reserved2[3]; + u64 ts; + u32 reg_status; + u32 reserved3[3]; +}; + +struct acc_bmmsg_timeslice { + u8 msg_id; + u8 txfifo_level; + u8 reserved1[2]; + u8 txtsfifo_level; + u8 reserved2[3]; + u64 ts; + u32 reserved3[4]; +}; + +struct acc_bmmsg_hwtimer { + u8 msg_id; + u8 reserved1[3]; + u32 reserved2[1]; + u64 timer; + u32 reserved3[4]; +}; + +struct acc_bmmsg_hotplug { + u8 msg_id; + u8 reserved1[3]; + u32 reserved2[7]; +}; + +union acc_bmmsg { + u8 msg_id; + struct acc_bmmsg_rxtxdone rxtxdone; + struct acc_bmmsg_txabort txabort; + struct acc_bmmsg_overrun overrun; + struct acc_bmmsg_buserr buserr; + struct acc_bmmsg_errstatechange errstatechange; + struct acc_bmmsg_timeslice timeslice; + struct acc_bmmsg_hwtimer hwtimer; +}; + +/* Check size of union acc_bmmsg to be of expected size. */ +static_assert(sizeof(union acc_bmmsg) == ACC_CORE_DMAMSG_SIZE); + +struct acc_bmfifo { + const union acc_bmmsg *messages; + /* irq_cnt points to an u32 value where the esdACC FPGA deposits + * the bm_fifo head index in coherent DMA memory. Only bits 7..0 + * are valid. Use READ_ONCE() to access this memory location. + */ + const u32 *irq_cnt; + u32 local_irq_cnt; + u32 msg_fifo_tail; +}; + +struct acc_core { + void __iomem *addr; + struct net_device *netdev; + struct acc_bmfifo bmfifo; + u8 tx_fifo_size; + u8 tx_fifo_head; + u8 tx_fifo_tail; +}; + +struct acc_ov { + void __iomem *addr; + struct acc_bmfifo bmfifo; + u32 timestamp_frequency; + u32 core_frequency; + u16 version; + u16 features; + u8 total_cores; + u8 active_cores; +}; + +struct acc_net_priv { + struct can_priv can; /* must be the first member! */ + struct acc_core *core; + struct acc_ov *ov; +}; + +static inline u32 acc_read32(struct acc_core *core, unsigned short offs) +{ + return ioread32be(core->addr + offs); +} + +static inline void acc_write32(struct acc_core *core, + unsigned short offs, u32 v) +{ + iowrite32be(v, core->addr + offs); +} + +static inline void acc_write32_noswap(struct acc_core *core, + unsigned short offs, u32 v) +{ + iowrite32(v, core->addr + offs); +} + +static inline void acc_set_bits(struct acc_core *core, + unsigned short offs, u32 mask) +{ + u32 v = acc_read32(core, offs); + + v |= mask; + acc_write32(core, offs, v); +} + +static inline void acc_clear_bits(struct acc_core *core, + unsigned short offs, u32 mask) +{ + u32 v = acc_read32(core, offs); + + v &= ~mask; + acc_write32(core, offs, v); +} + +static inline int acc_resetmode_entered(struct acc_core *core) +{ + u32 ctrl = acc_read32(core, ACC_CORE_OF_CTRL_MODE); + + return (ctrl & ACC_REG_CONTROL_MASK_MODE_RESETMODE) != 0; +} + +static inline u32 acc_ov_read32(struct acc_ov *ov, unsigned short offs) +{ + return ioread32be(ov->addr + offs); +} + +static inline void acc_ov_write32(struct acc_ov *ov, + unsigned short offs, u32 v) +{ + iowrite32be(v, ov->addr + offs); +} + +static inline void acc_ov_set_bits(struct acc_ov *ov, + unsigned short offs, u32 b) +{ + u32 v = acc_ov_read32(ov, offs); + + v |= b; + acc_ov_write32(ov, offs, v); +} + +static inline void acc_ov_clear_bits(struct acc_ov *ov, + unsigned short offs, u32 b) +{ + u32 v = acc_ov_read32(ov, offs); + + v &= ~b; + acc_ov_write32(ov, offs, v); +} + +static inline void acc_reset_fpga(struct acc_ov *ov) +{ + acc_ov_write32(ov, ACC_OV_OF_MODE, ACC_OV_REG_MODE_MASK_FPGA_RESET); + + /* (Re-)start and wait for completion of addon detection on the I^2C bus */ + acc_ov_set_bits(ov, ACC_OV_OF_MODE, ACC_OV_REG_MODE_MASK_I2C_ENABLE); + mdelay(ACC_I2C_ADDON_DETECT_DELAY_MS); +} + +void acc_init_ov(struct acc_ov *ov, struct device *dev); +void acc_init_bm_ptr(struct acc_ov *ov, struct acc_core *cores, + const void *mem); +int acc_open(struct net_device *netdev); +int acc_close(struct net_device *netdev); +netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev); +int acc_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec); +int acc_set_mode(struct net_device *netdev, enum can_mode mode); +int acc_set_bittiming(struct net_device *netdev); +irqreturn_t acc_card_interrupt(struct acc_ov *ov, struct acc_core *cores); From a163c5761019b94258ca655b27b46e82657fd6f5 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:07 +0100 Subject: [PATCH 1105/2255] can: m_can: Start/Cancel polling timer together with interrupts Interrupts are enabled/disabled in more places than just m_can_start() and m_can_stop(). Couple the polling timer with enabling/disabling of all interrupts to achieve equivalent behavior. Cc: Judith Mendez Fixes: b382380c0d2d ("can: m_can: Add hrtimer to generate software interrupt") Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-2-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 16ecc11c7f62..2395b1225cc8 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -418,6 +418,13 @@ static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable) static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev) { + if (!cdev->net->irq) { + dev_dbg(cdev->dev, "Start hrtimer\n"); + hrtimer_start(&cdev->hrtimer, + ms_to_ktime(HRTIMER_POLL_INTERVAL_MS), + HRTIMER_MODE_REL_PINNED); + } + /* Only interrupt line 0 is used in this driver */ m_can_write(cdev, M_CAN_ILE, ILE_EINT0); } @@ -425,6 +432,11 @@ static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev) static inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev) { m_can_write(cdev, M_CAN_ILE, 0x0); + + if (!cdev->net->irq) { + dev_dbg(cdev->dev, "Stop hrtimer\n"); + hrtimer_cancel(&cdev->hrtimer); + } } /* Retrieve internal timestamp counter from TSCV.TSC, and shift it to 32-bit @@ -1417,12 +1429,6 @@ static int m_can_start(struct net_device *dev) m_can_enable_all_interrupts(cdev); - if (!dev->irq) { - dev_dbg(cdev->dev, "Start hrtimer\n"); - hrtimer_start(&cdev->hrtimer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS), - HRTIMER_MODE_REL_PINNED); - } - return 0; } @@ -1577,11 +1583,6 @@ static void m_can_stop(struct net_device *dev) { struct m_can_classdev *cdev = netdev_priv(dev); - if (!dev->irq) { - dev_dbg(cdev->dev, "Stop hrtimer\n"); - hrtimer_cancel(&cdev->hrtimer); - } - /* disable all interrupts */ m_can_disable_all_interrupts(cdev); From ba72f6c78b9beb3d85736b62b8167eaa93e0866b Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:08 +0100 Subject: [PATCH 1106/2255] can: m_can: Move hrtimer init to m_can_class_register The hrtimer_init() is called in m_can_plat_probe() and the hrtimer function is set in m_can_class_register(). For readability it is better to keep these two together in m_can_class_register(). Cc: Judith Mendez Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-3-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 6 +++++- drivers/net/can/m_can/m_can_platform.c | 4 ---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 2395b1225cc8..45391492339e 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -2070,8 +2070,12 @@ int m_can_class_register(struct m_can_classdev *cdev) goto clk_disable; } - if (!cdev->net->irq) + if (!cdev->net->irq) { + dev_dbg(cdev->dev, "Polling enabled, initialize hrtimer"); + hrtimer_init(&cdev->hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_PINNED); cdev->hrtimer.function = &hrtimer_callback; + } ret = m_can_dev_setup(cdev); if (ret) diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c index cdb28d6a092c..ab1b8211a61c 100644 --- a/drivers/net/can/m_can/m_can_platform.c +++ b/drivers/net/can/m_can/m_can_platform.c @@ -109,10 +109,6 @@ static int m_can_plat_probe(struct platform_device *pdev) ret = irq; goto probe_fail; } - } else { - dev_dbg(mcan_class->dev, "Polling enabled, initialize hrtimer"); - hrtimer_init(&mcan_class->hrtimer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL_PINNED); } /* message ram could be shared */ From 4248ba9ea24fa2c8a2106bfb14f775035e9ea8aa Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:09 +0100 Subject: [PATCH 1107/2255] can: m_can: Write transmit header and data in one transaction Combine header and data before writing to the transmit fifo to reduce the overhead for peripheral chips. Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-4-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 45391492339e..a01c9261331d 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -320,6 +320,12 @@ struct id_and_dlc { u32 dlc; }; +struct m_can_fifo_element { + u32 id; + u32 dlc; + u8 data[CANFD_MAX_DLEN]; +}; + static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg) { return cdev->ops->read_reg(cdev, reg); @@ -1637,9 +1643,10 @@ static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) { struct canfd_frame *cf = (struct canfd_frame *)cdev->tx_skb->data; + u8 len_padded = DIV_ROUND_UP(cf->len, 4); + struct m_can_fifo_element fifo_element; struct net_device *dev = cdev->net; struct sk_buff *skb = cdev->tx_skb; - struct id_and_dlc fifo_header; u32 cccr, fdflags; u32 txfqs; int err; @@ -1650,27 +1657,27 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) /* Generate ID field for TX buffer Element */ /* Common to all supported M_CAN versions */ if (cf->can_id & CAN_EFF_FLAG) { - fifo_header.id = cf->can_id & CAN_EFF_MASK; - fifo_header.id |= TX_BUF_XTD; + fifo_element.id = cf->can_id & CAN_EFF_MASK; + fifo_element.id |= TX_BUF_XTD; } else { - fifo_header.id = ((cf->can_id & CAN_SFF_MASK) << 18); + fifo_element.id = ((cf->can_id & CAN_SFF_MASK) << 18); } if (cf->can_id & CAN_RTR_FLAG) - fifo_header.id |= TX_BUF_RTR; + fifo_element.id |= TX_BUF_RTR; if (cdev->version == 30) { netif_stop_queue(dev); - fifo_header.dlc = can_fd_len2dlc(cf->len) << 16; + fifo_element.dlc = can_fd_len2dlc(cf->len) << 16; /* Write the frame ID, DLC, and payload to the FIFO element. */ - err = m_can_fifo_write(cdev, 0, M_CAN_FIFO_ID, &fifo_header, 2); + err = m_can_fifo_write(cdev, 0, M_CAN_FIFO_ID, &fifo_element, 2); if (err) goto out_fail; err = m_can_fifo_write(cdev, 0, M_CAN_FIFO_DATA, - cf->data, DIV_ROUND_UP(cf->len, 4)); + cf->data, len_padded); if (err) goto out_fail; @@ -1732,15 +1739,15 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) fdflags |= TX_BUF_BRS; } - fifo_header.dlc = FIELD_PREP(TX_BUF_MM_MASK, putidx) | + fifo_element.dlc = FIELD_PREP(TX_BUF_MM_MASK, putidx) | FIELD_PREP(TX_BUF_DLC_MASK, can_fd_len2dlc(cf->len)) | fdflags | TX_BUF_EFC; - err = m_can_fifo_write(cdev, putidx, M_CAN_FIFO_ID, &fifo_header, 2); - if (err) - goto out_fail; - err = m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DATA, - cf->data, DIV_ROUND_UP(cf->len, 4)); + memcpy_and_pad(fifo_element.data, CANFD_MAX_DLEN, &cf->data, + cf->len, 0); + + err = m_can_fifo_write(cdev, putidx, M_CAN_FIFO_ID, + &fifo_element, 2 + len_padded); if (err) goto out_fail; From 07f25091ca0265da65ea7a4bd2409c627f529c6f Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:10 +0100 Subject: [PATCH 1108/2255] can: m_can: Implement receive coalescing m_can offers the possibility to set an interrupt on reaching a watermark level in the receive FIFO. This can be used to implement coalescing. Unfortunately there is no hardware timeout available to trigger an interrupt if only a few messages were received within a given time. To solve this I am using a hrtimer to wake up the irq thread after x microseconds. The timer is always started if receive coalescing is enabled and new received frames were available during an interrupt. The timer is stopped if during a interrupt handling no new data was available. If the timer is started the new item interrupt is disabled and the watermark interrupt takes over. If the timer is not started again, the new item interrupt is enabled again, notifying the handler about every new item received. Signed-off-by: Markus Schneider-Pargmann Link: https://lore.kernel.org/all/20240207093220.2681425-5-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 77 ++++++++++++++++++++++++++++++++--- drivers/net/can/m_can/m_can.h | 5 +++ 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index a01c9261331d..b76fcf5f3889 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -422,6 +422,25 @@ static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable) } } +static void m_can_interrupt_enable(struct m_can_classdev *cdev, u32 interrupts) +{ + if (cdev->active_interrupts == interrupts) + return; + cdev->ops->write_reg(cdev, M_CAN_IE, interrupts); + cdev->active_interrupts = interrupts; +} + +static void m_can_coalescing_disable(struct m_can_classdev *cdev) +{ + u32 new_interrupts = cdev->active_interrupts | IR_RF0N; + + if (!cdev->net->irq) + return; + + hrtimer_cancel(&cdev->hrtimer); + m_can_interrupt_enable(cdev, new_interrupts); +} + static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev) { if (!cdev->net->irq) { @@ -437,7 +456,9 @@ static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev) static inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev) { + m_can_coalescing_disable(cdev); m_can_write(cdev, M_CAN_ILE, 0x0); + cdev->active_interrupts = 0x0; if (!cdev->net->irq) { dev_dbg(cdev->dev, "Stop hrtimer\n"); @@ -1091,15 +1112,42 @@ static int m_can_echo_tx_event(struct net_device *dev) return err; } +static void m_can_coalescing_update(struct m_can_classdev *cdev, u32 ir) +{ + u32 new_interrupts = cdev->active_interrupts; + bool enable_timer = false; + + if (!cdev->net->irq) + return; + + if (cdev->rx_coalesce_usecs_irq > 0 && (ir & (IR_RF0N | IR_RF0W))) { + enable_timer = true; + new_interrupts &= ~IR_RF0N; + } else if (!hrtimer_active(&cdev->hrtimer)) { + new_interrupts |= IR_RF0N; + } + + m_can_interrupt_enable(cdev, new_interrupts); + if (enable_timer) { + hrtimer_start(&cdev->hrtimer, + ns_to_ktime(cdev->rx_coalesce_usecs_irq * NSEC_PER_USEC), + HRTIMER_MODE_REL); + } +} + static irqreturn_t m_can_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct m_can_classdev *cdev = netdev_priv(dev); u32 ir; - if (pm_runtime_suspended(cdev->dev)) + if (pm_runtime_suspended(cdev->dev)) { + m_can_coalescing_disable(cdev); return IRQ_NONE; + } + ir = m_can_read(cdev, M_CAN_IR); + m_can_coalescing_update(cdev, ir); if (!ir) return IRQ_NONE; @@ -1114,13 +1162,17 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) * - state change IRQ * - bus error IRQ and bus error reporting */ - if ((ir & IR_RF0N) || (ir & IR_ERR_ALL_30X)) { + if (ir & (IR_RF0N | IR_RF0W | IR_ERR_ALL_30X)) { cdev->irqstatus = ir; if (!cdev->is_peripheral) { m_can_disable_all_interrupts(cdev); napi_schedule(&cdev->napi); - } else if (m_can_rx_peripheral(dev, ir) < 0) { - goto out_fail; + } else { + int pkts; + + pkts = m_can_rx_peripheral(dev, ir); + if (pkts < 0) + goto out_fail; } } @@ -1156,6 +1208,15 @@ out_fail: return IRQ_HANDLED; } +static enum hrtimer_restart m_can_coalescing_timer(struct hrtimer *timer) +{ + struct m_can_classdev *cdev = container_of(timer, struct m_can_classdev, hrtimer); + + irq_wake_thread(cdev->net->irq, cdev->net); + + return HRTIMER_NORESTART; +} + static const struct can_bittiming_const m_can_bittiming_const_30X = { .name = KBUILD_MODNAME, .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ @@ -1296,7 +1357,7 @@ static int m_can_chip_config(struct net_device *dev) /* Disable unused interrupts */ interrupts &= ~(IR_ARA | IR_ELO | IR_DRX | IR_TEFF | IR_TEFW | IR_TFE | IR_TCF | IR_HPM | IR_RF1F | IR_RF1W | IR_RF1N | - IR_RF0F | IR_RF0W); + IR_RF0F); m_can_config_endisable(cdev, true); @@ -1340,6 +1401,7 @@ static int m_can_chip_config(struct net_device *dev) /* rx fifo configuration, blocking mode, fifo size 1 */ m_can_write(cdev, M_CAN_RXF0C, + FIELD_PREP(RXFC_FWM_MASK, cdev->rx_max_coalesced_frames_irq) | FIELD_PREP(RXFC_FS_MASK, cdev->mcfg[MRAM_RXF0].num) | cdev->mcfg[MRAM_RXF0].off); @@ -1398,7 +1460,7 @@ static int m_can_chip_config(struct net_device *dev) else interrupts &= ~(IR_ERR_LEC_31X); } - m_can_write(cdev, M_CAN_IE, interrupts); + m_can_interrupt_enable(cdev, interrupts); /* route all interrupts to INT0 */ m_can_write(cdev, M_CAN_ILS, ILS_ALL_INT0); @@ -2082,6 +2144,9 @@ int m_can_class_register(struct m_can_classdev *cdev) hrtimer_init(&cdev->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); cdev->hrtimer.function = &hrtimer_callback; + } else { + hrtimer_init(&cdev->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + cdev->hrtimer.function = m_can_coalescing_timer; } ret = m_can_dev_setup(cdev); diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 520e14277dff..b916206199f1 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -92,6 +92,11 @@ struct m_can_classdev { int pm_clock_support; int is_peripheral; + // Cached M_CAN_IE register content + u32 active_interrupts; + u32 rx_max_coalesced_frames_irq; + u32 rx_coalesce_usecs_irq; + struct mram_cfg mcfg[MRAM_CFG_NUM]; struct hrtimer hrtimer; From ec390d0876170c075fb5ada568db1e03dd790b5b Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:11 +0100 Subject: [PATCH 1109/2255] can: m_can: Implement transmit coalescing Extend the coalescing implementation for transmits. In normal mode the chip raises an interrupt for every finished transmit. This implementation switches to coalescing mode as soon as an interrupt handled a transmit. For coalescing the watermark level interrupt is used to interrupt exactly after x frames were sent. It switches back into normal mode once there was an interrupt with no finished transmit and the timer being inactive. The timer is shared with receive coalescing. The time for receive and transmit coalescing timers have to be the same for that to work. The benefit is to have only a single running timer. Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-6-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 33 ++++++++++++++++++++------------- drivers/net/can/m_can/m_can.h | 4 ++++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index b76fcf5f3889..9b3e8e09f3aa 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -255,6 +255,7 @@ enum m_can_reg { #define TXESC_TBDS_64B 0x7 /* Tx Event FIFO Configuration (TXEFC) */ +#define TXEFC_EFWM_MASK GENMASK(29, 24) #define TXEFC_EFS_MASK GENMASK(21, 16) /* Tx Event FIFO Status (TXEFS) */ @@ -432,7 +433,7 @@ static void m_can_interrupt_enable(struct m_can_classdev *cdev, u32 interrupts) static void m_can_coalescing_disable(struct m_can_classdev *cdev) { - u32 new_interrupts = cdev->active_interrupts | IR_RF0N; + u32 new_interrupts = cdev->active_interrupts | IR_RF0N | IR_TEFN; if (!cdev->net->irq) return; @@ -1115,24 +1116,29 @@ static int m_can_echo_tx_event(struct net_device *dev) static void m_can_coalescing_update(struct m_can_classdev *cdev, u32 ir) { u32 new_interrupts = cdev->active_interrupts; - bool enable_timer = false; + bool enable_rx_timer = false; + bool enable_tx_timer = false; if (!cdev->net->irq) return; if (cdev->rx_coalesce_usecs_irq > 0 && (ir & (IR_RF0N | IR_RF0W))) { - enable_timer = true; + enable_rx_timer = true; new_interrupts &= ~IR_RF0N; - } else if (!hrtimer_active(&cdev->hrtimer)) { - new_interrupts |= IR_RF0N; } + if (cdev->tx_coalesce_usecs_irq > 0 && (ir & (IR_TEFN | IR_TEFW))) { + enable_tx_timer = true; + new_interrupts &= ~IR_TEFN; + } + if (!enable_rx_timer && !hrtimer_active(&cdev->hrtimer)) + new_interrupts |= IR_RF0N; + if (!enable_tx_timer && !hrtimer_active(&cdev->hrtimer)) + new_interrupts |= IR_TEFN; m_can_interrupt_enable(cdev, new_interrupts); - if (enable_timer) { - hrtimer_start(&cdev->hrtimer, - ns_to_ktime(cdev->rx_coalesce_usecs_irq * NSEC_PER_USEC), + if (enable_rx_timer | enable_tx_timer) + hrtimer_start(&cdev->hrtimer, cdev->irq_timer_wait, HRTIMER_MODE_REL); - } } static irqreturn_t m_can_isr(int irq, void *dev_id) @@ -1187,7 +1193,7 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) netif_wake_queue(dev); } } else { - if (ir & IR_TEFN) { + if (ir & (IR_TEFN | IR_TEFW)) { /* New TX FIFO Element arrived */ if (m_can_echo_tx_event(dev) != 0) goto out_fail; @@ -1355,9 +1361,8 @@ static int m_can_chip_config(struct net_device *dev) } /* Disable unused interrupts */ - interrupts &= ~(IR_ARA | IR_ELO | IR_DRX | IR_TEFF | IR_TEFW | IR_TFE | - IR_TCF | IR_HPM | IR_RF1F | IR_RF1W | IR_RF1N | - IR_RF0F); + interrupts &= ~(IR_ARA | IR_ELO | IR_DRX | IR_TEFF | IR_TFE | IR_TCF | + IR_HPM | IR_RF1F | IR_RF1W | IR_RF1N | IR_RF0F); m_can_config_endisable(cdev, true); @@ -1394,6 +1399,8 @@ static int m_can_chip_config(struct net_device *dev) } else { /* Full TX Event FIFO is used */ m_can_write(cdev, M_CAN_TXEFC, + FIELD_PREP(TXEFC_EFWM_MASK, + cdev->tx_max_coalesced_frames_irq) | FIELD_PREP(TXEFC_EFS_MASK, cdev->mcfg[MRAM_TXE].num) | cdev->mcfg[MRAM_TXE].off); diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index b916206199f1..1e461d305bce 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -84,6 +84,8 @@ struct m_can_classdev { struct sk_buff *tx_skb; struct phy *transceiver; + ktime_t irq_timer_wait; + struct m_can_ops *ops; int version; @@ -96,6 +98,8 @@ struct m_can_classdev { u32 active_interrupts; u32 rx_max_coalesced_frames_irq; u32 rx_coalesce_usecs_irq; + u32 tx_max_coalesced_frames_irq; + u32 tx_coalesce_usecs_irq; struct mram_cfg mcfg[MRAM_CFG_NUM]; From 9515223bd0bb9bb0a31b61a68f1049148c1d85ff Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:12 +0100 Subject: [PATCH 1110/2255] can: m_can: Add rx coalescing ethtool support Add the possibility to set coalescing parameters with ethtool. rx-frames-irq and rx-usecs-irq can only be set and unset together as the implemented mechanism would not work otherwise. rx-frames-irq can't be greater than the RX FIFO size. Also all values can only be changed if the chip is not active. Polling is excluded from irq coalescing support. Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-7-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 55 ++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 9b3e8e09f3aa..6dad1f569f82 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1977,7 +1977,57 @@ static const struct net_device_ops m_can_netdev_ops = { .ndo_change_mtu = can_change_mtu, }; +static int m_can_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kec, + struct netlink_ext_ack *ext_ack) +{ + struct m_can_classdev *cdev = netdev_priv(dev); + + ec->rx_max_coalesced_frames_irq = cdev->rx_max_coalesced_frames_irq; + ec->rx_coalesce_usecs_irq = cdev->rx_coalesce_usecs_irq; + + return 0; +} + +static int m_can_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kec, + struct netlink_ext_ack *ext_ack) +{ + struct m_can_classdev *cdev = netdev_priv(dev); + + if (cdev->can.state != CAN_STATE_STOPPED) { + netdev_err(dev, "Device is in use, please shut it down first\n"); + return -EBUSY; + } + + if (ec->rx_max_coalesced_frames_irq > cdev->mcfg[MRAM_RXF0].num) { + netdev_err(dev, "rx-frames-irq %u greater than the RX FIFO %u\n", + ec->rx_max_coalesced_frames_irq, + cdev->mcfg[MRAM_RXF0].num); + return -EINVAL; + } + if ((ec->rx_max_coalesced_frames_irq == 0) != (ec->rx_coalesce_usecs_irq == 0)) { + netdev_err(dev, "rx-frames-irq and rx-usecs-irq can only be set together\n"); + return -EINVAL; + } + + cdev->rx_max_coalesced_frames_irq = ec->rx_max_coalesced_frames_irq; + cdev->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq; + + return 0; +} + static const struct ethtool_ops m_can_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS_IRQ | + ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ, + .get_ts_info = ethtool_op_get_ts_info, + .get_coalesce = m_can_get_coalesce, + .set_coalesce = m_can_set_coalesce, +}; + +static const struct ethtool_ops m_can_ethtool_ops_polling = { .get_ts_info = ethtool_op_get_ts_info, }; @@ -1985,7 +2035,10 @@ static int register_m_can_dev(struct net_device *dev) { dev->flags |= IFF_ECHO; /* we support local echo */ dev->netdev_ops = &m_can_netdev_ops; - dev->ethtool_ops = &m_can_ethtool_ops; + if (dev->irq) + dev->ethtool_ops = &m_can_ethtool_ops; + else + dev->ethtool_ops = &m_can_ethtool_ops_polling; return register_candev(dev); } From e55b963e4e94011e9de7a6448ea8e50a12bb9953 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:13 +0100 Subject: [PATCH 1111/2255] can: m_can: Add tx coalescing ethtool support Add TX support to get/set functions for ethtool coalescing. tx-frames-irq and tx-usecs-irq can only be set/unset together. tx-frames-irq needs to be less than TXE and TXB. As rx and tx share the same timer, rx-usecs-irq and tx-usecs-irq can be enabled/disabled individually but they need to have the same value if enabled. Polling is excluded from TX irq coalescing. Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-8-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 38 ++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 6dad1f569f82..b31df3e3ceeb 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1986,6 +1986,8 @@ static int m_can_get_coalesce(struct net_device *dev, ec->rx_max_coalesced_frames_irq = cdev->rx_max_coalesced_frames_irq; ec->rx_coalesce_usecs_irq = cdev->rx_coalesce_usecs_irq; + ec->tx_max_coalesced_frames_irq = cdev->tx_max_coalesced_frames_irq; + ec->tx_coalesce_usecs_irq = cdev->tx_coalesce_usecs_irq; return 0; } @@ -2012,16 +2014,50 @@ static int m_can_set_coalesce(struct net_device *dev, netdev_err(dev, "rx-frames-irq and rx-usecs-irq can only be set together\n"); return -EINVAL; } + if (ec->tx_max_coalesced_frames_irq > cdev->mcfg[MRAM_TXE].num) { + netdev_err(dev, "tx-frames-irq %u greater than the TX event FIFO %u\n", + ec->tx_max_coalesced_frames_irq, + cdev->mcfg[MRAM_TXE].num); + return -EINVAL; + } + if (ec->tx_max_coalesced_frames_irq > cdev->mcfg[MRAM_TXB].num) { + netdev_err(dev, "tx-frames-irq %u greater than the TX FIFO %u\n", + ec->tx_max_coalesced_frames_irq, + cdev->mcfg[MRAM_TXB].num); + return -EINVAL; + } + if ((ec->tx_max_coalesced_frames_irq == 0) != (ec->tx_coalesce_usecs_irq == 0)) { + netdev_err(dev, "tx-frames-irq and tx-usecs-irq can only be set together\n"); + return -EINVAL; + } + if (ec->rx_coalesce_usecs_irq != 0 && ec->tx_coalesce_usecs_irq != 0 && + ec->rx_coalesce_usecs_irq != ec->tx_coalesce_usecs_irq) { + netdev_err(dev, "rx-usecs-irq %u needs to be equal to tx-usecs-irq %u if both are enabled\n", + ec->rx_coalesce_usecs_irq, + ec->tx_coalesce_usecs_irq); + return -EINVAL; + } cdev->rx_max_coalesced_frames_irq = ec->rx_max_coalesced_frames_irq; cdev->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq; + cdev->tx_max_coalesced_frames_irq = ec->tx_max_coalesced_frames_irq; + cdev->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq; + + if (cdev->rx_coalesce_usecs_irq) + cdev->irq_timer_wait = + ns_to_ktime(cdev->rx_coalesce_usecs_irq * NSEC_PER_USEC); + else + cdev->irq_timer_wait = + ns_to_ktime(cdev->tx_coalesce_usecs_irq * NSEC_PER_USEC); return 0; } static const struct ethtool_ops m_can_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS_IRQ | - ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ, + ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ | + ETHTOOL_COALESCE_TX_USECS_IRQ | + ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ, .get_ts_info = ethtool_op_get_ts_info, .get_coalesce = m_can_get_coalesce, .set_coalesce = m_can_set_coalesce, From 14f0a0a4407ebb6f36eb7d394d497d4632c654dc Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:14 +0100 Subject: [PATCH 1112/2255] can: m_can: Use u32 for putidx putidx is not an integer normally, it is an unsigned field used in hardware registers. Use a u32 for it. Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-9-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index b31df3e3ceeb..1b62613f195c 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -486,7 +486,7 @@ static void m_can_clean(struct net_device *net) struct m_can_classdev *cdev = netdev_priv(net); if (cdev->tx_skb) { - int putidx = 0; + u32 putidx = 0; net->stats.tx_errors++; if (cdev->version > 30) @@ -1695,12 +1695,12 @@ static int m_can_close(struct net_device *dev) return 0; } -static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) +static int m_can_next_echo_skb_occupied(struct net_device *dev, u32 putidx) { struct m_can_classdev *cdev = netdev_priv(dev); /*get wrap around for loopback skb index */ unsigned int wrap = cdev->can.echo_skb_max; - int next_idx; + u32 next_idx; /* calculate next index */ next_idx = (++putidx >= wrap ? 0 : putidx); @@ -1719,7 +1719,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) u32 cccr, fdflags; u32 txfqs; int err; - int putidx; + u32 putidx; cdev->tx_skb = NULL; From 80c5bac02a820dc569e38e102456ec4b34f6f607 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:15 +0100 Subject: [PATCH 1113/2255] can: m_can: Cache tx putidx m_can_tx_handler is the only place where data is written to the tx fifo. We can calculate the putidx in the driver code here to avoid the dependency on the txfqs register. Signed-off-by: Markus Schneider-Pargmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20240207093220.2681425-10-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 8 +++++++- drivers/net/can/m_can/m_can.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 1b62613f195c..a8e7b910ef81 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1504,6 +1504,10 @@ static int m_can_start(struct net_device *dev) m_can_enable_all_interrupts(cdev); + if (cdev->version > 30) + cdev->tx_fifo_putidx = FIELD_GET(TXFQS_TFQPI_MASK, + m_can_read(cdev, M_CAN_TXFQS)); + return 0; } @@ -1793,7 +1797,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) } /* get put index for frame */ - putidx = FIELD_GET(TXFQS_TFQPI_MASK, txfqs); + putidx = cdev->tx_fifo_putidx; /* Construct DLC Field, with CAN-FD configuration. * Use the put index of the fifo as the message marker, @@ -1827,6 +1831,8 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) /* Enable TX FIFO element to start transfer */ m_can_write(cdev, M_CAN_TXBAR, (1 << putidx)); + cdev->tx_fifo_putidx = (++cdev->tx_fifo_putidx >= cdev->can.echo_skb_max ? + 0 : cdev->tx_fifo_putidx); /* stop network queue if fifo full */ if (m_can_tx_fifo_full(cdev) || diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 1e461d305bce..0de42fc5ef1e 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -101,6 +101,9 @@ struct m_can_classdev { u32 tx_max_coalesced_frames_irq; u32 tx_coalesce_usecs_irq; + // Store this internally to avoid fetch delays on peripheral chips + int tx_fifo_putidx; + struct mram_cfg mcfg[MRAM_CFG_NUM]; struct hrtimer hrtimer; From e668673ed3992579f23413a13d7ed314cb62ee74 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:16 +0100 Subject: [PATCH 1114/2255] can: m_can: Use the workqueue as queue The current implementation uses the workqueue for peripheral chips to submit work. Only a single work item is queued and used at any time. To be able to keep more than one transmit in flight at a time, prepare the workqueue to support multiple transmits at the same time. Each work item now has a separate storage for a skb and a pointer to cdev. This assures that each workitem can be processed individually. The workqueue is replaced by an ordered workqueue which makes sure that only a single worker processes the items queued on the workqueue. Also items are ordered by the order they were enqueued. This removes most of the concurrency the workqueue normally offers. It is not necessary for this driver. The cleanup functions have to be adopted a bit to handle this new mechanism. Signed-off-by: Markus Schneider-Pargmann Link: https://lore.kernel.org/all/20240207093220.2681425-11-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 109 ++++++++++++++++++++-------------- drivers/net/can/m_can/m_can.h | 14 ++++- 2 files changed, 76 insertions(+), 47 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index a8e7b910ef81..8d7dbf2eb46c 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -485,17 +485,18 @@ static void m_can_clean(struct net_device *net) { struct m_can_classdev *cdev = netdev_priv(net); - if (cdev->tx_skb) { - u32 putidx = 0; + if (cdev->tx_ops) { + for (int i = 0; i != cdev->tx_fifo_size; ++i) { + if (!cdev->tx_ops[i].skb) + continue; - net->stats.tx_errors++; - if (cdev->version > 30) - putidx = FIELD_GET(TXFQS_TFQPI_MASK, - m_can_read(cdev, M_CAN_TXFQS)); - - can_free_echo_skb(cdev->net, putidx, NULL); - cdev->tx_skb = NULL; + net->stats.tx_errors++; + cdev->tx_ops[i].skb = NULL; + } } + + for (int i = 0; i != cdev->can.echo_skb_max; ++i) + can_free_echo_skb(cdev->net, i, NULL); } /* For peripherals, pass skb to rx-offload, which will push skb from @@ -1685,8 +1686,9 @@ static int m_can_close(struct net_device *dev) m_can_clk_stop(cdev); free_irq(dev->irq, dev); + m_can_clean(dev); + if (cdev->is_peripheral) { - cdev->tx_skb = NULL; destroy_workqueue(cdev->tx_wq); cdev->tx_wq = NULL; can_rx_offload_disable(&cdev->offload); @@ -1713,20 +1715,18 @@ static int m_can_next_echo_skb_occupied(struct net_device *dev, u32 putidx) return !!cdev->can.echo_skb[next_idx]; } -static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) +static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, + struct sk_buff *skb) { - struct canfd_frame *cf = (struct canfd_frame *)cdev->tx_skb->data; + struct canfd_frame *cf = (struct canfd_frame *)skb->data; u8 len_padded = DIV_ROUND_UP(cf->len, 4); struct m_can_fifo_element fifo_element; struct net_device *dev = cdev->net; - struct sk_buff *skb = cdev->tx_skb; u32 cccr, fdflags; u32 txfqs; int err; u32 putidx; - cdev->tx_skb = NULL; - /* Generate ID field for TX buffer Element */ /* Common to all supported M_CAN versions */ if (cf->can_id & CAN_EFF_FLAG) { @@ -1850,10 +1850,31 @@ out_fail: static void m_can_tx_work_queue(struct work_struct *ws) { - struct m_can_classdev *cdev = container_of(ws, struct m_can_classdev, - tx_work); + struct m_can_tx_op *op = container_of(ws, struct m_can_tx_op, work); + struct m_can_classdev *cdev = op->cdev; + struct sk_buff *skb = op->skb; - m_can_tx_handler(cdev); + op->skb = NULL; + m_can_tx_handler(cdev, skb); +} + +static void m_can_tx_queue_skb(struct m_can_classdev *cdev, struct sk_buff *skb) +{ + cdev->tx_ops[cdev->next_tx_op].skb = skb; + queue_work(cdev->tx_wq, &cdev->tx_ops[cdev->next_tx_op].work); + + ++cdev->next_tx_op; + if (cdev->next_tx_op >= cdev->tx_fifo_size) + cdev->next_tx_op = 0; +} + +static netdev_tx_t m_can_start_peripheral_xmit(struct m_can_classdev *cdev, + struct sk_buff *skb) +{ + netif_stop_queue(cdev->net); + m_can_tx_queue_skb(cdev, skb); + + return NETDEV_TX_OK; } static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, @@ -1864,30 +1885,15 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK; - if (cdev->is_peripheral) { - if (cdev->tx_skb) { - netdev_err(dev, "hard_xmit called while tx busy\n"); - return NETDEV_TX_BUSY; - } - - if (cdev->can.state == CAN_STATE_BUS_OFF) { - m_can_clean(dev); - } else { - /* Need to stop the queue to avoid numerous requests - * from being sent. Suggested improvement is to create - * a queueing mechanism that will queue the skbs and - * process them in order. - */ - cdev->tx_skb = skb; - netif_stop_queue(cdev->net); - queue_work(cdev->tx_wq, &cdev->tx_work); - } - } else { - cdev->tx_skb = skb; - return m_can_tx_handler(cdev); + if (cdev->can.state == CAN_STATE_BUS_OFF) { + m_can_clean(cdev->net); + return NETDEV_TX_OK; } - return NETDEV_TX_OK; + if (cdev->is_peripheral) + return m_can_start_peripheral_xmit(cdev, skb); + else + return m_can_tx_handler(cdev, skb); } static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer) @@ -1927,15 +1933,17 @@ static int m_can_open(struct net_device *dev) /* register interrupt handler */ if (cdev->is_peripheral) { - cdev->tx_skb = NULL; - cdev->tx_wq = alloc_workqueue("mcan_wq", - WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); + cdev->tx_wq = alloc_ordered_workqueue("mcan_wq", + WQ_FREEZABLE | WQ_MEM_RECLAIM); if (!cdev->tx_wq) { err = -ENOMEM; goto out_wq_fail; } - INIT_WORK(&cdev->tx_work, m_can_tx_work_queue); + for (int i = 0; i != cdev->tx_fifo_size; ++i) { + cdev->tx_ops[i].cdev = cdev; + INIT_WORK(&cdev->tx_ops[i].work, m_can_tx_work_queue); + } err = request_threaded_irq(dev->irq, NULL, m_can_isr, IRQF_ONESHOT, @@ -2228,6 +2236,19 @@ int m_can_class_register(struct m_can_classdev *cdev) { int ret; + cdev->tx_fifo_size = max(1, min(cdev->mcfg[MRAM_TXB].num, + cdev->mcfg[MRAM_TXE].num)); + if (cdev->is_peripheral) { + cdev->tx_ops = + devm_kzalloc(cdev->dev, + cdev->tx_fifo_size * sizeof(*cdev->tx_ops), + GFP_KERNEL); + if (!cdev->tx_ops) { + dev_err(cdev->dev, "Failed to allocate tx_ops for workqueue\n"); + return -ENOMEM; + } + } + if (cdev->pm_clock_support) { ret = m_can_clk_start(cdev); if (ret) diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 0de42fc5ef1e..be1d2119bd53 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -70,6 +70,12 @@ struct m_can_ops { int (*init)(struct m_can_classdev *cdev); }; +struct m_can_tx_op { + struct m_can_classdev *cdev; + struct work_struct work; + struct sk_buff *skb; +}; + struct m_can_classdev { struct can_priv can; struct can_rx_offload offload; @@ -80,8 +86,6 @@ struct m_can_classdev { struct clk *cclk; struct workqueue_struct *tx_wq; - struct work_struct tx_work; - struct sk_buff *tx_skb; struct phy *transceiver; ktime_t irq_timer_wait; @@ -102,7 +106,11 @@ struct m_can_classdev { u32 tx_coalesce_usecs_irq; // Store this internally to avoid fetch delays on peripheral chips - int tx_fifo_putidx; + u32 tx_fifo_putidx; + + struct m_can_tx_op *tx_ops; + int tx_fifo_size; + int next_tx_op; struct mram_cfg mcfg[MRAM_CFG_NUM]; From 1fa80e23c15051edc1c594270517de3517ded798 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:17 +0100 Subject: [PATCH 1115/2255] can: m_can: Introduce a tx_fifo_in_flight counter Keep track of the number of transmits in flight. This patch prepares the driver to control the network interface queue based on this counter. By itself this counter be implemented with an atomic, but as we need to do other things in the critical sections later I am using a spinlock instead. Signed-off-by: Markus Schneider-Pargmann Link: https://lore.kernel.org/all/20240207093220.2681425-12-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 30 ++++++++++++++++++++++++++++++ drivers/net/can/m_can/m_can.h | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 8d7dbf2eb46c..2c68b1a60887 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -484,6 +484,7 @@ static u32 m_can_get_timestamp(struct m_can_classdev *cdev) static void m_can_clean(struct net_device *net) { struct m_can_classdev *cdev = netdev_priv(net); + unsigned long irqflags; if (cdev->tx_ops) { for (int i = 0; i != cdev->tx_fifo_size; ++i) { @@ -497,6 +498,10 @@ static void m_can_clean(struct net_device *net) for (int i = 0; i != cdev->can.echo_skb_max; ++i) can_free_echo_skb(cdev->net, i, NULL); + + spin_lock_irqsave(&cdev->tx_handling_spinlock, irqflags); + cdev->tx_fifo_in_flight = 0; + spin_unlock_irqrestore(&cdev->tx_handling_spinlock, irqflags); } /* For peripherals, pass skb to rx-offload, which will push skb from @@ -1067,6 +1072,24 @@ static void m_can_tx_update_stats(struct m_can_classdev *cdev, stats->tx_packets++; } +static void m_can_finish_tx(struct m_can_classdev *cdev, int transmitted) +{ + unsigned long irqflags; + + spin_lock_irqsave(&cdev->tx_handling_spinlock, irqflags); + cdev->tx_fifo_in_flight -= transmitted; + spin_unlock_irqrestore(&cdev->tx_handling_spinlock, irqflags); +} + +static void m_can_start_tx(struct m_can_classdev *cdev) +{ + unsigned long irqflags; + + spin_lock_irqsave(&cdev->tx_handling_spinlock, irqflags); + ++cdev->tx_fifo_in_flight; + spin_unlock_irqrestore(&cdev->tx_handling_spinlock, irqflags); +} + static int m_can_echo_tx_event(struct net_device *dev) { u32 txe_count = 0; @@ -1076,6 +1099,7 @@ static int m_can_echo_tx_event(struct net_device *dev) int i = 0; int err = 0; unsigned int msg_mark; + int processed = 0; struct m_can_classdev *cdev = netdev_priv(dev); @@ -1105,12 +1129,15 @@ static int m_can_echo_tx_event(struct net_device *dev) /* update stats */ m_can_tx_update_stats(cdev, msg_mark, timestamp); + ++processed; } if (ack_fgi != -1) m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK, ack_fgi)); + m_can_finish_tx(cdev, processed); + return err; } @@ -1192,6 +1219,7 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) timestamp = m_can_get_timestamp(cdev); m_can_tx_update_stats(cdev, 0, timestamp); netif_wake_queue(dev); + m_can_finish_tx(cdev, 1); } } else { if (ir & (IR_TEFN | IR_TEFW)) { @@ -1890,6 +1918,8 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } + m_can_start_tx(cdev); + if (cdev->is_peripheral) return m_can_start_peripheral_xmit(cdev, skb); else diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index be1d2119bd53..76b1ce1b7c1b 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -108,6 +108,10 @@ struct m_can_classdev { // Store this internally to avoid fetch delays on peripheral chips u32 tx_fifo_putidx; + /* Protects shared state between start_xmit and m_can_isr */ + spinlock_t tx_handling_spinlock; + int tx_fifo_in_flight; + struct m_can_tx_op *tx_ops; int tx_fifo_size; int next_tx_op; From 7508a10ca295c635fad9c9f34ac96384d806af89 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:18 +0100 Subject: [PATCH 1116/2255] can: m_can: Use tx_fifo_in_flight for netif_queue control The network queue is currently always stopped in start_xmit and continued in the interrupt handler. This is not possible anymore if we want to keep multiple transmits in flight in parallel. Use the previously introduced tx_fifo_in_flight counter to control the network queue instead. This has the benefit of not needing to ask the hardware about fifo status. This patch stops the network queue in start_xmit if the number of transmits in flight reaches the size of the fifo and wakes up the queue from the interrupt handler once the transmits in flight drops below the fifo size. This means any skbs over the limit will be rejected immediately in start_xmit (it shouldn't be possible at all to reach that state anyways). The maximum number of transmits in flight is the size of the fifo. Signed-off-by: Markus Schneider-Pargmann Link: https://lore.kernel.org/all/20240207093220.2681425-13-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 77 +++++++++-------------------------- 1 file changed, 20 insertions(+), 57 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 2c68b1a60887..20595b7141af 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -379,16 +379,6 @@ m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset, u32 *val) return cdev->ops->read_fifo(cdev, addr_offset, val, 1); } -static inline bool _m_can_tx_fifo_full(u32 txfqs) -{ - return !!(txfqs & TXFQS_TFQF); -} - -static inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev) -{ - return _m_can_tx_fifo_full(m_can_read(cdev, M_CAN_TXFQS)); -} - static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable) { u32 cccr = m_can_read(cdev, M_CAN_CCCR); @@ -1077,17 +1067,31 @@ static void m_can_finish_tx(struct m_can_classdev *cdev, int transmitted) unsigned long irqflags; spin_lock_irqsave(&cdev->tx_handling_spinlock, irqflags); + if (cdev->tx_fifo_in_flight >= cdev->tx_fifo_size && transmitted > 0) + netif_wake_queue(cdev->net); cdev->tx_fifo_in_flight -= transmitted; spin_unlock_irqrestore(&cdev->tx_handling_spinlock, irqflags); } -static void m_can_start_tx(struct m_can_classdev *cdev) +static netdev_tx_t m_can_start_tx(struct m_can_classdev *cdev) { unsigned long irqflags; + int tx_fifo_in_flight; spin_lock_irqsave(&cdev->tx_handling_spinlock, irqflags); - ++cdev->tx_fifo_in_flight; + tx_fifo_in_flight = cdev->tx_fifo_in_flight + 1; + if (tx_fifo_in_flight >= cdev->tx_fifo_size) { + netif_stop_queue(cdev->net); + if (tx_fifo_in_flight > cdev->tx_fifo_size) { + netdev_err_once(cdev->net, "hard_xmit called while TX FIFO full\n"); + spin_unlock_irqrestore(&cdev->tx_handling_spinlock, irqflags); + return NETDEV_TX_BUSY; + } + } + cdev->tx_fifo_in_flight = tx_fifo_in_flight; spin_unlock_irqrestore(&cdev->tx_handling_spinlock, irqflags); + + return NETDEV_TX_OK; } static int m_can_echo_tx_event(struct net_device *dev) @@ -1218,7 +1222,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) if (cdev->is_peripheral) timestamp = m_can_get_timestamp(cdev); m_can_tx_update_stats(cdev, 0, timestamp); - netif_wake_queue(dev); m_can_finish_tx(cdev, 1); } } else { @@ -1226,10 +1229,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) /* New TX FIFO Element arrived */ if (m_can_echo_tx_event(dev) != 0) goto out_fail; - - if (netif_queue_stopped(dev) && - !m_can_tx_fifo_full(cdev)) - netif_wake_queue(dev); } } @@ -1729,20 +1728,6 @@ static int m_can_close(struct net_device *dev) return 0; } -static int m_can_next_echo_skb_occupied(struct net_device *dev, u32 putidx) -{ - struct m_can_classdev *cdev = netdev_priv(dev); - /*get wrap around for loopback skb index */ - unsigned int wrap = cdev->can.echo_skb_max; - u32 next_idx; - - /* calculate next index */ - next_idx = (++putidx >= wrap ? 0 : putidx); - - /* check if occupied */ - return !!cdev->can.echo_skb[next_idx]; -} - static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, struct sk_buff *skb) { @@ -1751,7 +1736,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, struct m_can_fifo_element fifo_element; struct net_device *dev = cdev->net; u32 cccr, fdflags; - u32 txfqs; int err; u32 putidx; @@ -1806,24 +1790,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, } else { /* Transmit routine for version >= v3.1.x */ - txfqs = m_can_read(cdev, M_CAN_TXFQS); - - /* Check if FIFO full */ - if (_m_can_tx_fifo_full(txfqs)) { - /* This shouldn't happen */ - netif_stop_queue(dev); - netdev_warn(dev, - "TX queue active although FIFO is full."); - - if (cdev->is_peripheral) { - kfree_skb(skb); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } else { - return NETDEV_TX_BUSY; - } - } - /* get put index for frame */ putidx = cdev->tx_fifo_putidx; @@ -1861,11 +1827,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, m_can_write(cdev, M_CAN_TXBAR, (1 << putidx)); cdev->tx_fifo_putidx = (++cdev->tx_fifo_putidx >= cdev->can.echo_skb_max ? 0 : cdev->tx_fifo_putidx); - - /* stop network queue if fifo full */ - if (m_can_tx_fifo_full(cdev) || - m_can_next_echo_skb_occupied(dev, putidx)) - netif_stop_queue(dev); } return NETDEV_TX_OK; @@ -1899,7 +1860,6 @@ static void m_can_tx_queue_skb(struct m_can_classdev *cdev, struct sk_buff *skb) static netdev_tx_t m_can_start_peripheral_xmit(struct m_can_classdev *cdev, struct sk_buff *skb) { - netif_stop_queue(cdev->net); m_can_tx_queue_skb(cdev, skb); return NETDEV_TX_OK; @@ -1909,6 +1869,7 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct m_can_classdev *cdev = netdev_priv(dev); + netdev_tx_t ret; if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK; @@ -1918,7 +1879,9 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } - m_can_start_tx(cdev); + ret = m_can_start_tx(cdev); + if (ret != NETDEV_TX_OK) + return ret; if (cdev->is_peripheral) return m_can_start_peripheral_xmit(cdev, skb); From 251f913d19a8a960126359c20bd5719461e5399f Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:19 +0100 Subject: [PATCH 1117/2255] can: m_can: Implement BQL Implement byte queue limiting in preparation for the use of xmit_more(). Signed-off-by: Markus Schneider-Pargmann Link: https://lore.kernel.org/all/20240207093220.2681425-14-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 50 +++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 20595b7141af..48968da69ae9 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -489,6 +489,8 @@ static void m_can_clean(struct net_device *net) for (int i = 0; i != cdev->can.echo_skb_max; ++i) can_free_echo_skb(cdev->net, i, NULL); + netdev_reset_queue(cdev->net); + spin_lock_irqsave(&cdev->tx_handling_spinlock, irqflags); cdev->tx_fifo_in_flight = 0; spin_unlock_irqrestore(&cdev->tx_handling_spinlock, irqflags); @@ -1043,29 +1045,34 @@ static int m_can_poll(struct napi_struct *napi, int quota) * echo. timestamp is used for peripherals to ensure correct ordering * by rx-offload, and is ignored for non-peripherals. */ -static void m_can_tx_update_stats(struct m_can_classdev *cdev, - unsigned int msg_mark, - u32 timestamp) +static unsigned int m_can_tx_update_stats(struct m_can_classdev *cdev, + unsigned int msg_mark, u32 timestamp) { struct net_device *dev = cdev->net; struct net_device_stats *stats = &dev->stats; + unsigned int frame_len; if (cdev->is_peripheral) stats->tx_bytes += can_rx_offload_get_echo_skb_queue_timestamp(&cdev->offload, msg_mark, timestamp, - NULL); + &frame_len); else - stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL); + stats->tx_bytes += can_get_echo_skb(dev, msg_mark, &frame_len); stats->tx_packets++; + + return frame_len; } -static void m_can_finish_tx(struct m_can_classdev *cdev, int transmitted) +static void m_can_finish_tx(struct m_can_classdev *cdev, int transmitted, + unsigned int transmitted_frame_len) { unsigned long irqflags; + netdev_completed_queue(cdev->net, transmitted, transmitted_frame_len); + spin_lock_irqsave(&cdev->tx_handling_spinlock, irqflags); if (cdev->tx_fifo_in_flight >= cdev->tx_fifo_size && transmitted > 0) netif_wake_queue(cdev->net); @@ -1104,6 +1111,7 @@ static int m_can_echo_tx_event(struct net_device *dev) int err = 0; unsigned int msg_mark; int processed = 0; + unsigned int processed_frame_len = 0; struct m_can_classdev *cdev = netdev_priv(dev); @@ -1132,7 +1140,9 @@ static int m_can_echo_tx_event(struct net_device *dev) fgi = (++fgi >= cdev->mcfg[MRAM_TXE].num ? 0 : fgi); /* update stats */ - m_can_tx_update_stats(cdev, msg_mark, timestamp); + processed_frame_len += m_can_tx_update_stats(cdev, msg_mark, + timestamp); + ++processed; } @@ -1140,7 +1150,7 @@ static int m_can_echo_tx_event(struct net_device *dev) m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK, ack_fgi)); - m_can_finish_tx(cdev, processed); + m_can_finish_tx(cdev, processed, processed_frame_len); return err; } @@ -1218,11 +1228,12 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) if (ir & IR_TC) { /* Transmission Complete Interrupt*/ u32 timestamp = 0; + unsigned int frame_len; if (cdev->is_peripheral) timestamp = m_can_get_timestamp(cdev); - m_can_tx_update_stats(cdev, 0, timestamp); - m_can_finish_tx(cdev, 1); + frame_len = m_can_tx_update_stats(cdev, 0, timestamp); + m_can_finish_tx(cdev, 1, frame_len); } } else { if (ir & (IR_TEFN | IR_TEFW)) { @@ -1738,6 +1749,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, u32 cccr, fdflags; int err; u32 putidx; + unsigned int frame_len = can_skb_get_frame_len(skb); /* Generate ID field for TX buffer Element */ /* Common to all supported M_CAN versions */ @@ -1783,7 +1795,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, } m_can_write(cdev, M_CAN_TXBTIE, 0x1); - can_put_echo_skb(skb, dev, 0, 0); + can_put_echo_skb(skb, dev, 0, frame_len); m_can_write(cdev, M_CAN_TXBAR, 0x1); /* End of xmit function for version 3.0.x */ @@ -1821,7 +1833,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, /* Push loopback echo. * Will be looped back on TX interrupt based on message marker */ - can_put_echo_skb(skb, dev, putidx, 0); + can_put_echo_skb(skb, dev, putidx, frame_len); /* Enable TX FIFO element to start transfer */ m_can_write(cdev, M_CAN_TXBAR, (1 << putidx)); @@ -1869,11 +1881,14 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct m_can_classdev *cdev = netdev_priv(dev); + unsigned int frame_len; netdev_tx_t ret; if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK; + frame_len = can_skb_get_frame_len(skb); + if (cdev->can.state == CAN_STATE_BUS_OFF) { m_can_clean(cdev->net); return NETDEV_TX_OK; @@ -1883,10 +1898,17 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, if (ret != NETDEV_TX_OK) return ret; + netdev_sent_queue(dev, frame_len); + if (cdev->is_peripheral) - return m_can_start_peripheral_xmit(cdev, skb); + ret = m_can_start_peripheral_xmit(cdev, skb); else - return m_can_tx_handler(cdev, skb); + ret = m_can_tx_handler(cdev, skb); + + if (ret != NETDEV_TX_OK) + netdev_completed_queue(dev, 1, frame_len); + + return ret; } static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer) From c306c3873de0804bea4bb2ac717bd2c088acc589 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 7 Feb 2024 10:32:20 +0100 Subject: [PATCH 1118/2255] can: m_can: Implement transmit submission coalescing m_can supports submitting multiple transmits with one register write. This is an interesting option to reduce the number of SPI transfers for peripheral chips. The m_can_tx_op is extended with a bool that signals if it is the last transmission and the submit should be executed immediately. The worker then writes the skb to the FIFO and submits it only if the submit bool is set. If it isn't set, the worker will write the next skb which is waiting in the workqueue to the FIFO, etc. Signed-off-by: Markus Schneider-Pargmann Link: https://lore.kernel.org/all/20240207093220.2681425-15-msp@baylibre.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 56 ++++++++++++++++++++++++++++++++--- drivers/net/can/m_can/m_can.h | 6 ++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 48968da69ae9..b7dbce4c342a 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1539,6 +1539,9 @@ static int m_can_start(struct net_device *dev) if (ret) return ret; + netdev_queue_set_dql_min_limit(netdev_get_tx_queue(cdev->net, 0), + cdev->tx_max_coalesced_frames); + cdev->can.state = CAN_STATE_ERROR_ACTIVE; m_can_enable_all_interrupts(cdev); @@ -1835,8 +1838,13 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev, */ can_put_echo_skb(skb, dev, putidx, frame_len); - /* Enable TX FIFO element to start transfer */ - m_can_write(cdev, M_CAN_TXBAR, (1 << putidx)); + if (cdev->is_peripheral) { + /* Delay enabling TX FIFO element */ + cdev->tx_peripheral_submit |= BIT(putidx); + } else { + /* Enable TX FIFO element to start transfer */ + m_can_write(cdev, M_CAN_TXBAR, BIT(putidx)); + } cdev->tx_fifo_putidx = (++cdev->tx_fifo_putidx >= cdev->can.echo_skb_max ? 0 : cdev->tx_fifo_putidx); } @@ -1849,6 +1857,17 @@ out_fail: return NETDEV_TX_BUSY; } +static void m_can_tx_submit(struct m_can_classdev *cdev) +{ + if (cdev->version == 30) + return; + if (!cdev->is_peripheral) + return; + + m_can_write(cdev, M_CAN_TXBAR, cdev->tx_peripheral_submit); + cdev->tx_peripheral_submit = 0; +} + static void m_can_tx_work_queue(struct work_struct *ws) { struct m_can_tx_op *op = container_of(ws, struct m_can_tx_op, work); @@ -1857,11 +1876,15 @@ static void m_can_tx_work_queue(struct work_struct *ws) op->skb = NULL; m_can_tx_handler(cdev, skb); + if (op->submit) + m_can_tx_submit(cdev); } -static void m_can_tx_queue_skb(struct m_can_classdev *cdev, struct sk_buff *skb) +static void m_can_tx_queue_skb(struct m_can_classdev *cdev, struct sk_buff *skb, + bool submit) { cdev->tx_ops[cdev->next_tx_op].skb = skb; + cdev->tx_ops[cdev->next_tx_op].submit = submit; queue_work(cdev->tx_wq, &cdev->tx_ops[cdev->next_tx_op].work); ++cdev->next_tx_op; @@ -1872,7 +1895,17 @@ static void m_can_tx_queue_skb(struct m_can_classdev *cdev, struct sk_buff *skb) static netdev_tx_t m_can_start_peripheral_xmit(struct m_can_classdev *cdev, struct sk_buff *skb) { - m_can_tx_queue_skb(cdev, skb); + bool submit; + + ++cdev->nr_txs_without_submit; + if (cdev->nr_txs_without_submit >= cdev->tx_max_coalesced_frames || + !netdev_xmit_more()) { + cdev->nr_txs_without_submit = 0; + submit = true; + } else { + submit = false; + } + m_can_tx_queue_skb(cdev, skb, submit); return NETDEV_TX_OK; } @@ -2015,6 +2048,7 @@ static int m_can_get_coalesce(struct net_device *dev, ec->rx_max_coalesced_frames_irq = cdev->rx_max_coalesced_frames_irq; ec->rx_coalesce_usecs_irq = cdev->rx_coalesce_usecs_irq; + ec->tx_max_coalesced_frames = cdev->tx_max_coalesced_frames; ec->tx_max_coalesced_frames_irq = cdev->tx_max_coalesced_frames_irq; ec->tx_coalesce_usecs_irq = cdev->tx_coalesce_usecs_irq; @@ -2059,6 +2093,18 @@ static int m_can_set_coalesce(struct net_device *dev, netdev_err(dev, "tx-frames-irq and tx-usecs-irq can only be set together\n"); return -EINVAL; } + if (ec->tx_max_coalesced_frames > cdev->mcfg[MRAM_TXE].num) { + netdev_err(dev, "tx-frames %u greater than the TX event FIFO %u\n", + ec->tx_max_coalesced_frames, + cdev->mcfg[MRAM_TXE].num); + return -EINVAL; + } + if (ec->tx_max_coalesced_frames > cdev->mcfg[MRAM_TXB].num) { + netdev_err(dev, "tx-frames %u greater than the TX FIFO %u\n", + ec->tx_max_coalesced_frames, + cdev->mcfg[MRAM_TXB].num); + return -EINVAL; + } if (ec->rx_coalesce_usecs_irq != 0 && ec->tx_coalesce_usecs_irq != 0 && ec->rx_coalesce_usecs_irq != ec->tx_coalesce_usecs_irq) { netdev_err(dev, "rx-usecs-irq %u needs to be equal to tx-usecs-irq %u if both are enabled\n", @@ -2069,6 +2115,7 @@ static int m_can_set_coalesce(struct net_device *dev, cdev->rx_max_coalesced_frames_irq = ec->rx_max_coalesced_frames_irq; cdev->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq; + cdev->tx_max_coalesced_frames = ec->tx_max_coalesced_frames; cdev->tx_max_coalesced_frames_irq = ec->tx_max_coalesced_frames_irq; cdev->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq; @@ -2086,6 +2133,7 @@ static const struct ethtool_ops m_can_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS_IRQ | ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ | ETHTOOL_COALESCE_TX_USECS_IRQ | + ETHTOOL_COALESCE_TX_MAX_FRAMES | ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ, .get_ts_info = ethtool_op_get_ts_info, .get_coalesce = m_can_get_coalesce, diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 76b1ce1b7c1b..2986c4ce0b2f 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -74,6 +74,7 @@ struct m_can_tx_op { struct m_can_classdev *cdev; struct work_struct work; struct sk_buff *skb; + bool submit; }; struct m_can_classdev { @@ -102,6 +103,7 @@ struct m_can_classdev { u32 active_interrupts; u32 rx_max_coalesced_frames_irq; u32 rx_coalesce_usecs_irq; + u32 tx_max_coalesced_frames; u32 tx_max_coalesced_frames_irq; u32 tx_coalesce_usecs_irq; @@ -116,6 +118,10 @@ struct m_can_classdev { int tx_fifo_size; int next_tx_op; + int nr_txs_without_submit; + /* bitfield of fifo elements that will be submitted together */ + u32 tx_peripheral_submit; + struct mram_cfg mcfg[MRAM_CFG_NUM]; struct hrtimer hrtimer; From 7af9682d9eab968afe3293d0cde8f43d7bf4e622 Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Mon, 5 Feb 2024 20:15:02 +0900 Subject: [PATCH 1119/2255] can: change can network drivers maintainer Wolfgang has not been active on the linux-can mailing list other the last two years, his last activity being on November 2021 [1]. In replacement, I would like to nominate myself (Vincent Mailhol) as the second maintainer of the CAN drivers subtree. Wolfgang is already listed in the CREDITS since [2], so despite this removal, his legacy remains credited. Thank you for all your contributions! [1] https://lore.kernel.org/linux-can/?q=f%3AWolfgang+Grandegger [2] commit 4261a2043f1b ("can: Update MAINTAINERS and CREDITS file") Link: https://git.kernel.org/torvalds/c/4261a2043f1b CC: Marc Kleine-Budde CC: Wolfgang Grandegger Signed-off-by: Vincent Mailhol Link: https://lore.kernel.org/all/20240205111743.920528-2-mailhol.vincent@wanadoo.fr Signed-off-by: Marc Kleine-Budde --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7f3e554671c4..a5a17a463685 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4632,8 +4632,8 @@ S: Maintained F: net/sched/sch_cake.c CAN NETWORK DRIVERS -M: Wolfgang Grandegger M: Marc Kleine-Budde +M: Vincent Mailhol L: linux-can@vger.kernel.org S: Maintained W: https://github.com/linux-can From 85216f56bde74ec365da3fdff1929505538ce894 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 13 Nov 2023 14:47:17 +0100 Subject: [PATCH 1120/2255] can: kvaser_pciefd: Add support for Kvaser M.2 PCIe 4xCAN Add support for new Kvaser pciefd device, M.2 PCIe 4xCAN, based on Xilinx FPGA. Signed-off-by: Jimmy Assarsson Link: https://lore.kernel.org/all/20231113134717.515037-1-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/Kconfig | 1 + drivers/net/can/kvaser_pciefd.c | 55 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 2da126f13641..620766eb6bc1 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -168,6 +168,7 @@ config CAN_KVASER_PCIEFD Kvaser Mini PCI Express 2xHS v2 Kvaser Mini PCI Express 1xCAN v3 Kvaser Mini PCI Express 2xCAN v3 + Kvaser M.2 PCIe 4xCAN config CAN_SLCAN tristate "Serial / USB serial CAN Adaptors (slcan)" diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index a57005faa04f..416f10480b40 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -47,12 +47,18 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_MINIPCIE_2CAN_V3_DEVICE_ID 0x0015 #define KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID 0x0016 +/* Xilinx based devices */ +#define KVASER_PCIEFD_M2_4CAN_DEVICE_ID 0x0017 + /* Altera SerDes Enable 64-bit DMA address translation */ #define KVASER_PCIEFD_ALTERA_DMA_64BIT BIT(0) /* SmartFusion2 SerDes LSB address translation mask */ #define KVASER_PCIEFD_SF2_DMA_LSB_MASK GENMASK(31, 12) +/* Xilinx SerDes LSB address translation mask */ +#define KVASER_PCIEFD_XILINX_DMA_LSB_MASK GENMASK(31, 12) + /* Kvaser KCAN CAN controller registers */ #define KVASER_PCIEFD_KCAN_FIFO_REG 0x100 #define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180 @@ -281,6 +287,8 @@ static void kvaser_pciefd_write_dma_map_altera(struct kvaser_pciefd *pcie, dma_addr_t addr, int index); static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie, dma_addr_t addr, int index); +static void kvaser_pciefd_write_dma_map_xilinx(struct kvaser_pciefd *pcie, + dma_addr_t addr, int index); struct kvaser_pciefd_address_offset { u32 serdes; @@ -335,6 +343,18 @@ static const struct kvaser_pciefd_address_offset kvaser_pciefd_sf2_address_offse .kcan_ch1 = 0x142000, }; +static const struct kvaser_pciefd_address_offset kvaser_pciefd_xilinx_address_offset = { + .serdes = 0x00208, + .pci_ien = 0x102004, + .pci_irq = 0x102008, + .sysid = 0x100000, + .loopback = 0x103000, + .kcan_srb_fifo = 0x120000, + .kcan_srb = 0x121000, + .kcan_ch0 = 0x140000, + .kcan_ch1 = 0x142000, +}; + static const struct kvaser_pciefd_irq_mask kvaser_pciefd_altera_irq_mask = { .kcan_rx0 = BIT(4), .kcan_tx = { BIT(0), BIT(1), BIT(2), BIT(3) }, @@ -347,6 +367,12 @@ static const struct kvaser_pciefd_irq_mask kvaser_pciefd_sf2_irq_mask = { .all = GENMASK(19, 16) | BIT(4), }; +static const struct kvaser_pciefd_irq_mask kvaser_pciefd_xilinx_irq_mask = { + .kcan_rx0 = BIT(4), + .kcan_tx = { BIT(16), BIT(17), BIT(18), BIT(19) }, + .all = GENMASK(19, 16) | BIT(4), +}; + static const struct kvaser_pciefd_dev_ops kvaser_pciefd_altera_dev_ops = { .kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_altera, }; @@ -355,6 +381,10 @@ static const struct kvaser_pciefd_dev_ops kvaser_pciefd_sf2_dev_ops = { .kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_sf2, }; +static const struct kvaser_pciefd_dev_ops kvaser_pciefd_xilinx_dev_ops = { + .kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_xilinx, +}; + static const struct kvaser_pciefd_driver_data kvaser_pciefd_altera_driver_data = { .address_offset = &kvaser_pciefd_altera_address_offset, .irq_mask = &kvaser_pciefd_altera_irq_mask, @@ -367,6 +397,12 @@ static const struct kvaser_pciefd_driver_data kvaser_pciefd_sf2_driver_data = { .ops = &kvaser_pciefd_sf2_dev_ops, }; +static const struct kvaser_pciefd_driver_data kvaser_pciefd_xilinx_driver_data = { + .address_offset = &kvaser_pciefd_xilinx_address_offset, + .irq_mask = &kvaser_pciefd_xilinx_irq_mask, + .ops = &kvaser_pciefd_xilinx_dev_ops, +}; + struct kvaser_pciefd_can { struct can_priv can; struct kvaser_pciefd *kv_pcie; @@ -456,6 +492,10 @@ static struct pci_device_id kvaser_pciefd_id_table[] = { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID), .driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data, }, + { + PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_M2_4CAN_DEVICE_ID), + .driver_data = (kernel_ulong_t)&kvaser_pciefd_xilinx_driver_data, + }, { 0, }, @@ -1035,6 +1075,21 @@ static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie, iowrite32(msb, serdes_base + 0x4); } +static void kvaser_pciefd_write_dma_map_xilinx(struct kvaser_pciefd *pcie, + dma_addr_t addr, int index) +{ + void __iomem *serdes_base; + u32 lsb = addr & KVASER_PCIEFD_XILINX_DMA_LSB_MASK; + u32 msb = 0x0; + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + msb = addr >> 32; +#endif + serdes_base = KVASER_PCIEFD_SERDES_ADDR(pcie) + 0x8 * index; + iowrite32(msb, serdes_base); + iowrite32(lsb, serdes_base + 0x4); +} + static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) { int i; From 383de5664c87abe097d6369d18305c3a6e559bb2 Mon Sep 17 00:00:00 2001 From: Daniil Dulov Date: Sun, 11 Feb 2024 07:05:35 -0800 Subject: [PATCH 1121/2255] can: softing: remove redundant NULL check In this case dev cannot be NULL, so remove redundant check. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 03fd3cf5a179 ("can: add driver for Softing card") Signed-off-by: Daniil Dulov Link: https://lore.kernel.org/all/20240211150535.3529-1-d.dulov@aladdin.ru Signed-off-by: Marc Kleine-Budde --- drivers/net/can/softing/softing_fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c index 32286f861a19..721df91cdbfb 100644 --- a/drivers/net/can/softing/softing_fw.c +++ b/drivers/net/can/softing/softing_fw.c @@ -436,7 +436,7 @@ int softing_startstop(struct net_device *dev, int up) return ret; bus_bitmask_start = 0; - if (dev && up) + if (up) /* prepare to start this bus as well */ bus_bitmask_start |= (1 << priv->index); /* bring netdevs down */ From f64e189442332f198cea239eee4da6f72465059e Mon Sep 17 00:00:00 2001 From: Grzegorz Nitka Date: Wed, 6 Dec 2023 20:29:17 +0100 Subject: [PATCH 1122/2255] ice: introduce new E825C devices family Introduce new Intel Ethernet E825C family devices. Add new PCI device IDs which are going to be supported by the driver: - 579C: Intel(R) Ethernet Connection E825-C for backplane - 579D: Intel(R) Ethernet Connection E825-C for QSFP - 579E: Intel(R) Ethernet Connection E825-C for SFP - 579F: Intel(R) Ethernet Connection E825-C for SGMII Add helper function ice_is_e825c() to verify if the running device belongs to E825C family. Co-developed-by: Jan Glaza Signed-off-by: Jan Glaza Co-developed-by: Michal Michalik Signed-off-by: Michal Michalik Signed-off-by: Grzegorz Nitka Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 19 +++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 1 + drivers/net/ethernet/intel/ice/ice_devids.h | 8 ++++++++ drivers/net/ethernet/intel/ice/ice_main.c | 4 ++++ 4 files changed, 32 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 10c32cd80fff..cc8c9f2b72f5 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -240,6 +240,25 @@ bool ice_is_e823(struct ice_hw *hw) } } +/** + * ice_is_e825c - Check if a device is E825C family device + * @hw: pointer to the hardware structure + * + * Return: true if the device is E825-C based, false if not. + */ +bool ice_is_e825c(struct ice_hw *hw) +{ + switch (hw->device_id) { + case ICE_DEV_ID_E825C_BACKPLANE: + case ICE_DEV_ID_E825C_QSFP: + case ICE_DEV_ID_E825C_SFP: + case ICE_DEV_ID_E825C_SGMII: + return true; + default: + return false; + } +} + /** * ice_clear_pf_cfg - Clear PF configuration * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 3e933f75e948..42d45a73359c 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -251,6 +251,7 @@ ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat); bool ice_is_e810t(struct ice_hw *hw); bool ice_is_e823(struct ice_hw *hw); +bool ice_is_e825c(struct ice_hw *hw); int ice_sched_query_elem(struct ice_hw *hw, u32 node_teid, struct ice_aqc_txsched_elem_data *buf); diff --git a/drivers/net/ethernet/intel/ice/ice_devids.h b/drivers/net/ethernet/intel/ice/ice_devids.h index a2d384dbfc76..9dfae9bce758 100644 --- a/drivers/net/ethernet/intel/ice/ice_devids.h +++ b/drivers/net/ethernet/intel/ice/ice_devids.h @@ -71,5 +71,13 @@ #define ICE_DEV_ID_E822L_10G_BASE_T 0x1899 /* Intel(R) Ethernet Connection E822-L 1GbE */ #define ICE_DEV_ID_E822L_SGMII 0x189A +/* Intel(R) Ethernet Connection E825-C for backplane */ +#define ICE_DEV_ID_E825C_BACKPLANE 0x579c +/* Intel(R) Ethernet Connection E825-C for QSFP */ +#define ICE_DEV_ID_E825C_QSFP 0x579d +/* Intel(R) Ethernet Connection E825-C for SFP */ +#define ICE_DEV_ID_E825C_SFP 0x579e +/* Intel(R) Ethernet Connection E825-C 1GbE */ +#define ICE_DEV_ID_E825C_SGMII 0x579f #endif /* _ICE_DEVIDS_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 2b7960824bc3..b3c24e40ccb6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -5752,6 +5752,10 @@ static const struct pci_device_id ice_pci_tbl[] = { { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE) }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP) }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822_SI_DFLT) }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E825C_BACKPLANE), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E825C_QSFP), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E825C_SFP), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E825C_SGMII), }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E830_BACKPLANE) }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E830_QSFP56) }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E830_SFP) }, From 7a15668f665c014f345761fdc283051b97a48e00 Mon Sep 17 00:00:00 2001 From: Grzegorz Nitka Date: Wed, 6 Dec 2023 20:29:18 +0100 Subject: [PATCH 1123/2255] ice: Add helper function ice_is_generic_mac E800 series devices have a couple of quirks: 1. Sideband control queues are not supported 2. The registers that the driver needs to program for the "Precision Time Protocol (PTP)" feature are different for E800 series devices compared to other devices supported by this driver. Both these require conditional logic based on the underlying device we are dealing with. The function ice_is_sbq_supported added by commit 8f5ee3c477a8 ("ice: add support for sideband messages") addresses (1). The same function can be used to address (2) as well but this just looks weird readability wise in cases that have nothing to do with sideband control queues: if (ice_is_sbq_supported(hw)) /* program register A */ else /* program register B */ For these cases, the function ice_is_generic_mac introduced by this patch communicates the idea/intention better. Also rework ice_is_sbq_supported to use this new function. As side-band queue is supported for E825C devices, it's mac_type is considered as generic mac_type. Co-developed-by: Anirudh Venkataramanan Signed-off-by: Anirudh Venkataramanan Signed-off-by: Grzegorz Nitka Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 12 ++++++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 1 + drivers/net/ethernet/intel/ice/ice_controlq.c | 2 +- drivers/net/ethernet/intel/ice/ice_main.c | 6 ++++-- drivers/net/ethernet/intel/ice/ice_type.h | 1 + 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index cc8c9f2b72f5..a7e6e5c1d06e 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -169,6 +169,18 @@ static int ice_set_mac_type(struct ice_hw *hw) return 0; } +/** + * ice_is_generic_mac - check if device's mac_type is generic + * @hw: pointer to the hardware structure + * + * Return: true if mac_type is generic (with SBQ support), false if not + */ +bool ice_is_generic_mac(struct ice_hw *hw) +{ + return (hw->mac_type == ICE_MAC_GENERIC || + hw->mac_type == ICE_MAC_GENERIC_3K_E825); +} + /** * ice_is_e810 * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 42d45a73359c..32fd10de620c 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -112,6 +112,7 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, int ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags, struct ice_sq_cd *cd); +bool ice_is_generic_mac(struct ice_hw *hw); bool ice_is_e810(struct ice_hw *hw); int ice_clear_pf_cfg(struct ice_hw *hw); int diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index e7d2474c431c..ffe660f34992 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -666,7 +666,7 @@ bool ice_is_sbq_supported(struct ice_hw *hw) /* The device sideband queue is only supported on devices with the * generic MAC type. */ - return hw->mac_type == ICE_MAC_GENERIC; + return ice_is_generic_mac(hw); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b3c24e40ccb6..1fa3f40743f5 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1649,8 +1649,10 @@ static void ice_clean_sbq_subtask(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; - /* Nothing to do here if sideband queue is not supported */ - if (!ice_is_sbq_supported(hw)) { + /* if mac_type is not generic, sideband is not supported + * and there's nothing to do here + */ + if (!ice_is_generic_mac(hw)) { clear_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state); return; } diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index a508e917ce5f..9ff92dba5823 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -132,6 +132,7 @@ enum ice_mac_type { ICE_MAC_E810, ICE_MAC_E830, ICE_MAC_GENERIC, + ICE_MAC_GENERIC_3K_E825, }; /* Media Types */ From 372e27de4ca8e5f22586198cd9429bfea75021ac Mon Sep 17 00:00:00 2001 From: Grzegorz Nitka Date: Wed, 6 Dec 2023 20:29:19 +0100 Subject: [PATCH 1124/2255] ice: add support for 3k signing DDP sections for E825C E825C devices shall support the new signing type of RSA 3K for new DDP section (SEGMENT_SIGN_TYPE_RSA3K_E825 (5) - already in the code). The driver is responsible to verify the presence of correct signing type. Add 3k signinig support for E825C devices based on mac_type: ICE_MAC_GENERIC_3K_E825; Signed-off-by: Grzegorz Nitka Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 6 ++++++ drivers/net/ethernet/intel/ice/ice_ddp.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index a7e6e5c1d06e..9266f25a9978 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -154,6 +154,12 @@ static int ice_set_mac_type(struct ice_hw *hw) case ICE_DEV_ID_E823L_SFP: hw->mac_type = ICE_MAC_GENERIC; break; + case ICE_DEV_ID_E825C_BACKPLANE: + case ICE_DEV_ID_E825C_QSFP: + case ICE_DEV_ID_E825C_SFP: + case ICE_DEV_ID_E825C_SGMII: + hw->mac_type = ICE_MAC_GENERIC_3K_E825; + break; case ICE_DEV_ID_E830_BACKPLANE: case ICE_DEV_ID_E830_QSFP56: case ICE_DEV_ID_E830_SFP: diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.c b/drivers/net/ethernet/intel/ice/ice_ddp.c index 8b7504a9df31..7532d11ad7f3 100644 --- a/drivers/net/ethernet/intel/ice/ice_ddp.c +++ b/drivers/net/ethernet/intel/ice/ice_ddp.c @@ -1825,6 +1825,7 @@ static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type) seg_id = SEGMENT_TYPE_ICE_E830; break; case ICE_MAC_GENERIC: + case ICE_MAC_GENERIC_3K_E825: default: seg_id = SEGMENT_TYPE_ICE_E810; break; @@ -1845,6 +1846,9 @@ static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type) case ICE_MAC_E830: sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB; break; + case ICE_MAC_GENERIC_3K_E825: + sign_type = SEGMENT_SIGN_TYPE_RSA3K_E825; + break; case ICE_MAC_GENERIC: default: sign_type = SEGMENT_SIGN_TYPE_RSA2K; From 41cc4e53934c30f1cf7745c257154e538c78a1f5 Mon Sep 17 00:00:00 2001 From: Wojciech Drewek Date: Mon, 5 Feb 2024 14:03:56 +0100 Subject: [PATCH 1125/2255] ice: Remove and readd netdev during devlink reload Recent changes to the devlink reload (commit 9b2348e2d6c9 ("devlink: warn about existing entities during reload-reinit")) force the drivers to destroy devlink ports during reinit. Adjust ice driver to this requirement, unregister netdvice, destroy devlink port. ice_init_eth() was removed and all the common code between probe and reload was moved to ice_load(). During devlink reload we can't take devl_lock (it's already taken) and in ice_probe() we have to lock it. Use devl_* variant of the API which does not acquire and release devl_lock. Guard ice_load() with devl_lock only in case of probe. Suggested-by: Jiri Pirko Reviewed-by: Przemek Kitszel Reviewed-by: Vadim Fedorenko Reviewed-by: Simon Horman Reviewed-by: Brett Creeley Signed-off-by: Wojciech Drewek Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 2 + drivers/net/ethernet/intel/ice/ice_devlink.c | 68 ++++++- drivers/net/ethernet/intel/ice/ice_main.c | 190 ++++++------------- 3 files changed, 127 insertions(+), 133 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index a4ba60e17d0b..118e84835720 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -983,6 +983,8 @@ void ice_service_task_schedule(struct ice_pf *pf); int ice_load(struct ice_pf *pf); void ice_unload(struct ice_pf *pf); void ice_adv_lnk_speed_maps_init(void); +int ice_init_dev(struct ice_pf *pf); +void ice_deinit_dev(struct ice_pf *pf); /** * ice_set_rdma_cap - enable RDMA support diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 65be56f2af9e..b516e42b41f0 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -444,6 +444,20 @@ ice_devlink_reload_empr_start(struct ice_pf *pf, return 0; } +/** + * ice_devlink_reinit_down - unload given PF + * @pf: pointer to the PF struct + */ +static void ice_devlink_reinit_down(struct ice_pf *pf) +{ + /* No need to take devl_lock, it's already taken by devlink API */ + ice_unload(pf); + rtnl_lock(); + ice_vsi_decfg(ice_get_main_vsi(pf)); + rtnl_unlock(); + ice_deinit_dev(pf); +} + /** * ice_devlink_reload_down - prepare for reload * @devlink: pointer to the devlink instance to reload @@ -477,7 +491,7 @@ ice_devlink_reload_down(struct devlink *devlink, bool netns_change, "Remove all VFs before doing reinit\n"); return -EOPNOTSUPP; } - ice_unload(pf); + ice_devlink_reinit_down(pf); return 0; case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: return ice_devlink_reload_empr_start(pf, extack); @@ -1269,6 +1283,45 @@ static int ice_devlink_set_parent(struct devlink_rate *devlink_rate, return status; } +/** + * ice_devlink_reinit_up - do reinit of the given PF + * @pf: pointer to the PF struct + */ +static int ice_devlink_reinit_up(struct ice_pf *pf) +{ + struct ice_vsi *vsi = ice_get_main_vsi(pf); + struct ice_vsi_cfg_params params; + int err; + + err = ice_init_dev(pf); + if (err) + return err; + + params = ice_vsi_to_params(vsi); + params.flags = ICE_VSI_FLAG_INIT; + + rtnl_lock(); + err = ice_vsi_cfg(vsi, ¶ms); + rtnl_unlock(); + if (err) + goto err_vsi_cfg; + + /* No need to take devl_lock, it's already taken by devlink API */ + err = ice_load(pf); + if (err) + goto err_load; + + return 0; + +err_load: + rtnl_lock(); + ice_vsi_decfg(vsi); + rtnl_unlock(); +err_vsi_cfg: + ice_deinit_dev(pf); + return err; +} + /** * ice_devlink_reload_up - do reload up after reinit * @devlink: pointer to the devlink instance reloading @@ -1289,7 +1342,7 @@ ice_devlink_reload_up(struct devlink *devlink, switch (action) { case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); - return ice_load(pf); + return ice_devlink_reinit_up(pf); case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: *actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE); return ice_devlink_reload_empr_finish(pf, extack); @@ -1569,6 +1622,7 @@ static const struct devlink_port_ops ice_devlink_port_ops = { * @pf: the PF to create a devlink port for * * Create and register a devlink_port for this PF. + * This function has to be called under devl_lock. * * Return: zero on success or an error code on failure. */ @@ -1581,6 +1635,8 @@ int ice_devlink_create_pf_port(struct ice_pf *pf) struct device *dev; int err; + devlink = priv_to_devlink(pf); + dev = ice_pf_to_dev(pf); devlink_port = &pf->devlink_port; @@ -1601,10 +1657,9 @@ int ice_devlink_create_pf_port(struct ice_pf *pf) ice_devlink_set_switch_id(pf, &attrs.switch_id); devlink_port_attrs_set(devlink_port, &attrs); - devlink = priv_to_devlink(pf); - err = devlink_port_register_with_ops(devlink, devlink_port, vsi->idx, - &ice_devlink_port_ops); + err = devl_port_register_with_ops(devlink, devlink_port, vsi->idx, + &ice_devlink_port_ops); if (err) { dev_err(dev, "Failed to create devlink port for PF %d, error %d\n", pf->hw.pf_id, err); @@ -1619,10 +1674,11 @@ int ice_devlink_create_pf_port(struct ice_pf *pf) * @pf: the PF to cleanup * * Unregisters the devlink_port structure associated with this PF. + * This function has to be called under devl_lock. */ void ice_devlink_destroy_pf_port(struct ice_pf *pf) { - devlink_port_unregister(&pf->devlink_port); + devl_port_unregister(&pf->devlink_port); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 1fa3f40743f5..85a996ad2c1f 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4574,90 +4574,6 @@ static void ice_decfg_netdev(struct ice_vsi *vsi) vsi->netdev = NULL; } -static int ice_start_eth(struct ice_vsi *vsi) -{ - int err; - - err = ice_init_mac_fltr(vsi->back); - if (err) - return err; - - err = ice_vsi_open(vsi); - if (err) - ice_fltr_remove_all(vsi); - - return err; -} - -static void ice_stop_eth(struct ice_vsi *vsi) -{ - ice_fltr_remove_all(vsi); - ice_vsi_close(vsi); -} - -static int ice_init_eth(struct ice_pf *pf) -{ - struct ice_vsi *vsi = ice_get_main_vsi(pf); - int err; - - if (!vsi) - return -EINVAL; - - /* init channel list */ - INIT_LIST_HEAD(&vsi->ch_list); - - err = ice_cfg_netdev(vsi); - if (err) - return err; - /* Setup DCB netlink interface */ - ice_dcbnl_setup(vsi); - - err = ice_init_mac_fltr(pf); - if (err) - goto err_init_mac_fltr; - - err = ice_devlink_create_pf_port(pf); - if (err) - goto err_devlink_create_pf_port; - - SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port); - - err = ice_register_netdev(vsi); - if (err) - goto err_register_netdev; - - err = ice_tc_indir_block_register(vsi); - if (err) - goto err_tc_indir_block_register; - - ice_napi_add(vsi); - - return 0; - -err_tc_indir_block_register: - ice_unregister_netdev(vsi); -err_register_netdev: - ice_devlink_destroy_pf_port(pf); -err_devlink_create_pf_port: -err_init_mac_fltr: - ice_decfg_netdev(vsi); - return err; -} - -static void ice_deinit_eth(struct ice_pf *pf) -{ - struct ice_vsi *vsi = ice_get_main_vsi(pf); - - if (!vsi) - return; - - ice_vsi_close(vsi); - ice_unregister_netdev(vsi); - ice_devlink_destroy_pf_port(pf); - ice_tc_indir_block_unregister(vsi); - ice_decfg_netdev(vsi); -} - /** * ice_wait_for_fw - wait for full FW readiness * @hw: pointer to the hardware structure @@ -4683,7 +4599,7 @@ static int ice_wait_for_fw(struct ice_hw *hw, u32 timeout) return -ETIMEDOUT; } -static int ice_init_dev(struct ice_pf *pf) +int ice_init_dev(struct ice_pf *pf) { struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; @@ -4776,7 +4692,7 @@ err_init_pf: return err; } -static void ice_deinit_dev(struct ice_pf *pf) +void ice_deinit_dev(struct ice_pf *pf) { ice_free_irq_msix_misc(pf); ice_deinit_pf(pf); @@ -5081,31 +4997,47 @@ static void ice_deinit(struct ice_pf *pf) /** * ice_load - load pf by init hw and starting VSI * @pf: pointer to the pf instance + * + * This function has to be called under devl_lock. */ int ice_load(struct ice_pf *pf) { - struct ice_vsi_cfg_params params = {}; struct ice_vsi *vsi; int err; - err = ice_init_dev(pf); - if (err) - return err; + devl_assert_locked(priv_to_devlink(pf)); vsi = ice_get_main_vsi(pf); - params = ice_vsi_to_params(vsi); - params.flags = ICE_VSI_FLAG_INIT; + /* init channel list */ + INIT_LIST_HEAD(&vsi->ch_list); - rtnl_lock(); - err = ice_vsi_cfg(vsi, ¶ms); + err = ice_cfg_netdev(vsi); if (err) - goto err_vsi_cfg; + return err; - err = ice_start_eth(ice_get_main_vsi(pf)); + /* Setup DCB netlink interface */ + ice_dcbnl_setup(vsi); + + err = ice_init_mac_fltr(pf); if (err) - goto err_start_eth; - rtnl_unlock(); + goto err_init_mac_fltr; + + err = ice_devlink_create_pf_port(pf); + if (err) + goto err_devlink_create_pf_port; + + SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port); + + err = ice_register_netdev(vsi); + if (err) + goto err_register_netdev; + + err = ice_tc_indir_block_register(vsi); + if (err) + goto err_tc_indir_block_register; + + ice_napi_add(vsi); err = ice_init_rdma(pf); if (err) @@ -5119,29 +5051,35 @@ int ice_load(struct ice_pf *pf) return 0; err_init_rdma: - ice_vsi_close(ice_get_main_vsi(pf)); - rtnl_lock(); -err_start_eth: - ice_vsi_decfg(ice_get_main_vsi(pf)); -err_vsi_cfg: - rtnl_unlock(); - ice_deinit_dev(pf); + ice_tc_indir_block_unregister(vsi); +err_tc_indir_block_register: + ice_unregister_netdev(vsi); +err_register_netdev: + ice_devlink_destroy_pf_port(pf); +err_devlink_create_pf_port: +err_init_mac_fltr: + ice_decfg_netdev(vsi); return err; } /** * ice_unload - unload pf by stopping VSI and deinit hw * @pf: pointer to the pf instance + * + * This function has to be called under devl_lock. */ void ice_unload(struct ice_pf *pf) { + struct ice_vsi *vsi = ice_get_main_vsi(pf); + + devl_assert_locked(priv_to_devlink(pf)); + ice_deinit_features(pf); ice_deinit_rdma(pf); - rtnl_lock(); - ice_stop_eth(ice_get_main_vsi(pf)); - ice_vsi_decfg(ice_get_main_vsi(pf)); - rtnl_unlock(); - ice_deinit_dev(pf); + ice_tc_indir_block_unregister(vsi); + ice_unregister_netdev(vsi); + ice_devlink_destroy_pf_port(pf); + ice_decfg_netdev(vsi); } /** @@ -5239,27 +5177,23 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) if (err) goto err_init; - err = ice_init_eth(pf); + devl_lock(priv_to_devlink(pf)); + err = ice_load(pf); + devl_unlock(priv_to_devlink(pf)); if (err) - goto err_init_eth; - - err = ice_init_rdma(pf); - if (err) - goto err_init_rdma; + goto err_load; err = ice_init_devlink(pf); if (err) goto err_init_devlink; - ice_init_features(pf); - return 0; err_init_devlink: - ice_deinit_rdma(pf); -err_init_rdma: - ice_deinit_eth(pf); -err_init_eth: + devl_lock(priv_to_devlink(pf)); + ice_unload(pf); + devl_unlock(priv_to_devlink(pf)); +err_load: ice_deinit(pf); err_init: pci_disable_device(pdev); @@ -5357,12 +5291,14 @@ static void ice_remove(struct pci_dev *pdev) if (!ice_is_safe_mode(pf)) ice_remove_arfs(pf); - ice_deinit_features(pf); - ice_deinit_devlink(pf); - ice_deinit_rdma(pf); - ice_deinit_eth(pf); - ice_deinit(pf); + ice_deinit_devlink(pf); + + devl_lock(priv_to_devlink(pf)); + ice_unload(pf); + devl_unlock(priv_to_devlink(pf)); + + ice_deinit(pf); ice_vsi_release_all(pf); ice_setup_mc_magic_wake(pf); From 500d0df5b4b2394a06b949bab05f7ed0242b9858 Mon Sep 17 00:00:00 2001 From: Wojciech Drewek Date: Mon, 5 Feb 2024 14:03:57 +0100 Subject: [PATCH 1126/2255] ice: Fix debugfs with devlink reload During devlink reload it is needed to remove debugfs entries correlated with only one PF. ice_debugfs_exit() removes all entries created by ice driver so we can't use it. Introduce ice_debugfs_pf_deinit() in order to release PF's debugfs entries. Move ice_debugfs_exit() call to ice_module_exit(), it makes more sense since ice_debugfs_init() is called in ice_module_init() and not in ice_probe(). Signed-off-by: Wojciech Drewek Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Reviewed-by: Brett Creeley Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_debugfs.c | 10 ++++++++++ drivers/net/ethernet/intel/ice/ice_fwlog.c | 2 ++ drivers/net/ethernet/intel/ice/ice_main.c | 3 +-- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 118e84835720..365c03d1c462 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -896,6 +896,7 @@ static inline bool ice_is_adq_active(struct ice_pf *pf) } void ice_debugfs_fwlog_init(struct ice_pf *pf); +void ice_debugfs_pf_deinit(struct ice_pf *pf); void ice_debugfs_init(void); void ice_debugfs_exit(void); void ice_pf_fwlog_update_module(struct ice_pf *pf, int log_level, int module); diff --git a/drivers/net/ethernet/intel/ice/ice_debugfs.c b/drivers/net/ethernet/intel/ice/ice_debugfs.c index 85aa31dd86b1..d252d98218d0 100644 --- a/drivers/net/ethernet/intel/ice/ice_debugfs.c +++ b/drivers/net/ethernet/intel/ice/ice_debugfs.c @@ -644,6 +644,16 @@ err_create_module_files: kfree(fw_modules); } +/** + * ice_debugfs_pf_deinit - cleanup PF's debugfs + * @pf: pointer to the PF struct + */ +void ice_debugfs_pf_deinit(struct ice_pf *pf) +{ + debugfs_remove_recursive(pf->ice_debugfs_pf); + pf->ice_debugfs_pf = NULL; +} + /** * ice_debugfs_init - create root directory for debugfs entries */ diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.c b/drivers/net/ethernet/intel/ice/ice_fwlog.c index 92b5dac481cd..4fd15387a7e5 100644 --- a/drivers/net/ethernet/intel/ice/ice_fwlog.c +++ b/drivers/net/ethernet/intel/ice/ice_fwlog.c @@ -188,6 +188,8 @@ void ice_fwlog_deinit(struct ice_hw *hw) if (hw->bus.func) return; + ice_debugfs_pf_deinit(hw->back); + /* make sure FW logging is disabled to not put the FW in a weird state * for the next driver load */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 85a996ad2c1f..9c2c8637b4a7 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -5276,8 +5276,6 @@ static void ice_remove(struct pci_dev *pdev) msleep(100); } - ice_debugfs_exit(); - if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) { set_bit(ICE_VF_RESETS_DISABLED, pf->state); ice_free_vfs(pf); @@ -5783,6 +5781,7 @@ module_init(ice_module_init); static void __exit ice_module_exit(void) { pci_unregister_driver(&ice_driver); + ice_debugfs_exit(); destroy_workqueue(ice_wq); destroy_workqueue(ice_lag_wq); pr_info("module unloaded\n"); From 6f656131f6988709e3bf828c3ad992032b717c2e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 8 Feb 2024 12:01:43 +0100 Subject: [PATCH 1127/2255] 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(-) 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)); } } From f6ca96aa51a4ae1b3a416fbe85acdf1197c405a6 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 5 Feb 2024 21:59:50 +0530 Subject: [PATCH 1128/2255] wifi: cfg80211: add support for link id attribute in NL80211_CMD_DEL_STATION Currently whenever NL80211_CMD_DEL_STATION command is called without any MAC address, all stations present on that interface are flushed. However with MLO there is a need to flush such stations only which are using at least a particular link from the AP MLD interface. For example - 2 GHz and 5 GHz are part of an AP MLD. To this interface, following stations are connected - 1. One non-EHT STA on 2 GHz link. 2. One non-EHT STA on 5 GHz link. 3. One Multi-Link STA having 2 GHz and 5 GHz as active links. Now if currently, NL80211_CMD_DEL_STATION is issued by the 2 GHz link without any MAC address, it would flush all station entries. However, flushing of station entry #2 at least is not desireable since it is connected to 5 GHz link alone. Hence, add an option to pass link ID as well in the command so that if link ID is passed, stations using that passed link ID alone would be flushed and others will not. So after this, station entries #1 and #3 alone would be flushed and #2 will remain as it is. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240205162952.1697646-2-quic_adisi@quicinc.com [clarify documentation] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 3 ++- net/wireless/nl80211.c | 19 ++++++++++++++++++- net/wireless/trace.h | 7 +++++-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f52f989a54ad..62894b024e88 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1780,11 +1780,15 @@ struct station_parameters { * @subtype: Management frame subtype to use for indicating removal * (10 = Disassociation, 12 = Deauthentication) * @reason_code: Reason code for the Disassociation/Deauthentication frame + * @link_id: Link ID indicating a link that stations to be flushed must be + * using; valid only for MLO, but can also be -1 for MLO to really + * remove all stations. */ struct station_del_parameters { const u8 *mac; u8 subtype; u16 reason_code; + int link_id; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 853ac538a686..805bfe712971 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -438,7 +438,8 @@ * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type * of disconnection indication should be sent to the station * (Deauthentication or Disassociation frame and reason code for that - * frame). + * frame). %NL80211_ATTR_MLO_LINK_ID can be used optionally to remove + * stations connected and using at least that link as one of its links. * * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to * destination %NL80211_ATTR_MAC on the interface identified by diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e1106ae35e21..5ca545753810 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7624,14 +7624,16 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; struct station_del_parameters params; + int link_id = nl80211_link_id_or_invalid(info->attrs); memset(¶ms, 0, sizeof(params)); if (info->attrs[NL80211_ATTR_MAC]) params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]); - switch (dev->ieee80211_ptr->iftype) { + switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MESH_POINT: @@ -7672,6 +7674,17 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID; } + /* Link ID not expected in case of non-ML operation */ + if (!wdev->valid_links && link_id != -1) + return -EINVAL; + + /* If given, a valid link ID should be passed during MLO */ + if (wdev->valid_links && link_id >= 0 && + !(wdev->valid_links & BIT(link_id))) + return -EINVAL; + + params.link_id = link_id; + return rdev_del_station(rdev, dev, ¶ms); } @@ -16773,6 +16786,10 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_del_station, .flags = GENL_UNS_ADMIN_PERM, + /* cannot use NL80211_FLAG_MLO_VALID_LINK_ID, depends on + * whether MAC address is passed or not. If MAC address is + * passed, then even during MLO, link ID is not required. + */ .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), }, { diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 194ea2471717..361331c29116 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -867,6 +867,7 @@ DECLARE_EVENT_CLASS(station_del, MAC_ENTRY(sta_mac) __field(u8, subtype) __field(u16, reason_code) + __field(int, link_id) ), TP_fast_assign( WIPHY_ASSIGN; @@ -874,11 +875,13 @@ DECLARE_EVENT_CLASS(station_del, MAC_ASSIGN(sta_mac, params->mac); __entry->subtype = params->subtype; __entry->reason_code = params->reason_code; + __entry->link_id = params->link_id; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: %pM" - ", subtype: %u, reason_code: %u", + ", subtype: %u, reason_code: %u, link_id: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sta_mac, - __entry->subtype, __entry->reason_code) + __entry->subtype, __entry->reason_code, + __entry->link_id) ); DEFINE_EVENT(station_del, rdev_del_station, From ec67d6e0d491d2a2df270ddcb7aa44db0984e11c Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 5 Feb 2024 21:59:51 +0530 Subject: [PATCH 1129/2255] wifi: mac80211: flush only stations using requests links Whenever sta_flush() function is invoked, all STAs present in that interface are flushed. In case of MLO, it is desirable to only flush such STAs that are at least using a given link id as one of their links. Add support for this by making change in the __sta_info_flush API argument to accept a link ID. And then, only if the STA is using the given link as one of its links, it would be flushed. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240205162952.1697646-3-quic_adisi@quicinc.com [reword commit message, in particular this isn't about "active" links] Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 4 ++-- net/mac80211/ibss.c | 4 ++-- net/mac80211/iface.c | 2 +- net/mac80211/mesh.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/ocb.c | 2 +- net/mac80211/sta_info.c | 21 ++++++++++++++------- net/mac80211/sta_info.h | 14 +++++++++++--- 8 files changed, 33 insertions(+), 18 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6f7c96c358f4..41fca30c896e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1616,7 +1616,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, link_conf->ema_ap = false; link_conf->bssid_indicator = 0; - __sta_info_flush(sdata, true); + __sta_info_flush(sdata, true, -1); ieee80211_free_keys(sdata, true); link_conf->enable_beacon = false; @@ -2096,7 +2096,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, if (params->mac) return sta_info_destroy_addr_bss(sdata, params->mac); - sta_info_flush(sdata); + sta_info_flush(sdata, params->link_id); return 0; } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 27cc9ddd0432..7ace5cdc6c26 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -237,7 +237,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, drv_reset_tsf(local, sdata); if (!ether_addr_equal(ifibss->bssid, bssid)) - sta_info_flush(sdata); + sta_info_flush(sdata, -1); /* if merging, indicate to driver that we leave the old IBSS */ if (sdata->vif.cfg.ibss_joined) { @@ -682,7 +682,7 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) ifibss->state = IEEE80211_IBSS_MLME_SEARCH; - sta_info_flush(sdata); + sta_info_flush(sdata, -1); spin_lock_bh(&ifibss->incomplete_lock); while (!list_empty(&ifibss->incomplete_stations)) { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 227c8dc3fbe5..b75b83a5142b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -511,7 +511,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do * would have removed them, but in other modes there shouldn't * be any stations. */ - flushed = sta_info_flush(sdata); + flushed = sta_info_flush(sdata, -1); WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && flushed > 0); /* don't count this interface for allmulti while it is down */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 49f79512c144..32475da98d73 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1214,7 +1214,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) netif_carrier_off(sdata->dev); /* flush STAs and mpaths on this iface */ - sta_info_flush(sdata); + sta_info_flush(sdata, -1); ieee80211_free_keys(sdata, true); mesh_path_flush_by_iface(sdata); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dd97f402a624..e1554666d706 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3151,7 +3151,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sdata->vif.cfg.ssid_len = 0; /* remove AP and TDLS peers */ - sta_info_flush(sdata); + sta_info_flush(sdata, -1); /* finally reset all BSS / config parameters */ if (!ieee80211_vif_is_mld(&sdata->vif)) diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index 2dd4a2196af4..9ef14e475c90 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -208,7 +208,7 @@ int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) lockdep_assert_wiphy(sdata->local->hw.wiphy); ifocb->joined = false; - sta_info_flush(sdata); + sta_info_flush(sdata, -1); spin_lock_bh(&ifocb->incomplete_lock); while (!list_empty(&ifocb->incomplete_stations)) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4391d8dd634b..da5fdd6f5c85 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1566,7 +1566,8 @@ void sta_info_stop(struct ieee80211_local *local) } -int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans) +int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans, + int link_id) { struct ieee80211_local *local = sdata->local; struct sta_info *sta, *tmp; @@ -1580,12 +1581,18 @@ int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans) WARN_ON(vlans && !sdata->bss); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - if (sdata == sta->sdata || - (vlans && sdata->bss == sta->sdata->bss)) { - if (!WARN_ON(__sta_info_destroy_part1(sta))) - list_add(&sta->free_list, &free_list); - ret++; - } + if (sdata != sta->sdata && + (!vlans || sdata->bss != sta->sdata->bss)) + continue; + + if (link_id >= 0 && sta->sta.valid_links && + !(sta->sta.valid_links & BIT(link_id))) + continue; + + if (!WARN_ON(__sta_info_destroy_part1(sta))) + list_add(&sta->free_list, &free_list); + + ret++; } if (!list_empty(&free_list)) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5ef1554f991f..f03731a5bbee 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -886,8 +886,12 @@ void sta_info_stop(struct ieee80211_local *local); * * @sdata: sdata to remove all stations from * @vlans: if the given interface is an AP interface, also flush VLANs + * @link_id: if given (>=0), all those STA entries using @link_id only + * will be removed. If -1 is passed, all STA entries will be + * removed. */ -int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans); +int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans, + int link_id); /** * sta_info_flush - flush matching STA entries from the STA table @@ -895,10 +899,14 @@ int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans); * Returns the number of removed STA entries. * * @sdata: sdata to remove all stations from + * @link_id: if given (>=0), all those STA entries using @link_id only + * will be removed. If -1 is passed, all STA entries will be + * removed. */ -static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata) +static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata, + int link_id) { - return __sta_info_flush(sdata, false); + return __sta_info_flush(sdata, false, link_id); } void sta_set_rate_info_tx(struct sta_info *sta, From 16405bd7fd2ea8553bc87a5aa9720e3014e91df6 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 5 Feb 2024 21:59:52 +0530 Subject: [PATCH 1130/2255] wifi: mac80211: remove only own link stations during stop_ap Currently, whenever AP link is brought down via ieee80211_stop_ap() function, all stations connected to the sdata are flushed. However, in case of MLO there is a requirement to flush only stations connected to that link and not all. For instance - Consider 2 GHz and 5 GHz are AP MLD. Now due to some reason 5 GHz link of this AP is going down (link removal or any other case). All stations connected, even legacy stations connected to 2 GHz link AP would also be flushed. Flushing of other link stations is not desirable. Fix this issue by passing self link ID to sta_flush() function. This would then only remove the stations which are still using the passed link ID as their link sta. Other stations will not be affected. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240205162952.1697646-4-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 41fca30c896e..0744113f3535 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1616,7 +1616,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, link_conf->ema_ap = false; link_conf->bssid_indicator = 0; - __sta_info_flush(sdata, true, -1); + __sta_info_flush(sdata, true, link_id); ieee80211_free_keys(sdata, true); link_conf->enable_beacon = false; From 675516f55db27b351334c9027407e40b1e72818b Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 6 Feb 2024 16:54:04 +0200 Subject: [PATCH 1131/2255] 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(-) 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); From 7b5e25b8baebc02db728bfbdc3080be863144c7b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 16:54:07 +0200 Subject: [PATCH 1132/2255] wifi: cfg80211: rename UHB to 6 GHz UHB stands for "Ultra High Band", but this term doesn't really exist in the spec. Rename all occurrences to "6 GHz", but keep a few defines for userspace API compatibility. Link: https://msgid.link/20240206164849.c9cfb9400839.I153db3b951934a1d84409c17fbe1f1d1782543fa@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 10 +++++----- include/uapi/linux/nl80211.h | 31 ++++++++++++++++++++----------- net/wireless/nl80211.c | 8 ++++---- net/wireless/reg.c | 10 +++++----- net/wireless/scan.c | 8 ++++---- 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 62894b024e88..7bb8484e859e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -118,9 +118,9 @@ struct wiphy; * restrictions. * @IEEE80211_CHAN_NO_EHT: EHT operation is not permitted on this channel. * @IEEE80211_CHAN_DFS_CONCURRENT: See %NL80211_RRF_DFS_CONCURRENT - * @IEEE80211_CHAN_NO_UHB_VLP_CLIENT: Client connection with VLP AP + * @IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT: Client connection with VLP AP * not permitted using this channel - * @IEEE80211_CHAN_NO_UHB_AFC_CLIENT: Client connection with AFC AP + * @IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT: Client connection with AFC AP * not permitted using this channel */ enum ieee80211_channel_flags { @@ -146,8 +146,8 @@ enum ieee80211_channel_flags { IEEE80211_CHAN_NO_320MHZ = 1<<19, IEEE80211_CHAN_NO_EHT = 1<<20, IEEE80211_CHAN_DFS_CONCURRENT = 1<<21, - IEEE80211_CHAN_NO_UHB_VLP_CLIENT= 1<<22, - IEEE80211_CHAN_NO_UHB_AFC_CLIENT= 1<<23, + IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT = 1<<22, + IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT = 1<<23, }; #define IEEE80211_CHAN_NO_HT40 \ @@ -4935,7 +4935,7 @@ struct cfg80211_ops { * enum wiphy_flags - wiphy capability flags * * @WIPHY_FLAG_SPLIT_SCAN_6GHZ: if set to true, the scan request will be split - * into two, first for legacy bands and second for UHB. + * into two, first for legacy bands and second for 6 GHz. * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this * wiphy at all * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 805bfe712971..13fa10804909 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -11,7 +11,7 @@ * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -4269,9 +4269,9 @@ enum nl80211_wmm_rule { * allowed for peer-to-peer or adhoc communication under the control * of a DFS master which operates on the same channel (FCC-594280 D01 * Section B.3). Should be used together with %NL80211_RRF_DFS only. - * @NL80211_FREQUENCY_ATTR_NO_UHB_VLP_CLIENT: Client connection to VLP AP + * @NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT: Client connection to VLP AP * not allowed using this channel - * @NL80211_FREQUENCY_ATTR_NO_UHB_AFC_CLIENT: Client connection to AFC AP + * @NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT: Client connection to AFC AP * not allowed using this channel * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined @@ -4313,8 +4313,8 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_EHT, NL80211_FREQUENCY_ATTR_PSD, NL80211_FREQUENCY_ATTR_DFS_CONCURRENT, - NL80211_FREQUENCY_ATTR_NO_UHB_VLP_CLIENT, - NL80211_FREQUENCY_ATTR_NO_UHB_AFC_CLIENT, + NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT, + NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -4327,6 +4327,10 @@ enum nl80211_frequency_attr { #define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR #define NL80211_FREQUENCY_ATTR_GO_CONCURRENT \ NL80211_FREQUENCY_ATTR_IR_CONCURRENT +#define NL80211_FREQUENCY_ATTR_NO_UHB_VLP_CLIENT \ + NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT +#define NL80211_FREQUENCY_ATTR_NO_UHB_AFC_CLIENT \ + NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT /** * enum nl80211_bitrate_attr - bitrate attributes @@ -4517,8 +4521,8 @@ enum nl80211_sched_scan_match_attr { peer-to-peer or adhoc communication under the control of a DFS master which operates on the same channel (FCC-594280 D01 Section B.3). Should be used together with %NL80211_RRF_DFS only. - * @NL80211_RRF_NO_UHB_VLP_CLIENT: Client connection to VLP AP not allowed - * @NL80211_RRF_NO_UHB_AFC_CLIENT: Client connection to AFC AP not allowed + * @NL80211_RRF_NO_6GHZ_VLP_CLIENT: Client connection to VLP AP not allowed + * @NL80211_RRF_NO_6GHZ_AFC_CLIENT: Client connection to AFC AP not allowed */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -4541,8 +4545,8 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_EHT = 1<<19, NL80211_RRF_PSD = 1<<20, NL80211_RRF_DFS_CONCURRENT = 1<<21, - NL80211_RRF_NO_UHB_VLP_CLIENT = 1<<22, - NL80211_RRF_NO_UHB_AFC_CLIENT = 1<<23, + NL80211_RRF_NO_6GHZ_VLP_CLIENT = 1<<22, + NL80211_RRF_NO_6GHZ_AFC_CLIENT = 1<<23, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR @@ -4551,6 +4555,8 @@ enum nl80211_reg_rule_flags { #define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\ NL80211_RRF_NO_HT40PLUS) #define NL80211_RRF_GO_CONCURRENT NL80211_RRF_IR_CONCURRENT +#define NL80211_RRF_NO_UHB_VLP_CLIENT NL80211_RRF_NO_6GHZ_VLP_CLIENT +#define NL80211_RRF_NO_UHB_AFC_CLIENT NL80211_RRF_NO_6GHZ_AFC_CLIENT /* For backport compatibility with older userspace */ #define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) @@ -5098,14 +5104,17 @@ enum nl80211_bss_use_for { * BSS isn't possible * @NL80211_BSS_CANNOT_USE_NSTR_NONPRIMARY: NSTR nonprimary links aren't * supported by the device, and this BSS entry represents one. - * @NL80211_BSS_CANNOT_USE_UHB_PWR_MISMATCH: STA is not supporting + * @NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH: STA is not supporting * the AP power type (SP, VLP, AP) that the AP uses. */ enum nl80211_bss_cannot_use_reasons { NL80211_BSS_CANNOT_USE_NSTR_NONPRIMARY = 1 << 0, - NL80211_BSS_CANNOT_USE_UHB_PWR_MISMATCH = 1 << 1, + NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH = 1 << 1, }; +#define NL80211_BSS_CANNOT_USE_UHB_PWR_MISMATCH \ + NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH + /** * enum nl80211_bss - netlink attributes for a BSS * diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5ca545753810..3b3b511f9f69 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1198,11 +1198,11 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy, if ((chan->flags & IEEE80211_CHAN_DFS_CONCURRENT) && nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DFS_CONCURRENT)) goto nla_put_failure; - if ((chan->flags & IEEE80211_CHAN_NO_UHB_VLP_CLIENT) && - nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_UHB_VLP_CLIENT)) + if ((chan->flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT)) goto nla_put_failure; - if ((chan->flags & IEEE80211_CHAN_NO_UHB_AFC_CLIENT) && - nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_UHB_AFC_CLIENT)) + if ((chan->flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT)) goto nla_put_failure; } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2741b626919a..50cadbad485f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -5,7 +5,7 @@ * Copyright 2008-2011 Luis R. Rodriguez * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2023 Intel Corporation + * Copyright (C) 2018 - 2024 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1595,10 +1595,10 @@ static u32 map_regdom_flags(u32 rd_flags) channel_flags |= IEEE80211_CHAN_NO_EHT; if (rd_flags & NL80211_RRF_DFS_CONCURRENT) channel_flags |= IEEE80211_CHAN_DFS_CONCURRENT; - if (rd_flags & NL80211_RRF_NO_UHB_VLP_CLIENT) - channel_flags |= IEEE80211_CHAN_NO_UHB_VLP_CLIENT; - if (rd_flags & NL80211_RRF_NO_UHB_AFC_CLIENT) - channel_flags |= IEEE80211_CHAN_NO_UHB_AFC_CLIENT; + if (rd_flags & NL80211_RRF_NO_6GHZ_VLP_CLIENT) + channel_flags |= IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT; + if (rd_flags & NL80211_RRF_NO_6GHZ_AFC_CLIENT) + channel_flags |= IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT; if (rd_flags & NL80211_RRF_PSD) channel_flags |= IEEE80211_CHAN_PSD; return channel_flags; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 04039e9dbd05..88e8b25c073a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -5,7 +5,7 @@ * Copyright 2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include #include @@ -3041,9 +3041,9 @@ static bool cfg80211_uhb_power_type_valid(const u8 *ie, case IEEE80211_6GHZ_CTRL_REG_LPI_AP: return true; case IEEE80211_6GHZ_CTRL_REG_SP_AP: - return !(flags & IEEE80211_CHAN_NO_UHB_AFC_CLIENT); + return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); case IEEE80211_6GHZ_CTRL_REG_VLP_AP: - return !(flags & IEEE80211_CHAN_NO_UHB_VLP_CLIENT); + return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); } } return false; @@ -3112,7 +3112,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, data->restrict_use = 1; data->use_for = 0; data->cannot_use_reasons = - NL80211_BSS_CANNOT_USE_UHB_PWR_MISMATCH; + NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH; } if (ext) { From a110a3b79177ddd7e7295671df97fb5386406835 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 16:54:08 +0200 Subject: [PATCH 1133/2255] wifi: cfg80211: optionally support monitor on disabled channels If the hardware supports a disabled channel, it may in some cases be possible to use monitor mode (without any transmit) on it when it's otherwise disabled. Add a new channel flag IEEE80211_CHAN_CAN_MONITOR that makes it possible for a driver to indicate such a thing. Make it per channel so drivers could have a choice with it, perhaps it's only possible on some channels, perhaps some channels are not supported at all, but still there and marked disabled. In _nl80211_parse_chandef() simplify the code and check only for an unknown channel, _cfg80211_chandef_usable() will later check for IEEE80211_CHAN_DISABLED anyway. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206164849.87fad3a21a09.I9116b2fdc2e2c9fd59a9273a64db7fcb41fc0328@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 4 ++++ net/wireless/chan.c | 26 +++++++++++++++++++------- net/wireless/core.h | 5 ++++- net/wireless/nl80211.c | 27 ++++++++++++++++++--------- 5 files changed, 49 insertions(+), 17 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7bb8484e859e..0a3151587556 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -122,6 +122,9 @@ struct wiphy; * not permitted using this channel * @IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT: Client connection with AFC AP * not permitted using this channel + * @IEEE80211_CHAN_CAN_MONITOR: This channel can be used for monitor + * mode even in the presence of other (regulatory) restrictions, + * even if it is otherwise disabled. */ enum ieee80211_channel_flags { IEEE80211_CHAN_DISABLED = 1<<0, @@ -148,6 +151,7 @@ enum ieee80211_channel_flags { IEEE80211_CHAN_DFS_CONCURRENT = 1<<21, IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT = 1<<22, IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT = 1<<23, + IEEE80211_CHAN_CAN_MONITOR = 1<<24, }; #define IEEE80211_CHAN_NO_HT40 \ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 13fa10804909..546cc176c2a9 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4273,6 +4273,9 @@ enum nl80211_wmm_rule { * not allowed using this channel * @NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT: Client connection to AFC AP * not allowed using this channel + * @NL80211_FREQUENCY_ATTR_CAN_MONITOR: This channel can be used in monitor + * mode despite other (regulatory) restrictions, even if the channel is + * otherwise completely disabled. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -4315,6 +4318,7 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_DFS_CONCURRENT, NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT, NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT, + NL80211_FREQUENCY_ATTR_CAN_MONITOR, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, diff --git a/net/wireless/chan.c b/net/wireless/chan.c index e2ce89afa9ff..3414b2c3abcc 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -1145,7 +1145,7 @@ EXPORT_SYMBOL(cfg80211_chandef_dfs_cac_time); static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, u32 center_freq, u32 bandwidth, - u32 prohibited_flags) + u32 prohibited_flags, bool monitor) { struct ieee80211_channel *c; u32 freq, start_freq, end_freq; @@ -1155,7 +1155,11 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) { c = ieee80211_get_channel_khz(wiphy, freq); - if (!c || c->flags & prohibited_flags) + if (!c) + return false; + if (monitor && c->flags & IEEE80211_CHAN_CAN_MONITOR) + continue; + if (c->flags & prohibited_flags) return false; } @@ -1215,9 +1219,9 @@ static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels, return true; } -bool cfg80211_chandef_usable(struct wiphy *wiphy, - const struct cfg80211_chan_def *chandef, - u32 prohibited_flags) +bool _cfg80211_chandef_usable(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + u32 prohibited_flags, bool monitor) { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; @@ -1379,14 +1383,22 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, if (!cfg80211_secondary_chans_ok(wiphy, ieee80211_chandef_to_khz(chandef), - width, prohibited_flags)) + width, prohibited_flags, monitor)) return false; if (!chandef->center_freq2) return true; return cfg80211_secondary_chans_ok(wiphy, MHZ_TO_KHZ(chandef->center_freq2), - width, prohibited_flags); + width, prohibited_flags, monitor); +} + +bool cfg80211_chandef_usable(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + u32 prohibited_flags) +{ + return _cfg80211_chandef_usable(wiphy, chandef, prohibited_flags, + false); } EXPORT_SYMBOL(cfg80211_chandef_usable); diff --git a/net/wireless/core.h b/net/wireless/core.h index debf63e6c61f..118f2f619828 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -3,7 +3,7 @@ * Wireless configuration interface internals. * * Copyright 2006-2010 Johannes Berg - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H @@ -492,6 +492,9 @@ bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev, struct ieee80211_channel *chan, bool primary_only); +bool _cfg80211_chandef_usable(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + u32 prohibited_flags, bool monitor); static inline unsigned int elapsed_jiffies_msecs(unsigned long start) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3b3b511f9f69..612ca99fbf39 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3218,9 +3218,9 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) wdev->iftype == NL80211_IFTYPE_P2P_GO; } -int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, - struct genl_info *info, - struct cfg80211_chan_def *chandef) +static int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev, + struct genl_info *info, bool monitor, + struct cfg80211_chan_def *chandef) { struct netlink_ext_ack *extack = info->extack; struct nlattr **attrs = info->attrs; @@ -3245,10 +3245,9 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, chandef->freq1_offset = control_freq % 1000; chandef->center_freq2 = 0; - /* Primary channel not allowed */ - if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) { + if (!chandef->chan) { NL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ], - "Channel is disabled"); + "Unknown channel"); return -EINVAL; } @@ -3343,8 +3342,9 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, return -EINVAL; } - if (!cfg80211_chandef_usable(&rdev->wiphy, chandef, - IEEE80211_CHAN_DISABLED)) { + if (!_cfg80211_chandef_usable(&rdev->wiphy, chandef, + IEEE80211_CHAN_DISABLED, + monitor)) { NL_SET_ERR_MSG(extack, "(extension) channel is disabled"); return -EINVAL; } @@ -3359,6 +3359,13 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, return 0; } +int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, + struct genl_info *info, + struct cfg80211_chan_def *chandef) +{ + return _nl80211_parse_chandef(rdev, info, false, chandef); +} + static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, struct net_device *dev, struct genl_info *info, @@ -3383,7 +3390,9 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, link_id = 0; } - result = nl80211_parse_chandef(rdev, info, &chandef); + result = _nl80211_parse_chandef(rdev, info, + iftype == NL80211_IFTYPE_MONITOR, + &chandef); if (result) return result; From 49c17da387bb069d802b9be538f0f07d08e1c2b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 16:54:09 +0200 Subject: [PATCH 1134/2255] wifi: mac80211: drop injection on disabled-chan monitor If the driver uses the new IEEE80211_CHAN_CAN_MONITOR, we may monitor on channels that are, e.g. via regulatory, otherwise considered disabled. However, we really shouldn't transmit on them, so prevent that. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206164849.9c03dcf67dbe.Ib86a851c274c440908c663f6dd774b79bfc3965d@changeid Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 876de3ba98ba..373275d18f5a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation * * Transmit and frame generation functions. */ @@ -2393,6 +2393,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, else goto fail_rcu; + /* + * If driver/HW supports IEEE80211_CHAN_CAN_MONITOR we still + * shouldn't transmit on disabled channels. + */ + if (!cfg80211_chandef_usable(local->hw.wiphy, chandef, + IEEE80211_CHAN_DISABLED)) + goto fail_rcu; + /* * Frame injection is not allowed if beaconing is not allowed * or if we need radar detection. Beaconing is usually not allowed when From 93d9f26db5b34ec4d2d5056aeb8819cbef35519c Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 6 Feb 2024 16:54:10 +0200 Subject: [PATCH 1135/2255] wifi: nl80211: allow reporting wakeup for unprot deauth/disassoc Add a report reason for waking up due to an unprotected deauth/disassoc when MFP is used. If setting wowlan to wake on disconnection, and an unprotected deatuh/disassoc arrived (in MFP), some drivers might want to report wakeup due to unprotected deauth/disassoc, rather than dissassociation. Add support for that. Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206164849.8dc9ad531a17.I7f8e926adf927f762e11aaa3458f6354665c7fc5@changeid Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 546cc176c2a9..f23ecbdd84a2 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5757,6 +5757,8 @@ struct nl80211_pattern_support { * %NL80211_ATTR_SCAN_FREQUENCIES contains more than one * frequency, it means that the match occurred in more than one * channel. + * @NL80211_WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC: For wakeup reporting only. + * Wake up happened due to unprotected deauth or disassoc frame in MFP. * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number * @@ -5784,6 +5786,7 @@ enum nl80211_wowlan_triggers { NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, NL80211_WOWLAN_TRIG_NET_DETECT, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS, + NL80211_WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC, /* keep last */ NUM_NL80211_WOWLAN_TRIG, From a64be8296e31f432d4a9df4db684cc8a250eb81c Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 6 Feb 2024 16:54:11 +0200 Subject: [PATCH 1136/2255] wifi: cfg80211: report unprotected deauth/disassoc in wowlan Add to cfg80211_wowlan_wakeup another wakeup reason - unprot_deauth_disassoc. To be set to true if the woke up was due to an unprotected deauth or disassoc frame in MFP. In that case report WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC. Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206164849.a3d739850d03.I8f52a21c4f36d1af1f8068bed79e2f9cbf8289ef@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 ++++- net/wireless/nl80211.c | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0a3151587556..93e9abb7fc3d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3612,12 +3612,15 @@ struct cfg80211_wowlan_nd_info { * @tcp_connlost: TCP connection lost or failed to establish * @tcp_nomoretokens: TCP data ran out of tokens * @net_detect: if not %NULL, woke up because of net detect + * @unprot_deauth_disassoc: woke up due to unprotected deauth or + * disassoc frame (in MFP). */ struct cfg80211_wowlan_wakeup { bool disconnect, magic_pkt, gtk_rekey_failure, eap_identity_req, four_way_handshake, rfkill_release, packet_80211, - tcp_match, tcp_connlost, tcp_nomoretokens; + tcp_match, tcp_connlost, tcp_nomoretokens, + unprot_deauth_disassoc; s32 pattern_idx; u32 packet_present_len, packet_len; const void *packet; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 612ca99fbf39..5f18cbf7cc3d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -19851,6 +19851,11 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS)) goto free_msg; + if (wakeup->unprot_deauth_disassoc && + nla_put_flag(msg, + NL80211_WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC)) + goto free_msg; + if (wakeup->packet) { u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; From 24e5252c590dd8fd9ed702e0fbe426eda78641cd Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 6 Feb 2024 18:02:12 +0200 Subject: [PATCH 1137/2255] 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(+) 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; From 0d2fc8821a7d667180ce27732697105db843a1b9 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Thu, 8 Feb 2024 18:58:35 +0200 Subject: [PATCH 1138/2255] 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 --- .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 33 ++++++++++++++++--- .../wireless/intel/iwlwifi/iwl-nvm-parse.h | 2 +- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +- 3 files changed, 31 insertions(+), 7 deletions(-) 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)) { From 07da4a1b2a59d1392fc61ed12692602b89c33e8a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:36 +0200 Subject: [PATCH 1139/2255] 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(-) 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; From 59214747f26a6c1b3616ef75f9eec7543ddba8e4 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Feb 2024 18:58:37 +0200 Subject: [PATCH 1140/2255] 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(-) 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); } From 4cdb86487e3eaddb4b3a7df30ae709e810aac84b Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Feb 2024 18:58:38 +0200 Subject: [PATCH 1141/2255] 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(-) 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); From 41c5f4707d9d54255f5bfa90d184eac68f06a2f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:39 +0200 Subject: [PATCH 1142/2255] 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(-) 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 */ /** From 8efadbc3882b8f9084869c5da9660d49cd62c060 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:40 +0200 Subject: [PATCH 1143/2255] 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(-) 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); From 8cb3a308ceb19f8f74114c618b9e1778be498780 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:41 +0200 Subject: [PATCH 1144/2255] 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(-) 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 */ From ac71795bfdc988b2dc305fcf91bc6d712c3603be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:42 +0200 Subject: [PATCH 1145/2255] 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 --- .../wireless/intel/iwlwifi/fw/error-dump.h | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) 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, From ecf7e563031d2685e9d3e6a870d6a7fc60d537f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:43 +0200 Subject: [PATCH 1146/2255] 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(-) 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 { From f16368a157008ac0755aa9457bc71a44e5e8a5f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:44 +0200 Subject: [PATCH 1147/2255] 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(-) 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 From d8af46dec1ff0141f66253336f5a52cbb237d18a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:45 +0200 Subject: [PATCH 1148/2255] 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 --- .../net/wireless/intel/iwlwifi/iwl-trans.h | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) 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; From d34637a986d6105875f3a02cdd16bd26d5811c38 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 8 Feb 2024 18:58:46 +0200 Subject: [PATCH 1149/2255] 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(-) 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 From 182094411e29fa76b6651f31fd7b941780a45c56 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:47 +0200 Subject: [PATCH 1150/2255] 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(+) 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); From f25e7b82635f59af87bd720bbb8c2ea19e8e0f67 Mon Sep 17 00:00:00 2001 From: Joe Damato Date: Fri, 9 Feb 2024 20:23:08 +0000 Subject: [PATCH 1151/2255] net/mlx5e: link NAPI instances to queues and IRQs Make mlx5 compatible with the newly added netlink queue GET APIs. Signed-off-by: Joe Damato Reviewed-by: Tariq Toukan Link: https://lore.kernel.org/r/20240209202312.30181-1-jdamato@fastly.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c | 5 ++++- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c index 078f56a3cbb2..fd4ef6431142 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c @@ -935,6 +935,7 @@ void mlx5e_ptp_activate_channel(struct mlx5e_ptp *c) if (test_bit(MLX5E_PTP_STATE_RX, c->state)) { mlx5e_ptp_rx_set_fs(c->priv); mlx5e_activate_rq(&c->rq); + netif_queue_set_napi(c->netdev, c->rq.ix, NETDEV_QUEUE_TYPE_RX, &c->napi); } mlx5e_trigger_napi_sched(&c->napi); } @@ -943,8 +944,10 @@ void mlx5e_ptp_deactivate_channel(struct mlx5e_ptp *c) { int tc; - if (test_bit(MLX5E_PTP_STATE_RX, c->state)) + if (test_bit(MLX5E_PTP_STATE_RX, c->state)) { + netif_queue_set_napi(c->netdev, c->rq.ix, NETDEV_QUEUE_TYPE_RX, NULL); mlx5e_deactivate_rq(&c->rq); + } if (test_bit(MLX5E_PTP_STATE_TX, c->state)) { for (tc = 0; tc < c->num_tc; tc++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c8e8f512803e..be809556b2e1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1806,6 +1806,7 @@ void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq) set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state); netdev_tx_reset_queue(sq->txq); netif_tx_start_queue(sq->txq); + netif_queue_set_napi(sq->netdev, sq->txq_ix, NETDEV_QUEUE_TYPE_TX, sq->cq.napi); } void mlx5e_tx_disable_queue(struct netdev_queue *txq) @@ -1819,6 +1820,7 @@ void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq) { struct mlx5_wq_cyc *wq = &sq->wq; + netif_queue_set_napi(sq->netdev, sq->txq_ix, NETDEV_QUEUE_TYPE_TX, NULL); clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state); synchronize_net(); /* Sync with NAPI to prevent netif_tx_wake_queue. */ @@ -2560,6 +2562,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, c->lag_port = mlx5e_enumerate_lag_port(priv->mdev, ix); netif_napi_add(netdev, &c->napi, mlx5e_napi_poll); + netif_napi_set_irq(&c->napi, irq); err = mlx5e_open_queues(c, params, cparam); if (unlikely(err)) @@ -2602,12 +2605,16 @@ static void mlx5e_activate_channel(struct mlx5e_channel *c) mlx5e_activate_xsk(c); else mlx5e_activate_rq(&c->rq); + + netif_queue_set_napi(c->netdev, c->ix, NETDEV_QUEUE_TYPE_RX, &c->napi); } static void mlx5e_deactivate_channel(struct mlx5e_channel *c) { int tc; + netif_queue_set_napi(c->netdev, c->ix, NETDEV_QUEUE_TYPE_RX, NULL); + if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state)) mlx5e_deactivate_xsk(c); else From a3522a2edb3faf8cb98d38c2a99f5967beef24e2 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 9 Feb 2024 17:43:37 +0100 Subject: [PATCH 1152/2255] ipv4: Set the routing scope properly in ip_route_output_ports(). Set scope automatically in ip_route_output_ports() (using the socket SOCK_LOCALROUTE flag). This way, callers don't have to overload the tos with the RTO_ONLINK flag, like RT_CONN_FLAGS() does. For callers that don't pass a struct sock, this doesn't change anything as the scope is still set to RT_SCOPE_UNIVERSE when sk is NULL. Callers that passed a struct sock and used RT_CONN_FLAGS(sk) or RT_CONN_FLAGS_TOS(sk, tos) for the tos are modified to use ip_sock_tos(sk) and RT_TOS(tos) respectively, as overloading tos with the RTO_ONLINK flag now becomes unnecessary. In drivers/net/amt.c, all ip_route_output_ports() calls use a 0 tos parameter, ignoring the SOCK_LOCALROUTE flag of the socket. But the sk parameter is a kernel socket, which doesn't have any configuration path for setting SOCK_LOCALROUTE anyway. Therefore, ip_route_output_ports() will continue to initialise scope with RT_SCOPE_UNIVERSE and amt.c doesn't need to be modified. Also, remove RT_CONN_FLAGS() and RT_CONN_FLAGS_TOS() from route.h as these macros are now unused. The objective is to eventually remove RTO_ONLINK entirely to allow converting ->flowi4_tos to dscp_t. This will ensure proper isolation between the DSCP and ECN bits, thus minimising the risk of introducing bugs where TOS values interfere with ECN. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Link: https://lore.kernel.org/r/dacfd2ab40685e20959ab7b53c427595ba229e7d.1707496938.git.gnault@redhat.com Signed-off-by: Jakub Kicinski --- include/net/route.h | 7 ++----- net/ipv4/af_inet.c | 2 +- net/ipv4/datagram.c | 2 +- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/ip_output.c | 2 +- net/l2tp/l2tp_ip.c | 2 +- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/net/route.h b/include/net/route.h index 980ab474eabd..d4a0147942f1 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -37,9 +37,6 @@ #define RTO_ONLINK 0x01 -#define RT_CONN_FLAGS(sk) (RT_TOS(READ_ONCE(inet_sk(sk)->tos)) | sock_flag(sk, SOCK_LOCALROUTE)) -#define RT_CONN_FLAGS_TOS(sk,tos) (RT_TOS(tos) | sock_flag(sk, SOCK_LOCALROUTE)) - static inline __u8 ip_sock_rt_scope(const struct sock *sk) { if (sock_flag(sk, SOCK_LOCALROUTE)) @@ -163,8 +160,8 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi __u8 proto, __u8 tos, int oif) { flowi4_init_output(fl4, oif, sk ? READ_ONCE(sk->sk_mark) : 0, tos, - RT_SCOPE_UNIVERSE, proto, - sk ? inet_sk_flowi_flags(sk) : 0, + sk ? ip_sock_rt_scope(sk) : RT_SCOPE_UNIVERSE, + proto, sk ? inet_sk_flowi_flags(sk) : 0, daddr, saddr, dport, sport, sock_net_uid(net, sk)); if (sk) security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4)); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index a5a820ee2026..ad278009e469 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1326,7 +1326,7 @@ int inet_sk_rebuild_header(struct sock *sk) fl4 = &inet->cork.fl.u.ip4; rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, - sk->sk_protocol, RT_CONN_FLAGS(sk), + sk->sk_protocol, ip_sock_rt_tos(sk), sk->sk_bound_dev_if); if (!IS_ERR(rt)) { err = 0; diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 2cc50cbfc2a3..cc6d0bd7b0a9 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -119,7 +119,7 @@ void ip4_datagram_release_cb(struct sock *sk) rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, - RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); + ip_sock_rt_tos(sk), sk->sk_bound_dev_if); dst = !IS_ERR(rt) ? &rt->dst : NULL; sk_dst_set(sk, dst); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 459af1f89739..747ed7344cbe 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -1467,7 +1467,7 @@ static struct dst_entry *inet_csk_rebuild_route(struct sock *sk, struct flowi *f rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, - RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); + ip_sock_rt_tos(sk), sk->sk_bound_dev_if); if (IS_ERR(rt)) rt = NULL; if (rt) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 41537d18eecf..5b5a0adb927f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -493,7 +493,7 @@ int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, inet->inet_dport, inet->inet_sport, sk->sk_protocol, - RT_CONN_FLAGS_TOS(sk, tos), + RT_TOS(tos), sk->sk_bound_dev_if); if (IS_ERR(rt)) goto no_route; diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 9a2a9ed3ba47..970af3983d11 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -478,7 +478,7 @@ static int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, - sk->sk_protocol, RT_CONN_FLAGS(sk), + sk->sk_protocol, ip_sock_rt_tos(sk), sk->sk_bound_dev_if); if (IS_ERR(rt)) goto no_route; From 6256fbfd651c8b3653b7f1cfe08e635404e4b51d Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Thu, 8 Feb 2024 11:35:25 +0100 Subject: [PATCH 1153/2255] net: stmmac: Simplify mtl IRQ status checking Commit 8a7cb245cf28 ("net: stmmac: Do not enable RX FIFO overflow interrupts") disabled the RX FIFO overflow interrupts. However, it left the status variable around, but never checks it. As stmmac_host_mtl_irq_status() returns only 0 now, the code can be simplified. Signed-off-by: Kurt Kanzenbach Link: https://lore.kernel.org/r/20240208-stmmac_irq-v1-1-8bab236026d4@linutronix.de Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9159d93ceb03..ae2ffa9595d6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -6061,10 +6061,8 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) priv->tx_path_in_lpi_mode = false; } - for (queue = 0; queue < queues_count; queue++) { - status = stmmac_host_mtl_irq_status(priv, priv->hw, - queue); - } + for (queue = 0; queue < queues_count; queue++) + stmmac_host_mtl_irq_status(priv, priv->hw, queue); /* PCS link status */ if (priv->hw->pcs && From 86fe596b588fc9ec23bf93a5c8f86fc16225dd3a Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Fri, 9 Feb 2024 10:06:56 -0800 Subject: [PATCH 1154/2255] net: sched: Remove NET_ACT_IPT from Kconfig After this commit ba24ea129126 ("net/sched: Retire ipt action") NET_ACT_IPT is not needed anymore as the action is retired and the code is removed. Clean the Kconfig part as well. Signed-off-by: Harshit Mogalapalli Acked-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20240209180656.867546-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Paolo Abeni --- net/sched/Kconfig | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 470c70deffe2..8180d0c12fce 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -737,16 +737,6 @@ config NET_ACT_SAMPLE To compile this code as a module, choose M here: the module will be called act_sample. -config NET_ACT_IPT - tristate "IPtables targets" - depends on NET_CLS_ACT && NETFILTER && NETFILTER_XTABLES - help - Say Y here to be able to invoke iptables targets after successful - classification. - - To compile this code as a module, choose M here: the - module will be called act_ipt. - config NET_ACT_NAT tristate "Stateless NAT" depends on NET_CLS_ACT From c83c22ec1493c0b7cc77327bedbd387e295872b6 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Mon, 12 Feb 2024 22:35:50 +0100 Subject: [PATCH 1155/2255] can: canxl: add virtual CAN network identifier support CAN XL data frames contain an 8-bit virtual CAN network identifier (VCID). A VCID value of zero represents an 'untagged' CAN XL frame. To receive and send these optional VCIDs via CAN_RAW sockets a new socket option CAN_RAW_XL_VCID_OPTS is introduced to define/access VCID content: - tx: set the outgoing VCID value by the kernel (one fixed 8-bit value) - tx: pass through VCID values from the user space (e.g. for traffic replay) - rx: apply VCID receive filter (value/mask) to be passed to the user space With the 'tx pass through' option CAN_RAW_XL_VCID_TX_PASS all valid VCID values can be sent, e.g. to replay full qualified CAN XL traffic. The VCID value provided for the CAN_RAW_XL_VCID_TX_SET option will override the VCID value in the struct canxl_frame.prio defined for CAN_RAW_XL_VCID_TX_PASS when both flags are set. With a rx_vcid_mask of zero all possible VCID values (0x00 - 0xFF) are passed to the user space when the CAN_RAW_XL_VCID_RX_FILTER flag is set. Without this flag only untagged CAN XL frames (VCID = 0x00) are delivered to the user space (default). The 8-bit VCID is stored inside the CAN XL prio element (only in CAN XL frames!) to not interfere with other CAN content or the CAN filters provided by the CAN_RAW sockets and kernel infrastruture. Signed-off-by: Oliver Hartkopp Link: https://lore.kernel.org/all/20240212213550.18516-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde --- include/uapi/linux/can.h | 9 +++- include/uapi/linux/can/raw.h | 16 +++++++ net/can/af_can.c | 2 + net/can/raw.c | 93 ++++++++++++++++++++++++++++++++---- 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h index 939db2388208..e78cbd85ce7c 100644 --- a/include/uapi/linux/can.h +++ b/include/uapi/linux/can.h @@ -193,9 +193,14 @@ struct canfd_frame { #define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */ #define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */ +/* the 8-bit VCID is optionally placed in the canxl_frame.prio element */ +#define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */ +#define CANXL_VCID_VAL_MASK 0xFFUL /* VCID is an 8-bit value */ +#define CANXL_VCID_MASK (CANXL_VCID_VAL_MASK << CANXL_VCID_OFFSET) + /** * struct canxl_frame - CAN with e'X'tended frame 'L'ength frame structure - * @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags + * @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags / VCID * @flags: additional flags for CAN XL * @sdt: SDU (service data unit) type * @len: frame payload length in byte (CANXL_MIN_DLEN .. CANXL_MAX_DLEN) @@ -205,7 +210,7 @@ struct canfd_frame { * @prio shares the same position as @can_id from struct can[fd]_frame. */ struct canxl_frame { - canid_t prio; /* 11 bit priority for arbitration (canid_t) */ + canid_t prio; /* 11 bit priority for arbitration / 8 bit VCID */ __u8 flags; /* additional flags for CAN XL */ __u8 sdt; /* SDU (service data unit) type */ __u16 len; /* frame payload length in byte */ diff --git a/include/uapi/linux/can/raw.h b/include/uapi/linux/can/raw.h index 31622c9b7988..e024d896e278 100644 --- a/include/uapi/linux/can/raw.h +++ b/include/uapi/linux/can/raw.h @@ -65,6 +65,22 @@ enum { CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */ + CAN_RAW_XL_VCID_OPTS, /* CAN XL VCID configuration options */ }; +/* configuration for CAN XL virtual CAN identifier (VCID) handling */ +struct can_raw_vcid_options { + + __u8 flags; /* flags for vcid (filter) behaviour */ + __u8 tx_vcid; /* VCID value set into canxl_frame.prio */ + __u8 rx_vcid; /* VCID value for VCID filter */ + __u8 rx_vcid_mask; /* VCID mask for VCID filter */ + +}; + +/* can_raw_vcid_options.flags for CAN XL virtual CAN identifier handling */ +#define CAN_RAW_XL_VCID_TX_SET 0x01 +#define CAN_RAW_XL_VCID_TX_PASS 0x02 +#define CAN_RAW_XL_VCID_RX_FILTER 0x04 + #endif /* !_UAPI_CAN_RAW_H */ diff --git a/net/can/af_can.c b/net/can/af_can.c index 7343fd487dbe..707576eeeb58 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -865,6 +865,8 @@ static __init int can_init(void) /* check for correct padding to be able to use the structs similarly */ BUILD_BUG_ON(offsetof(struct can_frame, len) != offsetof(struct canfd_frame, len) || + offsetof(struct can_frame, len) != + offsetof(struct canxl_frame, flags) || offsetof(struct can_frame, data) != offsetof(struct canfd_frame, data)); diff --git a/net/can/raw.c b/net/can/raw.c index e6b822624ba2..cb8e6f788af8 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -91,6 +91,10 @@ struct raw_sock { int recv_own_msgs; int fd_frames; int xl_frames; + struct can_raw_vcid_options raw_vcid_opts; + canid_t tx_vcid_shifted; + canid_t rx_vcid_shifted; + canid_t rx_vcid_mask_shifted; int join_filters; int count; /* number of active filters */ struct can_filter dfilter; /* default/single filter */ @@ -134,10 +138,29 @@ static void raw_rcv(struct sk_buff *oskb, void *data) return; /* make sure to not pass oversized frames to the socket */ - if ((!ro->fd_frames && can_is_canfd_skb(oskb)) || - (!ro->xl_frames && can_is_canxl_skb(oskb))) + if (!ro->fd_frames && can_is_canfd_skb(oskb)) return; + if (can_is_canxl_skb(oskb)) { + struct canxl_frame *cxl = (struct canxl_frame *)oskb->data; + + /* make sure to not pass oversized frames to the socket */ + if (!ro->xl_frames) + return; + + /* filter CAN XL VCID content */ + if (ro->raw_vcid_opts.flags & CAN_RAW_XL_VCID_RX_FILTER) { + /* apply VCID filter if user enabled the filter */ + if ((cxl->prio & ro->rx_vcid_mask_shifted) != + (ro->rx_vcid_shifted & ro->rx_vcid_mask_shifted)) + return; + } else { + /* no filter => do not forward VCID tagged frames */ + if (cxl->prio & CANXL_VCID_MASK) + return; + } + } + /* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr(ro->uniq)->skb == oskb && this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) { @@ -698,6 +721,19 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, ro->fd_frames = ro->xl_frames; break; + case CAN_RAW_XL_VCID_OPTS: + if (optlen != sizeof(ro->raw_vcid_opts)) + return -EINVAL; + + if (copy_from_sockptr(&ro->raw_vcid_opts, optval, optlen)) + return -EFAULT; + + /* prepare 32 bit values for handling in hot path */ + ro->tx_vcid_shifted = ro->raw_vcid_opts.tx_vcid << CANXL_VCID_OFFSET; + ro->rx_vcid_shifted = ro->raw_vcid_opts.rx_vcid << CANXL_VCID_OFFSET; + ro->rx_vcid_mask_shifted = ro->raw_vcid_opts.rx_vcid_mask << CANXL_VCID_OFFSET; + break; + case CAN_RAW_JOIN_FILTERS: if (optlen != sizeof(ro->join_filters)) return -EINVAL; @@ -786,6 +822,21 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, val = &ro->xl_frames; break; + case CAN_RAW_XL_VCID_OPTS: + /* user space buffer to small for VCID opts? */ + if (len < sizeof(ro->raw_vcid_opts)) { + /* return -ERANGE and needed space in optlen */ + err = -ERANGE; + if (put_user(sizeof(ro->raw_vcid_opts), optlen)) + err = -EFAULT; + } else { + if (len > sizeof(ro->raw_vcid_opts)) + len = sizeof(ro->raw_vcid_opts); + if (copy_to_user(optval, &ro->raw_vcid_opts, len)) + err = -EFAULT; + } + break; + case CAN_RAW_JOIN_FILTERS: if (len > sizeof(int)) len = sizeof(int); @@ -803,23 +854,41 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, return 0; } -static bool raw_bad_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu) +static void raw_put_canxl_vcid(struct raw_sock *ro, struct sk_buff *skb) +{ + struct canxl_frame *cxl = (struct canxl_frame *)skb->data; + + /* sanitize non CAN XL bits */ + cxl->prio &= (CANXL_PRIO_MASK | CANXL_VCID_MASK); + + /* clear VCID in CAN XL frame if pass through is disabled */ + if (!(ro->raw_vcid_opts.flags & CAN_RAW_XL_VCID_TX_PASS)) + cxl->prio &= CANXL_PRIO_MASK; + + /* set VCID in CAN XL frame if enabled */ + if (ro->raw_vcid_opts.flags & CAN_RAW_XL_VCID_TX_SET) { + cxl->prio &= CANXL_PRIO_MASK; + cxl->prio |= ro->tx_vcid_shifted; + } +} + +static unsigned int raw_check_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu) { /* Classical CAN -> no checks for flags and device capabilities */ if (can_is_can_skb(skb)) - return false; + return CAN_MTU; /* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */ if (ro->fd_frames && can_is_canfd_skb(skb) && (mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu))) - return false; + return CANFD_MTU; /* CAN XL -> needs to be enabled and a CAN XL device */ if (ro->xl_frames && can_is_canxl_skb(skb) && can_is_canxl_dev_mtu(mtu)) - return false; + return CANXL_MTU; - return true; + return 0; } static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) @@ -829,6 +898,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) struct sockcm_cookie sockc; struct sk_buff *skb; struct net_device *dev; + unsigned int txmtu; int ifindex; int err = -EINVAL; @@ -869,9 +939,16 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) goto free_skb; err = -EINVAL; - if (raw_bad_txframe(ro, skb, dev->mtu)) + + /* check for valid CAN (CC/FD/XL) frame content */ + txmtu = raw_check_txframe(ro, skb, dev->mtu); + if (!txmtu) goto free_skb; + /* only CANXL: clear/forward/set VCID value */ + if (txmtu == CANXL_MTU) + raw_put_canxl_vcid(ro, skb); + sockcm_init(&sockc, sk); if (msg->msg_controllen) { err = sock_cmsg_send(sk, msg, &sockc); From 73b8f5015889d4b5fbd885fa310ad8905fe50e4f Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 13 Feb 2024 11:43:51 +0100 Subject: [PATCH 1156/2255] MAINTAINERS: can: xilinx_can: remove Naga Sureshkumar Relli Mails to naga.sureshkumar.relli@xilinx.com are bouncing due to a mail loop. Seems Naga Sureshkumar Relli has left the company. Remove Naga Sureshkumar Relli from the xilinx_can driver. Cc: Appana Durga Kedareswara rao Link: https://lore.kernel.org/all/20240213-xilinx_can-v1-1-79820de803ea@pengutronix.de Signed-off-by: Marc Kleine-Budde --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a5a17a463685..1da02866febe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24140,7 +24140,6 @@ F: drivers/net/ethernet/xilinx/xilinx_axienet* XILINX CAN DRIVER M: Appana Durga Kedareswara rao -R: Naga Sureshkumar Relli L: linux-can@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/net/can/xilinx,can.yaml From 400909df6e6543cb5cce3db9bbcd413d59125327 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 10 Feb 2024 17:58:29 +0100 Subject: [PATCH 1157/2255] r8169: simplify code by using core-provided pcpu stats allocation Use core-provided pcpu stats allocation instead of open-coding it in the driver. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/03f5bb3b-d7f4-48be-ae8a-54862ec4566c@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/realtek/r8169_main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index b43db3c49d82..ddfa6f62472a 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5233,11 +5233,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) raw_spin_lock_init(&tp->mac_ocp_lock); mutex_init(&tp->led_lock); - dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, - struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - /* Get the *optional* external "ether_clk" used on some boards */ tp->clk = devm_clk_get_optional_enabled(&pdev->dev, "ether_clk"); if (IS_ERR(tp->clk)) @@ -5352,6 +5347,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; + netdev_sw_irq_coalesce_default_on(dev); /* configure chip for default features */ From 32c7eec21c11e149a9195cf0d48cc530d1e5a637 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 11 Feb 2024 09:24:55 -0800 Subject: [PATCH 1158/2255] net: sched: codel replace GPLv2/BSD boilerplate The prologue to codel is using BSD-3 clause and GPL-2 boiler plate language. Replace it by using SPDX. The automated treewide scan in commit d2912cb15bdd ("treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 500") did not pickup dual licensed code. Signed-off-by: Stephen Hemminger Acked-by: Dave Taht Link: https://lore.kernel.org/r/20240211172532.6568-1-stephen@networkplumber.org Signed-off-by: Paolo Abeni --- net/sched/sch_codel.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index 61904d3a593b..ecb3f164bb25 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Codel - The Controlled-Delay Active Queue Management algorithm * @@ -7,37 +8,6 @@ * Implemented on linux by : * Copyright (C) 2012 Michael D. Taht * Copyright (C) 2012,2015 Eric Dumazet - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the authors may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Alternatively, provided that this notice is retained in full, this - * software may be distributed under the terms of the GNU General - * Public License ("GPL") version 2, in which case the provisions of the - * GPL apply INSTEAD OF those given above. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * */ #include From bed90b06b6812d9c8c848414b090ddf38f0e6cc1 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Sun, 11 Feb 2024 19:16:41 +0100 Subject: [PATCH 1159/2255] net: phy: aquantia: clear PMD Global Transmit Disable bit during init PMD Global Transmit Disable bit should be cleared for normal operation. This should be HW default, however I found that on Asus RT-AX89X that uses AQR113C PHY and firmware 5.4 this bit is set by default. With this bit set the AQR cannot achieve a link with its link-partner and it took me multiple hours of digging through the vendor GPL source to find this out, so lets always clear this bit during .config_init() to avoid a situation like this in the future. Signed-off-by: Robert Marko Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240211181732.646311-1-robimarko@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/phy/aquantia/aquantia_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 97a2fafa15ca..e1f092cbfdce 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -727,6 +727,15 @@ static int aqr113c_config_init(struct phy_device *phydev) if (ret < 0) return ret; + ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, + MDIO_PMD_TXDIS_GLOBAL); + if (ret) + return ret; + + ret = aqr107_wait_processor_intensive_op(phydev); + if (ret) + return ret; + return aqr107_fill_interface_modes(phydev); } From 5b268d1ebcdceacf992dfda8f9031d56005a274e Mon Sep 17 00:00:00 2001 From: Daniel Xu Date: Sun, 4 Feb 2024 14:06:34 -0700 Subject: [PATCH 1160/2255] bpf: Have bpf_rdonly_cast() take a const pointer Since 20d59ee55172 ("libbpf: add bpf_core_cast() macro"), libbpf is now exporting a const arg version of bpf_rdonly_cast(). This causes the following conflicting type error when generating kfunc prototypes from BTF: In file included from skeleton/pid_iter.bpf.c:5: /home/dxu/dev/linux/tools/bpf/bpftool/bootstrap/libbpf/include/bpf/bpf_core_read.h:297:14: error: conflicting types for 'bpf_rdonly_cast' extern void *bpf_rdonly_cast(const void *obj__ign, __u32 btf_id__k) __ksym __weak; ^ ./vmlinux.h:135625:14: note: previous declaration is here extern void *bpf_rdonly_cast(void *obj__ign, u32 btf_id__k) __weak __ksym; This is b/c the kernel defines bpf_rdonly_cast() with non-const arg. Since const arg is more permissive and thus backwards compatible, we change the kernel definition as well to avoid conflicting type errors. Signed-off-by: Daniel Xu Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/dfd3823f11ffd2d4c838e961d61ec9ae8a646773.1707080349.git.dxu@dxuuu.xyz --- kernel/bpf/helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 4db1c658254c..3503949b4c1b 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2484,9 +2484,9 @@ __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) return obj; } -__bpf_kfunc void *bpf_rdonly_cast(void *obj__ign, u32 btf_id__k) +__bpf_kfunc void *bpf_rdonly_cast(const void *obj__ign, u32 btf_id__k) { - return obj__ign; + return (void *)obj__ign; } __bpf_kfunc void bpf_rcu_read_lock(void) From 178c54666f9c4d2f49f2ea661d0c11b52f0ed190 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 6 Feb 2024 23:01:02 -0800 Subject: [PATCH 1161/2255] bpf: Mark bpf_spin_{lock,unlock}() helpers with notrace correctly Currently tracing is supposed not to allow for bpf_spin_{lock,unlock}() helper calls. This is to prevent deadlock for the following cases: - there is a prog (prog-A) calling bpf_spin_{lock,unlock}(). - there is a tracing program (prog-B), e.g., fentry, attached to bpf_spin_lock() and/or bpf_spin_unlock(). - prog-B calls bpf_spin_{lock,unlock}(). For such a case, when prog-A calls bpf_spin_{lock,unlock}(), a deadlock will happen. The related source codes are below in kernel/bpf/helpers.c: notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) notrace is supposed to prevent fentry prog from attaching to bpf_spin_{lock,unlock}(). But actually this is not the case and fentry prog can successfully attached to bpf_spin_lock(). Siddharth Chintamaneni reported the issue in [1]. The following is the macro definition for above BPF_CALL_1: #define BPF_CALL_x(x, name, ...) \ static __always_inline \ u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \ typedef u64 (*btf_##name)(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \ u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \ u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)) \ { \ return ((btf_##name)____##name)(__BPF_MAP(x,__BPF_CAST,__BPF_N,__VA_ARGS__));\ } \ static __always_inline \ u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)) #define BPF_CALL_1(name, ...) BPF_CALL_x(1, name, __VA_ARGS__) The notrace attribute is actually applied to the static always_inline function ____bpf_spin_{lock,unlock}(). The actual callback function bpf_spin_{lock,unlock}() is not marked with notrace, hence allowing fentry prog to attach to two helpers, and this may cause the above mentioned deadlock. Siddharth Chintamaneni actually has a reproducer in [2]. To fix the issue, a new macro NOTRACE_BPF_CALL_1 is introduced which will add notrace attribute to the original function instead of the hidden always_inline function and this fixed the problem. [1] https://lore.kernel.org/bpf/CAE5sdEigPnoGrzN8WU7Tx-h-iFuMZgW06qp0KHWtpvoXxf1OAQ@mail.gmail.com/ [2] https://lore.kernel.org/bpf/CAE5sdEg6yUc_Jz50AnUXEEUh6O73yQ1Z6NV2srJnef0ZrQkZew@mail.gmail.com/ Fixes: d83525ca62cf ("bpf: introduce bpf_spin_lock") Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/20240207070102.335167-1-yonghong.song@linux.dev --- include/linux/filter.h | 21 ++++++++++++--------- kernel/bpf/helpers.c | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index fee070b9826e..36cc29a2934c 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -547,24 +547,27 @@ static inline bool insn_is_zext(const struct bpf_insn *insn) __BPF_MAP(n, __BPF_DECL_ARGS, __BPF_N, u64, __ur_1, u64, __ur_2, \ u64, __ur_3, u64, __ur_4, u64, __ur_5) -#define BPF_CALL_x(x, name, ...) \ +#define BPF_CALL_x(x, attr, name, ...) \ static __always_inline \ u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \ typedef u64 (*btf_##name)(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \ - u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \ - u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)) \ + attr u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \ + attr u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)) \ { \ return ((btf_##name)____##name)(__BPF_MAP(x,__BPF_CAST,__BPF_N,__VA_ARGS__));\ } \ static __always_inline \ u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)) -#define BPF_CALL_0(name, ...) BPF_CALL_x(0, name, __VA_ARGS__) -#define BPF_CALL_1(name, ...) BPF_CALL_x(1, name, __VA_ARGS__) -#define BPF_CALL_2(name, ...) BPF_CALL_x(2, name, __VA_ARGS__) -#define BPF_CALL_3(name, ...) BPF_CALL_x(3, name, __VA_ARGS__) -#define BPF_CALL_4(name, ...) BPF_CALL_x(4, name, __VA_ARGS__) -#define BPF_CALL_5(name, ...) BPF_CALL_x(5, name, __VA_ARGS__) +#define __NOATTR +#define BPF_CALL_0(name, ...) BPF_CALL_x(0, __NOATTR, name, __VA_ARGS__) +#define BPF_CALL_1(name, ...) BPF_CALL_x(1, __NOATTR, name, __VA_ARGS__) +#define BPF_CALL_2(name, ...) BPF_CALL_x(2, __NOATTR, name, __VA_ARGS__) +#define BPF_CALL_3(name, ...) BPF_CALL_x(3, __NOATTR, name, __VA_ARGS__) +#define BPF_CALL_4(name, ...) BPF_CALL_x(4, __NOATTR, name, __VA_ARGS__) +#define BPF_CALL_5(name, ...) BPF_CALL_x(5, __NOATTR, name, __VA_ARGS__) + +#define NOTRACE_BPF_CALL_1(name, ...) BPF_CALL_x(1, notrace, name, __VA_ARGS__) #define bpf_ctx_range(TYPE, MEMBER) \ offsetof(TYPE, MEMBER) ... offsetofend(TYPE, MEMBER) - 1 diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 3503949b4c1b..93edf730d288 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -334,7 +334,7 @@ static inline void __bpf_spin_lock_irqsave(struct bpf_spin_lock *lock) __this_cpu_write(irqsave_flags, flags); } -notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) +NOTRACE_BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) { __bpf_spin_lock_irqsave(lock); return 0; @@ -357,7 +357,7 @@ static inline void __bpf_spin_unlock_irqrestore(struct bpf_spin_lock *lock) local_irq_restore(flags); } -notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) +NOTRACE_BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) { __bpf_spin_unlock_irqrestore(lock); return 0; From fc1c9e40da37905f87c73711a1ecc57f52c1fe1c Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 6 Feb 2024 23:01:07 -0800 Subject: [PATCH 1162/2255] selftests/bpf: Ensure fentry prog cannot attach to bpf_spin_{lock,unlcok}() Add two tests to ensure fentry programs cannot attach to bpf_spin_{lock,unlock}() helpers. The tracing_failure.c files can be used in the future for other tracing failure cases. Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240207070107.335341-1-yonghong.song@linux.dev --- .../bpf/prog_tests/tracing_failure.c | 37 +++++++++++++++++++ .../selftests/bpf/progs/tracing_failure.c | 20 ++++++++++ 2 files changed, 57 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/tracing_failure.c create mode 100644 tools/testing/selftests/bpf/progs/tracing_failure.c diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c new file mode 100644 index 000000000000..a222df765bc3 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include "tracing_failure.skel.h" + +static void test_bpf_spin_lock(bool is_spin_lock) +{ + struct tracing_failure *skel; + int err; + + skel = tracing_failure__open(); + if (!ASSERT_OK_PTR(skel, "tracing_failure__open")) + return; + + if (is_spin_lock) + bpf_program__set_autoload(skel->progs.test_spin_lock, true); + else + bpf_program__set_autoload(skel->progs.test_spin_unlock, true); + + err = tracing_failure__load(skel); + if (!ASSERT_OK(err, "tracing_failure__load")) + goto out; + + err = tracing_failure__attach(skel); + ASSERT_ERR(err, "tracing_failure__attach"); + +out: + tracing_failure__destroy(skel); +} + +void test_tracing_failure(void) +{ + if (test__start_subtest("bpf_spin_lock")) + test_bpf_spin_lock(true); + if (test__start_subtest("bpf_spin_unlock")) + test_bpf_spin_lock(false); +} diff --git a/tools/testing/selftests/bpf/progs/tracing_failure.c b/tools/testing/selftests/bpf/progs/tracing_failure.c new file mode 100644 index 000000000000..d41665d2ec8c --- /dev/null +++ b/tools/testing/selftests/bpf/progs/tracing_failure.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include + +char _license[] SEC("license") = "GPL"; + +SEC("?fentry/bpf_spin_lock") +int BPF_PROG(test_spin_lock, struct bpf_spin_lock *lock) +{ + return 0; +} + +SEC("?fentry/bpf_spin_unlock") +int BPF_PROG(test_spin_unlock, struct bpf_spin_lock *lock) +{ + return 0; +} From 52dbd67dff5d050e99301100e2cac578eef9b2e9 Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Thu, 8 Feb 2024 21:36:12 +0100 Subject: [PATCH 1163/2255] bpf: Abstract loop unrolling pragmas in BPF selftests [Changes from V1: - Avoid conflict by rebasing with latest master.] Some BPF tests use loop unrolling compiler pragmas that are clang specific and not supported by GCC. These pragmas, along with their GCC equivalences are: #pragma clang loop unroll_count(N) #pragma GCC unroll N #pragma clang loop unroll(full) #pragma GCC unroll 65534 #pragma clang loop unroll(disable) #pragma GCC unroll 1 #pragma unroll [aka #pragma clang loop unroll(enable)] There is no GCC equivalence to this pragma. It enables unrolling on loops that the compiler would not ordinarily unroll even with -O2|-funroll-loops, but it is not equivalent to full unrolling either. This patch adds a new header progs/bpf_compiler.h that defines the following macros, which correspond to each pair of compiler-specific pragmas above: __pragma_loop_unroll_count(N) __pragma_loop_unroll_full __pragma_loop_no_unroll __pragma_loop_unroll The selftests using loop unrolling pragmas are then changed to include the header and use these macros in place of the explicit pragmas. Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240208203612.29611-1-jose.marchesi@oracle.com --- .../selftests/bpf/progs/bpf_compiler.h | 33 +++++++++++++++++++ tools/testing/selftests/bpf/progs/iters.c | 5 +-- tools/testing/selftests/bpf/progs/loop4.c | 4 ++- .../selftests/bpf/progs/profiler.inc.h | 17 +++++----- tools/testing/selftests/bpf/progs/pyperf.h | 7 ++-- .../testing/selftests/bpf/progs/strobemeta.h | 18 +++++----- .../selftests/bpf/progs/test_cls_redirect.c | 5 +-- .../selftests/bpf/progs/test_lwt_seg6local.c | 6 ++-- .../selftests/bpf/progs/test_seg6_loop.c | 4 ++- .../selftests/bpf/progs/test_skb_ctx.c | 4 ++- .../selftests/bpf/progs/test_sysctl_loop1.c | 6 ++-- .../selftests/bpf/progs/test_sysctl_loop2.c | 6 ++-- .../selftests/bpf/progs/test_sysctl_prog.c | 6 ++-- .../selftests/bpf/progs/test_tc_tunnel.c | 3 +- tools/testing/selftests/bpf/progs/test_xdp.c | 3 +- .../selftests/bpf/progs/test_xdp_loop.c | 3 +- .../selftests/bpf/progs/test_xdp_noinline.c | 5 +-- .../selftests/bpf/progs/xdp_synproxy_kern.c | 6 ++-- .../testing/selftests/bpf/progs/xdping_kern.c | 3 +- 19 files changed, 102 insertions(+), 42 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/bpf_compiler.h diff --git a/tools/testing/selftests/bpf/progs/bpf_compiler.h b/tools/testing/selftests/bpf/progs/bpf_compiler.h new file mode 100644 index 000000000000..a7c343dc82e6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bpf_compiler.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __BPF_COMPILER_H__ +#define __BPF_COMPILER_H__ + +#define DO_PRAGMA_(X) _Pragma(#X) + +#if __clang__ +#define __pragma_loop_unroll DO_PRAGMA_(clang loop unroll(enable)) +#else +/* In GCC -funroll-loops, which is enabled with -O2, should have the + same impact than the loop-unroll-enable pragma above. */ +#define __pragma_loop_unroll +#endif + +#if __clang__ +#define __pragma_loop_unroll_count(N) DO_PRAGMA_(clang loop unroll_count(N)) +#else +#define __pragma_loop_unroll_count(N) DO_PRAGMA_(GCC unroll N) +#endif + +#if __clang__ +#define __pragma_loop_unroll_full DO_PRAGMA_(clang loop unroll(full)) +#else +#define __pragma_loop_unroll_full DO_PRAGMA_(GCC unroll 65534) +#endif + +#if __clang__ +#define __pragma_loop_no_unroll DO_PRAGMA_(clang loop unroll(disable)) +#else +#define __pragma_loop_no_unroll DO_PRAGMA_(GCC unroll 1) +#endif + +#endif diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c index 225f02dd66d0..3db416606f2f 100644 --- a/tools/testing/selftests/bpf/progs/iters.c +++ b/tools/testing/selftests/bpf/progs/iters.c @@ -5,6 +5,7 @@ #include #include #include "bpf_misc.h" +#include "bpf_compiler.h" #define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof((x)[0])) @@ -183,7 +184,7 @@ int iter_pragma_unroll_loop(const void *ctx) MY_PID_GUARD(); bpf_iter_num_new(&it, 0, 2); -#pragma nounroll + __pragma_loop_no_unroll for (i = 0; i < 3; i++) { v = bpf_iter_num_next(&it); bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1); @@ -238,7 +239,7 @@ int iter_multiple_sequential_loops(const void *ctx) bpf_iter_num_destroy(&it); bpf_iter_num_new(&it, 0, 2); -#pragma nounroll + __pragma_loop_no_unroll for (i = 0; i < 3; i++) { v = bpf_iter_num_next(&it); bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1); diff --git a/tools/testing/selftests/bpf/progs/loop4.c b/tools/testing/selftests/bpf/progs/loop4.c index b35337926d66..0de0357f57cc 100644 --- a/tools/testing/selftests/bpf/progs/loop4.c +++ b/tools/testing/selftests/bpf/progs/loop4.c @@ -3,6 +3,8 @@ #include #include +#include "bpf_compiler.h" + char _license[] SEC("license") = "GPL"; SEC("socket") @@ -10,7 +12,7 @@ int combinations(volatile struct __sk_buff* skb) { int ret = 0, i; -#pragma nounroll + __pragma_loop_no_unroll for (i = 0; i < 20; i++) if (skb->len) ret |= 1 << i; diff --git a/tools/testing/selftests/bpf/progs/profiler.inc.h b/tools/testing/selftests/bpf/progs/profiler.inc.h index de3b6e4e4d0a..6957d9f2805e 100644 --- a/tools/testing/selftests/bpf/progs/profiler.inc.h +++ b/tools/testing/selftests/bpf/progs/profiler.inc.h @@ -8,6 +8,7 @@ #include "profiler.h" #include "err.h" #include "bpf_experimental.h" +#include "bpf_compiler.h" #ifndef NULL #define NULL 0 @@ -169,7 +170,7 @@ static INLINE int get_var_spid_index(struct var_kill_data_arr_t* arr_struct, int spid) { #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++) if (arr_struct->array[i].meta.pid == spid) @@ -185,7 +186,7 @@ static INLINE void populate_ancestors(struct task_struct* task, ancestors_data->num_ancestors = 0; #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (num_ancestors = 0; num_ancestors < MAX_ANCESTORS; num_ancestors++) { parent = BPF_CORE_READ(parent, real_parent); @@ -212,7 +213,7 @@ static INLINE void* read_full_cgroup_path(struct kernfs_node* cgroup_node, size_t filepart_length; #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < MAX_CGROUPS_PATH_DEPTH; i++) { filepart_length = @@ -261,7 +262,7 @@ static INLINE void* populate_cgroup_info(struct cgroup_data_t* cgroup_data, int cgrp_id = bpf_core_enum_value(enum cgroup_subsys_id___local, pids_cgrp_id___local); #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < CGROUP_SUBSYS_COUNT; i++) { struct cgroup_subsys_state* subsys = @@ -402,7 +403,7 @@ static INLINE int trace_var_sys_kill(void* ctx, int tpid, int sig) if (kill_data == NULL) return 0; #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++) if (arr_struct->array[i].meta.pid == 0) { @@ -482,7 +483,7 @@ read_absolute_file_path_from_dentry(struct dentry* filp_dentry, void* payload) struct dentry* parent_dentry; #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < MAX_PATH_DEPTH; i++) { filepart_length = @@ -508,7 +509,7 @@ is_ancestor_in_allowed_inodes(struct dentry* filp_dentry) { struct dentry* parent_dentry; #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < MAX_PATH_DEPTH; i++) { u64 dir_ino = BPF_CORE_READ(filp_dentry, d_inode, i_ino); @@ -629,7 +630,7 @@ int raw_tracepoint__sched_process_exit(void* ctx) struct kernfs_node* proc_kernfs = BPF_CORE_READ(task, cgroups, dfl_cgrp, kn); #ifdef UNROLL -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++) { struct var_kill_data_t* past_kill_data = &arr_struct->array[i]; diff --git a/tools/testing/selftests/bpf/progs/pyperf.h b/tools/testing/selftests/bpf/progs/pyperf.h index 026d573ce179..86484f07e1d1 100644 --- a/tools/testing/selftests/bpf/progs/pyperf.h +++ b/tools/testing/selftests/bpf/progs/pyperf.h @@ -8,6 +8,7 @@ #include #include #include "bpf_misc.h" +#include "bpf_compiler.h" #define FUNCTION_NAME_LEN 64 #define FILE_NAME_LEN 128 @@ -298,11 +299,11 @@ int __on_event(struct bpf_raw_tracepoint_args *ctx) #if defined(USE_ITER) /* no for loop, no unrolling */ #elif defined(NO_UNROLL) -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll #elif defined(UNROLL_COUNT) -#pragma clang loop unroll_count(UNROLL_COUNT) + __pragma_loop_unroll_count(UNROLL_COUNT) #else -#pragma clang loop unroll(full) + __pragma_loop_unroll_full #endif /* NO_UNROLL */ /* Unwind python stack */ #ifdef USE_ITER diff --git a/tools/testing/selftests/bpf/progs/strobemeta.h b/tools/testing/selftests/bpf/progs/strobemeta.h index 40df2cc26eaf..f74459eead26 100644 --- a/tools/testing/selftests/bpf/progs/strobemeta.h +++ b/tools/testing/selftests/bpf/progs/strobemeta.h @@ -10,6 +10,8 @@ #include #include +#include "bpf_compiler.h" + typedef uint32_t pid_t; struct task_struct {}; @@ -419,9 +421,9 @@ static __always_inline uint64_t read_map_var(struct strobemeta_cfg *cfg, } #ifdef NO_UNROLL -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll #else -#pragma unroll + __pragma_loop_unroll #endif for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { if (i >= map.cnt) @@ -560,25 +562,25 @@ static void *read_strobe_meta(struct task_struct *task, payload_off = sizeof(data->payload); #else #ifdef NO_UNROLL -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll #else -#pragma unroll + __pragma_loop_unroll #endif /* NO_UNROLL */ for (int i = 0; i < STROBE_MAX_INTS; ++i) { read_int_var(cfg, i, tls_base, &value, data); } #ifdef NO_UNROLL -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll #else -#pragma unroll + __pragma_loop_unroll #endif /* NO_UNROLL */ for (int i = 0; i < STROBE_MAX_STRS; ++i) { payload_off = read_str_var(cfg, i, tls_base, &value, data, payload_off); } #ifdef NO_UNROLL -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll #else -#pragma unroll + __pragma_loop_unroll #endif /* NO_UNROLL */ for (int i = 0; i < STROBE_MAX_MAPS; ++i) { payload_off = read_map_var(cfg, i, tls_base, &value, data, payload_off); diff --git a/tools/testing/selftests/bpf/progs/test_cls_redirect.c b/tools/testing/selftests/bpf/progs/test_cls_redirect.c index bfc9179259d5..683c8aaa63da 100644 --- a/tools/testing/selftests/bpf/progs/test_cls_redirect.c +++ b/tools/testing/selftests/bpf/progs/test_cls_redirect.c @@ -20,6 +20,7 @@ #include #include +#include "bpf_compiler.h" #include "test_cls_redirect.h" #pragma GCC diagnostic ignored "-Waddress-of-packed-member" @@ -269,7 +270,7 @@ static INLINING void pkt_ipv4_checksum(struct iphdr *iph) uint32_t acc = 0; uint16_t *ipw = (uint16_t *)iph; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (size_t i = 0; i < sizeof(struct iphdr) / 2; i++) { acc += ipw[i]; } @@ -296,7 +297,7 @@ bool pkt_skip_ipv6_extension_headers(buf_t *pkt, }; *is_fragment = false; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (int i = 0; i < 6; i++) { switch (exthdr.next) { case IPPROTO_FRAGMENT: diff --git a/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c b/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c index 48ff2b2ad5e7..fed66f36adb6 100644 --- a/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c +++ b/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c @@ -6,6 +6,8 @@ #include #include +#include "bpf_compiler.h" + /* Packet parsing state machine helpers. */ #define cursor_advance(_cursor, _len) \ ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) @@ -131,7 +133,7 @@ int is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, *pad_off = 0; // we can only go as far as ~10 TLVs due to the BPF max stack size - #pragma clang loop unroll(full) + __pragma_loop_unroll_full for (int i = 0; i < 10; i++) { struct sr6_tlv_t tlv; @@ -302,7 +304,7 @@ int __encap_srh(struct __sk_buff *skb) seg = (struct ip6_addr_t *)((char *)srh + sizeof(*srh)); - #pragma clang loop unroll(full) + __pragma_loop_unroll_full for (unsigned long long lo = 0; lo < 4; lo++) { seg->lo = bpf_cpu_to_be64(4 - lo); seg->hi = bpf_cpu_to_be64(hi); diff --git a/tools/testing/selftests/bpf/progs/test_seg6_loop.c b/tools/testing/selftests/bpf/progs/test_seg6_loop.c index a7278f064368..5059050f74f6 100644 --- a/tools/testing/selftests/bpf/progs/test_seg6_loop.c +++ b/tools/testing/selftests/bpf/progs/test_seg6_loop.c @@ -6,6 +6,8 @@ #include #include +#include "bpf_compiler.h" + /* Packet parsing state machine helpers. */ #define cursor_advance(_cursor, _len) \ ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) @@ -134,7 +136,7 @@ static __always_inline int is_valid_tlv_boundary(struct __sk_buff *skb, // we can only go as far as ~10 TLVs due to the BPF max stack size // workaround: define induction variable "i" as "long" instead // of "int" to prevent alu32 sub-register spilling. - #pragma clang loop unroll(disable) + __pragma_loop_no_unroll for (long i = 0; i < 100; i++) { struct sr6_tlv_t tlv; diff --git a/tools/testing/selftests/bpf/progs/test_skb_ctx.c b/tools/testing/selftests/bpf/progs/test_skb_ctx.c index c482110cfc95..a724a70c6700 100644 --- a/tools/testing/selftests/bpf/progs/test_skb_ctx.c +++ b/tools/testing/selftests/bpf/progs/test_skb_ctx.c @@ -3,12 +3,14 @@ #include #include +#include "bpf_compiler.h" + char _license[] SEC("license") = "GPL"; SEC("tc") int process(struct __sk_buff *skb) { - #pragma clang loop unroll(full) + __pragma_loop_unroll_full for (int i = 0; i < 5; i++) { if (skb->cb[i] != i + 1) return 1; diff --git a/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c b/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c index 553a282d816a..7f74077d6622 100644 --- a/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c +++ b/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c @@ -9,6 +9,8 @@ #include +#include "bpf_compiler.h" + #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif @@ -30,7 +32,7 @@ static __always_inline int is_tcp_mem(struct bpf_sysctl *ctx) if (ret < 0 || ret != sizeof(tcp_mem_name) - 1) return 0; -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll for (i = 0; i < sizeof(tcp_mem_name); ++i) if (name[i] != tcp_mem_name[i]) return 0; @@ -59,7 +61,7 @@ int sysctl_tcp_mem(struct bpf_sysctl *ctx) if (ret < 0 || ret >= MAX_VALUE_STR_LEN) return 0; -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll for (i = 0; i < ARRAY_SIZE(tcp_mem); ++i) { ret = bpf_strtoul(value + off, MAX_ULONG_STR_LEN, 0, tcp_mem + i); diff --git a/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c b/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c index 2b64bc563a12..68a75436e8af 100644 --- a/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c +++ b/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c @@ -9,6 +9,8 @@ #include +#include "bpf_compiler.h" + #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif @@ -30,7 +32,7 @@ static __attribute__((noinline)) int is_tcp_mem(struct bpf_sysctl *ctx) if (ret < 0 || ret != sizeof(tcp_mem_name) - 1) return 0; -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll for (i = 0; i < sizeof(tcp_mem_name); ++i) if (name[i] != tcp_mem_name[i]) return 0; @@ -57,7 +59,7 @@ int sysctl_tcp_mem(struct bpf_sysctl *ctx) if (ret < 0 || ret >= MAX_VALUE_STR_LEN) return 0; -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll for (i = 0; i < ARRAY_SIZE(tcp_mem); ++i) { ret = bpf_strtoul(value + off, MAX_ULONG_STR_LEN, 0, tcp_mem + i); diff --git a/tools/testing/selftests/bpf/progs/test_sysctl_prog.c b/tools/testing/selftests/bpf/progs/test_sysctl_prog.c index 5489823c83fc..efc3c61f7852 100644 --- a/tools/testing/selftests/bpf/progs/test_sysctl_prog.c +++ b/tools/testing/selftests/bpf/progs/test_sysctl_prog.c @@ -9,6 +9,8 @@ #include +#include "bpf_compiler.h" + /* Max supported length of a string with unsigned long in base 10 (pow2 - 1). */ #define MAX_ULONG_STR_LEN 0xF @@ -31,7 +33,7 @@ static __always_inline int is_tcp_mem(struct bpf_sysctl *ctx) if (ret < 0 || ret != sizeof(tcp_mem_name) - 1) return 0; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (i = 0; i < sizeof(tcp_mem_name); ++i) if (name[i] != tcp_mem_name[i]) return 0; @@ -57,7 +59,7 @@ int sysctl_tcp_mem(struct bpf_sysctl *ctx) if (ret < 0 || ret >= MAX_VALUE_STR_LEN) return 0; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (i = 0; i < ARRAY_SIZE(tcp_mem); ++i) { ret = bpf_strtoul(value + off, MAX_ULONG_STR_LEN, 0, tcp_mem + i); diff --git a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c index d8d7ab5e8e30..404124a93892 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c +++ b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c @@ -19,6 +19,7 @@ #include #include +#include "bpf_compiler.h" #pragma GCC diagnostic ignored "-Waddress-of-packed-member" @@ -83,7 +84,7 @@ static __always_inline void set_ipv4_csum(struct iphdr *iph) iph->check = 0; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (i = 0, csum = 0; i < sizeof(*iph) >> 1; i++) csum += *iph16++; diff --git a/tools/testing/selftests/bpf/progs/test_xdp.c b/tools/testing/selftests/bpf/progs/test_xdp.c index d7a9a74b7245..8caf58be5818 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp.c +++ b/tools/testing/selftests/bpf/progs/test_xdp.c @@ -19,6 +19,7 @@ #include #include #include "test_iptunnel_common.h" +#include "bpf_compiler.h" struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); @@ -137,7 +138,7 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp) iph->ttl = 8; next_iph = (__u16 *)iph; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (i = 0; i < sizeof(*iph) >> 1; i++) csum += *next_iph++; diff --git a/tools/testing/selftests/bpf/progs/test_xdp_loop.c b/tools/testing/selftests/bpf/progs/test_xdp_loop.c index c98fb44156f0..93267a68825b 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_loop.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_loop.c @@ -15,6 +15,7 @@ #include #include #include "test_iptunnel_common.h" +#include "bpf_compiler.h" struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); @@ -133,7 +134,7 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp) iph->ttl = 8; next_iph = (__u16 *)iph; -#pragma clang loop unroll(disable) + __pragma_loop_no_unroll for (i = 0; i < sizeof(*iph) >> 1; i++) csum += *next_iph++; diff --git a/tools/testing/selftests/bpf/progs/test_xdp_noinline.c b/tools/testing/selftests/bpf/progs/test_xdp_noinline.c index 42c8f6ded0e4..5c7e4758a0ca 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_noinline.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_noinline.c @@ -15,6 +15,7 @@ #include #include #include +#include "bpf_compiler.h" static __always_inline __u32 rol32(__u32 word, unsigned int shift) { @@ -362,7 +363,7 @@ bool encap_v4(struct xdp_md *xdp, struct ctl_value *cval, iph->ttl = 4; next_iph_u16 = (__u16 *) iph; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (int i = 0; i < sizeof(struct iphdr) >> 1; i++) csum += *next_iph_u16++; iph->check = ~((csum & 0xffff) + (csum >> 16)); @@ -409,7 +410,7 @@ int send_icmp_reply(void *data, void *data_end) iph->saddr = tmp_addr; iph->check = 0; next_iph_u16 = (__u16 *) iph; -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (int i = 0; i < sizeof(struct iphdr) >> 1; i++) csum += *next_iph_u16++; iph->check = ~((csum & 0xffff) + (csum >> 16)); diff --git a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c index 518329c666e9..7ea9785738b5 100644 --- a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c +++ b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c @@ -7,6 +7,8 @@ #include #include +#include "bpf_compiler.h" + #define TC_ACT_OK 0 #define TC_ACT_SHOT 2 @@ -151,11 +153,11 @@ static __always_inline __u16 csum_ipv6_magic(const struct in6_addr *saddr, __u64 sum = csum; int i; -#pragma unroll + __pragma_loop_unroll for (i = 0; i < 4; i++) sum += (__u32)saddr->in6_u.u6_addr32[i]; -#pragma unroll + __pragma_loop_unroll for (i = 0; i < 4; i++) sum += (__u32)daddr->in6_u.u6_addr32[i]; diff --git a/tools/testing/selftests/bpf/progs/xdping_kern.c b/tools/testing/selftests/bpf/progs/xdping_kern.c index 54cf1765118b..44e2b0ef23ae 100644 --- a/tools/testing/selftests/bpf/progs/xdping_kern.c +++ b/tools/testing/selftests/bpf/progs/xdping_kern.c @@ -15,6 +15,7 @@ #include #include +#include "bpf_compiler.h" #include "xdping.h" struct { @@ -116,7 +117,7 @@ int xdping_client(struct xdp_md *ctx) return XDP_PASS; if (pinginfo->start) { -#pragma clang loop unroll(full) + __pragma_loop_unroll_full for (i = 0; i < XDPING_MAX_COUNT; i++) { if (pinginfo->times[i] == 0) break; From 12bbcf8e840f40b82b02981e96e0a5fbb0703ea9 Mon Sep 17 00:00:00 2001 From: Cupertino Miranda Date: Tue, 13 Feb 2024 17:35:43 +0000 Subject: [PATCH 1164/2255] libbpf: Add support to GCC in CORE macro definitions Due to internal differences between LLVM and GCC the current implementation for the CO-RE macros does not fit GCC parser, as it will optimize those expressions even before those would be accessible by the BPF backend. As examples, the following would be optimized out with the original definitions: - As enums are converted to their integer representation during parsing, the IR would not know how to distinguish an integer constant from an actual enum value. - Types need to be kept as temporary variables, as the existing type casts of the 0 address (as expanded for LLVM), are optimized away by the GCC C parser, never really reaching GCCs IR. Although, the macros appear to add extra complexity, the expanded code is removed from the compilation flow very early in the compilation process, not really affecting the quality of the generated assembly. Signed-off-by: Cupertino Miranda Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240213173543.1397708-1-cupertino.miranda@oracle.com --- tools/lib/bpf/bpf_core_read.h | 45 +++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/tools/lib/bpf/bpf_core_read.h b/tools/lib/bpf/bpf_core_read.h index 0d3e88bd7d5f..1ce738d91685 100644 --- a/tools/lib/bpf/bpf_core_read.h +++ b/tools/lib/bpf/bpf_core_read.h @@ -46,7 +46,7 @@ enum bpf_enum_value_kind { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \ bpf_probe_read_kernel( \ - (void *)dst, \ + (void *)dst, \ __CORE_RELO(src, fld, BYTE_SIZE), \ (const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET)) #else @@ -145,8 +145,29 @@ enum bpf_enum_value_kind { } \ }) +/* Differentiator between compilers builtin implementations. This is a + * requirement due to the compiler parsing differences where GCC optimizes + * early in parsing those constructs of type pointers to the builtin specific + * type, resulting in not being possible to collect the required type + * information in the builtin expansion. + */ +#ifdef __clang__ +#define ___bpf_typeof(type) ((typeof(type) *) 0) +#else +#define ___bpf_typeof1(type, NR) ({ \ + extern typeof(type) *___concat(bpf_type_tmp_, NR); \ + ___concat(bpf_type_tmp_, NR); \ +}) +#define ___bpf_typeof(type) ___bpf_typeof1(type, __COUNTER__) +#endif + +#ifdef __clang__ #define ___bpf_field_ref1(field) (field) -#define ___bpf_field_ref2(type, field) (((typeof(type) *)0)->field) +#define ___bpf_field_ref2(type, field) (___bpf_typeof(type)->field) +#else +#define ___bpf_field_ref1(field) (&(field)) +#define ___bpf_field_ref2(type, field) (&(___bpf_typeof(type)->field)) +#endif #define ___bpf_field_ref(args...) \ ___bpf_apply(___bpf_field_ref, ___bpf_narg(args))(args) @@ -196,7 +217,7 @@ enum bpf_enum_value_kind { * BTF. Always succeeds. */ #define bpf_core_type_id_local(type) \ - __builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL) + __builtin_btf_type_id(*___bpf_typeof(type), BPF_TYPE_ID_LOCAL) /* * Convenience macro to get BTF type ID of a target kernel's type that matches @@ -206,7 +227,7 @@ enum bpf_enum_value_kind { * - 0, if no matching type was found in a target kernel BTF. */ #define bpf_core_type_id_kernel(type) \ - __builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET) + __builtin_btf_type_id(*___bpf_typeof(type), BPF_TYPE_ID_TARGET) /* * Convenience macro to check that provided named type @@ -216,7 +237,7 @@ enum bpf_enum_value_kind { * 0, if no matching type is found. */ #define bpf_core_type_exists(type) \ - __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS) + __builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_EXISTS) /* * Convenience macro to check that provided named type @@ -226,7 +247,7 @@ enum bpf_enum_value_kind { * 0, if the type does not match any in the target kernel */ #define bpf_core_type_matches(type) \ - __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_MATCHES) + __builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_MATCHES) /* * Convenience macro to get the byte size of a provided named type @@ -236,7 +257,7 @@ enum bpf_enum_value_kind { * 0, if no matching type is found. */ #define bpf_core_type_size(type) \ - __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE) + __builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_SIZE) /* * Convenience macro to check that provided enumerator value is defined in @@ -246,8 +267,13 @@ enum bpf_enum_value_kind { * kernel's BTF; * 0, if no matching enum and/or enum value within that enum is found. */ +#ifdef __clang__ #define bpf_core_enum_value_exists(enum_type, enum_value) \ __builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS) +#else +#define bpf_core_enum_value_exists(enum_type, enum_value) \ + __builtin_preserve_enum_value(___bpf_typeof(enum_type), enum_value, BPF_ENUMVAL_EXISTS) +#endif /* * Convenience macro to get the integer value of an enumerator value in @@ -257,8 +283,13 @@ enum bpf_enum_value_kind { * present in target kernel's BTF; * 0, if no matching enum and/or enum value within that enum is found. */ +#ifdef __clang__ #define bpf_core_enum_value(enum_type, enum_value) \ __builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE) +#else +#define bpf_core_enum_value(enum_type, enum_value) \ + __builtin_preserve_enum_value(___bpf_typeof(enum_type), enum_value, BPF_ENUMVAL_VALUE) +#endif /* * bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures From dc8543b597c282643a433e9a8af0459ed3046908 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 8 Feb 2024 14:14:49 -0800 Subject: [PATCH 1165/2255] bpf, docs: Update ISA document title * Use "Instruction Set Architecture (ISA)" instead of "Instruction Set Specification" * Remove version number As previously discussed on the mailing list at https://mailarchive.ietf.org/arch/msg/bpf/SEpn3OL9TabNRn-4rDX9A6XVbjM/ Signed-off-by: Dave Thaler Signed-off-by: Daniel Borkmann Acked-by: David Vernet Link: https://lore.kernel.org/bpf/20240208221449.12274-1-dthaler1968@gmail.com --- Documentation/bpf/standardization/instruction-set.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index bdfe0cd0e499..868d9f6177e3 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -1,11 +1,11 @@ .. contents:: .. sectnum:: -======================================= -BPF Instruction Set Specification, v1.0 -======================================= +====================================== +BPF Instruction Set Architecture (ISA) +====================================== -This document specifies version 1.0 of the BPF instruction set. +This document specifies the BPF instruction set architecture (ISA). Documentation conventions ========================= From 77c0208e199ccb0986fb3612f2409c8cdcb036ad Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 18:37:47 -0800 Subject: [PATCH 1166/2255] bpf: add btf pointer to struct bpf_ctx_arg_aux. Enable the providers to use types defined in a module instead of in the kernel (btf_vmlinux). Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240209023750.1153905-2-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 1 + kernel/bpf/btf.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1ebbee1d648e..3b7836f0a83e 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1415,6 +1415,7 @@ struct bpf_jit_poke_descriptor { struct bpf_ctx_arg_aux { u32 offset; enum bpf_reg_type reg_type; + struct btf *btf; u32 btf_id; }; diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 8e06d29961f1..cf100b5573ca 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6266,7 +6266,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, } info->reg_type = ctx_arg_info->reg_type; - info->btf = btf_vmlinux; + info->btf = ctx_arg_info->btf ? : btf_vmlinux; info->btf_id = ctx_arg_info->btf_id; return true; } From 6115a0aeef01aef152ad7738393aad11422bfb82 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 18:37:48 -0800 Subject: [PATCH 1167/2255] bpf: Move __kfunc_param_match_suffix() to btf.c. Move __kfunc_param_match_suffix() to btf.c and rename it as btf_param_match_suffix(). It can be reused by bpf_struct_ops later. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240209023750.1153905-3-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/btf.h | 4 ++++ kernel/bpf/btf.c | 18 ++++++++++++++++++ kernel/bpf/verifier.c | 38 ++++++++++---------------------------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index 1ee8977b8c95..df76a14c64f6 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -495,6 +495,10 @@ static inline void *btf_id_set8_contains(const struct btf_id_set8 *set, u32 id) return bsearch(&id, set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func); } +bool btf_param_match_suffix(const struct btf *btf, + const struct btf_param *arg, + const char *suffix); + struct bpf_verifier_log; #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index cf100b5573ca..447da964f217 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -8904,3 +8904,21 @@ errout: } EXPORT_SYMBOL_GPL(__register_bpf_struct_ops); #endif + +bool btf_param_match_suffix(const struct btf *btf, + const struct btf_param *arg, + const char *suffix) +{ + int suffix_len = strlen(suffix), len; + const char *param_name; + + /* In the future, this can be ported to use BTF tagging */ + param_name = btf_name_by_offset(btf, arg->name_off); + if (str_is_empty(param_name)) + return false; + len = strlen(param_name); + if (len <= suffix_len) + return false; + param_name += len - suffix_len; + return !strncmp(param_name, suffix, suffix_len); +} diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ddaf09db1175..c92d6af7d975 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10682,24 +10682,6 @@ static bool is_kfunc_rcu_protected(struct bpf_kfunc_call_arg_meta *meta) return meta->kfunc_flags & KF_RCU_PROTECTED; } -static bool __kfunc_param_match_suffix(const struct btf *btf, - const struct btf_param *arg, - const char *suffix) -{ - int suffix_len = strlen(suffix), len; - const char *param_name; - - /* In the future, this can be ported to use BTF tagging */ - param_name = btf_name_by_offset(btf, arg->name_off); - if (str_is_empty(param_name)) - return false; - len = strlen(param_name); - if (len < suffix_len) - return false; - param_name += len - suffix_len; - return !strncmp(param_name, suffix, suffix_len); -} - static bool is_kfunc_arg_mem_size(const struct btf *btf, const struct btf_param *arg, const struct bpf_reg_state *reg) @@ -10710,7 +10692,7 @@ static bool is_kfunc_arg_mem_size(const struct btf *btf, if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE) return false; - return __kfunc_param_match_suffix(btf, arg, "__sz"); + return btf_param_match_suffix(btf, arg, "__sz"); } static bool is_kfunc_arg_const_mem_size(const struct btf *btf, @@ -10723,47 +10705,47 @@ static bool is_kfunc_arg_const_mem_size(const struct btf *btf, if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE) return false; - return __kfunc_param_match_suffix(btf, arg, "__szk"); + return btf_param_match_suffix(btf, arg, "__szk"); } static bool is_kfunc_arg_optional(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__opt"); + return btf_param_match_suffix(btf, arg, "__opt"); } static bool is_kfunc_arg_constant(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__k"); + return btf_param_match_suffix(btf, arg, "__k"); } static bool is_kfunc_arg_ignore(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__ign"); + return btf_param_match_suffix(btf, arg, "__ign"); } static bool is_kfunc_arg_alloc_obj(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__alloc"); + return btf_param_match_suffix(btf, arg, "__alloc"); } static bool is_kfunc_arg_uninit(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__uninit"); + return btf_param_match_suffix(btf, arg, "__uninit"); } static bool is_kfunc_arg_refcounted_kptr(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__refcounted_kptr"); + return btf_param_match_suffix(btf, arg, "__refcounted_kptr"); } static bool is_kfunc_arg_nullable(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__nullable"); + return btf_param_match_suffix(btf, arg, "__nullable"); } static bool is_kfunc_arg_const_str(const struct btf *btf, const struct btf_param *arg) { - return __kfunc_param_match_suffix(btf, arg, "__str"); + return btf_param_match_suffix(btf, arg, "__str"); } static bool is_kfunc_arg_scalar_with_name(const struct btf *btf, From 1611603537a4b88cec7993f32b70c03113801a46 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 18:37:49 -0800 Subject: [PATCH 1168/2255] bpf: Create argument information for nullable arguments. Collect argument information from the type information of stub functions to mark arguments of BPF struct_ops programs with PTR_MAYBE_NULL if they are nullable. A nullable argument is annotated by suffixing "__nullable" at the argument name of stub function. For nullable arguments, this patch sets a struct bpf_ctx_arg_aux to label their reg_type with PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL. This makes the verifier to check programs and ensure that they properly check the pointer. The programs should check if the pointer is null before accessing the pointed memory. The implementer of a struct_ops type should annotate the arguments that can be null. The implementer should define a stub function (empty) as a placeholder for each defined operator. The name of a stub function should be in the pattern "__". For example, for test_maybe_null of struct bpf_testmod_ops, it's stub function name should be "bpf_testmod_ops__test_maybe_null". You mark an argument nullable by suffixing the argument name with "__nullable" at the stub function. Since we already has stub functions for kCFI, we just reuse these stub functions with the naming convention mentioned earlier. These stub functions with the naming convention is only required if there are nullable arguments to annotate. For functions having not nullable arguments, stub functions are not necessary for the purpose of this patch. This patch will prepare a list of struct bpf_ctx_arg_aux, aka arg_info, for each member field of a struct_ops type. "arg_info" will be assigned to "prog->aux->ctx_arg_info" of BPF struct_ops programs in check_struct_ops_btf_id() so that it can be used by btf_ctx_access() later to set reg_type properly for the verifier. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240209023750.1153905-4-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 21 ++++ include/linux/btf.h | 2 + kernel/bpf/bpf_struct_ops.c | 213 ++++++++++++++++++++++++++++++++++-- kernel/bpf/btf.c | 27 +++++ kernel/bpf/verifier.c | 6 + 5 files changed, 257 insertions(+), 12 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 3b7836f0a83e..c7aa99b44dbd 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1709,6 +1709,19 @@ struct bpf_struct_ops { struct btf_func_model func_models[BPF_STRUCT_OPS_MAX_NR_MEMBERS]; }; +/* Every member of a struct_ops type has an instance even a member is not + * an operator (function pointer). The "info" field will be assigned to + * prog->aux->ctx_arg_info of BPF struct_ops programs to provide the + * argument information required by the verifier to verify the program. + * + * btf_ctx_access() will lookup prog->aux->ctx_arg_info to find the + * corresponding entry for an given argument. + */ +struct bpf_struct_ops_arg_info { + struct bpf_ctx_arg_aux *info; + u32 cnt; +}; + struct bpf_struct_ops_desc { struct bpf_struct_ops *st_ops; @@ -1716,6 +1729,9 @@ struct bpf_struct_ops_desc { const struct btf_type *value_type; u32 type_id; u32 value_id; + + /* Collection of argument information for each member */ + struct bpf_struct_ops_arg_info *arg_info; }; enum bpf_struct_ops_state { @@ -1790,6 +1806,7 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, struct btf *btf, struct bpf_verifier_log *log); void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map); +void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc); #else #define register_bpf_struct_ops(st_ops, type) ({ (void *)(st_ops); 0; }) static inline bool bpf_try_module_get(const void *data, struct module *owner) @@ -1814,6 +1831,10 @@ static inline void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struc { } +static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc) +{ +} + #endif #if defined(CONFIG_CGROUP_BPF) && defined(CONFIG_BPF_LSM) diff --git a/include/linux/btf.h b/include/linux/btf.h index df76a14c64f6..cb96f6263638 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -498,6 +498,8 @@ static inline void *btf_id_set8_contains(const struct btf_id_set8 *set, u32 id) bool btf_param_match_suffix(const struct btf *btf, const struct btf_param *arg, const char *suffix); +int btf_ctx_arg_offset(const struct btf *btf, const struct btf_type *func_proto, + u32 arg_no); struct bpf_verifier_log; diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index f98f580de77a..0d7be97a2411 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -116,17 +116,183 @@ static bool is_valid_value_type(struct btf *btf, s32 value_id, return true; } +#define MAYBE_NULL_SUFFIX "__nullable" +#define MAX_STUB_NAME 128 + +/* Return the type info of a stub function, if it exists. + * + * The name of a stub function is made up of the name of the struct_ops and + * the name of the function pointer member, separated by "__". For example, + * if the struct_ops type is named "foo_ops" and the function pointer + * member is named "bar", the stub function name would be "foo_ops__bar". + */ +static const struct btf_type * +find_stub_func_proto(const struct btf *btf, const char *st_op_name, + const char *member_name) +{ + char stub_func_name[MAX_STUB_NAME]; + const struct btf_type *func_type; + s32 btf_id; + int cp; + + cp = snprintf(stub_func_name, MAX_STUB_NAME, "%s__%s", + st_op_name, member_name); + if (cp >= MAX_STUB_NAME) { + pr_warn("Stub function name too long\n"); + return NULL; + } + btf_id = btf_find_by_name_kind(btf, stub_func_name, BTF_KIND_FUNC); + if (btf_id < 0) + return NULL; + func_type = btf_type_by_id(btf, btf_id); + if (!func_type) + return NULL; + + return btf_type_by_id(btf, func_type->type); /* FUNC_PROTO */ +} + +/* Prepare argument info for every nullable argument of a member of a + * struct_ops type. + * + * Initialize a struct bpf_struct_ops_arg_info according to type info of + * the arguments of a stub function. (Check kCFI for more information about + * stub functions.) + * + * Each member in the struct_ops type has a struct bpf_struct_ops_arg_info + * to provide an array of struct bpf_ctx_arg_aux, which in turn provides + * the information that used by the verifier to check the arguments of the + * BPF struct_ops program assigned to the member. Here, we only care about + * the arguments that are marked as __nullable. + * + * The array of struct bpf_ctx_arg_aux is eventually assigned to + * prog->aux->ctx_arg_info of BPF struct_ops programs and passed to the + * verifier. (See check_struct_ops_btf_id()) + * + * arg_info->info will be the list of struct bpf_ctx_arg_aux if success. If + * fails, it will be kept untouched. + */ +static int prepare_arg_info(struct btf *btf, + const char *st_ops_name, + const char *member_name, + const struct btf_type *func_proto, + struct bpf_struct_ops_arg_info *arg_info) +{ + const struct btf_type *stub_func_proto, *pointed_type; + const struct btf_param *stub_args, *args; + struct bpf_ctx_arg_aux *info, *info_buf; + u32 nargs, arg_no, info_cnt = 0; + u32 arg_btf_id; + int offset; + + stub_func_proto = find_stub_func_proto(btf, st_ops_name, member_name); + if (!stub_func_proto) + return 0; + + /* Check if the number of arguments of the stub function is the same + * as the number of arguments of the function pointer. + */ + nargs = btf_type_vlen(func_proto); + if (nargs != btf_type_vlen(stub_func_proto)) { + pr_warn("the number of arguments of the stub function %s__%s does not match the number of arguments of the member %s of struct %s\n", + st_ops_name, member_name, member_name, st_ops_name); + return -EINVAL; + } + + if (!nargs) + return 0; + + args = btf_params(func_proto); + stub_args = btf_params(stub_func_proto); + + info_buf = kcalloc(nargs, sizeof(*info_buf), GFP_KERNEL); + if (!info_buf) + return -ENOMEM; + + /* Prepare info for every nullable argument */ + info = info_buf; + for (arg_no = 0; arg_no < nargs; arg_no++) { + /* Skip arguments that is not suffixed with + * "__nullable". + */ + if (!btf_param_match_suffix(btf, &stub_args[arg_no], + MAYBE_NULL_SUFFIX)) + continue; + + /* Should be a pointer to struct */ + pointed_type = btf_type_resolve_ptr(btf, + args[arg_no].type, + &arg_btf_id); + if (!pointed_type || + !btf_type_is_struct(pointed_type)) { + pr_warn("stub function %s__%s has %s tagging to an unsupported type\n", + st_ops_name, member_name, MAYBE_NULL_SUFFIX); + goto err_out; + } + + offset = btf_ctx_arg_offset(btf, func_proto, arg_no); + if (offset < 0) { + pr_warn("stub function %s__%s has an invalid trampoline ctx offset for arg#%u\n", + st_ops_name, member_name, arg_no); + goto err_out; + } + + if (args[arg_no].type != stub_args[arg_no].type) { + pr_warn("arg#%u type in stub function %s__%s does not match with its original func_proto\n", + arg_no, st_ops_name, member_name); + goto err_out; + } + + /* Fill the information of the new argument */ + info->reg_type = + PTR_TRUSTED | PTR_TO_BTF_ID | PTR_MAYBE_NULL; + info->btf_id = arg_btf_id; + info->btf = btf; + info->offset = offset; + + info++; + info_cnt++; + } + + if (info_cnt) { + arg_info->info = info_buf; + arg_info->cnt = info_cnt; + } else { + kfree(info_buf); + } + + return 0; + +err_out: + kfree(info_buf); + + return -EINVAL; +} + +/* Clean up the arg_info in a struct bpf_struct_ops_desc. */ +void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc) +{ + struct bpf_struct_ops_arg_info *arg_info; + int i; + + arg_info = st_ops_desc->arg_info; + for (i = 0; i < btf_type_vlen(st_ops_desc->type); i++) + kfree(arg_info[i].info); + + kfree(arg_info); +} + int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, struct btf *btf, struct bpf_verifier_log *log) { struct bpf_struct_ops *st_ops = st_ops_desc->st_ops; + struct bpf_struct_ops_arg_info *arg_info; const struct btf_member *member; const struct btf_type *t; s32 type_id, value_id; char value_name[128]; const char *mname; - int i; + int i, err; if (strlen(st_ops->name) + VALUE_PREFIX_LEN >= sizeof(value_name)) { @@ -160,6 +326,17 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, if (!is_valid_value_type(btf, value_id, t, value_name)) return -EINVAL; + arg_info = kcalloc(btf_type_vlen(t), sizeof(*arg_info), + GFP_KERNEL); + if (!arg_info) + return -ENOMEM; + + st_ops_desc->arg_info = arg_info; + st_ops_desc->type = t; + st_ops_desc->type_id = type_id; + st_ops_desc->value_id = value_id; + st_ops_desc->value_type = btf_type_by_id(btf, value_id); + for_each_member(i, t, member) { const struct btf_type *func_proto; @@ -167,40 +344,52 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, if (!*mname) { pr_warn("anon member in struct %s is not supported\n", st_ops->name); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto errout; } if (__btf_member_bitfield_size(t, member)) { pr_warn("bit field member %s in struct %s is not supported\n", mname, st_ops->name); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto errout; } func_proto = btf_type_resolve_func_ptr(btf, member->type, NULL); - if (func_proto && - btf_distill_func_proto(log, btf, + if (!func_proto) + continue; + + if (btf_distill_func_proto(log, btf, func_proto, mname, &st_ops->func_models[i])) { pr_warn("Error in parsing func ptr %s in struct %s\n", mname, st_ops->name); - return -EINVAL; + err = -EINVAL; + goto errout; } + + err = prepare_arg_info(btf, st_ops->name, mname, + func_proto, + arg_info + i); + if (err) + goto errout; } if (st_ops->init(btf)) { pr_warn("Error in init bpf_struct_ops %s\n", st_ops->name); - return -EINVAL; + err = -EINVAL; + goto errout; } - st_ops_desc->type_id = type_id; - st_ops_desc->type = t; - st_ops_desc->value_id = value_id; - st_ops_desc->value_type = btf_type_by_id(btf, value_id); - return 0; + +errout: + bpf_struct_ops_desc_release(st_ops_desc); + + return err; } static int bpf_struct_ops_map_get_next_key(struct bpf_map *map, void *key, diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 447da964f217..efd9bc274be0 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -1699,6 +1699,13 @@ static void btf_free_struct_meta_tab(struct btf *btf) static void btf_free_struct_ops_tab(struct btf *btf) { struct btf_struct_ops_tab *tab = btf->struct_ops_tab; + u32 i; + + if (!tab) + return; + + for (i = 0; i < tab->cnt; i++) + bpf_struct_ops_desc_release(&tab->ops[i]); kfree(tab); btf->struct_ops_tab = NULL; @@ -6130,6 +6137,26 @@ static bool prog_args_trusted(const struct bpf_prog *prog) } } +int btf_ctx_arg_offset(const struct btf *btf, const struct btf_type *func_proto, + u32 arg_no) +{ + const struct btf_param *args; + const struct btf_type *t; + int off = 0, i; + u32 sz; + + args = btf_params(func_proto); + for (i = 0; i < arg_no; i++) { + t = btf_type_by_id(btf, args[i].type); + t = btf_resolve_size(btf, t, &sz); + if (IS_ERR(t)) + return PTR_ERR(t); + off += roundup(sz, 8); + } + + return off; +} + bool btf_ctx_access(int off, int size, enum bpf_access_type type, const struct bpf_prog *prog, struct bpf_insn_access_aux *info) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c92d6af7d975..72ca27f49616 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20419,6 +20419,12 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) } } + /* btf_ctx_access() used this to provide argument type info */ + prog->aux->ctx_arg_info = + st_ops_desc->arg_info[member_idx].info; + prog->aux->ctx_arg_info_size = + st_ops_desc->arg_info[member_idx].cnt; + prog->aux->attach_func_proto = func_proto; prog->aux->attach_func_name = mname; env->ops = st_ops->verifier_ops; From 00f239eccf461a6403b3c16e767d04f3954cae98 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Thu, 8 Feb 2024 18:37:50 -0800 Subject: [PATCH 1169/2255] selftests/bpf: Test PTR_MAYBE_NULL arguments of struct_ops operators. Test if the verifier verifies nullable pointer arguments correctly for BPF struct_ops programs. "test_maybe_null" in struct bpf_testmod_ops is the operator defined for the test cases here. A BPF program should check a pointer for NULL beforehand to access the value pointed by the nullable pointer arguments, or the verifier should reject the programs. The test here includes two parts; the programs checking pointers properly and the programs not checking pointers beforehand. The test checks if the verifier accepts the programs checking properly and rejects the programs not checking at all. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240209023750.1153905-5-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- .../selftests/bpf/bpf_testmod/bpf_testmod.c | 13 +++++- .../selftests/bpf/bpf_testmod/bpf_testmod.h | 4 ++ .../prog_tests/test_struct_ops_maybe_null.c | 46 +++++++++++++++++++ .../bpf/progs/struct_ops_maybe_null.c | 29 ++++++++++++ .../bpf/progs/struct_ops_maybe_null_fail.c | 24 ++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_null.c create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_maybe_null.c create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_maybe_null_fail.c diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index a06daebc75c9..66787e99ba1b 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -555,7 +555,11 @@ static int bpf_dummy_reg(void *kdata) { struct bpf_testmod_ops *ops = kdata; - ops->test_2(4, 3); + /* Some test cases (ex. struct_ops_maybe_null) may not have test_2 + * initialized, so we need to check for NULL. + */ + if (ops->test_2) + ops->test_2(4, 3); return 0; } @@ -573,9 +577,16 @@ static void bpf_testmod_test_2(int a, int b) { } +static int bpf_testmod_ops__test_maybe_null(int dummy, + struct task_struct *task__nullable) +{ + return 0; +} + static struct bpf_testmod_ops __bpf_testmod_ops = { .test_1 = bpf_testmod_test_1, .test_2 = bpf_testmod_test_2, + .test_maybe_null = bpf_testmod_ops__test_maybe_null, }; struct bpf_struct_ops bpf_bpf_testmod_ops = { diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h index 537beca42896..c3b0cf788f9f 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h @@ -5,6 +5,8 @@ #include +struct task_struct; + struct bpf_testmod_test_read_ctx { char *buf; loff_t off; @@ -31,6 +33,8 @@ struct bpf_iter_testmod_seq { struct bpf_testmod_ops { int (*test_1)(void); void (*test_2)(int a, int b); + /* Used to test nullable arguments. */ + int (*test_maybe_null)(int dummy, struct task_struct *task); }; #endif /* _BPF_TESTMOD_H */ diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_null.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_null.c new file mode 100644 index 000000000000..01dc2613c8a5 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_null.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include + +#include "struct_ops_maybe_null.skel.h" +#include "struct_ops_maybe_null_fail.skel.h" + +/* Test that the verifier accepts a program that access a nullable pointer + * with a proper check. + */ +static void maybe_null(void) +{ + struct struct_ops_maybe_null *skel; + + skel = struct_ops_maybe_null__open_and_load(); + if (!ASSERT_OK_PTR(skel, "struct_ops_module_open_and_load")) + return; + + struct_ops_maybe_null__destroy(skel); +} + +/* Test that the verifier rejects a program that access a nullable pointer + * without a check beforehand. + */ +static void maybe_null_fail(void) +{ + struct struct_ops_maybe_null_fail *skel; + + skel = struct_ops_maybe_null_fail__open_and_load(); + if (ASSERT_ERR_PTR(skel, "struct_ops_module_fail__open_and_load")) + return; + + struct_ops_maybe_null_fail__destroy(skel); +} + +void test_struct_ops_maybe_null(void) +{ + /* The verifier verifies the programs at load time, so testing both + * programs in the same compile-unit is complicated. We run them in + * separate objects to simplify the testing. + */ + if (test__start_subtest("maybe_null")) + maybe_null(); + if (test__start_subtest("maybe_null_fail")) + maybe_null_fail(); +} diff --git a/tools/testing/selftests/bpf/progs/struct_ops_maybe_null.c b/tools/testing/selftests/bpf/progs/struct_ops_maybe_null.c new file mode 100644 index 000000000000..b450f72e744a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/struct_ops_maybe_null.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include "../bpf_testmod/bpf_testmod.h" + +char _license[] SEC("license") = "GPL"; + +pid_t tgid = 0; + +/* This is a test BPF program that uses struct_ops to access an argument + * that may be NULL. This is a test for the verifier to ensure that it can + * rip PTR_MAYBE_NULL correctly. + */ +SEC("struct_ops/test_maybe_null") +int BPF_PROG(test_maybe_null, int dummy, + struct task_struct *task) +{ + if (task) + tgid = task->tgid; + + return 0; +} + +SEC(".struct_ops.link") +struct bpf_testmod_ops testmod_1 = { + .test_maybe_null = (void *)test_maybe_null, +}; + diff --git a/tools/testing/selftests/bpf/progs/struct_ops_maybe_null_fail.c b/tools/testing/selftests/bpf/progs/struct_ops_maybe_null_fail.c new file mode 100644 index 000000000000..6283099ec383 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/struct_ops_maybe_null_fail.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include "../bpf_testmod/bpf_testmod.h" + +char _license[] SEC("license") = "GPL"; + +pid_t tgid = 0; + +SEC("struct_ops/test_maybe_null_struct_ptr") +int BPF_PROG(test_maybe_null_struct_ptr, int dummy, + struct task_struct *task) +{ + tgid = task->tgid; + + return 0; +} + +SEC(".struct_ops.link") +struct bpf_testmod_ops testmod_struct_ptr = { + .test_maybe_null = (void *)test_maybe_null_struct_ptr, +}; + From 32e18e7688c6847b0c9db073aafb00639ecf576c Mon Sep 17 00:00:00 2001 From: Oliver Crumrine Date: Fri, 9 Feb 2024 14:41:22 -0500 Subject: [PATCH 1170/2255] bpf: remove check in __cgroup_bpf_run_filter_skb Originally, this patch removed a redundant check in BPF_CGROUP_RUN_PROG_INET_EGRESS, as the check was already being done in the function it called, __cgroup_bpf_run_filter_skb. For v2, it was reccomended that I remove the check from __cgroup_bpf_run_filter_skb, and add the checks to the other macro that calls that function, BPF_CGROUP_RUN_PROG_INET_INGRESS. To sum it up, checking that the socket exists and that it is a full socket is now part of both macros BPF_CGROUP_RUN_PROG_INET_EGRESS and BPF_CGROUP_RUN_PROG_INET_INGRESS, and it is no longer part of the function they call, __cgroup_bpf_run_filter_skb. v3->v4: Fixed weird merge conflict. v2->v3: Sent to bpf-next instead of generic patch v1->v2: Addressed feedback about where check should be removed. Signed-off-by: Oliver Crumrine Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/r/7lv62yiyvmj5a7eozv2iznglpkydkdfancgmbhiptrgvgan5sy@3fl3onchgdz3 Signed-off-by: Martin KaFai Lau --- include/linux/bpf-cgroup.h | 3 ++- kernel/bpf/cgroup.c | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index a789266feac3..fb3c3e7181e6 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -196,7 +196,8 @@ static inline bool cgroup_bpf_sock_enabled(struct sock *sk, ({ \ int __ret = 0; \ if (cgroup_bpf_enabled(CGROUP_INET_INGRESS) && \ - cgroup_bpf_sock_enabled(sk, CGROUP_INET_INGRESS)) \ + cgroup_bpf_sock_enabled(sk, CGROUP_INET_INGRESS) && sk && \ + sk_fullsock(sk)) \ __ret = __cgroup_bpf_run_filter_skb(sk, skb, \ CGROUP_INET_INGRESS); \ \ diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 98e0e3835b28..5a568bbbeaeb 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1364,9 +1364,6 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk, struct cgroup *cgrp; int ret; - if (!sk || !sk_fullsock(sk)) - return 0; - if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6) return 0; From f383ced24d6ae6c1989394d052d3109b9d645f11 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 11 Feb 2024 21:44:03 +0000 Subject: [PATCH 1171/2255] vlan: use xarray iterator to implement /proc/net/vlan/config Adopt net->dev_by_index as I did in commit 0e0939c0adf9 ("net-procfs: use xarray iterator to implement /proc/net/dev") Not only this removes quadratic behavior, it also makes sure an existing vlan device is always visible in the dump, regardless of concurrent net->dev_base_head changes. Signed-off-by: Eric Dumazet Reviewed-by: Jakub Kicinski Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/20240211214404.1882191-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/8021q/vlanproc.c | 46 +++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 7825c129742a..87b959da00cd 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -163,48 +163,34 @@ void vlan_proc_rem_dev(struct net_device *vlandev) * The following few functions build the content of /proc/net/vlan/config */ -/* start read of /proc/net/vlan/config */ +static void *vlan_seq_from_index(struct seq_file *seq, loff_t *pos) +{ + unsigned long ifindex = *pos; + struct net_device *dev; + + for_each_netdev_dump(seq_file_net(seq), dev, ifindex) { + if (!is_vlan_dev(dev)) + continue; + *pos = dev->ifindex; + return dev; + } + return NULL; +} + static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) __acquires(rcu) { - struct net_device *dev; - struct net *net = seq_file_net(seq); - loff_t i = 1; - rcu_read_lock(); if (*pos == 0) return SEQ_START_TOKEN; - for_each_netdev_rcu(net, dev) { - if (!is_vlan_dev(dev)) - continue; - - if (i++ == *pos) - return dev; - } - - return NULL; + return vlan_seq_from_index(seq, pos); } static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct net_device *dev; - struct net *net = seq_file_net(seq); - ++*pos; - - dev = v; - if (v == SEQ_START_TOKEN) - dev = net_device_entry(&net->dev_base_head); - - for_each_netdev_continue_rcu(net, dev) { - if (!is_vlan_dev(dev)) - continue; - - return dev; - } - - return NULL; + return vlan_seq_from_index(seq, pos); } static void vlan_seq_stop(struct seq_file *seq, void *v) From 3e41af90767dcf8e5ca91cfbbbcb772584940df9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 11 Feb 2024 21:44:04 +0000 Subject: [PATCH 1172/2255] rtnetlink: use xarray iterator to implement rtnl_dump_ifinfo() Adopt net->dev_by_index as I did in commit 0e0939c0adf9 ("net-procfs: use xarray iterator to implement /proc/net/dev") This makes sure an existing device is always visible in the dump, regardless of concurrent insertions/deletions. v2: added suggestions from Jakub Kicinski and Ido Schimmel, thanks for the help ! Link: https://lore.kernel.org/all/20240209142441.6c56435b@kernel.org/ Link: https://lore.kernel.org/all/ZckR-XOsULLI9EHc@shredder/ Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/20240211214404.1882191-3-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/core/rtnetlink.c | 60 ++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 31f433950c8d..6f1c5537e842 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2188,25 +2188,22 @@ static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh, static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { + const struct rtnl_link_ops *kind_ops = NULL; struct netlink_ext_ack *extack = cb->extack; const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); - struct net *tgt_net = net; - int h, s_h; - int idx = 0, s_idx; - struct net_device *dev; - struct hlist_head *head; - struct nlattr *tb[IFLA_MAX+1]; - u32 ext_filter_mask = 0; - const struct rtnl_link_ops *kind_ops = NULL; unsigned int flags = NLM_F_MULTI; + struct nlattr *tb[IFLA_MAX+1]; + struct { + unsigned long ifindex; + } *ctx = (void *)cb->ctx; + struct net *tgt_net = net; + u32 ext_filter_mask = 0; + struct net_device *dev; int master_idx = 0; int netnsid = -1; int err, i; - s_h = cb->args[0]; - s_idx = cb->args[1]; - err = rtnl_valid_dump_ifinfo_req(nlh, cb->strict_check, tb, extack); if (err < 0) { if (cb->strict_check) @@ -2250,36 +2247,21 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) flags |= NLM_F_DUMP_FILTERED; walk_entries: - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &tgt_net->dev_index_head[h]; - hlist_for_each_entry(dev, head, index_hlist) { - if (link_dump_filtered(dev, master_idx, kind_ops)) - goto cont; - if (idx < s_idx) - goto cont; - err = rtnl_fill_ifinfo(skb, dev, net, - RTM_NEWLINK, - NETLINK_CB(cb->skb).portid, - nlh->nlmsg_seq, 0, flags, - ext_filter_mask, 0, NULL, 0, - netnsid, GFP_KERNEL); - - if (err < 0) { - if (likely(skb->len)) - goto out; - - goto out_err; - } -cont: - idx++; + err = 0; + for_each_netdev_dump(tgt_net, dev, ctx->ifindex) { + if (link_dump_filtered(dev, master_idx, kind_ops)) + continue; + err = rtnl_fill_ifinfo(skb, dev, net, RTM_NEWLINK, + NETLINK_CB(cb->skb).portid, + nlh->nlmsg_seq, 0, flags, + ext_filter_mask, 0, NULL, 0, + netnsid, GFP_KERNEL); + if (err < 0) { + if (likely(skb->len)) + err = skb->len; + break; } } -out: - err = skb->len; -out_err: - cb->args[1] = idx; - cb->args[0] = h; cb->seq = tgt_net->dev_base_seq; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); if (netnsid >= 0) From 9a3c93af549185863761fc4815ace9ab17dfc350 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 12 Feb 2024 14:06:58 +0000 Subject: [PATCH 1173/2255] vlan: use netdev_lockdep_set_classes() vlan uses vlan_dev_set_lockdep_class() which lacks qdisc_tx_busylock initialization. Use generic netdev_lockdep_set_classes() to not worry anymore. Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20240212140700.2795436-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/8021q/vlan_dev.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 407b2335f091..790b54a7cbe3 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -504,28 +504,6 @@ static void vlan_dev_set_rx_mode(struct net_device *vlan_dev) dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev); } -/* - * vlan network devices have devices nesting below it, and are a special - * "super class" of normal network devices; split their locks off into a - * separate class since they always nest. - */ -static struct lock_class_key vlan_netdev_xmit_lock_key; -static struct lock_class_key vlan_netdev_addr_lock_key; - -static void vlan_dev_set_lockdep_one(struct net_device *dev, - struct netdev_queue *txq, - void *unused) -{ - lockdep_set_class(&txq->_xmit_lock, &vlan_netdev_xmit_lock_key); -} - -static void vlan_dev_set_lockdep_class(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, - &vlan_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, NULL); -} - static __be16 vlan_parse_protocol(const struct sk_buff *skb) { struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); @@ -627,7 +605,7 @@ static int vlan_dev_init(struct net_device *dev) SET_NETDEV_DEVTYPE(dev, &vlan_type); - vlan_dev_set_lockdep_class(dev); + netdev_lockdep_set_classes(dev); vlan->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats); if (!vlan->vlan_pcpu_stats) From c74e1039912e63b91e8697796e321d157b44692e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 12 Feb 2024 14:06:59 +0000 Subject: [PATCH 1174/2255] net: bridge: use netdev_lockdep_set_classes() br_set_lockdep_class() is missing many details. Use generic netdev_lockdep_set_classes() to not worry anymore. Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20240212140700.2795436-3-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/bridge/br_device.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 65cee0ad3c1b..717e9750614c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -108,13 +108,6 @@ out: return NETDEV_TX_OK; } -static struct lock_class_key bridge_netdev_addr_lock_key; - -static void br_set_lockdep_class(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, &bridge_netdev_addr_lock_key); -} - static int br_dev_init(struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); @@ -153,7 +146,7 @@ static int br_dev_init(struct net_device *dev) br_fdb_hash_fini(br); } - br_set_lockdep_class(dev); + netdev_lockdep_set_classes(dev); return err; } From 0bef512012b1cd8820f0c9ec80e5f8ceb43fdd59 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 12 Feb 2024 14:07:00 +0000 Subject: [PATCH 1175/2255] net: add netdev_lockdep_set_classes() to virtual drivers Based on a syzbot report, it appears many virtual drivers do not yet use netdev_lockdep_set_classes(), triggerring lockdep false positives. WARNING: possible recursive locking detected 6.8.0-rc4-next-20240212-syzkaller #0 Not tainted syz-executor.0/19016 is trying to acquire lock: ffff8880162cb298 (_xmit_ETHER#2){+.-.}-{2:2}, at: spin_lock include/linux/spinlock.h:351 [inline] ffff8880162cb298 (_xmit_ETHER#2){+.-.}-{2:2}, at: __netif_tx_lock include/linux/netdevice.h:4452 [inline] ffff8880162cb298 (_xmit_ETHER#2){+.-.}-{2:2}, at: sch_direct_xmit+0x1c4/0x5f0 net/sched/sch_generic.c:340 but task is already holding lock: ffff8880223db4d8 (_xmit_ETHER#2){+.-.}-{2:2}, at: spin_lock include/linux/spinlock.h:351 [inline] ffff8880223db4d8 (_xmit_ETHER#2){+.-.}-{2:2}, at: __netif_tx_lock include/linux/netdevice.h:4452 [inline] ffff8880223db4d8 (_xmit_ETHER#2){+.-.}-{2:2}, at: sch_direct_xmit+0x1c4/0x5f0 net/sched/sch_generic.c:340 other info that might help us debug this: Possible unsafe locking scenario: CPU0 lock(_xmit_ETHER#2); lock(_xmit_ETHER#2); *** DEADLOCK *** May be due to missing lock nesting notation 9 locks held by syz-executor.0/19016: #0: ffffffff8f385208 (rtnl_mutex){+.+.}-{3:3}, at: rtnl_lock net/core/rtnetlink.c:79 [inline] #0: ffffffff8f385208 (rtnl_mutex){+.+.}-{3:3}, at: rtnetlink_rcv_msg+0x82c/0x1040 net/core/rtnetlink.c:6603 #1: ffffc90000a08c00 ((&in_dev->mr_ifc_timer)){+.-.}-{0:0}, at: call_timer_fn+0xc0/0x600 kernel/time/timer.c:1697 #2: ffffffff8e131520 (rcu_read_lock){....}-{1:2}, at: rcu_lock_acquire include/linux/rcupdate.h:298 [inline] #2: ffffffff8e131520 (rcu_read_lock){....}-{1:2}, at: rcu_read_lock include/linux/rcupdate.h:750 [inline] #2: ffffffff8e131520 (rcu_read_lock){....}-{1:2}, at: ip_finish_output2+0x45f/0x1360 net/ipv4/ip_output.c:228 #3: ffffffff8e131580 (rcu_read_lock_bh){....}-{1:2}, at: local_bh_disable include/linux/bottom_half.h:20 [inline] #3: ffffffff8e131580 (rcu_read_lock_bh){....}-{1:2}, at: rcu_read_lock_bh include/linux/rcupdate.h:802 [inline] #3: ffffffff8e131580 (rcu_read_lock_bh){....}-{1:2}, at: __dev_queue_xmit+0x2c4/0x3b10 net/core/dev.c:4284 #4: ffff8880416e3258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: spin_trylock include/linux/spinlock.h:361 [inline] #4: ffff8880416e3258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: qdisc_run_begin include/net/sch_generic.h:195 [inline] #4: ffff8880416e3258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: __dev_xmit_skb net/core/dev.c:3771 [inline] #4: ffff8880416e3258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: __dev_queue_xmit+0x1262/0x3b10 net/core/dev.c:4325 #5: ffff8880223db4d8 (_xmit_ETHER#2){+.-.}-{2:2}, at: spin_lock include/linux/spinlock.h:351 [inline] #5: ffff8880223db4d8 (_xmit_ETHER#2){+.-.}-{2:2}, at: __netif_tx_lock include/linux/netdevice.h:4452 [inline] #5: ffff8880223db4d8 (_xmit_ETHER#2){+.-.}-{2:2}, at: sch_direct_xmit+0x1c4/0x5f0 net/sched/sch_generic.c:340 #6: ffffffff8e131520 (rcu_read_lock){....}-{1:2}, at: rcu_lock_acquire include/linux/rcupdate.h:298 [inline] #6: ffffffff8e131520 (rcu_read_lock){....}-{1:2}, at: rcu_read_lock include/linux/rcupdate.h:750 [inline] #6: ffffffff8e131520 (rcu_read_lock){....}-{1:2}, at: ip_finish_output2+0x45f/0x1360 net/ipv4/ip_output.c:228 #7: ffffffff8e131580 (rcu_read_lock_bh){....}-{1:2}, at: local_bh_disable include/linux/bottom_half.h:20 [inline] #7: ffffffff8e131580 (rcu_read_lock_bh){....}-{1:2}, at: rcu_read_lock_bh include/linux/rcupdate.h:802 [inline] #7: ffffffff8e131580 (rcu_read_lock_bh){....}-{1:2}, at: __dev_queue_xmit+0x2c4/0x3b10 net/core/dev.c:4284 #8: ffff888014d9d258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: spin_trylock include/linux/spinlock.h:361 [inline] #8: ffff888014d9d258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: qdisc_run_begin include/net/sch_generic.h:195 [inline] #8: ffff888014d9d258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: __dev_xmit_skb net/core/dev.c:3771 [inline] #8: ffff888014d9d258 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: __dev_queue_xmit+0x1262/0x3b10 net/core/dev.c:4325 stack backtrace: CPU: 1 PID: 19016 Comm: syz-executor.0 Not tainted 6.8.0-rc4-next-20240212-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/25/2024 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x241/0x360 lib/dump_stack.c:114 check_deadlock kernel/locking/lockdep.c:3062 [inline] validate_chain+0x15c1/0x58e0 kernel/locking/lockdep.c:3856 __lock_acquire+0x1346/0x1fd0 kernel/locking/lockdep.c:5137 lock_acquire+0x1e4/0x530 kernel/locking/lockdep.c:5754 __raw_spin_lock include/linux/spinlock_api_smp.h:133 [inline] _raw_spin_lock+0x2e/0x40 kernel/locking/spinlock.c:154 spin_lock include/linux/spinlock.h:351 [inline] __netif_tx_lock include/linux/netdevice.h:4452 [inline] sch_direct_xmit+0x1c4/0x5f0 net/sched/sch_generic.c:340 __dev_xmit_skb net/core/dev.c:3784 [inline] __dev_queue_xmit+0x1912/0x3b10 net/core/dev.c:4325 neigh_output include/net/neighbour.h:542 [inline] ip_finish_output2+0xe66/0x1360 net/ipv4/ip_output.c:235 iptunnel_xmit+0x540/0x9b0 net/ipv4/ip_tunnel_core.c:82 ip_tunnel_xmit+0x20ee/0x2960 net/ipv4/ip_tunnel.c:831 erspan_xmit+0x9de/0x1460 net/ipv4/ip_gre.c:720 __netdev_start_xmit include/linux/netdevice.h:4989 [inline] netdev_start_xmit include/linux/netdevice.h:5003 [inline] xmit_one net/core/dev.c:3555 [inline] dev_hard_start_xmit+0x242/0x770 net/core/dev.c:3571 sch_direct_xmit+0x2b6/0x5f0 net/sched/sch_generic.c:342 __dev_xmit_skb net/core/dev.c:3784 [inline] __dev_queue_xmit+0x1912/0x3b10 net/core/dev.c:4325 neigh_output include/net/neighbour.h:542 [inline] ip_finish_output2+0xe66/0x1360 net/ipv4/ip_output.c:235 igmpv3_send_cr net/ipv4/igmp.c:723 [inline] igmp_ifc_timer_expire+0xb71/0xd90 net/ipv4/igmp.c:813 call_timer_fn+0x17e/0x600 kernel/time/timer.c:1700 expire_timers kernel/time/timer.c:1751 [inline] __run_timers+0x621/0x830 kernel/time/timer.c:2038 run_timer_softirq+0x67/0xf0 kernel/time/timer.c:2051 __do_softirq+0x2bc/0x943 kernel/softirq.c:554 invoke_softirq kernel/softirq.c:428 [inline] __irq_exit_rcu+0xf2/0x1c0 kernel/softirq.c:633 irq_exit_rcu+0x9/0x30 kernel/softirq.c:645 instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1076 [inline] sysvec_apic_timer_interrupt+0xa6/0xc0 arch/x86/kernel/apic/apic.c:1076 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:702 RIP: 0010:resched_offsets_ok kernel/sched/core.c:10127 [inline] RIP: 0010:__might_resched+0x16f/0x780 kernel/sched/core.c:10142 Code: 00 4c 89 e8 48 c1 e8 03 48 ba 00 00 00 00 00 fc ff df 48 89 44 24 38 0f b6 04 10 84 c0 0f 85 87 04 00 00 41 8b 45 00 c1 e0 08 <01> d8 44 39 e0 0f 85 d6 00 00 00 44 89 64 24 1c 48 8d bc 24 a0 00 RSP: 0018:ffffc9000ee069e0 EFLAGS: 00000246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff8880296a9e00 RDX: dffffc0000000000 RSI: ffff8880296a9e00 RDI: ffffffff8bfe8fa0 RBP: ffffc9000ee06b00 R08: ffffffff82326877 R09: 1ffff11002b5ad1b R10: dffffc0000000000 R11: ffffed1002b5ad1c R12: 0000000000000000 R13: ffff8880296aa23c R14: 000000000000062a R15: 1ffff92001dc0d44 down_write+0x19/0x50 kernel/locking/rwsem.c:1578 kernfs_activate fs/kernfs/dir.c:1403 [inline] kernfs_add_one+0x4af/0x8b0 fs/kernfs/dir.c:819 __kernfs_create_file+0x22e/0x2e0 fs/kernfs/file.c:1056 sysfs_add_file_mode_ns+0x24a/0x310 fs/sysfs/file.c:307 create_files fs/sysfs/group.c:64 [inline] internal_create_group+0x4f4/0xf20 fs/sysfs/group.c:152 internal_create_groups fs/sysfs/group.c:192 [inline] sysfs_create_groups+0x56/0x120 fs/sysfs/group.c:218 create_dir lib/kobject.c:78 [inline] kobject_add_internal+0x472/0x8d0 lib/kobject.c:240 kobject_add_varg lib/kobject.c:374 [inline] kobject_init_and_add+0x124/0x190 lib/kobject.c:457 netdev_queue_add_kobject net/core/net-sysfs.c:1706 [inline] netdev_queue_update_kobjects+0x1f3/0x480 net/core/net-sysfs.c:1758 register_queue_kobjects net/core/net-sysfs.c:1819 [inline] netdev_register_kobject+0x265/0x310 net/core/net-sysfs.c:2059 register_netdevice+0x1191/0x19c0 net/core/dev.c:10298 bond_newlink+0x3b/0x90 drivers/net/bonding/bond_netlink.c:576 rtnl_newlink_create net/core/rtnetlink.c:3506 [inline] __rtnl_newlink net/core/rtnetlink.c:3726 [inline] rtnl_newlink+0x158f/0x20a0 net/core/rtnetlink.c:3739 rtnetlink_rcv_msg+0x885/0x1040 net/core/rtnetlink.c:6606 netlink_rcv_skb+0x1e3/0x430 net/netlink/af_netlink.c:2543 netlink_unicast_kernel net/netlink/af_netlink.c:1341 [inline] netlink_unicast+0x7ea/0x980 net/netlink/af_netlink.c:1367 netlink_sendmsg+0xa3c/0xd70 net/netlink/af_netlink.c:1908 sock_sendmsg_nosec net/socket.c:730 [inline] __sock_sendmsg+0x221/0x270 net/socket.c:745 __sys_sendto+0x3a4/0x4f0 net/socket.c:2191 __do_sys_sendto net/socket.c:2203 [inline] __se_sys_sendto net/socket.c:2199 [inline] __x64_sys_sendto+0xde/0x100 net/socket.c:2199 do_syscall_64+0xfb/0x240 entry_SYSCALL_64_after_hwframe+0x6d/0x75 RIP: 0033:0x7fc3fa87fa9c Reported-by: syzbot Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20240212140700.2795436-4-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/dummy.c | 1 + drivers/net/geneve.c | 1 + drivers/net/loopback.c | 1 + drivers/net/veth.c | 1 + drivers/net/vxlan/vxlan_core.c | 1 + net/ipv4/ip_tunnel.c | 1 + net/ipv6/ip6_gre.c | 2 ++ net/ipv6/ip6_tunnel.c | 1 + net/ipv6/ip6_vti.c | 1 + net/ipv6/sit.c | 1 + 10 files changed, 11 insertions(+) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 768454aa36d6..946bba0701a4 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -71,6 +71,7 @@ static int dummy_dev_init(struct net_device *dev) if (!dev->lstats) return -ENOMEM; + netdev_lockdep_set_classes(dev); return 0; } diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 23e97c2e4f6f..256602a72356 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -335,6 +335,7 @@ static int geneve_init(struct net_device *dev) gro_cells_destroy(&geneve->gro_cells); return err; } + netdev_lockdep_set_classes(dev); return 0; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f6d53e63ef4e..f6eab66c2660 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -144,6 +144,7 @@ static int loopback_dev_init(struct net_device *dev) dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); if (!dev->lstats) return -ENOMEM; + netdev_lockdep_set_classes(dev); return 0; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 578e36ea1589..de1f13837782 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1499,6 +1499,7 @@ static void veth_free_queues(struct net_device *dev) static int veth_dev_init(struct net_device *dev) { + netdev_lockdep_set_classes(dev); return veth_alloc_queues(dev); } diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 11707647afb9..705a6fd6ab6c 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2855,6 +2855,7 @@ static int vxlan_init(struct net_device *dev) if (err) goto err_gro_cells_destroy; + netdev_lockdep_set_classes(dev); return 0; err_gro_cells_destroy: diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 00da0b80320f..58de780ab0e2 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1269,6 +1269,7 @@ int ip_tunnel_init(struct net_device *dev) if (tunnel->collect_md) netif_keep_dst(dev); + netdev_lockdep_set_classes(dev); return 0; } EXPORT_SYMBOL_GPL(ip_tunnel_init); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 428f03e9da45..5e97e0aa8e07 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1511,6 +1511,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev) ip6gre_tnl_init_features(dev); netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_lockdep_set_classes(dev); return 0; cleanup_dst_cache_init: @@ -1901,6 +1902,7 @@ static int ip6erspan_tap_init(struct net_device *dev) ip6erspan_tnl_link_config(tunnel, 1); netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_lockdep_set_classes(dev); return 0; cleanup_dst_cache_init: diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index bfb0a6c601c1..44406c28445d 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1898,6 +1898,7 @@ ip6_tnl_dev_init_gen(struct net_device *dev) dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len; netdev_hold(dev, &t->dev_tracker, GFP_KERNEL); + netdev_lockdep_set_classes(dev); return 0; destroy_dst: diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index cfe1b1ad4d85..7f4f976aa24a 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -935,6 +935,7 @@ static inline int vti6_dev_init_gen(struct net_device *dev) if (!dev->tstats) return -ENOMEM; netdev_hold(dev, &t->dev_tracker, GFP_KERNEL); + netdev_lockdep_set_classes(dev); return 0; } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 61b2b71fa8be..b2da1f1b5fec 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1460,6 +1460,7 @@ static int ipip6_tunnel_init(struct net_device *dev) return err; } netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_lockdep_set_classes(dev); return 0; } From fb5b86cfd4ef21ea18966718f6bf6c8f1b9df12e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 12 Feb 2024 15:32:18 -0800 Subject: [PATCH 1176/2255] bpf: simplify btf_get_prog_ctx_type() into btf_is_prog_ctx_type() Return result of btf_get_prog_ctx_type() is never used and callers only check NULL vs non-NULL case to determine if given type matches expected PTR_TO_CTX type. So rename function to `btf_is_prog_ctx_type()` and return a simple true/false. We'll use this simpler interface to handle kprobe program type's special typedef case in the next patch. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240212233221.2575350-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/btf.h | 17 ++++++++--------- kernel/bpf/btf.c | 27 +++++++++++++-------------- kernel/bpf/verifier.c | 2 +- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index cb96f6263638..f9e56fd12a9f 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -531,10 +531,9 @@ s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id); int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt, struct module *owner); struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf, u32 btf_id); -const struct btf_type * -btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, - const struct btf_type *t, enum bpf_prog_type prog_type, - int arg); +bool btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, + const struct btf_type *t, enum bpf_prog_type prog_type, + int arg); int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type); bool btf_types_are_same(const struct btf *btf1, u32 id1, const struct btf *btf2, u32 id2); @@ -574,12 +573,12 @@ static inline struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf { return NULL; } -static inline const struct btf_member * -btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, - const struct btf_type *t, enum bpf_prog_type prog_type, - int arg) +static inline bool +btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, + const struct btf_type *t, enum bpf_prog_type prog_type, + int arg) { - return NULL; + return false; } static inline int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type) { diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index efd9bc274be0..405f95722905 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -5694,10 +5694,9 @@ static int find_kern_ctx_type_id(enum bpf_prog_type prog_type) return ctx_type->type; } -const struct btf_type * -btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, - const struct btf_type *t, enum bpf_prog_type prog_type, - int arg) +bool btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, + const struct btf_type *t, enum bpf_prog_type prog_type, + int arg) { const struct btf_type *ctx_type; const char *tname, *ctx_tname; @@ -5711,26 +5710,26 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, * is not supported yet. * BPF_PROG_TYPE_RAW_TRACEPOINT is fine. */ - return NULL; + return false; } tname = btf_name_by_offset(btf, t->name_off); if (!tname) { bpf_log(log, "arg#%d struct doesn't have a name\n", arg); - return NULL; + return false; } ctx_type = find_canonical_prog_ctx_type(prog_type); if (!ctx_type) { bpf_log(log, "btf_vmlinux is malformed\n"); /* should not happen */ - return NULL; + return false; } again: ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_type->name_off); if (!ctx_tname) { /* should not happen */ bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n"); - return NULL; + return false; } /* only compare that prog's ctx type name is the same as * kernel expects. No need to compare field by field. @@ -5740,20 +5739,20 @@ again: * { // no fields of skb are ever used } */ if (strcmp(ctx_tname, "__sk_buff") == 0 && strcmp(tname, "sk_buff") == 0) - return ctx_type; + return true; if (strcmp(ctx_tname, "xdp_md") == 0 && strcmp(tname, "xdp_buff") == 0) - return ctx_type; + return true; if (strcmp(ctx_tname, tname)) { /* bpf_user_pt_regs_t is a typedef, so resolve it to * underlying struct and check name again */ if (!btf_type_is_modifier(ctx_type)) - return NULL; + return false; while (btf_type_is_modifier(ctx_type)) ctx_type = btf_type_by_id(btf_vmlinux, ctx_type->type); goto again; } - return ctx_type; + return true; } /* forward declarations for arch-specific underlying types of @@ -5905,7 +5904,7 @@ static int btf_translate_to_vmlinux(struct bpf_verifier_log *log, enum bpf_prog_type prog_type, int arg) { - if (!btf_get_prog_ctx_type(log, btf, t, prog_type, arg)) + if (!btf_is_prog_ctx_type(log, btf, t, prog_type, arg)) return -ENOENT; return find_kern_ctx_type_id(prog_type); } @@ -7211,7 +7210,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) if (!btf_type_is_ptr(t)) goto skip_pointer; - if ((tags & ARG_TAG_CTX) || btf_get_prog_ctx_type(log, btf, t, prog_type, i)) { + if ((tags & ARG_TAG_CTX) || btf_is_prog_ctx_type(log, btf, t, prog_type, i)) { if (tags & ~ARG_TAG_CTX) { bpf_log(log, "arg#%d has invalid combination of tags\n", i); return -EINVAL; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 72ca27f49616..aa192dc735a9 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -11015,7 +11015,7 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, * type to our caller. When a set of conditions hold in the BTF type of * arguments, we resolve it to a known kfunc_ptr_arg_type. */ - if (btf_get_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno)) + if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno)) return KF_ARG_PTR_TO_CTX; if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno])) From 824c58fb1090ae5e502284400682e30841280a87 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 12 Feb 2024 15:32:19 -0800 Subject: [PATCH 1177/2255] bpf: handle bpf_user_pt_regs_t typedef explicitly for PTR_TO_CTX global arg Expected canonical argument type for global function arguments representing PTR_TO_CTX is `bpf_user_pt_regs_t *ctx`. This currently works on s390x by accident because kernel resolves such typedef to underlying struct (which is anonymous on s390x), and erroneously accepting it as expected context type. We are fixing this problem next, which would break s390x arch, so we need to handle `bpf_user_pt_regs_t` case explicitly for KPROBE programs. Fixes: 91cc1a99740e ("bpf: Annotate context types") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240212233221.2575350-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 405f95722905..26dc0876e426 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -5702,6 +5702,21 @@ bool btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, const char *tname, *ctx_tname; t = btf_type_by_id(btf, t->type); + + /* KPROBE programs allow bpf_user_pt_regs_t typedef, which we need to + * check before we skip all the typedef below. + */ + if (prog_type == BPF_PROG_TYPE_KPROBE) { + while (btf_type_is_modifier(t) && !btf_type_is_typedef(t)) + t = btf_type_by_id(btf, t->type); + + if (btf_type_is_typedef(t)) { + tname = btf_name_by_offset(btf, t->name_off); + if (tname && strcmp(tname, "bpf_user_pt_regs_t") == 0) + return true; + } + } + while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); if (!btf_type_is_struct(t)) { From 879bbe7aa4afa80acf72a1cad7f52416ea78c52d Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 12 Feb 2024 15:32:20 -0800 Subject: [PATCH 1178/2255] bpf: don't infer PTR_TO_CTX for programs with unnamed context type For program types that don't have named context type name (e.g., BPF iterator programs or tracepoint programs), ctx_tname will be a non-NULL empty string. For such programs it shouldn't be possible to have PTR_TO_CTX argument for global subprogs based on type name alone. arg:ctx tag is the only way to have PTR_TO_CTX passed into global subprog for such program types. Fix this loophole, which currently would assume PTR_TO_CTX whenever user uses a pointer to anonymous struct as an argument to their global subprogs. This happens in practice with the following (quite common, in practice) approach: typedef struct { /* anonymous */ int x; } my_type_t; int my_subprog(my_type_t *arg) { ... } User's intent is to have PTR_TO_MEM argument for `arg`, but verifier will complain about expecting PTR_TO_CTX. This fix also closes unintended s390x-specific KPROBE handling of PTR_TO_CTX case. Selftest change is necessary to accommodate this. Fixes: 91cc1a99740e ("bpf: Annotate context types") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240212233221.2575350-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 3 +++ .../bpf/progs/test_global_func_ctx_args.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 26dc0876e426..6ff0bd1a91d5 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -5746,6 +5746,9 @@ again: bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n"); return false; } + /* program types without named context types work only with arg:ctx tag */ + if (ctx_tname[0] == '\0') + return false; /* only compare that prog's ctx type name is the same as * kernel expects. No need to compare field by field. * It's ok for bpf prog to do: diff --git a/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c b/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c index 9a06e5eb1fbe..143c8a4852bf 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c +++ b/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c @@ -26,6 +26,23 @@ int kprobe_typedef_ctx(void *ctx) return kprobe_typedef_ctx_subprog(ctx); } +/* s390x defines: + * + * typedef user_pt_regs bpf_user_pt_regs_t; + * typedef struct { ... } user_pt_regs; + * + * And so "canonical" underlying struct type is anonymous. + * So on s390x only valid ways to have PTR_TO_CTX argument in global subprogs + * are: + * - bpf_user_pt_regs_t *ctx (typedef); + * - struct bpf_user_pt_regs_t *ctx (backwards compatible struct hack); + * - void *ctx __arg_ctx (arg:ctx tag) + * + * Other architectures also allow using underlying struct types (e.g., + * `struct pt_regs *ctx` for x86-64) + */ +#ifndef bpf_target_s390 + #define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL))) __weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx) @@ -40,6 +57,8 @@ int kprobe_resolved_ctx(void *ctx) return kprobe_struct_ctx_subprog(ctx); } +#endif + /* this is current hack to make this work on old kernels */ struct bpf_user_pt_regs_t {}; From 63d5a33fb4ec2a4ed6907c8ac144b6f10f6dba47 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 12 Feb 2024 15:32:21 -0800 Subject: [PATCH 1179/2255] selftests/bpf: add anonymous user struct as global subprog arg test Add tests validating that kernel handles pointer to anonymous struct argument as PTR_TO_MEM case, not as PTR_TO_CTX case. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240212233221.2575350-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- .../bpf/progs/verifier_global_subprogs.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c index 67dddd941891..baff5ffe9405 100644 --- a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c +++ b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c @@ -115,6 +115,35 @@ int arg_tag_nullable_ptr_fail(void *ctx) return subprog_nullable_ptr_bad(&x); } +typedef struct { + int x; +} user_struct_t; + +__noinline __weak int subprog_user_anon_mem(user_struct_t *t) +{ + return t ? t->x : 0; +} + +SEC("?tracepoint") +__failure __log_level(2) +__msg("invalid bpf_context access") +__msg("Caller passes invalid args into func#1 ('subprog_user_anon_mem')") +int anon_user_mem_invalid(void *ctx) +{ + /* can't pass PTR_TO_CTX as user memory */ + return subprog_user_anon_mem(ctx); +} + +SEC("?tracepoint") +__success __log_level(2) +__msg("Func#1 ('subprog_user_anon_mem') is safe for any args that match its prototype") +int anon_user_mem_valid(void *ctx) +{ + user_struct_t t = { .x = 42 }; + + return subprog_user_anon_mem(&t); +} + __noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull) { return (*p1) * (*p2); /* good, no need for NULL checks */ From ff049886671ccd4e624a30ec464cb20e4c39a313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cs=C3=B3k=C3=A1s=20Bence?= Date: Mon, 12 Feb 2024 16:37:17 +0100 Subject: [PATCH 1180/2255] net: fec: Refactor: #define magic constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add defines for bits of ECR, RCR control registers, TX watermark etc. Signed-off-by: Csókás Bence Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240212153717.10023-1-csokas.bence@prolan.hu Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fec_main.c | 46 +++++++++++++++-------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 42bdc01a304e..c934ada246b2 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -240,8 +240,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define PKT_MINBUF_SIZE 64 /* FEC receive acceleration */ -#define FEC_RACC_IPDIS (1 << 1) -#define FEC_RACC_PRODIS (1 << 2) +#define FEC_RACC_IPDIS BIT(1) +#define FEC_RACC_PRODIS BIT(2) #define FEC_RACC_SHIFT16 BIT(7) #define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS) @@ -273,8 +273,23 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_MMFR_TA (2 << 16) #define FEC_MMFR_DATA(v) (v & 0xffff) /* FEC ECR bits definition */ -#define FEC_ECR_MAGICEN (1 << 2) -#define FEC_ECR_SLEEP (1 << 3) +#define FEC_ECR_RESET BIT(0) +#define FEC_ECR_ETHEREN BIT(1) +#define FEC_ECR_MAGICEN BIT(2) +#define FEC_ECR_SLEEP BIT(3) +#define FEC_ECR_EN1588 BIT(4) +#define FEC_ECR_BYTESWP BIT(8) +/* FEC RCR bits definition */ +#define FEC_RCR_LOOP BIT(0) +#define FEC_RCR_HALFDPX BIT(1) +#define FEC_RCR_MII BIT(2) +#define FEC_RCR_PROMISC BIT(3) +#define FEC_RCR_BC_REJ BIT(4) +#define FEC_RCR_FLOWCTL BIT(5) +#define FEC_RCR_RMII BIT(8) +#define FEC_RCR_10BASET BIT(9) +/* TX WMARK bits */ +#define FEC_TXWMRK_STRFWD BIT(8) #define FEC_MII_TIMEOUT 30000 /* us */ @@ -1062,7 +1077,7 @@ fec_restart(struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); u32 temp_mac[2]; u32 rcntl = OPT_FRAME_SIZE | 0x04; - u32 ecntl = 0x2; /* ETHEREN */ + u32 ecntl = FEC_ECR_ETHEREN; /* Whack a reset. We should wait for this. * For i.MX6SX SOC, enet use AXI bus, we use disable MAC @@ -1137,18 +1152,18 @@ fec_restart(struct net_device *ndev) fep->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) rcntl |= (1 << 6); else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) - rcntl |= (1 << 8); + rcntl |= FEC_RCR_RMII; else - rcntl &= ~(1 << 8); + rcntl &= ~FEC_RCR_RMII; /* 1G, 100M or 10M */ if (ndev->phydev) { if (ndev->phydev->speed == SPEED_1000) ecntl |= (1 << 5); else if (ndev->phydev->speed == SPEED_100) - rcntl &= ~(1 << 9); + rcntl &= ~FEC_RCR_10BASET; else - rcntl |= (1 << 9); + rcntl |= FEC_RCR_10BASET; } } else { #ifdef FEC_MIIGSK_ENR @@ -1207,13 +1222,13 @@ fec_restart(struct net_device *ndev) if (fep->quirks & FEC_QUIRK_ENET_MAC) { /* enable ENET endian swap */ - ecntl |= (1 << 8); + ecntl |= FEC_ECR_BYTESWP; /* enable ENET store and forward mode */ - writel(1 << 8, fep->hwp + FEC_X_WMRK); + writel(FEC_TXWMRK_STRFWD, fep->hwp + FEC_X_WMRK); } if (fep->bufdesc_ex) - ecntl |= (1 << 4); + ecntl |= FEC_ECR_EN1588; if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT && fep->rgmii_txc_dly) @@ -1312,7 +1327,7 @@ static void fec_stop(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); + u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & FEC_RCR_RMII; u32 val; /* We cannot expect a graceful transmit stop without link !!! */ @@ -1331,7 +1346,7 @@ fec_stop(struct net_device *ndev) if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) { writel(0, fep->hwp + FEC_ECNTRL); } else { - writel(1, fep->hwp + FEC_ECNTRL); + writel(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL); udelay(10); } } else { @@ -1345,12 +1360,11 @@ fec_stop(struct net_device *ndev) /* We have to keep ENET enabled to have MII interrupt stay working */ if (fep->quirks & FEC_QUIRK_ENET_MAC && !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { - writel(2, fep->hwp + FEC_ECNTRL); + writel(FEC_ECR_ETHEREN, fep->hwp + FEC_ECNTRL); writel(rmii_mode, fep->hwp + FEC_R_CNTRL); } } - static void fec_timeout(struct net_device *ndev, unsigned int txqueue) { From f7859a03fba93778594a90d9581f679b3a4ad561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cs=C3=B3k=C3=A1s=20Bence?= Date: Mon, 12 Feb 2024 16:37:19 +0100 Subject: [PATCH 1181/2255] net: fec: Refactor: Replace FEC_ENET_FCE with FEC_RCR_FLOWCTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FEC_ENET_FCE is the Flow Control Enable bit (bit 5) of the RCR. This is now defined as FEC_RCR_FLOWCTL. Signed-off-by: Csókás Bence Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240212153717.10023-2-csokas.bence@prolan.hu Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fec_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index c934ada246b2..207f1f66c117 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -85,8 +85,6 @@ static int fec_enet_xdp_tx_xmit(struct fec_enet_private *fep, static const u16 fec_enet_vlan_pri_to_queue[8] = {0, 0, 1, 1, 1, 2, 2, 2}; -/* Pause frame feild and FIFO threshold */ -#define FEC_ENET_FCE (1 << 5) #define FEC_ENET_RSEM_V 0x84 #define FEC_ENET_RSFL_V 16 #define FEC_ENET_RAEM_V 0x8 @@ -1196,7 +1194,7 @@ fec_restart(struct net_device *ndev) if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) || ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) && ndev->phydev && ndev->phydev->pause)) { - rcntl |= FEC_ENET_FCE; + rcntl |= FEC_RCR_FLOWCTL; /* set FIFO threshold parameter to reduce overrun */ writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM); @@ -1207,7 +1205,7 @@ fec_restart(struct net_device *ndev) /* OPD */ writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD); } else { - rcntl &= ~FEC_ENET_FCE; + rcntl &= ~FEC_RCR_FLOWCTL; } #endif /* !defined(CONFIG_M5272) */ From 4a78f0173be2673cbdadf91023085982888474a6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 12 Feb 2024 19:29:11 +0100 Subject: [PATCH 1182/2255] dt-bindings: net: qca,ar9331: convert to DT schema Convert the Qualcomm Atheros AR9331 built-in switch bindings to DT schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Conor Dooley Reviewed-by: Oleksij Rempel Link: https://lore.kernel.org/r/20240212182911.233819-1-krzysztof.kozlowski@linaro.org Signed-off-by: Jakub Kicinski --- .../devicetree/bindings/net/dsa/ar9331.txt | 147 ---------------- .../bindings/net/dsa/qca,ar9331.yaml | 161 ++++++++++++++++++ 2 files changed, 161 insertions(+), 147 deletions(-) delete mode 100644 Documentation/devicetree/bindings/net/dsa/ar9331.txt create mode 100644 Documentation/devicetree/bindings/net/dsa/qca,ar9331.yaml diff --git a/Documentation/devicetree/bindings/net/dsa/ar9331.txt b/Documentation/devicetree/bindings/net/dsa/ar9331.txt deleted file mode 100644 index f824fdae0da2..000000000000 --- a/Documentation/devicetree/bindings/net/dsa/ar9331.txt +++ /dev/null @@ -1,147 +0,0 @@ -Atheros AR9331 built-in switch -============================= - -It is a switch built-in to Atheros AR9331 WiSoC and addressable over internal -MDIO bus. All PHYs are built-in as well. - -Required properties: - - - compatible: should be: "qca,ar9331-switch" - - reg: Address on the MII bus for the switch. - - resets : Must contain an entry for each entry in reset-names. - - reset-names : Must include the following entries: "switch" - - interrupt-parent: Phandle to the parent interrupt controller - - interrupts: IRQ line for the switch - - interrupt-controller: Indicates the switch is itself an interrupt - controller. This is used for the PHY interrupts. - - #interrupt-cells: must be 1 - - mdio: Container of PHY and devices on the switches MDIO bus. - -See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional -required and optional properties. -Examples: - -eth0: ethernet@19000000 { - compatible = "qca,ar9330-eth"; - reg = <0x19000000 0x200>; - interrupts = <4>; - - resets = <&rst 9>, <&rst 22>; - reset-names = "mac", "mdio"; - clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>; - clock-names = "eth", "mdio"; - - phy-mode = "mii"; - phy-handle = <&phy_port4>; -}; - -eth1: ethernet@1a000000 { - compatible = "qca,ar9330-eth"; - reg = <0x1a000000 0x200>; - interrupts = <5>; - resets = <&rst 13>, <&rst 23>; - reset-names = "mac", "mdio"; - clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>; - clock-names = "eth", "mdio"; - - phy-mode = "gmii"; - - fixed-link { - speed = <1000>; - full-duplex; - }; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - - switch10: switch@10 { - #address-cells = <1>; - #size-cells = <0>; - - compatible = "qca,ar9331-switch"; - reg = <0x10>; - resets = <&rst 8>; - reset-names = "switch"; - - interrupt-parent = <&miscintc>; - interrupts = <12>; - - interrupt-controller; - #interrupt-cells = <1>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - switch_port0: port@0 { - reg = <0x0>; - ethernet = <ð1>; - - phy-mode = "gmii"; - - fixed-link { - speed = <1000>; - full-duplex; - }; - }; - - switch_port1: port@1 { - reg = <0x1>; - phy-handle = <&phy_port0>; - phy-mode = "internal"; - }; - - switch_port2: port@2 { - reg = <0x2>; - phy-handle = <&phy_port1>; - phy-mode = "internal"; - }; - - switch_port3: port@3 { - reg = <0x3>; - phy-handle = <&phy_port2>; - phy-mode = "internal"; - }; - - switch_port4: port@4 { - reg = <0x4>; - phy-handle = <&phy_port3>; - phy-mode = "internal"; - }; - }; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - - interrupt-parent = <&switch10>; - - phy_port0: phy@0 { - reg = <0x0>; - interrupts = <0>; - }; - - phy_port1: phy@1 { - reg = <0x1>; - interrupts = <0>; - }; - - phy_port2: phy@2 { - reg = <0x2>; - interrupts = <0>; - }; - - phy_port3: phy@3 { - reg = <0x3>; - interrupts = <0>; - }; - - phy_port4: phy@4 { - reg = <0x4>; - interrupts = <0>; - }; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/net/dsa/qca,ar9331.yaml b/Documentation/devicetree/bindings/net/dsa/qca,ar9331.yaml new file mode 100644 index 000000000000..fd9ddc59d38c --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/qca,ar9331.yaml @@ -0,0 +1,161 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/qca,ar9331.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Atheros AR9331 built-in switch + +maintainers: + - Oleksij Rempel + +description: + Qualcomm Atheros AR9331 is a switch built-in to Atheros AR9331 WiSoC and + addressable over internal MDIO bus. All PHYs are built-in as well. + +properties: + compatible: + const: qca,ar9331-switch + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': + const: 1 + + mdio: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + properties: + interrupt-parent: true + + patternProperties: + '(ethernet-)?phy@[0-4]+$': + type: object + unevaluatedProperties: false + + properties: + reg: true + interrupts: + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + items: + - const: switch + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - '#interrupt-cells' + - mdio + - ports + - resets + - reset-names + +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + +unevaluatedProperties: false + +examples: + - | + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch10: switch@10 { + compatible = "qca,ar9331-switch"; + reg = <0x10>; + + interrupt-parent = <&miscintc>; + interrupts = <12>; + interrupt-controller; + #interrupt-cells = <1>; + + resets = <&rst 8>; + reset-names = "switch"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0x0>; + ethernet = <ð1>; + + phy-mode = "gmii"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + port@1 { + reg = <0x1>; + phy-handle = <&phy_port0>; + phy-mode = "internal"; + }; + + port@2 { + reg = <0x2>; + phy-handle = <&phy_port1>; + phy-mode = "internal"; + }; + + port@3 { + reg = <0x3>; + phy-handle = <&phy_port2>; + phy-mode = "internal"; + }; + + port@4 { + reg = <0x4>; + phy-handle = <&phy_port3>; + phy-mode = "internal"; + }; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + interrupt-parent = <&switch10>; + + phy_port0: ethernet-phy@0 { + reg = <0x0>; + interrupts = <0>; + }; + + phy_port1: ethernet-phy@1 { + reg = <0x1>; + interrupts = <0>; + }; + + phy_port2: ethernet-phy@2 { + reg = <0x2>; + interrupts = <0>; + }; + + phy_port3: ethernet-phy@3 { + reg = <0x3>; + interrupts = <0>; + }; + + phy_port4: ethernet-phy@4 { + reg = <0x4>; + interrupts = <0>; + }; + }; + }; + }; From 7cc13adbd057f1905564ec2a254883d7fd407deb Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 12 Feb 2024 15:59:44 -0800 Subject: [PATCH 1183/2255] bpf: emit source code file name and line number in verifier log As BPF applications grow in size and complexity and are separated into multiple .bpf.c files that are statically linked together, it becomes harder and harder to match verifier's BPF assembly level output to original C code. While often annotated C source code is unique enough to be able to identify the file it belongs to, quite often this is actually problematic as parts of source code can be quite generic. Long story short, it is very useful to see source code file name and line number information along with the original C code. Verifier already knows this information, we just need to output it. This patch extends verifier log with file name and line number information, emitted next to original (presumably C) source code, annotating BPF assembly output, like so: ; @ .bpf.c: If file name has directory names in it, they are stripped away. This should be fine in practice as file names tend to be pretty unique with C code anyways, and keeping log size smaller is always good. In practice this might look something like below, where some code is coming from application files, while others are from libbpf's usdt.bpf.h header file: ; if (STROBEMETA_READ( @ strobemeta_probe.bpf.c:534 5592: (79) r1 = *(u64 *)(r10 -56) ; R1_w=mem_or_null(id=1589,sz=7680) R10=fp0 5593: (7b) *(u64 *)(r10 -56) = r1 ; R1_w=mem_or_null(id=1589,sz=7680) R10=fp0 5594: (79) r3 = *(u64 *)(r10 -8) ; R3_w=scalar() R10=fp0 fp-8=mmmmmmmm ... 170: (71) r1 = *(u8 *)(r8 +15) ; frame1: R1_w=scalar(...) R8_w=map_value(map=__bpf_usdt_spec,ks=4,vs=208) 171: (67) r1 <<= 56 ; frame1: R1_w=scalar(...) 172: (c7) r1 s>>= 56 ; frame1: R1_w=scalar(smin=smin32=-128,smax=smax32=127) ; val <<= arg_spec->arg_bitshift; @ usdt.bpf.h:183 173: (67) r1 <<= 32 ; frame1: R1_w=scalar(...) 174: (77) r1 >>= 32 ; frame1: R1_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff)) 175: (79) r2 = *(u64 *)(r10 -8) ; frame1: R2_w=scalar() R10=fp0 fp-8=mmmmmmmm 176: (6f) r2 <<= r1 ; frame1: R1_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff)) R2_w=scalar() 177: (7b) *(u64 *)(r10 -8) = r2 ; frame1: R2_w=scalar(id=61) R10=fp0 fp-8_w=scalar(id=61) ; if (arg_spec->arg_signed) @ usdt.bpf.h:184 178: (bf) r3 = r2 ; frame1: R2_w=scalar(id=61) R3_w=scalar(id=61) 179: (7f) r3 >>= r1 ; frame1: R1_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff)) R3_w=scalar() ; if (arg_spec->arg_signed) @ usdt.bpf.h:184 180: (71) r4 = *(u8 *)(r8 +14) 181: safe log_fixup tests needed a minor adjustment as verifier log output increased a bit and that test is quite sensitive to such changes. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240212235944.2816107-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 15 ++++++++++++--- .../testing/selftests/bpf/prog_tests/log_fixup.c | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 594a234f122b..cc789efc7f43 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -9,6 +9,7 @@ #include #include #include +#include #define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args) @@ -362,6 +363,8 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, const char *prefix_fmt, ...) { const struct bpf_line_info *linfo; + const struct btf *btf; + const char *s, *fname; if (!bpf_verifier_log_needed(&env->log)) return; @@ -378,9 +381,15 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, va_end(args); } - verbose(env, "%s\n", - ltrim(btf_name_by_offset(env->prog->aux->btf, - linfo->line_off))); + btf = env->prog->aux->btf; + s = ltrim(btf_name_by_offset(btf, linfo->line_off)); + verbose(env, "%s", s); /* source code line */ + + s = btf_name_by_offset(btf, linfo->file_name_off); + /* leave only file name */ + fname = strrchr(s, '/'); + fname = fname ? fname + 1 : s; + verbose(env, " @ %s:%u\n", fname, BPF_LINE_INFO_LINE_NUM(linfo->line_col)); env->prev_linfo = linfo; } diff --git a/tools/testing/selftests/bpf/prog_tests/log_fixup.c b/tools/testing/selftests/bpf/prog_tests/log_fixup.c index 7a3fa2ff567b..90a98e23be61 100644 --- a/tools/testing/selftests/bpf/prog_tests/log_fixup.c +++ b/tools/testing/selftests/bpf/prog_tests/log_fixup.c @@ -169,9 +169,9 @@ void test_log_fixup(void) if (test__start_subtest("bad_core_relo_trunc_none")) bad_core_relo(0, TRUNC_NONE /* full buf */); if (test__start_subtest("bad_core_relo_trunc_partial")) - bad_core_relo(280, TRUNC_PARTIAL /* truncate original log a bit */); + bad_core_relo(300, TRUNC_PARTIAL /* truncate original log a bit */); if (test__start_subtest("bad_core_relo_trunc_full")) - bad_core_relo(220, TRUNC_FULL /* truncate also libbpf's message patch */); + bad_core_relo(240, TRUNC_FULL /* truncate also libbpf's message patch */); if (test__start_subtest("bad_core_relo_subprog")) bad_core_relo_subprog(); if (test__start_subtest("missing_map")) From be51ed104ba9929c741afb718ef7198dbcecef94 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 12 Feb 2024 19:44:11 +0100 Subject: [PATCH 1184/2255] r8169: add LED support for RTL8125/RTL8126 This adds LED support for RTL8125/RTL8126. Note: Due to missing datasheets changing the 5Gbps link mode isn't supported for RTL8126. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/f982602c-9de3-4ca6-85a3-2c1d118dcb15@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 3 + drivers/net/ethernet/realtek/r8169_leds.c | 106 ++++++++++++++++++++++ drivers/net/ethernet/realtek/r8169_main.c | 61 ++++++++++++- 3 files changed, 166 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index c921456edeb9..4c043052198d 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -85,3 +85,6 @@ void r8169_get_led_name(struct rtl8169_private *tp, int idx, int rtl8168_get_led_mode(struct rtl8169_private *tp); int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); void rtl8168_init_leds(struct net_device *ndev); +int rtl8125_get_led_mode(struct rtl8169_private *tp, int index); +int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode); +void rtl8125_init_leds(struct net_device *ndev); diff --git a/drivers/net/ethernet/realtek/r8169_leds.c b/drivers/net/ethernet/realtek/r8169_leds.c index 78078eca3c43..7c5dc9d0df85 100644 --- a/drivers/net/ethernet/realtek/r8169_leds.c +++ b/drivers/net/ethernet/realtek/r8169_leds.c @@ -18,7 +18,14 @@ #define RTL8168_LED_CTRL_LINK_100 BIT(1) #define RTL8168_LED_CTRL_LINK_10 BIT(0) +#define RTL8125_LED_CTRL_ACT BIT(9) +#define RTL8125_LED_CTRL_LINK_2500 BIT(5) +#define RTL8125_LED_CTRL_LINK_1000 BIT(3) +#define RTL8125_LED_CTRL_LINK_100 BIT(1) +#define RTL8125_LED_CTRL_LINK_10 BIT(0) + #define RTL8168_NUM_LEDS 3 +#define RTL8125_NUM_LEDS 4 struct r8169_led_classdev { struct led_classdev led; @@ -156,3 +163,102 @@ void rtl8168_init_leds(struct net_device *ndev) for (i = 0; i < RTL8168_NUM_LEDS; i++) rtl8168_setup_ldev(leds + i, ndev, i); } + +static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev, + unsigned long flags) +{ + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); + struct rtl8169_private *tp = netdev_priv(ldev->ndev); + + if (!r8169_trigger_mode_is_valid(flags)) { + /* Switch LED off to indicate that mode isn't supported */ + rtl8125_set_led_mode(tp, ldev->index, 0); + return -EOPNOTSUPP; + } + + return 0; +} + +static int rtl8125_led_hw_control_set(struct led_classdev *led_cdev, + unsigned long flags) +{ + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); + struct rtl8169_private *tp = netdev_priv(ldev->ndev); + u16 mode = 0; + + if (flags & BIT(TRIGGER_NETDEV_LINK_10)) + mode |= RTL8125_LED_CTRL_LINK_10; + if (flags & BIT(TRIGGER_NETDEV_LINK_100)) + mode |= RTL8125_LED_CTRL_LINK_100; + if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) + mode |= RTL8125_LED_CTRL_LINK_1000; + if (flags & BIT(TRIGGER_NETDEV_LINK_2500)) + mode |= RTL8125_LED_CTRL_LINK_2500; + if (flags & (BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX))) + mode |= RTL8125_LED_CTRL_ACT; + + return rtl8125_set_led_mode(tp, ldev->index, mode); +} + +static int rtl8125_led_hw_control_get(struct led_classdev *led_cdev, + unsigned long *flags) +{ + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); + struct rtl8169_private *tp = netdev_priv(ldev->ndev); + int mode; + + mode = rtl8125_get_led_mode(tp, ldev->index); + if (mode < 0) + return mode; + + if (mode & RTL8125_LED_CTRL_LINK_10) + *flags |= BIT(TRIGGER_NETDEV_LINK_10); + if (mode & RTL8125_LED_CTRL_LINK_100) + *flags |= BIT(TRIGGER_NETDEV_LINK_100); + if (mode & RTL8125_LED_CTRL_LINK_1000) + *flags |= BIT(TRIGGER_NETDEV_LINK_1000); + if (mode & RTL8125_LED_CTRL_LINK_2500) + *flags |= BIT(TRIGGER_NETDEV_LINK_2500); + if (mode & RTL8125_LED_CTRL_ACT) + *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); + + return 0; +} + +static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev, + struct net_device *ndev, int index) +{ + struct rtl8169_private *tp = netdev_priv(ndev); + struct led_classdev *led_cdev = &ldev->led; + char led_name[LED_MAX_NAME_SIZE]; + + ldev->ndev = ndev; + ldev->index = index; + + r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); + led_cdev->name = led_name; + led_cdev->hw_control_trigger = "netdev"; + led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; + led_cdev->hw_control_is_supported = rtl8125_led_hw_control_is_supported; + led_cdev->hw_control_set = rtl8125_led_hw_control_set; + led_cdev->hw_control_get = rtl8125_led_hw_control_get; + led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; + + /* ignore errors */ + devm_led_classdev_register(&ndev->dev, led_cdev); +} + +void rtl8125_init_leds(struct net_device *ndev) +{ + /* bind resource mgmt to netdev */ + struct device *dev = &ndev->dev; + struct r8169_led_classdev *leds; + int i; + + leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL); + if (!leds) + return; + + for (i = 0; i < RTL8125_NUM_LEDS; i++) + rtl8125_setup_led_ldev(leds + i, ndev, i); +} diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index ddfa6f62472a..79ec5bb974f2 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -330,17 +330,23 @@ enum rtl8168_registers { }; enum rtl8125_registers { + LEDSEL0 = 0x18, INT_CFG0_8125 = 0x34, #define INT_CFG0_ENABLE_8125 BIT(0) #define INT_CFG0_CLKREQEN BIT(3) IntrMask_8125 = 0x38, IntrStatus_8125 = 0x3c, INT_CFG1_8125 = 0x7a, + LEDSEL2 = 0x84, + LEDSEL1 = 0x86, TxPoll_8125 = 0x90, + LEDSEL3 = 0x96, MAC0_BKP = 0x19e0, EEE_TXIDLE_TIMER_8125 = 0x6048, }; +#define LEDSEL_MASK_8125 0x23f + #define RX_VLAN_INNER_8125 BIT(22) #define RX_VLAN_OUTER_8125 BIT(23) #define RX_VLAN_8125 (RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125) @@ -830,6 +836,51 @@ int rtl8168_get_led_mode(struct rtl8169_private *tp) return ret; } +static int rtl8125_get_led_reg(int index) +{ + static const int led_regs[] = { LEDSEL0, LEDSEL1, LEDSEL2, LEDSEL3 }; + + return led_regs[index]; +} + +int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode) +{ + int reg = rtl8125_get_led_reg(index); + struct device *dev = tp_to_dev(tp); + int ret; + u16 val; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + mutex_lock(&tp->led_lock); + val = RTL_R16(tp, reg) & ~LEDSEL_MASK_8125; + RTL_W16(tp, reg, val | mode); + mutex_unlock(&tp->led_lock); + + pm_runtime_put_sync(dev); + + return 0; +} + +int rtl8125_get_led_mode(struct rtl8169_private *tp, int index) +{ + int reg = rtl8125_get_led_reg(index); + struct device *dev = tp_to_dev(tp); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + ret = RTL_R16(tp, reg); + + pm_runtime_put_sync(dev); + + return ret; +} + void r8169_get_led_name(struct rtl8169_private *tp, int idx, char *buf, int buf_len) { @@ -5385,10 +5436,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if (IS_ENABLED(CONFIG_R8169_LEDS) && - tp->mac_version > RTL_GIGA_MAC_VER_06 && - tp->mac_version < RTL_GIGA_MAC_VER_61) - rtl8168_init_leds(dev); + if (IS_ENABLED(CONFIG_R8169_LEDS)) { + if (rtl_is_8125(tp)) + rtl8125_init_leds(dev); + else if (tp->mac_version > RTL_GIGA_MAC_VER_06) + rtl8168_init_leds(dev); + } netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); From 2ce30993831041b9dcd31eb12896be6611e8b7e2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 12 Feb 2024 19:57:46 +0100 Subject: [PATCH 1185/2255] r8169: add generic rtl_set_eee_txidle_timer function Add a generic setter for the EEE tx idle timer and use it with all RTL8125/RTL8126 chip versions, in line with the vendor driver. This prepares for adding EEE tx idle timer support for additional chip versions. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/39beed72-0dc4-4c45-8899-b72c43ab62a7@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 34 +++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 79ec5bb974f2..f6ed74073ed7 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -619,6 +619,7 @@ struct rtl8169_private { struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */ u16 cp_cmd; + u16 tx_lpi_timer; u32 irq_mask; int irq; struct clk *clk; @@ -2031,6 +2032,22 @@ static int rtl_set_coalesce(struct net_device *dev, return 0; } +static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) +{ + unsigned int timer_val = READ_ONCE(tp->dev->mtu) + ETH_HLEN + 0x20; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_65: + tp->tx_lpi_timer = timer_val; + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); + break; + default: + break; + } +} + static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); @@ -2289,14 +2306,8 @@ static void rtl8125a_config_eee_mac(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xeb62, 0, BIT(2) | BIT(1)); } -static void rtl8125_set_eee_txidle_timer(struct rtl8169_private *tp) -{ - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, tp->dev->mtu + ETH_HLEN + 0x20); -} - static void rtl8125b_config_eee_mac(struct rtl8169_private *tp) { - rtl8125_set_eee_txidle_timer(tp); r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0)); } @@ -3829,6 +3840,8 @@ static void rtl_hw_start(struct rtl8169_private *tp) rtl_hw_aspm_clkreq_enable(tp, false); RTL_W16(tp, CPlusCmd, tp->cp_cmd); + rtl_set_eee_txidle_timer(tp); + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) rtl_hw_start_8169(tp); else if (rtl_is_8125(tp)) @@ -3862,14 +3875,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; netdev_update_features(dev); rtl_jumbo_config(tp); - - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: - rtl8125_set_eee_txidle_timer(tp); - break; - default: - break; - } + rtl_set_eee_txidle_timer(tp); return 0; } From 57d2d2c8f132c830565058a5cdd8138350e068ec Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 12 Feb 2024 19:58:47 +0100 Subject: [PATCH 1186/2255] r8169: support setting the EEE tx idle timer on RTL8168h Support setting the EEE tx idle timer also on RTL8168h. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/cfb69ec9-24c4-4aad-9909-fdae3088add4@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index f6ed74073ed7..5244f24a7cb8 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2037,6 +2037,11 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) unsigned int timer_val = READ_ONCE(tp->dev->mtu) + ETH_HLEN + 0x20; switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46: + case RTL_GIGA_MAC_VER_48: + tp->tx_lpi_timer = timer_val; + r8168_mac_ocp_write(tp, 0xe048, timer_val); + break; case RTL_GIGA_MAC_VER_61: case RTL_GIGA_MAC_VER_63: case RTL_GIGA_MAC_VER_65: From 9c50139727265c088f936e496777bf588850e9f1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 12 Feb 2024 19:59:26 +0100 Subject: [PATCH 1187/2255] r8169: add support for returning tx_lpi_timer in ethtool get_eee Add support for returning the tx_lpi_timer value to userspace. This is supported by few chip versions only: RTL8168h/RTL8125/RTL8126 Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/4eee9c34-c5d6-4c96-9b05-455896dea59a@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 5244f24a7cb8..7d3f6d59be8c 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2053,14 +2053,34 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) } } +static unsigned int r8169_get_tx_lpi_timer_us(struct rtl8169_private *tp) +{ + unsigned int speed = tp->phydev->speed; + unsigned int timer = tp->tx_lpi_timer; + + if (!timer || speed == SPEED_UNKNOWN) + return 0; + + /* tx_lpi_timer value is in bytes */ + return DIV_ROUND_CLOSEST(timer * BITS_PER_BYTE, speed); +} + static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); + int ret; if (!rtl_supports_eee(tp)) return -EOPNOTSUPP; - return phy_ethtool_get_eee(tp->phydev, data); + ret = phy_ethtool_get_eee(tp->phydev, data); + if (ret) + return ret; + + data->tx_lpi_timer = r8169_get_tx_lpi_timer_us(tp); + data->tx_lpi_enabled = data->tx_lpi_timer ? data->eee_enabled : false; + + return 0; } static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data) From 32e4a5447ed9fa904a2dfcf4609c64bce053b4e8 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Mon, 12 Feb 2024 18:34:33 -0300 Subject: [PATCH 1188/2255] net: dsa: realtek: fix digital interface select macro for EXT0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While no supported devices currently utilize EXT0, the register reserves the bits for an EXT0. EXT0 is utilized by devices from the generation prior to rtl8365mb, such as those supported by the driver library rtl8367b. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Alvin Šipraga Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240212-realtek-fix_ext0-v1-1-f3d2536d191a@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/realtek/rtl8365mb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index be56373e9473..12665a8a3412 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -209,10 +209,10 @@ #define RTL8365MB_EXT_PORT_MODE_100FX 13 /* External interface mode configuration registers 0~1 */ -#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 /* EXT1 */ +#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 /* EXT0,EXT1 */ #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 0x13C3 /* EXT2 */ #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(_extint) \ - ((_extint) == 1 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 : \ + ((_extint) <= 1 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 : \ (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ 0x0) #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ From 2b0cfa6e49566c8fa6759734cf821aa6e8271a9e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 12 Feb 2024 10:50:54 +0100 Subject: [PATCH 1189/2255] net: add generic percpu page_pool allocator Introduce generic percpu page_pools allocator. Moreover add page_pool_create_percpu() and cpuid filed in page_pool struct in order to recycle the page in the page_pool "hot" cache if napi_pp_put_page() is running on the same cpu. This is a preliminary patch to add xdp multi-buff support for xdp running in generic mode. Acked-by: Jesper Dangaard Brouer Reviewed-by: Toke Hoiland-Jorgensen Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/80bc4285228b6f4220cd03de1999d86e46e3fcbd.1707729884.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- include/net/page_pool/types.h | 3 +++ net/core/dev.c | 45 +++++++++++++++++++++++++++++++++++ net/core/page_pool.c | 23 ++++++++++++++---- net/core/skbuff.c | 5 ++-- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index 76481c465375..3828396ae60c 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -128,6 +128,7 @@ struct page_pool_stats { struct page_pool { struct page_pool_params_fast p; + int cpuid; bool has_init_callback; long frag_users; @@ -203,6 +204,8 @@ struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp); struct page *page_pool_alloc_frag(struct page_pool *pool, unsigned int *offset, unsigned int size, gfp_t gfp); struct page_pool *page_pool_create(const struct page_pool_params *params); +struct page_pool *page_pool_create_percpu(const struct page_pool_params *params, + int cpuid); struct xdp_mem_info; diff --git a/net/core/dev.c b/net/core/dev.c index 7cf15d2bf78d..e19bdf1421e0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -153,6 +153,8 @@ #include #include #include +#include +#include #include "dev.h" #include "net-sysfs.h" @@ -450,6 +452,12 @@ static RAW_NOTIFIER_HEAD(netdev_chain); DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data); EXPORT_PER_CPU_SYMBOL(softnet_data); +/* Page_pool has a lockless array/stack to alloc/recycle pages. + * PP consumers must pay attention to run APIs in the appropriate context + * (e.g. NAPI context). + */ +static DEFINE_PER_CPU_ALIGNED(struct page_pool *, system_page_pool); + #ifdef CONFIG_LOCKDEP /* * register_netdevice() inits txq->_xmit_lock and sets lockdep class @@ -11724,6 +11732,27 @@ static void __init net_dev_struct_check(void) * */ +/* We allocate 256 pages for each CPU if PAGE_SHIFT is 12 */ +#define SYSTEM_PERCPU_PAGE_POOL_SIZE ((1 << 20) / PAGE_SIZE) + +static int net_page_pool_create(int cpuid) +{ +#if IS_ENABLED(CONFIG_PAGE_POOL) + struct page_pool_params page_pool_params = { + .pool_size = SYSTEM_PERCPU_PAGE_POOL_SIZE, + .nid = NUMA_NO_NODE, + }; + struct page_pool *pp_ptr; + + pp_ptr = page_pool_create_percpu(&page_pool_params, cpuid); + if (IS_ERR(pp_ptr)) + return -ENOMEM; + + per_cpu(system_page_pool, cpuid) = pp_ptr; +#endif + return 0; +} + /* * This is called single threaded during boot, so no need * to take the rtnl semaphore. @@ -11776,6 +11805,9 @@ static int __init net_dev_init(void) init_gro_hash(&sd->backlog); sd->backlog.poll = process_backlog; sd->backlog.weight = weight_p; + + if (net_page_pool_create(i)) + goto out; } dev_boot_phase = 0; @@ -11803,6 +11835,19 @@ static int __init net_dev_init(void) WARN_ON(rc < 0); rc = 0; out: + if (rc < 0) { + for_each_possible_cpu(i) { + struct page_pool *pp_ptr; + + pp_ptr = per_cpu(system_page_pool, i); + if (!pp_ptr) + continue; + + page_pool_destroy(pp_ptr); + per_cpu(system_page_pool, i) = NULL; + } + } + return rc; } diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 4933762e5a6b..89c835fcf094 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -171,13 +171,16 @@ static void page_pool_producer_unlock(struct page_pool *pool, } static int page_pool_init(struct page_pool *pool, - const struct page_pool_params *params) + const struct page_pool_params *params, + int cpuid) { unsigned int ring_qsize = 1024; /* Default */ memcpy(&pool->p, ¶ms->fast, sizeof(pool->p)); memcpy(&pool->slow, ¶ms->slow, sizeof(pool->slow)); + pool->cpuid = cpuid; + /* Validate only known flags were used */ if (pool->p.flags & ~(PP_FLAG_ALL)) return -EINVAL; @@ -253,10 +256,12 @@ static void page_pool_uninit(struct page_pool *pool) } /** - * page_pool_create() - create a page pool. + * page_pool_create_percpu() - create a page pool for a given cpu. * @params: parameters, see struct page_pool_params + * @cpuid: cpu identifier */ -struct page_pool *page_pool_create(const struct page_pool_params *params) +struct page_pool * +page_pool_create_percpu(const struct page_pool_params *params, int cpuid) { struct page_pool *pool; int err; @@ -265,7 +270,7 @@ struct page_pool *page_pool_create(const struct page_pool_params *params) if (!pool) return ERR_PTR(-ENOMEM); - err = page_pool_init(pool, params); + err = page_pool_init(pool, params, cpuid); if (err < 0) goto err_free; @@ -282,6 +287,16 @@ err_free: kfree(pool); return ERR_PTR(err); } +EXPORT_SYMBOL(page_pool_create_percpu); + +/** + * page_pool_create() - create a page pool + * @params: parameters, see struct page_pool_params + */ +struct page_pool *page_pool_create(const struct page_pool_params *params) +{ + return page_pool_create_percpu(params, -1); +} EXPORT_SYMBOL(page_pool_create); static void page_pool_return_page(struct page_pool *pool, struct page *page); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index edbbef563d4d..9e5eb47b4025 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -923,9 +923,10 @@ bool napi_pp_put_page(struct page *page, bool napi_safe) */ if (napi_safe || in_softirq()) { const struct napi_struct *napi = READ_ONCE(pp->p.napi); + unsigned int cpuid = smp_processor_id(); - allow_direct = napi && - READ_ONCE(napi->list_owner) == smp_processor_id(); + allow_direct = napi && READ_ONCE(napi->list_owner) == cpuid; + allow_direct |= (pp->cpuid == cpuid); } /* Driver set this to memory recycling info. Reset it on recycle. From 4d2bb0bfe8741a8778e0053f31a4e0f0cba80e8b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 12 Feb 2024 10:50:55 +0100 Subject: [PATCH 1190/2255] xdp: rely on skb pointer reference in do_xdp_generic and netif_receive_generic_xdp Rely on skb pointer reference instead of the skb pointer in do_xdp_generic and netif_receive_generic_xdp routine signatures. This is a preliminary patch to add multi-buff support for xdp running in generic mode where we will need to reallocate the skb to avoid linearization and we will need to make it visible to do_xdp_generic() caller. Acked-by: Jesper Dangaard Brouer Reviewed-by: Toke Hoiland-Jorgensen Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/c09415b1f48c8620ef4d76deed35050a7bddf7c2.1707729884.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/tun.c | 4 ++-- include/linux/netdevice.h | 2 +- net/core/dev.c | 16 +++++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b472f2c972d8..bc80fc1d576e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1926,7 +1926,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog) { - ret = do_xdp_generic(xdp_prog, skb); + ret = do_xdp_generic(xdp_prog, &skb); if (ret != XDP_PASS) { rcu_read_unlock(); local_bh_enable(); @@ -2516,7 +2516,7 @@ build: skb_record_rx_queue(skb, tfile->queue_index); if (skb_xdp) { - ret = do_xdp_generic(xdp_prog, skb); + ret = do_xdp_generic(xdp_prog, &skb); if (ret != XDP_PASS) { ret = 0; goto out; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 07cefa32eafa..a3f9c95da51e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3958,7 +3958,7 @@ static inline void dev_consume_skb_any(struct sk_buff *skb) u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp, struct bpf_prog *xdp_prog); void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog); -int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff *skb); +int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff **pskb); int netif_rx(struct sk_buff *skb); int __netif_rx(struct sk_buff *skb); diff --git a/net/core/dev.c b/net/core/dev.c index e19bdf1421e0..ffeb0e0279fe 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4936,10 +4936,11 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp, return act; } -static u32 netif_receive_generic_xdp(struct sk_buff *skb, +static u32 netif_receive_generic_xdp(struct sk_buff **pskb, struct xdp_buff *xdp, struct bpf_prog *xdp_prog) { + struct sk_buff *skb = *pskb; u32 act = XDP_DROP; /* Reinjected packets coming from act_mirred or similar should @@ -5020,24 +5021,24 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog) static DEFINE_STATIC_KEY_FALSE(generic_xdp_needed_key); -int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff *skb) +int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff **pskb) { if (xdp_prog) { struct xdp_buff xdp; u32 act; int err; - act = netif_receive_generic_xdp(skb, &xdp, xdp_prog); + act = netif_receive_generic_xdp(pskb, &xdp, xdp_prog); if (act != XDP_PASS) { switch (act) { case XDP_REDIRECT: - err = xdp_do_generic_redirect(skb->dev, skb, + err = xdp_do_generic_redirect((*pskb)->dev, *pskb, &xdp, xdp_prog); if (err) goto out_redir; break; case XDP_TX: - generic_xdp_tx(skb, xdp_prog); + generic_xdp_tx(*pskb, xdp_prog); break; } return XDP_DROP; @@ -5045,7 +5046,7 @@ int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff *skb) } return XDP_PASS; out_redir: - kfree_skb_reason(skb, SKB_DROP_REASON_XDP); + kfree_skb_reason(*pskb, SKB_DROP_REASON_XDP); return XDP_DROP; } EXPORT_SYMBOL_GPL(do_xdp_generic); @@ -5368,7 +5369,8 @@ another_round: int ret2; migrate_disable(); - ret2 = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog), skb); + ret2 = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog), + &skb); migrate_enable(); if (ret2 != XDP_PASS) { From e6d5dbdd20aa6a86974af51deb9414cd2e7794cb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 12 Feb 2024 10:50:56 +0100 Subject: [PATCH 1191/2255] xdp: add multi-buff support for xdp running in generic mode Similar to native xdp, do not always linearize the skb in netif_receive_generic_xdp routine but create a non-linear xdp_buff to be processed by the eBPF program. This allow to add multi-buffer support for xdp running in generic mode. Acked-by: Jesper Dangaard Brouer Reviewed-by: Toke Hoiland-Jorgensen Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/1044d6412b1c3e95b40d34993fd5f37cd2f319fd.1707729884.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 2 + net/core/dev.c | 70 +++++++++++++++++++++++--------- net/core/skbuff.c | 91 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 19 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2dde34c29203..def3d8689c3d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3446,6 +3446,8 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f) __skb_frag_ref(&skb_shinfo(skb)->frags[f]); } +int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb, + struct bpf_prog *prog); bool napi_pp_put_page(struct page *page, bool napi_safe); static inline void diff --git a/net/core/dev.c b/net/core/dev.c index ffeb0e0279fe..2d02ca8a3da5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4874,6 +4874,12 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp, xdp_init_buff(xdp, frame_sz, &rxqueue->xdp_rxq); xdp_prepare_buff(xdp, hard_start, skb_headroom(skb) - mac_len, skb_headlen(skb) + mac_len, true); + if (skb_is_nonlinear(skb)) { + skb_shinfo(skb)->xdp_frags_size = skb->data_len; + xdp_buff_set_frags_flag(xdp); + } else { + xdp_buff_clear_frags_flag(xdp); + } orig_data_end = xdp->data_end; orig_data = xdp->data; @@ -4903,6 +4909,14 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp, skb->len += off; /* positive on grow, negative on shrink */ } + /* XDP frag metadata (e.g. nr_frags) are updated in eBPF helpers + * (e.g. bpf_xdp_adjust_tail), we need to update data_len here. + */ + if (xdp_buff_has_frags(xdp)) + skb->data_len = skb_shinfo(skb)->xdp_frags_size; + else + skb->data_len = 0; + /* check if XDP changed eth hdr such SKB needs update */ eth = (struct ethhdr *)xdp->data; if ((orig_eth_type != eth->h_proto) || @@ -4936,12 +4950,35 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp, return act; } +static int +netif_skb_check_for_xdp(struct sk_buff **pskb, struct bpf_prog *prog) +{ + struct sk_buff *skb = *pskb; + int err, hroom, troom; + + if (!skb_cow_data_for_xdp(this_cpu_read(system_page_pool), pskb, prog)) + return 0; + + /* In case we have to go down the path and also linearize, + * then lets do the pskb_expand_head() work just once here. + */ + hroom = XDP_PACKET_HEADROOM - skb_headroom(skb); + troom = skb->tail + skb->data_len - skb->end; + err = pskb_expand_head(skb, + hroom > 0 ? ALIGN(hroom, NET_SKB_PAD) : 0, + troom > 0 ? troom + 128 : 0, GFP_ATOMIC); + if (err) + return err; + + return skb_linearize(skb); +} + static u32 netif_receive_generic_xdp(struct sk_buff **pskb, struct xdp_buff *xdp, struct bpf_prog *xdp_prog) { struct sk_buff *skb = *pskb; - u32 act = XDP_DROP; + u32 mac_len, act = XDP_DROP; /* Reinjected packets coming from act_mirred or similar should * not get XDP generic processing. @@ -4949,41 +4986,36 @@ static u32 netif_receive_generic_xdp(struct sk_buff **pskb, if (skb_is_redirected(skb)) return XDP_PASS; - /* XDP packets must be linear and must have sufficient headroom - * of XDP_PACKET_HEADROOM bytes. This is the guarantee that also - * native XDP provides, thus we need to do it here as well. + /* XDP packets must have sufficient headroom of XDP_PACKET_HEADROOM + * bytes. This is the guarantee that also native XDP provides, + * thus we need to do it here as well. */ + mac_len = skb->data - skb_mac_header(skb); + __skb_push(skb, mac_len); + if (skb_cloned(skb) || skb_is_nonlinear(skb) || skb_headroom(skb) < XDP_PACKET_HEADROOM) { - int hroom = XDP_PACKET_HEADROOM - skb_headroom(skb); - int troom = skb->tail + skb->data_len - skb->end; - - /* In case we have to go down the path and also linearize, - * then lets do the pskb_expand_head() work just once here. - */ - if (pskb_expand_head(skb, - hroom > 0 ? ALIGN(hroom, NET_SKB_PAD) : 0, - troom > 0 ? troom + 128 : 0, GFP_ATOMIC)) - goto do_drop; - if (skb_linearize(skb)) + if (netif_skb_check_for_xdp(pskb, xdp_prog)) goto do_drop; } - act = bpf_prog_run_generic_xdp(skb, xdp, xdp_prog); + __skb_pull(*pskb, mac_len); + + act = bpf_prog_run_generic_xdp(*pskb, xdp, xdp_prog); switch (act) { case XDP_REDIRECT: case XDP_TX: case XDP_PASS: break; default: - bpf_warn_invalid_xdp_action(skb->dev, xdp_prog, act); + bpf_warn_invalid_xdp_action((*pskb)->dev, xdp_prog, act); fallthrough; case XDP_ABORTED: - trace_xdp_exception(skb->dev, xdp_prog, act); + trace_xdp_exception((*pskb)->dev, xdp_prog, act); fallthrough; case XDP_DROP: do_drop: - kfree_skb(skb); + kfree_skb(*pskb); break; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9e5eb47b4025..bdb94749f05d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -895,6 +895,97 @@ static bool is_pp_page(struct page *page) return (page->pp_magic & ~0x3UL) == PP_SIGNATURE; } +static int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, + unsigned int headroom) +{ +#if IS_ENABLED(CONFIG_PAGE_POOL) + u32 size, truesize, len, max_head_size, off; + struct sk_buff *skb = *pskb, *nskb; + int err, i, head_off; + void *data; + + /* XDP does not support fraglist so we need to linearize + * the skb. + */ + if (skb_has_frag_list(skb)) + return -EOPNOTSUPP; + + max_head_size = SKB_WITH_OVERHEAD(PAGE_SIZE - headroom); + if (skb->len > max_head_size + MAX_SKB_FRAGS * PAGE_SIZE) + return -ENOMEM; + + size = min_t(u32, skb->len, max_head_size); + truesize = SKB_HEAD_ALIGN(size) + headroom; + data = page_pool_dev_alloc_va(pool, &truesize); + if (!data) + return -ENOMEM; + + nskb = napi_build_skb(data, truesize); + if (!nskb) { + page_pool_free_va(pool, data, true); + return -ENOMEM; + } + + skb_reserve(nskb, headroom); + skb_copy_header(nskb, skb); + skb_mark_for_recycle(nskb); + + err = skb_copy_bits(skb, 0, nskb->data, size); + if (err) { + consume_skb(nskb); + return err; + } + skb_put(nskb, size); + + head_off = skb_headroom(nskb) - skb_headroom(skb); + skb_headers_offset_update(nskb, head_off); + + off = size; + len = skb->len - off; + for (i = 0; i < MAX_SKB_FRAGS && off < skb->len; i++) { + struct page *page; + u32 page_off; + + size = min_t(u32, len, PAGE_SIZE); + truesize = size; + + page = page_pool_dev_alloc(pool, &page_off, &truesize); + if (!data) { + consume_skb(nskb); + return -ENOMEM; + } + + skb_add_rx_frag(nskb, i, page, page_off, size, truesize); + err = skb_copy_bits(skb, off, page_address(page) + page_off, + size); + if (err) { + consume_skb(nskb); + return err; + } + + len -= size; + off += size; + } + + consume_skb(skb); + *pskb = nskb; + + return 0; +#else + return -EOPNOTSUPP; +#endif +} + +int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb, + struct bpf_prog *prog) +{ + if (!prog->aux->xdp_has_frags) + return -EINVAL; + + return skb_pp_cow_data(pool, pskb, XDP_PACKET_HEADROOM); +} +EXPORT_SYMBOL(skb_cow_data_for_xdp); + #if IS_ENABLED(CONFIG_PAGE_POOL) bool napi_pp_put_page(struct page *page, bool napi_safe) { From 27accb3cc08a0ec4e348356774042d5fa5f30cce Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 12 Feb 2024 10:50:57 +0100 Subject: [PATCH 1192/2255] veth: rely on skb_pp_cow_data utility routine Rely on skb_pp_cow_data utility routine and remove duplicated code. Acked-by: Jesper Dangaard Brouer Reviewed-by: Toke Hoiland-Jorgensen Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/029cc14cce41cb242ee7efdcf32acc81f1ce4e9f.1707729884.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/veth.c | 74 ++---------------------------------------- include/linux/skbuff.h | 2 ++ net/core/skbuff.c | 5 +-- 3 files changed, 7 insertions(+), 74 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index de1f13837782..500b9dfccd08 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -729,80 +729,10 @@ static int veth_convert_skb_to_xdp_buff(struct veth_rq *rq, if (skb_shared(skb) || skb_head_is_locked(skb) || skb_shinfo(skb)->nr_frags || skb_headroom(skb) < XDP_PACKET_HEADROOM) { - u32 size, len, max_head_size, off, truesize, page_offset; - struct sk_buff *nskb; - struct page *page; - int i, head_off; - void *va; - - /* We need a private copy of the skb and data buffers since - * the ebpf program can modify it. We segment the original skb - * into order-0 pages without linearize it. - * - * Make sure we have enough space for linear and paged area - */ - max_head_size = SKB_WITH_OVERHEAD(PAGE_SIZE - - VETH_XDP_HEADROOM); - if (skb->len > PAGE_SIZE * MAX_SKB_FRAGS + max_head_size) + if (skb_pp_cow_data(rq->page_pool, pskb, XDP_PACKET_HEADROOM)) goto drop; - size = min_t(u32, skb->len, max_head_size); - truesize = SKB_HEAD_ALIGN(size) + VETH_XDP_HEADROOM; - - /* Allocate skb head */ - va = page_pool_dev_alloc_va(rq->page_pool, &truesize); - if (!va) - goto drop; - - nskb = napi_build_skb(va, truesize); - if (!nskb) { - page_pool_free_va(rq->page_pool, va, true); - goto drop; - } - - skb_reserve(nskb, VETH_XDP_HEADROOM); - skb_copy_header(nskb, skb); - skb_mark_for_recycle(nskb); - - if (skb_copy_bits(skb, 0, nskb->data, size)) { - consume_skb(nskb); - goto drop; - } - skb_put(nskb, size); - - head_off = skb_headroom(nskb) - skb_headroom(skb); - skb_headers_offset_update(nskb, head_off); - - /* Allocate paged area of new skb */ - off = size; - len = skb->len - off; - - for (i = 0; i < MAX_SKB_FRAGS && off < skb->len; i++) { - size = min_t(u32, len, PAGE_SIZE); - truesize = size; - - page = page_pool_dev_alloc(rq->page_pool, &page_offset, - &truesize); - if (!page) { - consume_skb(nskb); - goto drop; - } - - skb_add_rx_frag(nskb, i, page, page_offset, size, - truesize); - if (skb_copy_bits(skb, off, - page_address(page) + page_offset, - size)) { - consume_skb(nskb); - goto drop; - } - - len -= size; - off += size; - } - - consume_skb(skb); - skb = nskb; + skb = *pskb; } /* SKB "head" area always have tailroom for skb_shared_info */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index def3d8689c3d..696e7680656f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3446,6 +3446,8 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f) __skb_frag_ref(&skb_shinfo(skb)->frags[f]); } +int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, + unsigned int headroom); int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb, struct bpf_prog *prog); bool napi_pp_put_page(struct page *page, bool napi_safe); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bdb94749f05d..0d9a489e6ae1 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -895,8 +895,8 @@ static bool is_pp_page(struct page *page) return (page->pp_magic & ~0x3UL) == PP_SIGNATURE; } -static int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, - unsigned int headroom) +int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, + unsigned int headroom) { #if IS_ENABLED(CONFIG_PAGE_POOL) u32 size, truesize, len, max_head_size, off; @@ -975,6 +975,7 @@ static int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, return -EOPNOTSUPP; #endif } +EXPORT_SYMBOL(skb_pp_cow_data); int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb, struct bpf_prog *prog) From 64493a7ff74b679640ff493aed11753a1d284ca9 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Fri, 9 Feb 2024 12:35:35 +0100 Subject: [PATCH 1193/2255] wifi: ath11k: Do not directly use scan_flags in struct scan_req_params As discussed in [1] lets not use WMI_SCAN_XXX defines in combination with scan_flags directly when setting scan params in struct scan_req_params but use the underlying bitfield. This bitfield is then converted to WMI_SCAN_XXX when filling the WMI command to send to the firmware. [1] https://lore.kernel.org/all/871qae51wx.fsf@kernel.org/ Tested-on: QCN9074 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240209113536.266822-2-nico.escande@gmail.com --- drivers/net/wireless/ath/ath11k/mac.c | 6 +++--- drivers/net/wireless/ath/ath11k/wmi.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index be04f823566f..7bf5d1068164 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4013,7 +4013,7 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, req->ssids[i].ssid_len); } } else { - arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg->scan_f_passive = 1; } if (req->n_channels) { @@ -9252,8 +9252,8 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw, arg->dwell_time_active = scan_time_msec; arg->dwell_time_passive = scan_time_msec; arg->max_scan_time = scan_time_msec; - arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE; - arg->scan_flags |= WMI_SCAN_FILTER_PROBE_REQ; + arg->scan_f_passive = 1; + arg->scan_f_filter_prb_req = 1; arg->burst_duration = duration; ret = ath11k_start_scan(ar, arg); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 688ee20528a0..78c11025c21c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2098,7 +2098,7 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar, WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHAN | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; + arg->scan_f_chan_stat_evnt = 1; if (test_bit(WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE, ar->ab->wmi_ab.svc_map)) From 79ad70c6df0af8e6515a0cc064423b280f281582 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Fri, 9 Feb 2024 12:35:36 +0100 Subject: [PATCH 1194/2255] wifi: ath11k: Remove scan_flags union from struct scan_req_params Now that we do not use scan_flags directly with WMI_SCAN_XXX macros anymore but only the bitfield scan_f_xxx, lets remove the scan_flags & the underlying union. This will prevent further problems as some entries in the scan_f_xxx bitfield don't match their corresponding WMI_SCAN_XXX flags as seen in [1] [1] https://lore.kernel.org/all/20231127180559.1696041-1-nico.escande@gmail.com/ Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240209113536.266822-3-nico.escande@gmail.com --- drivers/net/wireless/ath/ath11k/wmi.h | 55 ++++++++++++--------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 6dcd14700570..bc7adf7f13fb 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3394,36 +3394,31 @@ struct scan_req_params { u32 idle_time; u32 max_scan_time; u32 probe_delay; - union { - struct { - u32 scan_f_passive:1, - scan_f_bcast_probe:1, - scan_f_cck_rates:1, - scan_f_ofdm_rates:1, - scan_f_chan_stat_evnt:1, - scan_f_filter_prb_req:1, - scan_f_bypass_dfs_chn:1, - scan_f_continue_on_err:1, - scan_f_offchan_mgmt_tx:1, - scan_f_offchan_data_tx:1, - scan_f_promisc_mode:1, - scan_f_capture_phy_err:1, - scan_f_strict_passive_pch:1, - scan_f_half_rate:1, - scan_f_quarter_rate:1, - scan_f_force_active_dfs_chn:1, - scan_f_add_tpc_ie_in_probe:1, - scan_f_add_ds_ie_in_probe:1, - scan_f_add_spoofed_mac_in_probe:1, - scan_f_add_rand_seq_in_probe:1, - scan_f_en_ie_whitelist_in_probe:1, - scan_f_forced:1, - scan_f_2ghz:1, - scan_f_5ghz:1, - scan_f_80mhz:1; - }; - u32 scan_flags; - }; + u32 scan_f_passive:1, + scan_f_bcast_probe:1, + scan_f_cck_rates:1, + scan_f_ofdm_rates:1, + scan_f_chan_stat_evnt:1, + scan_f_filter_prb_req:1, + scan_f_bypass_dfs_chn:1, + scan_f_continue_on_err:1, + scan_f_offchan_mgmt_tx:1, + scan_f_offchan_data_tx:1, + scan_f_promisc_mode:1, + scan_f_capture_phy_err:1, + scan_f_strict_passive_pch:1, + scan_f_half_rate:1, + scan_f_quarter_rate:1, + scan_f_force_active_dfs_chn:1, + scan_f_add_tpc_ie_in_probe:1, + scan_f_add_ds_ie_in_probe:1, + scan_f_add_spoofed_mac_in_probe:1, + scan_f_add_rand_seq_in_probe:1, + scan_f_en_ie_whitelist_in_probe:1, + scan_f_forced:1, + scan_f_2ghz:1, + scan_f_5ghz:1, + scan_f_80mhz:1; enum scan_dwelltime_adaptive_mode adaptive_dwell_time_mode; u32 burst_duration; u32 num_chan; From b53adefc884ce470a5b27885466439cbb087813e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 7 Feb 2024 17:15:24 +0000 Subject: [PATCH 1195/2255] wifi: carl9170: Remove redundant assignment to pointer super The pointer super is being assigned a value that is not being read, it is being re-assigned later. The assignment is redundant and can be removed. Cleans up clang scan warning: drivers/net/wireless/ath/carl9170/tx.c:192:34: warning: Value stored to 'super' during its initialization is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Acked-by: Christian Lamparter Signed-off-by: Kalle Valo Link: https://msgid.link/20240207171524.2458418-1-colin.i.king@gmail.com --- drivers/net/wireless/ath/carl9170/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 6bb9aa2bfe65..e902ca80eba7 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -189,7 +189,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) static int carl9170_alloc_dev_space(struct ar9170 *ar, struct sk_buff *skb) { - struct _carl9170_tx_superframe *super = (void *) skb->data; + struct _carl9170_tx_superframe *super; unsigned int chunks; int cookie = -1; From bcdb44f30be92b7bc750996dfc45c1fe3d49d715 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 15:55:47 +0100 Subject: [PATCH 1196/2255] wifi: ath12k: Do not use scan_flags from struct ath12k_wmi_scan_req_arg As discussed in [1] to fix the mismatch between the WMI_SCAN_XXX macros & their corresponding scan_f_xxx bitfield equivalent, lets stop using the scan_flags in the union altogether. [1] https://lore.kernel.org/all/4be7d62e-cb59-462d-aac2-94e27efc22ff@quicinc.com/ Tested-on: QCN9274 hw2.0 PCI CI_WLAN.WBE.1.3-02907.1-QCAHKSWPL_SILICONZ-10 Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240211145548.1939610-2-nico.escande@gmail.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 ++-- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a737a09a0b9c..7d3f5321a36d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3201,7 +3201,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, for (i = 0; i < arg.num_ssids; i++) arg.ssid[i] = req->ssids[i]; } else { - arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg.scan_f_passive = 1; } if (req->n_channels) { @@ -7555,7 +7555,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, arg.dwell_time_active = scan_time_msec; arg.dwell_time_passive = scan_time_msec; arg.max_scan_time = scan_time_msec; - arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg.scan_f_passive = 1; arg.burst_duration = duration; ret = ath12k_start_scan(ar, &arg); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 84d7d6584fba..2c2a010d88df 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2194,7 +2194,7 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar, WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHAN | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; + arg->scan_f_chan_stat_evnt = 1; arg->num_bssid = 1; /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be From 80fd22d7d41acd55ba362e9975290d9056079fea Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 15:55:48 +0100 Subject: [PATCH 1197/2255] wifi: ath12k: Remove unused scan_flags from struct ath12k_wmi_scan_req_arg As we did for ath11k lets remove the unused scan_flags from struct ath12k_wmi_scan_req_arg. This will prevent us from using out of sync values between WMI_SCAN_XXX & scan_f_xxx bitfield. While at it remove the underlying wrapping struct/union construct as it serves no purpose anymore. Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240211145548.1939610-3-nico.escande@gmail.com --- drivers/net/wireless/ath/ath12k/wmi.h | 55 ++++++++++++--------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 4bd1d0f270a1..892f21f95ee5 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3311,36 +3311,31 @@ struct ath12k_wmi_scan_req_arg { u32 idle_time; u32 max_scan_time; u32 probe_delay; - union { - struct { - u32 scan_f_passive:1, - scan_f_bcast_probe:1, - scan_f_cck_rates:1, - scan_f_ofdm_rates:1, - scan_f_chan_stat_evnt:1, - scan_f_filter_prb_req:1, - scan_f_bypass_dfs_chn:1, - scan_f_continue_on_err:1, - scan_f_offchan_mgmt_tx:1, - scan_f_offchan_data_tx:1, - scan_f_promisc_mode:1, - scan_f_capture_phy_err:1, - scan_f_strict_passive_pch:1, - scan_f_half_rate:1, - scan_f_quarter_rate:1, - scan_f_force_active_dfs_chn:1, - scan_f_add_tpc_ie_in_probe:1, - scan_f_add_ds_ie_in_probe:1, - scan_f_add_spoofed_mac_in_probe:1, - scan_f_add_rand_seq_in_probe:1, - scan_f_en_ie_whitelist_in_probe:1, - scan_f_forced:1, - scan_f_2ghz:1, - scan_f_5ghz:1, - scan_f_80mhz:1; - }; - u32 scan_flags; - }; + u32 scan_f_passive:1, + scan_f_bcast_probe:1, + scan_f_cck_rates:1, + scan_f_ofdm_rates:1, + scan_f_chan_stat_evnt:1, + scan_f_filter_prb_req:1, + scan_f_bypass_dfs_chn:1, + scan_f_continue_on_err:1, + scan_f_offchan_mgmt_tx:1, + scan_f_offchan_data_tx:1, + scan_f_promisc_mode:1, + scan_f_capture_phy_err:1, + scan_f_strict_passive_pch:1, + scan_f_half_rate:1, + scan_f_quarter_rate:1, + scan_f_force_active_dfs_chn:1, + scan_f_add_tpc_ie_in_probe:1, + scan_f_add_ds_ie_in_probe:1, + scan_f_add_spoofed_mac_in_probe:1, + scan_f_add_rand_seq_in_probe:1, + scan_f_en_ie_whitelist_in_probe:1, + scan_f_forced:1, + scan_f_2ghz:1, + scan_f_5ghz:1, + scan_f_80mhz:1; enum scan_dwelltime_adaptive_mode adaptive_dwell_time_mode; u32 burst_duration; u32 num_chan; From f0024c980df2547224a5b0843bbe96d26eb5b601 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 16:11:04 +0100 Subject: [PATCH 1198/2255] wifi: ath12k: remove the unused scan_events from ath12k_wmi_scan_req_arg As done for ath11k, lets keep on cleaning up struct ath12k_wmi_scan_req_arg by removing the unused scan_events. Also remove the underlying union & struct construct as it isn't needed anymore. No functionnal changes. Signed-off-by: Nicolas Escande Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240211151104.1951418-1-nico.escande@gmail.com --- drivers/net/wireless/ath/ath12k/wmi.h | 31 +++++++++++---------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 892f21f95ee5..103462feb935 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3281,24 +3281,19 @@ struct ath12k_wmi_scan_req_arg { u32 vdev_id; u32 pdev_id; enum wmi_scan_priority scan_priority; - union { - struct { - u32 scan_ev_started:1, - scan_ev_completed:1, - scan_ev_bss_chan:1, - scan_ev_foreign_chan:1, - scan_ev_dequeued:1, - scan_ev_preempted:1, - scan_ev_start_failed:1, - scan_ev_restarted:1, - scan_ev_foreign_chn_exit:1, - scan_ev_invalid:1, - scan_ev_gpio_timeout:1, - scan_ev_suspended:1, - scan_ev_resumed:1; - }; - u32 scan_events; - }; + u32 scan_ev_started:1, + scan_ev_completed:1, + scan_ev_bss_chan:1, + scan_ev_foreign_chan:1, + scan_ev_dequeued:1, + scan_ev_preempted:1, + scan_ev_start_failed:1, + scan_ev_restarted:1, + scan_ev_foreign_chn_exit:1, + scan_ev_invalid:1, + scan_ev_gpio_timeout:1, + scan_ev_suspended:1, + scan_ev_resumed:1; u32 dwell_time_active; u32 dwell_time_active_2g; u32 dwell_time_passive; From e517293fd72d9044902efae59f05203203a60736 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Fri, 5 Jan 2024 00:57:23 +0100 Subject: [PATCH 1199/2255] can: m_can: remove redundant check for pm_clock_support m_can_clk_start() already skip starting the clock when clock support is disabled, remove the redundant check in m_can_class_register(). This also solves the imbalance with m_can_clk_stop() that is called afterward in the same function before the return. Signed-off-by: Francesco Dolcini Reviewed-by: Markus Schneider-Pargmann Link: https://lore.kernel.org/all/20240104235723.46931-1-francesco@dolcini.it [mkl: rebased to net-next/main] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index b7dbce4c342a..290880ce5329 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -2312,11 +2312,9 @@ int m_can_class_register(struct m_can_classdev *cdev) } } - if (cdev->pm_clock_support) { - ret = m_can_clk_start(cdev); - if (ret) - return ret; - } + ret = m_can_clk_start(cdev); + if (ret) + return ret; if (cdev->is_peripheral) { ret = can_rx_offload_add_manual(cdev->net, &cdev->offload, From 997814491cee7b19c162ad82439818e555f99ad9 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Mon, 12 Feb 2024 18:45:23 +0530 Subject: [PATCH 1200/2255] Octeontx2-af: Fetch MAC channel info from firmware Packet ingress and egress MAC/serdes channel numbers are configurable on CN10K series of silicons. These channel numbers inturn used while installing MCAM rules to match ingress/egress port. Fetch these channel numbers from firmware at driver init time. Signed-off-by: Hariprasad Kelam Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 10 +++++++++- drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index a1d5fc65b92d..de8eba902276 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -443,6 +443,13 @@ struct mbox_wq_info { struct workqueue_struct *mbox_wq; }; +struct channel_fwdata { + struct sdp_node_info info; + u8 valid; +#define RVU_CHANL_INFO_RESERVED 379 + u8 reserved[RVU_CHANL_INFO_RESERVED]; +}; + struct rvu_fwdata { #define RVU_FWDATA_HEADER_MAGIC 0xCFDA /* Custom Firmware Data*/ #define RVU_FWDATA_VERSION 0x0001 @@ -461,7 +468,8 @@ struct rvu_fwdata { u64 msixtr_base; u32 ptp_ext_clk_rate; u32 ptp_ext_tstamp; -#define FWDATA_RESERVED_MEM 1022 + struct channel_fwdata channel_data; +#define FWDATA_RESERVED_MEM 1014 u64 reserved[FWDATA_RESERVED_MEM]; #define CGX_MAX 9 #define CGX_LMACS_MAX 4 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c index 1edfda0ae3e8..38cfe148f4b7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c @@ -56,6 +56,14 @@ int rvu_sdp_init(struct rvu *rvu) struct rvu_pfvf *pfvf; u32 i = 0; + if (rvu->fwdata->channel_data.valid) { + sdp_pf_num[0] = 0; + pfvf = &rvu->pf[sdp_pf_num[0]]; + pfvf->sdp_info = &rvu->fwdata->channel_data.info; + + return 0; + } + while ((i < MAX_SDP) && (pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OTX2_SDP_PF, pdev)) != NULL) { From 723615a14b870ab48d92dc39483043022ef05e12 Mon Sep 17 00:00:00 2001 From: Kamal Heib Date: Mon, 12 Feb 2024 22:17:18 -0500 Subject: [PATCH 1201/2255] net: ena: Remove redundant assignment There is no point in initializing an ndo to NULL, therefore the assignment is redundant and can be removed. Signed-off-by: Kamal Heib Reviewed-by: Brett Creeley Acked-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 03be2c008c4d..a77c380c9202 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2885,7 +2885,6 @@ static const struct net_device_ops ena_netdev_ops = { .ndo_get_stats64 = ena_get_stats64, .ndo_tx_timeout = ena_tx_timeout, .ndo_change_mtu = ena_change_mtu, - .ndo_set_mac_address = NULL, .ndo_validate_addr = eth_validate_addr, .ndo_bpf = ena_xdp, .ndo_xdp_xmit = ena_xdp_xmit, From 85455c795c07882091b15c0613f78d4567d9be36 Mon Sep 17 00:00:00 2001 From: Joe Damato Date: Tue, 13 Feb 2024 06:16:42 +0000 Subject: [PATCH 1202/2255] eventpoll: support busy poll per epoll instance Allow busy polling on a per-epoll context basis. The per-epoll context usec timeout value is preferred, but the pre-existing system wide sysctl value is still supported if it specified. busy_poll_usecs is a u32, but in a follow up patch the ioctl provided to the user only allows setting a value from 0 to S32_MAX. Signed-off-by: Joe Damato Acked-by: Stanislav Fomichev Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- fs/eventpoll.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 3534d36a1474..401f865eced9 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -227,6 +227,8 @@ struct eventpoll { #ifdef CONFIG_NET_RX_BUSY_POLL /* used to track busy poll napi_id */ unsigned int napi_id; + /* busy poll timeout */ + u32 busy_poll_usecs; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -387,11 +389,41 @@ static inline int ep_events_available(struct eventpoll *ep) } #ifdef CONFIG_NET_RX_BUSY_POLL +/** + * busy_loop_ep_timeout - check if busy poll has timed out. The timeout value + * from the epoll instance ep is preferred, but if it is not set fallback to + * the system-wide global via busy_loop_timeout. + * + * @start_time: The start time used to compute the remaining time until timeout. + * @ep: Pointer to the eventpoll context. + * + * Return: true if the timeout has expired, false otherwise. + */ +static bool busy_loop_ep_timeout(unsigned long start_time, + struct eventpoll *ep) +{ + unsigned long bp_usec = READ_ONCE(ep->busy_poll_usecs); + + if (bp_usec) { + unsigned long end_time = start_time + bp_usec; + unsigned long now = busy_loop_current_time(); + + return time_after(now, end_time); + } else { + return busy_loop_timeout(start_time); + } +} + +static bool ep_busy_loop_on(struct eventpoll *ep) +{ + return !!ep->busy_poll_usecs || net_busy_loop_on(); +} + static bool ep_busy_loop_end(void *p, unsigned long start_time) { struct eventpoll *ep = p; - return ep_events_available(ep) || busy_loop_timeout(start_time); + return ep_events_available(ep) || busy_loop_ep_timeout(start_time, ep); } /* @@ -404,7 +436,7 @@ static bool ep_busy_loop(struct eventpoll *ep, int nonblock) { unsigned int napi_id = READ_ONCE(ep->napi_id); - if ((napi_id >= MIN_NAPI_ID) && net_busy_loop_on()) { + if (napi_id >= MIN_NAPI_ID && ep_busy_loop_on(ep)) { napi_busy_loop(napi_id, nonblock ? NULL : ep_busy_loop_end, ep, false, BUSY_POLL_BUDGET); if (ep_events_available(ep)) @@ -425,12 +457,12 @@ static bool ep_busy_loop(struct eventpoll *ep, int nonblock) */ static inline void ep_set_busy_poll_napi_id(struct epitem *epi) { - struct eventpoll *ep; + struct eventpoll *ep = epi->ep; unsigned int napi_id; struct socket *sock; struct sock *sk; - if (!net_busy_loop_on()) + if (!ep_busy_loop_on(ep)) return; sock = sock_from_file(epi->ffd.file); @@ -442,7 +474,6 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi) return; napi_id = READ_ONCE(sk->sk_napi_id); - ep = epi->ep; /* Non-NAPI IDs can be rejected * or @@ -2058,6 +2089,9 @@ static int do_epoll_create(int flags) error = PTR_ERR(file); goto out_free_fd; } +#ifdef CONFIG_NET_RX_BUSY_POLL + ep->busy_poll_usecs = 0; +#endif ep->file = file; fd_install(fd, file); return fd; From c6aa2a7778d8e3ba7c6f84c8095f0b89f0617830 Mon Sep 17 00:00:00 2001 From: Joe Damato Date: Tue, 13 Feb 2024 06:16:43 +0000 Subject: [PATCH 1203/2255] eventpoll: Add per-epoll busy poll packet budget When using epoll-based busy poll, the packet budget is hardcoded to BUSY_POLL_BUDGET (8). Users may desire larger busy poll budgets, which can potentially increase throughput when busy polling under high network load. Other busy poll methods allow setting the busy poll budget via SO_BUSY_POLL_BUDGET, but epoll-based busy polling uses a hardcoded value. Fix this edge case by adding support for a per-epoll context busy poll packet budget. If not specified, the default value (BUSY_POLL_BUDGET) is used. Signed-off-by: Joe Damato Acked-by: Stanislav Fomichev Reviewed-by: Jakub Kicinski Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- fs/eventpoll.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 401f865eced9..ed83ae33dd45 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -229,6 +229,8 @@ struct eventpoll { unsigned int napi_id; /* busy poll timeout */ u32 busy_poll_usecs; + /* busy poll packet budget */ + u16 busy_poll_budget; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -435,10 +437,14 @@ static bool ep_busy_loop_end(void *p, unsigned long start_time) static bool ep_busy_loop(struct eventpoll *ep, int nonblock) { unsigned int napi_id = READ_ONCE(ep->napi_id); + u16 budget = READ_ONCE(ep->busy_poll_budget); + + if (!budget) + budget = BUSY_POLL_BUDGET; if (napi_id >= MIN_NAPI_ID && ep_busy_loop_on(ep)) { napi_busy_loop(napi_id, nonblock ? NULL : ep_busy_loop_end, ep, false, - BUSY_POLL_BUDGET); + budget); if (ep_events_available(ep)) return true; /* @@ -2091,6 +2097,7 @@ static int do_epoll_create(int flags) } #ifdef CONFIG_NET_RX_BUSY_POLL ep->busy_poll_usecs = 0; + ep->busy_poll_budget = 0; #endif ep->file = file; fd_install(fd, file); From de57a251082211b68e8c01e0e8210a23c022ac57 Mon Sep 17 00:00:00 2001 From: Joe Damato Date: Tue, 13 Feb 2024 06:16:44 +0000 Subject: [PATCH 1204/2255] eventpoll: Add per-epoll prefer busy poll option When using epoll-based busy poll, the prefer_busy_poll option is hardcoded to false. Users may want to enable prefer_busy_poll to be used in conjunction with gro_flush_timeout and defer_hard_irqs_count to keep device IRQs masked. Other busy poll methods allow enabling or disabling prefer busy poll via SO_PREFER_BUSY_POLL, but epoll-based busy polling uses a hardcoded value. Fix this edge case by adding support for a per-epoll context prefer_busy_poll option. The default is false, as it was hardcoded before this change. Signed-off-by: Joe Damato Acked-by: Stanislav Fomichev Reviewed-by: Jakub Kicinski Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- fs/eventpoll.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index ed83ae33dd45..1b8d01af0c2c 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -231,6 +231,7 @@ struct eventpoll { u32 busy_poll_usecs; /* busy poll packet budget */ u16 busy_poll_budget; + bool prefer_busy_poll; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -438,13 +439,14 @@ static bool ep_busy_loop(struct eventpoll *ep, int nonblock) { unsigned int napi_id = READ_ONCE(ep->napi_id); u16 budget = READ_ONCE(ep->busy_poll_budget); + bool prefer_busy_poll = READ_ONCE(ep->prefer_busy_poll); if (!budget) budget = BUSY_POLL_BUDGET; if (napi_id >= MIN_NAPI_ID && ep_busy_loop_on(ep)) { - napi_busy_loop(napi_id, nonblock ? NULL : ep_busy_loop_end, ep, false, - budget); + napi_busy_loop(napi_id, nonblock ? NULL : ep_busy_loop_end, + ep, prefer_busy_poll, budget); if (ep_events_available(ep)) return true; /* @@ -2098,6 +2100,7 @@ static int do_epoll_create(int flags) #ifdef CONFIG_NET_RX_BUSY_POLL ep->busy_poll_usecs = 0; ep->busy_poll_budget = 0; + ep->prefer_busy_poll = false; #endif ep->file = file; fd_install(fd, file); From 18e2bf0edf4dd88d9656ec92395aa47392e85b61 Mon Sep 17 00:00:00 2001 From: Joe Damato Date: Tue, 13 Feb 2024 06:16:45 +0000 Subject: [PATCH 1205/2255] eventpoll: Add epoll ioctl for epoll_params Add an ioctl for getting and setting epoll_params. User programs can use this ioctl to get and set the busy poll usec time, packet budget, and prefer busy poll params for a specific epoll context. Parameters are limited: - busy_poll_usecs is limited to <= s32_max - busy_poll_budget is limited to <= NAPI_POLL_WEIGHT by unprivileged users (!capable(CAP_NET_ADMIN)) - prefer_busy_poll must be 0 or 1 - __pad must be 0 Signed-off-by: Joe Damato Acked-by: Stanislav Fomichev Reviewed-by: Jiri Slaby Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- .../userspace-api/ioctl/ioctl-number.rst | 1 + fs/eventpoll.c | 73 +++++++++++++++++++ include/uapi/linux/eventpoll.h | 13 ++++ 3 files changed, 87 insertions(+) diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 457e16f06e04..b33918232f78 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -309,6 +309,7 @@ Code Seq# Include File Comments 0x89 0B-DF linux/sockios.h 0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range 0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range +0x8A 00-1F linux/eventpoll.h 0x8B all linux/wireless.h 0x8C 00-3F WiNRADiO driver diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 1b8d01af0c2c..df2ed3af486e 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -37,6 +37,7 @@ #include #include #include +#include #include /* @@ -494,6 +495,49 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi) ep->napi_id = napi_id; } +static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct eventpoll *ep = file->private_data; + void __user *uarg = (void __user *)arg; + struct epoll_params epoll_params; + + switch (cmd) { + case EPIOCSPARAMS: + if (copy_from_user(&epoll_params, uarg, sizeof(epoll_params))) + return -EFAULT; + + /* pad byte must be zero */ + if (epoll_params.__pad) + return -EINVAL; + + if (epoll_params.busy_poll_usecs > S32_MAX) + return -EINVAL; + + if (epoll_params.prefer_busy_poll > 1) + return -EINVAL; + + if (epoll_params.busy_poll_budget > NAPI_POLL_WEIGHT && + !capable(CAP_NET_ADMIN)) + return -EPERM; + + WRITE_ONCE(ep->busy_poll_usecs, epoll_params.busy_poll_usecs); + WRITE_ONCE(ep->busy_poll_budget, epoll_params.busy_poll_budget); + WRITE_ONCE(ep->prefer_busy_poll, epoll_params.prefer_busy_poll); + return 0; + case EPIOCGPARAMS: + memset(&epoll_params, 0, sizeof(epoll_params)); + epoll_params.busy_poll_usecs = READ_ONCE(ep->busy_poll_usecs); + epoll_params.busy_poll_budget = READ_ONCE(ep->busy_poll_budget); + epoll_params.prefer_busy_poll = READ_ONCE(ep->prefer_busy_poll); + if (copy_to_user(uarg, &epoll_params, sizeof(epoll_params))) + return -EFAULT; + return 0; + default: + return -ENOIOCTLCMD; + } +} + #else static inline bool ep_busy_loop(struct eventpoll *ep, int nonblock) @@ -505,6 +549,12 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi) { } +static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_NET_RX_BUSY_POLL */ /* @@ -864,6 +914,27 @@ static void ep_clear_and_put(struct eventpoll *ep) ep_free(ep); } +static long ep_eventpoll_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + + if (!is_file_epoll(file)) + return -EINVAL; + + switch (cmd) { + case EPIOCSPARAMS: + case EPIOCGPARAMS: + ret = ep_eventpoll_bp_ioctl(file, cmd, arg); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + static int ep_eventpoll_release(struct inode *inode, struct file *file) { struct eventpoll *ep = file->private_data; @@ -970,6 +1041,8 @@ static const struct file_operations eventpoll_fops = { .release = ep_eventpoll_release, .poll = ep_eventpoll_poll, .llseek = noop_llseek, + .unlocked_ioctl = ep_eventpoll_ioctl, + .compat_ioctl = compat_ptr_ioctl, }; /* diff --git a/include/uapi/linux/eventpoll.h b/include/uapi/linux/eventpoll.h index cfbcc4cc49ac..4f4b948ef381 100644 --- a/include/uapi/linux/eventpoll.h +++ b/include/uapi/linux/eventpoll.h @@ -85,4 +85,17 @@ struct epoll_event { __u64 data; } EPOLL_PACKED; +struct epoll_params { + __u32 busy_poll_usecs; + __u16 busy_poll_budget; + __u8 prefer_busy_poll; + + /* pad the struct to a multiple of 64bits */ + __u8 __pad; +}; + +#define EPOLL_IOC_TYPE 0x8A +#define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params) +#define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params) + #endif /* _UAPI_LINUX_EVENTPOLL_H */ From 1c07dbb0cccfe85060b6eb089db3d6bfeb6aaf31 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:33 +0000 Subject: [PATCH 1206/2255] net: annotate data-races around dev->name_assign_type name_assign_type_show() runs locklessly, we should annotate accesses to dev->name_assign_type. Alternative would be to grab devnet_rename_sem semaphore from name_assign_type_show(), but this would not bring more accuracy. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 6 +++--- net/core/net-sysfs.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 2d02ca8a3da5..720bd6838212 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1228,13 +1228,13 @@ int dev_change_name(struct net_device *dev, const char *newname) dev->flags & IFF_UP ? " (while UP)" : ""); old_assign_type = dev->name_assign_type; - dev->name_assign_type = NET_NAME_RENAMED; + WRITE_ONCE(dev->name_assign_type, NET_NAME_RENAMED); rollback: ret = device_rename(&dev->dev, dev->name); if (ret) { memcpy(dev->name, oldname, IFNAMSIZ); - dev->name_assign_type = old_assign_type; + WRITE_ONCE(dev->name_assign_type, old_assign_type); up_write(&devnet_rename_sem); return ret; } @@ -1263,7 +1263,7 @@ rollback: down_write(&devnet_rename_sem); memcpy(dev->name, oldname, IFNAMSIZ); memcpy(oldname, newname, IFNAMSIZ); - dev->name_assign_type = old_assign_type; + WRITE_ONCE(dev->name_assign_type, old_assign_type); old_assign_type = NET_NAME_RENAMED; goto rollback; } else { diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index a09d507c5b03..f4c2b8267495 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -125,7 +125,7 @@ static DEVICE_ATTR_RO(iflink); static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) { - return sysfs_emit(buf, fmt_dec, dev->name_assign_type); + return sysfs_emit(buf, fmt_dec, READ_ONCE(dev->name_assign_type)); } static ssize_t name_assign_type_show(struct device *dev, @@ -135,7 +135,7 @@ static ssize_t name_assign_type_show(struct device *dev, struct net_device *ndev = to_net_dev(dev); ssize_t ret = -EINVAL; - if (ndev->name_assign_type != NET_NAME_UNKNOWN) + if (READ_ONCE(ndev->name_assign_type) != NET_NAME_UNKNOWN) ret = netdev_show(dev, attr, buf, format_name_assign_type); return ret; From f694eee9e1c00d6ca06c5e59c04e3b6ff7d64aa9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:34 +0000 Subject: [PATCH 1207/2255] ip_tunnel: annotate data-races around t->parms.link t->parms.link is read locklessly, annotate these reads and opposite writes accordingly. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ip_tunnel.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 58de780ab0e2..9f44c49a61de 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -102,10 +102,9 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, if (!ip_tunnel_key_match(&t->parms, flags, key)) continue; - if (t->parms.link == link) + if (READ_ONCE(t->parms.link) == link) return t; - else - cand = t; + cand = t; } hlist_for_each_entry_rcu(t, head, hash_node) { @@ -117,9 +116,9 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, if (!ip_tunnel_key_match(&t->parms, flags, key)) continue; - if (t->parms.link == link) + if (READ_ONCE(t->parms.link) == link) return t; - else if (!cand) + if (!cand) cand = t; } @@ -137,9 +136,9 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, if (!ip_tunnel_key_match(&t->parms, flags, key)) continue; - if (t->parms.link == link) + if (READ_ONCE(t->parms.link) == link) return t; - else if (!cand) + if (!cand) cand = t; } @@ -150,9 +149,9 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, !(t->dev->flags & IFF_UP)) continue; - if (t->parms.link == link) + if (READ_ONCE(t->parms.link) == link) return t; - else if (!cand) + if (!cand) cand = t; } @@ -221,7 +220,7 @@ static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn, hlist_for_each_entry_rcu(t, head, hash_node) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && - link == t->parms.link && + link == READ_ONCE(t->parms.link) && type == t->dev->type && ip_tunnel_key_match(&t->parms, flags, key)) break; @@ -747,7 +746,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr, tunnel->parms.o_key, RT_TOS(tos), - dev_net(dev), tunnel->parms.link, + dev_net(dev), READ_ONCE(tunnel->parms.link), tunnel->fwmark, skb_get_hash(skb), 0); if (ip_tunnel_encap(skb, &tunnel->encap, &protocol, &fl4) < 0) @@ -867,7 +866,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn, if (t->parms.link != p->link || t->fwmark != fwmark) { int mtu; - t->parms.link = p->link; + WRITE_ONCE(t->parms.link, p->link); t->fwmark = fwmark; mtu = ip_tunnel_bind_dev(dev); if (set_mtu) @@ -1057,9 +1056,9 @@ EXPORT_SYMBOL(ip_tunnel_get_link_net); int ip_tunnel_get_iflink(const struct net_device *dev) { - struct ip_tunnel *tunnel = netdev_priv(dev); + const struct ip_tunnel *tunnel = netdev_priv(dev); - return tunnel->parms.link; + return READ_ONCE(tunnel->parms.link); } EXPORT_SYMBOL(ip_tunnel_get_iflink); From a6473fe9b623f6667af72d972b87cd9a5ff87e21 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:35 +0000 Subject: [PATCH 1208/2255] dev: annotate accesses to dev->link Following patch will read dev->link locklessly, annotate the write from do_setlink(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 6f1c5537e842..fd47a4422a51 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2956,7 +2956,7 @@ static int do_setlink(const struct sk_buff *skb, write_lock(&dev_base_lock); if (dev->link_mode ^ value) status |= DO_SETLINK_NOTIFY; - dev->link_mode = value; + WRITE_ONCE(dev->link_mode, value); write_unlock(&dev_base_lock); } From 4d42b37def70327b2bb19f823d42289aed2cd7c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:36 +0000 Subject: [PATCH 1209/2255] net: convert dev->reg_state to u8 Prepares things so that dev->reg_state reads can be lockless, by adding WRITE_ONCE() on write side. READ_ONCE()/WRITE_ONCE() do not support bitfields. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 23 ++++++++++++++--------- net/core/dev.c | 8 ++++---- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a3f9c95da51e..631124655107 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1815,6 +1815,15 @@ enum netdev_stat_type { NETDEV_PCPU_STAT_DSTATS, /* struct pcpu_dstats */ }; +enum netdev_reg_state { + NETREG_UNINITIALIZED = 0, + NETREG_REGISTERED, /* completed register_netdevice */ + NETREG_UNREGISTERING, /* called unregister_netdevice */ + NETREG_UNREGISTERED, /* completed unregister todo */ + NETREG_RELEASED, /* called free_netdev */ + NETREG_DUMMY, /* dummy device for NAPI poll */ +}; + /** * struct net_device - The DEVICE structure. * @@ -2372,13 +2381,7 @@ struct net_device { struct list_head link_watch_list; - enum { NETREG_UNINITIALIZED=0, - NETREG_REGISTERED, /* completed register_netdevice */ - NETREG_UNREGISTERING, /* called unregister_netdevice */ - NETREG_UNREGISTERED, /* completed unregister todo */ - NETREG_RELEASED, /* called free_netdev */ - NETREG_DUMMY, /* dummy device for NAPI poll */ - } reg_state:8; + u8 reg_state; bool dismantle; @@ -5254,7 +5257,9 @@ static inline const char *netdev_name(const struct net_device *dev) static inline const char *netdev_reg_state(const struct net_device *dev) { - switch (dev->reg_state) { + u8 reg_state = READ_ONCE(dev->reg_state); + + switch (reg_state) { case NETREG_UNINITIALIZED: return " (uninitialized)"; case NETREG_REGISTERED: return ""; case NETREG_UNREGISTERING: return " (unregistering)"; @@ -5263,7 +5268,7 @@ static inline const char *netdev_reg_state(const struct net_device *dev) case NETREG_DUMMY: return " (dummy)"; } - WARN_ONCE(1, "%s: unknown reg_state %d\n", dev->name, dev->reg_state); + WARN_ONCE(1, "%s: unknown reg_state %d\n", dev->name, reg_state); return " (unknown)"; } diff --git a/net/core/dev.c b/net/core/dev.c index 720bd6838212..9c95cae9d6ab 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10339,7 +10339,7 @@ int register_netdevice(struct net_device *dev) ret = netdev_register_kobject(dev); write_lock(&dev_base_lock); - dev->reg_state = ret ? NETREG_UNREGISTERED : NETREG_REGISTERED; + WRITE_ONCE(dev->reg_state, ret ? NETREG_UNREGISTERED : NETREG_REGISTERED); write_unlock(&dev_base_lock); if (ret) goto err_uninit_notify; @@ -10630,7 +10630,7 @@ void netdev_run_todo(void) } write_lock(&dev_base_lock); - dev->reg_state = NETREG_UNREGISTERED; + WRITE_ONCE(dev->reg_state, NETREG_UNREGISTERED); write_unlock(&dev_base_lock); linkwatch_sync_dev(dev); } @@ -11050,7 +11050,7 @@ void free_netdev(struct net_device *dev) } BUG_ON(dev->reg_state != NETREG_UNREGISTERED); - dev->reg_state = NETREG_RELEASED; + WRITE_ONCE(dev->reg_state, NETREG_RELEASED); /* will free via device release */ put_device(&dev->dev); @@ -11140,7 +11140,7 @@ void unregister_netdevice_many_notify(struct list_head *head, /* And unlink it from device chain. */ write_lock(&dev_base_lock); unlist_netdevice(dev, false); - dev->reg_state = NETREG_UNREGISTERING; + WRITE_ONCE(dev->reg_state, NETREG_UNREGISTERING); write_unlock(&dev_base_lock); } flush_all_backlogs(); From 12692e3df2dacf2993c56aa23b6d3de921a5bdff Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:37 +0000 Subject: [PATCH 1210/2255] net-sysfs: convert netdev_show() to RCU Make clear dev_isalive() can be called with RCU protection. Then convert netdev_show() to RCU, to remove dev_base_lock dependency. Also add RCU to broadcast_show(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index f4c2b8267495..678e4be69082 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -34,10 +34,10 @@ static const char fmt_dec[] = "%d\n"; static const char fmt_ulong[] = "%lu\n"; static const char fmt_u64[] = "%llu\n"; -/* Caller holds RTNL or dev_base_lock */ +/* Caller holds RTNL, RCU or dev_base_lock */ static inline int dev_isalive(const struct net_device *dev) { - return dev->reg_state <= NETREG_REGISTERED; + return READ_ONCE(dev->reg_state) <= NETREG_REGISTERED; } /* use same locking rules as GIF* ioctl's */ @@ -48,10 +48,10 @@ static ssize_t netdev_show(const struct device *dev, struct net_device *ndev = to_net_dev(dev); ssize_t ret = -EINVAL; - read_lock(&dev_base_lock); + rcu_read_lock(); if (dev_isalive(ndev)) ret = (*format)(ndev, buf); - read_unlock(&dev_base_lock); + rcu_read_unlock(); return ret; } @@ -60,7 +60,7 @@ static ssize_t netdev_show(const struct device *dev, #define NETDEVICE_SHOW(field, format_string) \ static ssize_t format_##field(const struct net_device *dev, char *buf) \ { \ - return sysfs_emit(buf, format_string, dev->field); \ + return sysfs_emit(buf, format_string, READ_ONCE(dev->field)); \ } \ static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -161,10 +161,13 @@ static ssize_t broadcast_show(struct device *dev, struct device_attribute *attr, char *buf) { struct net_device *ndev = to_net_dev(dev); + int ret = -EINVAL; + rcu_read_lock(); if (dev_isalive(ndev)) - return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); - return -EINVAL; + ret = sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); + rcu_read_unlock(); + return ret; } static DEVICE_ATTR_RO(broadcast); From c7d52737e7ebd31cc5fef46380d94b58becf9479 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:38 +0000 Subject: [PATCH 1211/2255] net-sysfs: use dev_addr_sem to remove races in address_show() Using dev_base_lock is not preventing from reading garbage. Use dev_addr_sem instead. v4: place dev_addr_sem extern in net/core/dev.h (Jakub Kicinski) Link: https://lore.kernel.org/netdev/20240212175845.10f6680a@kernel.org/ Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- net/core/dev.h | 3 +++ net/core/net-sysfs.c | 10 +++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 9c95cae9d6ab..26f93446b743 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8993,7 +8993,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa, } EXPORT_SYMBOL(dev_set_mac_address); -static DECLARE_RWSEM(dev_addr_sem); +DECLARE_RWSEM(dev_addr_sem); int dev_set_mac_address_user(struct net_device *dev, struct sockaddr *sa, struct netlink_ext_ack *extack) diff --git a/net/core/dev.h b/net/core/dev.h index a43dfe3de50e..45892267848d 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -3,6 +3,7 @@ #define _NET_CORE_DEV_H #include +#include struct net; struct net_device; @@ -46,6 +47,8 @@ extern int weight_p; extern int dev_weight_rx_bias; extern int dev_weight_tx_bias; +extern struct rw_semaphore dev_addr_sem; + /* rtnl helpers */ extern struct list_head net_todo_list; void netdev_run_todo(void); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 678e4be69082..23ef2df549c3 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -142,17 +142,21 @@ static ssize_t name_assign_type_show(struct device *dev, } static DEVICE_ATTR_RO(name_assign_type); -/* use same locking rules as GIFHWADDR ioctl's */ +/* use same locking rules as GIFHWADDR ioctl's (dev_get_mac_address()) */ static ssize_t address_show(struct device *dev, struct device_attribute *attr, char *buf) { struct net_device *ndev = to_net_dev(dev); ssize_t ret = -EINVAL; - read_lock(&dev_base_lock); + down_read(&dev_addr_sem); + + rcu_read_lock(); if (dev_isalive(ndev)) ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); - read_unlock(&dev_base_lock); + rcu_read_unlock(); + + up_read(&dev_addr_sem); return ret; } static DEVICE_ATTR_RO(address); From 004d138364fd10dd5ff8ceb54cfdc2d792a7b338 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:39 +0000 Subject: [PATCH 1212/2255] net-sysfs: convert dev->operstate reads to lockless ones operstate_show() can omit dev_base_lock acquisition only to read dev->operstate. Annotate accesses to dev->operstate. Writers still acquire dev_base_lock for mutual exclusion. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/bridge/br_netlink.c | 3 ++- net/core/link_watch.c | 4 ++-- net/core/net-sysfs.c | 4 +--- net/core/rtnetlink.c | 4 ++-- net/hsr/hsr_device.c | 10 +++++----- net/ipv6/addrconf.c | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 5ad4abfcb7ba..2cf4fc756263 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -455,7 +455,8 @@ static int br_fill_ifinfo(struct sk_buff *skb, u32 filter_mask, const struct net_device *dev, bool getlink) { - u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; + u8 operstate = netif_running(dev) ? READ_ONCE(dev->operstate) : + IF_OPER_DOWN; struct nlattr *af = NULL; struct net_bridge *br; struct ifinfomsg *hdr; diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 429571c258da..1b93e054c9a3 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -67,7 +67,7 @@ static void rfc2863_policy(struct net_device *dev) { unsigned char operstate = default_operstate(dev); - if (operstate == dev->operstate) + if (operstate == READ_ONCE(dev->operstate)) return; write_lock(&dev_base_lock); @@ -87,7 +87,7 @@ static void rfc2863_policy(struct net_device *dev) break; } - dev->operstate = operstate; + WRITE_ONCE(dev->operstate, operstate); write_unlock(&dev_base_lock); } diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 23ef2df549c3..c5d164b8c6bf 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -325,11 +325,9 @@ static ssize_t operstate_show(struct device *dev, const struct net_device *netdev = to_net_dev(dev); unsigned char operstate; - read_lock(&dev_base_lock); - operstate = netdev->operstate; + operstate = READ_ONCE(netdev->operstate); if (!netif_running(netdev)) operstate = IF_OPER_DOWN; - read_unlock(&dev_base_lock); if (operstate >= ARRAY_SIZE(operstates)) return -EINVAL; /* should not happen */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index fd47a4422a51..43d92de8601c 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -866,9 +866,9 @@ static void set_operstate(struct net_device *dev, unsigned char transition) break; } - if (dev->operstate != operstate) { + if (READ_ONCE(dev->operstate) != operstate) { write_lock(&dev_base_lock); - dev->operstate = operstate; + WRITE_ONCE(dev->operstate, operstate); write_unlock(&dev_base_lock); netdev_state_change(dev); } diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 9d71b66183da..be0e43f46556 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -31,8 +31,8 @@ static bool is_slave_up(struct net_device *dev) static void __hsr_set_operstate(struct net_device *dev, int transition) { write_lock(&dev_base_lock); - if (dev->operstate != transition) { - dev->operstate = transition; + if (READ_ONCE(dev->operstate) != transition) { + WRITE_ONCE(dev->operstate, transition); write_unlock(&dev_base_lock); netdev_state_change(dev); } else { @@ -78,14 +78,14 @@ static void hsr_check_announce(struct net_device *hsr_dev, hsr = netdev_priv(hsr_dev); - if (hsr_dev->operstate == IF_OPER_UP && old_operstate != IF_OPER_UP) { + if (READ_ONCE(hsr_dev->operstate) == IF_OPER_UP && old_operstate != IF_OPER_UP) { /* Went up */ hsr->announce_count = 0; mod_timer(&hsr->announce_timer, jiffies + msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL)); } - if (hsr_dev->operstate != IF_OPER_UP && old_operstate == IF_OPER_UP) + if (READ_ONCE(hsr_dev->operstate) != IF_OPER_UP && old_operstate == IF_OPER_UP) /* Went down */ del_timer(&hsr->announce_timer); } @@ -100,7 +100,7 @@ void hsr_check_carrier_and_operstate(struct hsr_priv *hsr) /* netif_stacked_transfer_operstate() cannot be used here since * it doesn't set IF_OPER_LOWERLAYERDOWN (?) */ - old_operstate = master->dev->operstate; + old_operstate = READ_ONCE(master->dev->operstate); has_carrier = hsr_check_carrier(master); hsr_set_operstate(master, has_carrier); hsr_check_announce(master->dev, old_operstate); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ca1b719323c0..2c1ed642e3f4 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -6025,7 +6025,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, (dev->ifindex != dev_get_iflink(dev) && nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev))) || nla_put_u8(skb, IFLA_OPERSTATE, - netif_running(dev) ? dev->operstate : IF_OPER_DOWN)) + netif_running(dev) ? READ_ONCE(dev->operstate) : IF_OPER_DOWN)) goto nla_put_failure; protoinfo = nla_nest_start_noflag(skb, IFLA_PROTINFO); if (!protoinfo) From e154bb7a6ebbe5414accb5d94dc5ba80c204ea64 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:40 +0000 Subject: [PATCH 1213/2255] net-sysfs: convert netstat_show() to RCU dev_get_stats() can be called from RCU, there is no need to acquire dev_base_lock. Change dev_isalive() comment to reflect we no longer use dev_base_lock from net/core/net-sysfs.c Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index c5d164b8c6bf..946caefdd959 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -34,7 +34,7 @@ static const char fmt_dec[] = "%d\n"; static const char fmt_ulong[] = "%lu\n"; static const char fmt_u64[] = "%llu\n"; -/* Caller holds RTNL, RCU or dev_base_lock */ +/* Caller holds RTNL or RCU */ static inline int dev_isalive(const struct net_device *dev) { return READ_ONCE(dev->reg_state) <= NETREG_REGISTERED; @@ -685,14 +685,14 @@ static ssize_t netstat_show(const struct device *d, WARN_ON(offset > sizeof(struct rtnl_link_stats64) || offset % sizeof(u64) != 0); - read_lock(&dev_base_lock); + rcu_read_lock(); if (dev_isalive(dev)) { struct rtnl_link_stats64 temp; const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); ret = sysfs_emit(buf, fmt_u64, *(u64 *)(((u8 *)stats) + offset)); } - read_unlock(&dev_base_lock); + rcu_read_unlock(); return ret; } From 328771deab16fcac55763309bb59e28b1c050853 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:41 +0000 Subject: [PATCH 1214/2255] net: remove stale mentions of dev_base_lock in comments Change comments incorrectly mentioning dev_base_lock. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/networking/netdevices.rst | 4 ++-- drivers/net/ethernet/cisco/enic/enic_main.c | 2 +- drivers/net/ethernet/nvidia/forcedeth.c | 4 ++-- drivers/net/ethernet/sfc/efx_common.c | 2 +- drivers/net/ethernet/sfc/falcon/efx.c | 2 +- drivers/net/ethernet/sfc/siena/efx_common.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/networking/netdevices.rst b/Documentation/networking/netdevices.rst index 9e4cccb90b87..c2476917a6c3 100644 --- a/Documentation/networking/netdevices.rst +++ b/Documentation/networking/netdevices.rst @@ -252,8 +252,8 @@ ndo_eth_ioctl: Context: process ndo_get_stats: - Synchronization: rtnl_lock() semaphore, dev_base_lock rwlock, or RCU. - Context: atomic (can't sleep under rwlock or RCU) + Synchronization: rtnl_lock() semaphore, or RCU. + Context: atomic (can't sleep under RCU) ndo_start_xmit: Synchronization: __netif_tx_lock spinlock. diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 37bd38d772e8..d266a87297a5 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -872,7 +872,7 @@ error: return NETDEV_TX_OK; } -/* dev_base_lock rwlock held, nominally process context */ +/* rcu_read_lock potentially held, nominally process context */ static void enic_get_stats(struct net_device *netdev, struct rtnl_link_stats64 *net_stats) { diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 7a549b834e97..31f896c4aa26 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -1761,7 +1761,7 @@ static void nv_get_stats(int cpu, struct fe_priv *np, /* * nv_get_stats64: dev->ndo_get_stats64 function * Get latest stats value from the nic. - * Called with read_lock(&dev_base_lock) held for read - + * Called with rcu_read_lock() held - * only synchronized against unregister_netdevice. */ static void @@ -3090,7 +3090,7 @@ static void set_bufsize(struct net_device *dev) /* * nv_change_mtu: dev->change_mtu function - * Called with dev_base_lock held for read. + * Called with RTNL held for read. */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c index 175bd9cdfdac..551f890db90a 100644 --- a/drivers/net/ethernet/sfc/efx_common.c +++ b/drivers/net/ethernet/sfc/efx_common.c @@ -595,7 +595,7 @@ void efx_stop_all(struct efx_nic *efx) efx_stop_datapath(efx); } -/* Context: process, dev_base_lock or RTNL held, non-blocking. */ +/* Context: process, rcu_read_lock or RTNL held, non-blocking. */ void efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats) { struct efx_nic *efx = efx_netdev_priv(net_dev); diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index e001f27085c6..1cb32aedd89c 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -2085,7 +2085,7 @@ int ef4_net_stop(struct net_device *net_dev) return 0; } -/* Context: process, dev_base_lock or RTNL held, non-blocking. */ +/* Context: process, rcu_read_lock or RTNL held, non-blocking. */ static void ef4_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats) { diff --git a/drivers/net/ethernet/sfc/siena/efx_common.c b/drivers/net/ethernet/sfc/siena/efx_common.c index e4b294b8e9ac..88e5bc347a44 100644 --- a/drivers/net/ethernet/sfc/siena/efx_common.c +++ b/drivers/net/ethernet/sfc/siena/efx_common.c @@ -605,7 +605,7 @@ static size_t efx_siena_update_stats_atomic(struct efx_nic *efx, u64 *full_stats return efx->type->update_stats(efx, full_stats, core_stats); } -/* Context: process, dev_base_lock or RTNL held, non-blocking. */ +/* Context: process, rcu_read_lock or RTNL held, non-blocking. */ void efx_siena_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats) { From 6a2968ee1ee2cc6fce30f6f5724442b34b1483b3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:42 +0000 Subject: [PATCH 1215/2255] net: add netdev_set_operstate() helper dev_base_lock is going away, add netdev_set_operstate() helper so that hsr does not have to know core internals. Remove dev_base_lock acquisition from rfc2863_policy() v3: use an "unsigned int" for dev->operstate, so that try_cmpxchg() can work on all arches. ( https://lore.kernel.org/oe-kbuild-all/202402081918.OLyGaea3-lkp@intel.com/ ) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- include/linux/rtnetlink.h | 2 ++ net/core/link_watch.c | 9 ++------- net/core/rtnetlink.c | 22 +++++++++++++++------- net/hsr/hsr_device.c | 22 ++++++---------------- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 631124655107..697370706a82 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2258,7 +2258,7 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif - unsigned char operstate; + unsigned int operstate; unsigned char link_mode; unsigned char if_port; diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 21780608cf47..cdfc897f1e3c 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -172,4 +172,6 @@ rtnl_notify_needed(const struct net *net, u16 nlflags, u32 group) return (nlflags & NLM_F_ECHO) || rtnl_has_listeners(net, group); } +void netdev_set_operstate(struct net_device *dev, int newstate); + #endif /* __LINUX_RTNETLINK_H */ diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 1b93e054c9a3..8ec35194bfcb 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -33,7 +33,7 @@ static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); static LIST_HEAD(lweventlist); static DEFINE_SPINLOCK(lweventlist_lock); -static unsigned char default_operstate(const struct net_device *dev) +static unsigned int default_operstate(const struct net_device *dev) { if (netif_testing(dev)) return IF_OPER_TESTING; @@ -62,16 +62,13 @@ static unsigned char default_operstate(const struct net_device *dev) return IF_OPER_UP; } - static void rfc2863_policy(struct net_device *dev) { - unsigned char operstate = default_operstate(dev); + unsigned int operstate = default_operstate(dev); if (operstate == READ_ONCE(dev->operstate)) return; - write_lock(&dev_base_lock); - switch(dev->link_mode) { case IF_LINK_MODE_TESTING: if (operstate == IF_OPER_UP) @@ -88,8 +85,6 @@ static void rfc2863_policy(struct net_device *dev) } WRITE_ONCE(dev->operstate, operstate); - - write_unlock(&dev_base_lock); } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 43d92de8601c..e484ba44f23b 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -842,9 +842,22 @@ int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, } EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); +void netdev_set_operstate(struct net_device *dev, int newstate) +{ + unsigned int old = READ_ONCE(dev->operstate); + + do { + if (old == newstate) + return; + } while (!try_cmpxchg(&dev->operstate, &old, newstate)); + + netdev_state_change(dev); +} +EXPORT_SYMBOL(netdev_set_operstate); + static void set_operstate(struct net_device *dev, unsigned char transition) { - unsigned char operstate = dev->operstate; + unsigned char operstate = READ_ONCE(dev->operstate); switch (transition) { case IF_OPER_UP: @@ -866,12 +879,7 @@ static void set_operstate(struct net_device *dev, unsigned char transition) break; } - if (READ_ONCE(dev->operstate) != operstate) { - write_lock(&dev_base_lock); - WRITE_ONCE(dev->operstate, operstate); - write_unlock(&dev_base_lock); - netdev_state_change(dev); - } + netdev_set_operstate(dev, operstate); } static unsigned int rtnl_dev_get_flags(const struct net_device *dev) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index be0e43f46556..5ef6d437db72 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -28,29 +28,19 @@ static bool is_slave_up(struct net_device *dev) return dev && is_admin_up(dev) && netif_oper_up(dev); } -static void __hsr_set_operstate(struct net_device *dev, int transition) -{ - write_lock(&dev_base_lock); - if (READ_ONCE(dev->operstate) != transition) { - WRITE_ONCE(dev->operstate, transition); - write_unlock(&dev_base_lock); - netdev_state_change(dev); - } else { - write_unlock(&dev_base_lock); - } -} - static void hsr_set_operstate(struct hsr_port *master, bool has_carrier) { - if (!is_admin_up(master->dev)) { - __hsr_set_operstate(master->dev, IF_OPER_DOWN); + struct net_device *dev = master->dev; + + if (!is_admin_up(dev)) { + netdev_set_operstate(dev, IF_OPER_DOWN); return; } if (has_carrier) - __hsr_set_operstate(master->dev, IF_OPER_UP); + netdev_set_operstate(dev, IF_OPER_UP); else - __hsr_set_operstate(master->dev, IF_OPER_LOWERLAYERDOWN); + netdev_set_operstate(dev, IF_OPER_LOWERLAYERDOWN); } static bool hsr_check_carrier(struct hsr_port *master) From 2dd4d828d648e101aaf19326afcdfee8667cb185 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:43 +0000 Subject: [PATCH 1216/2255] net: remove dev_base_lock from do_setlink() We hold RTNL here, and dev->link_mode readers already are using READ_ONCE(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e484ba44f23b..39e66bf3e238 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2961,11 +2961,9 @@ static int do_setlink(const struct sk_buff *skb, if (tb[IFLA_LINKMODE]) { unsigned char value = nla_get_u8(tb[IFLA_LINKMODE]); - write_lock(&dev_base_lock); if (dev->link_mode ^ value) status |= DO_SETLINK_NOTIFY; WRITE_ONCE(dev->link_mode, value); - write_unlock(&dev_base_lock); } if (tb[IFLA_VFINFO_LIST]) { From e51b962438741f5482c82fb225c1d59136f0fd87 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:44 +0000 Subject: [PATCH 1217/2255] net: remove dev_base_lock from register_netdevice() and friends. RTNL already protects writes to dev->reg_state, we no longer need to hold dev_base_lock to protect the readers. unlist_netdevice() second argument can be removed. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 26f93446b743..02cf9fd68da6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -414,7 +414,7 @@ static void list_netdevice(struct net_device *dev) /* Device list removal * caller must respect a RCU grace period before freeing/reusing dev */ -static void unlist_netdevice(struct net_device *dev, bool lock) +static void unlist_netdevice(struct net_device *dev) { struct netdev_name_node *name_node; struct net *net = dev_net(dev); @@ -427,13 +427,11 @@ static void unlist_netdevice(struct net_device *dev, bool lock) netdev_name_node_del(name_node); /* Unlink dev from the device chain */ - if (lock) - write_lock(&dev_base_lock); + write_lock(&dev_base_lock); list_del_rcu(&dev->dev_list); netdev_name_node_del(dev->name_node); hlist_del_rcu(&dev->index_hlist); - if (lock) - write_unlock(&dev_base_lock); + write_unlock(&dev_base_lock); dev_base_seq_inc(dev_net(dev)); } @@ -10338,9 +10336,9 @@ int register_netdevice(struct net_device *dev) goto err_ifindex_release; ret = netdev_register_kobject(dev); - write_lock(&dev_base_lock); + WRITE_ONCE(dev->reg_state, ret ? NETREG_UNREGISTERED : NETREG_REGISTERED); - write_unlock(&dev_base_lock); + if (ret) goto err_uninit_notify; @@ -10629,9 +10627,7 @@ void netdev_run_todo(void) continue; } - write_lock(&dev_base_lock); WRITE_ONCE(dev->reg_state, NETREG_UNREGISTERED); - write_unlock(&dev_base_lock); linkwatch_sync_dev(dev); } @@ -11138,10 +11134,8 @@ void unregister_netdevice_many_notify(struct list_head *head, list_for_each_entry(dev, head, unreg_list) { /* And unlink it from device chain. */ - write_lock(&dev_base_lock); - unlist_netdevice(dev, false); + unlist_netdevice(dev); WRITE_ONCE(dev->reg_state, NETREG_UNREGISTERING); - write_unlock(&dev_base_lock); } flush_all_backlogs(); @@ -11323,7 +11317,7 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net, dev_close(dev); /* And unlink it from device chain */ - unlist_netdevice(dev, true); + unlist_netdevice(dev); synchronize_net(); From 1b3ef46cb7f2618cc0b507393220a69810f6da12 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Feb 2024 06:32:45 +0000 Subject: [PATCH 1218/2255] net: remove dev_base_lock dev_base_lock is not needed anymore, all remaining users also hold RTNL. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 -- net/core/dev.c | 39 ++++----------------------------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 697370706a82..c541550b0e6e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3077,8 +3077,6 @@ int call_netdevice_notifiers(unsigned long val, struct net_device *dev); int call_netdevice_notifiers_info(unsigned long val, struct netdev_notifier_info *info); -extern rwlock_t dev_base_lock; /* Device list lock */ - #define for_each_netdev(net, d) \ list_for_each_entry(d, &(net)->dev_base_head, dev_list) #define for_each_netdev_reverse(net, d) \ diff --git a/net/core/dev.c b/net/core/dev.c index 02cf9fd68da6..d8dd293a7a27 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -168,28 +168,6 @@ static int call_netdevice_notifiers_extack(unsigned long val, struct net_device *dev, struct netlink_ext_ack *extack); -/* - * The @dev_base_head list is protected by @dev_base_lock and the rtnl - * semaphore. - * - * Pure readers hold dev_base_lock for reading, or rcu_read_lock() - * - * Writers must hold the rtnl semaphore while they loop through the - * dev_base_head list, and hold dev_base_lock for writing when they do the - * actual updates. This allows pure readers to access the list even - * while a writer is preparing to update it. - * - * To put it another way, dev_base_lock is held for writing only to - * protect against pure readers; the rtnl semaphore provides the - * protection against other writers. - * - * See, for example usages, register_netdevice() and - * unregister_netdevice(), which must be called with the rtnl - * semaphore held. - */ -DEFINE_RWLOCK(dev_base_lock); -EXPORT_SYMBOL(dev_base_lock); - static DEFINE_MUTEX(ifalias_mutex); /* protects napi_hash addition/deletion and napi_gen_id */ @@ -395,12 +373,10 @@ static void list_netdevice(struct net_device *dev) ASSERT_RTNL(); - write_lock(&dev_base_lock); list_add_tail_rcu(&dev->dev_list, &net->dev_base_head); netdev_name_node_add(net, dev->name_node); hlist_add_head_rcu(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); - write_unlock(&dev_base_lock); netdev_for_each_altname(dev, name_node) netdev_name_node_add(net, name_node); @@ -427,11 +403,9 @@ static void unlist_netdevice(struct net_device *dev) netdev_name_node_del(name_node); /* Unlink dev from the device chain */ - write_lock(&dev_base_lock); list_del_rcu(&dev->dev_list); netdev_name_node_del(dev->name_node); hlist_del_rcu(&dev->index_hlist); - write_unlock(&dev_base_lock); dev_base_seq_inc(dev_net(dev)); } @@ -752,9 +726,9 @@ EXPORT_SYMBOL_GPL(dev_fill_forward_path); * @net: the applicable net namespace * @name: name to find * - * Find an interface by name. Must be called under RTNL semaphore - * or @dev_base_lock. If the name is found a pointer to the device - * is returned. If the name is not found then %NULL is returned. The + * Find an interface by name. Must be called under RTNL semaphore. + * If the name is found a pointer to the device is returned. + * If the name is not found then %NULL is returned. The * reference counters are not incremented so the caller must be * careful with locks. */ @@ -835,8 +809,7 @@ EXPORT_SYMBOL(netdev_get_by_name); * Search for an interface by index. Returns %NULL if the device * is not found or a pointer to the device. The device has not * had its reference counter increased so the caller must be careful - * about locking. The caller must hold either the RTNL semaphore - * or @dev_base_lock. + * about locking. The caller must hold the RTNL semaphore. */ struct net_device *__dev_get_by_index(struct net *net, int ifindex) @@ -1241,15 +1214,11 @@ rollback: netdev_adjacent_rename_links(dev, oldname); - write_lock(&dev_base_lock); netdev_name_node_del(dev->name_node); - write_unlock(&dev_base_lock); synchronize_net(); - write_lock(&dev_base_lock); netdev_name_node_add(net, dev->name_node); - write_unlock(&dev_base_lock); ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); ret = notifier_to_errno(ret); From ed1d7dac08c532a23dd1da62451b40dbe1305dbd Mon Sep 17 00:00:00 2001 From: Catalin Popescu Date: Tue, 13 Feb 2024 09:07:04 +0100 Subject: [PATCH 1219/2255] dt-bindings: net: dp83826: support TX data voltage tuning Add properties ti,cfg-dac-minus-one-bp/ti,cfg-dac-plus-one-bp to support voltage tuning of logical levels -1/+1 of the MLT-3 encoded TX data. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Catalin Popescu Signed-off-by: David S. Miller --- .../devicetree/bindings/net/ti,dp83822.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/devicetree/bindings/net/ti,dp83822.yaml b/Documentation/devicetree/bindings/net/ti,dp83822.yaml index db74474207ed..8f4350be689c 100644 --- a/Documentation/devicetree/bindings/net/ti,dp83822.yaml +++ b/Documentation/devicetree/bindings/net/ti,dp83822.yaml @@ -62,6 +62,24 @@ properties: for the PHY. The internal delay for the PHY is fixed to 3.5ns relative to transmit data. + ti,cfg-dac-minus-one-bp: + description: | + DP83826 PHY only. + Sets the voltage ratio (with respect to the nominal value) + of the logical level -1 for the MLT-3 encoded TX data. + enum: [5000, 5625, 6250, 6875, 7500, 8125, 8750, 9375, 10000, + 10625, 11250, 11875, 12500, 13125, 13750, 14375, 15000] + default: 10000 + + ti,cfg-dac-plus-one-bp: + description: | + DP83826 PHY only. + Sets the voltage ratio (with respect to the nominal value) + of the logical level +1 for the MLT-3 encoded TX data. + enum: [5000, 5625, 6250, 6875, 7500, 8125, 8750, 9375, 10000, + 10625, 11250, 11875, 12500, 13125, 13750, 14375, 15000] + default: 10000 + required: - reg From d1d77120bc2867b3e449e07ee656a26b2fb03d1e Mon Sep 17 00:00:00 2001 From: Catalin Popescu Date: Tue, 13 Feb 2024 09:07:05 +0100 Subject: [PATCH 1220/2255] net: phy: dp83826: support TX data voltage tuning DP83826 offers the possibility to tune the voltage of logical levels of the MLT-3 encoded TX data. This is useful when there is a voltage drop in between the PHY and the connector and we want to increase the voltage levels to compensate for that drop. Prior to PHY configuration, the driver SW resets the PHY which has the same effect as the HW reset pin according to the datasheet. Hence, there's no need to force update the VOD_CFG registers to make sure they hold their reset values. VOD_CFG registers need to be updated only if the DT has been configured with values other than the reset ones. Reviewed-by: Andrew Lunn Signed-off-by: Catalin Popescu Signed-off-by: David S. Miller --- drivers/net/phy/dp83822.c | 130 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index b7cb71817780..30f2616ab1c2 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -12,6 +12,7 @@ #include #include #include +#include #define DP83822_PHY_ID 0x2000a240 #define DP83825S_PHY_ID 0x2000a140 @@ -34,6 +35,10 @@ #define MII_DP83822_GENCFG 0x465 #define MII_DP83822_SOR1 0x467 +/* DP83826 specific registers */ +#define MII_DP83826_VOD_CFG1 0x30b +#define MII_DP83826_VOD_CFG2 0x30c + /* GENCFG */ #define DP83822_SIG_DET_LOW BIT(0) @@ -110,6 +115,19 @@ #define DP83822_RX_ER_STR_MASK GENMASK(9, 8) #define DP83822_RX_ER_SHIFT 8 +/* DP83826: VOD_CFG1 & VOD_CFG2 */ +#define DP83826_VOD_CFG1_MINUS_MDIX_MASK GENMASK(13, 12) +#define DP83826_VOD_CFG1_MINUS_MDI_MASK GENMASK(11, 6) +#define DP83826_VOD_CFG2_MINUS_MDIX_MASK GENMASK(15, 12) +#define DP83826_VOD_CFG2_PLUS_MDIX_MASK GENMASK(11, 6) +#define DP83826_VOD_CFG2_PLUS_MDI_MASK GENMASK(5, 0) +#define DP83826_CFG_DAC_MINUS_MDIX_5_TO_4 GENMASK(5, 4) +#define DP83826_CFG_DAC_MINUS_MDIX_3_TO_0 GENMASK(3, 0) +#define DP83826_CFG_DAC_PERCENT_PER_STEP 625 +#define DP83826_CFG_DAC_PERCENT_DEFAULT 10000 +#define DP83826_CFG_DAC_MINUS_DEFAULT 0x30 +#define DP83826_CFG_DAC_PLUS_DEFAULT 0x10 + #define MII_DP83822_FIBER_ADVERTISE (ADVERTISED_TP | ADVERTISED_MII | \ ADVERTISED_FIBRE | \ ADVERTISED_Pause | ADVERTISED_Asym_Pause) @@ -118,6 +136,8 @@ struct dp83822_private { bool fx_signal_det_low; int fx_enabled; u16 fx_sd_enable; + u8 cfg_dac_minus; + u8 cfg_dac_plus; }; static int dp83822_set_wol(struct phy_device *phydev, @@ -233,7 +253,7 @@ static int dp83822_config_intr(struct phy_device *phydev) DP83822_ENERGY_DET_INT_EN | DP83822_LINK_QUAL_INT_EN); - /* Private data pointer is NULL on DP83825/26 */ + /* Private data pointer is NULL on DP83825 */ if (!dp83822 || !dp83822->fx_enabled) misr_status |= DP83822_ANEG_COMPLETE_INT_EN | DP83822_DUP_MODE_CHANGE_INT_EN | @@ -254,7 +274,7 @@ static int dp83822_config_intr(struct phy_device *phydev) DP83822_PAGE_RX_INT_EN | DP83822_EEE_ERROR_CHANGE_INT_EN); - /* Private data pointer is NULL on DP83825/26 */ + /* Private data pointer is NULL on DP83825 */ if (!dp83822 || !dp83822->fx_enabled) misr_status |= DP83822_ANEG_ERR_INT_EN | DP83822_WOL_PKT_INT_EN; @@ -474,6 +494,43 @@ static int dp83822_config_init(struct phy_device *phydev) return dp8382x_disable_wol(phydev); } +static int dp83826_config_init(struct phy_device *phydev) +{ + struct dp83822_private *dp83822 = phydev->priv; + u16 val, mask; + int ret; + + if (dp83822->cfg_dac_minus != DP83826_CFG_DAC_MINUS_DEFAULT) { + val = FIELD_PREP(DP83826_VOD_CFG1_MINUS_MDI_MASK, dp83822->cfg_dac_minus) | + FIELD_PREP(DP83826_VOD_CFG1_MINUS_MDIX_MASK, + FIELD_GET(DP83826_CFG_DAC_MINUS_MDIX_5_TO_4, + dp83822->cfg_dac_minus)); + mask = DP83826_VOD_CFG1_MINUS_MDIX_MASK | DP83826_VOD_CFG1_MINUS_MDI_MASK; + ret = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83826_VOD_CFG1, mask, val); + if (ret) + return ret; + + val = FIELD_PREP(DP83826_VOD_CFG2_MINUS_MDIX_MASK, + FIELD_GET(DP83826_CFG_DAC_MINUS_MDIX_3_TO_0, + dp83822->cfg_dac_minus)); + mask = DP83826_VOD_CFG2_MINUS_MDIX_MASK; + ret = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83826_VOD_CFG2, mask, val); + if (ret) + return ret; + } + + if (dp83822->cfg_dac_plus != DP83826_CFG_DAC_PLUS_DEFAULT) { + val = FIELD_PREP(DP83826_VOD_CFG2_PLUS_MDIX_MASK, dp83822->cfg_dac_plus) | + FIELD_PREP(DP83826_VOD_CFG2_PLUS_MDI_MASK, dp83822->cfg_dac_plus); + mask = DP83826_VOD_CFG2_PLUS_MDIX_MASK | DP83826_VOD_CFG2_PLUS_MDI_MASK; + ret = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83826_VOD_CFG2, mask, val); + if (ret) + return ret; + } + + return 0; +} + static int dp8382x_config_init(struct phy_device *phydev) { return dp8382x_disable_wol(phydev); @@ -509,11 +566,44 @@ static int dp83822_of_init(struct phy_device *phydev) return 0; } + +static int dp83826_to_dac_minus_one_regval(int percent) +{ + int tmp = DP83826_CFG_DAC_PERCENT_DEFAULT - percent; + + return tmp / DP83826_CFG_DAC_PERCENT_PER_STEP; +} + +static int dp83826_to_dac_plus_one_regval(int percent) +{ + int tmp = percent - DP83826_CFG_DAC_PERCENT_DEFAULT; + + return tmp / DP83826_CFG_DAC_PERCENT_PER_STEP; +} + +static void dp83826_of_init(struct phy_device *phydev) +{ + struct dp83822_private *dp83822 = phydev->priv; + struct device *dev = &phydev->mdio.dev; + u32 val; + + dp83822->cfg_dac_minus = DP83826_CFG_DAC_MINUS_DEFAULT; + if (!device_property_read_u32(dev, "ti,cfg-dac-minus-one-bp", &val)) + dp83822->cfg_dac_minus += dp83826_to_dac_minus_one_regval(val); + + dp83822->cfg_dac_plus = DP83826_CFG_DAC_PLUS_DEFAULT; + if (!device_property_read_u32(dev, "ti,cfg-dac-plus-one-bp", &val)) + dp83822->cfg_dac_plus += dp83826_to_dac_plus_one_regval(val); +} #else static int dp83822_of_init(struct phy_device *phydev) { return 0; } + +static void dp83826_of_init(struct phy_device *phydev) +{ +} #endif /* CONFIG_OF_MDIO */ static int dp83822_read_straps(struct phy_device *phydev) @@ -567,6 +657,22 @@ static int dp83822_probe(struct phy_device *phydev) return 0; } +static int dp83826_probe(struct phy_device *phydev) +{ + struct dp83822_private *dp83822; + + dp83822 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83822), + GFP_KERNEL); + if (!dp83822) + return -ENOMEM; + + phydev->priv = dp83822; + + dp83826_of_init(phydev); + + return 0; +} + static int dp83822_suspend(struct phy_device *phydev) { int value; @@ -610,6 +716,22 @@ static int dp83822_resume(struct phy_device *phydev) .resume = dp83822_resume, \ } +#define DP83826_PHY_DRIVER(_id, _name) \ + { \ + PHY_ID_MATCH_MODEL(_id), \ + .name = (_name), \ + /* PHY_BASIC_FEATURES */ \ + .probe = dp83826_probe, \ + .soft_reset = dp83822_phy_reset, \ + .config_init = dp83826_config_init, \ + .get_wol = dp83822_get_wol, \ + .set_wol = dp83822_set_wol, \ + .config_intr = dp83822_config_intr, \ + .handle_interrupt = dp83822_handle_interrupt, \ + .suspend = dp83822_suspend, \ + .resume = dp83822_resume, \ + } + #define DP8382X_PHY_DRIVER(_id, _name) \ { \ PHY_ID_MATCH_MODEL(_id), \ @@ -628,8 +750,8 @@ static int dp83822_resume(struct phy_device *phydev) static struct phy_driver dp83822_driver[] = { DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"), DP8382X_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"), - DP8382X_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"), - DP8382X_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"), + DP83826_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"), + DP83826_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"), DP8382X_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"), DP8382X_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"), DP8382X_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"), From b00cf4f62969eb7067bc44851de9519953a7ae01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= Date: Mon, 13 Nov 2023 14:14:52 +0100 Subject: [PATCH 1221/2255] dt-bindings: can: tcan4x5x: Document the wakeup-source flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let it be known that the tcan4x5x device can now be configured to wake the host from suspend when a can frame is received. Signed-off-by: Martin Hundebøll Acked-by: Conor Dooley [mkl: make first the first patch] Signed-off-by: Marc Kleine-Budde --- Documentation/devicetree/bindings/net/can/tcan4x5x.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/can/tcan4x5x.txt b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt index 170e23f0610d..20c0572c9853 100644 --- a/Documentation/devicetree/bindings/net/can/tcan4x5x.txt +++ b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt @@ -28,6 +28,8 @@ Optional properties: available with tcan4552/4553. - device-wake-gpios: Wake up GPIO to wake up the TCAN device. Not available with tcan4552/4553. + - wakeup-source: Leave the chip running when suspended, and configure + the RX interrupt to wake up the device. Example: tcan4x5x: tcan4x5x@0 { @@ -42,4 +44,5 @@ tcan4x5x: tcan4x5x@0 { device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>; + wakeup-source; }; From 4a94d7e31cf5ab33f43ed381c35aabb0d1f2748d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= Date: Mon, 13 Nov 2023 14:14:50 +0100 Subject: [PATCH 1222/2255] can: m_can: allow keeping the transceiver running in suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a flag to the device class structure that leaves the chip in a running state with rx interrupt enabled, so that an m_can device driver can configure and use the interrupt as a wakeup source. Signed-off-by: Martin Hundebøll Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 22 +++++++++++++++++----- drivers/net/can/m_can/m_can.h | 1 + drivers/net/can/m_can/m_can_pci.c | 1 + drivers/net/can/m_can/m_can_platform.c | 1 + drivers/net/can/m_can/tcan4x5x-core.c | 1 + 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 290880ce5329..14b231c4d7ec 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -2382,7 +2382,15 @@ int m_can_class_suspend(struct device *dev) if (netif_running(ndev)) { netif_stop_queue(ndev); netif_device_detach(ndev); - m_can_stop(ndev); + + /* leave the chip running with rx interrupt enabled if it is + * used as a wake-up source. + */ + if (cdev->pm_wake_source) + m_can_write(cdev, M_CAN_IE, IR_RF0N); + else + m_can_stop(ndev); + m_can_clk_stop(cdev); } @@ -2409,11 +2417,15 @@ int m_can_class_resume(struct device *dev) ret = m_can_clk_start(cdev); if (ret) return ret; - ret = m_can_start(ndev); - if (ret) { - m_can_clk_stop(cdev); - return ret; + if (cdev->pm_wake_source) { + m_can_write(cdev, M_CAN_IE, cdev->active_interrupts); + } else { + ret = m_can_start(ndev); + if (ret) { + m_can_clk_stop(cdev); + return ret; + } } netif_device_attach(ndev); diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 2986c4ce0b2f..3a9edc292593 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -97,6 +97,7 @@ struct m_can_classdev { u32 irqstatus; int pm_clock_support; + int pm_wake_source; int is_peripheral; // Cached M_CAN_IE register content diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c index f2219aa2824b..45400de4163d 100644 --- a/drivers/net/can/m_can/m_can_pci.c +++ b/drivers/net/can/m_can/m_can_pci.c @@ -125,6 +125,7 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) mcan_class->dev = &pci->dev; mcan_class->net->irq = pci_irq_vector(pci, 0); mcan_class->pm_clock_support = 1; + mcan_class->pm_wake_source = 0; mcan_class->can.clock.freq = id->driver_data; mcan_class->ops = &m_can_pci_ops; diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c index ab1b8211a61c..df0367124b4c 100644 --- a/drivers/net/can/m_can/m_can_platform.c +++ b/drivers/net/can/m_can/m_can_platform.c @@ -139,6 +139,7 @@ static int m_can_plat_probe(struct platform_device *pdev) mcan_class->net->irq = irq; mcan_class->pm_clock_support = 1; + mcan_class->pm_wake_source = 0; mcan_class->can.clock.freq = clk_get_rate(mcan_class->cclk); mcan_class->dev = &pdev->dev; mcan_class->transceiver = transceiver; diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c index ae8c42f5debd..71a9e1bec008 100644 --- a/drivers/net/can/m_can/tcan4x5x-core.c +++ b/drivers/net/can/m_can/tcan4x5x-core.c @@ -411,6 +411,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi) priv->spi = spi; mcan_class->pm_clock_support = 0; + mcan_class->pm_wake_source = 0; mcan_class->can.clock.freq = freq; mcan_class->dev = &spi->dev; mcan_class->ops = &tcan4x5x_ops; From b6b640c04446887486edd76b215f81668c7e6005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= Date: Mon, 13 Nov 2023 14:14:51 +0100 Subject: [PATCH 1223/2255] can: tcan4x5x: support resuming from rx interrupt signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the "wakeup-source" device tree property, so the chip is left running when suspending, and its rx interrupt is used as a wakeup source to resume operation. Signed-off-by: Martin Hundebøll Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-core.c | 34 +++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c index 71a9e1bec008..a42600dac70d 100644 --- a/drivers/net/can/m_can/tcan4x5x-core.c +++ b/drivers/net/can/m_can/tcan4x5x-core.c @@ -411,7 +411,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi) priv->spi = spi; mcan_class->pm_clock_support = 0; - mcan_class->pm_wake_source = 0; + mcan_class->pm_wake_source = device_property_read_bool(&spi->dev, "wakeup-source"); mcan_class->can.clock.freq = freq; mcan_class->dev = &spi->dev; mcan_class->ops = &tcan4x5x_ops; @@ -460,6 +460,9 @@ static int tcan4x5x_can_probe(struct spi_device *spi) goto out_power; } + if (mcan_class->pm_wake_source) + device_init_wakeup(&spi->dev, true); + ret = m_can_class_register(mcan_class); if (ret) { dev_err(&spi->dev, "Failed registering m_can device %pe\n", @@ -488,6 +491,29 @@ static void tcan4x5x_can_remove(struct spi_device *spi) m_can_class_free_dev(priv->cdev.net); } +static int __maybe_unused tcan4x5x_suspend(struct device *dev) +{ + struct m_can_classdev *cdev = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + + if (cdev->pm_wake_source) + enable_irq_wake(spi->irq); + + return m_can_class_suspend(dev); +} + +static int __maybe_unused tcan4x5x_resume(struct device *dev) +{ + struct m_can_classdev *cdev = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + int ret = m_can_class_resume(dev); + + if (cdev->pm_wake_source) + disable_irq_wake(spi->irq); + + return ret; +} + static const struct of_device_id tcan4x5x_of_match[] = { { .compatible = "ti,tcan4x5x", @@ -506,11 +532,15 @@ static const struct spi_device_id tcan4x5x_id_table[] = { }; MODULE_DEVICE_TABLE(spi, tcan4x5x_id_table); +static const struct dev_pm_ops tcan4x5x_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tcan4x5x_suspend, tcan4x5x_resume) +}; + static struct spi_driver tcan4x5x_can_driver = { .driver = { .name = KBUILD_MODNAME, .of_match_table = tcan4x5x_of_match, - .pm = NULL, + .pm = &tcan4x5x_pm_ops, }, .id_table = tcan4x5x_id_table, .probe = tcan4x5x_can_probe, From 1159d27852207e8efb8d6ef2dae5aaa87ec4e225 Mon Sep 17 00:00:00 2001 From: Matt Bobrowski Date: Wed, 14 Feb 2024 09:14:23 +0000 Subject: [PATCH 1224/2255] libbpf: Make remark about zero-initializing bpf_*_info structs In some situations, if you fail to zero-initialize the bpf_{prog,map,btf,link}_info structs supplied to the set of LIBBPF helpers bpf_{prog,map,btf,link}_get_info_by_fd(), you can expect the helper to return an error. This can possibly leave people in a situation where they're scratching their heads for an unnnecessary amount of time. Make an explicit remark about the requirement of zero-initializing the supplied bpf_{prog,map,btf,link}_info structs for the respective LIBBPF helpers. Internally, LIBBPF helpers bpf_{prog,map,btf,link}_get_info_by_fd() call into bpf_obj_get_info_by_fd() where the bpf(2) BPF_OBJ_GET_INFO_BY_FD command is used. This specific command is effectively backed by restrictions enforced by the bpf_check_uarg_tail_zero() helper. This function ensures that if the size of the supplied bpf_{prog,map,btf,link}_info structs are larger than what the kernel can handle, trailing bits are zeroed. This can be a problem when compiling against UAPI headers that don't necessarily match the sizes of the same underlying types known to the kernel. Signed-off-by: Matt Bobrowski Signed-off-by: Andrii Nakryiko Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/ZcyEb8x4VbhieWsL@google.com --- tools/lib/bpf/bpf.h | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index f866e98b2436..ab2570d28aec 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -500,7 +500,10 @@ LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len); * program corresponding to *prog_fd*. * * Populates up to *info_len* bytes of *info* and updates *info_len* with the - * actual number of bytes written to *info*. + * actual number of bytes written to *info*. Note that *info* should be + * zero-initialized or initialized as expected by the requested *info* + * type. Failing to (zero-)initialize *info* under certain circumstances can + * result in this helper returning an error. * * @param prog_fd BPF program file descriptor * @param info pointer to **struct bpf_prog_info** that will be populated with @@ -517,7 +520,10 @@ LIBBPF_API int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info, * map corresponding to *map_fd*. * * Populates up to *info_len* bytes of *info* and updates *info_len* with the - * actual number of bytes written to *info*. + * actual number of bytes written to *info*. Note that *info* should be + * zero-initialized or initialized as expected by the requested *info* + * type. Failing to (zero-)initialize *info* under certain circumstances can + * result in this helper returning an error. * * @param map_fd BPF map file descriptor * @param info pointer to **struct bpf_map_info** that will be populated with @@ -530,11 +536,14 @@ LIBBPF_API int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info, LIBBPF_API int bpf_map_get_info_by_fd(int map_fd, struct bpf_map_info *info, __u32 *info_len); /** - * @brief **bpf_btf_get_info_by_fd()** obtains information about the + * @brief **bpf_btf_get_info_by_fd()** obtains information about the * BTF object corresponding to *btf_fd*. * * Populates up to *info_len* bytes of *info* and updates *info_len* with the - * actual number of bytes written to *info*. + * actual number of bytes written to *info*. Note that *info* should be + * zero-initialized or initialized as expected by the requested *info* + * type. Failing to (zero-)initialize *info* under certain circumstances can + * result in this helper returning an error. * * @param btf_fd BTF object file descriptor * @param info pointer to **struct bpf_btf_info** that will be populated with @@ -551,7 +560,10 @@ LIBBPF_API int bpf_btf_get_info_by_fd(int btf_fd, struct bpf_btf_info *info, __u * link corresponding to *link_fd*. * * Populates up to *info_len* bytes of *info* and updates *info_len* with the - * actual number of bytes written to *info*. + * actual number of bytes written to *info*. Note that *info* should be + * zero-initialized or initialized as expected by the requested *info* + * type. Failing to (zero-)initialize *info* under certain circumstances can + * result in this helper returning an error. * * @param link_fd BPF link file descriptor * @param info pointer to **struct bpf_link_info** that will be populated with From a4561f5afef8a8ff25a2cfd46d587f65869494f2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 13 Feb 2024 16:23:11 -0800 Subject: [PATCH 1225/2255] bpf: Use O(log(N)) binary search to find line info record Real-world BPF applications keep growing in size. Medium-sized production application can easily have 50K+ verified instructions, and its line info section in .BTF.ext has more than 3K entries. When verifier emits log with log_level>=1, it annotates assembly code with matched original C source code. Currently it uses linear search over line info records to find a match. As complexity of BPF applications grows, this O(K * N) approach scales poorly. So, let's instead of linear O(N) search for line info record use faster equivalent O(log(N)) binary search algorithm. It's not a plain binary search, as we don't look for exact match. It's an upper bound search variant, looking for rightmost line info record that starts at or before given insn_off. Some unscientific measurements were done before and after this change. They were done in VM and fluctuate a bit, but overall the speed up is undeniable. BASELINE ======== File Program Duration (us) Insns -------------------------------- ---------------- ------------- ------ katran.bpf.o balancer_ingress 2497130 343552 pyperf600.bpf.linked3.o on_event 12389611 627288 strobelight_pyperf_libbpf.o on_py_event 387399 52445 -------------------------------- ---------------- ------------- ------ BINARY SEARCH ============= File Program Duration (us) Insns -------------------------------- ---------------- ------------- ------ katran.bpf.o balancer_ingress 2339312 343552 pyperf600.bpf.linked3.o on_event 5602203 627288 strobelight_pyperf_libbpf.o on_py_event 294761 52445 -------------------------------- ---------------- ------------- ------ While Katran's speed up is pretty modest (about 105ms, or 6%), for production pyperf BPF program (on_py_event) it's much greater already, going from 387ms down to 295ms (23% improvement). Looking at BPF selftests's biggest pyperf example, we can see even more dramatic improvement, shaving more than 50% of time, going from 12.3s down to 5.6s. Different amount of improvement is the function of overall amount of BPF assembly instructions in .bpf.o files (which contributes to how much line info records there will be and thus, on average, how much time linear search will take), among other things: $ llvm-objdump -d katran.bpf.o | wc -l 3863 $ llvm-objdump -d strobelight_pyperf_libbpf.o | wc -l 6997 $ llvm-objdump -d pyperf600.bpf.linked3.o | wc -l 87854 Granted, this only applies to debugging cases (e.g., using veristat, or failing verification in production), but seems worth doing to improve overall developer experience anyways. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/20240214002311.2197116-1-andrii@kernel.org --- kernel/bpf/log.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index cc789efc7f43..995e3b82e17b 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -334,7 +334,8 @@ find_linfo(const struct bpf_verifier_env *env, u32 insn_off) { const struct bpf_line_info *linfo; const struct bpf_prog *prog; - u32 i, nr_linfo; + u32 nr_linfo; + int l, r, m; prog = env->prog; nr_linfo = prog->aux->nr_linfo; @@ -343,11 +344,30 @@ find_linfo(const struct bpf_verifier_env *env, u32 insn_off) return NULL; linfo = prog->aux->linfo; - for (i = 1; i < nr_linfo; i++) - if (insn_off < linfo[i].insn_off) - break; + /* Loop invariant: linfo[l].insn_off <= insns_off. + * linfo[0].insn_off == 0 which always satisfies above condition. + * Binary search is searching for rightmost linfo entry that satisfies + * the above invariant, giving us the desired record that covers given + * instruction offset. + */ + l = 0; + r = nr_linfo - 1; + while (l < r) { + /* (r - l + 1) / 2 means we break a tie to the right, so if: + * l=1, r=2, linfo[l].insn_off <= insn_off, linfo[r].insn_off > insn_off, + * then m=2, we see that linfo[m].insn_off > insn_off, and so + * r becomes 1 and we exit the loop with correct l==1. + * If the tie was broken to the left, m=1 would end us up in + * an endless loop where l and m stay at 1 and r stays at 2. + */ + m = l + (r - l + 1) / 2; + if (linfo[m].insn_off <= insn_off) + l = m; + else + r = m - 1; + } - return &linfo[i - 1]; + return &linfo[l]; } static const char *ltrim(const char *s) From 35c1bbd93c4e6969b3ac238b48a8bdff3e223ed8 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:06 +0200 Subject: [PATCH 1226/2255] 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 +- .../wireless/intel/iwlwifi/mvm/time-event.c | 89 ++++++++----------- 2 files changed, 38 insertions(+), 55 deletions(-) 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, From 77770189921e38597a42744c7032b8222538cdf3 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:08 +0200 Subject: [PATCH 1227/2255] 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 --- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) 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; } From 414532d8aa8915d9aebd01c6b5aa54bdfd98da71 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Feb 2024 20:08:43 +0100 Subject: [PATCH 1228/2255] wifi: cfg80211: use IEEE80211_MAX_MESH_ID_LEN appropriately Even if that's the same as IEEE80211_MAX_SSID_LEN, we really should just use IEEE80211_MAX_MESH_ID_LEN for mesh, rather than having the BUILD_BUG_ON()s. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 +- net/wireless/nl80211.c | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 93e9abb7fc3d..57c2298af35b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6223,7 +6223,7 @@ struct wireless_dev { int beacon_interval; struct cfg80211_chan_def preset_chandef; struct cfg80211_chan_def chandef; - u8 id[IEEE80211_MAX_SSID_LEN]; + u8 id[IEEE80211_MAX_MESH_ID_LEN]; u8 id_len, id_up_len; } mesh; struct { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5f18cbf7cc3d..dd9a092b6bab 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4205,8 +4205,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (netif_running(dev)) return -EBUSY; - BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != - IEEE80211_MAX_MESH_ID_LEN); wdev->u.mesh.id_up_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); memcpy(wdev->u.mesh.id, @@ -4312,8 +4310,6 @@ static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) case NL80211_IFTYPE_MESH_POINT: if (!info->attrs[NL80211_ATTR_MESH_ID]) break; - BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != - IEEE80211_MAX_MESH_ID_LEN); wdev->u.mesh.id_up_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); memcpy(wdev->u.mesh.id, From 3be0d950b62852a693182cb678948f481de02825 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 12 Feb 2024 12:49:34 +0100 Subject: [PATCH 1229/2255] net: phy: qca807x: move interface mode check to .config_init_once Currently, we are checking whether the PHY package mode matches the individual PHY interface modes at PHY package probe time, but at that time we only know the PHY package mode and not the individual PHY interface modes as of_get_phy_mode() that populates it will only get called once the netdev to which PHY-s are attached to is being probed and thus this check will always fail and return -EINVAL. So, lets move this check to .config_init_once as at that point individual PHY interface modes should be populated. Fixes: d1cb613efbd3 ("net: phy: qcom: add support for QCA807x PHY Family") Signed-off-by: Robert Marko Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240212115043.1725918-1-robimarko@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/phy/qcom/qca807x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/qcom/qca807x.c b/drivers/net/phy/qcom/qca807x.c index 01815f947060..780c28e2e4aa 100644 --- a/drivers/net/phy/qcom/qca807x.c +++ b/drivers/net/phy/qcom/qca807x.c @@ -562,6 +562,11 @@ static int qca807x_phy_package_config_init_once(struct phy_device *phydev) struct qca807x_shared_priv *priv = shared->priv; int val, ret; + /* Make sure PHY follow PHY package mode if enforced */ + if (priv->package_mode != PHY_INTERFACE_MODE_NA && + phydev->interface != priv->package_mode) + return -EINVAL; + phy_lock_mdio_bus(phydev); /* Set correct PHY package mode */ @@ -718,11 +723,6 @@ static int qca807x_probe(struct phy_device *phydev) shared = phydev->shared; shared_priv = shared->priv; - /* Make sure PHY follow PHY package mode if enforced */ - if (shared_priv->package_mode != PHY_INTERFACE_MODE_NA && - phydev->interface != shared_priv->package_mode) - return -EINVAL; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; From cb5942b77c05d54310a0420cac12935e9b6aa21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Mon, 12 Feb 2024 13:57:37 +0100 Subject: [PATCH 1230/2255] 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 --- .../net/wireless/microchip/wilc1000/netdev.c | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) 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) { - 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) { + list_for_each_entry_safe(vif, vif_tmp, &wilc->vif_list, list) { 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); - + list_del_rcu(&vif->list); wilc->vif_num--; mutex_unlock(&wilc->vif_mutex); synchronize_srcu(&wilc->srcu); - ifc_cnt++; + if (vif->ndev) + unregister_netdev(vif->ndev); } + wilc_wfi_deinit_mon_interface(wilc, false); + destroy_workqueue(wilc->hif_workqueue); + wilc_wlan_cfg_deinit(wilc); wlan_deinit_locks(wilc); wiphy_unregister(wilc->wiphy); From dd2f633eafa4ce5b9cb2ee09bf5d709535a02e79 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Mon, 12 Feb 2024 20:22:30 +0000 Subject: [PATCH 1231/2255] 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 +++++++++++++++---- .../net/wireless/microchip/wilc1000/wlan.c | 5 -- .../net/wireless/microchip/wilc1000/wlan.h | 5 ++ 3 files changed, 59 insertions(+), 20 deletions(-) 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); From 6ca3b88c320b5933b4371f940f70aba382e12ecf Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:10 +0800 Subject: [PATCH 1232/2255] 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(-) 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 From b8e59e55345878747b6de944e785728fb215b26c Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:11 +0800 Subject: [PATCH 1233/2255] 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(-) 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 { From 9de7829aa6fa78402f4efef60d919b1f8b54bbdb Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:12 +0800 Subject: [PATCH 1234/2255] 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(+) 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) { From f931cce310e0beb2d4b9f2b60b3e3ce69ff87dfb Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:13 +0800 Subject: [PATCH 1235/2255] 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(-) 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; + *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 = 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 { From 441a6014d0243a432a96e23266896d2761116735 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:14 +0800 Subject: [PATCH 1236/2255] 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(-) 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), From 63d94f7496233600186303f1eee000ab2ffc920a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 13 Feb 2024 20:25:56 +0800 Subject: [PATCH 1237/2255] 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(-) 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); } From bcfcbf23a98ca19ba5931914801b5939e0d17bda Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 13 Feb 2024 16:33:02 +0200 Subject: [PATCH 1238/2255] 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(-) 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 From 42ffccd0a36e099dea3d3272c5d62a0454ded1f0 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 13 Feb 2024 16:33:11 +0200 Subject: [PATCH 1239/2255] 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 --- .../wireless/realtek/rtlwifi/rtl8192cu/sw.c | 1 - .../wireless/realtek/rtlwifi/rtl8192cu/trx.c | 77 ++++++++++--------- .../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(-) 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; From f019f4dff2e4cb8704dc608496e3f2829de3e919 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Wed, 14 Feb 2024 10:38:10 +0200 Subject: [PATCH 1240/2255] wifi: ath11k: support 2 station interfaces Add hardware parameter support_dual_stations to indicate whether 2 station interfaces are supported. For chips which support this feature, limit total number of AP interface and mesh point to 1. The max interfaces are 3 for such chips. The chips affected are: QCA6390 hw2.0 WCN6855 hw2.0 WCN6855 hw2.1 Other chips are not affected. For affected chips, remove radar_detect_widths because now num_different_channels is set to 2. radar_detect_widths can be set only when num_different_channels is 1, see mac80211 function wiphy_verify_combinations for details. This means that in affectected chips DFS cannot be enabled in AP mode. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://msgid.link/20230714023801.2621802-2-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 14 +++++-- drivers/net/wireless/ath/ath11k/hw.c | 2 +- drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/mac.c | 56 +++++++++++++++++--------- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 0c6ecbb9a066..3c1ba8fd28f4 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -122,6 +122,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tcl_ring_retry = true, .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, + .support_dual_stations = false, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -205,6 +206,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, + .support_dual_stations = false, }, { .name = "qca6390 hw2.0", @@ -255,7 +257,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 2 + 1, .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), @@ -290,6 +292,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, + .support_dual_stations = true, }, { .name = "qcn9074 hw1.0", @@ -372,6 +375,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, + .support_dual_stations = false, }, { .name = "wcn6855 hw2.0", @@ -422,7 +426,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 2 + 1, .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), @@ -457,6 +461,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, + .support_dual_stations = true, }, { .name = "wcn6855 hw2.1", @@ -505,7 +510,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = false, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 2 + 1, .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), @@ -540,6 +545,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, + .support_dual_stations = true, }, { .name = "wcn6750 hw1.0", @@ -621,6 +627,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE_WCN6750, .smp2p_wow_exit = true, .support_fw_mac_sequence = true, + .support_dual_stations = false, }, { .hw_rev = ATH11K_HW_IPQ5018_HW10, @@ -702,6 +709,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, + .support_dual_stations = false, }, }; diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 77d8f9237680..caa6dc12a790 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -58,7 +58,7 @@ static void ath11k_hw_wcn6855_tx_mesh_enable(struct ath11k_base *ab, static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab, struct target_resource_config *config) { - config->num_vdevs = 4; + config->num_vdevs = ab->hw_params.num_vdevs; config->num_peers = 16; config->num_tids = 32; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 1b070747a5db..14ef4eb48f80 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -226,6 +226,7 @@ struct ath11k_hw_params { u32 tx_ring_size; bool smp2p_wow_exit; bool support_fw_mac_sequence; + bool support_dual_stations; }; struct ath11k_hw_ops { diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7bf5d1068164..7180ce9dbf98 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9843,28 +9843,46 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) return -ENOMEM; } - limits[0].max = 1; - limits[0].types |= BIT(NL80211_IFTYPE_STATION); + if (ab->hw_params.support_dual_stations) { + limits[0].max = 2; + limits[0].types |= BIT(NL80211_IFTYPE_STATION); - limits[1].max = 16; - limits[1].types |= BIT(NL80211_IFTYPE_AP); + limits[1].max = 1; + limits[1].types |= BIT(NL80211_IFTYPE_AP); + if (IS_ENABLED(CONFIG_MAC80211_MESH) && + ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); - if (IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) - limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + combinations[0].limits = limits; + combinations[0].n_limits = 2; + combinations[0].max_interfaces = ab->hw_params.num_vdevs; + combinations[0].num_different_channels = 2; + combinations[0].beacon_int_infra_match = true; + combinations[0].beacon_int_min_gcd = 100; + } else { + limits[0].max = 1; + limits[0].types |= BIT(NL80211_IFTYPE_STATION); - combinations[0].limits = limits; - combinations[0].n_limits = n_limits; - combinations[0].max_interfaces = 16; - combinations[0].num_different_channels = 1; - combinations[0].beacon_int_infra_match = true; - combinations[0].beacon_int_min_gcd = 100; - combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80) | - BIT(NL80211_CHAN_WIDTH_80P80) | - BIT(NL80211_CHAN_WIDTH_160); + limits[1].max = 16; + limits[1].types |= BIT(NL80211_IFTYPE_AP); + + if (IS_ENABLED(CONFIG_MAC80211_MESH) && + ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + + combinations[0].limits = limits; + combinations[0].n_limits = 2; + combinations[0].max_interfaces = 16; + combinations[0].num_different_channels = 1; + combinations[0].beacon_int_infra_match = true; + combinations[0].beacon_int_min_gcd = 100; + combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_80P80) | + BIT(NL80211_CHAN_WIDTH_160); + } ar->hw->wiphy->iface_combinations = combinations; ar->hw->wiphy->n_iface_combinations = 1; From 24395ec117076216c78d0874d9d44f62ba1f9747 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Wed, 14 Feb 2024 10:38:10 +0200 Subject: [PATCH 1241/2255] wifi: ath11k: provide address list if chip supports 2 stations Provide address list to mac80211 so user doesn't need to specify addresses when a second interface is added because the address can be allocated from the list by mac80211. The derived addresses have LAA (Local Administered Address) bit set, and only the first byte is changed. Take the 00:03:7f:xx:xx:xx as example to derive: addresses[0] is unchanged, it's still 00:03:7f:xx:xx:xx, addresses[1] is 02:03:7f:xx:xx:xx, addresses[2] is 12:03:7f:xx:xx:xx, addresses[3] is 22:03:7f:xx:xx:xx, addresses[4] is 32:03:7f:xx:xx:xx. However as only 3 addresses are reported now, so addresses[3] and addresses[4] aren't actually derived. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://msgid.link/20230714023801.2621802-3-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7180ce9dbf98..7f18a6a68b81 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9824,6 +9824,33 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, return 0; } +static void ath11k_mac_setup_mac_address_list(struct ath11k *ar) +{ + struct mac_address *addresses; + u16 n_addresses; + int i; + + if (!ar->ab->hw_params.support_dual_stations) + return; + + n_addresses = ar->ab->hw_params.num_vdevs; + addresses = kcalloc(n_addresses, sizeof(*addresses), GFP_KERNEL); + if (!addresses) + return; + + memcpy(addresses[0].addr, ar->mac_addr, ETH_ALEN); + for (i = 1; i < n_addresses; i++) { + memcpy(addresses[i].addr, ar->mac_addr, ETH_ALEN); + /* set Local Administered Address bit */ + addresses[i].addr[0] |= 0x2; + + addresses[i].addr[0] += (i - 1) << 4; + } + + ar->hw->wiphy->addresses = addresses; + ar->hw->wiphy->n_addresses = n_addresses; +} + static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; @@ -9947,6 +9974,8 @@ static void __ath11k_mac_unregister(struct ath11k *ar) kfree(ar->hw->wiphy->iface_combinations[0].limits); kfree(ar->hw->wiphy->iface_combinations); + kfree(ar->hw->wiphy->addresses); + SET_IEEE80211_DEV(ar->hw, NULL); } @@ -9989,6 +10018,7 @@ static int __ath11k_mac_register(struct ath11k *ar) ath11k_pdev_caps_update(ar); SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr); + ath11k_mac_setup_mac_address_list(ar); SET_IEEE80211_DEV(ar->hw, ab->dev); From 515bcdf587f9911f2d5de51524cb7e048d295052 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 9 Jan 2024 10:13:35 +0800 Subject: [PATCH 1242/2255] wifi: ath11k: move pci.ops registration ahead In ath11k_pci_probe() there is a switch statement that, based upon the PCI device ID, assigns pci_ops. After the switch, ath11k_pcic_register_pci_ops() is called to register the pci_ops. Unfortunately, this registration is too late if any of the cases in the switch need to perform operations that require the pci_ops to already be registered. In particular, an upcoming patch for QCA2066 needs to call ath11k_pcic_read32(). To address this issue, call ath11k_pcic_register_pci_ops() from each case instead of doing so after the switch. That way the ops will be registered if any subsequent operations within the case processing require the ops to be present. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20240109021336.4143-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/pci.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d667d5e06a66..022d695be00f 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -742,7 +742,6 @@ static int ath11k_pci_probe(struct pci_dev *pdev, struct ath11k_base *ab; struct ath11k_pci *ab_pci; u32 soc_hw_version_major, soc_hw_version_minor, addr; - const struct ath11k_pci_ops *pci_ops; int ret; ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); @@ -788,6 +787,12 @@ static int ath11k_pci_probe(struct pci_dev *pdev, switch (pci_dev->device) { case QCA6390_DEVICE_ID: + ret = ath11k_pcic_register_pci_ops(ab, &ath11k_pci_ops_qca6390); + if (ret) { + ath11k_err(ab, "failed to register PCI ops: %d\n", ret); + goto err_pci_free_region; + } + ath11k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { @@ -801,13 +806,21 @@ static int ath11k_pci_probe(struct pci_dev *pdev, goto err_pci_free_region; } - pci_ops = &ath11k_pci_ops_qca6390; break; case QCN9074_DEVICE_ID: - pci_ops = &ath11k_pci_ops_qcn9074; + ret = ath11k_pcic_register_pci_ops(ab, &ath11k_pci_ops_qcn9074); + if (ret) { + ath11k_err(ab, "failed to register PCI ops: %d\n", ret); + goto err_pci_free_region; + } ab->hw_rev = ATH11K_HW_QCN9074_HW10; break; case WCN6855_DEVICE_ID: + ret = ath11k_pcic_register_pci_ops(ab, &ath11k_pci_ops_qca6390); + if (ret) { + ath11k_err(ab, "failed to register PCI ops: %d\n", ret); + goto err_pci_free_region; + } ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; ath11k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); @@ -834,7 +847,6 @@ unsupported_wcn6855_soc: goto err_pci_free_region; } - pci_ops = &ath11k_pci_ops_qca6390; break; default: dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", @@ -843,12 +855,6 @@ unsupported_wcn6855_soc: goto err_pci_free_region; } - ret = ath11k_pcic_register_pci_ops(ab, pci_ops); - if (ret) { - ath11k_err(ab, "failed to register PCI ops: %d\n", ret); - goto err_pci_free_region; - } - ret = ath11k_pcic_init_msi_config(ab); if (ret) { ath11k_err(ab, "failed to init msi config: %d\n", ret); From 5dc9d1a55e953d9059ecbdd8fe6ec81e9edd349e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 9 Jan 2024 10:13:36 +0800 Subject: [PATCH 1243/2255] wifi: ath11k: add support for QCA2066 QCA2066 is a PCI based DBS device. It is very similar to WCN6855 overall: they share the same PCI device ID, the same major and minor version numbers, the same register address, and same HAL descriptors etc. The most significant difference is that QCA2066 supports 3-antenna configuration while WCN6855 does not. To differentiate them, subversion numbers are used. Currently four numbers are used by QCA2066: 0x1019A0E1, 0x1019B0E1, 0x1019C0E1 and 0x1019D0E1. Tested-on: QCA2066 hw2.1 PCI WLAN.HSP.1.1-03737-QCAHSPSWPL_V2_SILICONZ_CE-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20240109021336.4143-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 86 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/mhi.c | 1 + drivers/net/wireless/ath/ath11k/pci.c | 17 ++++- drivers/net/wireless/ath/ath11k/pcic.c | 11 ++++ 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 3c1ba8fd28f4..922e67f8e04f 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -711,6 +711,92 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, }, + { + .name = "qca2066 hw2.1", + .hw_rev = ATH11K_HW_QCA2066_HW21, + .fw = { + .dir = "QCA2066/hw2.1", + .board_size = 256 * 1024, + .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, + .hw_ops = &wcn6855_ops, + .ring_mask = &ath11k_hw_ring_mask_qca6390, + .internal_sleep_clock = true, + .regs = &wcn6855_regs, + .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390, + .host_ce_config = ath11k_host_ce_config_qca6390, + .ce_count = 9, + .target_ce_config = ath11k_target_ce_config_wlan_qca6390, + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, + .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + + .spectral = { + .fft_sz = 0, + .fft_pad_sz = 0, + .summary_pad_sz = 0, + .fft_hdr_len = 0, + .max_fft_bins = 0, + .fragment_160mhz = false, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, + .full_monitor_mode = false, + .supports_shadow_regs = true, + .idle_ps = true, + .supports_sta_ps = true, + .coldboot_cal_mm = false, + .coldboot_cal_ftm = false, + .cbcal_restart_fw = false, + .fw_mem_mode = 0, + .num_vdevs = 2 + 1, + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .supports_regdb = true, + .fix_l1ss = false, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, + .dbr_debug_support = false, + .global_reset = true, + .bios_sar_capa = &ath11k_hw_sar_capa_wcn6855, + .m3_fw_support = true, + .fixed_bdf_addr = false, + .fixed_mem_region = false, + .static_window_map = false, + .hybrid_bus_type = false, + .fixed_fw_mem = false, + .support_off_channel_tx = true, + .supports_multi_bssid = true, + + .sram_dump = { + .start = 0x01400000, + .end = 0x0177ffff, + }, + + .tcl_ring_retry = true, + .tx_ring_size = DP_TCL_DATA_RING_SIZE, + .smp2p_wow_exit = false, + .support_fw_mac_sequence = true, + .support_dual_stations = true, + }, }; static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 0b2d4a93d706..b3fb74a226fb 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -147,6 +147,7 @@ enum ath11k_hw_rev { ATH11K_HW_WCN6855_HW21, ATH11K_HW_WCN6750_HW10, ATH11K_HW_IPQ5018_HW10, + ATH11K_HW_QCA2066_HW21, }; enum ath11k_firmware_mode { diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index e6e69bb91103..b53659145fcf 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -443,6 +443,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) case ATH11K_HW_QCA6390_HW20: case ATH11K_HW_WCN6855_HW20: case ATH11K_HW_WCN6855_HW21: + case ATH11K_HW_QCA2066_HW21: ath11k_mhi_config = &ath11k_mhi_config_qca6390; break; default: diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 022d695be00f..be9d2c69cc41 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -29,6 +29,8 @@ #define QCN9074_DEVICE_ID 0x1104 #define WCN6855_DEVICE_ID 0x1103 +#define TCSR_SOC_HW_SUB_VER 0x1910010 + static const struct pci_device_id ath11k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, @@ -743,6 +745,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, struct ath11k_pci *ab_pci; u32 soc_hw_version_major, soc_hw_version_minor, addr; int ret; + u32 sub_version; ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); @@ -833,7 +836,19 @@ static int ath11k_pci_probe(struct pci_dev *pdev, break; case 0x10: case 0x11: - ab->hw_rev = ATH11K_HW_WCN6855_HW21; + sub_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_SUB_VER); + ath11k_dbg(ab, ATH11K_DBG_PCI, "sub_version 0x%x\n", + sub_version); + switch (sub_version) { + case 0x1019A0E1: + case 0x1019B0E1: + case 0x1019C0E1: + case 0x1019D0E1: + ab->hw_rev = ATH11K_HW_QCA2066_HW21; + break; + default: + ab->hw_rev = ATH11K_HW_WCN6855_HW21; + } break; default: goto unsupported_wcn6855_soc; diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index 15e2ceb22a44..add4db4c50bc 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -115,6 +115,17 @@ static const struct ath11k_msi_config ath11k_msi_config[] = { }, .hw_rev = ATH11K_HW_WCN6750_HW10, }, + { + .total_vectors = 32, + .total_users = 4, + .users = (struct ath11k_msi_user[]) { + { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, + { .name = "CE", .num_vectors = 10, .base_vector = 3 }, + { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, + { .name = "DP", .num_vectors = 18, .base_vector = 14 }, + }, + .hw_rev = ATH11K_HW_QCA2066_HW21, + }, }; int ath11k_pcic_init_msi_config(struct ath11k_base *ab) From 3ab6aff5793c3c7bdf6535d9b0024544a4abbdd5 Mon Sep 17 00:00:00 2001 From: Nicolas Escande Date: Sun, 11 Feb 2024 16:10:36 +0100 Subject: [PATCH 1244/2255] wifi: ath11k: remove unused scan_events from struct scan_req_params As discussed lets remove the unused scan_events field from struct scan_req_params. Also, as it is not needed anymore, remove the underlying union wrapping too. No functionnal changes. Link: https://lore.kernel.org/all/4be7d62e-cb59-462d-aac2-94e27efc22ff@quicinc.com/ Signed-off-by: Nicolas Escande Signed-off-by: Kalle Valo Link: https://msgid.link/20240211151036.1950292-1-nico.escande@gmail.com --- drivers/net/wireless/ath/ath11k/wmi.h | 31 +++++++++++---------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index bc7adf7f13fb..bb419e3abb00 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3363,24 +3363,19 @@ struct scan_req_params { u32 vdev_id; u32 pdev_id; enum wmi_scan_priority scan_priority; - union { - struct { - u32 scan_ev_started:1, - scan_ev_completed:1, - scan_ev_bss_chan:1, - scan_ev_foreign_chan:1, - scan_ev_dequeued:1, - scan_ev_preempted:1, - scan_ev_start_failed:1, - scan_ev_restarted:1, - scan_ev_foreign_chn_exit:1, - scan_ev_invalid:1, - scan_ev_gpio_timeout:1, - scan_ev_suspended:1, - scan_ev_resumed:1; - }; - u32 scan_events; - }; + u32 scan_ev_started:1, + scan_ev_completed:1, + scan_ev_bss_chan:1, + scan_ev_foreign_chan:1, + scan_ev_dequeued:1, + scan_ev_preempted:1, + scan_ev_start_failed:1, + scan_ev_restarted:1, + scan_ev_foreign_chn_exit:1, + scan_ev_invalid:1, + scan_ev_gpio_timeout:1, + scan_ev_suspended:1, + scan_ev_resumed:1; u32 scan_ctrl_flags_ext; u32 dwell_time_active; u32 dwell_time_active_2g; From d25f32722f5069faf688b2646ec4071ac2cb3c53 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Tue, 13 Feb 2024 21:12:05 +0800 Subject: [PATCH 1245/2255] tcp: no need to use acceptable for conn_request Since tcp_conn_request() always returns zero, there is no need to keep the dead code. Remove it then. Link: https://lore.kernel.org/netdev/CANn89iJwx9b2dUGUKFSV3PF=kN5o+kxz3A_fHZZsOS4AnXhBNw@mail.gmail.com/ Suggested-by: Eric Dumazet Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20240213131205.4309-1-kerneljasonxing@gmail.com Signed-off-by: Paolo Abeni --- net/ipv4/tcp_input.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2d20edf652e6..b1c4462a0798 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6623,7 +6623,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); struct request_sock *req; int queued = 0; - bool acceptable; SKB_DR(reason); switch (sk->sk_state) { @@ -6649,12 +6648,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) */ rcu_read_lock(); local_bh_disable(); - acceptable = icsk->icsk_af_ops->conn_request(sk, skb) >= 0; + icsk->icsk_af_ops->conn_request(sk, skb); local_bh_enable(); rcu_read_unlock(); - if (!acceptable) - return 1; consume_skb(skb); return 0; } From 038ba1dc4e54d51d953f5618d8eb5dd39bd9de25 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 13 Feb 2024 14:35:51 +0100 Subject: [PATCH 1246/2255] net: phy: aquantia: add AQR111 and AQR111B0 PHY ID Add Aquantia AQR111 and AQR111B0 PHY ID. These PHY advertise 10G speed but actually supports up to 5G speed, hence some manual fixup is needed. The Aquantia AQR111B0 PHY is just a variant of the AQR111 with smaller chip size. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240213133558.1836-1-ansuelsmth@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/phy/aquantia/aquantia_main.c | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index e1f092cbfdce..109387acabeb 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -22,6 +22,8 @@ #define PHY_ID_AQR107 0x03a1b4e0 #define PHY_ID_AQCS109 0x03a1b5c2 #define PHY_ID_AQR405 0x03a1b4b0 +#define PHY_ID_AQR111 0x03a1b610 +#define PHY_ID_AQR111B0 0x03a1b612 #define PHY_ID_AQR112 0x03a1b662 #define PHY_ID_AQR412 0x03a1b712 #define PHY_ID_AQR113C 0x31c31c12 @@ -755,6 +757,16 @@ static int aqr107_probe(struct phy_device *phydev) return aqr_hwmon_probe(phydev); } +static int aqr111_config_init(struct phy_device *phydev) +{ + /* AQR111 reports supporting speed up to 10G, + * however only speeds up to 5G are supported. + */ + phy_set_max_speed(phydev, SPEED_5000); + + return aqr107_config_init(phydev); +} + static struct phy_driver aqr_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202), @@ -828,6 +840,44 @@ static struct phy_driver aqr_driver[] = { .get_stats = aqr107_get_stats, .link_change_notify = aqr107_link_change_notify, }, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR111), + .name = "Aquantia AQR111", + .probe = aqr107_probe, + .get_rate_matching = aqr107_get_rate_matching, + .config_init = aqr111_config_init, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0), + .name = "Aquantia AQR111B0", + .probe = aqr107_probe, + .get_rate_matching = aqr107_get_rate_matching, + .config_init = aqr111_config_init, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, { PHY_ID_MATCH_MODEL(PHY_ID_AQR405), .name = "Aquantia AQR405", @@ -903,6 +953,8 @@ static struct mdio_device_id __maybe_unused aqr_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR111) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, From 984328c7657dbf2fea8f67e1171cb93a22d7fc06 Mon Sep 17 00:00:00 2001 From: Shigeru Yoshida Date: Tue, 13 Feb 2024 22:40:58 +0900 Subject: [PATCH 1247/2255] tipc: Cleanup tipc_nl_bearer_add() error paths Consolidate the error paths of tipc_nl_bearer_add() under the common label if the function holds rtnl_lock. Signed-off-by: Shigeru Yoshida Reviewed-by: Tung Nguyen Link: https://lore.kernel.org/r/20240213134058.386123-1-syoshida@redhat.com Signed-off-by: Paolo Abeni --- net/tipc/bearer.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 878415c43527..5a526ebafeb4 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -1079,30 +1079,27 @@ int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); b = tipc_bearer_find(net, name); if (!b) { - rtnl_unlock(); NL_SET_ERR_MSG(info->extack, "Bearer not found"); - return -EINVAL; + err = -EINVAL; + goto out; } #ifdef CONFIG_TIPC_MEDIA_UDP if (attrs[TIPC_NLA_BEARER_UDP_OPTS]) { if (b->media->type_id != TIPC_MEDIA_TYPE_UDP) { - rtnl_unlock(); NL_SET_ERR_MSG(info->extack, "UDP option is unsupported"); - return -EINVAL; + err = -EINVAL; + goto out; } err = tipc_udp_nl_bearer_add(b, attrs[TIPC_NLA_BEARER_UDP_OPTS]); - if (err) { - rtnl_unlock(); - return err; - } } #endif +out: rtnl_unlock(); - return 0; + return err; } int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) From 81800aef0eba33df2b30f2e29a0137078b9ba256 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 13 Feb 2024 11:48:00 -0300 Subject: [PATCH 1248/2255] net: mdio_bus: make mdio_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the mdio_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Andrew Lunn Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240213-bus_cleanup-mdio-v1-1-f9e799da7fda@marliere.net Signed-off-by: Paolo Abeni --- drivers/net/phy/mdio_bus.c | 2 +- drivers/net/phy/phy_device.c | 3 +-- include/linux/phy.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 08624f073014..b765466e767f 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -1426,7 +1426,7 @@ static const struct attribute_group *mdio_bus_dev_groups[] = { NULL, }; -struct bus_type mdio_bus_type = { +const struct bus_type mdio_bus_type = { .name = "mdio_bus", .dev_groups = mdio_bus_dev_groups, .match = mdio_bus_match, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 9f37c0bfbf8d..d63dca535746 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1604,7 +1604,6 @@ EXPORT_SYMBOL(phy_attach_direct); struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, phy_interface_t interface) { - struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; struct device *d; int rc; @@ -1615,7 +1614,7 @@ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, /* Search the list of PHY devices on the mdio bus for the * PHY with the requested name */ - d = bus_find_device_by_name(bus, NULL, bus_id); + d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id); if (!d) { pr_err("PHY %s not found\n", bus_id); return ERR_PTR(-ENODEV); diff --git a/include/linux/phy.h b/include/linux/phy.h index 2249cdb5957a..c2dda21b39e1 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -2129,7 +2129,7 @@ static inline bool phy_package_probe_once(struct phy_device *phydev) return __phy_package_set_once(phydev, PHY_SHARED_F_PROBE_DONE); } -extern struct bus_type mdio_bus_type; +extern const struct bus_type mdio_bus_type; struct mdio_board_info { const char *bus_id; From e8d8acad5a85b5ee3e9ec502357dbd8ac27b9015 Mon Sep 17 00:00:00 2001 From: Kamal Heib Date: Tue, 13 Feb 2024 11:15:02 -0500 Subject: [PATCH 1249/2255] net: ena: Remove unlikely() from IS_ERR() condition IS_ERR() is already using unlikely internally. Signed-off-by: Kamal Heib Acked-by: Arthur Kiyanovski Link: https://lore.kernel.org/r/20240213161502.2297048-1-kheib@redhat.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index a77c380c9202..2d28e97b2cf3 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -545,7 +545,7 @@ static int ena_alloc_rx_buffer(struct ena_ring *rx_ring, /* We handle DMA here */ page = ena_alloc_map_page(rx_ring, &dma); - if (unlikely(IS_ERR(page))) + if (IS_ERR(page)) return PTR_ERR(page); netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, From ea578703b03d5d651b091c39f717dc829155b520 Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Tue, 13 Feb 2024 10:41:37 -0800 Subject: [PATCH 1250/2255] igc: Add support for LEDs on i225/i226 Add support for LEDs on i225/i226. The LEDs can be controlled via sysfs from user space using the netdev trigger. The LEDs are named as igc-- to be easily identified. Offloading link speed and activity are supported. Other modes are simulated in software by using on/off. Tested on Intel i225. Signed-off-by: Kurt Kanzenbach Reviewed-by: Andrew Lunn Tested-by: Naama Meir Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20240213184138.1483968-1-anthony.l.nguyen@intel.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/intel/Kconfig | 8 + drivers/net/ethernet/intel/igc/Makefile | 1 + drivers/net/ethernet/intel/igc/igc.h | 5 + drivers/net/ethernet/intel/igc/igc_leds.c | 280 ++++++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_main.c | 6 + drivers/net/ethernet/intel/igc/igc_regs.h | 1 + 6 files changed, 301 insertions(+) create mode 100644 drivers/net/ethernet/intel/igc/igc_leds.c diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index d55638ad8704..767358b60507 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -368,6 +368,14 @@ config IGC To compile this driver as a module, choose M here. The module will be called igc. + +config IGC_LEDS + def_bool LEDS_TRIGGER_NETDEV + depends on IGC && LEDS_CLASS + help + Optional support for controlling the NIC LED's with the netdev + LED trigger. + config IDPF tristate "Intel(R) Infrastructure Data Path Function Support" depends on PCI_MSI diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 95d1e8c490a4..ebffd3054285 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -6,6 +6,7 @@ # obj-$(CONFIG_IGC) += igc.o +igc-$(CONFIG_IGC_LEDS) += igc_leds.o igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o \ igc_diag.o igc_ethtool.o igc_ptp.o igc_dump.o igc_tsn.o igc_xdp.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index d5833c057de4..cfa6baccec55 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -295,6 +295,9 @@ struct igc_adapter { struct timespec64 start; struct timespec64 period; } perout[IGC_N_PEROUT]; + + /* LEDs */ + struct mutex led_mutex; }; void igc_up(struct igc_adapter *adapter); @@ -720,6 +723,8 @@ void igc_ptp_tx_hang(struct igc_adapter *adapter); void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts); void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter); +int igc_led_setup(struct igc_adapter *adapter); + #define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring)) #define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS) diff --git a/drivers/net/ethernet/intel/igc/igc_leds.c b/drivers/net/ethernet/intel/igc/igc_leds.c new file mode 100644 index 000000000000..bf240c5daf86 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_leds.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2024 Linutronix GmbH */ + +#include +#include +#include +#include +#include + +#include "igc.h" + +#define IGC_NUM_LEDS 3 + +#define IGC_LEDCTL_LED0_MODE_SHIFT 0 +#define IGC_LEDCTL_LED0_MODE_MASK GENMASK(3, 0) +#define IGC_LEDCTL_LED0_BLINK BIT(7) +#define IGC_LEDCTL_LED1_MODE_SHIFT 8 +#define IGC_LEDCTL_LED1_MODE_MASK GENMASK(11, 8) +#define IGC_LEDCTL_LED1_BLINK BIT(15) +#define IGC_LEDCTL_LED2_MODE_SHIFT 16 +#define IGC_LEDCTL_LED2_MODE_MASK GENMASK(19, 16) +#define IGC_LEDCTL_LED2_BLINK BIT(23) + +#define IGC_LEDCTL_MODE_ON 0x00 +#define IGC_LEDCTL_MODE_OFF 0x01 +#define IGC_LEDCTL_MODE_LINK_10 0x05 +#define IGC_LEDCTL_MODE_LINK_100 0x06 +#define IGC_LEDCTL_MODE_LINK_1000 0x07 +#define IGC_LEDCTL_MODE_LINK_2500 0x08 +#define IGC_LEDCTL_MODE_ACTIVITY 0x0b + +#define IGC_SUPPORTED_MODES \ + (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK_1000) | \ + BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_10) | \ + BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) + +#define IGC_ACTIVITY_MODES \ + (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) + +struct igc_led_classdev { + struct net_device *netdev; + struct led_classdev led; + int index; +}; + +#define lcdev_to_igc_ldev(lcdev) \ + container_of(lcdev, struct igc_led_classdev, led) + +static void igc_led_select(struct igc_adapter *adapter, int led, + u32 *mask, u32 *shift, u32 *blink) +{ + switch (led) { + case 0: + *mask = IGC_LEDCTL_LED0_MODE_MASK; + *shift = IGC_LEDCTL_LED0_MODE_SHIFT; + *blink = IGC_LEDCTL_LED0_BLINK; + break; + case 1: + *mask = IGC_LEDCTL_LED1_MODE_MASK; + *shift = IGC_LEDCTL_LED1_MODE_SHIFT; + *blink = IGC_LEDCTL_LED1_BLINK; + break; + case 2: + *mask = IGC_LEDCTL_LED2_MODE_MASK; + *shift = IGC_LEDCTL_LED2_MODE_SHIFT; + *blink = IGC_LEDCTL_LED2_BLINK; + break; + default: + *mask = *shift = *blink = 0; + netdev_err(adapter->netdev, "Unknown LED %d selected!\n", led); + } +} + +static void igc_led_set(struct igc_adapter *adapter, int led, u32 mode, + bool blink) +{ + u32 shift, mask, blink_bit, ledctl; + struct igc_hw *hw = &adapter->hw; + + igc_led_select(adapter, led, &mask, &shift, &blink_bit); + + pm_runtime_get_sync(&adapter->pdev->dev); + mutex_lock(&adapter->led_mutex); + + /* Set mode */ + ledctl = rd32(IGC_LEDCTL); + ledctl &= ~mask; + ledctl |= mode << shift; + + /* Configure blinking */ + if (blink) + ledctl |= blink_bit; + else + ledctl &= ~blink_bit; + wr32(IGC_LEDCTL, ledctl); + + mutex_unlock(&adapter->led_mutex); + pm_runtime_put(&adapter->pdev->dev); +} + +static u32 igc_led_get(struct igc_adapter *adapter, int led) +{ + u32 shift, mask, blink_bit, ledctl; + struct igc_hw *hw = &adapter->hw; + + igc_led_select(adapter, led, &mask, &shift, &blink_bit); + + pm_runtime_get_sync(&adapter->pdev->dev); + mutex_lock(&adapter->led_mutex); + ledctl = rd32(IGC_LEDCTL); + mutex_unlock(&adapter->led_mutex); + pm_runtime_put(&adapter->pdev->dev); + + return (ledctl & mask) >> shift; +} + +static int igc_led_brightness_set_blocking(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); + struct igc_adapter *adapter = netdev_priv(ldev->netdev); + u32 mode; + + if (brightness) + mode = IGC_LEDCTL_MODE_ON; + else + mode = IGC_LEDCTL_MODE_OFF; + + netdev_dbg(adapter->netdev, "Set brightness for LED %d to mode %u!\n", + ldev->index, mode); + + igc_led_set(adapter, ldev->index, mode, false); + + return 0; +} + +static int igc_led_hw_control_is_supported(struct led_classdev *led_cdev, + unsigned long flags) +{ + if (flags & ~IGC_SUPPORTED_MODES) + return -EOPNOTSUPP; + + /* If Tx and Rx selected, activity can be offloaded unless some other + * mode is selected as well. + */ + if ((flags & BIT(TRIGGER_NETDEV_TX)) && + (flags & BIT(TRIGGER_NETDEV_RX)) && + !(flags & ~IGC_ACTIVITY_MODES)) + return 0; + + /* Single Rx or Tx activity is not supported. */ + if (flags & IGC_ACTIVITY_MODES) + return -EOPNOTSUPP; + + /* Only one mode can be active at a given time. */ + if (flags & (flags - 1)) + return -EOPNOTSUPP; + + return 0; +} + +static int igc_led_hw_control_set(struct led_classdev *led_cdev, + unsigned long flags) +{ + struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); + struct igc_adapter *adapter = netdev_priv(ldev->netdev); + u32 mode = IGC_LEDCTL_MODE_OFF; + bool blink = false; + + if (flags & BIT(TRIGGER_NETDEV_LINK_10)) + mode = IGC_LEDCTL_MODE_LINK_10; + if (flags & BIT(TRIGGER_NETDEV_LINK_100)) + mode = IGC_LEDCTL_MODE_LINK_100; + if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) + mode = IGC_LEDCTL_MODE_LINK_1000; + if (flags & BIT(TRIGGER_NETDEV_LINK_2500)) + mode = IGC_LEDCTL_MODE_LINK_2500; + if ((flags & BIT(TRIGGER_NETDEV_TX)) && + (flags & BIT(TRIGGER_NETDEV_RX))) + mode = IGC_LEDCTL_MODE_ACTIVITY; + + netdev_dbg(adapter->netdev, "Set HW control for LED %d to mode %u!\n", + ldev->index, mode); + + /* blink is recommended for activity */ + if (mode == IGC_LEDCTL_MODE_ACTIVITY) + blink = true; + + igc_led_set(adapter, ldev->index, mode, blink); + + return 0; +} + +static int igc_led_hw_control_get(struct led_classdev *led_cdev, + unsigned long *flags) +{ + struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); + struct igc_adapter *adapter = netdev_priv(ldev->netdev); + u32 mode; + + mode = igc_led_get(adapter, ldev->index); + + switch (mode) { + case IGC_LEDCTL_MODE_ACTIVITY: + *flags = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); + break; + case IGC_LEDCTL_MODE_LINK_10: + *flags = BIT(TRIGGER_NETDEV_LINK_10); + break; + case IGC_LEDCTL_MODE_LINK_100: + *flags = BIT(TRIGGER_NETDEV_LINK_100); + break; + case IGC_LEDCTL_MODE_LINK_1000: + *flags = BIT(TRIGGER_NETDEV_LINK_1000); + break; + case IGC_LEDCTL_MODE_LINK_2500: + *flags = BIT(TRIGGER_NETDEV_LINK_2500); + break; + } + + return 0; +} + +static struct device *igc_led_hw_control_get_device(struct led_classdev *led_cdev) +{ + struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); + + return &ldev->netdev->dev; +} + +static void igc_led_get_name(struct igc_adapter *adapter, int index, char *buf, + size_t buf_len) +{ + snprintf(buf, buf_len, "igc-%x%x-led%d", + pci_domain_nr(adapter->pdev->bus), + pci_dev_id(adapter->pdev), index); +} + +static void igc_setup_ldev(struct igc_led_classdev *ldev, + struct net_device *netdev, int index) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + struct led_classdev *led_cdev = &ldev->led; + char led_name[LED_MAX_NAME_SIZE]; + + ldev->netdev = netdev; + ldev->index = index; + + igc_led_get_name(adapter, index, led_name, LED_MAX_NAME_SIZE); + led_cdev->name = led_name; + led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; + led_cdev->max_brightness = 1; + led_cdev->brightness_set_blocking = igc_led_brightness_set_blocking; + led_cdev->hw_control_trigger = "netdev"; + led_cdev->hw_control_is_supported = igc_led_hw_control_is_supported; + led_cdev->hw_control_set = igc_led_hw_control_set; + led_cdev->hw_control_get = igc_led_hw_control_get; + led_cdev->hw_control_get_device = igc_led_hw_control_get_device; + + devm_led_classdev_register(&netdev->dev, led_cdev); +} + +int igc_led_setup(struct igc_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct device *dev = &netdev->dev; + struct igc_led_classdev *leds; + int i; + + mutex_init(&adapter->led_mutex); + + leds = devm_kcalloc(dev, IGC_NUM_LEDS, sizeof(*leds), GFP_KERNEL); + if (!leds) + return -ENOMEM; + + for (i = 0; i < IGC_NUM_LEDS; i++) + igc_setup_ldev(leds + i, netdev, i); + + return 0; +} diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index c3fe62813f43..3af52d238f3b 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -6978,6 +6978,12 @@ static int igc_probe(struct pci_dev *pdev, pm_runtime_put_noidle(&pdev->dev); + if (IS_ENABLED(CONFIG_IGC_LEDS)) { + err = igc_led_setup(adapter); + if (err) + goto err_register; + } + return 0; err_register: diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index d38c87d7e5e8..e5b893fc5b66 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -12,6 +12,7 @@ #define IGC_MDIC 0x00020 /* MDI Control - RW */ #define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ #define IGC_VET 0x00038 /* VLAN Ether Type - RW */ +#define IGC_LEDCTL 0x00E00 /* LED Control - RW */ #define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */ #define IGC_GPHY_VERSION 0x0001E /* I225 gPHY Firmware Version */ From 2aa8f155b09519814e449dc19adacf01fd1367ee Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 13 Feb 2024 23:26:30 -0700 Subject: [PATCH 1251/2255] net: ipv6/addrconf: ensure that regen_advance is at least 2 seconds RFC 8981 defines REGEN_ADVANCE as follows: REGEN_ADVANCE = 2 + (TEMP_IDGEN_RETRIES * DupAddrDetectTransmits * RetransTimer / 1000) Thus, allowing it to be less than 2 seconds is technically a protocol violation. Link: https://datatracker.ietf.org/doc/html/rfc8981#name-defined-protocol-parameters Signed-off-by: Alex Henrie Reviewed-by: David Ahern Signed-off-by: Paolo Abeni --- Documentation/networking/ip-sysctl.rst | 4 ++-- net/ipv6/addrconf.c | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 7afff42612e9..458305931345 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -2503,7 +2503,7 @@ use_tempaddr - INTEGER temp_valid_lft - INTEGER valid lifetime (in seconds) for temporary addresses. If less than the - minimum required lifetime (typically 5 seconds), temporary addresses + minimum required lifetime (typically 5-7 seconds), temporary addresses will not be created. Default: 172800 (2 days) @@ -2511,7 +2511,7 @@ temp_valid_lft - INTEGER temp_prefered_lft - INTEGER Preferred lifetime (in seconds) for temporary addresses. If temp_prefered_lft is less than the minimum required lifetime (typically - 5 seconds), temporary addresses will not be created. If + 5-7 seconds), temporary addresses will not be created. If temp_prefered_lft is greater than temp_valid_lft, the preferred lifetime is temp_valid_lft. diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2c1ed642e3f4..65e886d7d80c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1339,6 +1339,13 @@ out: in6_ifa_put(ifp); } +static unsigned long ipv6_get_regen_advance(struct inet6_dev *idev) +{ + return 2 + idev->cnf.regen_max_retry * + idev->cnf.dad_transmits * + max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; +} + static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) { struct inet6_dev *idev = ifp->idev; @@ -1380,9 +1387,7 @@ retry: age = (now - ifp->tstamp) / HZ; - regen_advance = idev->cnf.regen_max_retry * - idev->cnf.dad_transmits * - max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; + regen_advance = ipv6_get_regen_advance(idev); /* recalculate max_desync_factor each time and update * idev->desync_factor if it's larger @@ -4595,9 +4600,7 @@ restart: !ifp->regen_count && ifp->ifpub) { /* This is a non-regenerated temporary addr. */ - unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * - ifp->idev->cnf.dad_transmits * - max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; + unsigned long regen_advance = ipv6_get_regen_advance(ifp->idev); if (age + regen_advance >= ifp->prefered_lft) { struct inet6_ifaddr *ifpub = ifp->ifpub; From a5fcea2d2f790aa90b6e996d411ae2cf8db55186 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 13 Feb 2024 23:26:31 -0700 Subject: [PATCH 1252/2255] net: ipv6/addrconf: introduce a regen_min_advance sysctl In RFC 8981, REGEN_ADVANCE cannot be less than 2 seconds, and the RFC does not permit the creation of temporary addresses with lifetimes shorter than that: > When processing a Router Advertisement with a > Prefix Information option carrying a prefix for the purposes of > address autoconfiguration (i.e., the A bit is set), the host MUST > perform the following steps: > 5. A temporary address is created only if this calculated preferred > lifetime is greater than REGEN_ADVANCE time units. However, some users want to change their IPv6 address as frequently as possible regardless of the RFC's arbitrary minimum lifetime. For the benefit of those users, add a regen_min_advance sysctl parameter that can be set to below or above 2 seconds. Link: https://datatracker.ietf.org/doc/html/rfc8981 Signed-off-by: Alex Henrie Reviewed-by: David Ahern Signed-off-by: Paolo Abeni --- Documentation/networking/ip-sysctl.rst | 10 ++++++++++ include/linux/ipv6.h | 1 + include/net/addrconf.h | 5 +++-- net/ipv6/addrconf.c | 11 ++++++++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 458305931345..407d917d1a36 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -2535,6 +2535,16 @@ max_desync_factor - INTEGER Default: 600 +regen_min_advance - INTEGER + How far in advance (in seconds), at minimum, to create a new temporary + address before the current one is deprecated. This value is added to + the amount of time that may be required for duplicate address detection + to determine when to create a new address. Linux permits setting this + value to less than the default of 2 seconds, but a value less than 2 + does not conform to RFC 8981. + + Default: 2 + regen_max_retry - INTEGER Number of attempts before give up attempting to generate valid temporary addresses. diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 5e605e384aac..ef3aa060a289 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -27,6 +27,7 @@ struct ipv6_devconf { __s32 use_tempaddr; __s32 temp_valid_lft; __s32 temp_prefered_lft; + __s32 regen_min_advance; __s32 regen_max_retry; __s32 max_desync_factor; __s32 max_addresses; diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 61ebe723ee4d..30d6f1e84e46 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -8,8 +8,9 @@ #define MIN_VALID_LIFETIME (2*3600) /* 2 hours */ -#define TEMP_VALID_LIFETIME (7*86400) -#define TEMP_PREFERRED_LIFETIME (86400) +#define TEMP_VALID_LIFETIME (7*86400) /* 1 week */ +#define TEMP_PREFERRED_LIFETIME (86400) /* 24 hours */ +#define REGEN_MIN_ADVANCE (2) /* 2 seconds */ #define REGEN_MAX_RETRY (3) #define MAX_DESYNC_FACTOR (600) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 65e886d7d80c..283823fba96a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -195,6 +195,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .use_tempaddr = 0, .temp_valid_lft = TEMP_VALID_LIFETIME, .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, + .regen_min_advance = REGEN_MIN_ADVANCE, .regen_max_retry = REGEN_MAX_RETRY, .max_desync_factor = MAX_DESYNC_FACTOR, .max_addresses = IPV6_MAX_ADDRESSES, @@ -257,6 +258,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .use_tempaddr = 0, .temp_valid_lft = TEMP_VALID_LIFETIME, .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, + .regen_min_advance = REGEN_MIN_ADVANCE, .regen_max_retry = REGEN_MAX_RETRY, .max_desync_factor = MAX_DESYNC_FACTOR, .max_addresses = IPV6_MAX_ADDRESSES, @@ -1341,7 +1343,7 @@ out: static unsigned long ipv6_get_regen_advance(struct inet6_dev *idev) { - return 2 + idev->cnf.regen_max_retry * + return idev->cnf.regen_min_advance + idev->cnf.regen_max_retry * idev->cnf.dad_transmits * max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; } @@ -6819,6 +6821,13 @@ static const struct ctl_table addrconf_sysctl[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "regen_min_advance", + .data = &ipv6_devconf.regen_min_advance, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { .procname = "regen_max_retry", .data = &ipv6_devconf.regen_max_retry, From f4bcbf360ac8dc424dc4d2b384b528e69b6f34d9 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 13 Feb 2024 23:26:32 -0700 Subject: [PATCH 1253/2255] net: ipv6/addrconf: clamp preferred_lft to the minimum required If the preferred lifetime was less than the minimum required lifetime, ipv6_create_tempaddr would error out without creating any new address. On my machine and network, this error happened immediately with the preferred lifetime set to 5 seconds or less, after a few minutes with the preferred lifetime set to 6 seconds, and not at all with the preferred lifetime set to 7 seconds. During my investigation, I found a Stack Exchange post from another person who seems to have had the same problem: They stopped getting new addresses if they lowered the preferred lifetime below 3 seconds, and they didn't really know why. The preferred lifetime is a preference, not a hard requirement. The kernel does not strictly forbid new connections on a deprecated address, nor does it guarantee that the address will be disposed of the instant its total valid lifetime expires. So rather than disable IPv6 privacy extensions altogether if the minimum required lifetime swells above the preferred lifetime, it is more in keeping with the user's intent to increase the temporary address's lifetime to the minimum necessary for the current network conditions. With these fixes, setting the preferred lifetime to 5 or 6 seconds "just works" because the extra fraction of a second is practically unnoticeable. It's even possible to reduce the time before deprecation to 1 or 2 seconds by setting /proc/sys/net/ipv6/conf/*/regen_min_advance and /proc/sys/net/ipv6/conf/*/dad_transmits to 0. I realize that that is a pretty niche use case, but I know at least one person who would gladly sacrifice performance and convenience to be sure that they are getting the maximum possible level of privacy. Link: https://serverfault.com/a/1031168/310447 Signed-off-by: Alex Henrie Reviewed-by: David Ahern Signed-off-by: Paolo Abeni --- Documentation/networking/ip-sysctl.rst | 2 +- net/ipv6/addrconf.c | 43 ++++++++++++++++++++------ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 407d917d1a36..bd50df6a5a42 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -2511,7 +2511,7 @@ temp_valid_lft - INTEGER temp_prefered_lft - INTEGER Preferred lifetime (in seconds) for temporary addresses. If temp_prefered_lft is less than the minimum required lifetime (typically - 5-7 seconds), temporary addresses will not be created. If + 5-7 seconds), the preferred lifetime is the minimum required. If temp_prefered_lft is greater than temp_valid_lft, the preferred lifetime is temp_valid_lft. diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 283823fba96a..d3f4b7b9cf1f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1354,6 +1354,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) unsigned long tmp_tstamp, age; unsigned long regen_advance; unsigned long now = jiffies; + u32 if_public_preferred_lft; s32 cnf_temp_preferred_lft; struct inet6_ifaddr *ift; struct ifa6_config cfg; @@ -1409,11 +1410,13 @@ retry: } } + if_public_preferred_lft = ifp->prefered_lft; + memset(&cfg, 0, sizeof(cfg)); cfg.valid_lft = min_t(__u32, ifp->valid_lft, idev->cnf.temp_valid_lft + age); cfg.preferred_lft = cnf_temp_preferred_lft + age - idev->desync_factor; - cfg.preferred_lft = min_t(__u32, ifp->prefered_lft, cfg.preferred_lft); + cfg.preferred_lft = min_t(__u32, if_public_preferred_lft, cfg.preferred_lft); cfg.preferred_lft = min_t(__u32, cfg.valid_lft, cfg.preferred_lft); cfg.plen = ifp->prefix_len; @@ -1422,19 +1425,41 @@ retry: write_unlock_bh(&idev->lock); - /* A temporary address is created only if this calculated Preferred - * Lifetime is greater than REGEN_ADVANCE time units. In particular, - * an implementation must not create a temporary address with a zero - * Preferred Lifetime. + /* From RFC 4941: + * + * A temporary address is created only if this calculated Preferred + * Lifetime is greater than REGEN_ADVANCE time units. In + * particular, an implementation must not create a temporary address + * with a zero Preferred Lifetime. + * + * ... + * + * When creating a temporary address, the lifetime values MUST be + * derived from the corresponding prefix as follows: + * + * ... + * + * * Its Preferred Lifetime is the lower of the Preferred Lifetime + * of the public address or TEMP_PREFERRED_LIFETIME - + * DESYNC_FACTOR. + * + * To comply with the RFC's requirements, clamp the preferred lifetime + * to a minimum of regen_advance, unless that would exceed valid_lft or + * ifp->prefered_lft. + * * Use age calculation as in addrconf_verify to avoid unnecessary * temporary addresses being generated. */ age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; if (cfg.preferred_lft <= regen_advance + age) { - in6_ifa_put(ifp); - in6_dev_put(idev); - ret = -1; - goto out; + cfg.preferred_lft = regen_advance + age + 1; + if (cfg.preferred_lft > cfg.valid_lft || + cfg.preferred_lft > if_public_preferred_lft) { + in6_ifa_put(ifp); + in6_dev_put(idev); + ret = -1; + goto out; + } } cfg.ifa_flags = IFA_F_TEMPORARY; From 57354f5fdee8017783b5cc2e53b263641b6862e9 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 14 Feb 2024 09:41:00 -0800 Subject: [PATCH 1254/2255] bpf: improve duplicate source code line detection Verifier log avoids printing the same source code line multiple times when a consecutive block of BPF assembly instructions are covered by the same original (C) source code line. This greatly improves verifier log legibility. Unfortunately, this check is imperfect and in production applications it quite often happens that verifier log will have multiple duplicated source lines emitted, for no apparently good reason. E.g., this is excerpt from a real-world BPF application (with register states omitted for clarity): BEFORE ====== ; for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { @ strobemeta_probe.bpf.c:394 5369: (07) r8 += 2 ; 5370: (07) r7 += 16 ; ; for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { @ strobemeta_probe.bpf.c:394 5371: (07) r9 += 1 ; 5372: (79) r4 = *(u64 *)(r10 -32) ; ; for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { @ strobemeta_probe.bpf.c:394 5373: (55) if r9 != 0xf goto pc+2 ; if (i >= map->cnt) @ strobemeta_probe.bpf.c:396 5376: (79) r1 = *(u64 *)(r10 -40) ; 5377: (79) r1 = *(u64 *)(r1 +8) ; ; if (i >= map->cnt) @ strobemeta_probe.bpf.c:396 5378: (dd) if r1 s<= r9 goto pc-5 ; ; descr->key_lens[i] = 0; @ strobemeta_probe.bpf.c:398 5379: (b4) w1 = 0 ; 5380: (6b) *(u16 *)(r8 -30) = r1 ; ; task, data, off, STROBE_MAX_STR_LEN, map->entries[i].key); @ strobemeta_probe.bpf.c:400 5381: (79) r3 = *(u64 *)(r7 -8) ; 5382: (7b) *(u64 *)(r10 -24) = r6 ; ; task, data, off, STROBE_MAX_STR_LEN, map->entries[i].key); @ strobemeta_probe.bpf.c:400 5383: (bc) w6 = w6 ; ; barrier_var(payload_off); @ strobemeta_probe.bpf.c:280 5384: (bf) r2 = r6 ; 5385: (bf) r1 = r4 ; As can be seen, line 394 is emitted thrice, 396 is emitted twice, and line 400 is duplicated as well. Note that there are no intermingling other lines of source code in between these duplicates, so the issue is not compiler reordering assembly instruction such that multiple original source code lines are in effect. It becomes more obvious what's going on if we look at *full* original line info information (using btfdump for this, [0]): #2764: line: insn #5363 --> 394:3 @ ./././strobemeta_probe.bpf.c for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { #2765: line: insn #5373 --> 394:21 @ ./././strobemeta_probe.bpf.c for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { #2766: line: insn #5375 --> 394:47 @ ./././strobemeta_probe.bpf.c for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { #2767: line: insn #5377 --> 394:3 @ ./././strobemeta_probe.bpf.c for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { #2768: line: insn #5378 --> 414:10 @ ./././strobemeta_probe.bpf.c return off; We can see that there are four line info records covering instructions #5363 through #5377 (instruction indices are shifted due to subprog instruction being appended to main program), all of them are pointing to the same C source code line #394. But each of them points to a different part of that line, which is denoted by differing column numbers (3, 21, 47, 3). But verifier log doesn't distinguish between parts of the same source code line and doesn't emit this column number information, so for end user it's just a repetitive visual noise. So let's improve the detection of repeated source code line and avoid this. With the changes in this patch, we get this output for the same piece of BPF program log: AFTER ===== ; for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { @ strobemeta_probe.bpf.c:394 5369: (07) r8 += 2 ; 5370: (07) r7 += 16 ; 5371: (07) r9 += 1 ; 5372: (79) r4 = *(u64 *)(r10 -32) ; 5373: (55) if r9 != 0xf goto pc+2 ; if (i >= map->cnt) @ strobemeta_probe.bpf.c:396 5376: (79) r1 = *(u64 *)(r10 -40) ; 5377: (79) r1 = *(u64 *)(r1 +8) ; 5378: (dd) if r1 s<= r9 goto pc-5 ; ; descr->key_lens[i] = 0; @ strobemeta_probe.bpf.c:398 5379: (b4) w1 = 0 ; 5380: (6b) *(u16 *)(r8 -30) = r1 ; ; task, data, off, STROBE_MAX_STR_LEN, map->entries[i].key); @ strobemeta_probe.bpf.c:400 5381: (79) r3 = *(u64 *)(r7 -8) ; 5382: (7b) *(u64 *)(r10 -24) = r6 ; 5383: (bc) w6 = w6 ; ; barrier_var(payload_off); @ strobemeta_probe.bpf.c:280 5384: (bf) r2 = r6 ; 5385: (bf) r1 = r4 ; All the duplication is gone and the log is cleaner and less distracting. [0] https://github.com/anakryiko/btfdump Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20240214174100.2847419-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 995e3b82e17b..63c34e7b0715 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -382,15 +382,28 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, u32 insn_off, const char *prefix_fmt, ...) { - const struct bpf_line_info *linfo; + const struct bpf_line_info *linfo, *prev_linfo; const struct btf *btf; const char *s, *fname; if (!bpf_verifier_log_needed(&env->log)) return; + prev_linfo = env->prev_linfo; linfo = find_linfo(env, insn_off); - if (!linfo || linfo == env->prev_linfo) + if (!linfo || linfo == prev_linfo) + return; + + /* It often happens that two separate linfo records point to the same + * source code line, but have differing column numbers. Given verifier + * log doesn't emit column information, from user perspective we just + * end up emitting the same source code line twice unnecessarily. + * So instead check that previous and current linfo record point to + * the same file (file_name_offs match) and the same line number, and + * avoid emitting duplicated source code line in such case. + */ + if (prev_linfo && linfo->file_name_off == prev_linfo->file_name_off && + BPF_LINE_INFO_LINE_NUM(linfo->line_col) == BPF_LINE_INFO_LINE_NUM(prev_linfo->line_col)) return; if (prefix_fmt) { From 682158ab532a5bd24399fec25b65fec561f0f6e9 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 14 Feb 2024 15:29:51 -0800 Subject: [PATCH 1255/2255] bpf: Fix test verif_scale_strobemeta_subprogs failure due to llvm19 With latest llvm19, I hit the following selftest failures with $ ./test_progs -j libbpf: prog 'on_event': BPF program load failed: Permission denied libbpf: prog 'on_event': -- BEGIN PROG LOAD LOG -- combined stack size of 4 calls is 544. Too large verification time 1344153 usec stack depth 24+440+0+32 processed 51008 insns (limit 1000000) max_states_per_insn 19 total_states 1467 peak_states 303 mark_read 146 -- END PROG LOAD LOG -- libbpf: prog 'on_event': failed to load: -13 libbpf: failed to load object 'strobemeta_subprogs.bpf.o' scale_test:FAIL:expect_success unexpected error: -13 (errno 13) #498 verif_scale_strobemeta_subprogs:FAIL The verifier complains too big of the combined stack size (544 bytes) which exceeds the maximum stack limit 512. This is a regression from llvm19 ([1]). In the above error log, the original stack depth is 24+440+0+32. To satisfy interpreter's need, in verifier the stack depth is adjusted to 32+448+32+32=544 which exceeds 512, hence the error. The same adjusted stack size is also used for jit case. But the jitted codes could use smaller stack size. $ egrep -r stack_depth | grep round_up arm64/net/bpf_jit_comp.c: ctx->stack_size = round_up(prog->aux->stack_depth, 16); loongarch/net/bpf_jit.c: bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16); powerpc/net/bpf_jit_comp.c: cgctx.stack_size = round_up(fp->aux->stack_depth, 16); riscv/net/bpf_jit_comp32.c: round_up(ctx->prog->aux->stack_depth, STACK_ALIGN); riscv/net/bpf_jit_comp64.c: bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16); s390/net/bpf_jit_comp.c: u32 stack_depth = round_up(fp->aux->stack_depth, 8); sparc/net/bpf_jit_comp_64.c: stack_needed += round_up(stack_depth, 16); x86/net/bpf_jit_comp.c: EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8)); x86/net/bpf_jit_comp.c: int tcc_off = -4 - round_up(stack_depth, 8); x86/net/bpf_jit_comp.c: round_up(stack_depth, 8)); x86/net/bpf_jit_comp.c: int tcc_off = -4 - round_up(stack_depth, 8); x86/net/bpf_jit_comp.c: EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8)); In the above, STACK_ALIGN in riscv/net/bpf_jit_comp32.c is defined as 16. So stack is aligned in either 8 or 16, x86/s390 having 8-byte stack alignment and the rest having 16-byte alignment. This patch calculates total stack depth based on 16-byte alignment if jit is requested. For the above failing case, the new stack size will be 32+448+0+32=512 and no verification failure. llvm19 regression will be discussed separately in llvm upstream. The verifier change caused three test failures as these tests compared messages with stack size. More specifically, - test_global_funcs/global_func1: fail with interpreter mode and success with jit mode. Adjusted stack sizes so both jit and interpreter modes will fail. - async_stack_depth/{pseudo_call_check, async_call_root_check}: since jit and interpreter will calculate different stack sizes, the failure msg is adjusted to omit those specific stack size numbers. [1] https://lore.kernel.org/bpf/32bde0f0-1881-46c9-931a-673be566c61d@linux.dev/ Suggested-by: Alexei Starovoitov Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20240214232951.4113094-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 18 +++++++++++++----- .../selftests/bpf/progs/async_stack_depth.c | 4 ++-- .../selftests/bpf/progs/test_global_func1.c | 8 ++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index aa192dc735a9..011d54a1dc53 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5812,6 +5812,17 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, strict); } +static int round_up_stack_depth(struct bpf_verifier_env *env, int stack_depth) +{ + if (env->prog->jit_requested) + return round_up(stack_depth, 16); + + /* round up to 32-bytes, since this is granularity + * of interpreter stack size + */ + return round_up(max_t(u32, stack_depth, 1), 32); +} + /* starting from main bpf function walk all instructions of the function * and recursively walk all callees that given function can call. * Ignore jump and exit insns. @@ -5855,10 +5866,7 @@ process_func: depth); return -EACCES; } - /* round up to 32-bytes, since this is granularity - * of interpreter stack size - */ - depth += round_up(max_t(u32, subprog[idx].stack_depth, 1), 32); + depth += round_up_stack_depth(env, subprog[idx].stack_depth); if (depth > MAX_BPF_STACK) { verbose(env, "combined stack size of %d calls is %d. Too large\n", frame + 1, depth); @@ -5952,7 +5960,7 @@ continue_func: */ if (frame == 0) return 0; - depth -= round_up(max_t(u32, subprog[idx].stack_depth, 1), 32); + depth -= round_up_stack_depth(env, subprog[idx].stack_depth); frame--; i = ret_insn[frame]; idx = ret_prog[frame]; diff --git a/tools/testing/selftests/bpf/progs/async_stack_depth.c b/tools/testing/selftests/bpf/progs/async_stack_depth.c index 3517c0e01206..36734683acbd 100644 --- a/tools/testing/selftests/bpf/progs/async_stack_depth.c +++ b/tools/testing/selftests/bpf/progs/async_stack_depth.c @@ -30,7 +30,7 @@ static int bad_timer_cb(void *map, int *key, struct bpf_timer *timer) } SEC("tc") -__failure __msg("combined stack size of 2 calls is 576. Too large") +__failure __msg("combined stack size of 2 calls is") int pseudo_call_check(struct __sk_buff *ctx) { struct hmap_elem *elem; @@ -45,7 +45,7 @@ int pseudo_call_check(struct __sk_buff *ctx) } SEC("tc") -__failure __msg("combined stack size of 2 calls is 608. Too large") +__failure __msg("combined stack size of 2 calls is") int async_call_root_check(struct __sk_buff *ctx) { struct hmap_elem *elem; diff --git a/tools/testing/selftests/bpf/progs/test_global_func1.c b/tools/testing/selftests/bpf/progs/test_global_func1.c index 17a9f59bf5f3..fc69ff18880d 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func1.c +++ b/tools/testing/selftests/bpf/progs/test_global_func1.c @@ -5,7 +5,7 @@ #include #include "bpf_misc.h" -#define MAX_STACK (512 - 3 * 32 + 8) +#define MAX_STACK 260 static __attribute__ ((noinline)) int f0(int var, struct __sk_buff *skb) @@ -30,6 +30,10 @@ int f3(int, struct __sk_buff *skb, int); __attribute__ ((noinline)) int f2(int val, struct __sk_buff *skb) { + volatile char buf[MAX_STACK] = {}; + + __sink(buf[MAX_STACK - 1]); + return f1(skb) + f3(val, skb, 1); } @@ -44,7 +48,7 @@ int f3(int val, struct __sk_buff *skb, int var) } SEC("tc") -__failure __msg("combined stack size of 4 calls is 544") +__failure __msg("combined stack size of 3 calls is") int global_func1(struct __sk_buff *skb) { return f0(1, skb) + f1(skb) + f2(2, skb) + f3(3, skb, 4); From 3738d710af51286d3814332343d10b0c745eaa12 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Mon, 12 Feb 2024 11:47:14 +0100 Subject: [PATCH 1256/2255] configs/debug: add NET debug config The debug.config file is really great to easily enable a bunch of general debugging features on a CI-like setup. But it would be great to also include core networking debugging config. A few CI's validating features from the Net tree also enable a few other debugging options on top of debug.config. A small selection is quite generic for the whole net tree. They validate some assumptions in different parts of the core net tree. As suggested by Jakub Kicinski in [1], having them added to this debug.config file would help other CIs using network features to find bugs in this area. Note that the two REFCNT configs also select REF_TRACKER, which doesn't seem to be an issue. Link: https://lore.kernel.org/netdev/20240202093148.33bd2b14@kernel.org/T/ [1] Signed-off-by: Matthieu Baerts (NGI0) Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20240212-kconfig-debug-enable-net-v1-1-fb026de8174c@kernel.org Signed-off-by: Jakub Kicinski --- kernel/configs/debug.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config index 4722b998a324..509ee703de15 100644 --- a/kernel/configs/debug.config +++ b/kernel/configs/debug.config @@ -40,6 +40,12 @@ CONFIG_UBSAN_ENUM=y CONFIG_UBSAN_SHIFT=y CONFIG_UBSAN_UNREACHABLE=y # +# Networking Debugging +# +CONFIG_NET_DEV_REFCNT_TRACKER=y +CONFIG_NET_NS_REFCNT_TRACKER=y +CONFIG_DEBUG_NET=y +# # Memory Debugging # # CONFIG_DEBUG_PAGEALLOC is not set From 3de21a8990d3c2cc507e9cc4ed00f36358d5b93e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 12 Feb 2024 17:16:13 +0100 Subject: [PATCH 1257/2255] genetlink: Add per family bind/unbind callbacks Add genetlink family bind()/unbind() callbacks when adding/removing multicast group to/from netlink client socket via setsockopt() or bind() syscall. They can be used to track if consumers of netlink multicast messages emerge or disappear. Thus, a client implementing callbacks, can now send events only when there are active consumers, preventing unnecessary work when none exist. Suggested-by: Jakub Kicinski Signed-off-by: Stanislaw Gruszka Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240212161615.161935-2-stanislaw.gruszka@linux.intel.com Signed-off-by: Jakub Kicinski --- include/net/genetlink.h | 4 ++++ net/netlink/genetlink.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index e61469129402..ecadba836ae5 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -41,6 +41,8 @@ struct genl_info; * do additional, common, filtering and return an error * @post_doit: called after an operation's doit callback, it may * undo operations done by pre_doit, for example release locks + * @bind: called when family multicast group is added to a netlink socket + * @unbind: called when family multicast group is removed from a netlink socket * @module: pointer to the owning module (set to THIS_MODULE) * @mcgrps: multicast groups used by this family * @n_mcgrps: number of multicast groups @@ -84,6 +86,8 @@ struct genl_family { void (*post_doit)(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); + int (*bind)(int mcgrp); + void (*unbind)(int mcgrp); const struct genl_ops * ops; const struct genl_small_ops *small_ops; const struct genl_split_ops *split_ops; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 8c7af02f8454..50ec599a5cff 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1836,6 +1836,9 @@ static int genl_bind(struct net *net, int group) !ns_capable(net->user_ns, CAP_SYS_ADMIN)) ret = -EPERM; + if (family->bind) + family->bind(i); + break; } @@ -1843,12 +1846,39 @@ static int genl_bind(struct net *net, int group) return ret; } +static void genl_unbind(struct net *net, int group) +{ + const struct genl_family *family; + unsigned int id; + + down_read(&cb_lock); + + idr_for_each_entry(&genl_fam_idr, family, id) { + int i; + + if (family->n_mcgrps == 0) + continue; + + i = group - family->mcgrp_offset; + if (i < 0 || i >= family->n_mcgrps) + continue; + + if (family->unbind) + family->unbind(i); + + break; + } + + up_read(&cb_lock); +} + static int __net_init genl_pernet_init(struct net *net) { struct netlink_kernel_cfg cfg = { .input = genl_rcv, .flags = NL_CFG_F_NONROOT_RECV, .bind = genl_bind, + .unbind = genl_unbind, .release = genl_release, }; From ae94dc25fd73cb41df233a20ca638ba136cc5f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Tue, 13 Feb 2024 10:29:05 +0300 Subject: [PATCH 1258/2255] net: dsa: remove OF-based MDIO bus registration from DSA core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code block under the "!ds->user_mii_bus && ds->ops->phy_read" check under dsa_switch_setup() populates ds->user_mii_bus. The use of ds->user_mii_bus is inappropriate when the MDIO bus of the switch is described on the device tree [1]. For this reason, use this code block only for switches [with MDIO bus] probed on platform_data, and OF which the switch MDIO bus isn't described on the device tree. Therefore, remove OF-based MDIO bus registration as it's useless for these cases. These subdrivers which control switches [with MDIO bus] probed on OF, will lose the ability to register the MDIO bus OF-based: drivers/net/dsa/b53/b53_common.c drivers/net/dsa/lan9303-core.c drivers/net/dsa/vitesse-vsc73xx-core.c These subdrivers let the DSA core driver register the bus: - ds->ops->phy_read() and ds->ops->phy_write() are present. - ds->user_mii_bus is not populated. The commit fe7324b93222 ("net: dsa: OF-ware slave_mii_bus") which brought OF-based MDIO bus registration on the DSA core driver is reasonably recent and, in this time frame, there have been no device trees in the Linux repository that started describing the MDIO bus, or dt-bindings defining the MDIO bus for the switches these subdrivers control. So I don't expect any devices to be affected. The logic we encourage is that all subdrivers should register the switch MDIO bus on their own [2]. And, for subdrivers which control switches [with MDIO bus] probed on OF, this logic must be followed to support all cases properly: No switch MDIO bus defined: Populate ds->user_mii_bus, register the MDIO bus, set the interrupts for PHYs if "interrupt-controller" is defined at the switch node. This case should only be covered for the switches which their dt-bindings documentation didn't document the MDIO bus from the start. This is to keep supporting the device trees that do not describe the MDIO bus on the device tree but the MDIO bus is being used nonetheless. Switch MDIO bus defined: Don't populate ds->user_mii_bus, register the MDIO bus, set the interrupts for PHYs if ["interrupt-controller" is defined at the switch node and "interrupts" is defined at the PHY nodes under the switch MDIO bus node]. Switch MDIO bus defined but explicitly disabled: If the device tree says status = "disabled" for the MDIO bus, we shouldn't need an MDIO bus at all. Instead, just exit as early as possible and do not call any MDIO API. After all subdrivers that control switches with MDIO buses are made to register the MDIO buses on their own, we will be able to get rid of dsa_switch_ops :: phy_read() and :: phy_write(), and the code block for registering the MDIO bus on the DSA core driver. Link: https://lore.kernel.org/netdev/20231213120656.x46fyad6ls7sqyzv@skbuf/ [1] Link: https://lore.kernel.org/netdev/20240103184459.dcbh57wdnlox6w7d@skbuf/ [2] Suggested-by: Luiz Angelo Daros de Luca Acked-by: Luiz Angelo Daros de Luca Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/20240213-for-netnext-dsa-mdio-bus-v2-1-0ff6f4823a9e@arinc9.com Signed-off-by: Jakub Kicinski --- net/dsa/dsa.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ac7be864e80d..09d2f5d4b3dd 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -626,7 +625,6 @@ static void dsa_switch_teardown_tag_protocol(struct dsa_switch *ds) static int dsa_switch_setup(struct dsa_switch *ds) { - struct device_node *dn; int err; if (ds->setup) @@ -666,10 +664,7 @@ static int dsa_switch_setup(struct dsa_switch *ds) dsa_user_mii_bus_init(ds); - dn = of_get_child_by_name(ds->dev->of_node, "mdio"); - - err = of_mdiobus_register(ds->user_mii_bus, dn); - of_node_put(dn); + err = mdiobus_register(ds->user_mii_bus); if (err < 0) goto free_user_mii_bus; } From 31f26e4fec1fd9fd51efab0aee6b6c370b5e27e7 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 14 Feb 2024 17:21:28 +0800 Subject: [PATCH 1259/2255] selftests: bonding: make sure new active is not null One of Jakub's tests[1] shows that there may be period all ports are down and no active slave. This makes the new_active_slave null and the test fails. Add a check to make sure the new active is not null. [ 189.051966] br0: port 2(s1) entered disabled state [ 189.317881] bond0: (slave eth1): link status definitely down, disabling slave [ 189.318487] bond0: (slave eth2): making interface the new active one [ 190.435430] br0: port 4(s2) entered disabled state [ 190.773786] bond0: (slave eth0): link status definitely down, disabling slave [ 190.774204] bond0: (slave eth2): link status definitely down, disabling slave [ 190.774715] bond0: now running without any active interface! [ 190.877760] bond0: (slave eth0): link status definitely up [ 190.878098] bond0: (slave eth0): making interface the new active one [ 190.878495] bond0: active interface up! [ 191.802872] br0: port 4(s2) entered blocking state [ 191.803157] br0: port 4(s2) entered forwarding state [ 191.813756] bond0: (slave eth2): link status definitely up [ 192.847095] br0: port 2(s1) entered blocking state [ 192.847396] br0: port 2(s1) entered forwarding state [ 192.853740] bond0: (slave eth1): link status definitely up # TEST: prio (active-backup ns_ip6_target primary_reselect 1) [FAIL] # Current active slave is null but not eth0 [1] https://netdev-3.bots.linux.dev/vmksft-bonding/results/464481/1-bond-options-sh/stdout Fixes: 45bf79bc56c4 ("selftests: bonding: reduce garp_test/arp_validate test time") Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/bonding/bond_options.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/drivers/net/bonding/bond_options.sh b/tools/testing/selftests/drivers/net/bonding/bond_options.sh index 6fd0cff3e1e9..644ea5769e81 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond_options.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond_options.sh @@ -50,13 +50,13 @@ active_slave_changed() local old_active_slave=$1 local new_active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" \ ".[].linkinfo.info_data.active_slave") - test "$old_active_slave" != "$new_active_slave" + [ "$new_active_slave" != "$old_active_slave" -a "$new_active_slave" != "null" ] } check_active_slave() { local target_active_slave=$1 - slowwait 2 active_slave_changed $active_slave + slowwait 5 active_slave_changed $active_slave active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave") test "$active_slave" = "$target_active_slave" check_err $? "Current active slave is $active_slave but not $target_active_slave" From a260f080660ef8bac97404dd0b9ddbe35a608426 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 14 Feb 2024 15:57:55 +0200 Subject: [PATCH 1260/2255] net: ravb: Get rid of the temporary variable irq The 4th argument of ravb_setup_irq() is used to save the IRQ number that will be further used by the driver code. Not all ravb_setup_irqs() calls need to save the IRQ number. The previous code used to pass a dummy variable as the 4th argument in case the IRQ is not needed for further usage. That is not necessary as the code from ravb_setup_irq() can detect by itself if the IRQ needs to be saved. Thus, get rid of the code that is not needed. Reported-by: Sergey Shtylyov Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 29 +++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 529670852bd6..129965566c07 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2743,24 +2743,27 @@ static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name, struct device *dev = &pdev->dev; const char *dev_name; unsigned long flags; - int error; + int error, irq_num; if (irq_name) { dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch); if (!dev_name) return -ENOMEM; - *irq = platform_get_irq_byname(pdev, irq_name); + irq_num = platform_get_irq_byname(pdev, irq_name); flags = 0; } else { dev_name = ndev->name; - *irq = platform_get_irq(pdev, 0); + irq_num = platform_get_irq(pdev, 0); flags = IRQF_SHARED; } - if (*irq < 0) - return *irq; + if (irq_num < 0) + return irq_num; - error = devm_request_irq(dev, *irq, handler, flags, dev_name, ndev); + if (irq) + *irq = irq_num; + + error = devm_request_irq(dev, irq_num, handler, flags, dev_name, ndev); if (error) netdev_err(ndev, "cannot request IRQ %s\n", dev_name); @@ -2772,7 +2775,7 @@ static int ravb_setup_irqs(struct ravb_private *priv) const struct ravb_hw_info *info = priv->info; struct net_device *ndev = priv->ndev; const char *irq_name, *emac_irq_name; - int error, irq; + int error; if (!info->multi_irqs) return ravb_setup_irq(priv, NULL, NULL, &ndev->irq, ravb_interrupt); @@ -2795,28 +2798,28 @@ static int ravb_setup_irqs(struct ravb_private *priv) return error; if (info->err_mgmt_irqs) { - error = ravb_setup_irq(priv, "err_a", "err_a", &irq, ravb_multi_interrupt); + error = ravb_setup_irq(priv, "err_a", "err_a", NULL, ravb_multi_interrupt); if (error) return error; - error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", &irq, ravb_multi_interrupt); + error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", NULL, ravb_multi_interrupt); if (error) return error; } - error = ravb_setup_irq(priv, "ch0", "ch0:rx_be", &irq, ravb_be_interrupt); + error = ravb_setup_irq(priv, "ch0", "ch0:rx_be", NULL, ravb_be_interrupt); if (error) return error; - error = ravb_setup_irq(priv, "ch1", "ch1:rx_nc", &irq, ravb_nc_interrupt); + error = ravb_setup_irq(priv, "ch1", "ch1:rx_nc", NULL, ravb_nc_interrupt); if (error) return error; - error = ravb_setup_irq(priv, "ch18", "ch18:tx_be", &irq, ravb_be_interrupt); + error = ravb_setup_irq(priv, "ch18", "ch18:tx_be", NULL, ravb_be_interrupt); if (error) return error; - return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", &irq, ravb_nc_interrupt); + return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", NULL, ravb_nc_interrupt); } static int ravb_probe(struct platform_device *pdev) From a5f149a97d09cc9340d8fb4e22a3074a7bc1e02d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 14 Feb 2024 15:57:56 +0200 Subject: [PATCH 1261/2255] net: ravb: Keep the reverse order of operations in ravb_close() Keep the reverse order of operations in ravb_close() when compared with ravb_open(). This is the recommended configuration sequence. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 129965566c07..b2699c76ed9f 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2317,6 +2317,14 @@ static int ravb_close(struct net_device *ndev) ravb_write(ndev, 0, RIC2); ravb_write(ndev, 0, TIC); + /* PHY disconnect */ + if (ndev->phydev) { + phy_stop(ndev->phydev); + phy_disconnect(ndev->phydev); + if (of_phy_is_fixed_link(np)) + of_phy_deregister_fixed_link(np); + } + /* Stop PTP Clock driver */ if (info->gptp || info->ccc_gac) ravb_ptp_stop(ndev); @@ -2335,14 +2343,6 @@ static int ravb_close(struct net_device *ndev) } } - /* PHY disconnect */ - if (ndev->phydev) { - phy_stop(ndev->phydev); - phy_disconnect(ndev->phydev); - if (of_phy_is_fixed_link(np)) - of_phy_deregister_fixed_link(np); - } - cancel_work_sync(&priv->work); if (info->nc_queues) From bbf2345fa6582c5292bc5c537e7a29aad918be0c Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 14 Feb 2024 15:57:57 +0200 Subject: [PATCH 1262/2255] net: ravb: Return cached statistics if the interface is down Return the cached statistics in case the interface is down. There should be no drawback to this, as cached statistics are updated in ravb_close(). In order to avoid accessing the IP registers while the IP is runtime suspended pm_runtime_active() check was introduced. The device runtime PM usage counter has been incremented to avoid disabling the device clocks while the check is in progress (if any). The commit prepares the code for the addition of runtime PM support. Suggested-by: Sergey Shtylyov Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index b2699c76ed9f..8c4e5b52fbb8 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2244,8 +2244,15 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev) struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; struct net_device_stats *nstats, *stats0, *stats1; + struct device *dev = &priv->pdev->dev; nstats = &ndev->stats; + + pm_runtime_get_noresume(dev); + + if (!pm_runtime_active(dev)) + goto out_rpm_put; + stats0 = &priv->stats[RAVB_BE]; if (info->tx_counters) { @@ -2287,6 +2294,8 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev) nstats->rx_over_errors += stats1->rx_over_errors; } +out_rpm_put: + pm_runtime_put_noidle(dev); return nstats; } @@ -2354,6 +2363,9 @@ static int ravb_close(struct net_device *ndev) if (info->nc_queues) ravb_ring_free(ndev, RAVB_NC); + /* Update statistics. */ + ravb_get_stats(ndev); + /* Set reset mode. */ return ravb_set_opmode(ndev, CCC_OPC_RESET); } From 7bddccc9911cdff377e16b9a5a386721279b4438 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 14 Feb 2024 15:57:58 +0200 Subject: [PATCH 1263/2255] net: ravb: Move the update of ndev->features to ravb_set_features() Commit c2da9408579d ("ravb: Add Rx checksum offload support for GbEth") introduced support for setting GbEth features. With this the IP-specific features update functions update the ndev->features individually. Next commits add runtime PM support for the ravb driver. The runtime PM implementation will enable/disable the IP clocks on the ravb_open()/ravb_close() functions. Accessing the IP registers with clocks disabled blocks the system. The ravb_set_features() function could be executed when the Ethernet interface is closed so we need to ensure we don't access IP registers while the interface is down when runtime PM support will be in place. For these, move the update of ndev->features to ravb_set_features(). In this way we update the ndev->features only when the IP-specific features set function returns success and we can avoid code duplication when introducing runtime PM registers protection. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 8c4e5b52fbb8..1322eee524cc 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2538,7 +2538,6 @@ static int ravb_set_features_gbeth(struct net_device *ndev, goto done; } - ndev->features = features; done: spin_unlock_irqrestore(&priv->lock, flags); @@ -2553,8 +2552,6 @@ static int ravb_set_features_rcar(struct net_device *ndev, if (changed & NETIF_F_RXCSUM) ravb_set_rx_csum(ndev, features & NETIF_F_RXCSUM); - ndev->features = features; - return 0; } @@ -2563,8 +2560,15 @@ static int ravb_set_features(struct net_device *ndev, { struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; + int ret; - return info->set_feature(ndev, features); + ret = info->set_feature(ndev, features); + if (ret) + return ret; + + ndev->features = features; + + return 0; } static const struct net_device_ops ravb_netdev_ops = { From a71a50e391bf00fdc88bb13a867620c59ad744da Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 14 Feb 2024 15:57:59 +0200 Subject: [PATCH 1264/2255] net: ravb: Do not apply features to hardware if the interface is down Do not apply features to hardware if the interface is down. In case runtime PM is enabled, and while the interface is down, the IP will be in reset mode (as for some platforms disabling the clocks will switch the IP to reset mode, which will lead to losing register contents) and applying settings in reset mode is not an option. Instead, cache the features and apply them in ravb_open() through ravb_emac_init(). To avoid accessing the hardware while the interface is down pm_runtime_active() check was introduced. Along with it the device runtime PM usage counter has been incremented to avoid disabling the device clocks while the check is in progress (if any). Commit prepares for the addition of runtime PM. Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 1322eee524cc..a74348eb7ba1 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2560,9 +2560,18 @@ static int ravb_set_features(struct net_device *ndev, { struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; + struct device *dev = &priv->pdev->dev; int ret; - ret = info->set_feature(ndev, features); + pm_runtime_get_noresume(dev); + + if (pm_runtime_active(dev)) + ret = info->set_feature(ndev, features); + else + ret = 0; + + pm_runtime_put_noidle(dev); + if (ret) return ret; From 48f894ab07c444b9b26a0913d2032de663f4aecb Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 14 Feb 2024 15:58:00 +0200 Subject: [PATCH 1265/2255] net: ravb: Add runtime PM support Add runtime PM support for the ravb driver. As the driver is used by different IP variants, with different behaviors, to be able to have the runtime PM support available for all devices, the preparatory commits moved all the resources parsing and allocations in the driver's probe function and kept the settings for ravb_open(). This is due to the fact that on some IP variants-platforms tuples disabling/enabling the clocks will switch the IP to the reset operation mode where register contents is lost and reconfiguration needs to be done. For this the rabv_open() function enables the clocks, switches the IP to configuration mode, applies all the register settings and switches the IP to the operational mode. At the end of ravb_open() IP is ready to send/receive data. In ravb_close() necessary reverts are done (compared with ravb_open()), the IP is switched to reset mode and clocks are disabled. The ethtool APIs or IOCTLs that might execute while the interface is down are either cached (and applied in ravb_open()) or rejected (as at that time the IP is in reset mode). Keeping the IP in the reset mode also increases the power saved (according to the hardware manual). Signed-off-by: Claudiu Beznea Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 54 ++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index a74348eb7ba1..f9fb772b05c7 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1935,16 +1935,21 @@ static int ravb_open(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; + struct device *dev = &priv->pdev->dev; int error; napi_enable(&priv->napi[RAVB_BE]); if (info->nc_queues) napi_enable(&priv->napi[RAVB_NC]); + error = pm_runtime_resume_and_get(dev); + if (error < 0) + goto out_napi_off; + /* Set AVB config mode */ error = ravb_set_config_mode(ndev); if (error) - goto out_napi_off; + goto out_rpm_put; ravb_set_delay_mode(ndev); ravb_write(ndev, priv->desc_bat_dma, DBAT); @@ -1978,6 +1983,9 @@ out_ptp_stop: ravb_stop_dma(ndev); out_set_reset: ravb_set_opmode(ndev, CCC_OPC_RESET); +out_rpm_put: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); out_napi_off: if (info->nc_queues) napi_disable(&priv->napi[RAVB_NC]); @@ -2318,6 +2326,8 @@ static int ravb_close(struct net_device *ndev) struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; struct ravb_tstamp_skb *ts_skb, *ts_skb2; + struct device *dev = &priv->pdev->dev; + int error; netif_tx_stop_all_queues(ndev); @@ -2367,7 +2377,14 @@ static int ravb_close(struct net_device *ndev) ravb_get_stats(ndev); /* Set reset mode. */ - return ravb_set_opmode(ndev, CCC_OPC_RESET); + error = ravb_set_opmode(ndev, CCC_OPC_RESET); + if (error) + return error; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; } static int ravb_hwtstamp_get(struct net_device *ndev, struct ifreq *req) @@ -2922,6 +2939,8 @@ static int ravb_probe(struct platform_device *pdev) clk_prepare(priv->refclk); platform_set_drvdata(pdev, ndev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); error = pm_runtime_resume_and_get(&pdev->dev); if (error < 0) @@ -3027,6 +3046,9 @@ static int ravb_probe(struct platform_device *pdev) netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n", (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; out_napi_del: @@ -3044,6 +3066,7 @@ out_rpm_put: pm_runtime_put(&pdev->dev); out_rpm_disable: pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); clk_unprepare(priv->refclk); out_reset_assert: reset_control_assert(rstc); @@ -3057,6 +3080,12 @@ static void ravb_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *info = priv->info; + struct device *dev = &priv->pdev->dev; + int error; + + error = pm_runtime_resume_and_get(dev); + if (error < 0) + return; unregister_netdev(ndev); if (info->nc_queues) @@ -3068,8 +3097,9 @@ static void ravb_remove(struct platform_device *pdev) dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat, priv->desc_bat_dma); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync_suspend(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(dev); clk_unprepare(priv->refclk); reset_control_assert(priv->rstc); free_netdev(ndev); @@ -3151,6 +3181,10 @@ static int ravb_suspend(struct device *dev) if (ret) return ret; + ret = pm_runtime_force_suspend(&priv->pdev->dev); + if (ret) + return ret; + reset_assert: return reset_control_assert(priv->rstc); } @@ -3173,16 +3207,28 @@ static int ravb_resume(struct device *dev) ret = ravb_wol_restore(ndev); if (ret) return ret; + } else { + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; } /* Reopening the interface will restore the device to the working state. */ ret = ravb_open(ndev); if (ret < 0) - return ret; + goto out_rpm_put; ravb_set_rx_mode(ndev); netif_device_attach(ndev); + return 0; + +out_rpm_put: + if (!priv->wol_enabled) { + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } + return ret; } From 2210c5485e4331d0abd7a0296f10178d1dc25cd2 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 14 Feb 2024 09:47:07 +0100 Subject: [PATCH 1266/2255] net/iucv: fix virtual vs physical address confusion Fix virtual vs physical address confusion. This does not fix a bug since virtual and physical address spaces are currently the same. Acked-by: Alexandra Winter Signed-off-by: Alexander Gordeev Signed-off-by: David S. Miller --- net/iucv/iucv.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 6334f64f04d5..9e62783e6acb 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -286,6 +286,7 @@ static union iucv_param *iucv_param_irq[NR_CPUS]; */ static inline int __iucv_call_b2f0(int command, union iucv_param *parm) { + unsigned long reg1 = virt_to_phys(parm); int cc; asm volatile( @@ -296,7 +297,7 @@ static inline int __iucv_call_b2f0(int command, union iucv_param *parm) " srl %[cc],28\n" : [cc] "=&d" (cc), "+m" (*parm) : [reg0] "d" ((unsigned long)command), - [reg1] "d" ((unsigned long)parm) + [reg1] "d" (reg1) : "cc", "0", "1"); return cc; } @@ -1123,7 +1124,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); - parm->db.ipbfadr1 = (u32)(addr_t) buffer; + parm->db.ipbfadr1 = (u32)virt_to_phys(buffer); parm->db.ipbfln1f = (u32) size; parm->db.ipmsgid = msg->id; parm->db.ippathid = path->pathid; @@ -1241,7 +1242,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, parm->dpl.iptrgcls = msg->class; memcpy(parm->dpl.iprmmsg, reply, min_t(size_t, size, 8)); } else { - parm->db.ipbfadr1 = (u32)(addr_t) reply; + parm->db.ipbfadr1 = (u32)virt_to_phys(reply); parm->db.ipbfln1f = (u32) size; parm->db.ippathid = path->pathid; parm->db.ipflags1 = flags; @@ -1293,7 +1294,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, parm->dpl.ipmsgtag = msg->tag; memcpy(parm->dpl.iprmmsg, buffer, 8); } else { - parm->db.ipbfadr1 = (u32)(addr_t) buffer; + parm->db.ipbfadr1 = (u32)virt_to_phys(buffer); parm->db.ipbfln1f = (u32) size; parm->db.ippathid = path->pathid; parm->db.ipflags1 = flags | IUCV_IPNORPY; @@ -1378,7 +1379,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, parm->dpl.iptrgcls = msg->class; parm->dpl.ipsrccls = srccls; parm->dpl.ipmsgtag = msg->tag; - parm->dpl.ipbfadr2 = (u32)(addr_t) answer; + parm->dpl.ipbfadr2 = (u32)virt_to_phys(answer); parm->dpl.ipbfln2f = (u32) asize; memcpy(parm->dpl.iprmmsg, buffer, 8); } else { @@ -1387,9 +1388,9 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, parm->db.iptrgcls = msg->class; parm->db.ipsrccls = srccls; parm->db.ipmsgtag = msg->tag; - parm->db.ipbfadr1 = (u32)(addr_t) buffer; + parm->db.ipbfadr1 = (u32)virt_to_phys(buffer); parm->db.ipbfln1f = (u32) size; - parm->db.ipbfadr2 = (u32)(addr_t) answer; + parm->db.ipbfadr2 = (u32)virt_to_phys(answer); parm->db.ipbfln2f = (u32) asize; } rc = iucv_call_b2f0(IUCV_SEND, parm); From c699f35d658f3c21b69ed24e64b2ea26381e941d Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:01 -0800 Subject: [PATCH 1267/2255] ionic: set adminq irq affinity We claim to have the AdminQ on our irq0 and thus cpu id 0, but we need to be sure we set the affinity hint to try to keep it there. Signed-off-by: Shannon Nelson Reviewed-by: Brett Creeley Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index cf2d5ad7b68c..d92f8734d153 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -3391,9 +3391,12 @@ static int ionic_lif_adminq_init(struct ionic_lif *lif) napi_enable(&qcq->napi); - if (qcq->flags & IONIC_QCQ_F_INTR) + if (qcq->flags & IONIC_QCQ_F_INTR) { + irq_set_affinity_hint(qcq->intr.vector, + &qcq->intr.affinity_mask); ionic_intr_mask(idev->intr_ctrl, qcq->intr.index, IONIC_INTR_MASK_CLEAR); + } qcq->flags |= IONIC_QCQ_F_INITED; From 97538c146cca50dc6cd3d37b5ddcb43c6fc10a46 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:02 -0800 Subject: [PATCH 1268/2255] ionic: add helpers for accessing buffer info These helpers clean up some of the code around DMA mapping and other buffer references, and will be used in the next few patches for the XDP support. Signed-off-by: Shannon Nelson Reviewed-by: Brett Creeley Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_txrx.c | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 6f4776759863..acc1343113c2 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -88,6 +88,21 @@ static inline struct netdev_queue *q_to_ndq(struct ionic_queue *q) return netdev_get_tx_queue(q->lif->netdev, q->index); } +static void *ionic_rx_buf_va(struct ionic_buf_info *buf_info) +{ + return page_address(buf_info->page) + buf_info->page_offset; +} + +static dma_addr_t ionic_rx_buf_pa(struct ionic_buf_info *buf_info) +{ + return buf_info->dma_addr + buf_info->page_offset; +} + +static unsigned int ionic_rx_buf_size(struct ionic_buf_info *buf_info) +{ + return min_t(u32, IONIC_MAX_BUF_LEN, IONIC_PAGE_SIZE - buf_info->page_offset); +} + static int ionic_rx_page_alloc(struct ionic_queue *q, struct ionic_buf_info *buf_info) { @@ -207,12 +222,11 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, return NULL; } - frag_len = min_t(u16, len, min_t(u32, IONIC_MAX_BUF_LEN, - IONIC_PAGE_SIZE - buf_info->page_offset)); + frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); len -= frag_len; dma_sync_single_for_cpu(dev, - buf_info->dma_addr + buf_info->page_offset, + ionic_rx_buf_pa(buf_info), frag_len, DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, @@ -262,10 +276,10 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, return NULL; } - dma_sync_single_for_cpu(dev, buf_info->dma_addr + buf_info->page_offset, + dma_sync_single_for_cpu(dev, ionic_rx_buf_pa(buf_info), len, DMA_FROM_DEVICE); - skb_copy_to_linear_data(skb, page_address(buf_info->page) + buf_info->page_offset, len); - dma_sync_single_for_device(dev, buf_info->dma_addr + buf_info->page_offset, + skb_copy_to_linear_data(skb, ionic_rx_buf_va(buf_info), len); + dma_sync_single_for_device(dev, ionic_rx_buf_pa(buf_info), len, DMA_FROM_DEVICE); skb_put(skb, len); @@ -452,9 +466,8 @@ void ionic_rx_fill(struct ionic_queue *q) } /* fill main descriptor - buf[0] */ - desc->addr = cpu_to_le64(buf_info->dma_addr + buf_info->page_offset); - frag_len = min_t(u16, len, min_t(u32, IONIC_MAX_BUF_LEN, - IONIC_PAGE_SIZE - buf_info->page_offset)); + desc->addr = cpu_to_le64(ionic_rx_buf_pa(buf_info)); + frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); desc->len = cpu_to_le16(frag_len); remain_len -= frag_len; buf_info++; @@ -472,10 +485,8 @@ void ionic_rx_fill(struct ionic_queue *q) } } - sg_elem->addr = cpu_to_le64(buf_info->dma_addr + buf_info->page_offset); - frag_len = min_t(u16, remain_len, min_t(u32, IONIC_MAX_BUF_LEN, - IONIC_PAGE_SIZE - - buf_info->page_offset)); + sg_elem->addr = cpu_to_le64(ionic_rx_buf_pa(buf_info)); + frag_len = min_t(u16, remain_len, ionic_rx_buf_size(buf_info)); sg_elem->len = cpu_to_le16(frag_len); remain_len -= frag_len; buf_info++; From d67ee210dafd0a3f3d65ed2d01027cd0e0de93d6 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:03 -0800 Subject: [PATCH 1269/2255] ionic: use dma range APIs Convert Rx datapath handling to use the DMA range APIs in preparation for adding XDP handling. Signed-off-by: Shannon Nelson Reviewed-by: Brett Creeley Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index acc1343113c2..9865cad61649 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -225,9 +225,8 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); len -= frag_len; - dma_sync_single_for_cpu(dev, - ionic_rx_buf_pa(buf_info), - frag_len, DMA_FROM_DEVICE); + dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), + 0, frag_len, DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, buf_info->page, buf_info->page_offset, frag_len, @@ -276,11 +275,11 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, return NULL; } - dma_sync_single_for_cpu(dev, ionic_rx_buf_pa(buf_info), - len, DMA_FROM_DEVICE); + dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), + 0, len, DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, ionic_rx_buf_va(buf_info), len); - dma_sync_single_for_device(dev, ionic_rx_buf_pa(buf_info), - len, DMA_FROM_DEVICE); + dma_sync_single_range_for_device(dev, ionic_rx_buf_pa(buf_info), + 0, len, DMA_FROM_DEVICE); skb_put(skb, len); skb->protocol = eth_type_trans(skb, q->lif->netdev); From 180e35cdf035d1c2e9ebdc06a9944a9eb81cc3d8 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:04 -0800 Subject: [PATCH 1270/2255] ionic: add initial framework for XDP support Set up the basics for running Rx packets through XDP programs. Add new queue setup and teardown steps for adding/removing an XDP program, and add the call to run the XDP on a packet. The XDP frame size needs to be the MTU plus standard ethernet header, plus head room for XDP scribblings and tail room for a struct skb_shared_info. Also, at this point, we don't support XDP frags, only a single contiguous Rx buffer. This means that our page splitting is not very useful, so when XDP is in use we need to use the full Rx buffer size and not do sharing. Co-developed-by: Brett Creeley Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_dev.h | 7 + .../ethernet/pensando/ionic/ionic_ethtool.c | 5 + .../net/ethernet/pensando/ionic/ionic_lif.c | 175 +++++++++++++++++- .../net/ethernet/pensando/ionic/ionic_lif.h | 7 + .../net/ethernet/pensando/ionic/ionic_stats.c | 9 + .../net/ethernet/pensando/ionic/ionic_txrx.c | 80 ++++++-- 6 files changed, 269 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 2667e1cde16b..70f5725fdfe8 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "ionic_if.h" #include "ionic_regs.h" @@ -195,6 +196,11 @@ typedef void (*ionic_desc_cb)(struct ionic_queue *q, #define IONIC_PAGE_GFP_MASK (GFP_ATOMIC | __GFP_NOWARN |\ __GFP_COMP | __GFP_MEMALLOC) +#define IONIC_XDP_MAX_LINEAR_MTU (IONIC_PAGE_SIZE - \ + (VLAN_ETH_HLEN + \ + XDP_PACKET_HEADROOM + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))) + struct ionic_buf_info { struct page *page; dma_addr_t dma_addr; @@ -256,6 +262,7 @@ struct ionic_queue { struct ionic_txq_sg_desc *txq_sgl; struct ionic_rxq_sg_desc *rxq_sgl; }; + struct xdp_rxq_info *xdp_rxq_info; dma_addr_t base_pa; dma_addr_t cmb_base_pa; dma_addr_t sg_base_pa; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index cd3c0b01402e..98df2ee11c51 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -721,6 +721,11 @@ static int ionic_set_channels(struct net_device *netdev, ionic_init_queue_params(lif, &qparam); + if ((ch->rx_count || ch->tx_count) && lif->xdp_prog) { + netdev_info(lif->netdev, "Split Tx/Rx interrupts not available when using XDP\n"); + return -EOPNOTSUPP; + } + if (ch->rx_count != ch->tx_count) { netdev_info(netdev, "The rx and tx count must be equal\n"); return -EINVAL; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index d92f8734d153..d8c83ff47b66 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -46,6 +46,9 @@ static int ionic_start_queues(struct ionic_lif *lif); static void ionic_stop_queues(struct ionic_lif *lif); static void ionic_lif_queue_identify(struct ionic_lif *lif); +static int ionic_xdp_queues_config(struct ionic_lif *lif); +static void ionic_xdp_unregister_rxq_info(struct ionic_queue *q); + static void ionic_dim_work(struct work_struct *work) { struct dim *dim = container_of(work, struct dim, work); @@ -422,6 +425,7 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq) qcq->sg_base_pa = 0; } + ionic_xdp_unregister_rxq_info(&qcq->q); ionic_qcq_intr_free(lif, qcq); vfree(qcq->cq.info); @@ -862,8 +866,7 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) .type = q->type, .ver = lif->qtype_info[q->type].version, .index = cpu_to_le32(q->index), - .flags = cpu_to_le16(IONIC_QINIT_F_IRQ | - IONIC_QINIT_F_SG), + .flags = cpu_to_le16(IONIC_QINIT_F_IRQ), .intr_index = cpu_to_le16(cq->bound_intr->index), .pid = cpu_to_le16(q->pid), .ring_size = ilog2(q->num_descs), @@ -875,6 +878,9 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) }; int err; + if (!lif->xdp_prog) + ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_SG); + if (qcq->flags & IONIC_QCQ_F_CMB_RINGS) { ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_CMB); ctx.cmd.q_init.ring_base = cpu_to_le64(qcq->cmb_q_base_pa); @@ -1640,6 +1646,8 @@ static int ionic_init_nic_features(struct ionic_lif *lif) netdev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE; + netdev->xdp_features = NETDEV_XDP_ACT_BASIC; + return 0; } @@ -1777,6 +1785,18 @@ static int ionic_start_queues_reconfig(struct ionic_lif *lif) return err; } +static bool ionic_xdp_is_valid_mtu(struct ionic_lif *lif, u32 mtu, + struct bpf_prog *xdp_prog) +{ + if (!xdp_prog) + return true; + + if (mtu <= IONIC_XDP_MAX_LINEAR_MTU) + return true; + + return false; +} + static int ionic_change_mtu(struct net_device *netdev, int new_mtu) { struct ionic_lif *lif = netdev_priv(netdev); @@ -1789,8 +1809,13 @@ static int ionic_change_mtu(struct net_device *netdev, int new_mtu) .mtu = cpu_to_le32(new_mtu), }, }; + struct bpf_prog *xdp_prog; int err; + xdp_prog = READ_ONCE(lif->xdp_prog); + if (!ionic_xdp_is_valid_mtu(lif, new_mtu, xdp_prog)) + return -EINVAL; + err = ionic_adminq_post_wait(lif, &ctx); if (err) return err; @@ -2166,6 +2191,10 @@ static int ionic_txrx_enable(struct ionic_lif *lif) int derr = 0; int i, err; + err = ionic_xdp_queues_config(lif); + if (err) + return err; + for (i = 0; i < lif->nxqs; i++) { if (!(lif->rxqcqs[i] && lif->txqcqs[i])) { dev_err(lif->ionic->dev, "%s: bad qcq %d\n", __func__, i); @@ -2211,6 +2240,8 @@ err_out: derr = ionic_qcq_disable(lif, lif->rxqcqs[i], derr); } + ionic_xdp_queues_config(lif); + return err; } @@ -2668,11 +2699,150 @@ static void ionic_vf_attr_replay(struct ionic_lif *lif) ionic_vf_start(ionic); } +static void ionic_xdp_unregister_rxq_info(struct ionic_queue *q) +{ + struct xdp_rxq_info *xi; + + if (!q->xdp_rxq_info) + return; + + xi = q->xdp_rxq_info; + q->xdp_rxq_info = NULL; + + xdp_rxq_info_unreg(xi); + kfree(xi); +} + +static int ionic_xdp_register_rxq_info(struct ionic_queue *q, unsigned int napi_id) +{ + struct xdp_rxq_info *rxq_info; + int err; + + rxq_info = kzalloc(sizeof(*rxq_info), GFP_KERNEL); + if (!rxq_info) + return -ENOMEM; + + err = xdp_rxq_info_reg(rxq_info, q->lif->netdev, q->index, napi_id); + if (err) { + dev_err(q->dev, "Queue %d xdp_rxq_info_reg failed, err %d\n", + q->index, err); + goto err_out; + } + + err = xdp_rxq_info_reg_mem_model(rxq_info, MEM_TYPE_PAGE_ORDER0, NULL); + if (err) { + dev_err(q->dev, "Queue %d xdp_rxq_info_reg_mem_model failed, err %d\n", + q->index, err); + xdp_rxq_info_unreg(rxq_info); + goto err_out; + } + + q->xdp_rxq_info = rxq_info; + + return 0; + +err_out: + kfree(rxq_info); + return err; +} + +static int ionic_xdp_queues_config(struct ionic_lif *lif) +{ + unsigned int i; + int err; + + if (!lif->rxqcqs) + return 0; + + /* There's no need to rework memory if not going to/from NULL program. + * If there is no lif->xdp_prog, there should also be no q.xdp_rxq_info + * This way we don't need to keep an *xdp_prog in every queue struct. + */ + if (!lif->xdp_prog == !lif->rxqcqs[0]->q.xdp_rxq_info) + return 0; + + for (i = 0; i < lif->ionic->nrxqs_per_lif && lif->rxqcqs[i]; i++) { + struct ionic_queue *q = &lif->rxqcqs[i]->q; + + if (q->xdp_rxq_info) { + ionic_xdp_unregister_rxq_info(q); + continue; + } + + err = ionic_xdp_register_rxq_info(q, lif->rxqcqs[i]->napi.napi_id); + if (err) { + dev_err(lif->ionic->dev, "failed to register RX queue %d info for XDP, err %d\n", + i, err); + goto err_out; + } + } + + return 0; + +err_out: + for (i = 0; i < lif->ionic->nrxqs_per_lif && lif->rxqcqs[i]; i++) + ionic_xdp_unregister_rxq_info(&lif->rxqcqs[i]->q); + + return err; +} + +static int ionic_xdp_config(struct net_device *netdev, struct netdev_bpf *bpf) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct bpf_prog *old_prog; + u32 maxfs; + + if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) { +#define XDP_ERR_SPLIT "XDP not available with split Tx/Rx interrupts" + NL_SET_ERR_MSG_MOD(bpf->extack, XDP_ERR_SPLIT); + netdev_info(lif->netdev, XDP_ERR_SPLIT); + return -EOPNOTSUPP; + } + + if (!ionic_xdp_is_valid_mtu(lif, netdev->mtu, bpf->prog)) { +#define XDP_ERR_MTU "MTU is too large for XDP without frags support" + NL_SET_ERR_MSG_MOD(bpf->extack, XDP_ERR_MTU); + netdev_info(lif->netdev, XDP_ERR_MTU); + return -EINVAL; + } + + maxfs = __le32_to_cpu(lif->identity->eth.max_frame_size) - VLAN_ETH_HLEN; + if (bpf->prog) + maxfs = min_t(u32, maxfs, IONIC_XDP_MAX_LINEAR_MTU); + netdev->max_mtu = maxfs; + + if (!netif_running(netdev)) { + old_prog = xchg(&lif->xdp_prog, bpf->prog); + } else { + mutex_lock(&lif->queue_lock); + ionic_stop_queues_reconfig(lif); + old_prog = xchg(&lif->xdp_prog, bpf->prog); + ionic_start_queues_reconfig(lif); + mutex_unlock(&lif->queue_lock); + } + + if (old_prog) + bpf_prog_put(old_prog); + + return 0; +} + +static int ionic_xdp(struct net_device *netdev, struct netdev_bpf *bpf) +{ + switch (bpf->command) { + case XDP_SETUP_PROG: + return ionic_xdp_config(netdev, bpf); + default: + return -EINVAL; + } +} + static const struct net_device_ops ionic_netdev_ops = { .ndo_open = ionic_open, .ndo_stop = ionic_stop, .ndo_eth_ioctl = ionic_eth_ioctl, .ndo_start_xmit = ionic_start_xmit, + .ndo_bpf = ionic_xdp, .ndo_get_stats64 = ionic_get_stats64, .ndo_set_rx_mode = ionic_ndo_set_rx_mode, .ndo_set_features = ionic_set_features, @@ -2755,6 +2925,7 @@ static void ionic_swap_queues(struct ionic_qcq *a, struct ionic_qcq *b) swap(a->q.base, b->q.base); swap(a->q.base_pa, b->q.base_pa); swap(a->q.info, b->q.info); + swap(a->q.xdp_rxq_info, b->q.xdp_rxq_info); swap(a->q_base, b->q_base); swap(a->q_base_pa, b->q_base_pa); swap(a->q_size, b->q_size); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 61548b3eea93..61fa4ea4f04c 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -51,6 +51,9 @@ struct ionic_rx_stats { u64 alloc_err; u64 hwstamp_valid; u64 hwstamp_invalid; + u64 xdp_drop; + u64 xdp_aborted; + u64 xdp_pass; }; #define IONIC_QCQ_F_INITED BIT(0) @@ -135,6 +138,9 @@ struct ionic_lif_sw_stats { u64 hw_rx_over_errors; u64 hw_rx_missed_errors; u64 hw_tx_aborted_errors; + u64 xdp_drop; + u64 xdp_aborted; + u64 xdp_pass; }; enum ionic_lif_state_flags { @@ -230,6 +236,7 @@ struct ionic_lif { struct ionic_phc *phc; struct dentry *dentry; + struct bpf_prog *xdp_prog; }; struct ionic_phc { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c index 1f6022fb7679..2fb20173b2c6 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c @@ -27,6 +27,9 @@ static const struct ionic_stat_desc ionic_lif_stats_desc[] = { IONIC_LIF_STAT_DESC(hw_rx_over_errors), IONIC_LIF_STAT_DESC(hw_rx_missed_errors), IONIC_LIF_STAT_DESC(hw_tx_aborted_errors), + IONIC_LIF_STAT_DESC(xdp_drop), + IONIC_LIF_STAT_DESC(xdp_aborted), + IONIC_LIF_STAT_DESC(xdp_pass), }; static const struct ionic_stat_desc ionic_port_stats_desc[] = { @@ -149,6 +152,9 @@ static const struct ionic_stat_desc ionic_rx_stats_desc[] = { IONIC_RX_STAT_DESC(hwstamp_invalid), IONIC_RX_STAT_DESC(dropped), IONIC_RX_STAT_DESC(vlan_stripped), + IONIC_RX_STAT_DESC(xdp_drop), + IONIC_RX_STAT_DESC(xdp_aborted), + IONIC_RX_STAT_DESC(xdp_pass), }; #define IONIC_NUM_LIF_STATS ARRAY_SIZE(ionic_lif_stats_desc) @@ -185,6 +191,9 @@ static void ionic_add_lif_rxq_stats(struct ionic_lif *lif, int q_num, stats->rx_csum_error += rxstats->csum_error; stats->rx_hwstamp_valid += rxstats->hwstamp_valid; stats->rx_hwstamp_invalid += rxstats->hwstamp_invalid; + stats->xdp_drop += rxstats->xdp_drop; + stats->xdp_aborted += rxstats->xdp_aborted; + stats->xdp_pass += rxstats->xdp_pass; } static void ionic_get_lif_stats(struct ionic_lif *lif, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 9865cad61649..a1772263d84b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -177,7 +177,7 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q, if (page_to_nid(buf_info->page) != numa_mem_id()) return false; - size = ALIGN(used, IONIC_PAGE_SPLIT_SZ); + size = ALIGN(used, q->xdp_rxq_info ? IONIC_PAGE_SIZE : IONIC_PAGE_SPLIT_SZ); buf_info->page_offset += size; if (buf_info->page_offset >= IONIC_PAGE_SIZE) return false; @@ -189,7 +189,8 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q, static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct ionic_rxq_comp *comp) + struct ionic_rxq_comp *comp, + bool synced) { struct net_device *netdev = q->lif->netdev; struct ionic_buf_info *buf_info; @@ -225,8 +226,9 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); len -= frag_len; - dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), - 0, frag_len, DMA_FROM_DEVICE); + if (!synced) + dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), + 0, frag_len, DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, buf_info->page, buf_info->page_offset, frag_len, @@ -248,7 +250,8 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct ionic_rxq_comp *comp) + struct ionic_rxq_comp *comp, + bool synced) { struct net_device *netdev = q->lif->netdev; struct ionic_buf_info *buf_info; @@ -275,8 +278,9 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, return NULL; } - dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), - 0, len, DMA_FROM_DEVICE); + if (!synced) + dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), + 0, len, DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, ionic_rx_buf_va(buf_info), len); dma_sync_single_range_for_device(dev, ionic_rx_buf_pa(buf_info), 0, len, DMA_FROM_DEVICE); @@ -287,6 +291,50 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, return skb; } +static bool ionic_run_xdp(struct ionic_rx_stats *stats, + struct net_device *netdev, + struct bpf_prog *xdp_prog, + struct ionic_queue *rxq, + struct ionic_buf_info *buf_info, + int len) +{ + u32 xdp_action = XDP_ABORTED; + struct xdp_buff xdp_buf; + + xdp_init_buff(&xdp_buf, IONIC_PAGE_SIZE, rxq->xdp_rxq_info); + xdp_prepare_buff(&xdp_buf, ionic_rx_buf_va(buf_info), + 0, len, false); + + dma_sync_single_range_for_cpu(rxq->dev, ionic_rx_buf_pa(buf_info), + 0, len, + DMA_FROM_DEVICE); + + prefetchw(&xdp_buf.data_hard_start); + + xdp_action = bpf_prog_run_xdp(xdp_prog, &xdp_buf); + + switch (xdp_action) { + case XDP_PASS: + stats->xdp_pass++; + return false; /* false = we didn't consume the packet */ + + case XDP_DROP: + ionic_rx_page_free(rxq, buf_info); + stats->xdp_drop++; + break; + + case XDP_TX: + case XDP_REDIRECT: + case XDP_ABORTED: + default: + trace_xdp_exception(netdev, xdp_prog, xdp_action); + ionic_rx_page_free(rxq, buf_info); + stats->xdp_aborted++; + } + + return true; +} + static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_info, struct ionic_cq_info *cq_info, @@ -296,7 +344,9 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_qcq *qcq = q_to_qcq(q); struct ionic_rx_stats *stats; struct ionic_rxq_comp *comp; + struct bpf_prog *xdp_prog; struct sk_buff *skb; + u16 len; comp = cq_info->cq_desc + qcq->cq.desc_size - sizeof(*comp); @@ -307,13 +357,19 @@ static void ionic_rx_clean(struct ionic_queue *q, return; } + len = le16_to_cpu(comp->len); stats->pkts++; - stats->bytes += le16_to_cpu(comp->len); + stats->bytes += len; - if (le16_to_cpu(comp->len) <= q->lif->rx_copybreak) - skb = ionic_rx_copybreak(q, desc_info, comp); + xdp_prog = READ_ONCE(q->lif->xdp_prog); + if (xdp_prog && + ionic_run_xdp(stats, netdev, xdp_prog, q, desc_info->bufs, len)) + return; + + if (len <= q->lif->rx_copybreak) + skb = ionic_rx_copybreak(q, desc_info, comp, !!xdp_prog); else - skb = ionic_rx_frags(q, desc_info, comp); + skb = ionic_rx_frags(q, desc_info, comp, !!xdp_prog); if (unlikely(!skb)) { stats->dropped++; @@ -380,7 +436,7 @@ static void ionic_rx_clean(struct ionic_queue *q, } } - if (le16_to_cpu(comp->len) <= q->lif->rx_copybreak) + if (len <= q->lif->rx_copybreak) napi_gro_receive(&qcq->napi, skb); else napi_gro_frags(&qcq->napi); From f81da39bf4c0a544d057330d3c3c93336307ea51 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:05 -0800 Subject: [PATCH 1271/2255] ionic: Add XDP packet headroom If an xdp program is loaded, add headroom at the beginning of the frame to allow for editing and insertions that an XDP program might need room for, and tailroom used later for XDP frame tracking. These are only needed in the first Rx buffer in a packet, not for any trailing frags. Co-developed-by: Brett Creeley Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_txrx.c | 68 ++++++++++++------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index a1772263d84b..a4f6dd5030c0 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -189,7 +189,9 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q, static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct ionic_rxq_comp *comp, + unsigned int headroom, + unsigned int len, + unsigned int num_sg_elems, bool synced) { struct net_device *netdev = q->lif->netdev; @@ -199,12 +201,10 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, struct sk_buff *skb; unsigned int i; u16 frag_len; - u16 len; stats = q_to_rx_stats(q); buf_info = &desc_info->bufs[0]; - len = le16_to_cpu(comp->len); prefetchw(buf_info->page); @@ -216,23 +216,26 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, return NULL; } - i = comp->num_sg_elems + 1; + i = num_sg_elems + 1; do { if (unlikely(!buf_info->page)) { dev_kfree_skb(skb); return NULL; } - frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); + if (headroom) + frag_len = min_t(u16, len, IONIC_XDP_MAX_LINEAR_MTU + VLAN_ETH_HLEN); + else + frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); len -= frag_len; if (!synced) dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), - 0, frag_len, DMA_FROM_DEVICE); + headroom, frag_len, DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - buf_info->page, buf_info->page_offset, frag_len, - IONIC_PAGE_SIZE); + buf_info->page, buf_info->page_offset + headroom, + frag_len, IONIC_PAGE_SIZE); if (!ionic_rx_buf_recycle(q, buf_info, frag_len)) { dma_unmap_page(dev, buf_info->dma_addr, @@ -240,6 +243,10 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, buf_info->page = NULL; } + /* only needed on the first buffer */ + if (headroom) + headroom = 0; + buf_info++; i--; @@ -250,7 +257,8 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct ionic_rxq_comp *comp, + unsigned int headroom, + unsigned int len, bool synced) { struct net_device *netdev = q->lif->netdev; @@ -258,12 +266,10 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, struct ionic_rx_stats *stats; struct device *dev = q->dev; struct sk_buff *skb; - u16 len; stats = q_to_rx_stats(q); buf_info = &desc_info->bufs[0]; - len = le16_to_cpu(comp->len); skb = napi_alloc_skb(&q_to_qcq(q)->napi, len); if (unlikely(!skb)) { @@ -280,10 +286,10 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, if (!synced) dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info), - 0, len, DMA_FROM_DEVICE); - skb_copy_to_linear_data(skb, ionic_rx_buf_va(buf_info), len); + headroom, len, DMA_FROM_DEVICE); + skb_copy_to_linear_data(skb, ionic_rx_buf_va(buf_info) + headroom, len); dma_sync_single_range_for_device(dev, ionic_rx_buf_pa(buf_info), - 0, len, DMA_FROM_DEVICE); + headroom, len, DMA_FROM_DEVICE); skb_put(skb, len); skb->protocol = eth_type_trans(skb, q->lif->netdev); @@ -303,10 +309,10 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, xdp_init_buff(&xdp_buf, IONIC_PAGE_SIZE, rxq->xdp_rxq_info); xdp_prepare_buff(&xdp_buf, ionic_rx_buf_va(buf_info), - 0, len, false); + XDP_PACKET_HEADROOM, len, false); dma_sync_single_range_for_cpu(rxq->dev, ionic_rx_buf_pa(buf_info), - 0, len, + XDP_PACKET_HEADROOM, len, DMA_FROM_DEVICE); prefetchw(&xdp_buf.data_hard_start); @@ -345,6 +351,7 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_rx_stats *stats; struct ionic_rxq_comp *comp; struct bpf_prog *xdp_prog; + unsigned int headroom; struct sk_buff *skb; u16 len; @@ -366,10 +373,12 @@ static void ionic_rx_clean(struct ionic_queue *q, ionic_run_xdp(stats, netdev, xdp_prog, q, desc_info->bufs, len)) return; + headroom = q->xdp_rxq_info ? XDP_PACKET_HEADROOM : 0; if (len <= q->lif->rx_copybreak) - skb = ionic_rx_copybreak(q, desc_info, comp, !!xdp_prog); + skb = ionic_rx_copybreak(q, desc_info, headroom, len, !!xdp_prog); else - skb = ionic_rx_frags(q, desc_info, comp, !!xdp_prog); + skb = ionic_rx_frags(q, desc_info, headroom, len, + comp->num_sg_elems, !!xdp_prog); if (unlikely(!skb)) { stats->dropped++; @@ -493,8 +502,9 @@ void ionic_rx_fill(struct ionic_queue *q) unsigned int frag_len; unsigned int nfrags; unsigned int n_fill; - unsigned int i, j; unsigned int len; + unsigned int i; + unsigned int j; n_fill = ionic_q_space_avail(q); @@ -503,9 +513,12 @@ void ionic_rx_fill(struct ionic_queue *q) if (n_fill < fill_threshold) return; - len = netdev->mtu + ETH_HLEN + VLAN_HLEN; + len = netdev->mtu + VLAN_ETH_HLEN; for (i = n_fill; i; i--) { + unsigned int headroom; + unsigned int buf_len; + nfrags = 0; remain_len = len; desc_info = &q->info[q->head_idx]; @@ -520,9 +533,18 @@ void ionic_rx_fill(struct ionic_queue *q) } } - /* fill main descriptor - buf[0] */ - desc->addr = cpu_to_le64(ionic_rx_buf_pa(buf_info)); - frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); + /* fill main descriptor - buf[0] + * XDP uses space in the first buffer, so account for + * head room, tail room, and ip header in the first frag size. + */ + headroom = q->xdp_rxq_info ? XDP_PACKET_HEADROOM : 0; + if (q->xdp_rxq_info) + buf_len = IONIC_XDP_MAX_LINEAR_MTU + VLAN_ETH_HLEN; + else + buf_len = ionic_rx_buf_size(buf_info); + frag_len = min_t(u16, len, buf_len); + + desc->addr = cpu_to_le64(ionic_rx_buf_pa(buf_info) + headroom); desc->len = cpu_to_le16(frag_len); remain_len -= frag_len; buf_info++; From 8eeed8373e1cca836799bf8e4a05cffa8e444908 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:06 -0800 Subject: [PATCH 1272/2255] ionic: Add XDP_TX support The XDP_TX packets get fed back into the Rx queue's partnered Tx queue as an xdp_frame. Co-developed-by: Brett Creeley Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_dev.h | 3 + .../net/ethernet/pensando/ionic/ionic_lif.c | 4 + .../net/ethernet/pensando/ionic/ionic_lif.h | 4 + .../net/ethernet/pensando/ionic/ionic_stats.c | 6 + .../net/ethernet/pensando/ionic/ionic_txrx.c | 136 +++++++++++++++++- 5 files changed, 150 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 70f5725fdfe8..76425bb546ba 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -228,6 +228,8 @@ struct ionic_desc_info { struct ionic_buf_info bufs[MAX_SKB_FRAGS + 1]; ionic_desc_cb cb; void *cb_arg; + struct xdp_frame *xdpf; + enum xdp_action act; }; #define IONIC_QUEUE_NAME_MAX_SZ 16 @@ -263,6 +265,7 @@ struct ionic_queue { struct ionic_rxq_sg_desc *rxq_sgl; }; struct xdp_rxq_info *xdp_rxq_info; + struct ionic_queue *partner; dma_addr_t base_pa; dma_addr_t cmb_base_pa; dma_addr_t sg_base_pa; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index d8c83ff47b66..72bbab1576ab 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -878,6 +878,9 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) }; int err; + q->partner = &lif->txqcqs[q->index]->q; + q->partner->partner = q; + if (!lif->xdp_prog) ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_SG); @@ -2926,6 +2929,7 @@ static void ionic_swap_queues(struct ionic_qcq *a, struct ionic_qcq *b) swap(a->q.base_pa, b->q.base_pa); swap(a->q.info, b->q.info); swap(a->q.xdp_rxq_info, b->q.xdp_rxq_info); + swap(a->q.partner, b->q.partner); swap(a->q_base, b->q_base); swap(a->q_base_pa, b->q_base_pa); swap(a->q_size, b->q_size); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 61fa4ea4f04c..092ff08fc7e0 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -37,6 +37,7 @@ struct ionic_tx_stats { u64 dma_map_err; u64 hwstamp_valid; u64 hwstamp_invalid; + u64 xdp_frames; }; struct ionic_rx_stats { @@ -54,6 +55,7 @@ struct ionic_rx_stats { u64 xdp_drop; u64 xdp_aborted; u64 xdp_pass; + u64 xdp_tx; }; #define IONIC_QCQ_F_INITED BIT(0) @@ -141,6 +143,8 @@ struct ionic_lif_sw_stats { u64 xdp_drop; u64 xdp_aborted; u64 xdp_pass; + u64 xdp_tx; + u64 xdp_frames; }; enum ionic_lif_state_flags { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c index 2fb20173b2c6..5d48226e66cd 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c @@ -30,6 +30,8 @@ static const struct ionic_stat_desc ionic_lif_stats_desc[] = { IONIC_LIF_STAT_DESC(xdp_drop), IONIC_LIF_STAT_DESC(xdp_aborted), IONIC_LIF_STAT_DESC(xdp_pass), + IONIC_LIF_STAT_DESC(xdp_tx), + IONIC_LIF_STAT_DESC(xdp_frames), }; static const struct ionic_stat_desc ionic_port_stats_desc[] = { @@ -138,6 +140,7 @@ static const struct ionic_stat_desc ionic_tx_stats_desc[] = { IONIC_TX_STAT_DESC(csum_none), IONIC_TX_STAT_DESC(csum), IONIC_TX_STAT_DESC(vlan_inserted), + IONIC_TX_STAT_DESC(xdp_frames), }; static const struct ionic_stat_desc ionic_rx_stats_desc[] = { @@ -155,6 +158,7 @@ static const struct ionic_stat_desc ionic_rx_stats_desc[] = { IONIC_RX_STAT_DESC(xdp_drop), IONIC_RX_STAT_DESC(xdp_aborted), IONIC_RX_STAT_DESC(xdp_pass), + IONIC_RX_STAT_DESC(xdp_tx), }; #define IONIC_NUM_LIF_STATS ARRAY_SIZE(ionic_lif_stats_desc) @@ -177,6 +181,7 @@ static void ionic_add_lif_txq_stats(struct ionic_lif *lif, int q_num, stats->tx_csum += txstats->csum; stats->tx_hwstamp_valid += txstats->hwstamp_valid; stats->tx_hwstamp_invalid += txstats->hwstamp_invalid; + stats->xdp_frames += txstats->xdp_frames; } static void ionic_add_lif_rxq_stats(struct ionic_lif *lif, int q_num, @@ -194,6 +199,7 @@ static void ionic_add_lif_rxq_stats(struct ionic_lif *lif, int q_num, stats->xdp_drop += rxstats->xdp_drop; stats->xdp_aborted += rxstats->xdp_aborted; stats->xdp_pass += rxstats->xdp_pass; + stats->xdp_tx += rxstats->xdp_tx; } static void ionic_get_lif_stats(struct ionic_lif *lif, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index a4f6dd5030c0..3d4cadcf1c0c 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -10,6 +10,16 @@ #include "ionic_lif.h" #include "ionic_txrx.h" +static int ionic_maybe_stop_tx(struct ionic_queue *q, int ndescs); + +static dma_addr_t ionic_tx_map_single(struct ionic_queue *q, + void *data, size_t len); + +static void ionic_tx_clean(struct ionic_queue *q, + struct ionic_desc_info *desc_info, + struct ionic_cq_info *cq_info, + void *cb_arg); + static inline void ionic_txq_post(struct ionic_queue *q, bool ring_dbell, ionic_desc_cb cb_func, void *cb_arg) { @@ -297,6 +307,75 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, return skb; } +static void ionic_xdp_tx_desc_clean(struct ionic_queue *q, + struct ionic_desc_info *desc_info) +{ + unsigned int nbufs = desc_info->nbufs; + struct ionic_buf_info *buf_info; + struct device *dev = q->dev; + + if (!nbufs) + return; + + buf_info = desc_info->bufs; + dma_unmap_single(dev, buf_info->dma_addr, + buf_info->len, DMA_TO_DEVICE); + __free_pages(buf_info->page, 0); + buf_info->page = NULL; + + desc_info->nbufs = 0; + desc_info->xdpf = NULL; + desc_info->act = 0; +} + +static int ionic_xdp_post_frame(struct net_device *netdev, + struct ionic_queue *q, struct xdp_frame *frame, + enum xdp_action act, struct page *page, int off, + bool ring_doorbell) +{ + struct ionic_desc_info *desc_info; + struct ionic_buf_info *buf_info; + struct ionic_tx_stats *stats; + struct ionic_txq_desc *desc; + size_t len = frame->len; + dma_addr_t dma_addr; + u64 cmd; + + desc_info = &q->info[q->head_idx]; + desc = desc_info->txq_desc; + buf_info = desc_info->bufs; + stats = q_to_tx_stats(q); + + dma_addr = ionic_tx_map_single(q, frame->data, len); + if (dma_mapping_error(q->dev, dma_addr)) { + stats->dma_map_err++; + return -EIO; + } + buf_info->dma_addr = dma_addr; + buf_info->len = len; + buf_info->page = page; + buf_info->page_offset = off; + + desc_info->nbufs = 1; + desc_info->xdpf = frame; + desc_info->act = act; + + cmd = encode_txq_desc_cmd(IONIC_TXQ_DESC_OPCODE_CSUM_NONE, + 0, 0, buf_info->dma_addr); + desc->cmd = cpu_to_le64(cmd); + desc->len = cpu_to_le16(len); + desc->csum_start = 0; + desc->csum_offset = 0; + + stats->xdp_frames++; + stats->pkts++; + stats->bytes += len; + + ionic_txq_post(q, ring_doorbell, ionic_tx_clean, NULL); + + return 0; +} + static bool ionic_run_xdp(struct ionic_rx_stats *stats, struct net_device *netdev, struct bpf_prog *xdp_prog, @@ -306,6 +385,10 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, { u32 xdp_action = XDP_ABORTED; struct xdp_buff xdp_buf; + struct ionic_queue *txq; + struct netdev_queue *nq; + struct xdp_frame *xdpf; + int err = 0; xdp_init_buff(&xdp_buf, IONIC_PAGE_SIZE, rxq->xdp_rxq_info); xdp_prepare_buff(&xdp_buf, ionic_rx_buf_va(buf_info), @@ -330,14 +413,51 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, break; case XDP_TX: + xdpf = xdp_convert_buff_to_frame(&xdp_buf); + if (!xdpf) + goto out_xdp_abort; + + txq = rxq->partner; + nq = netdev_get_tx_queue(netdev, txq->index); + __netif_tx_lock(nq, smp_processor_id()); + txq_trans_cond_update(nq); + + if (netif_tx_queue_stopped(nq) || + unlikely(ionic_maybe_stop_tx(txq, 1))) { + __netif_tx_unlock(nq); + goto out_xdp_abort; + } + + dma_unmap_page(rxq->dev, buf_info->dma_addr, + IONIC_PAGE_SIZE, DMA_FROM_DEVICE); + + err = ionic_xdp_post_frame(netdev, txq, xdpf, XDP_TX, + buf_info->page, + buf_info->page_offset, + true); + __netif_tx_unlock(nq); + if (err) { + netdev_dbg(netdev, "tx ionic_xdp_post_frame err %d\n", err); + goto out_xdp_abort; + } + stats->xdp_tx++; + + /* the Tx completion will free the buffers */ + break; + case XDP_REDIRECT: case XDP_ABORTED: default: - trace_xdp_exception(netdev, xdp_prog, xdp_action); - ionic_rx_page_free(rxq, buf_info); - stats->xdp_aborted++; + goto out_xdp_abort; } + return true; + +out_xdp_abort: + trace_xdp_exception(netdev, xdp_prog, xdp_action); + ionic_rx_page_free(rxq, buf_info); + stats->xdp_aborted++; + return true; } @@ -893,6 +1013,16 @@ static void ionic_tx_clean(struct ionic_queue *q, struct sk_buff *skb = cb_arg; u16 qi; + if (desc_info->xdpf) { + ionic_xdp_tx_desc_clean(q->partner, desc_info); + stats->clean++; + + if (unlikely(__netif_subqueue_stopped(q->lif->netdev, q->index))) + netif_wake_subqueue(q->lif->netdev, q->index); + + return; + } + ionic_tx_desc_unmap_bufs(q, desc_info); if (!skb) From 587fc3f0dceb084cec3a689f71a54ca66c567e99 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:07 -0800 Subject: [PATCH 1273/2255] ionic: Add XDP_REDIRECT support The XDP_REDIRECT packets are given to the XDP stack and we drop the use of the related page: it will get freed by the driver that ends up doing the Tx. Because we have some hardware configurations with limited queue resources, we use the existing datapath Tx queues rather than creating and managing a separate set of xdp_tx queues. Co-developed-by: Brett Creeley Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_dev.h | 1 + .../net/ethernet/pensando/ionic/ionic_lif.c | 3 ++- .../net/ethernet/pensando/ionic/ionic_lif.h | 2 ++ .../net/ethernet/pensando/ionic/ionic_stats.c | 3 +++ .../net/ethernet/pensando/ionic/ionic_txrx.c | 24 +++++++++++++++++++ 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 76425bb546ba..bfcfc2d7bcbd 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -266,6 +266,7 @@ struct ionic_queue { }; struct xdp_rxq_info *xdp_rxq_info; struct ionic_queue *partner; + bool xdp_flush; dma_addr_t base_pa; dma_addr_t cmb_base_pa; dma_addr_t sg_base_pa; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 72bbab1576ab..79bb07083f35 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1649,7 +1649,8 @@ static int ionic_init_nic_features(struct ionic_lif *lif) netdev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE; - netdev->xdp_features = NETDEV_XDP_ACT_BASIC; + netdev->xdp_features = NETDEV_XDP_ACT_BASIC | + NETDEV_XDP_ACT_REDIRECT; return 0; } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 092ff08fc7e0..42006de8069d 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -56,6 +56,7 @@ struct ionic_rx_stats { u64 xdp_aborted; u64 xdp_pass; u64 xdp_tx; + u64 xdp_redirect; }; #define IONIC_QCQ_F_INITED BIT(0) @@ -144,6 +145,7 @@ struct ionic_lif_sw_stats { u64 xdp_aborted; u64 xdp_pass; u64 xdp_tx; + u64 xdp_redirect; u64 xdp_frames; }; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c index 5d48226e66cd..0107599a9dd4 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c @@ -31,6 +31,7 @@ static const struct ionic_stat_desc ionic_lif_stats_desc[] = { IONIC_LIF_STAT_DESC(xdp_aborted), IONIC_LIF_STAT_DESC(xdp_pass), IONIC_LIF_STAT_DESC(xdp_tx), + IONIC_LIF_STAT_DESC(xdp_redirect), IONIC_LIF_STAT_DESC(xdp_frames), }; @@ -159,6 +160,7 @@ static const struct ionic_stat_desc ionic_rx_stats_desc[] = { IONIC_RX_STAT_DESC(xdp_aborted), IONIC_RX_STAT_DESC(xdp_pass), IONIC_RX_STAT_DESC(xdp_tx), + IONIC_RX_STAT_DESC(xdp_redirect), }; #define IONIC_NUM_LIF_STATS ARRAY_SIZE(ionic_lif_stats_desc) @@ -200,6 +202,7 @@ static void ionic_add_lif_rxq_stats(struct ionic_lif *lif, int q_num, stats->xdp_aborted += rxstats->xdp_aborted; stats->xdp_pass += rxstats->xdp_pass; stats->xdp_tx += rxstats->xdp_tx; + stats->xdp_redirect += rxstats->xdp_redirect; } static void ionic_get_lif_stats(struct ionic_lif *lif, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 3d4cadcf1c0c..0ad649494e87 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -446,6 +446,20 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, break; case XDP_REDIRECT: + /* unmap the pages before handing them to a different device */ + dma_unmap_page(rxq->dev, buf_info->dma_addr, + IONIC_PAGE_SIZE, DMA_FROM_DEVICE); + + err = xdp_do_redirect(netdev, &xdp_buf, xdp_prog); + if (err) { + netdev_dbg(netdev, "xdp_do_redirect err %d\n", err); + goto out_xdp_abort; + } + buf_info->page = NULL; + rxq->xdp_flush = true; + stats->xdp_redirect++; + break; + case XDP_ABORTED: default: goto out_xdp_abort; @@ -809,6 +823,14 @@ int ionic_tx_napi(struct napi_struct *napi, int budget) return work_done; } +static void ionic_xdp_do_flush(struct ionic_cq *cq) +{ + if (cq->bound_q->xdp_flush) { + xdp_do_flush(); + cq->bound_q->xdp_flush = false; + } +} + int ionic_rx_napi(struct napi_struct *napi, int budget) { struct ionic_qcq *qcq = napi_to_qcq(napi); @@ -829,6 +851,7 @@ int ionic_rx_napi(struct napi_struct *napi, int budget) ionic_rx_fill(cq->bound_q); + ionic_xdp_do_flush(cq); if (work_done < budget && napi_complete_done(napi, work_done)) { ionic_dim_update(qcq, IONIC_LIF_F_RX_DIM_INTR); flags |= IONIC_INTR_CRED_UNMASK; @@ -878,6 +901,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget) ionic_rx_fill(rxcq->bound_q); + ionic_xdp_do_flush(rxcq); if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) { ionic_dim_update(rxqcq, 0); flags |= IONIC_INTR_CRED_UNMASK; From 26f5726a78574a4f9d77ef7610bfb6dc402cca81 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:08 -0800 Subject: [PATCH 1274/2255] ionic: add ndo_xdp_xmit When our ndo_xdp_xmit is called we mark the buffer with XDP_REDIRECT so we know to return it to the XDP stack for cleaning. Co-developed-by: Brett Creeley Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_lif.c | 4 +- .../net/ethernet/pensando/ionic/ionic_txrx.c | 63 ++++++++++++++++++- .../net/ethernet/pensando/ionic/ionic_txrx.h | 1 + 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 79bb07083f35..d26ea697804d 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1650,7 +1650,8 @@ static int ionic_init_nic_features(struct ionic_lif *lif) IFF_LIVE_ADDR_CHANGE; netdev->xdp_features = NETDEV_XDP_ACT_BASIC | - NETDEV_XDP_ACT_REDIRECT; + NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_NDO_XMIT; return 0; } @@ -2847,6 +2848,7 @@ static const struct net_device_ops ionic_netdev_ops = { .ndo_eth_ioctl = ionic_eth_ioctl, .ndo_start_xmit = ionic_start_xmit, .ndo_bpf = ionic_xdp, + .ndo_xdp_xmit = ionic_xdp_xmit, .ndo_get_stats64 = ionic_get_stats64, .ndo_set_rx_mode = ionic_ndo_set_rx_mode, .ndo_set_features = ionic_set_features, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 0ad649494e87..1b464ad4a7db 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -320,9 +320,13 @@ static void ionic_xdp_tx_desc_clean(struct ionic_queue *q, buf_info = desc_info->bufs; dma_unmap_single(dev, buf_info->dma_addr, buf_info->len, DMA_TO_DEVICE); - __free_pages(buf_info->page, 0); + if (desc_info->act == XDP_TX) + __free_pages(buf_info->page, 0); buf_info->page = NULL; + if (desc_info->act == XDP_REDIRECT) + xdp_return_frame(desc_info->xdpf); + desc_info->nbufs = 0; desc_info->xdpf = NULL; desc_info->act = 0; @@ -376,6 +380,63 @@ static int ionic_xdp_post_frame(struct net_device *netdev, return 0; } +int ionic_xdp_xmit(struct net_device *netdev, int n, + struct xdp_frame **xdp_frames, u32 flags) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic_queue *txq; + struct netdev_queue *nq; + int nxmit; + int space; + int cpu; + int qi; + + if (unlikely(!test_bit(IONIC_LIF_F_UP, lif->state))) + return -ENETDOWN; + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; + + /* AdminQ is assumed on cpu 0, while we attempt to affinitize the + * TxRx queue pairs 0..n-1 on cpus 1..n. We try to keep with that + * affinitization here, but of course irqbalance and friends might + * have juggled things anyway, so we have to check for the 0 case. + */ + cpu = smp_processor_id(); + qi = cpu ? (cpu - 1) % lif->nxqs : cpu; + + txq = &lif->txqcqs[qi]->q; + nq = netdev_get_tx_queue(netdev, txq->index); + __netif_tx_lock(nq, cpu); + txq_trans_cond_update(nq); + + if (netif_tx_queue_stopped(nq) || + unlikely(ionic_maybe_stop_tx(txq, 1))) { + __netif_tx_unlock(nq); + return -EIO; + } + + space = min_t(int, n, ionic_q_space_avail(txq)); + for (nxmit = 0; nxmit < space ; nxmit++) { + if (ionic_xdp_post_frame(netdev, txq, xdp_frames[nxmit], + XDP_REDIRECT, + virt_to_page(xdp_frames[nxmit]->data), + 0, false)) { + nxmit--; + break; + } + } + + if (flags & XDP_XMIT_FLUSH) + ionic_dbell_ring(lif->kern_dbpage, txq->hw_type, + txq->dbval | txq->head_idx); + + ionic_maybe_stop_tx(txq, 4); + __netif_tx_unlock(nq); + + return nxmit; +} + static bool ionic_run_xdp(struct ionic_rx_stats *stats, struct net_device *netdev, struct bpf_prog *xdp_prog, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.h b/drivers/net/ethernet/pensando/ionic/ionic_txrx.h index d7cbaad8a6fb..82fc38e0f573 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.h @@ -17,4 +17,5 @@ netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev); bool ionic_rx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info); bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info); +int ionic_xdp_xmit(struct net_device *netdev, int n, struct xdp_frame **xdp, u32 flags); #endif /* _IONIC_TXRX_H_ */ From 5377805dc1c02ad3721a9256f0eef9b4813952e7 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Feb 2024 09:59:09 -0800 Subject: [PATCH 1275/2255] ionic: implement xdp frags support Add support for using scatter-gather / frags in XDP in both Rx and Tx paths. Co-developed-by: Brett Creeley Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_lif.c | 12 ++- .../net/ethernet/pensando/ionic/ionic_txrx.c | 91 ++++++++++++++++++- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index d26ea697804d..5cfc784f1227 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -881,7 +881,8 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) q->partner = &lif->txqcqs[q->index]->q; q->partner->partner = q; - if (!lif->xdp_prog) + if (!lif->xdp_prog || + (lif->xdp_prog->aux && lif->xdp_prog->aux->xdp_has_frags)) ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_SG); if (qcq->flags & IONIC_QCQ_F_CMB_RINGS) { @@ -1651,7 +1652,9 @@ static int ionic_init_nic_features(struct ionic_lif *lif) netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | - NETDEV_XDP_ACT_NDO_XMIT; + NETDEV_XDP_ACT_RX_SG | + NETDEV_XDP_ACT_NDO_XMIT | + NETDEV_XDP_ACT_NDO_XMIT_SG; return 0; } @@ -1799,6 +1802,9 @@ static bool ionic_xdp_is_valid_mtu(struct ionic_lif *lif, u32 mtu, if (mtu <= IONIC_XDP_MAX_LINEAR_MTU) return true; + if (xdp_prog->aux && xdp_prog->aux->xdp_has_frags) + return true; + return false; } @@ -2812,7 +2818,7 @@ static int ionic_xdp_config(struct net_device *netdev, struct netdev_bpf *bpf) } maxfs = __le32_to_cpu(lif->identity->eth.max_frame_size) - VLAN_ETH_HLEN; - if (bpf->prog) + if (bpf->prog && !(bpf->prog->aux && bpf->prog->aux->xdp_has_frags)) maxfs = min_t(u32, maxfs, IONIC_XDP_MAX_LINEAR_MTU); netdev->max_mtu = maxfs; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 1b464ad4a7db..56a7ad5bff17 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -15,6 +15,13 @@ static int ionic_maybe_stop_tx(struct ionic_queue *q, int ndescs); static dma_addr_t ionic_tx_map_single(struct ionic_queue *q, void *data, size_t len); +static dma_addr_t ionic_tx_map_frag(struct ionic_queue *q, + const skb_frag_t *frag, + size_t offset, size_t len); + +static void ionic_tx_desc_unmap_bufs(struct ionic_queue *q, + struct ionic_desc_info *desc_info); + static void ionic_tx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_info, struct ionic_cq_info *cq_info, @@ -313,6 +320,7 @@ static void ionic_xdp_tx_desc_clean(struct ionic_queue *q, unsigned int nbufs = desc_info->nbufs; struct ionic_buf_info *buf_info; struct device *dev = q->dev; + int i; if (!nbufs) return; @@ -324,6 +332,15 @@ static void ionic_xdp_tx_desc_clean(struct ionic_queue *q, __free_pages(buf_info->page, 0); buf_info->page = NULL; + buf_info++; + for (i = 1; i < nbufs + 1 && buf_info->page; i++, buf_info++) { + dma_unmap_page(dev, buf_info->dma_addr, + buf_info->len, DMA_TO_DEVICE); + if (desc_info->act == XDP_TX) + __free_pages(buf_info->page, 0); + buf_info->page = NULL; + } + if (desc_info->act == XDP_REDIRECT) xdp_return_frame(desc_info->xdpf); @@ -364,8 +381,38 @@ static int ionic_xdp_post_frame(struct net_device *netdev, desc_info->xdpf = frame; desc_info->act = act; + if (xdp_frame_has_frags(frame)) { + struct ionic_txq_sg_elem *elem; + struct skb_shared_info *sinfo; + struct ionic_buf_info *bi; + skb_frag_t *frag; + int i; + + bi = &buf_info[1]; + sinfo = xdp_get_shared_info_from_frame(frame); + frag = sinfo->frags; + elem = desc_info->txq_sg_desc->elems; + for (i = 0; i < sinfo->nr_frags; i++, frag++, bi++) { + dma_addr = ionic_tx_map_frag(q, frag, 0, skb_frag_size(frag)); + if (dma_mapping_error(q->dev, dma_addr)) { + stats->dma_map_err++; + ionic_tx_desc_unmap_bufs(q, desc_info); + return -EIO; + } + bi->dma_addr = dma_addr; + bi->len = skb_frag_size(frag); + bi->page = skb_frag_page(frag); + + elem->addr = cpu_to_le64(bi->dma_addr); + elem->len = cpu_to_le16(bi->len); + elem++; + + desc_info->nbufs++; + } + } + cmd = encode_txq_desc_cmd(IONIC_TXQ_DESC_OPCODE_CSUM_NONE, - 0, 0, buf_info->dma_addr); + 0, (desc_info->nbufs - 1), buf_info->dma_addr); desc->cmd = cpu_to_le64(cmd); desc->len = cpu_to_le16(len); desc->csum_start = 0; @@ -449,11 +496,14 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, struct ionic_queue *txq; struct netdev_queue *nq; struct xdp_frame *xdpf; + int remain_len; + int frag_len; int err = 0; xdp_init_buff(&xdp_buf, IONIC_PAGE_SIZE, rxq->xdp_rxq_info); + frag_len = min_t(u16, len, IONIC_XDP_MAX_LINEAR_MTU + VLAN_ETH_HLEN); xdp_prepare_buff(&xdp_buf, ionic_rx_buf_va(buf_info), - XDP_PACKET_HEADROOM, len, false); + XDP_PACKET_HEADROOM, frag_len, false); dma_sync_single_range_for_cpu(rxq->dev, ionic_rx_buf_pa(buf_info), XDP_PACKET_HEADROOM, len, @@ -461,6 +511,43 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, prefetchw(&xdp_buf.data_hard_start); + /* We limit MTU size to one buffer if !xdp_has_frags, so + * if the recv len is bigger than one buffer + * then we know we have frag info to gather + */ + remain_len = len - frag_len; + if (remain_len) { + struct skb_shared_info *sinfo; + struct ionic_buf_info *bi; + skb_frag_t *frag; + + bi = buf_info; + sinfo = xdp_get_shared_info_from_buff(&xdp_buf); + sinfo->nr_frags = 0; + sinfo->xdp_frags_size = 0; + xdp_buff_set_frags_flag(&xdp_buf); + + do { + if (unlikely(sinfo->nr_frags >= MAX_SKB_FRAGS)) { + err = -ENOSPC; + goto out_xdp_abort; + } + + frag = &sinfo->frags[sinfo->nr_frags]; + sinfo->nr_frags++; + bi++; + frag_len = min_t(u16, remain_len, ionic_rx_buf_size(bi)); + dma_sync_single_range_for_cpu(rxq->dev, ionic_rx_buf_pa(bi), + 0, frag_len, DMA_FROM_DEVICE); + skb_frag_fill_page_desc(frag, bi->page, 0, frag_len); + sinfo->xdp_frags_size += frag_len; + remain_len -= frag_len; + + if (page_is_pfmemalloc(bi->page)) + xdp_buff_set_frag_pfmemalloc(&xdp_buf); + } while (remain_len > 0); + } + xdp_action = bpf_prog_run_xdp(xdp_prog, &xdp_buf); switch (xdp_action) { From 21bd52ea38a873b9dce2da86e9d63a95cdbe1275 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Feb 2024 14:12:21 +0100 Subject: [PATCH 1276/2255] tcp: Spelling s/curcuit/circuit/ Fix a misspelling of "circuit". Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b1c4462a0798..74c03f0a6c0c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1164,7 +1164,7 @@ static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered, * L|R 1 - orig is lost, retransmit is in flight. * S|R 1 - orig reached receiver, retrans is still in flight. * (L|S|R is logically valid, it could occur when L|R is sacked, - * but it is equivalent to plain S and code short-curcuits it to S. + * but it is equivalent to plain S and code short-circuits it to S. * L|S is logically invalid, it would mean -1 packet in flight 8)) * * These 6 states form finite state machine, controlled by the following events: From 1d085e9ce384c2014b967b0ddefd4ce7220dd445 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 15 Feb 2024 15:22:01 +0000 Subject: [PATCH 1277/2255] net: ti: icssg-prueth: Remove duplicate cleanup calls in emac_ndo_stop() Remove the duplicate calls to prueth_emac_stop() and prueth_cleanup_tx_chns() in emac_ndo_stop(). Signed-off-by: Diogo Ivo Reviewed-by: Roger Quadros Reviewed-by: MD Danish Anwar Reviewed-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/icssg/icssg_prueth.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c index 411898a4f38c..cf7b73f8f450 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c @@ -1489,9 +1489,6 @@ static int emac_ndo_stop(struct net_device *ndev) /* Destroying the queued work in ndo_stop() */ cancel_delayed_work_sync(&emac->stats_work); - /* stop PRUs */ - prueth_emac_stop(emac); - if (prueth->emacs_initialized == 1) icss_iep_exit(emac->iep); @@ -1502,7 +1499,6 @@ static int emac_ndo_stop(struct net_device *ndev) free_irq(emac->rx_chns.irq[rx_flow], emac); prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); - prueth_cleanup_tx_chns(emac); prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows); prueth_cleanup_tx_chns(emac); From 71b605d32017e5b8d257db7344bc2f8e8fcc973e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 15 Feb 2024 16:30:05 +0100 Subject: [PATCH 1278/2255] net: phy: aquantia: add AQR113 PHY ID Add Aquantia AQR113 PHY ID. Aquantia AQR113 is just a chip size variant of the already supported AQR133C where the only difference is the PHY ID and the hw chip size. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/aquantia/aquantia_main.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 109387acabeb..a6a7980585f5 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -26,6 +26,7 @@ #define PHY_ID_AQR111B0 0x03a1b612 #define PHY_ID_AQR112 0x03a1b662 #define PHY_ID_AQR412 0x03a1b712 +#define PHY_ID_AQR113 0x31c31c40 #define PHY_ID_AQR113C 0x31c31c12 #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 @@ -922,6 +923,25 @@ static struct phy_driver aqr_driver[] = { .get_stats = aqr107_get_stats, .link_change_notify = aqr107_link_change_notify, }, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR113), + .name = "Aquantia AQR113", + .probe = aqr107_probe, + .get_rate_matching = aqr107_get_rate_matching, + .config_init = aqr113c_config_init, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C), .name = "Aquantia AQR113C", @@ -957,6 +977,7 @@ static struct mdio_device_id __maybe_unused aqr_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, { } }; From 7075d733b8e431c011d30c219012d40ea0c92e1d Mon Sep 17 00:00:00 2001 From: Srinivas Goud Date: Tue, 13 Feb 2024 11:36:43 +0100 Subject: [PATCH 1279/2255] dt-bindings: can: xilinx_can: Add 'xlnx,has-ecc' optional property ECC feature added to CAN TX_OL, TX_TL and RX FIFOs of Xilinx AXI CAN Controller. ECC is an IP configuration option where counter registers are added in IP for 1bit/2bit ECC errors. 'xlnx,has-ecc' is an optional property and added to Xilinx AXI CAN Controller node if ECC block enabled in the HW Acked-by: Conor Dooley Signed-off-by: Srinivas Goud Link: https://lore.kernel.org/all/20240213-xilinx_ecc-v8-1-8d75f8b80771@pengutronix.de Signed-off-by: Marc Kleine-Budde --- Documentation/devicetree/bindings/net/can/xilinx,can.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/net/can/xilinx,can.yaml b/Documentation/devicetree/bindings/net/can/xilinx,can.yaml index 64d57c343e6f..8d4e5af6fd6c 100644 --- a/Documentation/devicetree/bindings/net/can/xilinx,can.yaml +++ b/Documentation/devicetree/bindings/net/can/xilinx,can.yaml @@ -49,6 +49,10 @@ properties: resets: maxItems: 1 + xlnx,has-ecc: + $ref: /schemas/types.yaml#/definitions/flag + description: CAN TX_OL, TX_TL and RX FIFOs have ECC support(AXI CAN) + required: - compatible - reg @@ -137,6 +141,7 @@ examples: interrupts = ; tx-fifo-depth = <0x40>; rx-fifo-depth = <0x40>; + xlnx,has-ecc; }; - | From 8e6fbf7f66dc056cbf23e02d4b66e9afd2b89887 Mon Sep 17 00:00:00 2001 From: Srinivas Goud Date: Tue, 13 Feb 2024 11:36:44 +0100 Subject: [PATCH 1280/2255] can: xilinx_can: Add ECC support Add ECC support for Xilinx CAN Controller, so this driver reports 1bit/2bit ECC errors for FIFO's based on ECC error interrupt. ECC feature for Xilinx CAN Controller selected through 'xlnx,has-ecc' DT property Signed-off-by: Srinivas Goud Link: https://lore.kernel.org/all/20240213-xilinx_ecc-v8-2-8d75f8b80771@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/xilinx_can.c | 105 +++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 3722eaa84234..af2af4eade3c 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -31,6 +31,7 @@ #include #include #include +#include #define DRIVER_NAME "xilinx_can" @@ -58,6 +59,13 @@ enum xcan_reg { */ XCAN_F_BTR_OFFSET = 0x08C, /* Data Phase Bit Timing */ XCAN_TRR_OFFSET = 0x0090, /* TX Buffer Ready Request */ + + /* only on AXI CAN cores */ + XCAN_ECC_CFG_OFFSET = 0xC8, /* ECC Configuration */ + XCAN_TXTLFIFO_ECC_OFFSET = 0xCC, /* TXTL FIFO ECC error counter */ + XCAN_TXOLFIFO_ECC_OFFSET = 0xD0, /* TXOL FIFO ECC error counter */ + XCAN_RXFIFO_ECC_OFFSET = 0xD4, /* RX FIFO ECC error counter */ + XCAN_AFR_EXT_OFFSET = 0x00E0, /* Acceptance Filter */ XCAN_FSR_OFFSET = 0x00E8, /* RX FIFO Status */ XCAN_TXMSG_BASE_OFFSET = 0x0100, /* TX Message Space */ @@ -124,6 +132,18 @@ enum xcan_reg { #define XCAN_IXR_TXFLL_MASK 0x00000004 /* Tx FIFO Full intr */ #define XCAN_IXR_TXOK_MASK 0x00000002 /* TX successful intr */ #define XCAN_IXR_ARBLST_MASK 0x00000001 /* Arbitration lost intr */ +#define XCAN_IXR_E2BERX_MASK BIT(23) /* RX FIFO two bit ECC error */ +#define XCAN_IXR_E1BERX_MASK BIT(22) /* RX FIFO one bit ECC error */ +#define XCAN_IXR_E2BETXOL_MASK BIT(21) /* TXOL FIFO two bit ECC error */ +#define XCAN_IXR_E1BETXOL_MASK BIT(20) /* TXOL FIFO One bit ECC error */ +#define XCAN_IXR_E2BETXTL_MASK BIT(19) /* TXTL FIFO Two bit ECC error */ +#define XCAN_IXR_E1BETXTL_MASK BIT(18) /* TXTL FIFO One bit ECC error */ +#define XCAN_IXR_ECC_MASK (XCAN_IXR_E2BERX_MASK | \ + XCAN_IXR_E1BERX_MASK | \ + XCAN_IXR_E2BETXOL_MASK | \ + XCAN_IXR_E1BETXOL_MASK | \ + XCAN_IXR_E2BETXTL_MASK | \ + XCAN_IXR_E1BETXTL_MASK) #define XCAN_IDR_ID1_MASK 0xFFE00000 /* Standard msg identifier */ #define XCAN_IDR_SRR_MASK 0x00100000 /* Substitute remote TXreq */ #define XCAN_IDR_IDE_MASK 0x00080000 /* Identifier extension */ @@ -137,6 +157,11 @@ enum xcan_reg { #define XCAN_2_FSR_RI_MASK 0x0000003F /* RX Read Index */ #define XCAN_DLCR_EDL_MASK 0x08000000 /* EDL Mask in DLC */ #define XCAN_DLCR_BRS_MASK 0x04000000 /* BRS Mask in DLC */ +#define XCAN_ECC_CFG_REECRX_MASK BIT(2) /* Reset RX FIFO ECC error counters */ +#define XCAN_ECC_CFG_REECTXOL_MASK BIT(1) /* Reset TXOL FIFO ECC error counters */ +#define XCAN_ECC_CFG_REECTXTL_MASK BIT(0) /* Reset TXTL FIFO ECC error counters */ +#define XCAN_ECC_1BIT_CNT_MASK GENMASK(15, 0) /* FIFO ECC 1bit count mask */ +#define XCAN_ECC_2BIT_CNT_MASK GENMASK(31, 16) /* FIFO ECC 2bit count mask */ /* CAN register bit shift - XCAN___SHIFT */ #define XCAN_BRPR_TDC_ENABLE BIT(16) /* Transmitter Delay Compensation (TDC) Enable */ @@ -202,6 +227,13 @@ struct xcan_devtype_data { * @devtype: Device type specific constants * @transceiver: Optional pointer to associated CAN transceiver * @rstc: Pointer to reset control + * @ecc_enable: ECC enable flag + * @ecc_rx_2_bit_errors: RXFIFO 2bit ECC count + * @ecc_rx_1_bit_errors: RXFIFO 1bit ECC count + * @ecc_txol_2_bit_errors: TXOLFIFO 2bit ECC count + * @ecc_txol_1_bit_errors: TXOLFIFO 1bit ECC count + * @ecc_txtl_2_bit_errors: TXTLFIFO 2bit ECC count + * @ecc_txtl_1_bit_errors: TXTLFIFO 1bit ECC count */ struct xcan_priv { struct can_priv can; @@ -221,6 +253,13 @@ struct xcan_priv { struct xcan_devtype_data devtype; struct phy *transceiver; struct reset_control *rstc; + bool ecc_enable; + u64_stats_t ecc_rx_2_bit_errors; + u64_stats_t ecc_rx_1_bit_errors; + u64_stats_t ecc_txol_2_bit_errors; + u64_stats_t ecc_txol_1_bit_errors; + u64_stats_t ecc_txtl_2_bit_errors; + u64_stats_t ecc_txtl_1_bit_errors; }; /* CAN Bittiming constants as per Xilinx CAN specs */ @@ -523,6 +562,9 @@ static int xcan_chip_start(struct net_device *ndev) XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK | xcan_rx_int_mask(priv); + if (priv->ecc_enable) + ier |= XCAN_IXR_ECC_MASK; + if (priv->devtype.flags & XCAN_FLAG_RXMNF) ier |= XCAN_IXR_RXMNF_MASK; @@ -1127,6 +1169,50 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) priv->can.can_stats.bus_error++; } + if (priv->ecc_enable && isr & XCAN_IXR_ECC_MASK) { + u32 reg_rx_ecc, reg_txol_ecc, reg_txtl_ecc; + + reg_rx_ecc = priv->read_reg(priv, XCAN_RXFIFO_ECC_OFFSET); + reg_txol_ecc = priv->read_reg(priv, XCAN_TXOLFIFO_ECC_OFFSET); + reg_txtl_ecc = priv->read_reg(priv, XCAN_TXTLFIFO_ECC_OFFSET); + + /* The counter reaches its maximum at 0xffff and does not overflow. + * Accept the small race window between reading and resetting ECC counters. + */ + priv->write_reg(priv, XCAN_ECC_CFG_OFFSET, XCAN_ECC_CFG_REECRX_MASK | + XCAN_ECC_CFG_REECTXOL_MASK | XCAN_ECC_CFG_REECTXTL_MASK); + + if (isr & XCAN_IXR_E2BERX_MASK) { + u64_stats_add(&priv->ecc_rx_2_bit_errors, + FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_rx_ecc)); + } + + if (isr & XCAN_IXR_E1BERX_MASK) { + u64_stats_add(&priv->ecc_rx_1_bit_errors, + FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_rx_ecc)); + } + + if (isr & XCAN_IXR_E2BETXOL_MASK) { + u64_stats_add(&priv->ecc_txol_2_bit_errors, + FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_txol_ecc)); + } + + if (isr & XCAN_IXR_E1BETXOL_MASK) { + u64_stats_add(&priv->ecc_txol_1_bit_errors, + FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_txol_ecc)); + } + + if (isr & XCAN_IXR_E2BETXTL_MASK) { + u64_stats_add(&priv->ecc_txtl_2_bit_errors, + FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_txtl_ecc)); + } + + if (isr & XCAN_IXR_E1BETXTL_MASK) { + u64_stats_add(&priv->ecc_txtl_1_bit_errors, + FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_txtl_ecc)); + } + } + if (cf.can_id) { struct can_frame *skb_cf; struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf); @@ -1354,8 +1440,8 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) { struct net_device *ndev = (struct net_device *)dev_id; struct xcan_priv *priv = netdev_priv(ndev); + u32 isr_errors, mask; u32 isr, ier; - u32 isr_errors; u32 rx_int_mask = xcan_rx_int_mask(priv); /* Get the interrupt status from Xilinx CAN */ @@ -1374,10 +1460,15 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) if (isr & XCAN_IXR_TXOK_MASK) xcan_tx_interrupt(ndev, isr); + mask = XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | + XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK | + XCAN_IXR_RXMNF_MASK; + + if (priv->ecc_enable) + mask |= XCAN_IXR_ECC_MASK; + /* Check for the type of error interrupt and Processing it */ - isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | - XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK | - XCAN_IXR_RXMNF_MASK); + isr_errors = isr & mask; if (isr_errors) { priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors); xcan_err_interrupt(ndev, isr); @@ -1793,6 +1884,7 @@ static int xcan_probe(struct platform_device *pdev) return -ENOMEM; priv = netdev_priv(ndev); + priv->ecc_enable = of_property_read_bool(pdev->dev.of_node, "xlnx,has-ecc"); priv->dev = &pdev->dev; priv->can.bittiming_const = devtype->bittiming_const; priv->can.do_set_mode = xcan_do_set_mode; @@ -1909,6 +2001,11 @@ static int xcan_probe(struct platform_device *pdev) priv->reg_base, ndev->irq, priv->can.clock.freq, hw_tx_max, priv->tx_max); + if (priv->ecc_enable) { + /* Reset FIFO ECC counters */ + priv->write_reg(priv, XCAN_ECC_CFG_OFFSET, XCAN_ECC_CFG_REECRX_MASK | + XCAN_ECC_CFG_REECTXOL_MASK | XCAN_ECC_CFG_REECTXTL_MASK); + } return 0; err_disableclks: From e1d1698eb36c4e3af9cc77e610cfbe47861c491c Mon Sep 17 00:00:00 2001 From: Srinivas Goud Date: Tue, 13 Feb 2024 11:36:45 +0100 Subject: [PATCH 1281/2255] can: xilinx_can: Add ethtool stats interface for ECC errors Add ethtool stats interface for reading FIFO 1bit/2bit ECC errors information. Signed-off-by: Srinivas Goud Link: https://lore.kernel.org/all/20240213-xilinx_ecc-v8-3-8d75f8b80771@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/xilinx_can.c | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index af2af4eade3c..fae0120473f8 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -228,6 +228,7 @@ struct xcan_devtype_data { * @transceiver: Optional pointer to associated CAN transceiver * @rstc: Pointer to reset control * @ecc_enable: ECC enable flag + * @syncp: synchronization for ECC error stats * @ecc_rx_2_bit_errors: RXFIFO 2bit ECC count * @ecc_rx_1_bit_errors: RXFIFO 1bit ECC count * @ecc_txol_2_bit_errors: TXOLFIFO 2bit ECC count @@ -254,6 +255,7 @@ struct xcan_priv { struct phy *transceiver; struct reset_control *rstc; bool ecc_enable; + struct u64_stats_sync syncp; u64_stats_t ecc_rx_2_bit_errors; u64_stats_t ecc_rx_1_bit_errors; u64_stats_t ecc_txol_2_bit_errors; @@ -347,6 +349,24 @@ static const struct can_tdc_const xcan_tdc_const_canfd2 = { .tdcf_max = 0, }; +enum xcan_stats_type { + XCAN_ECC_RX_2_BIT_ERRORS, + XCAN_ECC_RX_1_BIT_ERRORS, + XCAN_ECC_TXOL_2_BIT_ERRORS, + XCAN_ECC_TXOL_1_BIT_ERRORS, + XCAN_ECC_TXTL_2_BIT_ERRORS, + XCAN_ECC_TXTL_1_BIT_ERRORS, +}; + +static const char xcan_priv_flags_strings[][ETH_GSTRING_LEN] = { + [XCAN_ECC_RX_2_BIT_ERRORS] = "ecc_rx_2_bit_errors", + [XCAN_ECC_RX_1_BIT_ERRORS] = "ecc_rx_1_bit_errors", + [XCAN_ECC_TXOL_2_BIT_ERRORS] = "ecc_txol_2_bit_errors", + [XCAN_ECC_TXOL_1_BIT_ERRORS] = "ecc_txol_1_bit_errors", + [XCAN_ECC_TXTL_2_BIT_ERRORS] = "ecc_txtl_2_bit_errors", + [XCAN_ECC_TXTL_1_BIT_ERRORS] = "ecc_txtl_1_bit_errors", +}; + /** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure @@ -1182,6 +1202,8 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) priv->write_reg(priv, XCAN_ECC_CFG_OFFSET, XCAN_ECC_CFG_REECRX_MASK | XCAN_ECC_CFG_REECTXOL_MASK | XCAN_ECC_CFG_REECTXTL_MASK); + u64_stats_update_begin(&priv->syncp); + if (isr & XCAN_IXR_E2BERX_MASK) { u64_stats_add(&priv->ecc_rx_2_bit_errors, FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_rx_ecc)); @@ -1211,6 +1233,8 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) u64_stats_add(&priv->ecc_txtl_1_bit_errors, FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_txtl_ecc)); } + + u64_stats_update_end(&priv->syncp); } if (cf.can_id) { @@ -1637,6 +1661,43 @@ static int xcan_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv) return 0; } +static void xcan_get_strings(struct net_device *ndev, u32 stringset, u8 *buf) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(buf, &xcan_priv_flags_strings, + sizeof(xcan_priv_flags_strings)); + } +} + +static int xcan_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(xcan_priv_flags_strings); + default: + return -EOPNOTSUPP; + } +} + +static void xcan_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +{ + struct xcan_priv *priv = netdev_priv(ndev); + unsigned int start; + + do { + start = u64_stats_fetch_begin(&priv->syncp); + + data[XCAN_ECC_RX_2_BIT_ERRORS] = u64_stats_read(&priv->ecc_rx_2_bit_errors); + data[XCAN_ECC_RX_1_BIT_ERRORS] = u64_stats_read(&priv->ecc_rx_1_bit_errors); + data[XCAN_ECC_TXOL_2_BIT_ERRORS] = u64_stats_read(&priv->ecc_txol_2_bit_errors); + data[XCAN_ECC_TXOL_1_BIT_ERRORS] = u64_stats_read(&priv->ecc_txol_1_bit_errors); + data[XCAN_ECC_TXTL_2_BIT_ERRORS] = u64_stats_read(&priv->ecc_txtl_2_bit_errors); + data[XCAN_ECC_TXTL_1_BIT_ERRORS] = u64_stats_read(&priv->ecc_txtl_1_bit_errors); + } while (u64_stats_fetch_retry(&priv->syncp, start)); +} + static const struct net_device_ops xcan_netdev_ops = { .ndo_open = xcan_open, .ndo_stop = xcan_close, @@ -1646,6 +1707,9 @@ static const struct net_device_ops xcan_netdev_ops = { static const struct ethtool_ops xcan_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, + .get_strings = xcan_get_strings, + .get_sset_count = xcan_get_sset_count, + .get_ethtool_stats = xcan_get_ethtool_stats, }; /** From e1ea6db35fc3ba5ff063f097385e9f7a88c25356 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Feb 2024 11:05:37 +0100 Subject: [PATCH 1282/2255] 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 --- .../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(-) 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); From 7648f0c91eaa3598add9e91991a5483b29da32ee Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Fri, 16 Feb 2024 09:42:45 -0300 Subject: [PATCH 1283/2255] selftests/bpf: Remove empty TEST_CUSTOM_PROGS Commit f04a32b2c5b5 ("selftests/bpf: Do not use sign-file as testcase") removed the TEST_CUSTOM_PROGS assignment, and removed it from being used on TEST_GEN_FILES. Remove two leftovers from that cleanup. Found by inspection. Signed-off-by: Marcos Paulo de Souza Signed-off-by: Daniel Borkmann Cc: Alexey Gladkov Link: https://lore.kernel.org/bpf/20240216-bpf-selftests-custom-progs-v1-1-f7cf281a1fda@suse.com --- tools/testing/selftests/bpf/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index a38a3001527c..dbb8c5f94f34 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -197,8 +197,7 @@ endif # NOTE: Semicolon at the end is critical to override lib.mk's default static # rule for binaries. $(notdir $(TEST_GEN_PROGS) \ - $(TEST_GEN_PROGS_EXTENDED) \ - $(TEST_CUSTOM_PROGS)): %: $(OUTPUT)/% ; + $(TEST_GEN_PROGS_EXTENDED)): %: $(OUTPUT)/% ; # sort removes libbpf duplicates when not cross-building MAKE_DIRS := $(sort $(BUILD_DIR)/libbpf $(HOST_BUILD_DIR)/libbpf \ @@ -752,7 +751,7 @@ $(OUTPUT)/uprobe_multi: uprobe_multi.c $(call msg,BINARY,,$@) $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ -EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \ +EXTRA_CLEAN := $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \ prog_tests/tests.h map_tests/tests.h verifier/tests.h \ feature bpftool \ $(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h *.subskel.h \ From 7e6cec7d3bb0ae2107cda6175bbf3b0275ca0d09 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Fri, 24 Nov 2023 16:03:39 +0100 Subject: [PATCH 1284/2255] i40e: Use existing helper to find flow director VSI Use existing i40e_find_vsi_by_type() to find a VSI associated with flow director. Reviewed-by: Wojciech Drewek Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_main.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 54eb55464e31..6e59a9509868 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -15630,6 +15630,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_I40E_DCB enum i40e_get_fw_lldp_status_resp lldp_status; #endif /* CONFIG_I40E_DCB */ + struct i40e_vsi *vsi; struct i40e_pf *pf; struct i40e_hw *hw; u16 wol_nvm_bits; @@ -15640,7 +15641,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #endif /* CONFIG_I40E_DCB */ int err; u32 val; - u32 i; err = pci_enable_device_mem(pdev); if (err) @@ -15990,12 +15990,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_LIST_HEAD(&pf->vsi[pf->lan_vsi]->ch_list); /* if FDIR VSI was set up, start it now */ - for (i = 0; i < pf->num_alloc_vsi; i++) { - if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { - i40e_vsi_open(pf->vsi[i]); - break; - } - } + vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR); + if (vsi) + i40e_vsi_open(vsi); /* The driver only wants link up/down and module qualification * reports from firmware. Note the negative logic. From b1f1b46f466a0855b92bd191d8fea8bf297bc7ab Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Fri, 24 Nov 2023 16:03:40 +0100 Subject: [PATCH 1285/2255] i40e: Introduce and use macros for iterating VSIs and VEBs Introduce i40e_for_each_vsi() and i40e_for_each_veb() helper macros and use them to iterate relevant arrays. Replace pattern: for (i = 0; i < pf->num_alloc_vsi; i++) by: i40e_for_each_vsi(pf, i, vsi) and pattern: for (i = 0; i < I40E_MAX_VEB; i++) by i40e_for_each_veb(pf, i, veb) These macros also check if array item pf->vsi[i] or pf->veb[i] are not NULL and skip such items so we can remove redundant checks from loop bodies. Reviewed-by: Wojciech Drewek Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e.h | 56 ++- drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c | 10 +- .../net/ethernet/intel/i40e/i40e_debugfs.c | 54 +-- drivers/net/ethernet/intel/i40e/i40e_main.c | 389 ++++++++---------- 4 files changed, 264 insertions(+), 245 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 9b701615c7c6..5acb26644be7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -686,6 +686,54 @@ struct i40e_pf { struct list_head ddp_old_prof; }; +/** + * __i40e_pf_next_vsi - get next valid VSI + * @pf: pointer to the PF struct + * @idx: pointer to start position number + * + * Find and return next non-NULL VSI pointer in pf->vsi array and + * updates idx position. Returns NULL if no VSI is found. + **/ +static __always_inline struct i40e_vsi * +__i40e_pf_next_vsi(struct i40e_pf *pf, int *idx) +{ + while (*idx < pf->num_alloc_vsi) { + if (pf->vsi[*idx]) + return pf->vsi[*idx]; + (*idx)++; + } + return NULL; +} + +#define i40e_pf_for_each_vsi(_pf, _i, _vsi) \ + for (_i = 0, _vsi = __i40e_pf_next_vsi(_pf, &_i); \ + _vsi; \ + _i++, _vsi = __i40e_pf_next_vsi(_pf, &_i)) + +/** + * __i40e_pf_next_veb - get next valid VEB + * @pf: pointer to the PF struct + * @idx: pointer to start position number + * + * Find and return next non-NULL VEB pointer in pf->veb array and + * updates idx position. Returns NULL if no VEB is found. + **/ +static __always_inline struct i40e_veb * +__i40e_pf_next_veb(struct i40e_pf *pf, int *idx) +{ + while (*idx < I40E_MAX_VEB) { + if (pf->veb[*idx]) + return pf->veb[*idx]; + (*idx)++; + } + return NULL; +} + +#define i40e_pf_for_each_veb(_pf, _i, _veb) \ + for (_i = 0, _veb = __i40e_pf_next_veb(_pf, &_i); \ + _veb; \ + _i++, _veb = __i40e_pf_next_veb(_pf, &_i)) + /** * i40e_mac_to_hkey - Convert a 6-byte MAC Address to a u64 hash key * @macaddr: the MAC Address as the base key @@ -1120,14 +1168,12 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id); static inline struct i40e_vsi * i40e_find_vsi_by_type(struct i40e_pf *pf, u16 type) { + struct i40e_vsi *vsi; int i; - for (i = 0; i < pf->num_alloc_vsi; i++) { - struct i40e_vsi *vsi = pf->vsi[i]; - - if (vsi && vsi->type == type) + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->type == type) return vsi; - } return NULL; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c index b96a92187ab3..8aa43aefe84c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c @@ -947,16 +947,16 @@ static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi, static void i40e_dcbnl_del_app(struct i40e_pf *pf, struct i40e_dcb_app_priority_table *app) { + struct i40e_vsi *vsi; int v, err; - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (pf->vsi[v] && pf->vsi[v]->netdev) { - err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app); + i40e_pf_for_each_vsi(pf, v, vsi) + if (vsi->netdev) { + err = i40e_dcbnl_vsi_del_app(vsi, app); dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n", - pf->vsi[v]->seid, err, app->selector, + vsi->seid, err, app->selector, app->protocolid, app->priority); } - } } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index ef70ddbe9c2f..b236b0f93202 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -24,14 +24,18 @@ enum ring_type { **/ static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid) { + struct i40e_vsi *vsi; int i; - if (seid < 0) + if (seid < 0) { dev_info(&pf->pdev->dev, "%d: bad seid\n", seid); - else - for (i = 0; i < pf->num_alloc_vsi; i++) - if (pf->vsi[i] && (pf->vsi[i]->seid == seid)) - return pf->vsi[i]; + + return NULL; + } + + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->seid == seid) + return vsi; return NULL; } @@ -43,11 +47,13 @@ static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid) **/ static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid) { + struct i40e_veb *veb; int i; - for (i = 0; i < I40E_MAX_VEB; i++) - if (pf->veb[i] && pf->veb[i]->seid == seid) - return pf->veb[i]; + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == seid) + return veb; + return NULL; } @@ -653,12 +659,11 @@ out: **/ static void i40e_dbg_dump_vsi_no_seid(struct i40e_pf *pf) { + struct i40e_vsi *vsi; int i; - for (i = 0; i < pf->num_alloc_vsi; i++) - if (pf->vsi[i]) - dev_info(&pf->pdev->dev, "dump vsi[%d]: %d\n", - i, pf->vsi[i]->seid); + i40e_pf_for_each_vsi(pf, i, vsi) + dev_info(&pf->pdev->dev, "dump vsi[%d]: %d\n", i, vsi->seid); } /** @@ -718,11 +723,8 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf) struct i40e_veb *veb; int i; - for (i = 0; i < I40E_MAX_VEB; i++) { - veb = pf->veb[i]; - if (veb) - i40e_dbg_dump_veb_seid(pf, veb->seid); - } + i40e_pf_for_each_veb(pf, i, veb) + i40e_dbg_dump_veb_seid(pf, veb->seid); } /** @@ -873,9 +875,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp, goto command_write_done; } - for (i = 0; i < I40E_MAX_VEB; i++) - if (pf->veb[i] && pf->veb[i]->seid == uplink_seid) + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == uplink_seid) break; + if (i >= I40E_MAX_VEB && uplink_seid != 0 && uplink_seid != pf->mac_seid) { dev_info(&pf->pdev->dev, @@ -892,7 +895,9 @@ static ssize_t i40e_dbg_command_write(struct file *filp, dev_info(&pf->pdev->dev, "add relay failed\n"); } else if (strncmp(cmd_buf, "del relay", 9) == 0) { + struct i40e_veb *veb; int i; + cnt = sscanf(&cmd_buf[9], "%i", &veb_seid); if (cnt != 1) { dev_info(&pf->pdev->dev, @@ -906,9 +911,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } /* find the veb */ - for (i = 0; i < I40E_MAX_VEB; i++) - if (pf->veb[i] && pf->veb[i]->seid == veb_seid) + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == veb_seid) break; + if (i >= I40E_MAX_VEB) { dev_info(&pf->pdev->dev, "del relay: relay %d not found\n", veb_seid); @@ -916,7 +922,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } dev_info(&pf->pdev->dev, "deleting relay %d\n", veb_seid); - i40e_veb_release(pf->veb[i]); + i40e_veb_release(veb); } else if (strncmp(cmd_buf, "add pvid", 8) == 0) { unsigned int v; int ret; @@ -1251,8 +1257,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp, if (cnt == 0) { int i; - for (i = 0; i < pf->num_alloc_vsi; i++) - i40e_vsi_reset_stats(pf->vsi[i]); + i40e_pf_for_each_vsi(pf, i, vsi) + i40e_vsi_reset_stats(vsi); dev_info(&pf->pdev->dev, "vsi clear stats called for all vsi's\n"); } else if (cnt == 1) { vsi = i40e_dbg_find_vsi(pf, vsi_seid); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6e59a9509868..43e1b4f7f9dc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -310,11 +310,12 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id) **/ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id) { + struct i40e_vsi *vsi; int i; - for (i = 0; i < pf->num_alloc_vsi; i++) - if (pf->vsi[i] && (pf->vsi[i]->id == id)) - return pf->vsi[i]; + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->id == id) + return vsi; return NULL; } @@ -552,24 +553,19 @@ void i40e_vsi_reset_stats(struct i40e_vsi *vsi) **/ void i40e_pf_reset_stats(struct i40e_pf *pf) { + struct i40e_veb *veb; int i; memset(&pf->stats, 0, sizeof(pf->stats)); memset(&pf->stats_offsets, 0, sizeof(pf->stats_offsets)); pf->stat_offsets_loaded = false; - for (i = 0; i < I40E_MAX_VEB; i++) { - if (pf->veb[i]) { - memset(&pf->veb[i]->stats, 0, - sizeof(pf->veb[i]->stats)); - memset(&pf->veb[i]->stats_offsets, 0, - sizeof(pf->veb[i]->stats_offsets)); - memset(&pf->veb[i]->tc_stats, 0, - sizeof(pf->veb[i]->tc_stats)); - memset(&pf->veb[i]->tc_stats_offsets, 0, - sizeof(pf->veb[i]->tc_stats_offsets)); - pf->veb[i]->stat_offsets_loaded = false; - } + i40e_pf_for_each_veb(pf, i, veb) { + memset(&veb->stats, 0, sizeof(veb->stats)); + memset(&veb->stats_offsets, 0, sizeof(veb->stats_offsets)); + memset(&veb->tc_stats, 0, sizeof(veb->tc_stats)); + memset(&veb->tc_stats_offsets, 0, sizeof(veb->tc_stats_offsets)); + veb->stat_offsets_loaded = false; } pf->hw_csum_rx_error = 0; } @@ -2879,6 +2875,7 @@ err_no_memory_locked: **/ static void i40e_sync_filters_subtask(struct i40e_pf *pf) { + struct i40e_vsi *vsi; int v; if (!pf) @@ -2890,11 +2887,10 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf) return; } - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (pf->vsi[v] && - (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED) && - !test_bit(__I40E_VSI_RELEASING, pf->vsi[v]->state)) { - int ret = i40e_sync_vsi_filters(pf->vsi[v]); + i40e_pf_for_each_vsi(pf, v, vsi) { + if ((vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) && + !test_bit(__I40E_VSI_RELEASING, vsi->state)) { + int ret = i40e_sync_vsi_filters(vsi); if (ret) { /* come back and try again later */ @@ -5166,6 +5162,7 @@ static void i40e_reset_interrupt_capability(struct i40e_pf *pf) **/ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf) { + struct i40e_vsi *vsi; int i; if (test_bit(__I40E_MISC_IRQ_REQUESTED, pf->state)) @@ -5175,9 +5172,10 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf) I40E_IWARP_IRQ_PILE_ID); i40e_put_lump(pf->irq_pile, 0, I40E_PILE_VALID_BIT-1); - for (i = 0; i < pf->num_alloc_vsi; i++) - if (pf->vsi[i]) - i40e_vsi_free_q_vectors(pf->vsi[i]); + + i40e_pf_for_each_vsi(pf, i, vsi) + i40e_vsi_free_q_vectors(vsi); + i40e_reset_interrupt_capability(pf); } @@ -5274,12 +5272,11 @@ static void i40e_unquiesce_vsi(struct i40e_vsi *vsi) **/ static void i40e_pf_quiesce_all_vsi(struct i40e_pf *pf) { + struct i40e_vsi *vsi; int v; - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (pf->vsi[v]) - i40e_quiesce_vsi(pf->vsi[v]); - } + i40e_pf_for_each_vsi(pf, v, vsi) + i40e_quiesce_vsi(vsi); } /** @@ -5288,12 +5285,11 @@ static void i40e_pf_quiesce_all_vsi(struct i40e_pf *pf) **/ static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf) { + struct i40e_vsi *vsi; int v; - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (pf->vsi[v]) - i40e_unquiesce_vsi(pf->vsi[v]); - } + i40e_pf_for_each_vsi(pf, v, vsi) + i40e_unquiesce_vsi(vsi); } /** @@ -5354,14 +5350,13 @@ wait_rx: **/ static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf) { + struct i40e_vsi *vsi; int v, ret = 0; - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (pf->vsi[v]) { - ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]); - if (ret) - break; - } + i40e_pf_for_each_vsi(pf, v, vsi) { + ret = i40e_vsi_wait_queues_disabled(vsi); + if (ret) + break; } return ret; @@ -6778,32 +6773,29 @@ out: **/ static void i40e_dcb_reconfigure(struct i40e_pf *pf) { + struct i40e_vsi *vsi; + struct i40e_veb *veb; u8 tc_map = 0; int ret; - u8 v; + int v; /* Enable the TCs available on PF to all VEBs */ tc_map = i40e_pf_get_tc_map(pf); if (tc_map == I40E_DEFAULT_TRAFFIC_CLASS) return; - for (v = 0; v < I40E_MAX_VEB; v++) { - if (!pf->veb[v]) - continue; - ret = i40e_veb_config_tc(pf->veb[v], tc_map); + i40e_pf_for_each_veb(pf, v, veb) { + ret = i40e_veb_config_tc(veb, tc_map); if (ret) { dev_info(&pf->pdev->dev, "Failed configuring TC for VEB seid=%d\n", - pf->veb[v]->seid); + veb->seid); /* Will try to configure as many components */ } } /* Update each VSI */ - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (!pf->vsi[v]) - continue; - + i40e_pf_for_each_vsi(pf, v, vsi) { /* - Enable all TCs for the LAN VSI * - For all others keep them at TC0 for now */ @@ -6812,17 +6804,17 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf) else tc_map = I40E_DEFAULT_TRAFFIC_CLASS; - ret = i40e_vsi_config_tc(pf->vsi[v], tc_map); + ret = i40e_vsi_config_tc(vsi, tc_map); if (ret) { dev_info(&pf->pdev->dev, "Failed configuring TC for VSI seid=%d\n", - pf->vsi[v]->seid); + vsi->seid); /* Will try to configure as many components */ } else { /* Re-configure VSI vectors based on updated TC map */ - i40e_vsi_map_rings_to_vectors(pf->vsi[v]); - if (pf->vsi[v]->netdev) - i40e_dcbnl_set_all(pf->vsi[v]); + i40e_vsi_map_rings_to_vectors(vsi); + if (vsi->netdev) + i40e_dcbnl_set_all(vsi); } } } @@ -9257,7 +9249,9 @@ int i40e_close(struct net_device *netdev) **/ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired) { + struct i40e_vsi *vsi; u32 val; + int i; /* do the biggest reset indicated */ if (reset_flags & BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED)) { @@ -9313,29 +9307,20 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired) "FW LLDP is enabled\n"); } else if (reset_flags & BIT_ULL(__I40E_REINIT_REQUESTED)) { - int v; - /* Find the VSI(s) that requested a re-init */ - dev_info(&pf->pdev->dev, - "VSI reinit requested\n"); - for (v = 0; v < pf->num_alloc_vsi; v++) { - struct i40e_vsi *vsi = pf->vsi[v]; + dev_info(&pf->pdev->dev, "VSI reinit requested\n"); - if (vsi != NULL && - test_and_clear_bit(__I40E_VSI_REINIT_REQUESTED, + i40e_pf_for_each_vsi(pf, i, vsi) { + if (test_and_clear_bit(__I40E_VSI_REINIT_REQUESTED, vsi->state)) - i40e_vsi_reinit_locked(pf->vsi[v]); + i40e_vsi_reinit_locked(vsi); } } else if (reset_flags & BIT_ULL(__I40E_DOWN_REQUESTED)) { - int v; - /* Find the VSI(s) that needs to be brought down */ dev_info(&pf->pdev->dev, "VSI down requested\n"); - for (v = 0; v < pf->num_alloc_vsi; v++) { - struct i40e_vsi *vsi = pf->vsi[v]; - if (vsi != NULL && - test_and_clear_bit(__I40E_VSI_DOWN_REQUESTED, + i40e_pf_for_each_vsi(pf, i, vsi) { + if (test_and_clear_bit(__I40E_VSI_DOWN_REQUESTED, vsi->state)) { set_bit(__I40E_VSI_DOWN, vsi->state); i40e_down(vsi); @@ -9888,6 +9873,8 @@ static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up) **/ static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up) { + struct i40e_veb *veb_it; + struct i40e_vsi *vsi; struct i40e_pf *pf; int i; @@ -9896,14 +9883,14 @@ static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up) pf = veb->pf; /* depth first... */ - for (i = 0; i < I40E_MAX_VEB; i++) - if (pf->veb[i] && (pf->veb[i]->uplink_seid == veb->seid)) - i40e_veb_link_event(pf->veb[i], link_up); + i40e_pf_for_each_veb(pf, i, veb_it) + if (veb_it->uplink_seid == veb->seid) + i40e_veb_link_event(veb_it, link_up); /* ... now the local VSIs */ - for (i = 0; i < pf->num_alloc_vsi; i++) - if (pf->vsi[i] && (pf->vsi[i]->uplink_seid == veb->seid)) - i40e_vsi_link_event(pf->vsi[i], link_up); + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->uplink_seid == veb->seid) + i40e_vsi_link_event(vsi, link_up); } /** @@ -9995,6 +9982,8 @@ static void i40e_link_event(struct i40e_pf *pf) **/ static void i40e_watchdog_subtask(struct i40e_pf *pf) { + struct i40e_vsi *vsi; + struct i40e_veb *veb; int i; /* if interface is down do nothing */ @@ -10015,15 +10004,14 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) /* Update the stats for active netdevs so the network stack * can look at updated numbers whenever it cares to */ - for (i = 0; i < pf->num_alloc_vsi; i++) - if (pf->vsi[i] && pf->vsi[i]->netdev) - i40e_update_stats(pf->vsi[i]); + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->netdev) + i40e_update_stats(vsi); if (test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags)) { /* Update the stats for the active switching components */ - for (i = 0; i < I40E_MAX_VEB; i++) - if (pf->veb[i]) - i40e_update_veb_stats(pf->veb[i]); + i40e_pf_for_each_veb(pf, i, veb) + i40e_update_veb_stats(veb); } i40e_ptp_rx_hang(pf); @@ -10380,18 +10368,18 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) { struct i40e_vsi *ctl_vsi = NULL; struct i40e_pf *pf = veb->pf; - int v, veb_idx; - int ret; + struct i40e_veb *veb_it; + struct i40e_vsi *vsi; + int v, ret; /* build VSI that owns this VEB, temporarily attached to base VEB */ - for (v = 0; v < pf->num_alloc_vsi && !ctl_vsi; v++) { - if (pf->vsi[v] && - pf->vsi[v]->veb_idx == veb->idx && - pf->vsi[v]->flags & I40E_VSI_FLAG_VEB_OWNER) { - ctl_vsi = pf->vsi[v]; + i40e_pf_for_each_vsi(pf, v, vsi) + if (vsi->veb_idx == veb->idx && + vsi->flags & I40E_VSI_FLAG_VEB_OWNER) { + ctl_vsi = vsi; break; } - } + if (!ctl_vsi) { dev_info(&pf->pdev->dev, "missing owner VSI for veb_idx %d\n", veb->idx); @@ -10421,13 +10409,11 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) i40e_config_bridge_mode(veb); /* create the remaining VSIs attached to this VEB */ - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (!pf->vsi[v] || pf->vsi[v] == ctl_vsi) + i40e_pf_for_each_vsi(pf, v, vsi) { + if (vsi == ctl_vsi) continue; - if (pf->vsi[v]->veb_idx == veb->idx) { - struct i40e_vsi *vsi = pf->vsi[v]; - + if (vsi->veb_idx == veb->idx) { vsi->uplink_seid = veb->seid; ret = i40e_add_vsi(vsi); if (ret) { @@ -10441,10 +10427,10 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) } /* create any VEBs attached to this VEB - RECURSION */ - for (veb_idx = 0; veb_idx < I40E_MAX_VEB; veb_idx++) { - if (pf->veb[veb_idx] && pf->veb[veb_idx]->veb_idx == veb->idx) { - pf->veb[veb_idx]->uplink_seid = veb->seid; - ret = i40e_reconstitute_veb(pf->veb[veb_idx]); + i40e_pf_for_each_veb(pf, v, veb_it) { + if (veb_it->veb_idx == veb->idx) { + veb_it->uplink_seid = veb->seid; + ret = i40e_reconstitute_veb(veb_it); if (ret) break; } @@ -10718,6 +10704,7 @@ static void i40e_clean_xps_state(struct i40e_vsi *vsi) static void i40e_prep_for_reset(struct i40e_pf *pf) { struct i40e_hw *hw = &pf->hw; + struct i40e_vsi *vsi; int ret = 0; u32 v; @@ -10732,11 +10719,9 @@ static void i40e_prep_for_reset(struct i40e_pf *pf) /* quiesce the VSIs and their queues that are not already DOWN */ i40e_pf_quiesce_all_vsi(pf); - for (v = 0; v < pf->num_alloc_vsi; v++) { - if (pf->vsi[v]) { - i40e_clean_xps_state(pf->vsi[v]); - pf->vsi[v]->seid = 0; - } + i40e_pf_for_each_vsi(pf, v, vsi) { + i40e_clean_xps_state(vsi); + vsi->seid = 0; } i40e_shutdown_adminq(&pf->hw); @@ -10850,6 +10835,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) const bool is_recovery_mode_reported = i40e_check_recovery_mode(pf); struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_hw *hw = &pf->hw; + struct i40e_veb *veb; int ret; u32 val; int v; @@ -10992,14 +10978,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) if (vsi->uplink_seid != pf->mac_seid) { dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n"); /* find the one VEB connected to the MAC, and find orphans */ - for (v = 0; v < I40E_MAX_VEB; v++) { - if (!pf->veb[v]) - continue; - - if (pf->veb[v]->uplink_seid == pf->mac_seid || - pf->veb[v]->uplink_seid == 0) { - ret = i40e_reconstitute_veb(pf->veb[v]); - + i40e_pf_for_each_veb(pf, v, veb) { + if (veb->uplink_seid == pf->mac_seid || + veb->uplink_seid == 0) { + ret = i40e_reconstitute_veb(veb); if (!ret) continue; @@ -11009,13 +10991,13 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) * If orphan failed, we'll report the error * but try to keep going. */ - if (pf->veb[v]->uplink_seid == pf->mac_seid) { + if (veb->uplink_seid == pf->mac_seid) { dev_info(&pf->pdev->dev, "rebuild of switch failed: %d, will try to set up simple PF connection\n", ret); vsi->uplink_seid = pf->mac_seid; break; - } else if (pf->veb[v]->uplink_seid == 0) { + } else if (veb->uplink_seid == 0) { dev_info(&pf->pdev->dev, "rebuild of orphan VEB failed: %d\n", ret); @@ -12098,6 +12080,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf) */ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf) { + struct i40e_vsi *vsi; int err, i; /* We cleared the MSI and MSI-X flags when disabling the old interrupt @@ -12114,13 +12097,12 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf) /* Now that we've re-acquired IRQs, we need to remap the vectors and * rings together again. */ - for (i = 0; i < pf->num_alloc_vsi; i++) { - if (pf->vsi[i]) { - err = i40e_vsi_alloc_q_vectors(pf->vsi[i]); - if (err) - goto err_unwind; - i40e_vsi_map_rings_to_vectors(pf->vsi[i]); - } + i40e_pf_for_each_vsi(pf, i, vsi) { + err = i40e_vsi_alloc_q_vectors(vsi); + if (err) + goto err_unwind; + + i40e_vsi_map_rings_to_vectors(vsi); } err = i40e_setup_misc_vector(pf); @@ -13122,8 +13104,8 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; - struct i40e_veb *veb = NULL; struct nlattr *attr, *br_spec; + struct i40e_veb *veb; int i, rem; /* Only for PF VSI for now */ @@ -13131,10 +13113,11 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, return -EOPNOTSUPP; /* Find the HW bridge for PF VSI */ - for (i = 0; i < I40E_MAX_VEB && !veb; i++) { - if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid) - veb = pf->veb[i]; - } + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == vsi->uplink_seid) + break; + if (i == I40E_MAX_VEB) + veb = NULL; /* No VEB found */ br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); if (!br_spec) @@ -13207,12 +13190,10 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return -EOPNOTSUPP; /* Find the HW bridge for the PF VSI */ - for (i = 0; i < I40E_MAX_VEB && !veb; i++) { - if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid) - veb = pf->veb[i]; - } - - if (!veb) + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == vsi->uplink_seid) + break; + if (i == I40E_MAX_VEB) return 0; return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode, @@ -14143,9 +14124,9 @@ err: **/ int i40e_vsi_release(struct i40e_vsi *vsi) { + struct i40e_veb *veb, *veb_it; struct i40e_mac_filter *f; struct hlist_node *h; - struct i40e_veb *veb = NULL; struct i40e_pf *pf; u16 uplink_seid; int i, n, bkt; @@ -14215,20 +14196,18 @@ int i40e_vsi_release(struct i40e_vsi *vsi) * the orphan VEBs yet. We'll wait for an explicit remove request * from up the network stack. */ - for (n = 0, i = 0; i < pf->num_alloc_vsi; i++) { - if (pf->vsi[i] && - pf->vsi[i]->uplink_seid == uplink_seid && - (pf->vsi[i]->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) { + n = 0; + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->uplink_seid == uplink_seid && + (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) n++; /* count the VSIs */ - } - } - for (i = 0; i < I40E_MAX_VEB; i++) { - if (!pf->veb[i]) - continue; - if (pf->veb[i]->uplink_seid == uplink_seid) + + veb = NULL; + i40e_pf_for_each_veb(pf, i, veb_it) { + if (veb_it->uplink_seid == uplink_seid) n++; /* count the VEBs */ - if (pf->veb[i]->seid == uplink_seid) - veb = pf->veb[i]; + if (veb_it->seid == uplink_seid) + veb = veb_it; } if (n == 0 && veb && veb->uplink_seid != 0) i40e_veb_release(veb); @@ -14405,22 +14384,18 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, * * Find which uplink_seid we were given and create a new VEB if needed */ - for (i = 0; i < I40E_MAX_VEB; i++) { - if (pf->veb[i] && pf->veb[i]->seid == uplink_seid) { - veb = pf->veb[i]; + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == uplink_seid) break; - } - } + if (i == I40E_MAX_VEB) + veb = NULL; if (!veb && uplink_seid != pf->mac_seid) { - - for (i = 0; i < pf->num_alloc_vsi; i++) { - if (pf->vsi[i] && pf->vsi[i]->seid == uplink_seid) { - vsi = pf->vsi[i]; + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->seid == uplink_seid) break; - } - } - if (!vsi) { + + if (i == pf->num_alloc_vsi) { dev_info(&pf->pdev->dev, "no such uplink_seid %d\n", uplink_seid); return NULL; @@ -14448,11 +14423,10 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, } i40e_config_bridge_mode(veb); } - for (i = 0; i < I40E_MAX_VEB && !veb; i++) { - if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid) - veb = pf->veb[i]; - } - if (!veb) { + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == vsi->uplink_seid) + break; + if (i == I40E_MAX_VEB) { dev_info(&pf->pdev->dev, "couldn't add VEB\n"); return NULL; } @@ -14681,29 +14655,24 @@ static void i40e_switch_branch_release(struct i40e_veb *branch) struct i40e_pf *pf = branch->pf; u16 branch_seid = branch->seid; u16 veb_idx = branch->idx; + struct i40e_vsi *vsi; + struct i40e_veb *veb; int i; /* release any VEBs on this VEB - RECURSION */ - for (i = 0; i < I40E_MAX_VEB; i++) { - if (!pf->veb[i]) - continue; - if (pf->veb[i]->uplink_seid == branch->seid) - i40e_switch_branch_release(pf->veb[i]); - } + i40e_pf_for_each_veb(pf, i, veb) + if (veb->uplink_seid == branch->seid) + i40e_switch_branch_release(veb); /* Release the VSIs on this VEB, but not the owner VSI. * * NOTE: Removing the last VSI on a VEB has the SIDE EFFECT of removing * the VEB itself, so don't use (*branch) after this loop. */ - for (i = 0; i < pf->num_alloc_vsi; i++) { - if (!pf->vsi[i]) - continue; - if (pf->vsi[i]->uplink_seid == branch_seid && - (pf->vsi[i]->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) { - i40e_vsi_release(pf->vsi[i]); - } - } + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->uplink_seid == branch_seid && + (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) + i40e_vsi_release(vsi); /* There's one corner case where the VEB might not have been * removed, so double check it here and remove it if needed. @@ -14741,19 +14710,19 @@ static void i40e_veb_clear(struct i40e_veb *veb) **/ void i40e_veb_release(struct i40e_veb *veb) { - struct i40e_vsi *vsi = NULL; + struct i40e_vsi *vsi, *vsi_it; struct i40e_pf *pf; int i, n = 0; pf = veb->pf; /* find the remaining VSI and check for extras */ - for (i = 0; i < pf->num_alloc_vsi; i++) { - if (pf->vsi[i] && pf->vsi[i]->uplink_seid == veb->seid) { + i40e_pf_for_each_vsi(pf, i, vsi_it) + if (vsi_it->uplink_seid == veb->seid) { + vsi = vsi_it; n++; - vsi = pf->vsi[i]; } - } + if (n != 1) { dev_info(&pf->pdev->dev, "can't remove VEB %d with %d VSIs left\n", @@ -14851,6 +14820,7 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u8 enabled_tc) { struct i40e_veb *veb, *uplink_veb = NULL; + struct i40e_vsi *vsi; int vsi_idx, veb_idx; int ret; @@ -14864,9 +14834,10 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, } /* make sure there is such a vsi and uplink */ - for (vsi_idx = 0; vsi_idx < pf->num_alloc_vsi; vsi_idx++) - if (pf->vsi[vsi_idx] && pf->vsi[vsi_idx]->seid == vsi_seid) + i40e_pf_for_each_vsi(pf, vsi_idx, vsi) + if (vsi->seid == vsi_seid) break; + if (vsi_idx == pf->num_alloc_vsi && vsi_seid != 0) { dev_info(&pf->pdev->dev, "vsi seid %d not found\n", vsi_seid); @@ -14874,10 +14845,9 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, } if (uplink_seid && uplink_seid != pf->mac_seid) { - for (veb_idx = 0; veb_idx < I40E_MAX_VEB; veb_idx++) { - if (pf->veb[veb_idx] && - pf->veb[veb_idx]->seid == uplink_seid) { - uplink_veb = pf->veb[veb_idx]; + i40e_pf_for_each_veb(pf, veb_idx, veb) { + if (veb->seid == uplink_seid) { + uplink_veb = veb; break; } } @@ -14899,7 +14869,7 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, veb->enabled_tc = (enabled_tc ? enabled_tc : 0x1); /* create the VEB in the switch */ - ret = i40e_add_veb(veb, pf->vsi[vsi_idx]); + ret = i40e_add_veb(veb, vsi); if (ret) goto err_veb; if (vsi_idx == pf->lan_vsi) @@ -14930,6 +14900,7 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, u16 uplink_seid = le16_to_cpu(ele->uplink_seid); u8 element_type = ele->element_type; u16 seid = le16_to_cpu(ele->seid); + struct i40e_veb *veb; if (printconfig) dev_info(&pf->pdev->dev, @@ -14948,12 +14919,12 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, int v; /* find existing or else empty VEB */ - for (v = 0; v < I40E_MAX_VEB; v++) { - if (pf->veb[v] && (pf->veb[v]->seid == seid)) { + i40e_pf_for_each_veb(pf, v, veb) + if (veb->seid == seid) { pf->lan_veb = v; break; } - } + if (pf->lan_veb >= I40E_MAX_VEB) { v = i40e_veb_mem_alloc(pf); if (v < 0) @@ -16238,6 +16209,8 @@ static void i40e_remove(struct pci_dev *pdev) { struct i40e_pf *pf = pci_get_drvdata(pdev); struct i40e_hw *hw = &pf->hw; + struct i40e_vsi *vsi; + struct i40e_veb *veb; int ret_code; int i; @@ -16295,24 +16268,19 @@ static void i40e_remove(struct pci_dev *pdev) /* If there is a switch structure or any orphans, remove them. * This will leave only the PF's VSI remaining. */ - for (i = 0; i < I40E_MAX_VEB; i++) { - if (!pf->veb[i]) - continue; - - if (pf->veb[i]->uplink_seid == pf->mac_seid || - pf->veb[i]->uplink_seid == 0) - i40e_switch_branch_release(pf->veb[i]); - } + i40e_pf_for_each_veb(pf, i, veb) + if (veb->uplink_seid == pf->mac_seid || + veb->uplink_seid == 0) + i40e_switch_branch_release(veb); /* Now we can shutdown the PF's VSIs, just before we kill * adminq and hmc. */ - for (i = pf->num_alloc_vsi; i--;) - if (pf->vsi[i]) { - i40e_vsi_close(pf->vsi[i]); - i40e_vsi_release(pf->vsi[i]); - pf->vsi[i] = NULL; - } + i40e_pf_for_each_vsi(pf, i, vsi) { + i40e_vsi_close(vsi); + i40e_vsi_release(vsi); + pf->vsi[i] = NULL; + } i40e_cloud_filter_exit(pf); @@ -16349,18 +16317,17 @@ unmap: /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */ rtnl_lock(); i40e_clear_interrupt_scheme(pf); - for (i = 0; i < pf->num_alloc_vsi; i++) { - if (pf->vsi[i]) { - if (!test_bit(__I40E_RECOVERY_MODE, pf->state)) - i40e_vsi_clear_rings(pf->vsi[i]); - i40e_vsi_clear(pf->vsi[i]); - pf->vsi[i] = NULL; - } + i40e_pf_for_each_vsi(pf, i, vsi) { + if (!test_bit(__I40E_RECOVERY_MODE, pf->state)) + i40e_vsi_clear_rings(vsi); + + i40e_vsi_clear(vsi); + pf->vsi[i] = NULL; } rtnl_unlock(); - for (i = 0; i < I40E_MAX_VEB; i++) { - kfree(pf->veb[i]); + i40e_pf_for_each_veb(pf, i, veb) { + kfree(veb); pf->veb[i] = NULL; } From b7fac08db5e32a7de8c53e50dc7c841d123dda05 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Fri, 24 Nov 2023 16:03:41 +0100 Subject: [PATCH 1286/2255] i40e: Add helpers to find VSI and VEB by SEID and use them Add two helpers i40e_(veb|vsi)_get_by_seid() to find corresponding VEB or VSI by their SEID value and use these helpers to replace existing open-coded loops. Reviewed-by: Wojciech Drewek Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e.h | 36 ++++++++ .../net/ethernet/intel/i40e/i40e_debugfs.c | 38 ++------- drivers/net/ethernet/intel/i40e/i40e_main.c | 82 +++++++------------ 3 files changed, 69 insertions(+), 87 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 5acb26644be7..2990ff4f0306 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1355,4 +1355,40 @@ static inline struct i40e_pf *i40e_hw_to_pf(struct i40e_hw *hw) struct device *i40e_hw_to_dev(struct i40e_hw *hw); +/** + * i40e_pf_get_vsi_by_seid - find VSI by SEID + * @pf: pointer to a PF + * @seid: SEID of the VSI + **/ +static inline struct i40e_vsi * +i40e_pf_get_vsi_by_seid(struct i40e_pf *pf, u16 seid) +{ + struct i40e_vsi *vsi; + int i; + + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->seid == seid) + return vsi; + + return NULL; +} + +/** + * i40e_pf_get_veb_by_seid - find VEB by SEID + * @pf: pointer to a PF + * @seid: SEID of the VSI + **/ +static inline struct i40e_veb * +i40e_pf_get_veb_by_seid(struct i40e_pf *pf, u16 seid) +{ + struct i40e_veb *veb; + int i; + + i40e_pf_for_each_veb(pf, i, veb) + if (veb->seid == seid) + return veb; + + return NULL; +} + #endif /* _I40E_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index b236b0f93202..990a60889eef 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -24,37 +24,13 @@ enum ring_type { **/ static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid) { - struct i40e_vsi *vsi; - int i; - if (seid < 0) { dev_info(&pf->pdev->dev, "%d: bad seid\n", seid); return NULL; } - i40e_pf_for_each_vsi(pf, i, vsi) - if (vsi->seid == seid) - return vsi; - - return NULL; -} - -/** - * i40e_dbg_find_veb - searches for the veb with the given seid - * @pf: the PF structure to search for the veb - * @seid: seid of the veb it is searching for - **/ -static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid) -{ - struct i40e_veb *veb; - int i; - - i40e_pf_for_each_veb(pf, i, veb) - if (veb->seid == seid) - return veb; - - return NULL; + return i40e_pf_get_vsi_by_seid(pf, seid); } /************************************************************** @@ -701,7 +677,7 @@ static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid) { struct i40e_veb *veb; - veb = i40e_dbg_find_veb(pf, seid); + veb = i40e_pf_get_veb_by_seid(pf, seid); if (!veb) { dev_info(&pf->pdev->dev, "can't find veb %d\n", seid); return; @@ -853,7 +829,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } else if (strncmp(cmd_buf, "add relay", 9) == 0) { struct i40e_veb *veb; - int uplink_seid, i; + int uplink_seid; cnt = sscanf(&cmd_buf[9], "%i %i", &uplink_seid, &vsi_seid); if (cnt != 2) { @@ -875,12 +851,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp, goto command_write_done; } - i40e_pf_for_each_veb(pf, i, veb) - if (veb->seid == uplink_seid) - break; - - if (i >= I40E_MAX_VEB && uplink_seid != 0 && - uplink_seid != pf->mac_seid) { + veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); + if (!veb && uplink_seid != 0 && uplink_seid != pf->mac_seid) { dev_info(&pf->pdev->dev, "add relay: relay uplink %d not found\n", uplink_seid); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 43e1b4f7f9dc..e495a212d076 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -13106,18 +13106,14 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, struct i40e_pf *pf = vsi->back; struct nlattr *attr, *br_spec; struct i40e_veb *veb; - int i, rem; + int rem; /* Only for PF VSI for now */ if (vsi->seid != pf->vsi[pf->lan_vsi]->seid) return -EOPNOTSUPP; /* Find the HW bridge for PF VSI */ - i40e_pf_for_each_veb(pf, i, veb) - if (veb->seid == vsi->uplink_seid) - break; - if (i == I40E_MAX_VEB) - veb = NULL; /* No VEB found */ + veb = i40e_pf_get_veb_by_seid(pf, vsi->uplink_seid); br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); if (!br_spec) @@ -13182,18 +13178,15 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; - struct i40e_veb *veb = NULL; - int i; + struct i40e_veb *veb; /* Only for PF VSI for now */ if (vsi->seid != pf->vsi[pf->lan_vsi]->seid) return -EOPNOTSUPP; /* Find the HW bridge for the PF VSI */ - i40e_pf_for_each_veb(pf, i, veb) - if (veb->seid == vsi->uplink_seid) - break; - if (i == I40E_MAX_VEB) + veb = i40e_pf_get_veb_by_seid(pf, vsi->uplink_seid); + if (!veb) return 0; return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode, @@ -14368,8 +14361,8 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, struct i40e_vsi *vsi = NULL; struct i40e_veb *veb = NULL; u16 alloc_queue_pairs; - int ret, i; int v_idx; + int ret; /* The requested uplink_seid must be either * - the PF's port seid @@ -14384,18 +14377,10 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, * * Find which uplink_seid we were given and create a new VEB if needed */ - i40e_pf_for_each_veb(pf, i, veb) - if (veb->seid == uplink_seid) - break; - if (i == I40E_MAX_VEB) - veb = NULL; - + veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); if (!veb && uplink_seid != pf->mac_seid) { - i40e_pf_for_each_vsi(pf, i, vsi) - if (vsi->seid == uplink_seid) - break; - - if (i == pf->num_alloc_vsi) { + vsi = i40e_pf_get_vsi_by_seid(pf, uplink_seid); + if (!vsi) { dev_info(&pf->pdev->dev, "no such uplink_seid %d\n", uplink_seid); return NULL; @@ -14423,10 +14408,8 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, } i40e_config_bridge_mode(veb); } - i40e_pf_for_each_veb(pf, i, veb) - if (veb->seid == vsi->uplink_seid) - break; - if (i == I40E_MAX_VEB) { + veb = i40e_pf_get_veb_by_seid(pf, vsi->uplink_seid); + if (!veb) { dev_info(&pf->pdev->dev, "couldn't add VEB\n"); return NULL; } @@ -14820,8 +14803,8 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u8 enabled_tc) { struct i40e_veb *veb, *uplink_veb = NULL; - struct i40e_vsi *vsi; - int vsi_idx, veb_idx; + struct i40e_vsi *vsi = NULL; + int veb_idx; int ret; /* if one seid is 0, the other must be 0 to create a floating relay */ @@ -14834,23 +14817,16 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, } /* make sure there is such a vsi and uplink */ - i40e_pf_for_each_vsi(pf, vsi_idx, vsi) - if (vsi->seid == vsi_seid) - break; - - if (vsi_idx == pf->num_alloc_vsi && vsi_seid != 0) { - dev_info(&pf->pdev->dev, "vsi seid %d not found\n", - vsi_seid); - return NULL; - } - - if (uplink_seid && uplink_seid != pf->mac_seid) { - i40e_pf_for_each_veb(pf, veb_idx, veb) { - if (veb->seid == uplink_seid) { - uplink_veb = veb; - break; - } + if (vsi_seid) { + vsi = i40e_pf_get_vsi_by_seid(pf, vsi_seid); + if (!vsi) { + dev_err(&pf->pdev->dev, "vsi seid %d not found\n", + vsi_seid); + return NULL; } + } + if (uplink_seid && uplink_seid != pf->mac_seid) { + uplink_veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); if (!uplink_veb) { dev_info(&pf->pdev->dev, "uplink seid %d not found\n", uplink_seid); @@ -14872,7 +14848,8 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, ret = i40e_add_veb(veb, vsi); if (ret) goto err_veb; - if (vsi_idx == pf->lan_vsi) + + if (vsi && vsi->idx == pf->lan_vsi) pf->lan_veb = veb->idx; return veb; @@ -14919,13 +14896,10 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, int v; /* find existing or else empty VEB */ - i40e_pf_for_each_veb(pf, v, veb) - if (veb->seid == seid) { - pf->lan_veb = v; - break; - } - - if (pf->lan_veb >= I40E_MAX_VEB) { + veb = i40e_pf_get_veb_by_seid(pf, seid); + if (veb) { + pf->lan_veb = veb->idx; + } else { v = i40e_veb_mem_alloc(pf); if (v < 0) break; From 08cdde310e2252ea9381a37c3faa2125a5a663a3 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Fri, 24 Nov 2023 16:03:42 +0100 Subject: [PATCH 1287/2255] i40e: Fix broken support for floating VEBs Although the i40e supports so-called floating VEB (VEB without an uplink connection to external network), this support is broken. This functionality is currently unused (except debugfs) but it will be used by subsequent series for switchdev mode slow-path. Fix this by following: 1) Handle correctly floating VEB (VEB with uplink_seid == 0) in i40e_reconstitute_veb() and look for owner VSI and create it only for non-floating VEBs and also set bridge mode only for such VEBs as the floating ones are using always VEB mode. 2) Handle correctly floating VEB in i40e_veb_release() and disallow its release when there are some VSIs. This is different from regular VEB that have owner VSI that is connected to VEB's uplink after VEB deletion by FW. 3) Fix i40e_add_veb() to handle 'vsi' that is NULL for floating VEBs. For floating VEB use 0 for downlink SEID and 'true' for 'default_port' parameters as per datasheet. 4) Fix 'add relay' command in i40e_dbg_command_write() to allow to create floating VEB by 'add relay 0 0' or 'add relay' Tested using debugfs: 1) Initial state [root@host net-next]# echo dump switch > $CMD [root@host net-next]# dmesg -c [ 173.701286] i40e 0000:02:00.0: header: 3 reported 3 total [ 173.706701] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 173.713241] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 173.719507] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 2) Add floating VEB [root@host net-next]# CMD="/sys/kernel/debug/i40e/0000:02:00.0/command" [root@host net-next]# echo add relay > $CMD [root@host net-next]# dmesg -c [ 245.551720] i40e 0000:02:00.0: added relay 162 [root@host net-next]# echo dump switch > $CMD [root@host net-next]# dmesg -c [ 276.984371] i40e 0000:02:00.0: header: 4 reported 4 total [ 276.989779] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 276.996302] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 277.002569] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 [ 277.009091] i40e 0000:02:00.0: type=17 seid=162 uplink=0 downlink=0 3) Add VMDQ2 VSI to this new VEB [root@host net-next]# echo add vsi 162 > $CMD [root@host net-next]# dmesg -c [ 332.314030] i40e 0000:02:00.0: added VSI 394 to relay 162 [ 332.337486] enp2s0f0np0v0: NIC Link is Up, 40 Gbps Full Duplex, Flow Control: None [root@host net-next]# echo dump switch > $CMD [root@host net-next]# dmesg -c [ 387.284490] i40e 0000:02:00.0: header: 5 reported 5 total [ 387.289904] i40e 0000:02:00.0: type=19 seid=394 uplink=162 downlink=16 [ 387.296446] i40e 0000:02:00.0: type=17 seid=162 uplink=0 downlink=0 [ 387.302708] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 387.309234] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 387.315500] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 4) Try to delete the VEB [root@host net-next]# echo del relay 162 > $CMD [root@host net-next]# dmesg -c [ 428.749297] i40e 0000:02:00.0: deleting relay 162 [ 428.754011] i40e 0000:02:00.0: can't remove VEB 162 with 1 VSIs left 5) Do PF reset and check switch status after rebuild [root@host net-next]# echo pfr > $CMD [root@host net-next]# echo dump switch > $CMD [root@host net-next]# dmesg -c [ 738.056172] i40e 0000:02:00.0: header: 5 reported 5 total [ 738.061577] i40e 0000:02:00.0: type=19 seid=394 uplink=162 downlink=16 [ 738.068104] i40e 0000:02:00.0: type=17 seid=162 uplink=0 downlink=0 [ 738.074367] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 738.080892] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 738.087160] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 6) Delete VSI and delete VEB [root@host net-next]# echo del vsi 394 > $CMD [root@host net-next]# echo del relay 162 > $CMD [root@host net-next]# echo dump switch > $CMD [root@host net-next]# dmesg -c [ 1233.081126] i40e 0000:02:00.0: deleting VSI 394 [ 1239.345139] i40e 0000:02:00.0: deleting relay 162 [ 1244.886920] i40e 0000:02:00.0: header: 3 reported 3 total [ 1244.892328] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 1244.898853] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 1244.905119] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 Reviewed-by: Wojciech Drewek Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/i40e/i40e_debugfs.c | 29 +++--- drivers/net/ethernet/intel/i40e/i40e_main.c | 89 ++++++++++--------- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 990a60889eef..921a97d5479e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -829,10 +829,14 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } else if (strncmp(cmd_buf, "add relay", 9) == 0) { struct i40e_veb *veb; + u8 enabled_tc = 0x1; int uplink_seid; cnt = sscanf(&cmd_buf[9], "%i %i", &uplink_seid, &vsi_seid); - if (cnt != 2) { + if (cnt == 0) { + uplink_seid = 0; + vsi_seid = 0; + } else if (cnt != 2) { dev_info(&pf->pdev->dev, "add relay: bad command string, cnt=%d\n", cnt); @@ -844,23 +848,28 @@ static ssize_t i40e_dbg_command_write(struct file *filp, goto command_write_done; } - vsi = i40e_dbg_find_vsi(pf, vsi_seid); - if (!vsi) { - dev_info(&pf->pdev->dev, - "add relay: VSI %d not found\n", vsi_seid); - goto command_write_done; - } - veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); if (!veb && uplink_seid != 0 && uplink_seid != pf->mac_seid) { dev_info(&pf->pdev->dev, "add relay: relay uplink %d not found\n", uplink_seid); goto command_write_done; + } else if (uplink_seid) { + vsi = i40e_pf_get_vsi_by_seid(pf, vsi_seid); + if (!vsi) { + dev_info(&pf->pdev->dev, + "add relay: VSI %d not found\n", + vsi_seid); + goto command_write_done; + } + enabled_tc = vsi->tc_config.enabled_tc; + } else if (vsi_seid) { + dev_info(&pf->pdev->dev, + "add relay: VSI must be 0 for floating relay\n"); + goto command_write_done; } - veb = i40e_veb_setup(pf, 0, uplink_seid, vsi_seid, - vsi->tc_config.enabled_tc); + veb = i40e_veb_setup(pf, 0, uplink_seid, vsi_seid, enabled_tc); if (veb) dev_info(&pf->pdev->dev, "added relay %d\n", veb->seid); else diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index e495a212d076..31d1b1ff07b0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10372,41 +10372,48 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) struct i40e_vsi *vsi; int v, ret; - /* build VSI that owns this VEB, temporarily attached to base VEB */ - i40e_pf_for_each_vsi(pf, v, vsi) - if (vsi->veb_idx == veb->idx && - vsi->flags & I40E_VSI_FLAG_VEB_OWNER) { - ctl_vsi = vsi; - break; - } + if (veb->uplink_seid) { + /* Look for VSI that owns this VEB, temporarily attached to base VEB */ + i40e_pf_for_each_vsi(pf, v, vsi) + if (vsi->veb_idx == veb->idx && + vsi->flags & I40E_VSI_FLAG_VEB_OWNER) { + ctl_vsi = vsi; + break; + } - if (!ctl_vsi) { - dev_info(&pf->pdev->dev, - "missing owner VSI for veb_idx %d\n", veb->idx); - ret = -ENOENT; - goto end_reconstitute; + if (!ctl_vsi) { + dev_info(&pf->pdev->dev, + "missing owner VSI for veb_idx %d\n", + veb->idx); + ret = -ENOENT; + goto end_reconstitute; + } + if (ctl_vsi != pf->vsi[pf->lan_vsi]) + ctl_vsi->uplink_seid = + pf->vsi[pf->lan_vsi]->uplink_seid; + + ret = i40e_add_vsi(ctl_vsi); + if (ret) { + dev_info(&pf->pdev->dev, + "rebuild of veb_idx %d owner VSI failed: %d\n", + veb->idx, ret); + goto end_reconstitute; + } + i40e_vsi_reset_stats(ctl_vsi); } - if (ctl_vsi != pf->vsi[pf->lan_vsi]) - ctl_vsi->uplink_seid = pf->vsi[pf->lan_vsi]->uplink_seid; - ret = i40e_add_vsi(ctl_vsi); - if (ret) { - dev_info(&pf->pdev->dev, - "rebuild of veb_idx %d owner VSI failed: %d\n", - veb->idx, ret); - goto end_reconstitute; - } - i40e_vsi_reset_stats(ctl_vsi); /* create the VEB in the switch and move the VSI onto the VEB */ ret = i40e_add_veb(veb, ctl_vsi); if (ret) goto end_reconstitute; - if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) - veb->bridge_mode = BRIDGE_MODE_VEB; - else - veb->bridge_mode = BRIDGE_MODE_VEPA; - i40e_config_bridge_mode(veb); + if (veb->uplink_seid) { + if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) + veb->bridge_mode = BRIDGE_MODE_VEB; + else + veb->bridge_mode = BRIDGE_MODE_VEPA; + i40e_config_bridge_mode(veb); + } /* create the remaining VSIs attached to this VEB */ i40e_pf_for_each_vsi(pf, v, vsi) { @@ -14702,29 +14709,29 @@ void i40e_veb_release(struct i40e_veb *veb) /* find the remaining VSI and check for extras */ i40e_pf_for_each_vsi(pf, i, vsi_it) if (vsi_it->uplink_seid == veb->seid) { - vsi = vsi_it; + if (vsi_it->flags & I40E_VSI_FLAG_VEB_OWNER) + vsi = vsi_it; n++; } - if (n != 1) { + /* Floating VEB has to be empty and regular one must have + * single owner VSI. + */ + if ((veb->uplink_seid && n != 1) || (!veb->uplink_seid && n != 0)) { dev_info(&pf->pdev->dev, "can't remove VEB %d with %d VSIs left\n", veb->seid, n); return; } - /* move the remaining VSI to uplink veb */ - vsi->flags &= ~I40E_VSI_FLAG_VEB_OWNER; + /* For regular VEB move the owner VSI to uplink VEB */ if (veb->uplink_seid) { + vsi->flags &= ~I40E_VSI_FLAG_VEB_OWNER; vsi->uplink_seid = veb->uplink_seid; if (veb->uplink_seid == pf->mac_seid) vsi->veb_idx = I40E_NO_VEB; else vsi->veb_idx = veb->veb_idx; - } else { - /* floating VEB */ - vsi->uplink_seid = pf->vsi[pf->lan_vsi]->uplink_seid; - vsi->veb_idx = pf->vsi[pf->lan_vsi]->veb_idx; } i40e_aq_delete_element(&pf->hw, veb->seid, NULL); @@ -14742,8 +14749,8 @@ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) bool enable_stats = !!test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags); int ret; - ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid, - veb->enabled_tc, false, + ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi ? vsi->seid : 0, + veb->enabled_tc, vsi ? false : true, &veb->seid, enable_stats, NULL); /* get a VEB from the hardware */ @@ -14775,9 +14782,11 @@ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) return -ENOENT; } - vsi->uplink_seid = veb->seid; - vsi->veb_idx = veb->idx; - vsi->flags |= I40E_VSI_FLAG_VEB_OWNER; + if (vsi) { + vsi->uplink_seid = veb->seid; + vsi->veb_idx = veb->idx; + vsi->flags |= I40E_VSI_FLAG_VEB_OWNER; + } return 0; } From f09cbb6c94e47b4be985bfd3c8cf453818f5ef9d Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Fri, 24 Nov 2023 16:03:43 +0100 Subject: [PATCH 1288/2255] i40e: Remove VEB recursion The VEB (virtual embedded switch) as a switch element can be connected according datasheet though its uplink to: - Physical port - Port Virtualizer (not used directly by i40e driver but can be present in MFP mode where the physical port is shared between PFs) - No uplink (aka floating VEB) But VEB uplink cannot be connected to another VEB and any attempt to do so results in: "i40e 0000:02:00.0: couldn't add VEB, err -EIO aq_err I40E_AQ_RC_ENOENT" that indicates "the uplink SEID does not point to valid element". Remove this logic from the driver code this way: 1) For debugfs only allow to build floating VEB (uplink_seid == 0) or main VEB (uplink_seid == mac_seid) 2) Do not recurse in i40e_veb_link_event() as no VEB cannot have sub-VEBs 3) Ditto for i40e_veb_rebuild() + simplify the function as we know that the VEB for rebuild can be only the main LAN VEB or some of the floating VEBs 4) In i40e_rebuild() there is no need to check veb->uplink_seid as the possible ones are 0 and MAC SEID 5) In i40e_vsi_release() do not take into account VEBs whose uplink is another VEB as this is not possible 6) Remove veb_idx field from i40e_veb as a VEB cannot have sub-VEBs Tested using i40e debugfs interface: 1) Initial state [root@cnb-03 net-next]# CMD="/sys/kernel/debug/i40e/0000:02:00.0/command" [root@cnb-03 net-next]# echo dump switch > $CMD [root@cnb-03 net-next]# dmesg -c [ 98.440641] i40e 0000:02:00.0: header: 3 reported 3 total [ 98.446053] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 98.452593] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 98.458856] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 2) Add floating VEB [root@cnb-03 net-next]# echo add relay > $CMD [root@cnb-03 net-next]# dmesg -c [ 122.745630] i40e 0000:02:00.0: added relay 162 [root@cnb-03 net-next]# echo dump switch > $CMD [root@cnb-03 net-next]# dmesg -c [ 136.650049] i40e 0000:02:00.0: header: 4 reported 4 total [ 136.655466] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 136.661994] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 136.668264] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 [ 136.674787] i40e 0000:02:00.0: type=17 seid=162 uplink=0 downlink=0 3) Add VMDQ2 VSI to this new VEB [root@cnb-03 net-next]# dmesg -c [ 168.351763] i40e 0000:02:00.0: added VSI 394 to relay 162 [ 168.374652] enp2s0f0np0v0: NIC Link is Up, 40 Gbps Full Duplex, Flow Control: None [root@cnb-03 net-next]# echo dump switch > $CMD [root@cnb-03 net-next]# dmesg -c [ 195.683204] i40e 0000:02:00.0: header: 5 reported 5 total [ 195.688611] i40e 0000:02:00.0: type=19 seid=394 uplink=162 downlink=16 [ 195.695143] i40e 0000:02:00.0: type=17 seid=162 uplink=0 downlink=0 [ 195.701410] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 195.707935] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 195.714201] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 4) Try to delete the VEB [root@cnb-03 net-next]# echo del relay 162 > $CMD [root@cnb-03 net-next]# dmesg -c [ 239.260901] i40e 0000:02:00.0: deleting relay 162 [ 239.265621] i40e 0000:02:00.0: can't remove VEB 162 with 1 VSIs left 5) Do PF reset and check switch status after rebuild [root@cnb-03 net-next]# echo pfr > $CMD [root@cnb-03 net-next]# echo dump switch > $CMD [root@cnb-03 net-next]# dmesg -c ... [ 272.333655] i40e 0000:02:00.0: header: 5 reported 5 total [ 272.339066] i40e 0000:02:00.0: type=19 seid=394 uplink=162 downlink=16 [ 272.345599] i40e 0000:02:00.0: type=17 seid=162 uplink=0 downlink=0 [ 272.351862] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 272.358387] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 272.364654] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 6) Delete VSI and delete VEB [ 297.199116] i40e 0000:02:00.0: deleting VSI 394 [ 299.807580] i40e 0000:02:00.0: deleting relay 162 [ 309.767905] i40e 0000:02:00.0: header: 3 reported 3 total [ 309.773318] i40e 0000:02:00.0: type=19 seid=392 uplink=160 downlink=16 [ 309.779845] i40e 0000:02:00.0: type=17 seid=160 uplink=2 downlink=0 [ 309.786111] i40e 0000:02:00.0: type=19 seid=390 uplink=160 downlink=16 Reviewed-by: Wojciech Drewek Signed-off-by: Ivan Vecera Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e.h | 1 - .../net/ethernet/intel/i40e/i40e_debugfs.c | 8 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 176 ++++++++---------- 3 files changed, 76 insertions(+), 109 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 2990ff4f0306..ba24f3fa92c3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -783,7 +783,6 @@ struct i40e_new_mac_filter { struct i40e_veb { struct i40e_pf *pf; u16 idx; - u16 veb_idx; /* index of VEB parent */ u16 seid; u16 uplink_seid; u16 stats_idx; /* index of VEB parent */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 921a97d5479e..f9ba45f596c9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -683,9 +683,8 @@ static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid) return; } dev_info(&pf->pdev->dev, - "veb idx=%d,%d stats_ic=%d seid=%d uplink=%d mode=%s\n", - veb->idx, veb->veb_idx, veb->stats_idx, veb->seid, - veb->uplink_seid, + "veb idx=%d stats_ic=%d seid=%d uplink=%d mode=%s\n", + veb->idx, veb->stats_idx, veb->seid, veb->uplink_seid, veb->bridge_mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB"); i40e_dbg_dump_eth_stats(pf, &veb->stats); } @@ -848,8 +847,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, goto command_write_done; } - veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); - if (!veb && uplink_seid != 0 && uplink_seid != pf->mac_seid) { + if (uplink_seid != 0 && uplink_seid != pf->mac_seid) { dev_info(&pf->pdev->dev, "add relay: relay uplink %d not found\n", uplink_seid); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 31d1b1ff07b0..f12092cdb1f0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9873,7 +9873,6 @@ static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up) **/ static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up) { - struct i40e_veb *veb_it; struct i40e_vsi *vsi; struct i40e_pf *pf; int i; @@ -9882,12 +9881,7 @@ static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up) return; pf = veb->pf; - /* depth first... */ - i40e_pf_for_each_veb(pf, i, veb_it) - if (veb_it->uplink_seid == veb->seid) - i40e_veb_link_event(veb_it, link_up); - - /* ... now the local VSIs */ + /* Send link event to contained VSIs */ i40e_pf_for_each_vsi(pf, i, vsi) if (vsi->uplink_seid == veb->seid) i40e_vsi_link_event(vsi, link_up); @@ -10356,56 +10350,57 @@ static void i40e_config_bridge_mode(struct i40e_veb *veb) } /** - * i40e_reconstitute_veb - rebuild the VEB and anything connected to it + * i40e_reconstitute_veb - rebuild the VEB and VSIs connected to it * @veb: pointer to the VEB instance * - * This is a recursive function that first builds the attached VSIs then - * recurses in to build the next layer of VEB. We track the connections - * through our own index numbers because the seid's from the HW could - * change across the reset. + * This is a function that builds the attached VSIs. We track the connections + * through our own index numbers because the seid's from the HW could change + * across the reset. **/ static int i40e_reconstitute_veb(struct i40e_veb *veb) { struct i40e_vsi *ctl_vsi = NULL; struct i40e_pf *pf = veb->pf; - struct i40e_veb *veb_it; struct i40e_vsi *vsi; int v, ret; - if (veb->uplink_seid) { - /* Look for VSI that owns this VEB, temporarily attached to base VEB */ - i40e_pf_for_each_vsi(pf, v, vsi) - if (vsi->veb_idx == veb->idx && - vsi->flags & I40E_VSI_FLAG_VEB_OWNER) { - ctl_vsi = vsi; - break; - } + /* As we do not maintain PV (port virtualizer) switch element then + * there can be only one non-floating VEB that have uplink to MAC SEID + * and its control VSI is the main one. + */ + if (WARN_ON(veb->uplink_seid && veb->uplink_seid != pf->mac_seid)) { + dev_err(&pf->pdev->dev, + "Invalid uplink SEID for VEB %d\n", veb->idx); + return -ENOENT; + } - if (!ctl_vsi) { - dev_info(&pf->pdev->dev, - "missing owner VSI for veb_idx %d\n", - veb->idx); - ret = -ENOENT; - goto end_reconstitute; + if (veb->uplink_seid == pf->mac_seid) { + /* Check that the LAN VSI has VEB owning flag set */ + ctl_vsi = pf->vsi[pf->lan_vsi]; + + if (WARN_ON(ctl_vsi->veb_idx != veb->idx || + !(ctl_vsi->flags & I40E_VSI_FLAG_VEB_OWNER))) { + dev_err(&pf->pdev->dev, + "Invalid control VSI for VEB %d\n", veb->idx); + return -ENOENT; } - if (ctl_vsi != pf->vsi[pf->lan_vsi]) - ctl_vsi->uplink_seid = - pf->vsi[pf->lan_vsi]->uplink_seid; + /* Add the control VSI to switch */ ret = i40e_add_vsi(ctl_vsi); if (ret) { - dev_info(&pf->pdev->dev, - "rebuild of veb_idx %d owner VSI failed: %d\n", - veb->idx, ret); - goto end_reconstitute; + dev_err(&pf->pdev->dev, + "Rebuild of owner VSI for VEB %d failed: %d\n", + veb->idx, ret); + return ret; } + i40e_vsi_reset_stats(ctl_vsi); } /* create the VEB in the switch and move the VSI onto the VEB */ ret = i40e_add_veb(veb, ctl_vsi); if (ret) - goto end_reconstitute; + return ret; if (veb->uplink_seid) { if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) @@ -10427,23 +10422,12 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) dev_info(&pf->pdev->dev, "rebuild of vsi_idx %d failed: %d\n", v, ret); - goto end_reconstitute; + return ret; } i40e_vsi_reset_stats(vsi); } } - /* create any VEBs attached to this VEB - RECURSION */ - i40e_pf_for_each_veb(pf, v, veb_it) { - if (veb_it->veb_idx == veb->idx) { - veb_it->uplink_seid = veb->seid; - ret = i40e_reconstitute_veb(veb_it); - if (ret) - break; - } - } - -end_reconstitute: return ret; } @@ -10984,31 +10968,29 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) */ if (vsi->uplink_seid != pf->mac_seid) { dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n"); - /* find the one VEB connected to the MAC, and find orphans */ - i40e_pf_for_each_veb(pf, v, veb) { - if (veb->uplink_seid == pf->mac_seid || - veb->uplink_seid == 0) { - ret = i40e_reconstitute_veb(veb); - if (!ret) - continue; - /* If Main VEB failed, we're in deep doodoo, - * so give up rebuilding the switch and set up - * for minimal rebuild of PF VSI. - * If orphan failed, we'll report the error - * but try to keep going. - */ - if (veb->uplink_seid == pf->mac_seid) { - dev_info(&pf->pdev->dev, - "rebuild of switch failed: %d, will try to set up simple PF connection\n", - ret); - vsi->uplink_seid = pf->mac_seid; - break; - } else if (veb->uplink_seid == 0) { - dev_info(&pf->pdev->dev, - "rebuild of orphan VEB failed: %d\n", - ret); - } + /* Rebuild VEBs */ + i40e_pf_for_each_veb(pf, v, veb) { + ret = i40e_reconstitute_veb(veb); + if (!ret) + continue; + + /* If Main VEB failed, we're in deep doodoo, + * so give up rebuilding the switch and set up + * for minimal rebuild of PF VSI. + * If orphan failed, we'll report the error + * but try to keep going. + */ + if (veb->uplink_seid == pf->mac_seid) { + dev_info(&pf->pdev->dev, + "rebuild of switch failed: %d, will try to set up simple PF connection\n", + ret); + vsi->uplink_seid = pf->mac_seid; + break; + } else if (veb->uplink_seid == 0) { + dev_info(&pf->pdev->dev, + "rebuild of orphan VEB failed: %d\n", + ret); } } } @@ -14124,9 +14106,9 @@ err: **/ int i40e_vsi_release(struct i40e_vsi *vsi) { - struct i40e_veb *veb, *veb_it; struct i40e_mac_filter *f; struct hlist_node *h; + struct i40e_veb *veb; struct i40e_pf *pf; u16 uplink_seid; int i, n, bkt; @@ -14190,27 +14172,28 @@ int i40e_vsi_release(struct i40e_vsi *vsi) /* If this was the last thing on the VEB, except for the * controlling VSI, remove the VEB, which puts the controlling - * VSI onto the next level down in the switch. + * VSI onto the uplink port. * * Well, okay, there's one more exception here: don't remove - * the orphan VEBs yet. We'll wait for an explicit remove request + * the floating VEBs yet. We'll wait for an explicit remove request * from up the network stack. */ - n = 0; - i40e_pf_for_each_vsi(pf, i, vsi) - if (vsi->uplink_seid == uplink_seid && - (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) - n++; /* count the VSIs */ + veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); + if (veb && veb->uplink_seid) { + n = 0; - veb = NULL; - i40e_pf_for_each_veb(pf, i, veb_it) { - if (veb_it->uplink_seid == uplink_seid) - n++; /* count the VEBs */ - if (veb_it->seid == uplink_seid) - veb = veb_it; + /* Count non-controlling VSIs present on the VEB */ + i40e_pf_for_each_vsi(pf, i, vsi) + if (vsi->uplink_seid == uplink_seid && + (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) + n++; + + /* If there is no VSI except the control one then release + * the VEB and put the control VSI onto VEB uplink. + */ + if (!n) + i40e_veb_release(veb); } - if (n == 0 && veb && veb->uplink_seid != 0) - i40e_veb_release(veb); return 0; } @@ -14724,14 +14707,11 @@ void i40e_veb_release(struct i40e_veb *veb) return; } - /* For regular VEB move the owner VSI to uplink VEB */ + /* For regular VEB move the owner VSI to uplink port */ if (veb->uplink_seid) { vsi->flags &= ~I40E_VSI_FLAG_VEB_OWNER; vsi->uplink_seid = veb->uplink_seid; - if (veb->uplink_seid == pf->mac_seid) - vsi->veb_idx = I40E_NO_VEB; - else - vsi->veb_idx = veb->veb_idx; + vsi->veb_idx = I40E_NO_VEB; } i40e_aq_delete_element(&pf->hw, veb->seid, NULL); @@ -14811,8 +14791,8 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u16 uplink_seid, u16 vsi_seid, u8 enabled_tc) { - struct i40e_veb *veb, *uplink_veb = NULL; struct i40e_vsi *vsi = NULL; + struct i40e_veb *veb; int veb_idx; int ret; @@ -14834,14 +14814,6 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, return NULL; } } - if (uplink_seid && uplink_seid != pf->mac_seid) { - uplink_veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); - if (!uplink_veb) { - dev_info(&pf->pdev->dev, - "uplink seid %d not found\n", uplink_seid); - return NULL; - } - } /* get veb sw struct */ veb_idx = i40e_veb_mem_alloc(pf); @@ -14850,7 +14822,6 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, veb = pf->veb[veb_idx]; veb->flags = flags; veb->uplink_seid = uplink_seid; - veb->veb_idx = (uplink_veb ? uplink_veb->idx : I40E_NO_VEB); veb->enabled_tc = (enabled_tc ? enabled_tc : 0x1); /* create the VEB in the switch */ @@ -14921,7 +14892,6 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, pf->veb[pf->lan_veb]->seid = seid; pf->veb[pf->lan_veb]->uplink_seid = pf->mac_seid; pf->veb[pf->lan_veb]->pf = pf; - pf->veb[pf->lan_veb]->veb_idx = I40E_NO_VEB; break; case I40E_SWITCH_ELEMENT_TYPE_VSI: if (num_reported != 1) From 80e4021c25d8c1ddae0dd655ed5f6b1e938dd79b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 14 Feb 2024 21:16:19 +0100 Subject: [PATCH 1289/2255] net: mdio: add helpers for accessing the EEE CAP2 registers This adds helpers for accessing the EEE CAP2 registers. For now only 2500baseT and 5000baseT modes are supported. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- include/linux/mdio.h | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 79ceee3c8673..fd8ff310f9eb 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -439,6 +439,42 @@ static inline void mii_eee_cap1_mod_linkmode_t(unsigned long *adv, u32 val) adv, val & MDIO_EEE_10GKR); } +/** + * mii_eee_cap2_mod_linkmode_sup_t() + * @adv: target the linkmode settings + * @val: register value + * + * A function that translates value of following registers to the linkmode: + * IEEE 802.3-2022 45.2.3.11 "EEE control and capability 2" register (3.21) + */ +static inline void mii_eee_cap2_mod_linkmode_sup_t(unsigned long *adv, u32 val) +{ + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + adv, val & MDIO_EEE_2_5GT); + linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + adv, val & MDIO_EEE_5GT); +} + +/** + * mii_eee_cap2_mod_linkmode_adv_t() + * @adv: target the linkmode advertisement settings + * @val: register value + * + * A function that translates value of following registers to the linkmode: + * IEEE 802.3-2022 45.2.7.16 "EEE advertisement 2" register (7.62) + * IEEE 802.3-2022 45.2.7.17 "EEE link partner ability 2" register (7.63) + * Note: Currently this function is the same as mii_eee_cap2_mod_linkmode_sup_t. + * For certain, not yet supported, modes however the bits differ. + * Therefore create separate functions already. + */ +static inline void mii_eee_cap2_mod_linkmode_adv_t(unsigned long *adv, u32 val) +{ + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + adv, val & MDIO_EEE_2_5GT); + linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + adv, val & MDIO_EEE_5GT); +} + /** * linkmode_to_mii_eee_cap1_t() * @adv: the linkmode advertisement settings @@ -466,6 +502,25 @@ static inline u32 linkmode_to_mii_eee_cap1_t(unsigned long *adv) return result; } +/** + * linkmode_to_mii_eee_cap2_t() + * @adv: the linkmode advertisement settings + * + * A function that translates linkmode to value for IEEE 802.3-2022 45.2.7.16 + * "EEE advertisement 2" register (7.62) + */ +static inline u32 linkmode_to_mii_eee_cap2_t(unsigned long *adv) +{ + u32 result = 0; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, adv)) + result |= MDIO_EEE_2_5GT; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, adv)) + result |= MDIO_EEE_5GT; + + return result; +} + /** * mii_10base_t1_adv_mod_linkmode_t() * @adv: linkmode advertisement settings From ef6ee3a31bdc699391f2db4eff407fdb06895809 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 14 Feb 2024 21:17:11 +0100 Subject: [PATCH 1290/2255] net: phy: add PHY_EEE_CAP2_FEATURES As a prerequisite for adding EEE CAP2 register support, complement PHY_EEE_CAP1_FEATURES with PHY_EEE_CAP2_FEATURES. For now only 2500baseT and 5000baseT modes are supported. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 11 +++++++++++ include/linux/phy.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index d63dca535746..2eefee970851 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -148,6 +148,14 @@ static const int phy_eee_cap1_features_array[] = { __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_eee_cap1_features) __ro_after_init; EXPORT_SYMBOL_GPL(phy_eee_cap1_features); +static const int phy_eee_cap2_features_array[] = { + ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + ETHTOOL_LINK_MODE_5000baseT_Full_BIT, +}; + +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_eee_cap2_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_eee_cap2_features); + static void features_init(void) { /* 10/100 half/full*/ @@ -232,6 +240,9 @@ static void features_init(void) linkmode_set_bit_array(phy_eee_cap1_features_array, ARRAY_SIZE(phy_eee_cap1_features_array), phy_eee_cap1_features); + linkmode_set_bit_array(phy_eee_cap2_features_array, + ARRAY_SIZE(phy_eee_cap2_features_array), + phy_eee_cap2_features); } diff --git a/include/linux/phy.h b/include/linux/phy.h index c2dda21b39e1..e3ab2c347a59 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -54,6 +54,7 @@ extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_fec_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_eee_cap1_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_eee_cap2_features) __ro_after_init; #define PHY_BASIC_FEATURES ((unsigned long *)&phy_basic_features) #define PHY_BASIC_T1_FEATURES ((unsigned long *)&phy_basic_t1_features) @@ -65,6 +66,7 @@ extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_eee_cap1_features) __ro_after_init; #define PHY_10GBIT_FEC_FEATURES ((unsigned long *)&phy_10gbit_fec_features) #define PHY_10GBIT_FULL_FEATURES ((unsigned long *)&phy_10gbit_full_features) #define PHY_EEE_CAP1_FEATURES ((unsigned long *)&phy_eee_cap1_features) +#define PHY_EEE_CAP2_FEATURES ((unsigned long *)&phy_eee_cap2_features) extern const int phy_basic_ports_array[3]; extern const int phy_fibre_port_array[1]; From b63584c86edbaf7477c3569cec331672bb7714d5 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 14 Feb 2024 21:18:02 +0100 Subject: [PATCH 1291/2255] net: phy: c45: add and use genphy_c45_read_eee_cap2 Add and use genphy_c45_read_eee_cap2(), complementing genphy_c45_read_eee_cap1(). Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy-c45.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 46c87a903efd..5a245f0cc8b1 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -830,6 +830,30 @@ static int genphy_c45_read_eee_cap1(struct phy_device *phydev) return 0; } +/** + * genphy_c45_read_eee_cap2 - read supported EEE link modes from register 3.21 + * @phydev: target phy_device struct + */ +static int genphy_c45_read_eee_cap2(struct phy_device *phydev) +{ + int val; + + /* IEEE 802.3-2022 45.2.3.11 EEE control and capability 2 + * (Register 3.21) + */ + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE2); + if (val < 0) + return val; + + /* IEEE 802.3-2022 45.2.3.11 says 9 bits are reserved. */ + if (val == 0xffff) + return 0; + + mii_eee_cap2_mod_linkmode_sup_t(phydev->supported_eee, val); + + return 0; +} + /** * genphy_c45_read_eee_abilities - read supported EEE link modes * @phydev: target phy_device struct @@ -848,6 +872,13 @@ int genphy_c45_read_eee_abilities(struct phy_device *phydev) return val; } + /* Same for cap2 (3.21) */ + if (linkmode_intersects(phydev->supported, PHY_EEE_CAP2_FEATURES)) { + val = genphy_c45_read_eee_cap2(phydev); + if (val) + return val; + } + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, phydev->supported)) { /* IEEE 802.3cg-2019 45.2.1.186b 10BASE-T1L PMA status register From 1bbe04e305fb2b5127650e6f2c0dbd611e8ebb14 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 14 Feb 2024 21:18:50 +0100 Subject: [PATCH 1292/2255] net: phy: c45: add support for EEE link partner ability 2 to genphy_c45_read_eee_lpa Add support for reading EEE link partner ability 2 register. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy-c45.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 5a245f0cc8b1..b09c6baf0c08 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -781,6 +781,17 @@ static int genphy_c45_read_eee_lpa(struct phy_device *phydev, mii_eee_cap1_mod_linkmode_t(lpa, val); } + if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) { + /* IEEE 802.3-2022 45.2.7.17 EEE link partner ability 2 + * (Register 7.63) + */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE2); + if (val < 0) + return val; + + mii_eee_cap2_mod_linkmode_adv_t(lpa, val); + } + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, phydev->supported_eee)) { /* IEEE 802.3cg-2019 45.2.7.26 10BASE-T1 AN status register From 9a1e31299decfb4fc134933dbb6c34236187173f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 14 Feb 2024 21:19:47 +0100 Subject: [PATCH 1293/2255] net: phy: c45: add support for MDIO_AN_EEE_ADV2 Add support for handling the EEE advertisement 2 register. For now only 2500baseT and 5000baseT modes are supported. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy-c45.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index b09c6baf0c08..c69568e7695e 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -706,6 +706,22 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv) changed = 1; } + if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) { + val = linkmode_to_mii_eee_cap2_t(adv); + + /* IEEE 802.3-2022 45.2.7.16 EEE advertisement 2 + * (Register 7.62) + */ + val = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, + MDIO_AN_EEE_ADV2, + MDIO_EEE_2_5GT | MDIO_EEE_5GT, + val); + if (val < 0) + return val; + if (val > 0) + changed = 1; + } + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, phydev->supported_eee)) { val = linkmode_adv_to_mii_10base_t1_t(adv); @@ -745,6 +761,17 @@ int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv) mii_eee_cap1_mod_linkmode_t(adv, val); } + if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) { + /* IEEE 802.3-2022 45.2.7.16 EEE advertisement 2 + * (Register 7.62) + */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2); + if (val < 0) + return val; + + mii_eee_cap2_mod_linkmode_adv_t(adv, val); + } + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, phydev->supported_eee)) { /* IEEE 802.3cg-2019 45.2.7.25 10BASE-T1 AN control register From ea7f3cfaa58873bbe271577efa800647e30f18bd Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 15 Feb 2024 09:05:07 -0800 Subject: [PATCH 1294/2255] net: bql: allow the config to be disabled It is impossible to disable BQL individually today, since there is no prompt for the Kconfig entry, so, the BQL is always enabled if SYSFS is enabled. Create a prompt entry for BQL, so, it could be enabled or disabled at build time independently of SYSFS. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- net/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/net/Kconfig b/net/Kconfig index 4adc47d0c9c2..3e57ccf0da27 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -331,6 +331,7 @@ config NET_RX_BUSY_POLL config BQL bool + prompt "Enable Byte Queue Limits" depends on SYSFS select DQL default y From 6d47302a3f0ba31445478d518d98bd55918bc8ab Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 15 Feb 2024 22:43:30 +0100 Subject: [PATCH 1295/2255] net: phy: aquantia: add AQR813 PHY ID Aquantia AQR813 is the Octal Port variant of the AQR113. Add PHY ID for it to provide support for it. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/aquantia/aquantia_main.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index a6a7980585f5..71bfddb8f453 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -28,6 +28,7 @@ #define PHY_ID_AQR412 0x03a1b712 #define PHY_ID_AQR113 0x31c31c40 #define PHY_ID_AQR113C 0x31c31c12 +#define PHY_ID_AQR813 0x31c31cb2 #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) @@ -961,6 +962,25 @@ static struct phy_driver aqr_driver[] = { .get_stats = aqr107_get_stats, .link_change_notify = aqr107_link_change_notify, }, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR813), + .name = "Aquantia AQR813", + .probe = aqr107_probe, + .get_rate_matching = aqr107_get_rate_matching, + .config_init = aqr107_config_init, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, }; module_phy_driver(aqr_driver); @@ -979,6 +999,7 @@ static struct mdio_device_id __maybe_unused aqr_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, { } }; From 78e886ba2b549945ecada055ee0765f0ded5707a Mon Sep 17 00:00:00 2001 From: Kamal Heib Date: Thu, 15 Feb 2024 17:31:04 -0500 Subject: [PATCH 1296/2255] net: ena: Remove ena_select_queue Avoid the following warnings by removing the ena_select_queue() function and rely on the net core to do the queue selection, The issue happen when an skb received from an interface with more queues than ena is forwarded to the ena interface. [ 1176.159959] eth0 selects TX queue 11, but real number of TX queues is 8 [ 1176.863976] eth0 selects TX queue 14, but real number of TX queues is 8 [ 1180.767877] eth0 selects TX queue 14, but real number of TX queues is 8 [ 1188.703742] eth0 selects TX queue 14, but real number of TX queues is 8 Fixes: 1738cd3ed342 ("net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Kamal Heib Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 2d28e97b2cf3..09e7da1a69c9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2689,22 +2689,6 @@ error_drop_packet: return NETDEV_TX_OK; } -static u16 ena_select_queue(struct net_device *dev, struct sk_buff *skb, - struct net_device *sb_dev) -{ - u16 qid; - /* we suspect that this is good for in--kernel network services that - * want to loop incoming skb rx to tx in normal user generated traffic, - * most probably we will not get to this - */ - if (skb_rx_queue_recorded(skb)) - qid = skb_get_rx_queue(skb); - else - qid = netdev_pick_tx(dev, skb, NULL); - - return qid; -} - static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pdev) { struct device *dev = &pdev->dev; @@ -2881,7 +2865,6 @@ static const struct net_device_ops ena_netdev_ops = { .ndo_open = ena_open, .ndo_stop = ena_close, .ndo_start_xmit = ena_start_xmit, - .ndo_select_queue = ena_select_queue, .ndo_get_stats64 = ena_get_stats64, .ndo_tx_timeout = ena_tx_timeout, .ndo_change_mtu = ena_change_mtu, From d0bcc15cbae806cad7d1d90003c82ecb5833b533 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 15 Feb 2024 13:27:26 +0100 Subject: [PATCH 1297/2255] tools: ynl: don't access uninitialized attr_space variable If message contains unknown attribute and user passes "--process-unknown" command line option, _decode() gets called with space arg set to None. In that case, attr_space variable is not initialized used which leads to following trace: Traceback (most recent call last): File "./tools/net/ynl/cli.py", line 77, in main() File "./tools/net/ynl/cli.py", line 68, in main reply = ynl.dump(args.dump, attrs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "tools/net/ynl/lib/ynl.py", line 909, in dump return self._op(method, vals, [], dump=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "tools/net/ynl/lib/ynl.py", line 894, in _op rsp_msg = self._decode(decoded.raw_attrs, op.attr_set.name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "tools/net/ynl/lib/ynl.py", line 639, in _decode self._rsp_add(rsp, attr_name, None, self._decode_unknown(attr)) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "tools/net/ynl/lib/ynl.py", line 569, in _decode_unknown return self._decode(NlAttrs(attr.raw), None) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "tools/net/ynl/lib/ynl.py", line 630, in _decode search_attrs = SpaceAttrs(attr_space, rsp, outer_attrs) ^^^^^^^^^^ UnboundLocalError: cannot access local variable 'attr_space' where it is not associated with a value Fix this by moving search_attrs assignment under the if statement above it to make sure attr_space is initialized. Fixes: bf8b832374fb ("tools/net/ynl: Support sub-messages in nested attribute spaces") Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- tools/net/ynl/lib/ynl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 03c7ca6aaae9..f45ee5f29bed 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -588,10 +588,10 @@ class YnlFamily(SpecFamily): return decoded def _decode(self, attrs, space, outer_attrs = None): + rsp = dict() if space: attr_space = self.attr_sets[space] - rsp = dict() - search_attrs = SpaceAttrs(attr_space, rsp, outer_attrs) + search_attrs = SpaceAttrs(attr_space, rsp, outer_attrs) for attr in attrs: try: From d740f4be7cf0faded598fe43e2f472c47230c298 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 16 Feb 2024 14:29:50 -0800 Subject: [PATCH 1298/2255] pds_core: add simple AER handler Set up the pci_error_handlers error_detected and resume to be useful in handling AER events. Reviewed-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/pds_core/main.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c index 0050c5894563..e10451a5a89b 100644 --- a/drivers/net/ethernet/amd/pds_core/main.c +++ b/drivers/net/ethernet/amd/pds_core/main.c @@ -45,6 +45,7 @@ static void pdsc_unmap_bars(struct pdsc *pdsc) for (i = 0; i < PDS_CORE_BARS_MAX; i++) { if (bars[i].vaddr) pci_iounmap(pdsc->pdev, bars[i].vaddr); + bars[i].vaddr = NULL; } } @@ -512,10 +513,33 @@ void pdsc_reset_done(struct pci_dev *pdev) pdsc_restart_health_thread(pdsc); } +static pci_ers_result_t pdsc_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t error) +{ + if (error == pci_channel_io_frozen) { + pdsc_reset_prepare(pdev); + return PCI_ERS_RESULT_NEED_RESET; + } + + return PCI_ERS_RESULT_NONE; +} + +static void pdsc_pci_error_resume(struct pci_dev *pdev) +{ + struct pdsc *pdsc = pci_get_drvdata(pdev); + + if (test_bit(PDSC_S_FW_DEAD, &pdsc->state)) + pci_reset_function_locked(pdev); +} + static const struct pci_error_handlers pdsc_err_handler = { /* FLR handling */ .reset_prepare = pdsc_reset_prepare, .reset_done = pdsc_reset_done, + + /* AER handling */ + .error_detected = pdsc_pci_error_detected, + .resume = pdsc_pci_error_resume, }; static struct pci_driver pdsc_driver = { From 2dac60e062340c1e5c975ad6465192d11c40d47a Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 16 Feb 2024 14:29:51 -0800 Subject: [PATCH 1299/2255] pds_core: delete VF dev on reset When the VF is hit with a reset, remove the aux device in the prepare for reset and try to restore it after the reset. The userland mechanics will need to recover and rebuild whatever uses the device afterwards. Reviewed-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/pds_core/auxbus.c | 18 +++++++++++++++++- drivers/net/ethernet/amd/pds_core/main.c | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c index 11c23a7f3172..a3c79848a69a 100644 --- a/drivers/net/ethernet/amd/pds_core/auxbus.c +++ b/drivers/net/ethernet/amd/pds_core/auxbus.c @@ -184,6 +184,9 @@ int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf) struct pds_auxiliary_dev *padev; int err = 0; + if (!cf) + return -ENODEV; + mutex_lock(&pf->config_lock); padev = pf->vfs[cf->vf_id].padev; @@ -202,14 +205,27 @@ int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf) int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf) { struct pds_auxiliary_dev *padev; - enum pds_core_vif_types vt; char devname[PDS_DEVNAME_LEN]; + enum pds_core_vif_types vt; + unsigned long mask; u16 vt_support; int client_id; int err = 0; + if (!cf) + return -ENODEV; + mutex_lock(&pf->config_lock); + mask = BIT_ULL(PDSC_S_FW_DEAD) | + BIT_ULL(PDSC_S_STOPPING_DRIVER); + if (cf->state & mask) { + dev_err(pf->dev, "%s: can't add dev, VF client in bad state %#lx\n", + __func__, cf->state); + err = -ENXIO; + goto out_unlock; + } + /* We only support vDPA so far, so it is the only one to * be verified that it is available in the Core device and * enabled in the devlink param. In the future this might diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c index e10451a5a89b..82901a847306 100644 --- a/drivers/net/ethernet/amd/pds_core/main.c +++ b/drivers/net/ethernet/amd/pds_core/main.c @@ -476,6 +476,14 @@ void pdsc_reset_prepare(struct pci_dev *pdev) pdsc_stop_health_thread(pdsc); pdsc_fw_down(pdsc); + if (pdev->is_virtfn) { + struct pdsc *pf; + + pf = pdsc_get_pf_struct(pdsc->pdev); + if (!IS_ERR(pf)) + pdsc_auxbus_dev_del(pdsc, pf); + } + pdsc_unmap_bars(pdsc); pci_release_regions(pdev); pci_disable_device(pdev); @@ -511,6 +519,14 @@ void pdsc_reset_done(struct pci_dev *pdev) pdsc_fw_up(pdsc); pdsc_restart_health_thread(pdsc); + + if (pdev->is_virtfn) { + struct pdsc *pf; + + pf = pdsc_get_pf_struct(pdsc->pdev); + if (!IS_ERR(pf)) + pdsc_auxbus_dev_add(pdsc, pf); + } } static pci_ers_result_t pdsc_pci_error_detected(struct pci_dev *pdev, From 2cbab3c296f1addd73b40549a2271b30f960df8b Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 16 Feb 2024 14:29:52 -0800 Subject: [PATCH 1300/2255] pds_core: use pci_reset_function for health reset We get the benefit of all the PCI reset locking and recovery if we use the existing pci_reset_function() that will call our local reset handlers. Reviewed-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/pds_core/core.c | 3 +-- drivers/net/ethernet/amd/pds_core/core.h | 3 --- drivers/net/ethernet/amd/pds_core/main.c | 7 ++++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c index 1234a4a8a4ae..9662ee72814c 100644 --- a/drivers/net/ethernet/amd/pds_core/core.c +++ b/drivers/net/ethernet/amd/pds_core/core.c @@ -607,8 +607,7 @@ static void pdsc_check_pci_health(struct pdsc *pdsc) if (fw_status != PDS_RC_BAD_PCI) return; - pdsc_reset_prepare(pdsc->pdev); - pdsc_reset_done(pdsc->pdev); + pci_reset_function(pdsc->pdev); } void pdsc_health_thread(struct work_struct *work) diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h index 3468a63f5ae9..92d7657dd614 100644 --- a/drivers/net/ethernet/amd/pds_core/core.h +++ b/drivers/net/ethernet/amd/pds_core/core.h @@ -284,9 +284,6 @@ int pdsc_devcmd_reset(struct pdsc *pdsc); int pdsc_dev_init(struct pdsc *pdsc); void pdsc_dev_uninit(struct pdsc *pdsc); -void pdsc_reset_prepare(struct pci_dev *pdev); -void pdsc_reset_done(struct pci_dev *pdev); - int pdsc_intr_alloc(struct pdsc *pdsc, char *name, irq_handler_t handler, void *data); void pdsc_intr_free(struct pdsc *pdsc, int index); diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c index 82901a847306..ab6133e7db42 100644 --- a/drivers/net/ethernet/amd/pds_core/main.c +++ b/drivers/net/ethernet/amd/pds_core/main.c @@ -469,7 +469,7 @@ static void pdsc_restart_health_thread(struct pdsc *pdsc) mod_timer(&pdsc->wdtimer, jiffies + 1); } -void pdsc_reset_prepare(struct pci_dev *pdev) +static void pdsc_reset_prepare(struct pci_dev *pdev) { struct pdsc *pdsc = pci_get_drvdata(pdev); @@ -486,10 +486,11 @@ void pdsc_reset_prepare(struct pci_dev *pdev) pdsc_unmap_bars(pdsc); pci_release_regions(pdev); - pci_disable_device(pdev); + if (pci_is_enabled(pdev)) + pci_disable_device(pdev); } -void pdsc_reset_done(struct pci_dev *pdev) +static void pdsc_reset_done(struct pci_dev *pdev) { struct pdsc *pdsc = pci_get_drvdata(pdev); struct device *dev = pdsc->dev; From 1e63e5a813fa6203d7430af51d6bffb728525015 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Feb 2024 15:27:44 -0800 Subject: [PATCH 1301/2255] net: sched: Annotate struct tc_pedit with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct tc_pedit. Additionally, since the element count member must be set before accessing the annotated flexible array member, move its initialization earlier. Link: https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci [1] Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/uapi/linux/tc_act/tc_pedit.h | 2 +- net/sched/act_pedit.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/tc_act/tc_pedit.h b/include/uapi/linux/tc_act/tc_pedit.h index f3e61b04fa01..f5cab7fc96ab 100644 --- a/include/uapi/linux/tc_act/tc_pedit.h +++ b/include/uapi/linux/tc_act/tc_pedit.h @@ -62,7 +62,7 @@ struct tc_pedit_sel { tc_gen; unsigned char nkeys; unsigned char flags; - struct tc_pedit_key keys[0]; + struct tc_pedit_key keys[] __counted_by(nkeys); }; #define tc_pedit tc_pedit_sel diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index df5a02d5f919..fc0a35a7b62a 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -515,11 +515,11 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, spin_unlock_bh(&p->tcf_lock); return -ENOBUFS; } + opt->nkeys = parms->tcfp_nkeys; memcpy(opt->keys, parms->tcfp_keys, flex_array_size(opt, keys, parms->tcfp_nkeys)); opt->index = p->tcf_index; - opt->nkeys = parms->tcfp_nkeys; opt->flags = parms->tcfp_flags; opt->action = p->tcf_action; opt->refcnt = refcount_read(&p->tcf_refcnt) - ref; From ca1e1163889395cae54c4f051c301a8a6d6de311 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:38 +0800 Subject: [PATCH 1302/2255] 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(-) 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); } From f59cb1a030989ca0e5638fd4de91afddfbdbf89f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:39 +0800 Subject: [PATCH 1303/2255] 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(+) 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, From 2c681cbf6c3a76ef3cdd9b33c3b1644caab209d1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:40 +0800 Subject: [PATCH 1304/2255] 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 + .../net/wireless/realtek/rtw89/rtw8922a_rfk.c | 120 ++++++++++++++++++ .../net/wireless/realtek/rtw89/rtw8922a_rfk.h | 3 + 6 files changed, 208 insertions(+) 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 From 03830bb909a064bd590748127367878cf1d50fb0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:41 +0800 Subject: [PATCH 1305/2255] 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 +++++++++++++++++++ .../net/wireless/realtek/rtw89/rtw8922a_rfk.c | 23 +++++++++ .../net/wireless/realtek/rtw89/rtw8922a_rfk.h | 2 + 3 files changed, 76 insertions(+) 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 From 5d2dbccc2b3cec2db5af6b7305ca144b35200024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Thu, 15 Feb 2024 16:36:18 +0100 Subject: [PATCH 1306/2255] 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 --- .../net/wireless/microchip/wilc1000/netdev.c | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) 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; From 059d0e3876abacd3967d22b6c59ff1e52d1c10ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Thu, 15 Feb 2024 16:36:19 +0100 Subject: [PATCH 1307/2255] 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(-) 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); From 51e4aa8c449b4c3821170f5438d084bafb003bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Thu, 15 Feb 2024 16:36:20 +0100 Subject: [PATCH 1308/2255] 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(-) 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; From dd66185c23f71af36397bebfc99ede608dca07b6 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 15 Feb 2024 16:36:21 +0100 Subject: [PATCH 1309/2255] 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 +++++++++++-------- .../net/wireless/microchip/wilc1000/netdev.c | 8 ++- 2 files changed, 35 insertions(+), 25 deletions(-) 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) From 5983e5df86303564f0968e6e4108ca08e00828ee Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 1 Feb 2024 15:22:42 -0500 Subject: [PATCH 1310/2255] dt-bindings: net: fec: add iommus property iMX8QM have iommu. Add proerty 'iommus'. Signed-off-by: Frank Li Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240201-8qm_smmu-v2-2-3d12a80201a3@nxp.com Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/fsl,fec.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/fsl,fec.yaml b/Documentation/devicetree/bindings/net/fsl,fec.yaml index 8948a11c994e..5536c06139ca 100644 --- a/Documentation/devicetree/bindings/net/fsl,fec.yaml +++ b/Documentation/devicetree/bindings/net/fsl,fec.yaml @@ -224,6 +224,9 @@ properties: Can be omitted thus no delay is observed. Delay is in range of 1ms to 1000ms. Other delays are invalid. + iommus: + maxItems: 1 + required: - compatible - reg From 56ef27e3abe6d6453b1f4f6127041f3a65d7cbc9 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Thu, 15 Feb 2024 12:39:05 +0100 Subject: [PATCH 1311/2255] page_pool: disable direct recycling based on pool->cpuid on destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that direct recycling is performed basing on pool->cpuid when set, memory leaks are possible: 1. A pool is destroyed. 2. Alloc cache is emptied (it's done only once). 3. pool->cpuid is still set. 4. napi_pp_put_page() does direct recycling basing on pool->cpuid. 5. Now alloc cache is not empty, but it won't ever be freed. In order to avoid that, rewrite pool->cpuid to -1 when unlinking NAPI to make sure no direct recycling will be possible after emptying the cache. This involves a bit of overhead as pool->cpuid now must be accessed via READ_ONCE() to avoid partial reads. Rename page_pool_unlink_napi() -> page_pool_disable_direct_recycling() to reflect what it actually does and unexport it. Signed-off-by: Alexander Lobakin Reviewed-by: Toke Høiland-Jørgensen Link: https://lore.kernel.org/r/20240215113905.96817-1-aleksander.lobakin@intel.com Signed-off-by: Jakub Kicinski --- include/net/page_pool/types.h | 5 ----- net/core/page_pool.c | 10 +++++++--- net/core/skbuff.c | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index 3828396ae60c..3590fbe6e3f1 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -210,17 +210,12 @@ struct page_pool *page_pool_create_percpu(const struct page_pool_params *params, struct xdp_mem_info; #ifdef CONFIG_PAGE_POOL -void page_pool_unlink_napi(struct page_pool *pool); void page_pool_destroy(struct page_pool *pool); void page_pool_use_xdp_mem(struct page_pool *pool, void (*disconnect)(void *), struct xdp_mem_info *mem); void page_pool_put_page_bulk(struct page_pool *pool, void **data, int count); #else -static inline void page_pool_unlink_napi(struct page_pool *pool) -{ -} - static inline void page_pool_destroy(struct page_pool *pool) { } diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 89c835fcf094..e8b9399d8e32 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -949,8 +949,13 @@ void page_pool_use_xdp_mem(struct page_pool *pool, void (*disconnect)(void *), pool->xdp_mem_id = mem->id; } -void page_pool_unlink_napi(struct page_pool *pool) +static void page_pool_disable_direct_recycling(struct page_pool *pool) { + /* Disable direct recycling based on pool->cpuid. + * Paired with READ_ONCE() in napi_pp_put_page(). + */ + WRITE_ONCE(pool->cpuid, -1); + if (!pool->p.napi) return; @@ -962,7 +967,6 @@ void page_pool_unlink_napi(struct page_pool *pool) WRITE_ONCE(pool->p.napi, NULL); } -EXPORT_SYMBOL(page_pool_unlink_napi); void page_pool_destroy(struct page_pool *pool) { @@ -972,7 +976,7 @@ void page_pool_destroy(struct page_pool *pool) if (!page_pool_put(pool)) return; - page_pool_unlink_napi(pool); + page_pool_disable_direct_recycling(pool); page_pool_free_frag(pool); if (!page_pool_release(pool)) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0d9a489e6ae1..b41856585c24 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1018,7 +1018,7 @@ bool napi_pp_put_page(struct page *page, bool napi_safe) unsigned int cpuid = smp_processor_id(); allow_direct = napi && READ_ONCE(napi->list_owner) == cpuid; - allow_direct |= (pp->cpuid == cpuid); + allow_direct |= READ_ONCE(pp->cpuid) == cpuid; } /* Driver set this to memory recycling info. Reset it on recycle. From f853fa5c54e7a0364a52125074dedeaf2c7ddace Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 16 Feb 2024 10:25:43 +0100 Subject: [PATCH 1312/2255] net: page_pool: fix recycle stats for system page_pool allocator Use global percpu page_pool_recycle_stats counter for system page_pool allocator instead of allocating a separate percpu variable for each (also percpu) page pool instance. Reviewed-by: Toke Hoiland-Jorgensen Signed-off-by: Lorenzo Bianconi Reviewed-by: Alexander Lobakin Link: https://lore.kernel.org/r/87f572425e98faea3da45f76c3c68815c01a20ee.1708075412.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- include/net/page_pool/types.h | 5 +++-- net/core/dev.c | 1 + net/core/page_pool.c | 22 +++++++++++++++++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h index 3590fbe6e3f1..5e43a08d3231 100644 --- a/include/net/page_pool/types.h +++ b/include/net/page_pool/types.h @@ -18,8 +18,9 @@ * Please note DMA-sync-for-CPU is still * device driver responsibility */ -#define PP_FLAG_ALL (PP_FLAG_DMA_MAP |\ - PP_FLAG_DMA_SYNC_DEV) +#define PP_FLAG_SYSTEM_POOL BIT(2) /* Global system page_pool */ +#define PP_FLAG_ALL (PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV | \ + PP_FLAG_SYSTEM_POOL) /* * Fast allocation side cache array/stack diff --git a/net/core/dev.c b/net/core/dev.c index cc9c2eda65ac..c588808be77f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -11738,6 +11738,7 @@ static int net_page_pool_create(int cpuid) #if IS_ENABLED(CONFIG_PAGE_POOL) struct page_pool_params page_pool_params = { .pool_size = SYSTEM_PERCPU_PAGE_POOL_SIZE, + .flags = PP_FLAG_SYSTEM_POOL, .nid = NUMA_NO_NODE, }; struct page_pool *pp_ptr; diff --git a/net/core/page_pool.c b/net/core/page_pool.c index e8b9399d8e32..d706fe5548df 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -31,6 +31,8 @@ #define BIAS_MAX (LONG_MAX >> 1) #ifdef CONFIG_PAGE_POOL_STATS +static DEFINE_PER_CPU(struct page_pool_recycle_stats, pp_system_recycle_stats); + /* alloc_stat_inc is intended to be used in softirq context */ #define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++) /* recycle_stat_inc is safe to use when preemption is possible. */ @@ -220,14 +222,23 @@ static int page_pool_init(struct page_pool *pool, pool->has_init_callback = !!pool->slow.init_callback; #ifdef CONFIG_PAGE_POOL_STATS - pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats); - if (!pool->recycle_stats) - return -ENOMEM; + if (!(pool->p.flags & PP_FLAG_SYSTEM_POOL)) { + pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats); + if (!pool->recycle_stats) + return -ENOMEM; + } else { + /* For system page pool instance we use a singular stats object + * instead of allocating a separate percpu variable for each + * (also percpu) page pool instance. + */ + pool->recycle_stats = &pp_system_recycle_stats; + } #endif if (ptr_ring_init(&pool->ring, ring_qsize, GFP_KERNEL) < 0) { #ifdef CONFIG_PAGE_POOL_STATS - free_percpu(pool->recycle_stats); + if (!(pool->p.flags & PP_FLAG_SYSTEM_POOL)) + free_percpu(pool->recycle_stats); #endif return -ENOMEM; } @@ -251,7 +262,8 @@ static void page_pool_uninit(struct page_pool *pool) put_device(pool->p.dev); #ifdef CONFIG_PAGE_POOL_STATS - free_percpu(pool->recycle_stats); + if (!(pool->p.flags & PP_FLAG_SYSTEM_POOL)) + free_percpu(pool->recycle_stats); #endif } From 74293ea1c4db62cb969e741fbfd479a34d935024 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 16 Feb 2024 01:41:52 -0800 Subject: [PATCH 1313/2255] net: sysfs: Do not create sysfs for non BQL device Creation of sysfs entries is expensive, mainly for workloads that constantly creates netdev and netns often. Do not create BQL sysfs entries for devices that don't need, basically those that do not have a real queue, i.e, devices that has NETIF_F_LLTX and IFF_NO_QUEUE, such as `lo` interface. This will remove the /sys/class/net/eth0/queues/tx-X/byte_queue_limits/ directory for these devices. In the example below, eth0 has the `byte_queue_limits` directory but not `lo`. # ls /sys/class/net/lo/queues/tx-0/ traffic_class tx_maxrate tx_timeout xps_cpus xps_rxqs # ls /sys/class/net/eth0/queues/tx-0/byte_queue_limits/ hold_time inflight limit limit_max limit_min This also removes the #ifdefs, since we can also use netdev_uses_bql() to check if the config is enabled. (as suggested by Jakub). Suggested-by: Eric Dumazet Signed-off-by: Breno Leitao Link: https://lore.kernel.org/r/20240216094154.3263843-1-leitao@debian.org Signed-off-by: Jakub Kicinski --- net/core/net-sysfs.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 946caefdd959..af238026ac3c 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1459,6 +1459,9 @@ static const struct attribute_group dql_group = { .name = "byte_queue_limits", .attrs = dql_attrs, }; +#else +/* Fake declaration, all the code using it should be dead */ +extern const struct attribute_group dql_group; #endif /* CONFIG_BQL */ #ifdef CONFIG_XPS @@ -1696,6 +1699,15 @@ static const struct kobj_type netdev_queue_ktype = { .get_ownership = netdev_queue_get_ownership, }; +static bool netdev_uses_bql(const struct net_device *dev) +{ + if (dev->features & NETIF_F_LLTX || + dev->priv_flags & IFF_NO_QUEUE) + return false; + + return IS_ENABLED(CONFIG_BQL); +} + static int netdev_queue_add_kobject(struct net_device *dev, int index) { struct netdev_queue *queue = dev->_tx + index; @@ -1713,11 +1725,11 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index) if (error) goto err; -#ifdef CONFIG_BQL - error = sysfs_create_group(kobj, &dql_group); - if (error) - goto err; -#endif + if (netdev_uses_bql(dev)) { + error = sysfs_create_group(kobj, &dql_group); + if (error) + goto err; + } kobject_uevent(kobj, KOBJ_ADD); return 0; @@ -1738,9 +1750,9 @@ static int tx_queue_change_owner(struct net_device *ndev, int index, if (error) return error; -#ifdef CONFIG_BQL - error = sysfs_group_change_owner(kobj, &dql_group, kuid, kgid); -#endif + if (netdev_uses_bql(ndev)) + error = sysfs_group_change_owner(kobj, &dql_group, kuid, kgid); + return error; } #endif /* CONFIG_SYSFS */ @@ -1772,9 +1784,10 @@ netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) if (!refcount_read(&dev_net(dev)->ns.count)) queue->kobj.uevent_suppress = 1; -#ifdef CONFIG_BQL - sysfs_remove_group(&queue->kobj, &dql_group); -#endif + + if (netdev_uses_bql(dev)) + sysfs_remove_group(&queue->kobj, &dql_group); + kobject_put(&queue->kobj); } From c8fba5d6df5e476aa791db4f1f014dad2bb5e904 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Mon, 19 Feb 2024 21:00:21 +0100 Subject: [PATCH 1314/2255] can: raw: fix getsockopt() for new CAN_RAW_XL_VCID_OPTS The code for the CAN_RAW_XL_VCID_OPTS getsockopt() was incompletely adopted from the CAN_RAW_FILTER getsockopt(). Add the missing put_user() and return statements. Flagged by Smatch. Fixes: c83c22ec1493 ("can: canxl: add virtual CAN network identifier support") Reported-by: Simon Horman Signed-off-by: Oliver Hartkopp Link: https://lore.kernel.org/all/20240219200021.12113-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde --- net/can/raw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/can/raw.c b/net/can/raw.c index cb8e6f788af8..897ffc17d850 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -835,7 +835,9 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, if (copy_to_user(optval, &ro->raw_vcid_opts, len)) err = -EFAULT; } - break; + if (!err) + err = put_user(len, optlen); + return err; case CAN_RAW_JOIN_FILTERS: if (len > sizeof(int)) From 18ddbf5cf0e7553fd05c3e1a02d740514ee3f0a6 Mon Sep 17 00:00:00 2001 From: Mina Almasry Date: Wed, 14 Feb 2024 14:34:02 -0800 Subject: [PATCH 1315/2255] net: introduce abstraction for network memory Add the netmem_ref type, an abstraction for network memory. To add support for new memory types to the net stack, we must first abstract the current memory type. Currently parts of the net stack use struct page directly: - page_pool - drivers - skb_frag_t Originally the plan was to reuse struct page* for the new memory types, and to set the LSB on the page* to indicate it's not really a page. However, for compiler type checking we need to introduce a new type. netmem_ref is introduced to abstract the underlying memory type. Currently it's a no-op abstraction that is always a struct page underneath. In parallel there is an undergoing effort to add support for devmem to the net stack: https://lore.kernel.org/netdev/20231208005250.2910004-1-almasrymina@google.com/ netmem_ref can be pointers to different underlying memory types, and the low bits are set to indicate the memory type. Helpers are provided to convert netmem pointers to the underlying memory type (currently only struct page). In the devmem series helpers are provided so that calling code can use netmem without worrying about the underlying memory type unless absolutely necessary. Reviewed-by: Shakeel Butt Signed-off-by: Mina Almasry Signed-off-by: Paolo Abeni --- include/net/netmem.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 include/net/netmem.h diff --git a/include/net/netmem.h b/include/net/netmem.h new file mode 100644 index 000000000000..d8b810245c1d --- /dev/null +++ b/include/net/netmem.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Network memory + * + * Author: Mina Almasry + */ + +#ifndef _NET_NETMEM_H +#define _NET_NETMEM_H + +/** + * typedef netmem_ref - a nonexistent type marking a reference to generic + * network memory. + * + * A netmem_ref currently is always a reference to a struct page. This + * abstraction is introduced so support for new memory types can be added. + * + * Use the supplied helpers to obtain the underlying memory pointer and fields. + */ +typedef unsigned long __bitwise netmem_ref; + +/* This conversion fails (returns NULL) if the netmem_ref is not struct page + * backed. + * + * Currently struct page is the only possible netmem, and this helper never + * fails. + */ +static inline struct page *netmem_to_page(netmem_ref netmem) +{ + return (__force struct page *)netmem; +} + +/* Converting from page to netmem is always safe, because a page can always be + * a netmem. + */ +static inline netmem_ref page_to_netmem(struct page *page) +{ + return (__force netmem_ref)page; +} + +#endif /* _NET_NETMEM_H */ From 21d2e6737c9789aa9b23c8a4131cbca8260139fd Mon Sep 17 00:00:00 2001 From: Mina Almasry Date: Wed, 14 Feb 2024 14:34:03 -0800 Subject: [PATCH 1316/2255] net: add netmem to skb_frag_t Use struct netmem* instead of page in skb_frag_t. Currently struct netmem* is always a struct page underneath, but the abstraction allows efforts to add support for skb frags not backed by pages. There is unfortunately 1 instance where the skb_frag_t is assumed to be a exactly a bio_vec in kcm. For this case, WARN_ON_ONCE and return error before doing a cast. Add skb[_frag]_fill_netmem_*() and skb_add_rx_frag_netmem() helpers so that the API can be used to create netmem skbs. Signed-off-by: Mina Almasry Acked-by: Paolo Abeni Signed-off-by: Paolo Abeni --- include/linux/skbuff.h | 100 +++++++++++++++++++++++++++++------------ net/core/skbuff.c | 34 +++++++++++--- net/kcm/kcmsock.c | 7 +-- 3 files changed, 102 insertions(+), 39 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 696e7680656f..e3a2ed5d09ad 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -37,6 +37,7 @@ #endif #include #include +#include /** * DOC: skb checksums @@ -359,7 +360,11 @@ extern int sysctl_max_skb_frags; */ #define GSO_BY_FRAGS 0xFFFF -typedef struct bio_vec skb_frag_t; +typedef struct skb_frag { + netmem_ref netmem; + unsigned int len; + unsigned int offset; +} skb_frag_t; /** * skb_frag_size() - Returns the size of a skb fragment @@ -367,7 +372,7 @@ typedef struct bio_vec skb_frag_t; */ static inline unsigned int skb_frag_size(const skb_frag_t *frag) { - return frag->bv_len; + return frag->len; } /** @@ -377,7 +382,7 @@ static inline unsigned int skb_frag_size(const skb_frag_t *frag) */ static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size) { - frag->bv_len = size; + frag->len = size; } /** @@ -387,7 +392,7 @@ static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size) */ static inline void skb_frag_size_add(skb_frag_t *frag, int delta) { - frag->bv_len += delta; + frag->len += delta; } /** @@ -397,7 +402,7 @@ static inline void skb_frag_size_add(skb_frag_t *frag, int delta) */ static inline void skb_frag_size_sub(skb_frag_t *frag, int delta) { - frag->bv_len -= delta; + frag->len -= delta; } /** @@ -417,7 +422,7 @@ static inline bool skb_frag_must_loop(struct page *p) * skb_frag_foreach_page - loop over pages in a fragment * * @f: skb frag to operate on - * @f_off: offset from start of f->bv_page + * @f_off: offset from start of f->netmem * @f_len: length from f_off to loop over * @p: (temp var) current page * @p_off: (temp var) offset from start of current page, @@ -2429,22 +2434,37 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb) return skb_headlen(skb) + __skb_pagelen(skb); } +static inline void skb_frag_fill_netmem_desc(skb_frag_t *frag, + netmem_ref netmem, int off, + int size) +{ + frag->netmem = netmem; + frag->offset = off; + skb_frag_size_set(frag, size); +} + static inline void skb_frag_fill_page_desc(skb_frag_t *frag, struct page *page, int off, int size) { - frag->bv_page = page; - frag->bv_offset = off; - skb_frag_size_set(frag, size); + skb_frag_fill_netmem_desc(frag, page_to_netmem(page), off, size); +} + +static inline void __skb_fill_netmem_desc_noacc(struct skb_shared_info *shinfo, + int i, netmem_ref netmem, + int off, int size) +{ + skb_frag_t *frag = &shinfo->frags[i]; + + skb_frag_fill_netmem_desc(frag, netmem, off, size); } static inline void __skb_fill_page_desc_noacc(struct skb_shared_info *shinfo, int i, struct page *page, int off, int size) { - skb_frag_t *frag = &shinfo->frags[i]; - - skb_frag_fill_page_desc(frag, page, off, size); + __skb_fill_netmem_desc_noacc(shinfo, i, page_to_netmem(page), off, + size); } /** @@ -2460,10 +2480,10 @@ static inline void skb_len_add(struct sk_buff *skb, int delta) } /** - * __skb_fill_page_desc - initialise a paged fragment in an skb + * __skb_fill_netmem_desc - initialise a fragment in an skb * @skb: buffer containing fragment to be initialised - * @i: paged fragment index to initialise - * @page: the page to use for this fragment + * @i: fragment index to initialise + * @netmem: the netmem to use for this fragment * @off: the offset to the data with @page * @size: the length of the data * @@ -2472,10 +2492,12 @@ static inline void skb_len_add(struct sk_buff *skb, int delta) * * Does not take any additional reference on the fragment. */ -static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, - struct page *page, int off, int size) +static inline void __skb_fill_netmem_desc(struct sk_buff *skb, int i, + netmem_ref netmem, int off, int size) { - __skb_fill_page_desc_noacc(skb_shinfo(skb), i, page, off, size); + struct page *page = netmem_to_page(netmem); + + __skb_fill_netmem_desc_noacc(skb_shinfo(skb), i, netmem, off, size); /* Propagate page pfmemalloc to the skb if we can. The problem is * that not all callers have unique ownership of the page but rely @@ -2483,7 +2505,20 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, */ page = compound_head(page); if (page_is_pfmemalloc(page)) - skb->pfmemalloc = true; + skb->pfmemalloc = true; +} + +static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, + struct page *page, int off, int size) +{ + __skb_fill_netmem_desc(skb, i, page_to_netmem(page), off, size); +} + +static inline void skb_fill_netmem_desc(struct sk_buff *skb, int i, + netmem_ref netmem, int off, int size) +{ + __skb_fill_netmem_desc(skb, i, netmem, off, size); + skb_shinfo(skb)->nr_frags = i + 1; } /** @@ -2503,8 +2538,7 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, static inline void skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) { - __skb_fill_page_desc(skb, i, page, off, size); - skb_shinfo(skb)->nr_frags = i + 1; + skb_fill_netmem_desc(skb, i, page_to_netmem(page), off, size); } /** @@ -2528,8 +2562,16 @@ static inline void skb_fill_page_desc_noacc(struct sk_buff *skb, int i, shinfo->nr_frags = i + 1; } -void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, - int size, unsigned int truesize); +void skb_add_rx_frag_netmem(struct sk_buff *skb, int i, netmem_ref netmem, + int off, int size, unsigned int truesize); + +static inline void skb_add_rx_frag(struct sk_buff *skb, int i, + struct page *page, int off, int size, + unsigned int truesize) +{ + skb_add_rx_frag_netmem(skb, i, page_to_netmem(page), off, size, + truesize); +} void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size, unsigned int truesize); @@ -3378,7 +3420,7 @@ static inline void skb_propagate_pfmemalloc(const struct page *page, */ static inline unsigned int skb_frag_off(const skb_frag_t *frag) { - return frag->bv_offset; + return frag->offset; } /** @@ -3388,7 +3430,7 @@ static inline unsigned int skb_frag_off(const skb_frag_t *frag) */ static inline void skb_frag_off_add(skb_frag_t *frag, int delta) { - frag->bv_offset += delta; + frag->offset += delta; } /** @@ -3398,7 +3440,7 @@ static inline void skb_frag_off_add(skb_frag_t *frag, int delta) */ static inline void skb_frag_off_set(skb_frag_t *frag, unsigned int offset) { - frag->bv_offset = offset; + frag->offset = offset; } /** @@ -3409,7 +3451,7 @@ static inline void skb_frag_off_set(skb_frag_t *frag, unsigned int offset) static inline void skb_frag_off_copy(skb_frag_t *fragto, const skb_frag_t *fragfrom) { - fragto->bv_offset = fragfrom->bv_offset; + fragto->offset = fragfrom->offset; } /** @@ -3420,7 +3462,7 @@ static inline void skb_frag_off_copy(skb_frag_t *fragto, */ static inline struct page *skb_frag_page(const skb_frag_t *frag) { - return frag->bv_page; + return netmem_to_page(frag->netmem); } /** @@ -3528,7 +3570,7 @@ static inline void *skb_frag_address_safe(const skb_frag_t *frag) static inline void skb_frag_page_copy(skb_frag_t *fragto, const skb_frag_t *fragfrom) { - fragto->bv_page = fragfrom->bv_page; + fragto->netmem = fragfrom->netmem; } bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b41856585c24..1434c422f76e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -115,6 +115,24 @@ static struct kmem_cache *skb_small_head_cache __ro_after_init; int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags); +/* kcm_write_msgs() relies on casting paged frags to bio_vec to use + * iov_iter_bvec(). These static asserts ensure the cast is valid is long as the + * netmem is a page. + */ +static_assert(offsetof(struct bio_vec, bv_page) == + offsetof(skb_frag_t, netmem)); +static_assert(sizeof_field(struct bio_vec, bv_page) == + sizeof_field(skb_frag_t, netmem)); + +static_assert(offsetof(struct bio_vec, bv_len) == offsetof(skb_frag_t, len)); +static_assert(sizeof_field(struct bio_vec, bv_len) == + sizeof_field(skb_frag_t, len)); + +static_assert(offsetof(struct bio_vec, bv_offset) == + offsetof(skb_frag_t, offset)); +static_assert(sizeof_field(struct bio_vec, bv_offset) == + sizeof_field(skb_frag_t, offset)); + #undef FN #define FN(reason) [SKB_DROP_REASON_##reason] = #reason, static const char * const drop_reasons[] = { @@ -845,17 +863,17 @@ skb_fail: } EXPORT_SYMBOL(__napi_alloc_skb); -void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, - int size, unsigned int truesize) +void skb_add_rx_frag_netmem(struct sk_buff *skb, int i, netmem_ref netmem, + int off, int size, unsigned int truesize) { DEBUG_NET_WARN_ON_ONCE(size > truesize); - skb_fill_page_desc(skb, i, page, off, size); + skb_fill_netmem_desc(skb, i, netmem, off, size); skb->len += size; skb->data_len += size; skb->truesize += truesize; } -EXPORT_SYMBOL(skb_add_rx_frag); +EXPORT_SYMBOL(skb_add_rx_frag_netmem); void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size, unsigned int truesize) @@ -1999,10 +2017,11 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) /* skb frags point to kernel buffers */ for (i = 0; i < new_frags - 1; i++) { - __skb_fill_page_desc(skb, i, head, 0, psize); + __skb_fill_netmem_desc(skb, i, page_to_netmem(head), 0, psize); head = (struct page *)page_private(head); } - __skb_fill_page_desc(skb, new_frags - 1, head, 0, d_off); + __skb_fill_netmem_desc(skb, new_frags - 1, page_to_netmem(head), 0, + d_off); skb_shinfo(skb)->nr_frags = new_frags; release: @@ -3740,7 +3759,8 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) if (plen) { page = virt_to_head_page(from->head); offset = from->data - (unsigned char *)page_address(page); - __skb_fill_page_desc(to, 0, page, offset, plen); + __skb_fill_netmem_desc(to, 0, page_to_netmem(page), + offset, plen); get_page(page); j = 1; len -= plen; diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 1184d40167b8..73c200c5c8e4 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -627,7 +627,8 @@ retry: skb = txm->frag_skb; } - if (WARN_ON(!skb_shinfo(skb)->nr_frags)) { + if (WARN_ON(!skb_shinfo(skb)->nr_frags) || + WARN_ON_ONCE(!skb_frag_page(&skb_shinfo(skb)->frags[0]))) { ret = -EINVAL; goto out; } @@ -637,8 +638,8 @@ retry: msize += skb_frag_size(&skb_shinfo(skb)->frags[i]); iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, - skb_shinfo(skb)->frags, skb_shinfo(skb)->nr_frags, - msize); + (const struct bio_vec *)skb_shinfo(skb)->frags, + skb_shinfo(skb)->nr_frags, msize); iov_iter_advance(&msg.msg_iter, txm->frag_offset); do { From 00bf80c437dcbbd808d61cc2866c8f065ff436bd Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 20 Feb 2024 09:16:16 +0100 Subject: [PATCH 1317/2255] can: raw: raw_getsockopt(): reduce scope of err Reduce the scope of the variable "err" to the individual cases. This is to avoid the mistake of setting "err" in the mistaken belief that it will be evaluated later. Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20240220-raw-setsockopt-v1-1-7d34cb1377fc@pengutronix.de Signed-off-by: Marc Kleine-Budde --- net/can/raw.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/can/raw.c b/net/can/raw.c index 897ffc17d850..00533f64d69d 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -756,7 +756,6 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, struct raw_sock *ro = raw_sk(sk); int len; void *val; - int err = 0; if (level != SOL_CAN_RAW) return -EINVAL; @@ -766,7 +765,9 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, return -EINVAL; switch (optname) { - case CAN_RAW_FILTER: + case CAN_RAW_FILTER: { + int err = 0; + lock_sock(sk); if (ro->count > 0) { int fsize = ro->count * sizeof(struct can_filter); @@ -791,7 +792,7 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, if (!err) err = put_user(len, optlen); return err; - + } case CAN_RAW_ERR_FILTER: if (len > sizeof(can_err_mask_t)) len = sizeof(can_err_mask_t); @@ -822,7 +823,9 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, val = &ro->xl_frames; break; - case CAN_RAW_XL_VCID_OPTS: + case CAN_RAW_XL_VCID_OPTS: { + int err = 0; + /* user space buffer to small for VCID opts? */ if (len < sizeof(ro->raw_vcid_opts)) { /* return -ERANGE and needed space in optlen */ @@ -838,7 +841,7 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, if (!err) err = put_user(len, optlen); return err; - + } case CAN_RAW_JOIN_FILTERS: if (len > sizeof(int)) len = sizeof(int); From 465c1abcb64426f0ff39e80e508e2432672c2dae Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 16 Feb 2024 12:54:43 +0000 Subject: [PATCH 1318/2255] net: tcp: Remove redundant initialization of variable len The variable len being initialized with a value that is never read, an if statement is initializing it in both paths of the if statement. The initialization is redundant and can be removed. Cleans up clang scan build warning: net/ipv4/tcp_ao.c:512:11: warning: Value stored to 'len' during its initialization is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Link: https://lore.kernel.org/r/20240216125443.2107244-1-colin.i.king@gmail.com Signed-off-by: Paolo Abeni --- net/ipv4/tcp_ao.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c index 87db432c6bb4..3afeeb68e8a7 100644 --- a/net/ipv4/tcp_ao.c +++ b/net/ipv4/tcp_ao.c @@ -509,9 +509,9 @@ static int tcp_ao_hash_header(struct tcp_sigpool *hp, bool exclude_options, u8 *hash, int hash_offset, int hash_len) { - int err, len = th->doff << 2; struct scatterlist sg; u8 *hdr = hp->scratch; + int err, len; /* We are not allowed to change tcphdr, make a local copy */ if (exclude_options) { From 5d4cc87414c5d11345c4b11d61377d351b5c28a2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 16 Feb 2024 16:20:06 +0000 Subject: [PATCH 1319/2255] net: reorganize "struct sock" fields Last major reorg happened in commit 9115e8cd2a0c ("net: reorganize struct sock for better data locality") Since then, many changes have been done. Before SO_PEEK_OFF support is added to TCP, we need to move sk_peek_off to a better location. It is time to make another pass, and add six groups, without explicit alignment. - sock_write_rx (following sk_refcnt) read-write fields in rx path. - sock_read_rx read-mostly fields in rx path. - sock_read_rxtx read-mostly fields in both rx and tx paths. - sock_write_rxtx read-write fields in both rx and tx paths. - sock_write_tx read-write fields in tx paths. - sock_read_tx read-mostly fields in tx paths. Results on TCP_RR benchmarks seem to show a gain (4 to 5 %). It is possible UDP needs a change, because sk_peek_off shares a cache line with sk_receive_queue. If this the case, we can exchange roles of sk->sk_receive and up->reader_queue queues. After this change, we have the following layout: struct sock { struct sock_common __sk_common; /* 0 0x88 */ /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */ __u8 __cacheline_group_begin__sock_write_rx[0]; /* 0x88 0 */ atomic_t sk_drops; /* 0x88 0x4 */ __s32 sk_peek_off; /* 0x8c 0x4 */ struct sk_buff_head sk_error_queue; /* 0x90 0x18 */ struct sk_buff_head sk_receive_queue; /* 0xa8 0x18 */ /* --- cacheline 3 boundary (192 bytes) --- */ struct { atomic_t rmem_alloc; /* 0xc0 0x4 */ int len; /* 0xc4 0x4 */ struct sk_buff * head; /* 0xc8 0x8 */ struct sk_buff * tail; /* 0xd0 0x8 */ } sk_backlog; /* 0xc0 0x18 */ struct { atomic_t rmem_alloc; /* 0 0x4 */ int len; /* 0x4 0x4 */ struct sk_buff * head; /* 0x8 0x8 */ struct sk_buff * tail; /* 0x10 0x8 */ /* size: 24, cachelines: 1, members: 4 */ /* last cacheline: 24 bytes */ }; __u8 __cacheline_group_end__sock_write_rx[0]; /* 0xd8 0 */ __u8 __cacheline_group_begin__sock_read_rx[0]; /* 0xd8 0 */ rcu * sk_rx_dst; /* 0xd8 0x8 */ int sk_rx_dst_ifindex; /* 0xe0 0x4 */ u32 sk_rx_dst_cookie; /* 0xe4 0x4 */ unsigned int sk_ll_usec; /* 0xe8 0x4 */ unsigned int sk_napi_id; /* 0xec 0x4 */ u16 sk_busy_poll_budget; /* 0xf0 0x2 */ u8 sk_prefer_busy_poll; /* 0xf2 0x1 */ u8 sk_userlocks; /* 0xf3 0x1 */ int sk_rcvbuf; /* 0xf4 0x4 */ rcu * sk_filter; /* 0xf8 0x8 */ /* --- cacheline 4 boundary (256 bytes) --- */ union { rcu * sk_wq; /* 0x100 0x8 */ struct socket_wq * sk_wq_raw; /* 0x100 0x8 */ }; /* 0x100 0x8 */ union { rcu * sk_wq; /* 0 0x8 */ struct socket_wq * sk_wq_raw; /* 0 0x8 */ }; void (*sk_data_ready)(struct sock *); /* 0x108 0x8 */ long sk_rcvtimeo; /* 0x110 0x8 */ int sk_rcvlowat; /* 0x118 0x4 */ __u8 __cacheline_group_end__sock_read_rx[0]; /* 0x11c 0 */ __u8 __cacheline_group_begin__sock_read_rxtx[0]; /* 0x11c 0 */ int sk_err; /* 0x11c 0x4 */ struct socket * sk_socket; /* 0x120 0x8 */ struct mem_cgroup * sk_memcg; /* 0x128 0x8 */ rcu * sk_policy[2]; /* 0x130 0x10 */ /* --- cacheline 5 boundary (320 bytes) --- */ __u8 __cacheline_group_end__sock_read_rxtx[0]; /* 0x140 0 */ __u8 __cacheline_group_begin__sock_write_rxtx[0]; /* 0x140 0 */ socket_lock_t sk_lock; /* 0x140 0x20 */ u32 sk_reserved_mem; /* 0x160 0x4 */ int sk_forward_alloc; /* 0x164 0x4 */ u32 sk_tsflags; /* 0x168 0x4 */ __u8 __cacheline_group_end__sock_write_rxtx[0]; /* 0x16c 0 */ __u8 __cacheline_group_begin__sock_write_tx[0]; /* 0x16c 0 */ int sk_write_pending; /* 0x16c 0x4 */ atomic_t sk_omem_alloc; /* 0x170 0x4 */ int sk_sndbuf; /* 0x174 0x4 */ int sk_wmem_queued; /* 0x178 0x4 */ refcount_t sk_wmem_alloc; /* 0x17c 0x4 */ /* --- cacheline 6 boundary (384 bytes) --- */ unsigned long sk_tsq_flags; /* 0x180 0x8 */ union { struct sk_buff * sk_send_head; /* 0x188 0x8 */ struct rb_root tcp_rtx_queue; /* 0x188 0x8 */ }; /* 0x188 0x8 */ union { struct sk_buff * sk_send_head; /* 0 0x8 */ struct rb_root tcp_rtx_queue; /* 0 0x8 */ }; struct sk_buff_head sk_write_queue; /* 0x190 0x18 */ u32 sk_dst_pending_confirm; /* 0x1a8 0x4 */ u32 sk_pacing_status; /* 0x1ac 0x4 */ struct page_frag sk_frag; /* 0x1b0 0x10 */ /* --- cacheline 7 boundary (448 bytes) --- */ struct timer_list sk_timer; /* 0x1c0 0x28 */ /* XXX last struct has 4 bytes of padding */ unsigned long sk_pacing_rate; /* 0x1e8 0x8 */ atomic_t sk_zckey; /* 0x1f0 0x4 */ atomic_t sk_tskey; /* 0x1f4 0x4 */ __u8 __cacheline_group_end__sock_write_tx[0]; /* 0x1f8 0 */ __u8 __cacheline_group_begin__sock_read_tx[0]; /* 0x1f8 0 */ unsigned long sk_max_pacing_rate; /* 0x1f8 0x8 */ /* --- cacheline 8 boundary (512 bytes) --- */ long sk_sndtimeo; /* 0x200 0x8 */ u32 sk_priority; /* 0x208 0x4 */ u32 sk_mark; /* 0x20c 0x4 */ rcu * sk_dst_cache; /* 0x210 0x8 */ netdev_features_t sk_route_caps; /* 0x218 0x8 */ u16 sk_gso_type; /* 0x220 0x2 */ u16 sk_gso_max_segs; /* 0x222 0x2 */ unsigned int sk_gso_max_size; /* 0x224 0x4 */ gfp_t sk_allocation; /* 0x228 0x4 */ u32 sk_txhash; /* 0x22c 0x4 */ u8 sk_pacing_shift; /* 0x230 0x1 */ bool sk_use_task_frag; /* 0x231 0x1 */ __u8 __cacheline_group_end__sock_read_tx[0]; /* 0x232 0 */ u8 sk_gso_disabled:1; /* 0x232: 0 0x1 */ u8 sk_kern_sock:1; /* 0x232:0x1 0x1 */ u8 sk_no_check_tx:1; /* 0x232:0x2 0x1 */ u8 sk_no_check_rx:1; /* 0x232:0x3 0x1 */ /* XXX 4 bits hole, try to pack */ u8 sk_shutdown; /* 0x233 0x1 */ u16 sk_type; /* 0x234 0x2 */ u16 sk_protocol; /* 0x236 0x2 */ unsigned long sk_lingertime; /* 0x238 0x8 */ /* --- cacheline 9 boundary (576 bytes) --- */ struct proto * sk_prot_creator; /* 0x240 0x8 */ rwlock_t sk_callback_lock; /* 0x248 0x8 */ int sk_err_soft; /* 0x250 0x4 */ u32 sk_ack_backlog; /* 0x254 0x4 */ u32 sk_max_ack_backlog; /* 0x258 0x4 */ kuid_t sk_uid; /* 0x25c 0x4 */ spinlock_t sk_peer_lock; /* 0x260 0x4 */ int sk_bind_phc; /* 0x264 0x4 */ struct pid * sk_peer_pid; /* 0x268 0x8 */ const struct cred * sk_peer_cred; /* 0x270 0x8 */ ktime_t sk_stamp; /* 0x278 0x8 */ /* --- cacheline 10 boundary (640 bytes) --- */ int sk_disconnects; /* 0x280 0x4 */ u8 sk_txrehash; /* 0x284 0x1 */ u8 sk_clockid; /* 0x285 0x1 */ u8 sk_txtime_deadline_mode:1; /* 0x286: 0 0x1 */ u8 sk_txtime_report_errors:1; /* 0x286:0x1 0x1 */ u8 sk_txtime_unused:6; /* 0x286:0x2 0x1 */ /* XXX 1 byte hole, try to pack */ void * sk_user_data; /* 0x288 0x8 */ void * sk_security; /* 0x290 0x8 */ struct sock_cgroup_data sk_cgrp_data; /* 0x298 0x8 */ void (*sk_state_change)(struct sock *); /* 0x2a0 0x8 */ void (*sk_write_space)(struct sock *); /* 0x2a8 0x8 */ void (*sk_error_report)(struct sock *); /* 0x2b0 0x8 */ int (*sk_backlog_rcv)(struct sock *, struct sk_buff *); /* 0x2b8 0x8 */ /* --- cacheline 11 boundary (704 bytes) --- */ void (*sk_destruct)(struct sock *); /* 0x2c0 0x8 */ rcu * sk_reuseport_cb; /* 0x2c8 0x8 */ rcu * sk_bpf_storage; /* 0x2d0 0x8 */ struct callback_head sk_rcu __attribute__((__aligned__(8))); /* 0x2d8 0x10 */ netns_tracker ns_tracker; /* 0x2e8 0x8 */ /* size: 752, cachelines: 12, members: 105 */ /* sum members: 749, holes: 1, sum holes: 1 */ /* sum bitfield members: 12 bits, bit holes: 1, sum bit holes: 4 bits */ /* paddings: 1, sum paddings: 4 */ /* forced alignments: 1 */ /* last cacheline: 48 bytes */ }; Signed-off-by: Eric Dumazet Acked-by: Paolo Abeni Link: https://lore.kernel.org/r/20240216162006.2342759-1-edumazet@google.com Signed-off-by: Paolo Abeni --- include/net/sock.h | 112 +++++++++++++++++++++++++-------------------- net/core/sock.c | 62 +++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 49 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index a9d99a9c583f..796a902cf4c1 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -378,14 +378,10 @@ struct sock { #define sk_flags __sk_common.skc_flags #define sk_rxhash __sk_common.skc_rxhash - /* early demux fields */ - struct dst_entry __rcu *sk_rx_dst; - int sk_rx_dst_ifindex; - u32 sk_rx_dst_cookie; + __cacheline_group_begin(sock_write_rx); - socket_lock_t sk_lock; atomic_t sk_drops; - int sk_rcvlowat; + __s32 sk_peek_off; struct sk_buff_head sk_error_queue; struct sk_buff_head sk_receive_queue; /* @@ -402,18 +398,24 @@ struct sock { struct sk_buff *head; struct sk_buff *tail; } sk_backlog; - #define sk_rmem_alloc sk_backlog.rmem_alloc - int sk_forward_alloc; - u32 sk_reserved_mem; + __cacheline_group_end(sock_write_rx); + + __cacheline_group_begin(sock_read_rx); + /* early demux fields */ + struct dst_entry __rcu *sk_rx_dst; + int sk_rx_dst_ifindex; + u32 sk_rx_dst_cookie; + #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sk_ll_usec; - /* ===== mostly read cache line ===== */ unsigned int sk_napi_id; + u16 sk_busy_poll_budget; + u8 sk_prefer_busy_poll; #endif + u8 sk_userlocks; int sk_rcvbuf; - int sk_disconnects; struct sk_filter __rcu *sk_filter; union { @@ -422,15 +424,33 @@ struct sock { struct socket_wq *sk_wq_raw; /* public: */ }; + + void (*sk_data_ready)(struct sock *sk); + long sk_rcvtimeo; + int sk_rcvlowat; + __cacheline_group_end(sock_read_rx); + + __cacheline_group_begin(sock_read_rxtx); + int sk_err; + struct socket *sk_socket; + struct mem_cgroup *sk_memcg; #ifdef CONFIG_XFRM struct xfrm_policy __rcu *sk_policy[2]; #endif + __cacheline_group_end(sock_read_rxtx); - struct dst_entry __rcu *sk_dst_cache; + __cacheline_group_begin(sock_write_rxtx); + socket_lock_t sk_lock; + u32 sk_reserved_mem; + int sk_forward_alloc; + u32 sk_tsflags; + __cacheline_group_end(sock_write_rxtx); + + __cacheline_group_begin(sock_write_tx); + int sk_write_pending; atomic_t sk_omem_alloc; int sk_sndbuf; - /* ===== cache line for TX ===== */ int sk_wmem_queued; refcount_t sk_wmem_alloc; unsigned long sk_tsq_flags; @@ -439,22 +459,36 @@ struct sock { struct rb_root tcp_rtx_queue; }; struct sk_buff_head sk_write_queue; - __s32 sk_peek_off; - int sk_write_pending; - __u32 sk_dst_pending_confirm; + u32 sk_dst_pending_confirm; u32 sk_pacing_status; /* see enum sk_pacing */ - long sk_sndtimeo; - struct timer_list sk_timer; - __u32 sk_priority; - __u32 sk_mark; - unsigned long sk_pacing_rate; /* bytes per second */ - unsigned long sk_max_pacing_rate; struct page_frag sk_frag; + struct timer_list sk_timer; + + unsigned long sk_pacing_rate; /* bytes per second */ + atomic_t sk_zckey; + atomic_t sk_tskey; + __cacheline_group_end(sock_write_tx); + + __cacheline_group_begin(sock_read_tx); + unsigned long sk_max_pacing_rate; + long sk_sndtimeo; + u32 sk_priority; + u32 sk_mark; + struct dst_entry __rcu *sk_dst_cache; netdev_features_t sk_route_caps; - int sk_gso_type; +#ifdef CONFIG_SOCK_VALIDATE_XMIT + struct sk_buff* (*sk_validate_xmit_skb)(struct sock *sk, + struct net_device *dev, + struct sk_buff *skb); +#endif + u16 sk_gso_type; + u16 sk_gso_max_segs; unsigned int sk_gso_max_size; gfp_t sk_allocation; - __u32 sk_txhash; + u32 sk_txhash; + u8 sk_pacing_shift; + bool sk_use_task_frag; + __cacheline_group_end(sock_read_tx); /* * Because of non atomicity rules, all @@ -463,64 +497,44 @@ struct sock { u8 sk_gso_disabled : 1, sk_kern_sock : 1, sk_no_check_tx : 1, - sk_no_check_rx : 1, - sk_userlocks : 4; - u8 sk_pacing_shift; + sk_no_check_rx : 1; + u8 sk_shutdown; u16 sk_type; u16 sk_protocol; - u16 sk_gso_max_segs; unsigned long sk_lingertime; struct proto *sk_prot_creator; rwlock_t sk_callback_lock; - int sk_err, - sk_err_soft; + int sk_err_soft; u32 sk_ack_backlog; u32 sk_max_ack_backlog; kuid_t sk_uid; - u8 sk_txrehash; -#ifdef CONFIG_NET_RX_BUSY_POLL - u8 sk_prefer_busy_poll; - u16 sk_busy_poll_budget; -#endif spinlock_t sk_peer_lock; int sk_bind_phc; struct pid *sk_peer_pid; const struct cred *sk_peer_cred; - long sk_rcvtimeo; ktime_t sk_stamp; #if BITS_PER_LONG==32 seqlock_t sk_stamp_seq; #endif - atomic_t sk_tskey; - atomic_t sk_zckey; - u32 sk_tsflags; - u8 sk_shutdown; + int sk_disconnects; + u8 sk_txrehash; u8 sk_clockid; u8 sk_txtime_deadline_mode : 1, sk_txtime_report_errors : 1, sk_txtime_unused : 6; - bool sk_use_task_frag; - struct socket *sk_socket; void *sk_user_data; #ifdef CONFIG_SECURITY void *sk_security; #endif struct sock_cgroup_data sk_cgrp_data; - struct mem_cgroup *sk_memcg; void (*sk_state_change)(struct sock *sk); - void (*sk_data_ready)(struct sock *sk); void (*sk_write_space)(struct sock *sk); void (*sk_error_report)(struct sock *sk); int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); -#ifdef CONFIG_SOCK_VALIDATE_XMIT - struct sk_buff* (*sk_validate_xmit_skb)(struct sock *sk, - struct net_device *dev, - struct sk_buff *skb); -#endif void (*sk_destruct)(struct sock *sk); struct sock_reuseport __rcu *sk_reuseport_cb; #ifdef CONFIG_BPF_SYSCALL diff --git a/net/core/sock.c b/net/core/sock.c index 88bf810394a5..3fef3407383e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -4234,3 +4234,65 @@ int sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) return sock_ioctl_out(sk, cmd, arg); } EXPORT_SYMBOL(sk_ioctl); + +static int __init sock_struct_check(void) +{ + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rx, sk_drops); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rx, sk_peek_off); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rx, sk_error_queue); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rx, sk_receive_queue); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rx, sk_backlog); + + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_rx_dst); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_rx_dst_ifindex); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_rx_dst_cookie); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_rcvbuf); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_filter); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_wq); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_data_ready); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_rcvtimeo); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rx, sk_rcvlowat); + + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rxtx, sk_err); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rxtx, sk_socket); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rxtx, sk_memcg); + + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rxtx, sk_lock); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rxtx, sk_reserved_mem); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rxtx, sk_forward_alloc); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rxtx, sk_tsflags); + + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_omem_alloc); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_omem_alloc); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_sndbuf); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_wmem_queued); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_wmem_alloc); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_tsq_flags); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_send_head); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_write_queue); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_write_pending); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_dst_pending_confirm); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_pacing_status); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_frag); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_timer); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_pacing_rate); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_zckey); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_tx, sk_tskey); + + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_max_pacing_rate); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_sndtimeo); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_priority); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_mark); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_dst_cache); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_route_caps); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_gso_type); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_gso_max_size); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_allocation); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_txhash); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_gso_max_segs); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_pacing_shift); + CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_tx, sk_use_task_frag); + return 0; +} + +core_initcall(sock_struct_check); From 219eee9c0d16f1b754a8b85275854ab17df0850a Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 16 Feb 2024 12:36:57 +0100 Subject: [PATCH 1320/2255] net: skbuff: add overflow debug check to pull/push helpers syzbot managed to trigger following splat: BUG: KASAN: use-after-free in __skb_flow_dissect+0x4a3b/0x5e50 Read of size 1 at addr ffff888208a4000e by task a.out/2313 [..] __skb_flow_dissect+0x4a3b/0x5e50 __skb_get_hash+0xb4/0x400 ip_tunnel_xmit+0x77e/0x26f0 ipip_tunnel_xmit+0x298/0x410 .. Analysis shows that the skb has a valid ->head, but bogus ->data pointer. skb->data gets its bogus value via the neigh layer, which does: 1556 __skb_pull(skb, skb_network_offset(skb)); ... and the skb was already dodgy at this point: skb_network_offset(skb) returns a negative value due to an earlier overflow of skb->network_header (u16). __skb_pull thus "adjusts" skb->data by a huge offset, pointing outside skb->head area. Allow debug builds to splat when we try to pull/push more than INT_MAX bytes. After this, the syzkaller reproducer yields a more precise splat before the flow dissector attempts to read off skb->data memory: WARNING: CPU: 5 PID: 2313 at include/linux/skbuff.h:2653 neigh_connected_output+0x28e/0x400 ip_finish_output2+0xb25/0xed0 iptunnel_xmit+0x4ff/0x870 ipgre_xmit+0x78e/0xbb0 Signed-off-by: Florian Westphal Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240216113700.23013-1-fw@strlen.de Signed-off-by: Paolo Abeni --- include/linux/skbuff.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e3a2ed5d09ad..28c7cb7ce251 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2684,6 +2684,8 @@ static inline void skb_put_u8(struct sk_buff *skb, u8 val) void *skb_push(struct sk_buff *skb, unsigned int len); static inline void *__skb_push(struct sk_buff *skb, unsigned int len) { + DEBUG_NET_WARN_ON_ONCE(len > INT_MAX); + skb->data -= len; skb->len += len; return skb->data; @@ -2692,6 +2694,8 @@ static inline void *__skb_push(struct sk_buff *skb, unsigned int len) void *skb_pull(struct sk_buff *skb, unsigned int len); static inline void *__skb_pull(struct sk_buff *skb, unsigned int len) { + DEBUG_NET_WARN_ON_ONCE(len > INT_MAX); + skb->len -= len; if (unlikely(skb->len < skb->data_len)) { #if defined(CONFIG_DEBUG_NET) @@ -2716,6 +2720,8 @@ void *__pskb_pull_tail(struct sk_buff *skb, int delta); static inline enum skb_drop_reason pskb_may_pull_reason(struct sk_buff *skb, unsigned int len) { + DEBUG_NET_WARN_ON_ONCE(len > INT_MAX); + if (likely(len <= skb_headlen(skb))) return SKB_NOT_DROPPED_YET; From c6a28acb1a27eb42970b959ff7af3a8a077f8cce Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 17 Feb 2024 12:12:14 +0100 Subject: [PATCH 1321/2255] net: fix pointer check in skb_pp_cow_data routine Properly check page pointer returned by page_pool_dev_alloc routine in skb_pp_cow_data() for non-linear part of the original skb. Reported-by: Julian Wiedmann Closes: https://lore.kernel.org/netdev/cover.1707729884.git.lorenzo@kernel.org/T/#m7d189b0015a7281ed9221903902490c03ed19a7a Fixes: e6d5dbdd20aa ("xdp: add multi-buff support for xdp running in generic mode") Signed-off-by: Lorenzo Bianconi Reviewed-by: Simon Horman Reviewed-by: Ilias Apalodimas Link: https://lore.kernel.org/r/25512af3e09befa9dcb2cf3632bdc45b807cf330.1708167716.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- net/core/skbuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1434c422f76e..b9de3ee65ae6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -968,7 +968,7 @@ int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, truesize = size; page = page_pool_dev_alloc(pool, &page_off, &truesize); - if (!data) { + if (!page) { consume_skb(nskb); return -ENOMEM; } From f4d3e595c0000ce39dec7e4799ea42ce42ab6867 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 17 Feb 2024 15:48:23 +0100 Subject: [PATCH 1322/2255] r8169: add MODULE_FIRMWARE entry for RTL8126A Add the missing MODULE_FIRMWARE entry for RTL8126A. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/47ef79d2-59c4-4d44-9595-366c70c4ad87@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 7d3f6d59be8c..0d2cbb32c870 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -676,6 +676,7 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3); MODULE_FIRMWARE(FIRMWARE_8107E_2); MODULE_FIRMWARE(FIRMWARE_8125A_3); MODULE_FIRMWARE(FIRMWARE_8125B_2); +MODULE_FIRMWARE(FIRMWARE_8126A_2); static inline struct device *tp_to_dev(struct rtl8169_private *tp) { From 2f3bfa8e30b5b4864a200be0dc2fb55d8e4b35e4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 17 Feb 2024 11:03:06 +0100 Subject: [PATCH 1323/2255] net: wan: framer: constify of_phandle_args in xlate The xlate callbacks are supposed to translate of_phandle_args to proper provider without modifying the of_phandle_args. Make the argument pointer to const for code safety and readability. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240217100306.86740-1-krzysztof.kozlowski@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/wan/framer/framer-core.c | 9 +++++---- include/linux/framer/framer-provider.h | 14 +++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/wan/framer/framer-core.c b/drivers/net/wan/framer/framer-core.c index c04dc88bda6c..33b358b99f70 100644 --- a/drivers/net/wan/framer/framer-core.c +++ b/drivers/net/wan/framer/framer-core.c @@ -384,7 +384,7 @@ static struct framer_provider *framer_provider_of_lookup(const struct device_nod return ERR_PTR(-EPROBE_DEFER); } -static struct framer *framer_of_get_from_provider(struct of_phandle_args *args) +static struct framer *framer_of_get_from_provider(const struct of_phandle_args *args) { struct framer_provider *framer_provider; struct framer *framer; @@ -735,7 +735,8 @@ EXPORT_SYMBOL_GPL(devm_framer_create); * should provide a custom of_xlate function that reads the *args* and returns * the appropriate framer. */ -struct framer *framer_provider_simple_of_xlate(struct device *dev, struct of_phandle_args *args) +struct framer *framer_provider_simple_of_xlate(struct device *dev, + const struct of_phandle_args *args) { struct class_dev_iter iter; struct framer *framer; @@ -768,7 +769,7 @@ EXPORT_SYMBOL_GPL(framer_provider_simple_of_xlate); struct framer_provider * __framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { struct framer_provider *framer_provider; @@ -830,7 +831,7 @@ static void devm_framer_provider_of_unregister(struct device *dev, void *res) struct framer_provider * __devm_framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { struct framer_provider **ptr, *framer_provider; diff --git a/include/linux/framer/framer-provider.h b/include/linux/framer/framer-provider.h index 782cd5fc83d5..f6fd2dd92591 100644 --- a/include/linux/framer/framer-provider.h +++ b/include/linux/framer/framer-provider.h @@ -93,7 +93,7 @@ struct framer_provider { struct module *owner; struct list_head list; struct framer * (*of_xlate)(struct device *dev, - struct of_phandle_args *args); + const struct of_phandle_args *args); }; static inline void framer_set_drvdata(struct framer *framer, void *data) @@ -118,19 +118,19 @@ struct framer *devm_framer_create(struct device *dev, struct device_node *node, const struct framer_ops *ops); struct framer *framer_provider_simple_of_xlate(struct device *dev, - struct of_phandle_args *args); + const struct of_phandle_args *args); struct framer_provider * __framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, - struct of_phandle_args *args)); + const struct of_phandle_args *args)); void framer_provider_of_unregister(struct framer_provider *framer_provider); struct framer_provider * __devm_framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, - struct of_phandle_args *args)); + const struct of_phandle_args *args)); void framer_notify_status_change(struct framer *framer); @@ -154,7 +154,7 @@ static inline struct framer *devm_framer_create(struct device *dev, struct devic } static inline struct framer *framer_provider_simple_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { return ERR_PTR(-ENOSYS); } @@ -162,7 +162,7 @@ static inline struct framer *framer_provider_simple_of_xlate(struct device *dev, static inline struct framer_provider * __framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { return ERR_PTR(-ENOSYS); } @@ -174,7 +174,7 @@ void framer_provider_of_unregister(struct framer_provider *framer_provider) static inline struct framer_provider * __devm_framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { return ERR_PTR(-ENOSYS); } From 3ce7caee3af0f467ac3a1f90277d469d94c95af5 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:23 -0300 Subject: [PATCH 1324/2255] net: usbnet: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the wlan_type and wwan_type variables to be constant structures as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 2d14b0d78541..b21ebe24057f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1654,11 +1654,11 @@ static const struct net_device_ops usbnet_netdev_ops = { // precondition: never called in_interrupt -static struct device_type wlan_type = { +static const struct device_type wlan_type = { .name = "wlan", }; -static struct device_type wwan_type = { +static const struct device_type wwan_type = { .name = "wwan", }; From 7e0acba3b49e3544b7ed170ca061001f0fdae839 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:24 -0300 Subject: [PATCH 1325/2255] net: dsa: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the dsa_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dsa/user.c b/net/dsa/user.c index 5d666dfb317d..4d53c76a9840 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -2429,7 +2429,7 @@ static const struct net_device_ops dsa_user_netdev_ops = { .ndo_fill_forward_path = dsa_user_fill_forward_path, }; -static struct device_type dsa_type = { +static const struct device_type dsa_type = { .name = "dsa", }; From bbc7e4cc21a43d7991a5c9a163d2990daddc8411 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:25 -0300 Subject: [PATCH 1326/2255] net: bridge: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the br_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/bridge/br_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 717e9750614c..874cec75a818 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -474,7 +474,7 @@ static const struct net_device_ops br_netdev_ops = { .ndo_fill_forward_path = br_fill_forward_path, }; -static struct device_type br_type = { +static const struct device_type br_type = { .name = "bridge", }; From c7170e7672e52cf38f5979416d20b9133a10726e Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:26 -0300 Subject: [PATCH 1327/2255] net: vxlan: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the vxlan_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Guillaume Nault Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 705a6fd6ab6c..386cbe4d3327 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3254,7 +3254,7 @@ static const struct net_device_ops vxlan_netdev_raw_ops = { }; /* Info for udev, that this is a virtual tunnel endpoint */ -static struct device_type vxlan_type = { +static const struct device_type vxlan_type = { .name = "vxlan", }; From 908ada0da6d47146eedc8dec0ecb05b2d79eb85d Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:27 -0300 Subject: [PATCH 1328/2255] net: ppp: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the ppp_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Guillaume Nault Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 3dd52bf28f15..db1d11ae817b 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1607,7 +1607,7 @@ static const struct net_device_ops ppp_netdev_ops = { .ndo_fill_forward_path = ppp_fill_forward_path, }; -static struct device_type ppp_type = { +static const struct device_type ppp_type = { .name = "ppp", }; From e443f3acbc6d9ac4f7b138833cc93319294f58e3 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:28 -0300 Subject: [PATCH 1329/2255] net: geneve: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the geneve_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Guillaume Nault Signed-off-by: David S. Miller --- drivers/net/geneve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 256602a72356..6f3f9b446b1d 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1142,7 +1142,7 @@ static const struct ethtool_ops geneve_ethtool_ops = { }; /* Info for udev, that this is a virtual tunnel endpoint */ -static struct device_type geneve_type = { +static const struct device_type geneve_type = { .name = "geneve", }; From 0072b2c1ffd0a15960ef2a8e2ccdde91dfa55566 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:29 -0300 Subject: [PATCH 1330/2255] net: hsr: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the hsr_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 5ef6d437db72..c98b5b71ad7c 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -467,7 +467,7 @@ static const struct net_device_ops hsr_device_ops = { .ndo_set_rx_mode = hsr_set_rx_mode, }; -static struct device_type hsr_type = { +static const struct device_type hsr_type = { .name = "hsr", }; From 43820fd1ddb52a4c2b64a3659a9e7c927fc839f0 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:30 -0300 Subject: [PATCH 1331/2255] net: l2tp: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the l2tpeth_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Guillaume Nault Signed-off-by: David S. Miller --- net/l2tp/l2tp_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 25ca89f80414..39e487ccc468 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -100,7 +100,7 @@ static const struct net_device_ops l2tp_eth_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static struct device_type l2tpeth_type = { +static const struct device_type l2tpeth_type = { .name = "l2tpeth", }; From 7ae9d3423f1db1a3e61b23038005f892858a6936 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:31 -0300 Subject: [PATCH 1332/2255] net: vlan: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the vlan_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 790b54a7cbe3..df5552518251 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -537,7 +537,7 @@ static const struct header_ops vlan_passthru_header_ops = { .parse_protocol = vlan_parse_protocol, }; -static struct device_type vlan_type = { +static const struct device_type vlan_type = { .name = "vlan", }; From 52042e092ba9cf9120ffe516dd03acb1d1e572b9 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:32 -0300 Subject: [PATCH 1333/2255] net: netdevsim: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the nsim_bus_dev_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/netdevsim/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index aedab1d9623a..0c5aff63d242 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -129,7 +129,7 @@ static void nsim_bus_dev_release(struct device *dev) complete(&nsim_bus_devs_released); } -static struct device_type nsim_bus_dev_type = { +static const struct device_type nsim_bus_dev_type = { .groups = nsim_bus_dev_attr_groups, .release = nsim_bus_dev_release, }; From 7eccf41b3bacb97092bffb23853529277c20e46a Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:33 -0300 Subject: [PATCH 1334/2255] net: wwan: core: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the wwan_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Reviewed-by: Sergey Ryazanov Signed-off-by: David S. Miller --- drivers/net/wwan/wwan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index 2ed20b20e7fc..b0030f3ed0f0 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -920,7 +920,7 @@ static int wwan_rtnl_validate(struct nlattr *tb[], struct nlattr *data[], return 0; } -static struct device_type wwan_type = { .name = "wwan" }; +static const struct device_type wwan_type = { .name = "wwan" }; static struct net_device *wwan_rtnl_alloc(struct nlattr *tb[], const char *ifname, From 55fad9c4a3c40f6853ce4570b69d5f8774c443b7 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 17 Feb 2024 17:13:34 -0300 Subject: [PATCH 1335/2255] net: hso: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the hso_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index f088ea2ba6f3..1aeb36119d3f 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2465,7 +2465,7 @@ static void hso_create_rfkill(struct hso_device *hso_dev, } } -static struct device_type hso_type = { +static const struct device_type hso_type = { .name = "wwan", }; From aa23cfe6ab500dbbfa630602b403f433522daf9f Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Wed, 24 Jan 2024 16:15:38 +0800 Subject: [PATCH 1336/2255] netfilter: expect: Simplify the allocation of slab caches in nf_conntrack_expect_init Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Signed-off-by: Florian Westphal --- net/netfilter/nf_conntrack_expect.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 81ca348915c9..21fa550966f0 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -722,9 +722,7 @@ int nf_conntrack_expect_init(void) nf_ct_expect_hsize = 1; } nf_ct_expect_max = nf_ct_expect_hsize * 4; - nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", - sizeof(struct nf_conntrack_expect), - 0, 0, NULL); + nf_ct_expect_cachep = KMEM_CACHE(nf_conntrack_expect, 0); if (!nf_ct_expect_cachep) return -ENOMEM; From 79578be4d35c842a802487e2f31c2aed80cc005f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 29 Jan 2024 20:24:24 +0100 Subject: [PATCH 1337/2255] netfilter: nf_log: consolidate check for NULL logger in lookup function Consolidate pointer fetch to logger and check for NULL in __find_logger(). Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- net/netfilter/nf_log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index e16f158388bb..e0bfeb75766f 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -31,10 +31,10 @@ static struct nf_logger *__find_logger(int pf, const char *str_logger) int i; for (i = 0; i < NF_LOG_TYPE_MAX; i++) { - if (loggers[pf][i] == NULL) + log = nft_log_dereference(loggers[pf][i]); + if (!log) continue; - log = nft_log_dereference(loggers[pf][i]); if (!strncasecmp(str_logger, log->name, strlen(log->name))) return log; } From c47ec2b120b4a9d573e65baa33ff3f542f7ba273 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 29 Jan 2024 20:24:25 +0100 Subject: [PATCH 1338/2255] netfilter: nf_log: validate nf_logger_find_get() Sanitize nf_logger_find_get() input parameters, no caller in the tree passes invalid values. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- net/netfilter/nf_log.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index e0bfeb75766f..370f8231385c 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -156,6 +156,11 @@ int nf_logger_find_get(int pf, enum nf_log_type type) struct nf_logger *logger; int ret = -ENOENT; + if (pf >= ARRAY_SIZE(loggers)) + return -EINVAL; + if (type >= NF_LOG_TYPE_MAX) + return -EINVAL; + if (pf == NFPROTO_INET) { ret = nf_logger_find_get(NFPROTO_IPV4, type); if (ret < 0) From 29a280025580d72bc0daf6c040518a069870421f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 29 Jan 2024 20:24:57 +0100 Subject: [PATCH 1339/2255] netfilter: nft_osf: simplify init path Remove useless branch to check for errors in nft_parse_register_store(). Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- net/netfilter/nft_osf.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c index 7f61506e5b44..7fec57ff736f 100644 --- a/net/netfilter/nft_osf.c +++ b/net/netfilter/nft_osf.c @@ -63,7 +63,6 @@ static int nft_osf_init(const struct nft_ctx *ctx, { struct nft_osf *priv = nft_expr_priv(expr); u32 flags; - int err; u8 ttl; if (!tb[NFTA_OSF_DREG]) @@ -83,13 +82,9 @@ static int nft_osf_init(const struct nft_ctx *ctx, priv->flags = flags; } - err = nft_parse_register_store(ctx, tb[NFTA_OSF_DREG], &priv->dreg, - NULL, NFT_DATA_VALUE, - NFT_OSF_MAXGENRELEN); - if (err < 0) - return err; - - return 0; + return nft_parse_register_store(ctx, tb[NFTA_OSF_DREG], &priv->dreg, + NULL, NFT_DATA_VALUE, + NFT_OSF_MAXGENRELEN); } static int nft_osf_dump(struct sk_buff *skb, From 749d4ef0868c5d8a98e07073791b2198178c93b4 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Feb 2024 14:55:53 +0100 Subject: [PATCH 1340/2255] netfilter: xtables: fix up kconfig dependencies Randy Dunlap reports arptables build failure: arp_tables.c:(.text+0x20): undefined reference to `xt_find_table' ... because recent change removed a 'select' on the xtables core. Add a "depends" clause on arptables to resolve this. Kernel test robot reports another build breakage: iptable_nat.c:(.text+0x8): undefined reference to `ipt_unregister_table_exit' ... because of a typo, the nat table selected ip6tables. Reported-by: kernel test robot Reported-by: Randy Dunlap Closes: https://lore.kernel.org/netfilter-devel/d0dfbaef-046a-4c42-9daa-53636664bf6d@infradead.org/ Fixes: a9525c7f6219 ("netfilter: xtables: allow xtables-nft only builds") Fixes: 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only builds") Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Signed-off-by: Florian Westphal --- net/ipv4/netfilter/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 783523087281..8f6e950163a7 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -217,7 +217,7 @@ config IP_NF_NAT default m if NETFILTER_ADVANCED=n select NF_NAT select NETFILTER_XT_NAT - select IP6_NF_IPTABLES_LEGACY + select IP_NF_IPTABLES_LEGACY help This enables the `nat' table in iptables. This allows masquerading, port forwarding and other forms of full Network Address Port @@ -329,6 +329,7 @@ config NFT_COMPAT_ARP config IP_NF_ARPFILTER tristate "arptables-legacy packet filtering support" select IP_NF_ARPTABLES + depends on NETFILTER_XTABLES help ARP packet filtering defines a table `filter', which has a series of rules for simple ARP packet filtering at local input and From f04df573faf90bb828a2241b650598c02c074323 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 13 Feb 2024 16:23:37 +0100 Subject: [PATCH 1341/2255] netfilter: nft_set_pipapo: constify lookup fn args where possible Those get called from packet path, content must not be modified. No functional changes intended. Reviewed-by: Stefano Brivio Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 18 +++++---- net/netfilter/nft_set_pipapo.h | 6 +-- net/netfilter/nft_set_pipapo_avx2.c | 59 +++++++++++++++++------------ 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index aa1d9e93a9a0..dedb17a4e07c 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -360,7 +360,7 @@ * Return: -1 on no match, bit position on 'match_only', 0 otherwise. */ int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst, - union nft_pipapo_map_bucket *mt, bool match_only) + const union nft_pipapo_map_bucket *mt, bool match_only) { unsigned long bitset; int k, ret = -1; @@ -412,9 +412,9 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set, struct nft_pipapo_scratch *scratch; unsigned long *res_map, *fill_map; u8 genmask = nft_genmask_cur(net); + const struct nft_pipapo_match *m; + const struct nft_pipapo_field *f; const u8 *rp = (const u8 *)key; - struct nft_pipapo_match *m; - struct nft_pipapo_field *f; bool map_index; int i; @@ -519,11 +519,13 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net, { struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT); struct nft_pipapo *priv = nft_set_priv(set); - struct nft_pipapo_match *m = priv->clone; unsigned long *res_map, *fill_map = NULL; - struct nft_pipapo_field *f; + const struct nft_pipapo_match *m; + const struct nft_pipapo_field *f; int i; + m = priv->clone; + res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC); if (!res_map) { ret = ERR_PTR(-ENOMEM); @@ -1597,7 +1599,7 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m) while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) { union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS]; - struct nft_pipapo_field *f; + const struct nft_pipapo_field *f; int i, start, rules_fx; start = first_rule; @@ -2039,8 +2041,8 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set, { struct nft_pipapo *priv = nft_set_priv(set); struct net *net = read_pnet(&set->net); - struct nft_pipapo_match *m; - struct nft_pipapo_field *f; + const struct nft_pipapo_match *m; + const struct nft_pipapo_field *f; int i, r; rcu_read_lock(); diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h index 3842c7341a9f..42464e7c24ac 100644 --- a/net/netfilter/nft_set_pipapo.h +++ b/net/netfilter/nft_set_pipapo.h @@ -187,7 +187,7 @@ struct nft_pipapo_elem { }; int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst, - union nft_pipapo_map_bucket *mt, bool match_only); + const union nft_pipapo_map_bucket *mt, bool match_only); /** * pipapo_and_field_buckets_4bit() - Intersect 4-bit buckets @@ -195,7 +195,7 @@ int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst, * @dst: Area to store result * @data: Input data selecting table buckets */ -static inline void pipapo_and_field_buckets_4bit(struct nft_pipapo_field *f, +static inline void pipapo_and_field_buckets_4bit(const struct nft_pipapo_field *f, unsigned long *dst, const u8 *data) { @@ -223,7 +223,7 @@ static inline void pipapo_and_field_buckets_4bit(struct nft_pipapo_field *f, * @dst: Area to store result * @data: Input data selecting table buckets */ -static inline void pipapo_and_field_buckets_8bit(struct nft_pipapo_field *f, +static inline void pipapo_and_field_buckets_8bit(const struct nft_pipapo_field *f, unsigned long *dst, const u8 *data) { diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c index a3a8ddca9918..d08407d589ea 100644 --- a/net/netfilter/nft_set_pipapo_avx2.c +++ b/net/netfilter/nft_set_pipapo_avx2.c @@ -212,8 +212,9 @@ static int nft_pipapo_avx2_refill(int offset, unsigned long *map, * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_4b_2(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b; u8 pg[2] = { pkt[0] >> 4, pkt[0] & 0xf }; @@ -274,8 +275,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_4b_4(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b; u8 pg[4] = { pkt[0] >> 4, pkt[0] & 0xf, pkt[1] >> 4, pkt[1] & 0xf }; @@ -350,8 +352,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_4b_8(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { u8 pg[8] = { pkt[0] >> 4, pkt[0] & 0xf, pkt[1] >> 4, pkt[1] & 0xf, pkt[2] >> 4, pkt[2] & 0xf, pkt[3] >> 4, pkt[3] & 0xf, @@ -445,8 +448,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_4b_12(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { u8 pg[12] = { pkt[0] >> 4, pkt[0] & 0xf, pkt[1] >> 4, pkt[1] & 0xf, pkt[2] >> 4, pkt[2] & 0xf, pkt[3] >> 4, pkt[3] & 0xf, @@ -534,8 +538,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_4b_32(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { u8 pg[32] = { pkt[0] >> 4, pkt[0] & 0xf, pkt[1] >> 4, pkt[1] & 0xf, pkt[2] >> 4, pkt[2] & 0xf, pkt[3] >> 4, pkt[3] & 0xf, @@ -669,8 +674,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_8b_1(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b; unsigned long *lt = f->lt, bsize = f->bsize; @@ -726,8 +732,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_8b_2(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b; unsigned long *lt = f->lt, bsize = f->bsize; @@ -790,8 +797,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_8b_4(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b; unsigned long *lt = f->lt, bsize = f->bsize; @@ -865,8 +873,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_8b_6(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b; unsigned long *lt = f->lt, bsize = f->bsize; @@ -950,8 +959,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_8b_16(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b; unsigned long *lt = f->lt, bsize = f->bsize; @@ -1042,8 +1052,9 @@ nothing: * word index to be checked next (i.e. first filled word). */ static int nft_pipapo_avx2_lookup_slow(unsigned long *map, unsigned long *fill, - struct nft_pipapo_field *f, int offset, - const u8 *pkt, bool first, bool last) + const struct nft_pipapo_field *f, + int offset, const u8 *pkt, + bool first, bool last) { unsigned long bsize = f->bsize; int i, ret = -1, b; @@ -1119,9 +1130,9 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, struct nft_pipapo *priv = nft_set_priv(set); struct nft_pipapo_scratch *scratch; u8 genmask = nft_genmask_cur(net); + const struct nft_pipapo_match *m; + const struct nft_pipapo_field *f; const u8 *rp = (const u8 *)key; - struct nft_pipapo_match *m; - struct nft_pipapo_field *f; unsigned long *res, *fill; bool map_index; int i, ret = 0; From 07ace0bbe03b3d8e85869af1dec5e4087b1d57b8 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 13 Feb 2024 16:23:38 +0100 Subject: [PATCH 1342/2255] netfilter: nft_set_pipapo: do not rely on ZERO_SIZE_PTR pipapo relies on kmalloc(0) returning ZERO_SIZE_PTR (i.e., not NULL but pointer is invalid). Rework this to not call slab allocator when we'd request a 0-byte allocation. Reviewed-by: Stefano Brivio Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index dedb17a4e07c..625c06b8bc39 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -525,6 +525,8 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net, int i; m = priv->clone; + if (m->bsize_max == 0) + return ret; res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC); if (!res_map) { @@ -1367,11 +1369,17 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) src->bsize * sizeof(*dst->lt) * src->groups * NFT_PIPAPO_BUCKETS(src->bb)); - dst->mt = kvmalloc(src->rules * sizeof(*src->mt), GFP_KERNEL); - if (!dst->mt) - goto out_mt; + if (src->rules > 0) { + dst->mt = kvmalloc_array(src->rules, sizeof(*src->mt), + GFP_KERNEL); + if (!dst->mt) + goto out_mt; + + memcpy(dst->mt, src->mt, src->rules * sizeof(*src->mt)); + } else { + dst->mt = NULL; + } - memcpy(dst->mt, src->mt, src->rules * sizeof(*src->mt)); src++; dst++; } From aac14d516c2b575af20b426fa04129a28d45c287 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 13 Feb 2024 16:23:39 +0100 Subject: [PATCH 1343/2255] netfilter: nft_set_pipapo: shrink data structures The set uses a mix of 'int', 'unsigned int', and size_t. The rule count limit is NFT_PIPAPO_RULE0_MAX, which cannot exceed INT_MAX (a few helpers use 'int' as return type). Add a compile-time assertion for this. Replace size_t usage in structs with unsigned int or u8 where the stored values are smaller. Replace signed-int arguments for lengths with 'unsigned int' where possible. Last, remove lt_aligned member: its set but never read. struct nft_pipapo_match 40 bytes -> 32 bytes struct nft_pipapo_field 56 bytes -> 32 bytes Reviewed-by: Stefano Brivio Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 62 ++++++++++++++++++++++------------ net/netfilter/nft_set_pipapo.h | 29 ++++++---------- 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 625c06b8bc39..b63278b2017a 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -359,11 +359,13 @@ * * Return: -1 on no match, bit position on 'match_only', 0 otherwise. */ -int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst, +int pipapo_refill(unsigned long *map, unsigned int len, unsigned int rules, + unsigned long *dst, const union nft_pipapo_map_bucket *mt, bool match_only) { unsigned long bitset; - int k, ret = -1; + unsigned int k; + int ret = -1; for (k = 0; k < len; k++) { bitset = map[k]; @@ -631,13 +633,17 @@ nft_pipapo_get(const struct net *net, const struct nft_set *set, * * Return: 0 on success, -ENOMEM on allocation failure. */ -static int pipapo_resize(struct nft_pipapo_field *f, int old_rules, int rules) +static int pipapo_resize(struct nft_pipapo_field *f, + unsigned int old_rules, unsigned int rules) { long *new_lt = NULL, *new_p, *old_lt = f->lt, *old_p; union nft_pipapo_map_bucket *new_mt, *old_mt = f->mt; - size_t new_bucket_size, copy; + unsigned int new_bucket_size, copy; int group, bucket; + if (rules >= NFT_PIPAPO_RULE0_MAX) + return -ENOSPC; + new_bucket_size = DIV_ROUND_UP(rules, BITS_PER_LONG); #ifdef NFT_PIPAPO_ALIGN new_bucket_size = roundup(new_bucket_size, @@ -690,7 +696,7 @@ mt: if (new_lt) { f->bsize = new_bucket_size; - NFT_PIPAPO_LT_ASSIGN(f, new_lt); + f->lt = new_lt; kvfree(old_lt); } @@ -847,8 +853,8 @@ static void pipapo_lt_8b_to_4b(int old_groups, int bsize, */ static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f) { + unsigned int groups, bb; unsigned long *new_lt; - int groups, bb; size_t lt_size; lt_size = f->groups * NFT_PIPAPO_BUCKETS(f->bb) * f->bsize * @@ -898,7 +904,7 @@ static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f) f->groups = groups; f->bb = bb; kvfree(f->lt); - NFT_PIPAPO_LT_ASSIGN(f, new_lt); + f->lt = new_lt; } /** @@ -915,7 +921,7 @@ static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f) static int pipapo_insert(struct nft_pipapo_field *f, const uint8_t *k, int mask_bits) { - int rule = f->rules, group, ret, bit_offset = 0; + unsigned int rule = f->rules, group, ret, bit_offset = 0; ret = pipapo_resize(f, f->rules, f->rules + 1); if (ret) @@ -1255,8 +1261,14 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, /* Validate */ start_p = start; end_p = end; + + /* some helpers return -1, or 0 >= for valid rule pos, + * so we cannot support more than INT_MAX rules at this time. + */ + BUILD_BUG_ON(NFT_PIPAPO_RULE0_MAX > INT_MAX); + nft_pipapo_for_each_field(f, i, m) { - if (f->rules >= (unsigned long)NFT_PIPAPO_RULE0_MAX) + if (f->rules >= NFT_PIPAPO_RULE0_MAX) return -ENOSPC; if (memcmp(start_p, end_p, @@ -1362,7 +1374,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) if (!new_lt) goto out_lt; - NFT_PIPAPO_LT_ASSIGN(dst, new_lt); + dst->lt = new_lt; memcpy(NFT_PIPAPO_LT_ALIGN(new_lt), NFT_PIPAPO_LT_ALIGN(src->lt), @@ -1433,10 +1445,10 @@ out_scratch: * * Return: Number of rules that originated from the same entry as @first. */ -static int pipapo_rules_same_key(struct nft_pipapo_field *f, int first) +static unsigned int pipapo_rules_same_key(struct nft_pipapo_field *f, unsigned int first) { struct nft_pipapo_elem *e = NULL; /* Keep gcc happy */ - int r; + unsigned int r; for (r = first; r < f->rules; r++) { if (r != first && e != f->mt[r].e) @@ -1489,8 +1501,9 @@ static int pipapo_rules_same_key(struct nft_pipapo_field *f, int first) * 0 1 2 * element pointers: 0x42 0x42 0x44 */ -static void pipapo_unmap(union nft_pipapo_map_bucket *mt, int rules, - int start, int n, int to_offset, bool is_last) +static void pipapo_unmap(union nft_pipapo_map_bucket *mt, unsigned int rules, + unsigned int start, unsigned int n, + unsigned int to_offset, bool is_last) { int i; @@ -1596,8 +1609,8 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m) { struct nft_pipapo *priv = nft_set_priv(set); struct net *net = read_pnet(&set->net); + unsigned int rules_f0, first_rule = 0; u64 tstamp = nft_net_tstamp(net); - int rules_f0, first_rule = 0; struct nft_pipapo_elem *e; struct nft_trans_gc *gc; @@ -1608,7 +1621,7 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m) while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) { union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS]; const struct nft_pipapo_field *f; - int i, start, rules_fx; + unsigned int i, start, rules_fx; start = first_rule; rules_fx = rules_f0; @@ -1986,7 +1999,7 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set, { struct nft_pipapo *priv = nft_set_priv(set); struct nft_pipapo_match *m = priv->clone; - int rules_f0, first_rule = 0; + unsigned int rules_f0, first_rule = 0; struct nft_pipapo_elem *e; const u8 *data; @@ -2051,7 +2064,7 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set, struct net *net = read_pnet(&set->net); const struct nft_pipapo_match *m; const struct nft_pipapo_field *f; - int i, r; + unsigned int i, r; rcu_read_lock(); if (iter->genmask == nft_genmask_cur(net)) @@ -2155,6 +2168,9 @@ static int nft_pipapo_init(const struct nft_set *set, field_count = desc->field_count ? : 1; + BUILD_BUG_ON(NFT_PIPAPO_MAX_FIELDS > 255); + BUILD_BUG_ON(NFT_PIPAPO_MAX_FIELDS != NFT_REG32_COUNT); + if (field_count > NFT_PIPAPO_MAX_FIELDS) return -EINVAL; @@ -2176,7 +2192,11 @@ static int nft_pipapo_init(const struct nft_set *set, rcu_head_init(&m->rcu); nft_pipapo_for_each_field(f, i, m) { - int len = desc->field_len[i] ? : set->klen; + unsigned int len = desc->field_len[i] ? : set->klen; + + /* f->groups is u8 */ + BUILD_BUG_ON((NFT_PIPAPO_MAX_BYTES * + BITS_PER_BYTE / NFT_PIPAPO_GROUP_BITS_LARGE_SET) >= 256); f->bb = NFT_PIPAPO_GROUP_BITS_INIT; f->groups = len * NFT_PIPAPO_GROUPS_PER_BYTE(f); @@ -2185,7 +2205,7 @@ static int nft_pipapo_init(const struct nft_set *set, f->bsize = 0; f->rules = 0; - NFT_PIPAPO_LT_ASSIGN(f, NULL); + f->lt = NULL; f->mt = NULL; } @@ -2221,7 +2241,7 @@ static void nft_set_pipapo_match_destroy(const struct nft_ctx *ctx, struct nft_pipapo_match *m) { struct nft_pipapo_field *f; - int i, r; + unsigned int i, r; for (i = 0, f = m->f; i < m->field_count - 1; i++, f++) ; diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h index 42464e7c24ac..ca64f7505e71 100644 --- a/net/netfilter/nft_set_pipapo.h +++ b/net/netfilter/nft_set_pipapo.h @@ -70,15 +70,9 @@ #define NFT_PIPAPO_ALIGN_HEADROOM \ (NFT_PIPAPO_ALIGN - ARCH_KMALLOC_MINALIGN) #define NFT_PIPAPO_LT_ALIGN(lt) (PTR_ALIGN((lt), NFT_PIPAPO_ALIGN)) -#define NFT_PIPAPO_LT_ASSIGN(field, x) \ - do { \ - (field)->lt_aligned = NFT_PIPAPO_LT_ALIGN(x); \ - (field)->lt = (x); \ - } while (0) #else #define NFT_PIPAPO_ALIGN_HEADROOM 0 #define NFT_PIPAPO_LT_ALIGN(lt) (lt) -#define NFT_PIPAPO_LT_ASSIGN(field, x) ((field)->lt = (x)) #endif /* NFT_PIPAPO_ALIGN */ #define nft_pipapo_for_each_field(field, index, match) \ @@ -110,22 +104,18 @@ union nft_pipapo_map_bucket { /** * struct nft_pipapo_field - Lookup, mapping tables and related data for a field - * @groups: Amount of bit groups * @rules: Number of inserted rules * @bsize: Size of each bucket in lookup table, in longs + * @groups: Amount of bit groups * @bb: Number of bits grouped together in lookup table buckets * @lt: Lookup table: 'groups' rows of buckets - * @lt_aligned: Version of @lt aligned to NFT_PIPAPO_ALIGN bytes * @mt: Mapping table: one bucket per rule */ struct nft_pipapo_field { - int groups; - unsigned long rules; - size_t bsize; - int bb; -#ifdef NFT_PIPAPO_ALIGN - unsigned long *lt_aligned; -#endif + unsigned int rules; + unsigned int bsize; + u8 groups; + u8 bb; unsigned long *lt; union nft_pipapo_map_bucket *mt; }; @@ -145,15 +135,15 @@ struct nft_pipapo_scratch { /** * struct nft_pipapo_match - Data used for lookup and matching * @field_count: Amount of fields in set - * @scratch: Preallocated per-CPU maps for partial matching results * @bsize_max: Maximum lookup table bucket size of all fields, in longs + * @scratch: Preallocated per-CPU maps for partial matching results * @rcu: Matching data is swapped on commits * @f: Fields, with lookup and mapping tables */ struct nft_pipapo_match { - int field_count; + u8 field_count; + unsigned int bsize_max; struct nft_pipapo_scratch * __percpu *scratch; - size_t bsize_max; struct rcu_head rcu; struct nft_pipapo_field f[] __counted_by(field_count); }; @@ -186,7 +176,8 @@ struct nft_pipapo_elem { struct nft_set_ext ext; }; -int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst, +int pipapo_refill(unsigned long *map, unsigned int len, unsigned int rules, + unsigned long *dst, const union nft_pipapo_map_bucket *mt, bool match_only); /** From 9f439bd6ef4f60c8a37bd9138fa9ed9b5e7ae0d7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 13 Feb 2024 16:23:40 +0100 Subject: [PATCH 1344/2255] netfilter: nft_set_pipapo: speed up bulk element insertions Insertions into the set are slow when we try to add many elements. For 800k elements I get: time nft -f pipapo_800k real 19m34.849s user 0m2.390s sys 19m12.828s perf stats: --95.39%--nft_pipapo_insert |--76.60%--pipapo_insert | --76.37%--pipapo_resize | |--72.87%--memcpy_orig | |--1.88%--__free_pages_ok | | --0.89%--free_tail_page_prepare | --1.38%--kvmalloc_node .. --18.56%--pipapo_get.isra.0 |--13.91%--__bitmap_and |--3.01%--pipapo_refill |--0.81%--__kmalloc | --0.74%--__kmalloc_large_node | --0.66%--__alloc_pages .. --0.52%--memset_orig So lots of time is spent in copying exising elements to make space for the next one. Instead of allocating to the exact size of the new rule count, allocate extra slack to reduce alloc/copy/free overhead. After: time nft -f pipapo_800k real 1m54.110s user 0m2.515s sys 1m51.377s --80.46%--nft_pipapo_insert |--73.45%--pipapo_get.isra.0 |--57.63%--__bitmap_and | |--8.52%--pipapo_refill |--3.45%--__kmalloc | --3.05%--__kmalloc_large_node | --2.58%--__alloc_pages --2.59%--memset_orig |--6.51%--pipapo_insert --5.96%--pipapo_resize |--3.63%--memcpy_orig --2.13%--kvmalloc_node The new @rules_alloc fills a hole, so struct size doesn't go up. Also make it so rule removal doesn't shrink unless the free/extra space exceeds two pages. This should be safe as well: When a rule gets removed, the attempt to lower the allocated size is already allowed to fail. Exception: do exact allocations as long as set is very small (less than one page needed). v2: address comments from Stefano: kdoc comment formatting changes remove redundant assignment switch back to PAGE_SIZE Link: https://lore.kernel.org/netfilter-devel/20240213141753.17ef27a6@elisabeth/ Reviewed-by: Stefano Brivio Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 83 +++++++++++++++++++++++++++------- net/netfilter/nft_set_pipapo.h | 2 + 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index b63278b2017a..6118e4bba2ef 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -621,6 +621,65 @@ nft_pipapo_get(const struct net *net, const struct nft_set *set, return &e->priv; } +/** + * pipapo_realloc_mt() - Reallocate mapping table if needed upon resize + * @f: Field containing mapping table + * @old_rules: Amount of existing mapped rules + * @rules: Amount of new rules to map + * + * Return: 0 on success, negative error code on failure. + */ +static int pipapo_realloc_mt(struct nft_pipapo_field *f, + unsigned int old_rules, unsigned int rules) +{ + union nft_pipapo_map_bucket *new_mt = NULL, *old_mt = f->mt; + const unsigned int extra = PAGE_SIZE / sizeof(*new_mt); + unsigned int rules_alloc = rules; + + might_sleep(); + + if (unlikely(rules == 0)) + goto out_free; + + /* growing and enough space left, no action needed */ + if (rules > old_rules && f->rules_alloc > rules) + return 0; + + /* downsize and extra slack has not grown too large */ + if (rules < old_rules) { + unsigned int remove = f->rules_alloc - rules; + + if (remove < (2u * extra)) + return 0; + } + + /* If set needs more than one page of memory for rules then + * allocate another extra page to avoid frequent reallocation. + */ + if (rules > extra && + check_add_overflow(rules, extra, &rules_alloc)) + return -EOVERFLOW; + + new_mt = kvmalloc_array(rules_alloc, sizeof(*new_mt), GFP_KERNEL); + if (!new_mt) + return -ENOMEM; + + if (old_mt) + memcpy(new_mt, old_mt, min(old_rules, rules) * sizeof(*new_mt)); + + if (rules > old_rules) { + memset(new_mt + old_rules, 0, + (rules - old_rules) * sizeof(*new_mt)); + } +out_free: + f->rules_alloc = rules_alloc; + f->mt = new_mt; + + kvfree(old_mt); + + return 0; +} + /** * pipapo_resize() - Resize lookup or mapping table, or both * @f: Field containing lookup and mapping tables @@ -637,9 +696,8 @@ static int pipapo_resize(struct nft_pipapo_field *f, unsigned int old_rules, unsigned int rules) { long *new_lt = NULL, *new_p, *old_lt = f->lt, *old_p; - union nft_pipapo_map_bucket *new_mt, *old_mt = f->mt; unsigned int new_bucket_size, copy; - int group, bucket; + int group, bucket, err; if (rules >= NFT_PIPAPO_RULE0_MAX) return -ENOSPC; @@ -682,16 +740,10 @@ static int pipapo_resize(struct nft_pipapo_field *f, } mt: - new_mt = kvmalloc(rules * sizeof(*new_mt), GFP_KERNEL); - if (!new_mt) { + err = pipapo_realloc_mt(f, old_rules, rules); + if (err) { kvfree(new_lt); - return -ENOMEM; - } - - memcpy(new_mt, f->mt, min(old_rules, rules) * sizeof(*new_mt)); - if (rules > old_rules) { - memset(new_mt + old_rules, 0, - (rules - old_rules) * sizeof(*new_mt)); + return err; } if (new_lt) { @@ -700,9 +752,6 @@ mt: kvfree(old_lt); } - f->mt = new_mt; - kvfree(old_mt); - return 0; } @@ -1382,14 +1431,15 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) src->groups * NFT_PIPAPO_BUCKETS(src->bb)); if (src->rules > 0) { - dst->mt = kvmalloc_array(src->rules, sizeof(*src->mt), - GFP_KERNEL); + dst->mt = kvmalloc_array(src->rules_alloc, + sizeof(*src->mt), GFP_KERNEL); if (!dst->mt) goto out_mt; memcpy(dst->mt, src->mt, src->rules * sizeof(*src->mt)); } else { dst->mt = NULL; + dst->rules_alloc = 0; } src++; @@ -2205,6 +2255,7 @@ static int nft_pipapo_init(const struct nft_set *set, f->bsize = 0; f->rules = 0; + f->rules_alloc = 0; f->lt = NULL; f->mt = NULL; } diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h index ca64f7505e71..24cd1ff73f98 100644 --- a/net/netfilter/nft_set_pipapo.h +++ b/net/netfilter/nft_set_pipapo.h @@ -106,6 +106,7 @@ union nft_pipapo_map_bucket { * struct nft_pipapo_field - Lookup, mapping tables and related data for a field * @rules: Number of inserted rules * @bsize: Size of each bucket in lookup table, in longs + * @rules_alloc: Number of allocated rules, always >= rules * @groups: Amount of bit groups * @bb: Number of bits grouped together in lookup table buckets * @lt: Lookup table: 'groups' rows of buckets @@ -114,6 +115,7 @@ union nft_pipapo_map_bucket { struct nft_pipapo_field { unsigned int rules; unsigned int bsize; + unsigned int rules_alloc; u8 groups; u8 bb; unsigned long *lt; From 5b651783d80b97167ecd27dc6a4408c694873902 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 15 Feb 2024 09:29:30 +0100 Subject: [PATCH 1345/2255] netfilter: nft_set_pipapo: use GFP_KERNEL for insertions An earlier attempt changed this to GFP_KERNEL, but the get helper is also called for get requests from userspace, which uses rcu. Let the caller pass in the kmalloc flags to allow insertions to schedule if needed. Suggested-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 6118e4bba2ef..c0ceea068936 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -507,6 +507,7 @@ out: * @data: Key data to be matched against existing elements * @genmask: If set, check that element is active in given genmask * @tstamp: timestamp to check for expired elements + * @gfp: the type of memory to allocate (see kmalloc). * * This is essentially the same as the lookup function, except that it matches * key data against the uncommitted copy and doesn't use preallocated maps for @@ -517,7 +518,7 @@ out: static struct nft_pipapo_elem *pipapo_get(const struct net *net, const struct nft_set *set, const u8 *data, u8 genmask, - u64 tstamp) + u64 tstamp, gfp_t gfp) { struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT); struct nft_pipapo *priv = nft_set_priv(set); @@ -530,13 +531,13 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net, if (m->bsize_max == 0) return ret; - res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC); + res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), gfp); if (!res_map) { ret = ERR_PTR(-ENOMEM); goto out; } - fill_map = kcalloc(m->bsize_max, sizeof(*res_map), GFP_ATOMIC); + fill_map = kcalloc(m->bsize_max, sizeof(*res_map), gfp); if (!fill_map) { ret = ERR_PTR(-ENOMEM); goto out; @@ -614,7 +615,8 @@ nft_pipapo_get(const struct net *net, const struct nft_set *set, struct nft_pipapo_elem *e; e = pipapo_get(net, set, (const u8 *)elem->key.val.data, - nft_genmask_cur(net), get_jiffies_64()); + nft_genmask_cur(net), get_jiffies_64(), + GFP_ATOMIC); if (IS_ERR(e)) return ERR_CAST(e); @@ -1275,7 +1277,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, else end = start; - dup = pipapo_get(net, set, start, genmask, tstamp); + dup = pipapo_get(net, set, start, genmask, tstamp, GFP_KERNEL); if (!IS_ERR(dup)) { /* Check if we already have the same exact entry */ const struct nft_data *dup_key, *dup_end; @@ -1297,7 +1299,8 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, if (PTR_ERR(dup) == -ENOENT) { /* Look for partially overlapping entries */ - dup = pipapo_get(net, set, end, nft_genmask_next(net), tstamp); + dup = pipapo_get(net, set, end, nft_genmask_next(net), tstamp, + GFP_KERNEL); } if (PTR_ERR(dup) != -ENOENT) { @@ -1865,7 +1868,8 @@ static void *pipapo_deactivate(const struct net *net, const struct nft_set *set, { struct nft_pipapo_elem *e; - e = pipapo_get(net, set, data, nft_genmask_next(net), nft_net_tstamp(net)); + e = pipapo_get(net, set, data, nft_genmask_next(net), + nft_net_tstamp(net), GFP_KERNEL); if (IS_ERR(e)) return NULL; From 3f801968889459ecae1eab524b039676e6eaa319 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 14 Feb 2024 14:41:02 +0100 Subject: [PATCH 1346/2255] netfilter: move nf_reinject into nfnetlink_queue modules No need to keep this in the core, move it to the nfnetlink_queue module. nf_reroute is moved too, there were no other callers. Signed-off-by: Florian Westphal --- include/linux/netfilter.h | 1 - include/net/netfilter/nf_queue.h | 1 - net/netfilter/nf_queue.c | 106 ----------------------- net/netfilter/nfnetlink_queue.c | 142 +++++++++++++++++++++++++++++++ net/netfilter/utils.c | 37 -------- 5 files changed, 142 insertions(+), 145 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 80900d910992..ffb5e0297eb5 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -370,7 +370,6 @@ __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook, u_int8_t protocol, unsigned short family); int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl, bool strict, unsigned short family); -int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry); #include diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index c81021ab07aa..4aeffddb7586 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -35,7 +35,6 @@ struct nf_queue_handler { void nf_register_queue_handler(const struct nf_queue_handler *qh); void nf_unregister_queue_handler(void); -void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); bool nf_queue_entry_get_refs(struct nf_queue_entry *entry); void nf_queue_entry_free(struct nf_queue_entry *entry); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index e2f334f70281..7f12e56e6e52 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -248,109 +248,3 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state, return 0; } EXPORT_SYMBOL_GPL(nf_queue); - -static unsigned int nf_iterate(struct sk_buff *skb, - struct nf_hook_state *state, - const struct nf_hook_entries *hooks, - unsigned int *index) -{ - const struct nf_hook_entry *hook; - unsigned int verdict, i = *index; - - while (i < hooks->num_hook_entries) { - hook = &hooks->hooks[i]; -repeat: - verdict = nf_hook_entry_hookfn(hook, skb, state); - if (verdict != NF_ACCEPT) { - *index = i; - if (verdict != NF_REPEAT) - return verdict; - goto repeat; - } - i++; - } - - *index = i; - return NF_ACCEPT; -} - -static struct nf_hook_entries *nf_hook_entries_head(const struct net *net, u8 pf, u8 hooknum) -{ - switch (pf) { -#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE - case NFPROTO_BRIDGE: - return rcu_dereference(net->nf.hooks_bridge[hooknum]); -#endif - case NFPROTO_IPV4: - return rcu_dereference(net->nf.hooks_ipv4[hooknum]); - case NFPROTO_IPV6: - return rcu_dereference(net->nf.hooks_ipv6[hooknum]); - default: - WARN_ON_ONCE(1); - return NULL; - } - - return NULL; -} - -/* Caller must hold rcu read-side lock */ -void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) -{ - const struct nf_hook_entry *hook_entry; - const struct nf_hook_entries *hooks; - struct sk_buff *skb = entry->skb; - const struct net *net; - unsigned int i; - int err; - u8 pf; - - net = entry->state.net; - pf = entry->state.pf; - - hooks = nf_hook_entries_head(net, pf, entry->state.hook); - - i = entry->hook_index; - if (WARN_ON_ONCE(!hooks || i >= hooks->num_hook_entries)) { - kfree_skb(skb); - nf_queue_entry_free(entry); - return; - } - - hook_entry = &hooks->hooks[i]; - - /* Continue traversal iff userspace said ok... */ - if (verdict == NF_REPEAT) - verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state); - - if (verdict == NF_ACCEPT) { - if (nf_reroute(skb, entry) < 0) - verdict = NF_DROP; - } - - if (verdict == NF_ACCEPT) { -next_hook: - ++i; - verdict = nf_iterate(skb, &entry->state, hooks, &i); - } - - switch (verdict & NF_VERDICT_MASK) { - case NF_ACCEPT: - case NF_STOP: - local_bh_disable(); - entry->state.okfn(entry->state.net, entry->state.sk, skb); - local_bh_enable(); - break; - case NF_QUEUE: - err = nf_queue(skb, &entry->state, i, verdict); - if (err == 1) - goto next_hook; - break; - case NF_STOLEN: - break; - default: - kfree_skb(skb); - } - - nf_queue_entry_free(entry); -} -EXPORT_SYMBOL(nf_reinject); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 5cf38fc0a366..00f4bd21c59b 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -225,6 +225,148 @@ find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) return entry; } +static unsigned int nf_iterate(struct sk_buff *skb, + struct nf_hook_state *state, + const struct nf_hook_entries *hooks, + unsigned int *index) +{ + const struct nf_hook_entry *hook; + unsigned int verdict, i = *index; + + while (i < hooks->num_hook_entries) { + hook = &hooks->hooks[i]; +repeat: + verdict = nf_hook_entry_hookfn(hook, skb, state); + if (verdict != NF_ACCEPT) { + *index = i; + if (verdict != NF_REPEAT) + return verdict; + goto repeat; + } + i++; + } + + *index = i; + return NF_ACCEPT; +} + +static struct nf_hook_entries *nf_hook_entries_head(const struct net *net, u8 pf, u8 hooknum) +{ + switch (pf) { +#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE + case NFPROTO_BRIDGE: + return rcu_dereference(net->nf.hooks_bridge[hooknum]); +#endif + case NFPROTO_IPV4: + return rcu_dereference(net->nf.hooks_ipv4[hooknum]); + case NFPROTO_IPV6: + return rcu_dereference(net->nf.hooks_ipv6[hooknum]); + default: + WARN_ON_ONCE(1); + return NULL; + } + + return NULL; +} + +static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry) +{ +#ifdef CONFIG_INET + const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); + + if (entry->state.hook == NF_INET_LOCAL_OUT) { + const struct iphdr *iph = ip_hdr(skb); + + if (!(iph->tos == rt_info->tos && + skb->mark == rt_info->mark && + iph->daddr == rt_info->daddr && + iph->saddr == rt_info->saddr)) + return ip_route_me_harder(entry->state.net, entry->state.sk, + skb, RTN_UNSPEC); + } +#endif + return 0; +} + +static int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry) +{ + const struct nf_ipv6_ops *v6ops; + int ret = 0; + + switch (entry->state.pf) { + case AF_INET: + ret = nf_ip_reroute(skb, entry); + break; + case AF_INET6: + v6ops = rcu_dereference(nf_ipv6_ops); + if (v6ops) + ret = v6ops->reroute(skb, entry); + break; + } + return ret; +} + +/* caller must hold rcu read-side lock */ +static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) +{ + const struct nf_hook_entry *hook_entry; + const struct nf_hook_entries *hooks; + struct sk_buff *skb = entry->skb; + const struct net *net; + unsigned int i; + int err; + u8 pf; + + net = entry->state.net; + pf = entry->state.pf; + + hooks = nf_hook_entries_head(net, pf, entry->state.hook); + + i = entry->hook_index; + if (WARN_ON_ONCE(!hooks || i >= hooks->num_hook_entries)) { + kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP); + nf_queue_entry_free(entry); + return; + } + + hook_entry = &hooks->hooks[i]; + + /* Continue traversal iff userspace said ok... */ + if (verdict == NF_REPEAT) + verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state); + + if (verdict == NF_ACCEPT) { + if (nf_reroute(skb, entry) < 0) + verdict = NF_DROP; + } + + if (verdict == NF_ACCEPT) { +next_hook: + ++i; + verdict = nf_iterate(skb, &entry->state, hooks, &i); + } + + switch (verdict & NF_VERDICT_MASK) { + case NF_ACCEPT: + case NF_STOP: + local_bh_disable(); + entry->state.okfn(entry->state.net, entry->state.sk, skb); + local_bh_enable(); + break; + case NF_QUEUE: + err = nf_queue(skb, &entry->state, i, verdict); + if (err == 1) + goto next_hook; + break; + case NF_STOLEN: + break; + default: + kfree_skb(skb); + } + + nf_queue_entry_free(entry); +} + static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) { const struct nf_ct_hook *ct_hook; diff --git a/net/netfilter/utils.c b/net/netfilter/utils.c index acef4155f0da..008419db815a 100644 --- a/net/netfilter/utils.c +++ b/net/netfilter/utils.c @@ -179,43 +179,6 @@ int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl, } EXPORT_SYMBOL_GPL(nf_route); -static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry) -{ -#ifdef CONFIG_INET - const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); - - if (entry->state.hook == NF_INET_LOCAL_OUT) { - const struct iphdr *iph = ip_hdr(skb); - - if (!(iph->tos == rt_info->tos && - skb->mark == rt_info->mark && - iph->daddr == rt_info->daddr && - iph->saddr == rt_info->saddr)) - return ip_route_me_harder(entry->state.net, entry->state.sk, - skb, RTN_UNSPEC); - } -#endif - return 0; -} - -int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry) -{ - const struct nf_ipv6_ops *v6ops; - int ret = 0; - - switch (entry->state.pf) { - case AF_INET: - ret = nf_ip_reroute(skb, entry); - break; - case AF_INET6: - v6ops = rcu_dereference(nf_ipv6_ops); - if (v6ops) - ret = v6ops->reroute(skb, entry); - break; - } - return ret; -} - /* Only get and check the lengths, not do any hop-by-hop stuff. */ int nf_ip6_check_hbh_len(struct sk_buff *skb, u32 *plen) { From 26f4dac11775a1ca24e2605cb30e828d4dbdea93 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Feb 2024 15:31:32 -0800 Subject: [PATCH 1347/2255] netfilter: x_tables: Use unsafe_memcpy() for 0-sized destination The struct xt_entry_target fake flexible array has not be converted to a true flexible array, which is mainly blocked by it being both UAPI and used in the middle of other structures. In order to properly check for 0-sized destinations in memcpy(), an exception must be made for the one place where it is still a destination. Since memcpy() was already skipping checks for 0-sized destinations, using unsafe_memcpy() is no change in behavior. Signed-off-by: Kees Cook Reviewed-by: Simon Horman Signed-off-by: Florian Westphal --- net/netfilter/x_tables.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 21624d68314f..da5d929c7c85 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1142,7 +1142,8 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, if (target->compat_from_user) target->compat_from_user(t->data, ct->data); else - memcpy(t->data, ct->data, tsize - sizeof(*ct)); + unsafe_memcpy(t->data, ct->data, tsize - sizeof(*ct), + /* UAPI 0-sized destination */); tsize += off; t->u.user.target_size = tsize; From 8306ee08c0ff1c78672bcc645544f26f4d652cca Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 18 Feb 2024 15:49:55 +0100 Subject: [PATCH 1348/2255] tg3: copy only needed fields from userspace-provided EEE data The current code overwrites fields in tp->eee with unchecked data from edata, e.g. the bitmap with supported modes. ethtool properly returns the received data from get_eee() call, but we have no guarantee that other users of the ioctl set_eee() interface behave properly too. Therefore copy only fields which are actually needed. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 7d0a2f5f3282..ed93149f3b67 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -14200,7 +14200,9 @@ static int tg3_set_eee(struct net_device *dev, struct ethtool_keee *edata) return -EINVAL; } - tp->eee = *edata; + tp->eee.eee_enabled = edata->eee_enabled; + tp->eee.tx_lpi_enabled = edata->tx_lpi_enabled; + tp->eee.tx_lpi_timer = edata->tx_lpi_timer; tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED; tg3_warn_mgmt_link_flap(tp); From ebb0346a117f96fe732791289628964276d51b7d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 18 Feb 2024 19:04:42 +0100 Subject: [PATCH 1349/2255] tg3: simplify tg3_phy_autoneg_cfg Make use of ethtool_adv_to_mmd_eee_adv_t() to simplify the code. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Reviewed-by: Kalesh AP Reviewed-by: Andrew Lunn Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index ed93149f3b67..eee759054aad 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -4354,21 +4354,12 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) if (!err) { u32 err2; - val = 0; - /* Advertise 100-BaseTX EEE ability */ - if (advertise & ADVERTISED_100baseT_Full) - val |= MDIO_AN_EEE_ADV_100TX; - /* Advertise 1000-BaseT EEE ability */ - if (advertise & ADVERTISED_1000baseT_Full) - val |= MDIO_AN_EEE_ADV_1000T; - - if (!tp->eee.eee_enabled) { + if (!tp->eee.eee_enabled) val = 0; - linkmode_zero(tp->eee.advertised); - } else { - mii_eee_cap1_mod_linkmode_t(tp->eee.advertised, val); - } + else + val = ethtool_adv_to_mmd_eee_adv_t(advertise); + mii_eee_cap1_mod_linkmode_t(tp->eee.advertised, val); err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); if (err) val = 0; From a381690dd84283d7a4f849649d692bdf3b8f424d Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 19 Feb 2024 05:43:28 -0800 Subject: [PATCH 1350/2255] net/dummy: Move stats allocation to core With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Move dummy driver to leverage the core allocation. Suggested-by: Jakub Kicinski Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/dummy.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 946bba0701a4..d29b5d7af0d7 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -67,19 +67,12 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) static int dummy_dev_init(struct net_device *dev) { - dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); - if (!dev->lstats) - return -ENOMEM; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_LSTATS; netdev_lockdep_set_classes(dev); return 0; } -static void dummy_dev_uninit(struct net_device *dev) -{ - free_percpu(dev->lstats); -} - static int dummy_change_carrier(struct net_device *dev, bool new_carrier) { if (new_carrier) @@ -91,7 +84,6 @@ static int dummy_change_carrier(struct net_device *dev, bool new_carrier) static const struct net_device_ops dummy_netdev_ops = { .ndo_init = dummy_dev_init, - .ndo_uninit = dummy_dev_uninit, .ndo_start_xmit = dummy_xmit, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = set_multicast_list, From 5073d64e99dfc7dbd2dcf022ddcc5510cba95349 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 20 Feb 2024 15:36:42 +0800 Subject: [PATCH 1351/2255] net: kcm: Simplify the allocation of slab caches Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. And change cache name from 'kcm_mux_cache' to 'kcm_mux', 'kcm_psock_cache' to 'kcm_psock'. Signed-off-by: Kunwu Chan Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- net/kcm/kcmsock.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 73c200c5c8e4..dc46f17a3187 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1878,15 +1878,11 @@ static int __init kcm_init(void) { int err = -ENOMEM; - kcm_muxp = kmem_cache_create("kcm_mux_cache", - sizeof(struct kcm_mux), 0, - SLAB_HWCACHE_ALIGN, NULL); + kcm_muxp = KMEM_CACHE(kcm_mux, SLAB_HWCACHE_ALIGN); if (!kcm_muxp) goto fail; - kcm_psockp = kmem_cache_create("kcm_psock_cache", - sizeof(struct kcm_psock), 0, - SLAB_HWCACHE_ALIGN, NULL); + kcm_psockp = KMEM_CACHE(kcm_psock, SLAB_HWCACHE_ALIGN); if (!kcm_psockp) goto fail; From 11a548f252c4a754026d4a46e1d91ffe6c88d051 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 20 Feb 2024 15:36:43 +0800 Subject: [PATCH 1352/2255] ip6mr: Simplify the allocation of slab caches in ip6_mr_init Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. And change cache name from 'ip6_mrt_cache' to 'mfc6_cache'. Signed-off-by: Kunwu Chan Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- net/ipv6/ip6mr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 9782c180fee6..1f19743f2540 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1373,10 +1373,7 @@ int __init ip6_mr_init(void) { int err; - mrt_cachep = kmem_cache_create("ip6_mrt_cache", - sizeof(struct mfc6_cache), - 0, SLAB_HWCACHE_ALIGN, - NULL); + mrt_cachep = KMEM_CACHE(mfc6_cache, SLAB_HWCACHE_ALIGN); if (!mrt_cachep) return -ENOMEM; From eec70af2b41cf5311f5bea5b22f24958f642c72a Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 20 Feb 2024 15:36:44 +0800 Subject: [PATCH 1353/2255] ipmr: Simplify the allocation of slab caches Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. And change cache name from 'ip_mrt_cache' to 'mfc_cache'. Signed-off-by: Kunwu Chan Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 362229836510..5561bce3a37e 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -3139,10 +3139,7 @@ int __init ip_mr_init(void) { int err; - mrt_cachep = kmem_cache_create("ip_mrt_cache", - sizeof(struct mfc_cache), - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, - NULL); + mrt_cachep = KMEM_CACHE(mfc_cache, SLAB_HWCACHE_ALIGN | SLAB_PANIC); err = register_pernet_subsys(&ipmr_net_ops); if (err) From 7eb2bc2481a1162ceacdbacd2089736558a08f8d Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 20 Feb 2024 15:36:45 +0800 Subject: [PATCH 1354/2255] ipv4: Simplify the allocation of slab caches in ip_rt_init Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. And change cache name from 'ip_dst_cache' to 'rtable'. Signed-off-by: Kunwu Chan Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- net/ipv4/route.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 16615d107cf0..b512288d6fcc 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3693,9 +3693,8 @@ int __init ip_rt_init(void) panic("IP: failed to allocate ip_rt_acct\n"); #endif - ipv4_dst_ops.kmem_cachep = - kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + ipv4_dst_ops.kmem_cachep = KMEM_CACHE(rtable, + SLAB_HWCACHE_ALIGN | SLAB_PANIC); ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep; From 072f88ca5ca4ef8655721341195028844165b2f1 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 20 Feb 2024 15:36:46 +0800 Subject: [PATCH 1355/2255] ipv6: Simplify the allocation of slab caches Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Signed-off-by: Kunwu Chan Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 805bbf26b3ef..6540d877d369 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -2493,10 +2493,8 @@ int __init fib6_init(void) { int ret = -ENOMEM; - fib6_node_kmem = kmem_cache_create("fib6_nodes", - sizeof(struct fib6_node), 0, - SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT, - NULL); + fib6_node_kmem = KMEM_CACHE(fib6_node, + SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT); if (!fib6_node_kmem) goto out; From 78b88ef392c1ccc189c74cf73c179cf59d23a258 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 19 Feb 2024 17:45:48 +0000 Subject: [PATCH 1356/2255] net: wan: framer: remove children from struct framer_ops kdoc Remove documentation of non-existent children field from the Kernel doc for struct framer_ops. Introduced by 82c944d05b1a ("net: wan: Add framer framework support") Signed-off-by: Simon Horman Acked-by: Herve Codina Signed-off-by: David S. Miller --- include/linux/framer/framer-provider.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/framer/framer-provider.h b/include/linux/framer/framer-provider.h index f6fd2dd92591..9724d4b44b9c 100644 --- a/include/linux/framer/framer-provider.h +++ b/include/linux/framer/framer-provider.h @@ -83,7 +83,6 @@ struct framer_ops { /** * struct framer_provider - represents the framer provider * @dev: framer provider device - * @children: can be used to override the default (dev->of_node) child node * @owner: the module owner having of_xlate * @list: to maintain a linked list of framer providers * @of_xlate: function pointer to obtain framer instance from framer pointer From ee975351cf0c2a11cdf97eae58265c126cb32850 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 19 Feb 2024 12:40:51 -0800 Subject: [PATCH 1357/2255] net: mdio: mdio-bcm-unimac: Manage clock around I/O accesses Up until now we have managed not to have the mdio-bcm-unimac manage its clock except during probe and suspend/resume. This works most of the time, except where it does not. With a fully modular build, we can get into a situation whereby the GENET driver is fully registered, and so is the mdio-bcm-unimac driver, however the Ethernet PHY driver is not yet, because it depends on a resource that is not yet available (e.g.: GPIO provider). In that state, the network device is not usable yet, and so to conserve power, the GENET driver will have turned off its "main" clock which feeds its MDIO controller. When the PHY driver finally probes however, we make an access to the PHY registers to e.g.: disable interrupts, and this causes a bus error within the MDIO controller space because the MDIO controller clock(s) are turned off. To remedy that, we manage the clock around all of the I/O accesses to the hardware which are done exclusively during read, write and clock divider configuration. This ensures that the register space is accessible, and this also ensures that there are not unnecessarily elevated reference counts keeping the clocks active when the network device is administratively turned off. It would be the case with the previous way of managing the clock. Reviewed-by: Jacob Keller Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/mdio/mdio-bcm-unimac.c | 93 ++++++++++--------- include/linux/platform_data/mdio-bcm-unimac.h | 3 + 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c index 68f8ee0ec8ba..6fe08427fdd4 100644 --- a/drivers/net/mdio/mdio-bcm-unimac.c +++ b/drivers/net/mdio/mdio-bcm-unimac.c @@ -94,6 +94,10 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg) int ret; u32 cmd; + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + /* Prepare the read operation */ cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT); unimac_mdio_writel(priv, cmd, MDIO_CMD); @@ -103,7 +107,7 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg) ret = priv->wait_func(priv->wait_func_data); if (ret) - return ret; + goto out; cmd = unimac_mdio_readl(priv, MDIO_CMD); @@ -112,10 +116,15 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg) * that condition here and ignore the MDIO controller read failure * indication. */ - if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL)) - return -EIO; + if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL)) { + ret = -EIO; + goto out; + } - return cmd & 0xffff; + ret = cmd & 0xffff; +out: + clk_disable_unprepare(priv->clk); + return ret; } static int unimac_mdio_write(struct mii_bus *bus, int phy_id, @@ -123,6 +132,11 @@ static int unimac_mdio_write(struct mii_bus *bus, int phy_id, { struct unimac_mdio_priv *priv = bus->priv; u32 cmd; + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; /* Prepare the write operation */ cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) | @@ -131,7 +145,10 @@ static int unimac_mdio_write(struct mii_bus *bus, int phy_id, unimac_mdio_start(priv); - return priv->wait_func(priv->wait_func_data); + ret = priv->wait_func(priv->wait_func_data); + clk_disable_unprepare(priv->clk); + + return ret; } /* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with @@ -178,14 +195,19 @@ static int unimac_mdio_reset(struct mii_bus *bus) return 0; } -static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv) +static int unimac_mdio_clk_set(struct unimac_mdio_priv *priv) { unsigned long rate; u32 reg, div; + int ret; /* Keep the hardware default values */ if (!priv->clk_freq) - return; + return 0; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; if (!priv->clk) rate = 250000000; @@ -195,7 +217,8 @@ static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv) div = (rate / (2 * priv->clk_freq)) - 1; if (div & ~MDIO_CLK_DIV_MASK) { pr_warn("Incorrect MDIO clock frequency, ignoring\n"); - return; + ret = 0; + goto out; } /* The MDIO clock is the reference clock (typically 250Mhz) divided by @@ -205,6 +228,9 @@ static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv) reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT); reg |= div << MDIO_CLK_DIV_SHIFT; unimac_mdio_writel(priv, reg, MDIO_CFG); +out: + clk_disable_unprepare(priv->clk); + return ret; } static int unimac_mdio_probe(struct platform_device *pdev) @@ -235,24 +261,12 @@ static int unimac_mdio_probe(struct platform_device *pdev) return -ENOMEM; } - priv->clk = devm_clk_get_optional(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq)) priv->clk_freq = 0; - unimac_mdio_clk_set(priv); - priv->mii_bus = mdiobus_alloc(); - if (!priv->mii_bus) { - ret = -ENOMEM; - goto out_clk_disable; - } + if (!priv->mii_bus) + return -ENOMEM; bus = priv->mii_bus; bus->priv = priv; @@ -261,17 +275,29 @@ static int unimac_mdio_probe(struct platform_device *pdev) priv->wait_func = pdata->wait_func; priv->wait_func_data = pdata->wait_func_data; bus->phy_mask = ~pdata->phy_mask; + priv->clk = pdata->clk; } else { bus->name = "unimac MII bus"; priv->wait_func_data = priv; priv->wait_func = unimac_mdio_poll; + priv->clk = devm_clk_get_optional(&pdev->dev, NULL); } + + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + goto out_mdio_free; + } + bus->parent = &pdev->dev; bus->read = unimac_mdio_read; bus->write = unimac_mdio_write; bus->reset = unimac_mdio_reset; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); + ret = unimac_mdio_clk_set(priv); + if (ret) + goto out_mdio_free; + ret = of_mdiobus_register(bus, np); if (ret) { dev_err(&pdev->dev, "MDIO bus registration failed\n"); @@ -286,8 +312,6 @@ static int unimac_mdio_probe(struct platform_device *pdev) out_mdio_free: mdiobus_free(bus); -out_clk_disable: - clk_disable_unprepare(priv->clk); return ret; } @@ -297,34 +321,17 @@ static void unimac_mdio_remove(struct platform_device *pdev) mdiobus_unregister(priv->mii_bus); mdiobus_free(priv->mii_bus); - clk_disable_unprepare(priv->clk); -} - -static int __maybe_unused unimac_mdio_suspend(struct device *d) -{ - struct unimac_mdio_priv *priv = dev_get_drvdata(d); - - clk_disable_unprepare(priv->clk); - - return 0; } static int __maybe_unused unimac_mdio_resume(struct device *d) { struct unimac_mdio_priv *priv = dev_get_drvdata(d); - int ret; - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - - unimac_mdio_clk_set(priv); - - return 0; + return unimac_mdio_clk_set(priv); } static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops, - unimac_mdio_suspend, unimac_mdio_resume); + NULL, unimac_mdio_resume); static const struct of_device_id unimac_mdio_ids[] = { { .compatible = "brcm,asp-v2.1-mdio", }, diff --git a/include/linux/platform_data/mdio-bcm-unimac.h b/include/linux/platform_data/mdio-bcm-unimac.h index 8a5f9f0b2c52..724e1f57b81f 100644 --- a/include/linux/platform_data/mdio-bcm-unimac.h +++ b/include/linux/platform_data/mdio-bcm-unimac.h @@ -1,11 +1,14 @@ #ifndef __MDIO_BCM_UNIMAC_PDATA_H #define __MDIO_BCM_UNIMAC_PDATA_H +struct clk; + struct unimac_mdio_pdata { u32 phy_mask; int (*wait_func)(void *data); void *wait_func_data; const char *bus_name; + struct clk *clk; }; #define UNIMAC_MDIO_DRV_NAME "unimac-mdio" From ee2b4cf8b281606bbf332cbd73ce2a73eac417f0 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 19 Feb 2024 12:40:52 -0800 Subject: [PATCH 1358/2255] net: bcmgenet: Pass "main" clock down to the MDIO driver GENET has historically had to create a MDIO platform device for its controller and pass some auxiliary data to it, like a MDIO completion callback. Now we also pass the "main" clock to allow for the MDIO bus controller to manage that clock adequately around I/O accesses. Reviewed-by: Jacob Keller Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index cbbe004621bc..7a21950da77c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -476,6 +476,10 @@ static int bcmgenet_mii_register(struct bcmgenet_priv *priv) ppd.wait_func = bcmgenet_mii_wait; ppd.wait_func_data = priv; ppd.bus_name = "bcmgenet MII bus"; + /* Pass a reference to our "main" clock which is used for MDIO + * transfers + */ + ppd.clk = priv->clk; /* Unimac MDIO bus controller starts at UniMAC offset + MDIO_CMD * and is 2 * 32-bits word long, 8 bytes total. From ba0b78371c46b2104197ff2c244f13f011ddfa80 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 19 Feb 2024 12:40:53 -0800 Subject: [PATCH 1359/2255] Revert "net: bcmgenet: Ensure MDIO unregistration has clocks enabled" This reverts commit 1b5ea7ffb7a3bdfffb4b7f40ce0d20a3372ee405 ("net: bcmgenet: Ensure MDIO unregistration has clocks enabled"). This is no longer necessary now that the MDIO bus controller has a clock that it can manage around the I/O accesses. Reviewed-by: Jacob Keller Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 7a21950da77c..9ada89355747 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -678,7 +678,5 @@ void bcmgenet_mii_exit(struct net_device *dev) if (of_phy_is_fixed_link(dn)) of_phy_deregister_fixed_link(dn); of_node_put(priv->phy_dn); - clk_prepare_enable(priv->clk); platform_device_unregister(priv->mii_pdev); - clk_disable_unprepare(priv->clk); } From 6030b3a469f8936d7f0f928e788f12a4fe14a4ca Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 16 Feb 2024 20:16:20 +0530 Subject: [PATCH 1360/2255] wifi: mac80211: check beacon countdown is complete on per link basis Currently, function to check if beacon countdown is complete uses deflink to fetch the beacon and check the counter. However, with MLO, there is a need to check 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. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240216144621.514385-2-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/mac.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 | 2 +- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 2 +- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++-- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- include/net/mac80211.h | 4 +++- net/mac80211/tx.c | 14 ++++++++++++-- 12 files changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 41053219ee95..e322b528baaf 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2034,7 +2034,7 @@ static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif) if (!arvif->is_up) return; - if (!ieee80211_beacon_cntdwn_is_complete(vif)) { + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) { ieee80211_beacon_update_cntdwn(vif, 0); ret = ath10k_mac_setup_bcn_tmpl(arvif); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ddf15717d504..2e9661f4bea8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3884,7 +3884,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) * actual channel switch is done */ if (arvif->vif->bss_conf.csa_active && - ieee80211_beacon_cntdwn_is_complete(arvif->vif)) { + ieee80211_beacon_cntdwn_is_complete(arvif->vif, 0)) { ieee80211_csa_finish(arvif->vif, 0); continue; } diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f7cab50bdfd1..a1e2729582e8 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1577,7 +1577,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) return; if (vif->bss_conf.color_change_active && - ieee80211_beacon_cntdwn_is_complete(vif)) { + ieee80211_beacon_cntdwn_is_complete(vif, 0)) { arvif->bcca_zero_sent = true; ieee80211_color_change_finish(vif); return; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 4e48407138b2..b399a7926ef5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -365,7 +365,7 @@ bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) if (!vif || !vif->bss_conf.csa_active) return false; - if (!ieee80211_beacon_cntdwn_is_complete(vif)) + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) return false; ieee80211_csa_finish(vif, 0); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8179d35dc310..547634f82183 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -514,7 +514,7 @@ bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) if (!vif || !vif->bss_conf.csa_active) return false; - if (!ieee80211_beacon_cntdwn_is_complete(vif)) + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) return false; ieee80211_csa_finish(vif, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index cc592e288188..123fe9bba982 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1466,7 +1466,7 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, mvmvif->csa_countdown = true; - if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) { + if (!ieee80211_beacon_cntdwn_is_complete(csa_vif, 0)) { int c = ieee80211_beacon_update_cntdwn(csa_vif, 0); iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 89b1c7a87660..a59d264a11c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -156,7 +156,7 @@ static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm) * So we just do nothing here and the switch * will be performed on the last TBTT. */ - if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) { + if (!ieee80211_beacon_cntdwn_is_complete(csa_vif, 0)) { IWL_WARN(mvm, "CSA NOA started too early\n"); goto out_unlock; } diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 8bf82755ca4c..758e380fdf1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1613,7 +1613,7 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power); 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)) + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0)) ieee80211_csa_finish(vif, 0); } @@ -1638,7 +1638,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!vif->bss_conf.csa_active) return; - dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); + dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0); } void mt76_csa_check(struct mt76_dev *dev) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 66bf92c164c3..db5041d23938 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5739,7 +5739,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)) { + if (ieee80211_beacon_cntdwn_is_complete(vif, 0)) { ieee80211_csa_finish(vif, 0); return; } diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 0554946ed30e..2ea11a86d920 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2305,7 +2305,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, rcu_dereference(link_conf->chanctx_conf)->def.chan); } - if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif, link_id)) ieee80211_csa_finish(vif, link_id); } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fc223761e3af..25c892ea9eb3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5566,10 +5566,12 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id); /** * ieee80211_beacon_cntdwn_is_complete - find out if countdown reached 1 * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: valid link_id during MLO or 0 for non-MLO * * This function returns whether the countdown reached zero. */ -bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif); +bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif, + unsigned int link_id); /** * ieee80211_color_change_finish - notify mac80211 about color change diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f4be4af568be..6bf223e6cd1a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5095,9 +5095,11 @@ unlock: } EXPORT_SYMBOL(ieee80211_beacon_set_cntdwn); -bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif) +bool ieee80211_beacon_cntdwn_is_complete(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 *beacon_data; size_t beacon_data_len; @@ -5106,9 +5108,17 @@ bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif) if (!ieee80211_sdata_running(sdata)) return false; + 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 out; + if (vif->type == NL80211_IFTYPE_AP) { - beacon = rcu_dereference(sdata->deflink.u.ap.beacon); + beacon = rcu_dereference(link->u.ap.beacon); if (WARN_ON(!beacon || !beacon->tail)) goto out; beacon_data = beacon->tail; From 7f501452364e2c1e38a819bcc96bdfdf59d2bbda Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 16 Feb 2024 20:16:21 +0530 Subject: [PATCH 1361/2255] wifi: mac80211_hwsim: add support for switch_vif_chanctx callback Currently switch_vif_chanctx mac80211 callback is not supported for MLO. Add it. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240216144621.514385-3-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 2ea11a86d920..b55fe320633c 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -3215,6 +3215,47 @@ static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, } } +static int mac80211_hwsim_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + int i; + + if (n_vifs <= 0) + return -EINVAL; + + wiphy_dbg(hw->wiphy, + "switch vif channel context mode: %u\n", mode); + + for (i = 0; i < n_vifs; i++) { + hwsim_check_chanctx_magic(vifs[i].old_ctx); + wiphy_dbg(hw->wiphy, + "switch vif channel context: %d MHz/width: %d/cfreqs:%d/%d MHz -> %d MHz/width: %d/cfreqs:%d/%d MHz\n", + vifs[i].old_ctx->def.chan->center_freq, + vifs[i].old_ctx->def.width, + vifs[i].old_ctx->def.center_freq1, + vifs[i].old_ctx->def.center_freq2, + vifs[i].new_ctx->def.chan->center_freq, + vifs[i].new_ctx->def.width, + vifs[i].new_ctx->def.center_freq1, + vifs[i].new_ctx->def.center_freq2); + + switch (mode) { + case CHANCTX_SWMODE_REASSIGN_VIF: + hwsim_check_chanctx_magic(vifs[i].new_ctx); + break; + case CHANCTX_SWMODE_SWAP_CONTEXTS: + hwsim_set_chanctx_magic(vifs[i].new_ctx); + hwsim_clear_chanctx_magic(vifs[i].old_ctx); + break; + default: + WARN_ON("Invalid mode"); + } + } + return 0; +} + static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_pkts_nic", "tx_bytes_nic", @@ -3940,7 +3981,8 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { .remove_chanctx = mac80211_hwsim_remove_chanctx, \ .change_chanctx = mac80211_hwsim_change_chanctx, \ .assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,\ - .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, + .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, \ + .switch_vif_chanctx = mac80211_hwsim_switch_vif_chanctx, static const struct ieee80211_ops mac80211_hwsim_mchan_ops = { HWSIM_COMMON_OPS From d73fbaf24c5a1e0698a7a5e17d66a5100efef72a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 6 Feb 2024 16:54:06 +0200 Subject: [PATCH 1362/2255] wifi: mac80211: make associated BSS pointer visible to the driver Some drivers need the data in it, so move it to the link conf, which is exposed to the driver. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206164849.6fe9782b87b4.Ifbffef638f07ca7f5c2b27f40d2cf2942d21de0b@changeid [remove bss pointer from internal struct, update docs] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 +++++ net/mac80211/ieee80211_i.h | 2 -- net/mac80211/mlme.c | 18 +++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 25c892ea9eb3..56c6ecb2c10a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -557,6 +557,10 @@ struct ieee80211_fils_discovery { * to that BSS) that can change during the lifetime of the BSS. * * @vif: reference to owning VIF + * @bss: the cfg80211 bss descriptor. Valid only for a station, and only + * when associated. Note: This contains information which is not + * necessarily authenticated. For example, information coming from probe + * responses. * @addr: (link) address used locally * @link_id: link ID, or 0 for non-MLO * @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE @@ -700,6 +704,7 @@ struct ieee80211_fils_discovery { */ struct ieee80211_bss_conf { struct ieee80211_vif *vif; + struct cfg80211_bss *bss; const u8 *bssid; unsigned int link_id; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f3edb1a148a7..4bec625a84d1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1006,8 +1006,6 @@ struct ieee80211_link_data_managed { int mu_edca_last_param_set; u8 bss_param_ch_cnt; - - struct cfg80211_bss *bss; }; struct ieee80211_link_data_ap { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e1554666d706..87ffc19770b8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2015,7 +2015,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct cfg80211_bss *cbss = link->u.mgd.bss; + struct cfg80211_bss *cbss = link->conf->bss; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; enum nl80211_band current_band; @@ -2928,7 +2928,7 @@ static u64 ieee80211_link_set_associated(struct ieee80211_link_data *link, ieee80211_check_rate_mask(link); - link->u.mgd.bss = cbss; + link->conf->bss = cbss; memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN); if (sdata->vif.p2p || @@ -3076,7 +3076,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->associated = false; /* other links will be destroyed */ - sdata->deflink.u.mgd.bss = NULL; + sdata->deflink.conf->bss = NULL; sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; netif_carrier_off(sdata->dev); @@ -3406,7 +3406,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_mlme_send_probe_req(sdata, sdata->vif.addr, dst, sdata->vif.cfg.ssid, sdata->vif.cfg.ssid_len, - sdata->deflink.u.mgd.bss->channel); + sdata->deflink.conf->bss->channel); } ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); @@ -3489,7 +3489,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, return NULL; if (ifmgd->associated) - cbss = sdata->deflink.u.mgd.bss; + cbss = sdata->deflink.conf->bss; else if (ifmgd->auth_data) cbss = ifmgd->auth_data->bss; else if (ifmgd->assoc_data && ifmgd->assoc_data->link[0].bss) @@ -3568,8 +3568,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) link = sdata_dereference(sdata->link[link_id], sdata); if (!link) continue; - cfg80211_unlink_bss(local->hw.wiphy, link->u.mgd.bss); - link->u.mgd.bss = NULL; + cfg80211_unlink_bss(local->hw.wiphy, link->conf->bss); + link->conf->bss = NULL; } } @@ -6208,7 +6208,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, } if (!ifmgd->associated || - !ieee80211_rx_our_beacon(bssid, link->u.mgd.bss)) + !ieee80211_rx_our_beacon(bssid, link->conf->bss)) return; bssid = link->u.mgd.bssid; @@ -6235,7 +6235,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, */ if (!ieee80211_is_s1g_beacon(hdr->frame_control)) ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); - parse_params.bss = link->u.mgd.bss; + parse_params.bss = link->conf->bss; parse_params.filter = care_about_ies; parse_params.crc = ncrc; elems = ieee802_11_parse_elems_full(&parse_params); From ba4b1fa3128b2fbf14e167230315cbd9074b629b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Feb 2024 23:21:51 +0000 Subject: [PATCH 1363/2255] wifi: mac80211: clean up assignments to pointer cache. The assignment to pointer cache in function mesh_fast_tx_gc can be made at the declaration time rather than a later assignment. There are also 3 functions where pointer cache is being initialized at declaration time and later re-assigned again with the same value, these are redundant and can be removed. Cleans up code and three clang scan build warnings: warning: Value stored to 'cache' during its initialization is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Simon Horman Link: https://msgid.link/20240215232151.2075483-1-colin.i.king@gmail.com Signed-off-by: Johannes Berg --- net/mac80211/mesh_pathtbl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 735edde1bd81..91b55d6a68b9 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -600,11 +600,10 @@ unlock_sta: void mesh_fast_tx_gc(struct ieee80211_sub_if_data *sdata) { unsigned long timeout = msecs_to_jiffies(MESH_FAST_TX_CACHE_TIMEOUT); - struct mesh_tx_cache *cache; + struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache; struct ieee80211_mesh_fast_tx *entry; struct hlist_node *n; - cache = &sdata->u.mesh.tx_cache; if (atomic_read(&cache->rht.nelems) < MESH_FAST_TX_CACHE_THRESHOLD_SIZE) return; @@ -622,7 +621,6 @@ void mesh_fast_tx_flush_mpath(struct mesh_path *mpath) struct ieee80211_mesh_fast_tx *entry; struct hlist_node *n; - cache = &sdata->u.mesh.tx_cache; spin_lock_bh(&cache->walk_lock); hlist_for_each_entry_safe(entry, n, &cache->walk_head, walk_list) if (entry->mpath == mpath) @@ -637,7 +635,6 @@ void mesh_fast_tx_flush_sta(struct ieee80211_sub_if_data *sdata, struct ieee80211_mesh_fast_tx *entry; struct hlist_node *n; - cache = &sdata->u.mesh.tx_cache; spin_lock_bh(&cache->walk_lock); hlist_for_each_entry_safe(entry, n, &cache->walk_head, walk_list) if (rcu_access_pointer(entry->mpath->next_hop) == sta) @@ -651,7 +648,6 @@ void mesh_fast_tx_flush_addr(struct ieee80211_sub_if_data *sdata, struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache; struct ieee80211_mesh_fast_tx *entry; - cache = &sdata->u.mesh.tx_cache; spin_lock_bh(&cache->walk_lock); entry = rhashtable_lookup_fast(&cache->rht, addr, fast_tx_rht_params); if (entry) From f79ab5d2bced9bd7c0ce86d2aa5b70d053001bb4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Feb 2024 17:41:36 +0200 Subject: [PATCH 1364/2255] wifi: cfg80211: Add KHZ_PER_GHZ to units.h and reuse The KHZ_PER_GHZ might be used by others (with the name aligned with similar constants). Define it in units.h and convert wireless to use it. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Horman Link: https://msgid.link/20240215154136.630029-1-andriy.shevchenko@linux.intel.com Signed-off-by: Johannes Berg --- include/linux/units.h | 5 ++++- net/wireless/reg.c | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/units.h b/include/linux/units.h index 45110daaf8d3..00e15de33eca 100644 --- a/include/linux/units.h +++ b/include/linux/units.h @@ -24,10 +24,13 @@ #define NANOHZ_PER_HZ 1000000000UL #define MICROHZ_PER_HZ 1000000UL #define MILLIHZ_PER_HZ 1000UL + #define HZ_PER_KHZ 1000UL -#define KHZ_PER_MHZ 1000UL #define HZ_PER_MHZ 1000000UL +#define KHZ_PER_MHZ 1000UL +#define KHZ_PER_GHZ 1000000UL + #define MILLIWATT_PER_WATT 1000UL #define MICROWATT_PER_MILLIWATT 1000UL #define MICROWATT_PER_WATT 1000000UL diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 50cadbad485f..753f8e9aa4b1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -57,6 +57,8 @@ #include #include #include +#include + #include #include "core.h" #include "reg.h" @@ -1289,20 +1291,17 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, u32 freq_khz) { -#define ONE_GHZ_IN_KHZ 1000000 /* * From 802.11ad: directional multi-gigabit (DMG): * Pertaining to operation in a frequency band containing a channel * with the Channel starting frequency above 45 GHz. */ - u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? - 20 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; + u32 limit = freq_khz > 45 * KHZ_PER_GHZ ? 20 * KHZ_PER_GHZ : 2 * KHZ_PER_GHZ; if (abs(freq_khz - freq_range->start_freq_khz) <= limit) return true; if (abs(freq_khz - freq_range->end_freq_khz) <= limit) return true; return false; -#undef ONE_GHZ_IN_KHZ } /* From f8599d634094b1257054a8d0815785d658cbdb74 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Feb 2024 13:54:27 +0200 Subject: [PATCH 1365/2255] wifi: cfg80211: set correct param change count in ML element The ML element generation code to create a BSS entry from a per-STA profile was not overwriting the BSS parameter change count. This meant that the incorrect parameter change count would be reported within the multi-link element. Fix this by returning the BSS parameter change count from the function and placing it into the ML element. The returned tbtt info was never used, so just drop that to simplify the code. Fixes: 5f478adf1f99 ("wifi: cfg80211: generate an ML element for per-STA profiles") Signed-off-by: Benjamin Berg Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.f2a507634692.I06b122c7a319a38b4e970f5e0bd3d3ef9cac4cbe@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 88e8b25c073a..0907a72231ee 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2567,9 +2567,9 @@ error: } static u8 -cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, - const struct ieee80211_neighbor_ap_info **ap_info, - const u8 **tbtt_info) +cfg80211_rnr_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, + const struct ieee80211_neighbor_ap_info **ap_info, + u8 *param_ch_count) { const struct ieee80211_neighbor_ap_info *info; const struct element *rnr; @@ -2626,7 +2626,9 @@ cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, if (mld_id == mld_params->mld_id && link_id == lid) { *ap_info = info; - *tbtt_info = pos; + *param_ch_count = + le16_get_bits(mld_params->params, + IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); return use_for; } @@ -2836,8 +2838,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, enum nl80211_band band; u32 freq; const u8 *profile; - const u8 *tbtt_info; ssize_t profile_len; + u8 param_ch_count; u8 link_id, use_for; if (!ieee80211_mle_basic_sta_prof_size_ok((u8 *)mle->sta_prof[i], @@ -2880,10 +2882,11 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, profile_len -= 2; /* Find in RNR to look up channel information */ - use_for = cfg80211_tbtt_info_for_mld_ap(tx_data->ie, - tx_data->ielen, - mld_id, link_id, - &ap_info, &tbtt_info); + use_for = cfg80211_rnr_info_for_mld_ap(tx_data->ie, + tx_data->ielen, + mld_id, link_id, + &ap_info, + ¶m_ch_count); if (!use_for) continue; @@ -2926,7 +2929,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, continue; /* Copy the Basic Multi-Link element including the common - * information, and then fix up the link ID. + * information, and then fix up the link ID and BSS param + * change count. * Note that the ML element length has been verified and we * also checked that it contains the link ID. */ @@ -2937,6 +2941,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, sizeof(*ml_elem) + ml_common_len); new_ie[data.ielen + sizeof(*ml_elem) + 1 + ETH_ALEN] = link_id; + new_ie[data.ielen + sizeof(*ml_elem) + 1 + ETH_ALEN + 1] = + param_ch_count; data.ielen += sizeof(*ml_elem) + ml_common_len; From 317bad4c3b61eaf14a7f5c65521a3aa8b0b6f1bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:28 +0200 Subject: [PATCH 1366/2255] wifi: cfg80211: remove cfg80211_inform_single_bss_frame_data() This function pretty much does what cfg80211_inform_single_bss_data() already does, except on a frame data. But we can call the other one, after populating the inform_data more completely, so we don't need to do everything twice. This also uncovered a few bugs: * the 6 GHz power type checks were only done in this function, move (and rename from 'uhb') those; * the chains/chain_signal information wasn't used in the latter, add that Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.f3f864f94c78.I2192adb32ab10713e71f395a9d203386264f6ed5@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 245 +++++++++++++++----------------------------- 1 file changed, 80 insertions(+), 165 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0907a72231ee..754138168646 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2087,6 +2087,35 @@ struct cfg80211_inform_single_bss_data { u64 cannot_use_reasons; }; +static bool cfg80211_6ghz_power_type_valid(const u8 *ie, size_t ielen, + const u32 flags) +{ + const struct element *tmp; + struct ieee80211_he_operation *he_oper; + + tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen); + if (tmp && tmp->datalen >= sizeof(*he_oper) + 1) { + const struct ieee80211_he_6ghz_oper *he_6ghz_oper; + + he_oper = (void *)&tmp->data[1]; + he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); + + if (!he_6ghz_oper) + return false; + + switch (u8_get_bits(he_6ghz_oper->control, + IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { + case IEEE80211_6GHZ_CTRL_REG_LPI_AP: + return true; + case IEEE80211_6GHZ_CTRL_REG_SP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); + case IEEE80211_6GHZ_CTRL_REG_VLP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); + } + } + return false; +} + /* Returned bss is reference counted and must be cleaned up appropriately. */ static struct cfg80211_bss * cfg80211_inform_single_bss_data(struct wiphy *wiphy, @@ -2119,6 +2148,14 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, if (!channel) return NULL; + if (channel->band == NL80211_BAND_6GHZ && + !cfg80211_6ghz_power_type_valid(data->ie, data->ielen, + channel->flags)) { + data->use_for = 0; + data->cannot_use_reasons = + NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH; + } + memcpy(tmp.pub.bssid, data->bssid, ETH_ALEN); tmp.pub.channel = channel; if (data->bss_source != BSS_SOURCE_STA_PROFILE) @@ -2130,6 +2167,9 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, tmp.ts_boottime = drv_data->boottime_ns; tmp.parent_tsf = drv_data->parent_tsf; ether_addr_copy(tmp.parent_bssid, drv_data->parent_bssid); + tmp.pub.chains = drv_data->chains; + memcpy(tmp.pub.chain_signal, drv_data->chain_signal, + IEEE80211_MAX_CHAINS); tmp.pub.use_for = data->use_for; tmp.pub.cannot_use_reasons = data->cannot_use_reasons; @@ -3025,59 +3065,23 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_inform_bss_data); -static bool cfg80211_uhb_power_type_valid(const u8 *ie, - size_t ielen, - const u32 flags) +struct cfg80211_bss * +cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + struct ieee80211_mgmt *mgmt, size_t len, + gfp_t gfp) { - const struct element *tmp; - struct ieee80211_he_operation *he_oper; - - tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen); - if (tmp && tmp->datalen >= sizeof(*he_oper) + 1) { - const struct ieee80211_he_6ghz_oper *he_6ghz_oper; - - he_oper = (void *)&tmp->data[1]; - he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); - - if (!he_6ghz_oper) - return false; - - switch (u8_get_bits(he_6ghz_oper->control, - IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { - case IEEE80211_6GHZ_CTRL_REG_LPI_AP: - return true; - case IEEE80211_6GHZ_CTRL_REG_SP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); - case IEEE80211_6GHZ_CTRL_REG_VLP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); - } - } - return false; -} - -/* cfg80211_inform_bss_width_frame helper */ -static struct cfg80211_bss * -cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - struct ieee80211_mgmt *mgmt, size_t len, - gfp_t gfp) -{ - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - struct cfg80211_internal_bss tmp = {}, *res; - struct cfg80211_bss_ies *ies; - struct ieee80211_channel *channel; - bool signal_valid; + struct cfg80211_inform_single_bss_data inform_data = { + .drv_data = data, + .use_for = data->restrict_use ? + data->use_for : + NL80211_BSS_USE_FOR_ALL, + .cannot_use_reasons = data->cannot_use_reasons, + }; + size_t min_hdr_len = offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); struct ieee80211_ext *ext = NULL; - u8 *bssid, *variable; - u16 capability, beacon_int; - size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt, - u.probe_resp.variable); - int bss_type; - - BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != - offsetof(struct ieee80211_mgmt, u.beacon.variable)); - - trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len); + struct cfg80211_bss *res; if (WARN_ON(!mgmt)) return NULL; @@ -3085,9 +3089,10 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, if (WARN_ON(!wiphy)) return NULL; - if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && - (data->signal < 0 || data->signal > 100))) - return NULL; + BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != + offsetof(struct ieee80211_mgmt, u.beacon.variable)); + + trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len); if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { ext = (void *) mgmt; @@ -3100,140 +3105,50 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, if (WARN_ON(len < min_hdr_len)) return NULL; - ielen = len - min_hdr_len; - variable = mgmt->u.probe_resp.variable; - if (ext) { - if (ieee80211_is_s1g_short_beacon(mgmt->frame_control)) - variable = ext->u.s1g_short_beacon.variable; - else - variable = ext->u.s1g_beacon.variable; - } - - channel = cfg80211_get_bss_channel(wiphy, variable, ielen, data->chan); - if (!channel) - return NULL; - - if (channel->band == NL80211_BAND_6GHZ && - !cfg80211_uhb_power_type_valid(variable, ielen, channel->flags)) { - data->restrict_use = 1; - data->use_for = 0; - data->cannot_use_reasons = - NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH; - } - + inform_data.ielen = len - min_hdr_len; + inform_data.ie = mgmt->u.probe_resp.variable; if (ext) { const struct ieee80211_s1g_bcn_compat_ie *compat; const struct element *elem; + if (ieee80211_is_s1g_short_beacon(mgmt->frame_control)) + inform_data.ie = ext->u.s1g_short_beacon.variable; + else + inform_data.ie = ext->u.s1g_beacon.variable; + elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, - variable, ielen); + inform_data.ie, inform_data.ielen); if (!elem) return NULL; if (elem->datalen < sizeof(*compat)) return NULL; compat = (void *)elem->data; - bssid = ext->u.s1g_beacon.sa; - capability = le16_to_cpu(compat->compat_info); - beacon_int = le16_to_cpu(compat->beacon_int); + memcpy(inform_data.bssid, ext->u.s1g_beacon.sa, ETH_ALEN); + inform_data.capability = le16_to_cpu(compat->compat_info); + inform_data.beacon_interval = le16_to_cpu(compat->beacon_int); } else { - bssid = mgmt->bssid; - beacon_int = le16_to_cpu(mgmt->u.probe_resp.beacon_int); - capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); + memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN); + inform_data.beacon_interval = + le16_to_cpu(mgmt->u.probe_resp.beacon_int); + inform_data.capability = + le16_to_cpu(mgmt->u.probe_resp.capab_info); } - if (channel->band == NL80211_BAND_60GHZ) { - bss_type = capability & WLAN_CAPABILITY_DMG_TYPE_MASK; - if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || - bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } else { - if (capability & WLAN_CAPABILITY_ESS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } - - ies = kzalloc(sizeof(*ies) + ielen, gfp); - if (!ies) - return NULL; - ies->len = ielen; - ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); - ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control) || - ieee80211_is_s1g_beacon(mgmt->frame_control); - memcpy(ies->data, variable, ielen); + inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); if (ieee80211_is_probe_resp(mgmt->frame_control)) - rcu_assign_pointer(tmp.pub.proberesp_ies, ies); + inform_data.ftype = CFG80211_BSS_FTYPE_PRESP; else - rcu_assign_pointer(tmp.pub.beacon_ies, ies); - rcu_assign_pointer(tmp.pub.ies, ies); + inform_data.ftype = CFG80211_BSS_FTYPE_BEACON; - memcpy(tmp.pub.bssid, bssid, ETH_ALEN); - tmp.pub.beacon_interval = beacon_int; - tmp.pub.capability = capability; - tmp.pub.channel = channel; - tmp.pub.signal = data->signal; - tmp.ts_boottime = data->boottime_ns; - tmp.parent_tsf = data->parent_tsf; - tmp.pub.chains = data->chains; - memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS); - ether_addr_copy(tmp.parent_bssid, data->parent_bssid); - tmp.pub.use_for = data->restrict_use ? - data->use_for : - NL80211_BSS_USE_FOR_ALL; - tmp.pub.cannot_use_reasons = data->cannot_use_reasons; - - signal_valid = data->chan == channel; - spin_lock_bh(&rdev->bss_lock); - res = __cfg80211_bss_update(rdev, &tmp, signal_valid, jiffies); - if (!res) - goto drop; - - rdev_inform_bss(rdev, &res->pub, ies, data->drv_data); - - spin_unlock_bh(&rdev->bss_lock); - - trace_cfg80211_return_bss(&res->pub); - /* __cfg80211_bss_update gives us a referenced result */ - return &res->pub; - -drop: - spin_unlock_bh(&rdev->bss_lock); - return NULL; -} - -struct cfg80211_bss * -cfg80211_inform_bss_frame_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - struct ieee80211_mgmt *mgmt, size_t len, - gfp_t gfp) -{ - struct cfg80211_inform_single_bss_data inform_data = { - .drv_data = data, - .ie = mgmt->u.probe_resp.variable, - .ielen = len - offsetof(struct ieee80211_mgmt, - u.probe_resp.variable), - .use_for = data->restrict_use ? - data->use_for : - NL80211_BSS_USE_FOR_ALL, - .cannot_use_reasons = data->cannot_use_reasons, - }; - struct cfg80211_bss *res; - - res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt, - len, gfp); + res = cfg80211_inform_single_bss_data(wiphy, &inform_data, gfp); if (!res) return NULL; /* don't do any further MBSSID/ML handling for S1G */ - if (ieee80211_is_s1g_beacon(mgmt->frame_control)) + if (ext) return res; - inform_data.ftype = ieee80211_is_beacon(mgmt->frame_control) ? - CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP; - memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN); - inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); - inform_data.beacon_interval = - le16_to_cpu(mgmt->u.probe_resp.beacon_int); - /* process each non-transmitting bss */ cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); From 7e899c1d6f0da2a98ebf6629274ef912d4c83359 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:29 +0200 Subject: [PATCH 1367/2255] wifi: cfg80211: clean up cfg80211_inform_bss_frame_data() Make cfg80211_inform_bss_frame_data() call the existing cfg80211_inform_bss_data() after parsing the frame in the appropriate way, so we have less code duplication. This required introducing a new CFG80211_BSS_FTYPE_S1G_BEACON, but that can be used by other drivers as well. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.874aed1eff5f.Ib7d88d126eec50c64763251a78cb432bb5df14df@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ net/wireless/scan.c | 71 +++++++++++++++++++----------------------- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 57c2298af35b..f9eada2a26ec 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7175,11 +7175,13 @@ size_t cfg80211_merge_profile(const u8 *ie, size_t ielen, * from a beacon or probe response * @CFG80211_BSS_FTYPE_BEACON: data comes from a beacon * @CFG80211_BSS_FTYPE_PRESP: data comes from a probe response + * @CFG80211_BSS_FTYPE_S1G_BEACON: data comes from an S1G beacon */ enum cfg80211_bss_frame_type { CFG80211_BSS_FTYPE_UNKNOWN, CFG80211_BSS_FTYPE_BEACON, CFG80211_BSS_FTYPE_PRESP, + CFG80211_BSS_FTYPE_S1G_BEACON, }; /** diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 754138168646..c2d85fa4b75d 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2213,6 +2213,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, switch (data->ftype) { case CFG80211_BSS_FTYPE_BEACON: + case CFG80211_BSS_FTYPE_S1G_BEACON: ies->from_beacon = true; fallthrough; case CFG80211_BSS_FTYPE_UNKNOWN: @@ -3057,6 +3058,10 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, if (!res) return NULL; + /* don't do any further MBSSID/ML handling for S1G */ + if (ftype == CFG80211_BSS_FTYPE_S1G_BEACON) + return res; + cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); cfg80211_parse_ml_sta_data(wiphy, &inform_data, res, gfp); @@ -3071,17 +3076,16 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp) { - struct cfg80211_inform_single_bss_data inform_data = { - .drv_data = data, - .use_for = data->restrict_use ? - data->use_for : - NL80211_BSS_USE_FOR_ALL, - .cannot_use_reasons = data->cannot_use_reasons, - }; size_t min_hdr_len = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); struct ieee80211_ext *ext = NULL; - struct cfg80211_bss *res; + enum cfg80211_bss_frame_type ftype; + u16 beacon_interval; + const u8 *bssid; + u16 capability; + const u8 *ie; + size_t ielen; + u64 tsf; if (WARN_ON(!mgmt)) return NULL; @@ -3105,56 +3109,45 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, if (WARN_ON(len < min_hdr_len)) return NULL; - inform_data.ielen = len - min_hdr_len; - inform_data.ie = mgmt->u.probe_resp.variable; + ielen = len - min_hdr_len; + ie = mgmt->u.probe_resp.variable; if (ext) { const struct ieee80211_s1g_bcn_compat_ie *compat; const struct element *elem; if (ieee80211_is_s1g_short_beacon(mgmt->frame_control)) - inform_data.ie = ext->u.s1g_short_beacon.variable; + ie = ext->u.s1g_short_beacon.variable; else - inform_data.ie = ext->u.s1g_beacon.variable; + ie = ext->u.s1g_beacon.variable; - elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, - inform_data.ie, inform_data.ielen); + elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT, ie, ielen); if (!elem) return NULL; if (elem->datalen < sizeof(*compat)) return NULL; compat = (void *)elem->data; - memcpy(inform_data.bssid, ext->u.s1g_beacon.sa, ETH_ALEN); - inform_data.capability = le16_to_cpu(compat->compat_info); - inform_data.beacon_interval = le16_to_cpu(compat->beacon_int); + bssid = ext->u.s1g_beacon.sa; + capability = le16_to_cpu(compat->compat_info); + beacon_interval = le16_to_cpu(compat->beacon_int); } else { - memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN); - inform_data.beacon_interval = - le16_to_cpu(mgmt->u.probe_resp.beacon_int); - inform_data.capability = - le16_to_cpu(mgmt->u.probe_resp.capab_info); + bssid = mgmt->bssid; + beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); + capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); } - inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); + tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); if (ieee80211_is_probe_resp(mgmt->frame_control)) - inform_data.ftype = CFG80211_BSS_FTYPE_PRESP; + ftype = CFG80211_BSS_FTYPE_PRESP; + else if (ext) + ftype = CFG80211_BSS_FTYPE_S1G_BEACON; else - inform_data.ftype = CFG80211_BSS_FTYPE_BEACON; + ftype = CFG80211_BSS_FTYPE_BEACON; - res = cfg80211_inform_single_bss_data(wiphy, &inform_data, gfp); - if (!res) - return NULL; - - /* don't do any further MBSSID/ML handling for S1G */ - if (ext) - return res; - - /* process each non-transmitting bss */ - cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); - - cfg80211_parse_ml_sta_data(wiphy, &inform_data, res, gfp); - - return res; + return cfg80211_inform_bss_data(wiphy, data, ftype, + bssid, tsf, capability, + beacon_interval, ie, ielen, + gfp); } EXPORT_SYMBOL(cfg80211_inform_bss_frame_data); From 6b756efcd9f01a7f972c0aa0da1c4f84658ba156 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:30 +0200 Subject: [PATCH 1368/2255] wifi: cfg80211: refactor RNR parsing We'll need more parsing of the reduced neighbor report element, and we already have two places doing pretty much the same. Combine by refactoring the parsing into a separate function with a callback for each item found. Signed-off-by: Johannes Berg Reviewed-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.cfff14b692fc.Ibe25be88a769eab29ebb17b9d19af666df6a2227@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 316 ++++++++++++++++++++++++-------------------- 1 file changed, 174 insertions(+), 142 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index c2d85fa4b75d..e46dfc71c497 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -611,104 +611,144 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, return 0; } -VISIBLE_IF_CFG80211_KUNIT int -cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, - struct list_head *list) +enum cfg80211_rnr_iter_ret { + RNR_ITER_CONTINUE, + RNR_ITER_BREAK, + RNR_ITER_ERROR, +}; + +static bool +cfg80211_iter_rnr(const u8 *elems, size_t elems_len, + enum cfg80211_rnr_iter_ret + (*iter)(void *data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len), + void *iter_data) { - struct ieee80211_neighbor_ap_info *ap_info; - const struct element *elem, *ssid_elem; + const struct element *rnr; const u8 *pos, *end; - u32 s_ssid_tmp; - int n_coloc = 0, ret; - LIST_HEAD(ap_list); - ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp); - if (ret) - return 0; + for_each_element_id(rnr, WLAN_EID_REDUCED_NEIGHBOR_REPORT, + elems, elems_len) { + const struct ieee80211_neighbor_ap_info *info; - for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT, - ies->data, ies->len) { - pos = elem->data; - end = elem->data + elem->datalen; + pos = rnr->data; + end = rnr->data + rnr->datalen; /* RNR IE may contain more than one NEIGHBOR_AP_INFO */ - while (pos + sizeof(*ap_info) <= end) { - enum nl80211_band band; - int freq; + while (sizeof(*info) <= end - pos) { u8 length, i, count; + u8 type; - ap_info = (void *)pos; - count = u8_get_bits(ap_info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1; - length = ap_info->tbtt_info_len; + info = (void *)pos; + count = u8_get_bits(info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_COUNT) + + 1; + length = info->tbtt_info_len; - pos += sizeof(*ap_info); + pos += sizeof(*info); - if (!ieee80211_operating_class_to_band(ap_info->op_class, - &band)) - break; + if (count * length > end - pos) + return false; - freq = ieee80211_channel_to_frequency(ap_info->channel, - band); - - if (end - pos < count * length) - break; - - if (u8_get_bits(ap_info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_TYPE) != - IEEE80211_TBTT_INFO_TYPE_TBTT) { - pos += count * length; - continue; - } - - /* TBTT info must include bss param + BSSID + - * (short SSID or same_ssid bit to be set). - * ignore other options, and move to the - * next AP info - */ - if (band != NL80211_BAND_6GHZ || - !(length == offsetofend(struct ieee80211_tbtt_info_7_8_9, - bss_params) || - length == sizeof(struct ieee80211_tbtt_info_7_8_9) || - length >= offsetofend(struct ieee80211_tbtt_info_ge_11, - bss_params))) { - pos += count * length; - continue; - } + type = u8_get_bits(info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_TYPE); for (i = 0; i < count; i++) { - struct cfg80211_colocated_ap *entry; - - entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN, - GFP_ATOMIC); - - if (!entry) - goto error; - - entry->center_freq = freq; - - if (!cfg80211_parse_ap_info(entry, pos, length, - ssid_elem, - s_ssid_tmp)) { - n_coloc++; - list_add_tail(&entry->list, &ap_list); - } else { - kfree(entry); + switch (iter(iter_data, type, info, + pos, length)) { + case RNR_ITER_CONTINUE: + break; + case RNR_ITER_BREAK: + return true; + case RNR_ITER_ERROR: + return false; } pos += length; } } -error: - if (pos != end) { - cfg80211_free_coloc_ap_list(&ap_list); - return 0; - } + if (pos != end) + return false; } - list_splice_tail(&ap_list, list); - return n_coloc; + return true; +} + +struct colocated_ap_data { + const struct element *ssid_elem; + struct list_head ap_list; + u32 s_ssid_tmp; + int n_coloc; +}; + +static enum cfg80211_rnr_iter_ret +cfg80211_parse_colocated_ap_iter(void *_data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len) +{ + struct colocated_ap_data *data = _data; + struct cfg80211_colocated_ap *entry; + enum nl80211_band band; + + if (type != IEEE80211_TBTT_INFO_TYPE_TBTT) + return RNR_ITER_CONTINUE; + + if (!ieee80211_operating_class_to_band(info->op_class, &band)) + return RNR_ITER_CONTINUE; + + /* TBTT info must include bss param + BSSID + (short SSID or + * same_ssid bit to be set). Ignore other options, and move to + * the next AP info + */ + if (band != NL80211_BAND_6GHZ || + !(tbtt_info_len == offsetofend(struct ieee80211_tbtt_info_7_8_9, + bss_params) || + tbtt_info_len == sizeof(struct ieee80211_tbtt_info_7_8_9) || + tbtt_info_len >= offsetofend(struct ieee80211_tbtt_info_ge_11, + bss_params))) + return RNR_ITER_CONTINUE; + + entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN, GFP_ATOMIC); + if (!entry) + return RNR_ITER_ERROR; + + entry->center_freq = + ieee80211_channel_to_frequency(info->channel, band); + + if (!cfg80211_parse_ap_info(entry, tbtt_info, tbtt_info_len, + data->ssid_elem, data->s_ssid_tmp)) { + data->n_coloc++; + list_add_tail(&entry->list, &data->ap_list); + } else { + kfree(entry); + } + + return RNR_ITER_CONTINUE; +} + +VISIBLE_IF_CFG80211_KUNIT int +cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, + struct list_head *list) +{ + struct colocated_ap_data data = {}; + int ret; + + INIT_LIST_HEAD(&data.ap_list); + + ret = cfg80211_calc_short_ssid(ies, &data.ssid_elem, &data.s_ssid_tmp); + if (ret) + return 0; + + if (!cfg80211_iter_rnr(ies->data, ies->len, + cfg80211_parse_colocated_ap_iter, &data)) { + cfg80211_free_coloc_ap_list(&data.ap_list); + return 0; + } + + list_splice_tail(&data.ap_list, list); + return data.n_coloc; } EXPORT_SYMBOL_IF_CFG80211_KUNIT(cfg80211_parse_colocated_ap); @@ -2607,79 +2647,71 @@ error: return NULL; } +struct tbtt_info_iter_data { + const struct ieee80211_neighbor_ap_info *ap_info; + u8 param_ch_count; + u32 use_for; + u8 mld_id, link_id; +}; + +static enum cfg80211_rnr_iter_ret +cfg802121_mld_ap_rnr_iter(void *_data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len) +{ + const struct ieee80211_rnr_mld_params *mld_params; + struct tbtt_info_iter_data *data = _data; + u8 link_id; + + if (type == IEEE80211_TBTT_INFO_TYPE_TBTT && + tbtt_info_len >= offsetofend(struct ieee80211_tbtt_info_ge_11, + mld_params)) + mld_params = (void *)(tbtt_info + + offsetof(struct ieee80211_tbtt_info_ge_11, + mld_params)); + else if (type == IEEE80211_TBTT_INFO_TYPE_MLD && + tbtt_info_len >= sizeof(struct ieee80211_rnr_mld_params)) + mld_params = (void *)tbtt_info; + else + return RNR_ITER_CONTINUE; + + link_id = le16_get_bits(mld_params->params, + IEEE80211_RNR_MLD_PARAMS_LINK_ID); + + if (data->mld_id != mld_params->mld_id) + return RNR_ITER_CONTINUE; + + if (data->link_id != link_id) + return RNR_ITER_CONTINUE; + + data->ap_info = info; + data->param_ch_count = + le16_get_bits(mld_params->params, + IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); + + if (type == IEEE80211_TBTT_INFO_TYPE_TBTT) + data->use_for = NL80211_BSS_USE_FOR_ALL; + else + data->use_for = NL80211_BSS_USE_FOR_MLD_LINK; + return RNR_ITER_BREAK; +} + static u8 cfg80211_rnr_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, const struct ieee80211_neighbor_ap_info **ap_info, u8 *param_ch_count) { - const struct ieee80211_neighbor_ap_info *info; - const struct element *rnr; - const u8 *pos, *end; + struct tbtt_info_iter_data data = { + .mld_id = mld_id, + .link_id = link_id, + }; - for_each_element_id(rnr, WLAN_EID_REDUCED_NEIGHBOR_REPORT, ie, ielen) { - pos = rnr->data; - end = rnr->data + rnr->datalen; + cfg80211_iter_rnr(ie, ielen, cfg802121_mld_ap_rnr_iter, &data); - /* RNR IE may contain more than one NEIGHBOR_AP_INFO */ - while (sizeof(*info) <= end - pos) { - const struct ieee80211_rnr_mld_params *mld_params; - u16 params; - u8 length, i, count, mld_params_offset; - u8 type, lid; - u32 use_for; + *ap_info = data.ap_info; + *param_ch_count = data.param_ch_count; - info = (void *)pos; - count = u8_get_bits(info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1; - length = info->tbtt_info_len; - - pos += sizeof(*info); - - if (count * length > end - pos) - return 0; - - type = u8_get_bits(info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_TYPE); - - if (type == IEEE80211_TBTT_INFO_TYPE_TBTT && - length >= - offsetofend(struct ieee80211_tbtt_info_ge_11, - mld_params)) { - mld_params_offset = - offsetof(struct ieee80211_tbtt_info_ge_11, mld_params); - use_for = NL80211_BSS_USE_FOR_ALL; - } else if (type == IEEE80211_TBTT_INFO_TYPE_MLD && - length >= sizeof(struct ieee80211_rnr_mld_params)) { - mld_params_offset = 0; - use_for = NL80211_BSS_USE_FOR_MLD_LINK; - } else { - pos += count * length; - continue; - } - - for (i = 0; i < count; i++) { - mld_params = (void *)pos + mld_params_offset; - params = le16_to_cpu(mld_params->params); - - lid = u16_get_bits(params, - IEEE80211_RNR_MLD_PARAMS_LINK_ID); - - if (mld_id == mld_params->mld_id && - link_id == lid) { - *ap_info = info; - *param_ch_count = - le16_get_bits(mld_params->params, - IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); - - return use_for; - } - - pos += length; - } - } - } - - return 0; + return data.use_for; } static struct element * From 6bd14aee0bd25525ab229acd9bfe536dd8642364 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:31 +0200 Subject: [PATCH 1369/2255] wifi: mac80211: align ieee80211_mle_get_bss_param_ch_cnt() Align the prototype of ieee80211_mle_get_bss_param_ch_cnt() to also take a u8 * like the other functions, and make it return -1 when the field isn't found, so that mac80211 can check that instead of explicitly open-coding the check. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.583309181bc3.Ia61cb0b4fc034d5ac8fcfaf6f6fb2e115fadafe7@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 11 ++++++----- net/mac80211/mlme.c | 9 +++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e4322238f273..303c75459897 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4990,17 +4990,18 @@ static inline int ieee80211_mle_get_link_id(const u8 *data) /** * ieee80211_mle_get_bss_param_ch_cnt - returns the BSS parameter change count - * @mle: the basic multi link element + * @data: pointer to the basic multi link element * * The element is assumed to be of the correct type (BASIC) and big enough, * this must be checked using ieee80211_mle_type_ok(). * * If the BSS parameter change count value can't be found (the presence bit - * for it is clear), 0 will be returned. + * for it is clear), -1 will be returned. */ -static inline u8 -ieee80211_mle_get_bss_param_ch_cnt(const struct ieee80211_multi_link_elem *mle) +static inline int +ieee80211_mle_get_bss_param_ch_cnt(const u8 *data) { + const struct ieee80211_multi_link_elem *mle = (const void *)data; u16 control = le16_to_cpu(mle->control); const u8 *common = mle->variable; @@ -5008,7 +5009,7 @@ ieee80211_mle_get_bss_param_ch_cnt(const struct ieee80211_multi_link_elem *mle) common += sizeof(struct ieee80211_mle_basic_common_info); if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)) - return 0; + return -1; if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) common += 1; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 87ffc19770b8..5f2e9f5e1779 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4202,13 +4202,14 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, */ assoc_data->link[link_id].status = WLAN_STATUS_SUCCESS; if (elems->ml_basic) { - if (!(elems->ml_basic->control & - cpu_to_le16(IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT))) { + int bss_param_ch_cnt = + ieee80211_mle_get_bss_param_ch_cnt((const void *)elems->ml_basic); + + if (bss_param_ch_cnt < 0) { ret = false; goto out; } - link->u.mgd.bss_param_ch_cnt = - ieee80211_mle_get_bss_param_ch_cnt(elems->ml_basic); + link->u.mgd.bss_param_ch_cnt = bss_param_ch_cnt; } } else if (elems->parse_error & IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC || !elems->prof || From 894dd84e49ec114a2dde7b312ae4cada40d15bdb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Feb 2024 13:54:32 +0200 Subject: [PATCH 1370/2255] wifi: cfg80211: use ML element parsing helpers Use the existing ML element parsing helpers and add a new one for this (ieee80211_mle_get_mld_id). Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240216135047.4da47b1f035b.I437a5570ac456449facb0b147851ef24a1e473c2@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 38 ++++++++++++++++++++++++++++++++++++ net/wireless/scan.c | 41 ++++++++------------------------------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 303c75459897..3385a2cc5b09 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -5115,6 +5115,44 @@ static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data) return get_unaligned_le16(common); } +/** + * ieee80211_mle_get_mld_id - returns the MLD ID + * @data: pointer to the multi link element + * + * The element is assumed to be of the correct type (BASIC) and big enough, + * this must be checked using ieee80211_mle_type_ok(). + * + * If the MLD ID is not present, 0 will be returned. + */ +static inline u8 ieee80211_mle_get_mld_id(const u8 *data) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control = le16_to_cpu(mle->control); + const u8 *common = mle->variable; + + /* + * common points now at the beginning of + * ieee80211_mle_basic_common_info + */ + common += sizeof(struct ieee80211_mle_basic_common_info); + + if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_ID)) + return 0; + + if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) + common += 2; + + return *common; +} + /** * ieee80211_mle_size_ok - validate multi-link element size * @data: pointer to the element data diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e46dfc71c497..7cf36b8d3ae7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2833,17 +2833,16 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, struct cfg80211_bss *bss; u8 mld_id, reporter_link_id, bss_change_count; u16 seen_links = 0; - const u8 *pos; u8 i; - if (!ieee80211_mle_size_ok(elem->data + 1, elem->datalen - 1)) + if (!ieee80211_mle_type_ok(elem->data + 1, + IEEE80211_ML_CONTROL_TYPE_BASIC, + elem->datalen - 1)) return; - ml_elem = (void *)elem->data + 1; + ml_elem = (void *)(elem->data + 1); control = le16_to_cpu(ml_elem->control); - if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) != - IEEE80211_ML_CONTROL_TYPE_BASIC) - return; + ml_common_len = ml_elem->variable[0]; /* Must be present when transmitted by an AP (in a probe response) */ if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) || @@ -2851,24 +2850,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, !(control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)) return; - ml_common_len = ml_elem->variable[0]; - - /* length + MLD MAC address */ - pos = ml_elem->variable + 1 + 6; - - reporter_link_id = pos[0]; - pos += 1; - - bss_change_count = pos[0]; - pos += 1; - - if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) - pos += 2; - if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_EML_CAPA)) - pos += 2; - - /* MLD capabilities and operations */ - pos += 2; + reporter_link_id = ieee80211_mle_get_link_id(elem->data + 1); + bss_change_count = ieee80211_mle_get_bss_param_ch_cnt(elem->data + 1); /* * The MLD ID of the reporting AP is always zero. It is set if the AP @@ -2876,15 +2859,7 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, * relating to a nontransmitted BSS (matching the Multi-BSSID Index, * Draft P802.11be_D3.2, 35.3.4.2) */ - if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MLD_ID)) { - mld_id = *pos; - pos += 1; - } else { - mld_id = 0; - } - - /* Extended MLD capabilities and operations */ - pos += 2; + mld_id = ieee80211_mle_get_mld_id(elem->data + 1); /* Fully defrag the ML element for sta information/profile iteration */ mle = cfg80211_defrag_mle(elem, tx_data->ie, tx_data->ielen, gfp); From 32a5690e9acb461c7c6a4595f9e77a6fb5c4094f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:42 +0200 Subject: [PATCH 1371/2255] wifi: iwlwifi: mvm: support wider-bandwidth OFDMA To support wider-bandwidth OFDMA we need to configure the PHY context in the firmware, which will in turn configure the DSP accordingly. Pass the relevant information down. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.ca666ede5dd6.I357972823d20e9045e2c97dbb7ac24fe9f5a6e41@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 5 +++-- .../wireless/intel/iwlwifi/mvm/debugfs-vif.c | 5 +++-- .../intel/iwlwifi/mvm/ftm-responder.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 9 ++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ .../net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 19 +++++++++++++++---- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index b6a9896bce25..9830a3c3600b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -720,7 +720,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_chanctx_conf *ctx; u8 chains_static, chains_dynamic; - struct cfg80211_chan_def chandef; + struct cfg80211_chan_def chandef, ap_def; int ret, i; struct iwl_binding_cmd_v1 binding_cmd = {}; struct iwl_time_quota_cmd quota_cmd = {}; @@ -742,12 +742,13 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EINVAL; } chandef = ctx->def; + ap_def = ctx->ap; chains_static = ctx->rx_chains_static; chains_dynamic = ctx->rx_chains_dynamic; rcu_read_unlock(); ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt, &chandef, - chains_static, chains_dynamic); + &ap_def, chains_static, chains_dynamic); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index aa3c9c2cbd7f..51b01f7528be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -592,7 +592,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, for_each_vif_active_link(vif, link_conf, link_id) { struct ieee80211_chanctx_conf *chanctx_conf; - struct cfg80211_chan_def min_def; + struct cfg80211_chan_def min_def, ap_def; struct iwl_mvm_phy_ctxt *phy_ctxt; u8 chains_static, chains_dynamic; @@ -606,6 +606,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, * everything here and use it after unlocking */ min_def = chanctx_conf->min_def; + ap_def = chanctx_conf->ap; chains_static = chanctx_conf->rx_chains_static; chains_dynamic = chanctx_conf->rx_chains_dynamic; rcu_read_unlock(); @@ -614,7 +615,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, if (!phy_ctxt) continue; - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, &ap_def, chains_static, chains_dynamic); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index dca36b0662c7..8e760300a1ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -438,7 +438,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, rcu_read_unlock(); phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, &ctx.ap, ctx.rx_chains_static, ctx.rx_chains_dynamic); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 229d87a786df..69f6a96b0cfb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1644,6 +1644,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, IEEE80211_VIF_SUPPORTS_CQM_RSSI; } + if (vif->p2p || iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) < 5) + vif->driver_flags |= IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW; + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mvm->p2p_device_vif = vif; @@ -4651,7 +4654,7 @@ static int iwl_mvm_p2p_find_phy_ctxt(struct iwl_mvm *mvm, cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); return iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt, - &chandef, 1, 1); + &chandef, NULL, 1, 1); } /* Execute the common part for MLD and non-MLD modes */ @@ -4772,7 +4775,7 @@ static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, goto out; } - ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, def, + ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, def, &ctx->ap, ctx->rx_chains_static, ctx->rx_chains_dynamic); if (ret) { @@ -4850,7 +4853,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, } iwl_mvm_bt_coex_vif_change(mvm); - iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def, + iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def, &ctx->ap, ctx->rx_chains_static, ctx->rx_chains_dynamic); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ce78c21883e9..fcae5199ac90 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1810,9 +1810,11 @@ void iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, 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, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic); int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic); void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index bac655834f32..e208e3c34c25 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -198,12 +198,16 @@ 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, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic, u32 action) { int ret; int ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1); + if (ver < 5 || !ap || !ap->chan) + ap = NULL; + if (ver >= 3 && ver <= 5) { struct iwl_phy_context_cmd cmd = {}; @@ -215,6 +219,11 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, chains_static, chains_dynamic); + if (ap) { + cmd.v5.sbb_bandwidth = iwl_mvm_get_channel_width(ap); + cmd.v5.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); + } + ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } else if (ver < 3) { @@ -255,6 +264,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, */ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic) { int ret; @@ -267,7 +277,7 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->width = chandef->width; ctxt->center_freq1 = chandef->center_freq1; - ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, ap, chains_static, chains_dynamic, FW_CTXT_ACTION_ADD); @@ -301,6 +311,7 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) */ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic) { enum iwl_ctxt_action action = FW_CTXT_ACTION_MODIFY; @@ -324,7 +335,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, int ret; /* ... remove it here ...*/ - ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, NULL, chains_static, chains_dynamic, FW_CTXT_ACTION_REMOVE); if (ret) @@ -338,7 +349,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->width = chandef->width; ctxt->center_freq1 = chandef->center_freq1; - return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, ap, chains_static, chains_dynamic, action); } @@ -358,7 +369,7 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) cfg80211_chandef_create(&chandef, ctxt->channel, NL80211_CHAN_NO_HT); - iwl_mvm_phy_ctxt_apply(mvm, ctxt, &chandef, 1, 1, + iwl_mvm_phy_ctxt_apply(mvm, ctxt, &chandef, NULL, 1, 1, FW_CTXT_ACTION_REMOVE); } From 3eab2034364dc446d3ccd0bee15af681638fcb9d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:43 +0200 Subject: [PATCH 1372/2255] wifi: iwlwifi: mvm: partially support PHY context version 6 The version 6 command adds the puncture mask to the PHY context and is otherwise the same. Support that in the API definitions, but don't fill it yet. While at it, also mark the field as removed from the link context command since it moved from there to PHY context. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.2156fca5b1a5.I57f47f26ec0d96ecfb1192039f72b1c6d4e8a357@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 10 ++++------ drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h | 9 +++++---- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 6 +++--- 3 files changed, 12 insertions(+), 13 deletions(-) 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 200362e5ceca..c6d1f5644638 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -373,7 +373,7 @@ struct iwl_mac_config_cmd { * iwl_link_ctx_cfg_cmd::bss_color_disable * @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask. * This flag can be set only if the MAC that this link relates to has - * eht_support set to true. + * eht_support set to true. No longer used since _VER_3 of this command. * @LINK_CONTEXT_MODIFY_ALL: set all above flags */ enum iwl_link_ctx_modify_flags { @@ -462,7 +462,7 @@ enum iwl_link_ctx_flags { * @bi: beacon interval in TU, applicable only when associated * @dtim_interval: DTIM interval in TU. * Relevant only for GO, otherwise this is offloaded. - * @puncture_mask: puncture mask for EHT + * @puncture_mask: puncture mask for EHT (removed in VER_3) * @frame_time_rts_th: HE duration RTS threshold, in units of 32us * @flags: a combination from &enum iwl_link_ctx_flags * @flags_mask: what of %flags have changed. Also &enum iwl_link_ctx_flags @@ -505,7 +505,7 @@ struct iwl_link_config_cmd { struct iwl_he_backoff_conf trig_based_txf[AC_NUM]; __le32 bi; __le32 dtim_interval; - __le16 puncture_mask; + __le16 puncture_mask; /* removed in _VER_3 */ __le16 frame_time_rts_th; __le32 flags; __le32 flags_mask; @@ -519,9 +519,7 @@ struct iwl_link_config_cmd { u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; __le32 reserved3[8]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 and - * LINK_CONTEXT_CONFIG_CMD_API_S_VER_2 - */ +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3 */ /* 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/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 205d0413e626..08a2c416ce60 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -156,17 +156,18 @@ struct iwl_phy_context_cmd { __le32 lmac_id; union { __le32 rxchain_info; /* reserved in _VER_4 */ - struct { /* used for _VER_5 */ + struct { /* used for _VER_5/_VER_6 */ u8 sbb_bandwidth; u8 sbb_ctrl_channel_loc; - __le16 reserved; - } v5; + __le16 puncture_mask; /* added in VER_6 */ + }; }; __le32 dsp_cfg_flags; __le32 reserved; } __packed; /* PHY_CONTEXT_CMD_API_VER_3, * PHY_CONTEXT_CMD_API_VER_4, - * PHY_CONTEXT_CMD_API_VER_5 + * PHY_CONTEXT_CMD_API_VER_5, + * PHY_CONTEXT_CMD_API_VER_6 */ #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 e208e3c34c25..5db44514d025 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -208,7 +208,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, if (ver < 5 || !ap || !ap->chan) ap = NULL; - if (ver >= 3 && ver <= 5) { + if (ver >= 3 && ver <= 6) { struct iwl_phy_context_cmd cmd = {}; /* Set the command header fields */ @@ -220,8 +220,8 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, chains_dynamic); if (ap) { - cmd.v5.sbb_bandwidth = iwl_mvm_get_channel_width(ap); - cmd.v5.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); + cmd.sbb_bandwidth = iwl_mvm_get_channel_width(ap); + cmd.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); } ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, From 9a43c1902e56231fcf11780d7e2015638ff43cca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:44 +0200 Subject: [PATCH 1373/2255] wifi: iwlwifi: mvm: support PHY context version 6 Fill the new puncture mask in the PHY context command if supported. In this case, also don't send it in the link context command. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.16d9f5fc41df.I9eeb55787d8483f820f5790e8874761f598da314@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 129eefcc45d6..f13f13e6b71a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -204,7 +204,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, def = iwl_mvm_chanctx_def(mvm, ctx); if (iwlwifi_mod_params.disable_11be || - !link_conf->eht_support || !def) + !link_conf->eht_support || !def || + iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) >= 6) changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS; else cmd.puncture_mask = cpu_to_le16(def->punctured); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 5db44514d025..ce264b386029 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-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) 2017 Intel Deutschland GmbH */ @@ -224,6 +224,9 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, cmd.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); } + if (ver == 6) + cmd.puncture_mask = cpu_to_le16(chandef->punctured); + ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } else if (ver < 3) { From 653a90f6b226d8f95d06cb6c0bf5473f99582cc9 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 18 Feb 2024 19:51:45 +0200 Subject: [PATCH 1374/2255] wifi: iwlwifi: bump FW API to 90 for BZ/SC devices Start supporting API version 90 for new devices. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.21cf0b641f12.I2f9196191f1ea78e96e92f9db8ecb3cc9bbfd9b3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 14c5cc265fe3..18b1f2cf08cc 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 89 +#define IWL_BZ_UCODE_API_MAX 90 /* 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 dbbcb2d0968c..9b79279fd76c 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 89 +#define IWL_SC_UCODE_API_MAX 90 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 82 From e2967e83921a3748116b8e330cbbb794817ceee8 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Feb 2024 19:51:46 +0200 Subject: [PATCH 1375/2255] wifi: iwlwifi: mvm: unlock mvm if there is no primary link At that point in the code mvm->mutex has already been taken, so jump to out_noreset in order to unlock before returning the error. Fixes: 8c9bef26e98b ("wifi: iwlwifi: mvm: d3: implement suspend with MLO") Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.21de6e68d9e5.I3c0ebe577dec6b26ab6b4eac48035d6f35a8b0f8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 9830a3c3600b..6d5ed79b9fff 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1290,8 +1290,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); mvm_link = mvmvif->link[primary_link]; - if (WARN_ON_ONCE(!mvm_link)) - return -EINVAL; + if (WARN_ON_ONCE(!mvm_link)) { + ret = -EINVAL; + goto out_noreset; + } if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) { /* if we're not associated, this must be netdetect */ From f63280ab7aa2a5ccd39a9e931ad2dc311ddc7e8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:48 +0200 Subject: [PATCH 1376/2255] wifi: iwlwifi: api: fix kernel-doc reference This is for iwl_tas_config_cmd_v4, not iwl_tas_config_cmd_v3. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.5475d49bce86.I640a12bc799612e82c3e7a4d628bbb7760511297@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 8c886569f01e..58034dfa7e70 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.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 */ @@ -462,7 +462,7 @@ struct iwl_tas_config_cmd_v3 { } __packed; /* TAS_CONFIG_CMD_API_S_VER_3 */ /** - * struct iwl_tas_config_cmd_v3 - configures the TAS + * struct iwl_tas_config_cmd_v4 - configures the TAS * @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 From ccb2f72cee5fb3421cc71e5d07bc46a57accd7ba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Feb 2024 19:51:49 +0200 Subject: [PATCH 1377/2255] wifi: iwlwifi: iwl-fh.h: fix kernel-doc issues Clean up kernel-doc in iwl-fh.h. In one case, rename the (otherwise unused) struct member to have the correct name. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.4a342ac06f0b.I604ea964a094b43df0ab29b06231c2f42d6bd79b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 36 ++++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index e0400ba2ab74..6ba374efaacb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2021, 2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021, 2023-2024 Intel Corporation * Copyright (C) 2015-2017 Intel Deutschland GmbH */ #ifndef __iwl_fh_h__ @@ -570,18 +570,19 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, /** * struct iwl_rb_status - reserve buffer status * host memory mapped FH registers - * @closed_rb_num [0:11] - Indicates the index of the RB which was closed - * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed - * @finished_rb_num [0:11] - Indicates the index of the current RB + * @closed_rb_num: [0:11] Indicates the index of the RB which was closed + * @closed_fr_num: [0:11] Indicates the index of the RX Frame which was closed + * @finished_rb_num: [0:11] Indicates the index of the current RB * in which the last frame was written to - * @finished_fr_num [0:11] - Indicates the index of the RX Frame + * @finished_fr_num: [0:11] Indicates the index of the RX Frame * which was transferred + * @__spare: reserved */ struct iwl_rb_status { __le16 closed_rb_num; __le16 closed_fr_num; __le16 finished_rb_num; - __le16 finished_fr_nam; + __le16 finished_fr_num; __le32 __spare; } __packed; @@ -651,15 +652,15 @@ struct iwl_tfd_tb { * * This structure contains dma address and length of transmission address * - * @tb_len length of the tx buffer - * @addr 64 bits dma address + * @tb_len: length of the tx buffer + * @addr: 64 bits dma address */ struct iwl_tfh_tb { __le16 tb_len; __le64 addr; } __packed; -/** +/* * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. * Both driver and device share these circular buffers, each of which must be * contiguous 256 TFDs. @@ -698,10 +699,11 @@ struct iwl_tfd { /** * struct iwl_tfh_tfd - Transmit Frame Descriptor (TFD) - * @ num_tbs 0-4 number of active tbs - * 5 -15 reserved - * @ tbs[25] transmit frame buffer descriptors - * @ __pad padding + * @num_tbs: + * 0-4 number of active tbs + * 5-15 reserved + * @tbs: transmit frame buffer descriptors + * @__pad: padding */ struct iwl_tfh_tfd { __le16 num_tbs; @@ -718,10 +720,12 @@ struct iwl_tfh_tfd { * struct iwlagn_schedq_bc_tbl scheduler byte count table * base physical address provided by SCD_DRAM_BASE_ADDR * For devices up to 22000: - * @tfd_offset 0-12 - tx command byte count + * @tfd_offset: + * For devices up to 22000: + * 0-12 - tx command byte count * 12-16 - station index - * For 22000: - * @tfd_offset 0-12 - tx command byte count + * For 22000: + * 0-12 - tx command byte count * 12-13 - number of 64 byte chunks * 14-16 - reserved */ From 740dfecc336bc79789b992f260e1a5bdfbdf2bfa Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 18 Feb 2024 19:51:51 +0200 Subject: [PATCH 1378/2255] wifi: iwlwifi: handle per-phy statistics from fw In the operational statistics notifications (both old and new API) the driver receives the statistics per phy. currently this statistics wasn't handled because they wasn't needed. Now the channel_load_by_us parameter in these statistics will be used for the link grading calculation (implemented in another patch), so store its value in phy_ctxt. Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://msgid.link/20240218194912.e84f975b69ee.Ibbc7817135827e45adaaa47b796be165f9f1ca48@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index fcae5199ac90..c85d9e460ad2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -106,6 +106,7 @@ struct iwl_mvm_phy_ctxt { /* track for RLC config command */ u32 center_freq1; bool rlc_disabled; + u32 channel_load_by_us; }; struct iwl_mvm_time_event_data { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 72df41996464..b1add7942c5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.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 */ @@ -752,6 +752,19 @@ iwl_mvm_update_tcm_from_stats(struct iwl_mvm *mvm, __le32 *air_time_le, spin_unlock(&mvm->tcm.lock); } +static void iwl_mvm_handle_per_phy_stats(struct iwl_mvm *mvm, + struct iwl_stats_ntfy_per_phy *per_phy) +{ + int i; + + for (i = 0; i < NUM_PHY_CTX; i++) { + if (!mvm->phy_ctxts[i].ref) + continue; + mvm->phy_ctxts[i].channel_load_by_us = + le32_to_cpu(per_phy[i].channel_load_by_us); + } +} + static void iwl_mvm_stats_ver_15(struct iwl_mvm *mvm, struct iwl_statistics_operational_ntfy *stats) @@ -766,6 +779,7 @@ iwl_mvm_stats_ver_15(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_stat_iterator_all_macs, &data); + iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy); } static void @@ -942,6 +956,7 @@ void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm, ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter, average_energy); + iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy); } void iwl_mvm_handle_rx_system_oper_part1_stats(struct iwl_mvm *mvm, From 32a1bbd3fe3ff21deca67e3508ab3cc05931ccd2 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sun, 18 Feb 2024 19:51:52 +0200 Subject: [PATCH 1379/2255] wifi: iwlwifi: load b0 version of ucode for HR1/HR2 load b0 version of ucode for both a0 and b0 step of HR RF. Signed-off-by: Mukesh Sisodiya Signed-off-by: Miri Korenblit Link: https://msgid.link/20240218194912.0166f5d2d5d2.I34c1d46aefd70b34c1c75cea67792bc5ec8bc285@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 91e974de0ade..4696d73c8971 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-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 */ @@ -187,6 +187,7 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) case IWL_CFG_RF_TYPE_HR1: case IWL_CFG_RF_TYPE_HR2: rf = "hr"; + rf_step = 'b'; break; case IWL_CFG_RF_TYPE_GF: rf = "gf"; From 4f4d8be6dc37a28b8655d03918680d8ea8c82f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Thu, 15 Feb 2024 15:13:52 +0100 Subject: [PATCH 1380/2255] wifi: nl80211: force WLAN_AKM_SUITE_SAE in big endian in NL80211_CMD_EXTERNAL_AUTH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-space supplicant (observed at least on wpa_supplicant) historically parses the NL80211_ATTR_AKM_SUITES from the NL80211_CMD_EXTERNAL_AUTH message as big endian _only_ when its value is WLAN_AKM_SUITE_SAE, while processing anything else in host endian. This behavior makes any driver relying on SAE external auth to switch AKM suite to big endian if it is WLAN_AKM_SUITE_SAE. A fix bringing compatibility with both endianness has been brought into wpa_supplicant, however we must keep compatibility with older versions, while trying to reduce the occurences of this manual conversion in wireless drivers. Add the be32 conversion specifically on WLAN_AKM_SUITE_SAE in nl80211 layer to keep compatibility with older wpa_supplicant versions. Suggested-by: Johannes Berg Signed-off-by: Alexis Lothoré Link: https://msgid.link/20240215-nl80211_fix_akm_suites_endianness-v1-1-57e902632f9d@bootlin.com Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index dd9a092b6bab..ab6d98cdac13 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -20132,9 +20132,26 @@ int cfg80211_external_auth_request(struct net_device *dev, if (!hdr) goto nla_put_failure; + /* Some historical mistakes in drivers <-> userspace interface (notably + * between drivers and wpa_supplicant) led to a big-endian conversion + * being needed on NL80211_ATTR_AKM_SUITES _only_ when its value is + * WLAN_AKM_SUITE_SAE. This is now fixed on userspace side, but for the + * benefit of older wpa_supplicant versions, send this particular value + * in big-endian. Note that newer wpa_supplicant will also detect this + * particular value in big endian still, so it all continues to work. + */ + if (params->key_mgmt_suite == WLAN_AKM_SUITE_SAE) { + if (nla_put_be32(msg, NL80211_ATTR_AKM_SUITES, + cpu_to_be32(WLAN_AKM_SUITE_SAE))) + goto nla_put_failure; + } else { + if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, + params->key_mgmt_suite)) + goto nla_put_failure; + } + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || - nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) || nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION, params->action) || nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) || From 81830c8f809c01f3780dc33f7d951be8e146ced1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Feb 2024 12:48:18 +0100 Subject: [PATCH 1381/2255] wifi: nl80211: refactor parsing CSA offsets The CSA offset parsing happens the same way for all of beacon template offsets, probe response template offsets and TX offsets (for using during probe response TX from userspace directly). Refactor the parsing here. There's an additional check this introduces, which is that the number of counters in TX offsets doesn't exceed the driver capability, but as only two counters are used at most for anything, this is hopefully OK. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 137 +++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 81 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ab6d98cdac13..bb65b684e26a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10048,6 +10048,42 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb, return 0; } +static int nl80211_parse_counter_offsets(struct cfg80211_registered_device *rdev, + const u8 *data, size_t datalen, + int first_count, struct nlattr *attr, + const u16 **offsets, unsigned int *n_offsets) +{ + int i; + + *n_offsets = 0; + + if (!attr) + return 0; + + if (!nla_len(attr) || (nla_len(attr) % sizeof(u16))) + return -EINVAL; + + *n_offsets = nla_len(attr) / sizeof(u16); + if (rdev->wiphy.max_num_csa_counters && + (*n_offsets > rdev->wiphy.max_num_csa_counters)) + return -EINVAL; + + *offsets = nla_data(attr); + + /* sanity checks - counters should fit and be the same */ + for (i = 0; i < *n_offsets; i++) { + u16 offset = (*offsets)[i]; + + if (offset >= datalen) + return -EINVAL; + + if (first_count != -1 && data[offset] != first_count) + return -EINVAL; + } + + return 0; +} + static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -10059,7 +10095,6 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) int err; bool need_new_beacon = false; bool need_handle_dfs_flag = true; - int len, i; u32 cs_count; if (!rdev->ops->channel_switch || @@ -10144,72 +10179,23 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) goto free; } - len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]); - if (!len || (len % sizeof(u16))) { - err = -EINVAL; + err = nl80211_parse_counter_offsets(rdev, params.beacon_csa.tail, + params.beacon_csa.tail_len, + params.count, + csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON], + ¶ms.counter_offsets_beacon, + ¶ms.n_counter_offsets_beacon); + if (err) goto free; - } - params.n_counter_offsets_beacon = len / sizeof(u16); - if (rdev->wiphy.max_num_csa_counters && - (params.n_counter_offsets_beacon > - rdev->wiphy.max_num_csa_counters)) { - err = -EINVAL; + err = nl80211_parse_counter_offsets(rdev, params.beacon_csa.probe_resp, + params.beacon_csa.probe_resp_len, + params.count, + csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP], + ¶ms.counter_offsets_presp, + ¶ms.n_counter_offsets_presp); + if (err) goto free; - } - - params.counter_offsets_beacon = - nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]); - - /* sanity checks - counters should fit and be the same */ - for (i = 0; i < params.n_counter_offsets_beacon; i++) { - u16 offset = params.counter_offsets_beacon[i]; - - if (offset >= params.beacon_csa.tail_len) { - err = -EINVAL; - goto free; - } - - if (params.beacon_csa.tail[offset] != params.count) { - err = -EINVAL; - goto free; - } - } - - if (csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]) { - len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]); - if (!len || (len % sizeof(u16))) { - err = -EINVAL; - goto free; - } - - params.n_counter_offsets_presp = len / sizeof(u16); - if (rdev->wiphy.max_num_csa_counters && - (params.n_counter_offsets_presp > - rdev->wiphy.max_num_csa_counters)) { - err = -EINVAL; - goto free; - } - - params.counter_offsets_presp = - nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]); - - /* sanity checks - counters should fit and be the same */ - for (i = 0; i < params.n_counter_offsets_presp; i++) { - u16 offset = params.counter_offsets_presp[i]; - - if (offset >= params.beacon_csa.probe_resp_len) { - err = -EINVAL; - goto free; - } - - if (params.beacon_csa.probe_resp[offset] != - params.count) { - err = -EINVAL; - goto free; - } - } - } skip_beacons: err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); @@ -12638,23 +12624,12 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); - if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) { - int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]); - int i; - - if (len % sizeof(u16)) - return -EINVAL; - - params.n_csa_offsets = len / sizeof(u16); - params.csa_offsets = - nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]); - - /* check that all the offsets fit the frame */ - for (i = 0; i < params.n_csa_offsets; i++) { - if (params.csa_offsets[i] >= params.len) - return -EINVAL; - } - } + err = nl80211_parse_counter_offsets(rdev, NULL, params.len, -1, + info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX], + ¶ms.csa_offsets, + ¶ms.n_csa_offsets); + if (err) + return err; if (!params.dont_wait_for_ack) { msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); From 00413dd3641408f5728694d794478613fbe06c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Thu, 15 Feb 2024 15:13:53 +0100 Subject: [PATCH 1382/2255] wifi: wilc1000: remove AKM suite be32 conversion for external auth request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver currently raises the following sparse warning: [...] cfg80211.c:360:42: warning: incorrect type in assignment (different base types) [...] cfg80211.c:360:42: expected unsigned int key_mgmt_suite [...] cfg80211.c:360:42: got restricted __be32 [usertype] CHECK drivers/net/wireless/microchip/wilc1000/netdev.c This conversion was needed because historically the external supplicant (observed with wpa_supplicant) expects AKM suite as big endian in NL80211_CMD_EXTERNAL_AUTH message when the AKM suite is WLAN_AKM_SUITE_SAE. This is not needed anymore: - new (to be released) versions of wpa_supplicant now reads it in host endian _while_ keeping compatibility for older drivers - for new drivers used with current/old wpa_supplicant, this conversion has been added to nl80211 to force big endian when the AKM suite is WLAN_AKM_SUITE_SAE Remove this not-needed-anymore conversion to fix the sparse warning. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308290615.lUTIgqUl-lkp@intel.com/ Tested-on: WILC1000 hwB SPI WILC_WIFI_FW_REL_16_1-13452 Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240215-nl80211_fix_akm_suites_endianness-v1-2-57e902632f9d@bootlin.com --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index 33f8e3a41937..089102ed9ae5 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -356,7 +356,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, memcpy(vif->auth.ssid.ssid, sme->ssid, sme->ssid_len); vif->auth.ssid.ssid_len = sme->ssid_len; } - vif->auth.key_mgmt_suite = cpu_to_be32(sme->crypto.akm_suites[0]); + vif->auth.key_mgmt_suite = sme->crypto.akm_suites[0]; ether_addr_copy(vif->auth.bssid, sme->bssid); break; From 8ca4cdef93297c9b9bf08da39bc940bd20acbb94 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Thu, 15 Feb 2024 20:57:59 +0200 Subject: [PATCH 1383/2255] wifi: rtlwifi: rtl8192cu: Fix TX aggregation rtl8192cu is checking rtl_mac.tids when deciding if it should enable aggregation. This is wrong because rtl_mac.tids is not initialised anywhere. Check rtl_sta_info.tids instead, which is initialised. Also, when enabling aggregation also enable RTS. The vendor driver does this, my router does this. It seems like the thing to do. Also also, it seems right to set the AMPDU density only when enabling aggregation. Also also also, delete the unused member rtl_mac.tids and the unused macros RTL_AGG_ON and RTL_AGG_OFF. Naturally, with working AMPDU the download/upload speeds are better. Before: 59/32 Mbps. After: 68/46 Mbps. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/4e936334-5f81-403f-a495-0628ebfb6903@gmail.com --- .../wireless/realtek/rtlwifi/rtl8192cu/trx.c | 29 +++++++++++-------- .../wireless/realtek/rtlwifi/rtl8192cu/trx.h | 2 -- drivers/net/wireless/realtek/rtlwifi/wifi.h | 3 -- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index 4856ed40005b..aa702ba7c9f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -482,8 +482,9 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 *qc = ieee80211_get_qos_ctl(hdr); - u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + struct rtl_sta_info *sta_entry; + u8 agg_state = RTL_AGG_STOP; + u8 ampdu_density = 0; u16 seq_number; __le16 fc = hdr->frame_control; u8 rate_flag = info->control.rates[0].flags; @@ -492,6 +493,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, skb_get_queue_mapping(skb)); u8 *txdesc8; __le32 *txdesc; + u8 tid; seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); @@ -505,10 +507,21 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, set_tx_desc_tx_rate(txdesc, tcb_desc->hw_rate); if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) set_tx_desc_data_shortgi(txdesc, 1); - if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && - info->flags & IEEE80211_TX_CTL_AMPDU) { + + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid = ieee80211_get_tid(hdr); + agg_state = sta_entry->tids[tid].agg.agg_state; + ampdu_density = sta->deflink.ht_cap.ampdu_density; + } + + if (agg_state == RTL_AGG_OPERATIONAL && + info->flags & IEEE80211_TX_CTL_AMPDU) { set_tx_desc_agg_enable(txdesc, 1); set_tx_desc_max_agg_num(txdesc, 0x14); + set_tx_desc_ampdu_density(txdesc, ampdu_density); + tcb_desc->rts_enable = 1; + tcb_desc->rts_rate = DESC_RATE24M; } else { set_tx_desc_agg_break(txdesc, 1); } @@ -543,14 +556,6 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, set_tx_desc_data_bw(txdesc, 0); set_tx_desc_data_sc(txdesc, 0); } - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); - if (sta) { - u8 ampdu_density = sta->deflink.ht_cap.ampdu_density; - - set_tx_desc_ampdu_density(txdesc, ampdu_density); - } - rcu_read_unlock(); if (info->control.hw_key) { struct ieee80211_key_conf *keyconf = info->control.hw_key; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h index 8678fa0043f4..09e61dc0f317 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h @@ -10,8 +10,6 @@ #define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */ #define RX_DRV_INFO_SIZE_UNIT 8 -#define RTL_AGG_ON 1 - enum usb_rx_agg_mode { USB_RX_AGG_DISABLE, USB_RX_AGG_DMA, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 01df00a43cdb..f388d13e2ba8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1397,8 +1397,6 @@ struct rtl_phy { #define RTL_AGG_PROGRESS 1 #define RTL_AGG_START 2 #define RTL_AGG_OPERATIONAL 3 -#define RTL_AGG_OFF 0 -#define RTL_AGG_ON 1 #define RTL_RX_AGG_START 1 #define RTL_RX_AGG_STOP 0 #define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 @@ -1473,7 +1471,6 @@ struct rtl_mac { enum nl80211_iftype opmode; /*Probe Beacon management */ - struct rtl_tid_data tids[MAX_TID_COUNT]; enum rtl_link_state link_state; int n_channels; From 513c559ca9f05394da79fbf20a8f89eec5f53dce Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 16 Feb 2024 11:39:23 +0800 Subject: [PATCH 1384/2255] wifi: rtl8xxxu: check vif before using in rtl8xxxu_tx() The 'vif' is from tx_info of SKB, and other codes check 'vif' before using, which raises smatch warnings: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:5656 rtl8xxxu_tx() warn: variable dereferenced before check 'vif' (see line 5553) Compile tested only. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240216033923.34683-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index db5041d23938..efddbe402f0d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5550,7 +5550,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct rtl8xxxu_tx_urb *tx_urb; struct ieee80211_sta *sta = NULL; struct ieee80211_vif *vif = tx_info->control.vif; - struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; + struct rtl8xxxu_vif *rtlvif = vif ? (struct rtl8xxxu_vif *)vif->drv_priv : NULL; struct device *dev = &priv->udev->dev; u32 queue, rts_rate; u16 pktlen = skb->len; @@ -5621,7 +5621,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, default: break; } - if (bmc && rtlvif->hw_key_idx != 0xff) { + if (bmc && rtlvif && rtlvif->hw_key_idx != 0xff) { tx_desc->txdw1 |= cpu_to_le32(TXDESC_EN_DESC_ID); macid = rtlvif->hw_key_idx; } From 9208e85c62720608aa6ec6e4265b584a48fb43b0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 16 Feb 2024 11:39:49 +0800 Subject: [PATCH 1385/2255] wifi: rtlwifi: set initial values for unexpected cases of USB endpoint priority Map USB endpoints to hardware and AC queues according to number of USB endpoints. However, original only give a warning for unexpected cases but initial values are not given. Then, smatch warns: drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:642 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuelow'. drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:644 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuehi'. drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:649 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuehi'. drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c:650 _rtl92cu_init_chipn_two_out_ep_priority() error: uninitialized symbol 'valuelow'. The regular selection is high and low queues, so move default (unexpected) case along with that. Compile tested only. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240216033949.34765-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index 5ec0eb8773a5..4217c9a08d01 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -622,6 +622,9 @@ static void _rtl92cu_init_chipn_two_out_ep_priority(struct ieee80211_hw *hw, u16 valuelow; switch (queue_sel) { + default: + WARN_ON(1); + fallthrough; case (TX_SELE_HQ | TX_SELE_LQ): valuehi = QUEUE_HIGH; valuelow = QUEUE_LOW; @@ -634,9 +637,6 @@ static void _rtl92cu_init_chipn_two_out_ep_priority(struct ieee80211_hw *hw, valuehi = QUEUE_HIGH; valuelow = QUEUE_NORMAL; break; - default: - WARN_ON(1); - break; } if (!wmm_enable) { beq = valuelow; From 32167707aa5e7ae4b160c18be79d85a7b4fdfcfb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 16 Feb 2024 22:36:49 +0100 Subject: [PATCH 1386/2255] wifi: brcmfmac: Add DMI nvram filename quirk for ACEPC W5 Pro The ACEPC W5 Pro HDMI stick contains quite generic names in the sys_vendor and product_name DMI strings, without this patch brcmfmac will try to load: "brcmfmac43455-sdio.$(DEFAULT_STRING)-$(DEFAULT_STRING).txt" as nvram file which is both too generic and messy with the $ symbols in the name. The ACEPC W5 Pro uses the same Ampak AP6255 module as the ACEPC T8 and the nvram for the T8 is already in linux-firmware, so point the new DMI nvram filename quirk to the T8 nvram file. Signed-off-by: Hans de Goede Acked-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240216213649.251718-1-hdegoede@redhat.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c index 86ff174936a9..c3a602197662 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c @@ -82,6 +82,15 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&acepc_t8_data, }, + { + /* ACEPC W5 Pro Cherry Trail Z8350 HDMI stick, same wifi as the T8 */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"), + DMI_MATCH(DMI_CHASSIS_TYPE, "3"), + DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), + }, + .driver_data = (void *)&acepc_t8_data, + }, { /* Chuwi Hi8 Pro with D2D3_Hi8Pro.233 BIOS */ .matches = { From f3ec643947634bed41b97bd56b248f7c78498eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9?= Date: Sat, 17 Feb 2024 14:22:41 +0100 Subject: [PATCH 1387/2255] wifi: wilc1000: revert reset line logic flip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fcf690b0b47494df51d214db5c5a714a400b0257. When using a wilc1000 chip over a spi bus, users can optionally define a reset gpio and a chip enable gpio. The reset line of wilc1000 is active low, so to hold the chip in reset, a low (physical) value must be applied. The corresponding device tree binding documentation was introduced by commit f31ee3c0a555 ("wilc1000: Document enable-gpios and reset-gpios properties") and correctly indicates that the reset line is an active-low signal. The corresponding driver part, brought by commit ec031ac4792c ("wilc1000: Add reset/enable GPIO support to SPI driver") was applying the correct logic. But commit fcf690b0b474 ("wifi: wilc1000: use correct sequence of RESET for chip Power-UP/Down") eventually flipped this logic and started misusing the gpiod APIs, applying an inverted logic when powering up/down the chip (for example, setting the reset line to a logic "1" during power up, which in fact asserts the reset line when device tree describes the reset line as GPIO_ACTIVE_LOW). As a consequence, any platform currently using the driver in SPI mode must use a faulty reset line description in device tree, or else chip will be maintained in reset and will not even allow to bring up the chip. Fix reset line usage by inverting back the gpiod APIs usage, setting the reset line to the logic value "0" when powering the chip, and the logic value "1" when powering off the chip. Fixes: fcf690b0b474 ("wifi: wilc1000: use correct sequence of RESET for chip Power-UP/Down") Signed-off-by: Alexis Lothoré Acked-by: Conor Dooley Acked-by: Ajay Singh Signed-off-by: Kalle Valo Link: https://msgid.link/20240217-wilc_1000_reset_line-v2-1-b216f433d7d5@bootlin.com --- drivers/net/wireless/microchip/wilc1000/spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 3c4451535c8a..61c3572ce321 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -194,11 +194,11 @@ static void wilc_wlan_power(struct wilc *wilc, bool on) /* assert ENABLE: */ gpiod_set_value(gpios->enable, 1); mdelay(5); - /* assert RESET: */ - gpiod_set_value(gpios->reset, 1); - } else { /* deassert RESET: */ gpiod_set_value(gpios->reset, 0); + } else { + /* assert RESET: */ + gpiod_set_value(gpios->reset, 1); /* deassert ENABLE: */ gpiod_set_value(gpios->enable, 0); } From 01dbd7d8720a0cc97dad5e70ec674dacdc66cf3c Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 20 Feb 2024 15:11:02 -0800 Subject: [PATCH 1388/2255] selftests/bpf: Remove intermediate test files. The test of linking process creates several intermediate files. Remove them once the build is over. This reduces the number of files in selftests/bpf/ directory from ~4400 to ~2600. Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20240220231102.49090-1-alexei.starovoitov@gmail.com --- tools/testing/selftests/bpf/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index dbb8c5f94f34..9be69ff701ba 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -536,6 +536,7 @@ $(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT) $(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) $(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@ $(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h) + $(Q)rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) $(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT) $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@) @@ -544,6 +545,7 @@ $(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT) $(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o) $(Q)diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) $(Q)$$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ + $(Q)rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) $(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_BPF_OBJS) $(BPFTOOL) | $(TRUNNER_OUTPUT) $$(call msg,LINK-BPF,$(TRUNNER_BINARY),$$(@:.skel.h=.bpf.o)) @@ -554,6 +556,7 @@ $(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_BPF_OBJS) $(BPFTOOL) | $(TRUNNER_OUTPUT) $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@) $(Q)$$(BPFTOOL) gen skeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$@ $(Q)$$(BPFTOOL) gen subskeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$(@:.skel.h=.subskel.h) + $(Q)rm -f $$(@:.skel.h=.linked1.o) $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o) endif # ensure we set up tests.h header generation rule just once From a3c70a3cf11eb4b6409afc2cce1a3747e1dfe96f Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 20 Feb 2024 15:50:01 -0800 Subject: [PATCH 1389/2255] bpf: Shrink size of struct bpf_map/bpf_array. Back in 2018 the commit be95a845cc44 ("bpf: avoid false sharing of map refcount with max_entries") added ____cacheline_aligned to "struct bpf_map" to make sure that fields like refcnt don't share a cache line with max_entries that is used to bounds check map access. That was done to make spectre style attacks harder. The main mitigation is done via code similar to array_index_nospec(), of course. This was an additional precaution. It increased the size of "struct bpf_map" a little, but it's affect on all other maps (like array) is significant, since "struct bpf_map" is typically the first member in other map types. Undo this ____cacheline_aligned tag. Instead move freeze_mutex field around, so that refcnt and max_entries are still in different cache lines. The main effect is seen in sizeof(struct bpf_array) that reduces from 320 to 248 bytes. BEFORE: struct bpf_map { const struct bpf_map_ops * ops; /* 0 8 */ ... char name[16]; /* 96 16 */ /* XXX 16 bytes hole, try to pack */ /* --- cacheline 2 boundary (128 bytes) --- */ atomic64_t refcnt __attribute__((__aligned__(64))); /* 128 8 */ ... /* size: 256, cachelines: 4, members: 30 */ /* sum members: 232, holes: 1, sum holes: 16 */ /* padding: 8 */ /* paddings: 1, sum paddings: 2 */ } __attribute__((__aligned__(64))); struct bpf_array { struct bpf_map map; /* 0 256 */ ... /* size: 320, cachelines: 5, members: 5 */ /* padding: 48 */ /* paddings: 1, sum paddings: 8 */ } __attribute__((__aligned__(64))); AFTER: struct bpf_map { /* size: 232, cachelines: 4, members: 30 */ /* paddings: 1, sum paddings: 2 */ /* last cacheline: 40 bytes */ }; struct bpf_array { /* size: 248, cachelines: 4, members: 5 */ /* last cacheline: 56 bytes */ }; Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240220235001.57411-1-alexei.starovoitov@gmail.com --- include/linux/bpf.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index c7aa99b44dbd..814dc913a968 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -251,10 +251,7 @@ struct bpf_list_node_kern { } __attribute__((aligned(8))); struct bpf_map { - /* The first two cachelines with read-mostly members of which some - * are also accessed in fast-path (e.g. ops, max_entries). - */ - const struct bpf_map_ops *ops ____cacheline_aligned; + const struct bpf_map_ops *ops; struct bpf_map *inner_map_meta; #ifdef CONFIG_SECURITY void *security; @@ -276,17 +273,14 @@ struct bpf_map { struct obj_cgroup *objcg; #endif char name[BPF_OBJ_NAME_LEN]; - /* The 3rd and 4th cacheline with misc members to avoid false sharing - * particularly with refcounting. - */ - atomic64_t refcnt ____cacheline_aligned; + struct mutex freeze_mutex; + atomic64_t refcnt; atomic64_t usercnt; /* rcu is used before freeing and work is only used during freeing */ union { struct work_struct work; struct rcu_head rcu; }; - struct mutex freeze_mutex; atomic64_t writecnt; /* 'Ownership' of program-containing map is claimed by the first program * that is going to use this map or by the first program which FD is From 59f95f5da813db6aee652feafebc7436a3a73b89 Mon Sep 17 00:00:00 2001 From: Raju Lakkaraju Date: Fri, 16 Feb 2024 11:14:35 +0530 Subject: [PATCH 1390/2255] net: phy: mxl-gpy: fill in possible_interfaces for GPY21x chipset Fill in the possible_interfaces member. GPY21x phys support the SGMII and 2500base-X interfaces Signed-off-by: Raju Lakkaraju Link: https://lore.kernel.org/r/20240216054435.22380-1-Raju.Lakkaraju@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mxl-gpy.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index ea1073adc5a1..b2d36a3a96f1 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -274,6 +274,14 @@ static int gpy_config_init(struct phy_device *phydev) return ret < 0 ? ret : 0; } +static int gpy21x_config_init(struct phy_device *phydev) +{ + __set_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces); + __set_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces); + + return gpy_config_init(phydev); +} + static int gpy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -867,7 +875,7 @@ static struct phy_driver gpy_drivers[] = { .phy_id_mask = PHY_ID_GPY21xB_MASK, .name = "Maxlinear Ethernet GPY211B", .get_features = genphy_c45_pma_read_abilities, - .config_init = gpy_config_init, + .config_init = gpy21x_config_init, .probe = gpy_probe, .suspend = genphy_suspend, .resume = genphy_resume, @@ -884,7 +892,7 @@ static struct phy_driver gpy_drivers[] = { PHY_ID_MATCH_MODEL(PHY_ID_GPY211C), .name = "Maxlinear Ethernet GPY211C", .get_features = genphy_c45_pma_read_abilities, - .config_init = gpy_config_init, + .config_init = gpy21x_config_init, .probe = gpy_probe, .suspend = genphy_suspend, .resume = genphy_resume, @@ -902,7 +910,7 @@ static struct phy_driver gpy_drivers[] = { .phy_id_mask = PHY_ID_GPY21xB_MASK, .name = "Maxlinear Ethernet GPY212B", .get_features = genphy_c45_pma_read_abilities, - .config_init = gpy_config_init, + .config_init = gpy21x_config_init, .probe = gpy_probe, .suspend = genphy_suspend, .resume = genphy_resume, @@ -919,7 +927,7 @@ static struct phy_driver gpy_drivers[] = { PHY_ID_MATCH_MODEL(PHY_ID_GPY212C), .name = "Maxlinear Ethernet GPY212C", .get_features = genphy_c45_pma_read_abilities, - .config_init = gpy_config_init, + .config_init = gpy21x_config_init, .probe = gpy_probe, .suspend = genphy_suspend, .resume = genphy_resume, @@ -937,7 +945,7 @@ static struct phy_driver gpy_drivers[] = { .phy_id_mask = PHY_ID_GPYx15B_MASK, .name = "Maxlinear Ethernet GPY215B", .get_features = genphy_c45_pma_read_abilities, - .config_init = gpy_config_init, + .config_init = gpy21x_config_init, .probe = gpy_probe, .suspend = genphy_suspend, .resume = genphy_resume, @@ -954,7 +962,7 @@ static struct phy_driver gpy_drivers[] = { PHY_ID_MATCH_MODEL(PHY_ID_GPY215C), .name = "Maxlinear Ethernet GPY215C", .get_features = genphy_c45_pma_read_abilities, - .config_init = gpy_config_init, + .config_init = gpy21x_config_init, .probe = gpy_probe, .suspend = genphy_suspend, .resume = genphy_resume, From 953cc643329b38434bb7d6206951d1a48016e38b Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:38 +0100 Subject: [PATCH 1391/2255] net: phy: Add BaseT1 auto-negotiation constants Added constants for advertising 100BT1 and 1000BT1 in register BASE-T1 auto-negotiation advertisement register [31:16] (Register 7.515) Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-2-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- include/uapi/linux/mdio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index 3c9097502403..c0c8ec995b06 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -350,6 +350,8 @@ /* BASE-T1 auto-negotiation advertisement register [31:16] */ #define MDIO_AN_T1_ADV_M_B10L 0x4000 /* device is compatible with 10BASE-T1L */ +#define MDIO_AN_T1_ADV_M_1000BT1 0x0080 /* advertise 1000BASE-T1 */ +#define MDIO_AN_T1_ADV_M_100BT1 0x0020 /* advertise 100BASE-T1 */ #define MDIO_AN_T1_ADV_M_MST 0x0010 /* advertise master preference */ /* BASE-T1 auto-negotiation advertisement register [47:32] */ From ac0c530619cefa68fba816dabbcf6f4ffbf60c3d Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:39 +0100 Subject: [PATCH 1392/2255] net: phy: Support 100/1000BT1 linkmode advertisements Extend helper functions mii_t1_adv_m_mod_linkmode_t and linkmode_adv_to_mii_t1_adv_m_t to support 100BT1 and 1000BT1 linkmode advertisements. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-3-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- include/linux/mdio.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/mdio.h b/include/linux/mdio.h index fd8ff310f9eb..68f8d2e970d4 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -373,6 +373,10 @@ static inline void mii_t1_adv_m_mod_linkmode_t(unsigned long *advertising, u32 l { linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, advertising, lpa & MDIO_AN_T1_ADV_M_B10L); + linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, + advertising, lpa & MDIO_AN_T1_ADV_M_100BT1); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, + advertising, lpa & MDIO_AN_T1_ADV_M_1000BT1); } /** @@ -409,6 +413,10 @@ static inline u32 linkmode_adv_to_mii_t1_adv_m_t(unsigned long *advertising) if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, advertising)) result |= MDIO_AN_T1_ADV_M_B10L; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, advertising)) + result |= MDIO_AN_T1_ADV_M_100BT1; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, advertising)) + result |= MDIO_AN_T1_ADV_M_1000BT1; return result; } From 8d9a577f0eea92f1b5b82874eabf93b505d02c78 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:40 +0100 Subject: [PATCH 1393/2255] net: phy: c45: detect 100/1000BASE-T1 linkmode advertisements Set 100BT1 and 1000BT1 linkmode advertisement bits to adv_l_mask to enable detection. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-4-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy-c45.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index c69568e7695e..fa5145c9328e 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -208,7 +208,8 @@ static int genphy_c45_baset1_an_config_aneg(struct phy_device *phydev) adv_l_mask = MDIO_AN_T1_ADV_L_FORCE_MS | MDIO_AN_T1_ADV_L_PAUSE_CAP | MDIO_AN_T1_ADV_L_PAUSE_ASYM; - adv_m_mask = MDIO_AN_T1_ADV_M_MST | MDIO_AN_T1_ADV_M_B10L; + adv_m_mask = MDIO_AN_T1_ADV_M_1000BT1 | MDIO_AN_T1_ADV_M_100BT1 | + MDIO_AN_T1_ADV_M_MST | MDIO_AN_T1_ADV_M_B10L; switch (phydev->master_slave_set) { case MASTER_SLAVE_CFG_MASTER_FORCE: From 944767b00dd4b2a4e01c8e6709d5f2d779b6cd51 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:41 +0100 Subject: [PATCH 1394/2255] net: phy: marvell-88q2xxx: fix typos Rename mv88q2xxxx_get_sqi to mv88q2xxx_get_sqi and mv88q2xxxx_get_sqi_max to mv88q2xxx_get_sqi_max. Fix linebreaks and use everywhere hexadecimal numbers written with lowercase letters instead of mixing it up. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-5-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 1c3ff77de56b..dcebb4643aff 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -14,7 +14,7 @@ #define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT 0x8000 #define MDIO_MMD_PCS_MV_100BT1_STAT1 33032 -#define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00FF +#define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00ff #define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LINK 0x0200 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX 0x1000 @@ -27,6 +27,8 @@ #define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK 0x0004 #define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE 0x0008 +#define MDIO_MMD_PCS_MV_RX_STAT 33328 + static int mv88q2xxx_soft_reset(struct phy_device *phydev) { int ret; @@ -63,7 +65,8 @@ static int mv88q2xxx_read_link_gbit(struct phy_device *phydev) * the link was already down. */ if (!phy_polling_mode(phydev) || !phydev->link) { - ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_STAT); + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_PCS_1000BT1_STAT); if (ret < 0) return ret; else if (ret & MDIO_PCS_1000BT1_STAT_LINK) @@ -71,7 +74,8 @@ static int mv88q2xxx_read_link_gbit(struct phy_device *phydev) } if (!link) { - ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_STAT); + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_PCS_1000BT1_STAT); if (ret < 0) return ret; else if (ret & MDIO_PCS_1000BT1_STAT_LINK) @@ -95,7 +99,8 @@ static int mv88q2xxx_read_link_100m(struct phy_device *phydev) * we always read the realtime status. */ if (!phy_polling_mode(phydev) || !phydev->link) { - ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1); + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_100BT1_STAT1); if (ret < 0) return ret; else if (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK) @@ -200,7 +205,7 @@ static int mv88q2xxx_config_init(struct phy_device *phydev) return mv88q2xxx_config_aneg(phydev); } -static int mv88q2xxxx_get_sqi(struct phy_device *phydev) +static int mv88q2xxx_get_sqi(struct phy_device *phydev) { int ret; @@ -208,7 +213,8 @@ static int mv88q2xxxx_get_sqi(struct phy_device *phydev) /* Read the SQI from the vendor specific receiver status * register */ - ret = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x8230); + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_RX_STAT); if (ret < 0) return ret; @@ -218,7 +224,7 @@ static int mv88q2xxxx_get_sqi(struct phy_device *phydev) * but can be found in the Software Initialization Guide. Only * revisions >= A0 are supported. */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 0xFC5D, 0x00FF, 0x00AC); + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 0xfc5d, 0xff, 0xac); if (ret < 0) return ret; @@ -227,10 +233,10 @@ static int mv88q2xxxx_get_sqi(struct phy_device *phydev) return ret; } - return ret & 0x0F; + return ret & 0x0f; } -static int mv88q2xxxx_get_sqi_max(struct phy_device *phydev) +static int mv88q2xxx_get_sqi_max(struct phy_device *phydev) { return 15; } @@ -246,8 +252,8 @@ static struct phy_driver mv88q2xxx_driver[] = { .read_status = mv88q2xxx_read_status, .soft_reset = mv88q2xxx_soft_reset, .set_loopback = genphy_c45_loopback, - .get_sqi = mv88q2xxxx_get_sqi, - .get_sqi_max = mv88q2xxxx_get_sqi_max, + .get_sqi = mv88q2xxx_get_sqi, + .get_sqi_max = mv88q2xxx_get_sqi_max, }, }; From e57e4c7f6cc943be3346f938361334bb3634db3d Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:42 +0100 Subject: [PATCH 1395/2255] net: phy: marvell-88q2xxx: add driver for the Marvell 88Q2220 PHY Add a driver for the Marvell 88Q2220. This driver allows to detect the link, switch between 100BASE-T1 and 1000BASE-T1 and switch between master and slave mode. Autonegotiation is supported. Reviewed-by: Andrew Lunn Tested-by: Gregor Herburger Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-6-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 214 ++++++++++++++++++++++++++++-- include/linux/marvell_phy.h | 1 + 2 files changed, 207 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index dcebb4643aff..9829facde253 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -1,11 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 /* * Marvell 88Q2XXX automotive 100BASE-T1/1000BASE-T1 PHY driver + * + * Derived from Marvell Q222x API + * + * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH */ #include #include #include +#define PHY_ID_88Q2220_REVB0 (MARVELL_PHY_ID_88Q2220 | 0x1) + #define MDIO_MMD_AN_MV_STAT 32769 #define MDIO_MMD_AN_MV_STAT_ANEG 0x0100 #define MDIO_MMD_AN_MV_STAT_LOCAL_RX 0x1000 @@ -13,6 +19,11 @@ #define MDIO_MMD_AN_MV_STAT_LOCAL_MASTER 0x4000 #define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT 0x8000 +#define MDIO_MMD_AN_MV_STAT2 32794 +#define MDIO_MMD_AN_MV_STAT2_AN_RESOLVED 0x0800 +#define MDIO_MMD_AN_MV_STAT2_100BT1 0x2000 +#define MDIO_MMD_AN_MV_STAT2_1000BT1 0x4000 + #define MDIO_MMD_PCS_MV_100BT1_STAT1 33032 #define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00ff #define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100 @@ -29,6 +40,42 @@ #define MDIO_MMD_PCS_MV_RX_STAT 33328 +struct mmd_val { + int devad; + u32 regnum; + u16 val; +}; + +static const struct mmd_val mv88q222x_revb0_init_seq0[] = { + { MDIO_MMD_PCS, 0x8033, 0x6801 }, + { MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 }, + { MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER | MDIO_PMA_CTRL1_SPEED1000 }, + { MDIO_MMD_PCS, 0xfe1b, 0x48 }, + { MDIO_MMD_PCS, 0xffe4, 0x6b6 }, + { MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0 }, + { MDIO_MMD_PCS, MDIO_CTRL1, 0x0 }, +}; + +static const struct mmd_val mv88q222x_revb0_init_seq1[] = { + { MDIO_MMD_PCS, 0xfe79, 0x0 }, + { MDIO_MMD_PCS, 0xfe07, 0x125a }, + { MDIO_MMD_PCS, 0xfe09, 0x1288 }, + { MDIO_MMD_PCS, 0xfe08, 0x2588 }, + { MDIO_MMD_PCS, 0xfe11, 0x1105 }, + { MDIO_MMD_PCS, 0xfe72, 0x042c }, + { MDIO_MMD_PCS, 0xfbba, 0xcb2 }, + { MDIO_MMD_PCS, 0xfbbb, 0xc4a }, + { MDIO_MMD_AN, 0x8032, 0x2020 }, + { MDIO_MMD_AN, 0x8031, 0xa28 }, + { MDIO_MMD_AN, 0x8031, 0xc28 }, + { MDIO_MMD_PCS, 0xffdb, 0xfc10 }, + { MDIO_MMD_PCS, 0xfe1b, 0x58 }, + { MDIO_MMD_PCS, 0xfe79, 0x4 }, + { MDIO_MMD_PCS, 0xfe5f, 0xe8 }, + { MDIO_MMD_PCS, 0xfe05, 0x755c }, +}; + static int mv88q2xxx_soft_reset(struct phy_device *phydev) { int ret; @@ -125,24 +172,90 @@ out: static int mv88q2xxx_read_link(struct phy_device *phydev) { - int ret; - /* The 88Q2XXX PHYs do not have the PMA/PMD status register available, * therefore we need to read the link status from the vendor specific * registers depending on the speed. */ - if (phydev->speed == SPEED_1000) - ret = mv88q2xxx_read_link_gbit(phydev); - else - ret = mv88q2xxx_read_link_100m(phydev); - return ret; + if (phydev->speed == SPEED_1000) + return mv88q2xxx_read_link_gbit(phydev); + else if (phydev->speed == SPEED_100) + return mv88q2xxx_read_link_100m(phydev); + + phydev->link = false; + return 0; +} + +static int mv88q2xxx_read_master_slave_state(struct phy_device *phydev) +{ + int ret; + + phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT); + if (ret < 0) + return ret; + + if (ret & MDIO_MMD_AN_MV_STAT_LOCAL_MASTER) + phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; + else + phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; + + return 0; +} + +static int mv88q2xxx_read_aneg_speed(struct phy_device *phydev) +{ + int ret; + + phydev->speed = SPEED_UNKNOWN; + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT2); + if (ret < 0) + return ret; + + if (!(ret & MDIO_MMD_AN_MV_STAT2_AN_RESOLVED)) + return 0; + + if (ret & MDIO_MMD_AN_MV_STAT2_100BT1) + phydev->speed = SPEED_100; + else if (ret & MDIO_MMD_AN_MV_STAT2_1000BT1) + phydev->speed = SPEED_1000; + + return 0; } static int mv88q2xxx_read_status(struct phy_device *phydev) { int ret; + if (phydev->autoneg == AUTONEG_ENABLE) { + /* We have to get the negotiated speed first, otherwise we are + * not able to read the link. + */ + ret = mv88q2xxx_read_aneg_speed(phydev); + if (ret < 0) + return ret; + + ret = mv88q2xxx_read_link(phydev); + if (ret < 0) + return ret; + + ret = genphy_c45_read_lpa(phydev); + if (ret < 0) + return ret; + + ret = genphy_c45_baset1_read_status(phydev); + if (ret < 0) + return ret; + + ret = mv88q2xxx_read_master_slave_state(phydev); + if (ret < 0) + return ret; + + phy_resolve_aneg_linkmode(phydev); + + return 0; + } + ret = mv88q2xxx_read_link(phydev); if (ret < 0) return ret; @@ -171,7 +284,9 @@ static int mv88q2xxx_get_features(struct phy_device *phydev) * sequence provided by Marvell. Disable it for now until a proper * workaround is found or a new PHY revision is released. */ - linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + if (phydev->drv->phy_id == MARVELL_PHY_ID_88Q2110) + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + phydev->supported); return 0; } @@ -241,6 +356,75 @@ static int mv88q2xxx_get_sqi_max(struct phy_device *phydev) return 15; } +static int mv88q222x_soft_reset(struct phy_device *phydev) +{ + int ret; + + /* Enable RESET of DCL */ + if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) { + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x48); + if (ret < 0) + return ret; + } + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL, + MDIO_PCS_1000BT1_CTRL_RESET); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xffe4, 0xc); + if (ret < 0) + return ret; + + /* Disable RESET of DCL */ + if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) + return phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x58); + + return 0; +} + +static int mv88q222x_config_aneg(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_config_aneg(phydev); + if (ret) + return ret; + + return mv88q222x_soft_reset(phydev); +} + +static int mv88q222x_revb0_config_init(struct phy_device *phydev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(mv88q222x_revb0_init_seq0); i++) { + ret = phy_write_mmd(phydev, mv88q222x_revb0_init_seq0[i].devad, + mv88q222x_revb0_init_seq0[i].regnum, + mv88q222x_revb0_init_seq0[i].val); + if (ret < 0) + return ret; + } + + usleep_range(5000, 10000); + + for (i = 0; i < ARRAY_SIZE(mv88q222x_revb0_init_seq1); i++) { + ret = phy_write_mmd(phydev, mv88q222x_revb0_init_seq1[i].devad, + mv88q222x_revb0_init_seq1[i].regnum, + mv88q222x_revb0_init_seq1[i].val); + if (ret < 0) + return ret; + } + + /* The 88Q2XXX PHYs do have the extended ability register available, but + * register MDIO_PMA_EXTABLE where they should signalize it does not + * work according to specification. Therefore, we force it here. + */ + phydev->pma_extable = MDIO_PMA_EXTABLE_BT1; + + return 0; +} + static struct phy_driver mv88q2xxx_driver[] = { { .phy_id = MARVELL_PHY_ID_88Q2110, @@ -255,12 +439,26 @@ static struct phy_driver mv88q2xxx_driver[] = { .get_sqi = mv88q2xxx_get_sqi, .get_sqi_max = mv88q2xxx_get_sqi_max, }, + { + PHY_ID_MATCH_EXACT(PHY_ID_88Q2220_REVB0), + .name = "mv88q2220", + .get_features = mv88q2xxx_get_features, + .config_aneg = mv88q222x_config_aneg, + .aneg_done = genphy_c45_aneg_done, + .config_init = mv88q222x_revb0_config_init, + .read_status = mv88q2xxx_read_status, + .soft_reset = mv88q222x_soft_reset, + .set_loopback = genphy_c45_loopback, + .get_sqi = mv88q2xxx_get_sqi, + .get_sqi_max = mv88q2xxx_get_sqi_max, + }, }; module_phy_driver(mv88q2xxx_driver); static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = { { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK }, + { PHY_ID_MATCH_EXACT(PHY_ID_88Q2220_REVB0), }, { /*sentinel*/ } }; MODULE_DEVICE_TABLE(mdio, mv88q2xxx_tbl); diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h index 9b54c4f0677f..693eba9869e4 100644 --- a/include/linux/marvell_phy.h +++ b/include/linux/marvell_phy.h @@ -26,6 +26,7 @@ #define MARVELL_PHY_ID_88E2110 0x002b09b0 #define MARVELL_PHY_ID_88X2222 0x01410f10 #define MARVELL_PHY_ID_88Q2110 0x002b0980 +#define MARVELL_PHY_ID_88Q2220 0x002b0b20 /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 From caa858b75742557dc0528fc878a1459209103c06 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:43 +0100 Subject: [PATCH 1396/2255] net: phy: marvell-88q2xxx: add interrupt support for link detection Added .config_intr and .handle_interrupt callbacks. Whenever the link goes up or down an interrupt will be triggered. Interrupts are configured separately for 100/1000BASET1. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-7-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 123 +++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 9829facde253..7c7517af346b 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -24,6 +24,19 @@ #define MDIO_MMD_AN_MV_STAT2_100BT1 0x2000 #define MDIO_MMD_AN_MV_STAT2_1000BT1 0x4000 +#define MDIO_MMD_PCS_MV_INT_EN 32784 +#define MDIO_MMD_PCS_MV_INT_EN_LINK_UP 0x0040 +#define MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN 0x0080 +#define MDIO_MMD_PCS_MV_INT_EN_100BT1 0x1000 + +#define MDIO_MMD_PCS_MV_GPIO_INT_STAT 32785 +#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP 0x0040 +#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN 0x0080 +#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_100BT1_GEN 0x1000 + +#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL 32787 +#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS 0x0800 + #define MDIO_MMD_PCS_MV_100BT1_STAT1 33032 #define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00ff #define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100 @@ -38,6 +51,12 @@ #define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK 0x0004 #define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE 0x0008 +#define MDIO_MMD_PCS_MV_100BT1_INT_EN 33042 +#define MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT 0x0400 + +#define MDIO_MMD_PCS_MV_COPPER_INT_STAT 33043 +#define MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT 0x0400 + #define MDIO_MMD_PCS_MV_RX_STAT 33328 struct mmd_val { @@ -99,13 +118,15 @@ static int mv88q2xxx_read_link_gbit(struct phy_device *phydev) /* Read vendor specific Auto-Negotiation status register to get local * and remote receiver status according to software initialization - * guide. + * guide. However, when not in polling mode the local and remote + * receiver status are not evaluated due to the Marvell 88Q2xxx APIs. */ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT); if (ret < 0) { return ret; - } else if ((ret & MDIO_MMD_AN_MV_STAT_LOCAL_RX) && - (ret & MDIO_MMD_AN_MV_STAT_REMOTE_RX)) { + } else if (((ret & MDIO_MMD_AN_MV_STAT_LOCAL_RX) && + (ret & MDIO_MMD_AN_MV_STAT_REMOTE_RX)) || + !phy_polling_mode(phydev)) { /* The link state is latched low so that momentary link * drops can be detected. Do not double-read the status * in polling mode to detect such short link drops except @@ -145,7 +166,18 @@ static int mv88q2xxx_read_link_100m(struct phy_device *phydev) * the link was already down. In case we are not polling, * we always read the realtime status. */ - if (!phy_polling_mode(phydev) || !phydev->link) { + if (!phy_polling_mode(phydev)) { + phydev->link = false; + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_100BT1_STAT2); + if (ret < 0) + return ret; + + if (ret & MDIO_MMD_PCS_MV_100BT1_STAT2_LINK) + phydev->link = true; + + return 0; + } else if (!phydev->link) { ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1); if (ret < 0) @@ -356,6 +388,79 @@ static int mv88q2xxx_get_sqi_max(struct phy_device *phydev) return 15; } +static int mv88q2xxx_config_intr(struct phy_device *phydev) +{ + int ret; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Enable interrupts for 1000BASE-T1 link up and down events + * and enable general interrupts for 100BASE-T1. + */ + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_INT_EN, + MDIO_MMD_PCS_MV_INT_EN_LINK_UP | + MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN | + MDIO_MMD_PCS_MV_INT_EN_100BT1); + if (ret < 0) + return ret; + + /* Enable interrupts for 100BASE-T1 link events */ + return phy_write_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_100BT1_INT_EN, + MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT); + } else { + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_INT_EN, 0); + if (ret < 0) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_100BT1_INT_EN, 0); + } +} + +static irqreturn_t mv88q2xxx_handle_interrupt(struct phy_device *phydev) +{ + bool trigger_machine = false; + int irq; + + /* Before we can acknowledge the 100BT1 general interrupt, that is in + * the 1000BT1 interrupt status register, we have to acknowledge any + * interrupts that are related to it. Therefore we read first the 100BT1 + * interrupt status register, followed by reading the 1000BT1 interrupt + * status register. + */ + + irq = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_COPPER_INT_STAT); + if (irq < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* Check link status for 100BT1 */ + if (irq & MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT) + trigger_machine = true; + + irq = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_GPIO_INT_STAT); + if (irq < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* Check link status for 1000BT1 */ + if ((irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP) || + (irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN)) + trigger_machine = true; + + if (!trigger_machine) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int mv88q222x_soft_reset(struct phy_device *phydev) { int ret; @@ -422,6 +527,14 @@ static int mv88q222x_revb0_config_init(struct phy_device *phydev) */ phydev->pma_extable = MDIO_PMA_EXTABLE_BT1; + /* Configure interrupt with default settings, output is driven low for + * active interrupt and high for inactive. + */ + if (phy_interrupt_is_valid(phydev)) + return phy_set_bits_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_GPIO_INT_CTRL, + MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS); + return 0; } @@ -448,6 +561,8 @@ static struct phy_driver mv88q2xxx_driver[] = { .config_init = mv88q222x_revb0_config_init, .read_status = mv88q2xxx_read_status, .soft_reset = mv88q222x_soft_reset, + .config_intr = mv88q2xxx_config_intr, + .handle_interrupt = mv88q2xxx_handle_interrupt, .set_loopback = genphy_c45_loopback, .get_sqi = mv88q2xxx_get_sqi, .get_sqi_max = mv88q2xxx_get_sqi_max, From 5f9f361a3dab3fcc7937e8f871d71c5e18a703fa Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:44 +0100 Subject: [PATCH 1397/2255] net: phy: marvell-88q2xxx: add suspend / resume ops Add suspend/resume ops for Marvell 88Q2xxx devices. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-8-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 7c7517af346b..8b8275552014 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -461,6 +461,38 @@ static irqreturn_t mv88q2xxx_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } +static int mv88q2xxx_suspend(struct phy_device *phydev) +{ + int ret; + + /* Disable PHY interrupts */ + if (phy_interrupt_is_valid(phydev)) { + phydev->interrupts = PHY_INTERRUPT_DISABLED; + ret = mv88q2xxx_config_intr(phydev); + if (ret) + return ret; + } + + return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER); +} + +static int mv88q2xxx_resume(struct phy_device *phydev) +{ + int ret; + + /* Enable PHY interrupts */ + if (phy_interrupt_is_valid(phydev)) { + phydev->interrupts = PHY_INTERRUPT_ENABLED; + ret = mv88q2xxx_config_intr(phydev); + if (ret) + return ret; + } + + return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER); +} + static int mv88q222x_soft_reset(struct phy_device *phydev) { int ret; @@ -566,6 +598,8 @@ static struct phy_driver mv88q2xxx_driver[] = { .set_loopback = genphy_c45_loopback, .get_sqi = mv88q2xxx_get_sqi, .get_sqi_max = mv88q2xxx_get_sqi_max, + .suspend = mv88q2xxx_suspend, + .resume = mv88q2xxx_resume, }, }; From a557a92e68812b295a80f0a3535d166027fb2804 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:45 +0100 Subject: [PATCH 1398/2255] net: phy: marvell-88q2xxx: add support for temperature sensor Marvell 88q2xxx devices have an inbuilt temperature sensor. Add hwmon support for this sensor. Reviewed-by: Andrew Lunn Reviewed-by: Guenter Roeck Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-9-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 1 + drivers/net/phy/marvell-88q2xxx.c | 146 ++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index e261e58bf158..1df0595c5ba9 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -232,6 +232,7 @@ config MARVELL_10G_PHY config MARVELL_88Q2XXX_PHY tristate "Marvell 88Q2XXX PHY" + depends on HWMON || HWMON=n help Support for the Marvell 88Q2XXX 100/1000BASE-T1 Automotive Ethernet PHYs. diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 8b8275552014..2ca1b47e8f8f 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -9,6 +9,7 @@ #include #include #include +#include #define PHY_ID_88Q2220_REVB0 (MARVELL_PHY_ID_88Q2220 | 0x1) @@ -37,6 +38,18 @@ #define MDIO_MMD_PCS_MV_GPIO_INT_CTRL 32787 #define MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS 0x0800 +#define MDIO_MMD_PCS_MV_TEMP_SENSOR1 32833 +#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT 0x0001 +#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT 0x0040 +#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT_EN 0x0080 + +#define MDIO_MMD_PCS_MV_TEMP_SENSOR2 32834 +#define MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK 0xc000 + +#define MDIO_MMD_PCS_MV_TEMP_SENSOR3 32835 +#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK 0xff00 +#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK 0x00ff + #define MDIO_MMD_PCS_MV_100BT1_STAT1 33032 #define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00ff #define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100 @@ -493,6 +506,138 @@ static int mv88q2xxx_resume(struct phy_device *phydev) MDIO_CTRL1_LPOWER); } +#if IS_ENABLED(CONFIG_HWMON) +static const struct hwmon_channel_info * const mv88q2xxx_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_ALARM), + NULL +}; + +static umode_t mv88q2xxx_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (attr) { + case hwmon_temp_input: + return 0444; + case hwmon_temp_max: + return 0644; + case hwmon_temp_alarm: + return 0444; + default: + return 0; + } +} + +static int mv88q2xxx_hwmon_read(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct phy_device *phydev = dev_get_drvdata(dev); + int ret; + + switch (attr) { + case hwmon_temp_input: + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_TEMP_SENSOR3); + if (ret < 0) + return ret; + + ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK, ret); + *val = (ret - 75) * 1000; + return 0; + case hwmon_temp_max: + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_TEMP_SENSOR3); + if (ret < 0) + return ret; + + ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK, + ret); + *val = (ret - 75) * 1000; + return 0; + case hwmon_temp_alarm: + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_TEMP_SENSOR1); + if (ret < 0) + return ret; + + *val = !!(ret & MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int mv88q2xxx_hwmon_write(struct device *dev, + enum hwmon_sensor_types type, u32 attr, + int channel, long val) +{ + struct phy_device *phydev = dev_get_drvdata(dev); + + switch (attr) { + case hwmon_temp_max: + clamp_val(val, -75000, 180000); + val = (val / 1000) + 75; + val = FIELD_PREP(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK, + val); + return phy_modify_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_TEMP_SENSOR3, + MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK, + val); + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_ops mv88q2xxx_hwmon_hwmon_ops = { + .is_visible = mv88q2xxx_hwmon_is_visible, + .read = mv88q2xxx_hwmon_read, + .write = mv88q2xxx_hwmon_write, +}; + +static const struct hwmon_chip_info mv88q2xxx_hwmon_chip_info = { + .ops = &mv88q2xxx_hwmon_hwmon_ops, + .info = mv88q2xxx_hwmon_info, +}; + +static int mv88q2xxx_hwmon_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct device *hwmon; + char *hwmon_name; + int ret; + + /* Enable temperature sense */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TEMP_SENSOR2, + MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK, 0); + if (ret < 0) + return ret; + + hwmon_name = devm_hwmon_sanitize_name(dev, dev_name(dev)); + if (IS_ERR(hwmon_name)) + return PTR_ERR(hwmon_name); + + hwmon = devm_hwmon_device_register_with_info(dev, + hwmon_name, + phydev, + &mv88q2xxx_hwmon_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon); +} + +#else +static int mv88q2xxx_hwmon_probe(struct phy_device *phydev) +{ + return 0; +} +#endif + +static int mv88q2xxx_probe(struct phy_device *phydev) +{ + return mv88q2xxx_hwmon_probe(phydev); +} + static int mv88q222x_soft_reset(struct phy_device *phydev) { int ret; @@ -587,6 +732,7 @@ static struct phy_driver mv88q2xxx_driver[] = { { PHY_ID_MATCH_EXACT(PHY_ID_88Q2220_REVB0), .name = "mv88q2220", + .probe = mv88q2xxx_probe, .get_features = mv88q2xxx_get_features, .config_aneg = mv88q222x_config_aneg, .aneg_done = genphy_c45_aneg_done, From 560d9a39aeb08ba7989eb15cd9b52f9fa343d9a3 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:46 +0100 Subject: [PATCH 1399/2255] net: phy: marvell-88q2xxx: add cable test support Add cable test support for Marvell 88Q222x devices. Reported distance granularity is 1m. 1m cable, open: Cable test started for device eth0. Cable test completed for device eth0. Pair A code Open Circuit Pair A, fault length: 1.00m 1m cable, shorted: Cable test started for device eth0. Cable test completed for device eth0. Pair A code Short within Pair Pair A, fault length: 1.00m 6m cable, open: Cable test started for device eth0. Cable test completed for device eth0. Pair A code Open Circuit Pair A, fault length: 6.00m 6m cable, shorted: Cable test started for device eth0. Cable test completed for device eth0. Pair A code Short within Pair Pair A, fault length: 6.00m Signed-off-by: Dimitri Fedrau Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240218075753.18067-10-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 107 ++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 2ca1b47e8f8f..11963d8176b2 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -72,6 +72,27 @@ #define MDIO_MMD_PCS_MV_RX_STAT 33328 +#define MDIO_MMD_PCS_MV_TDR_RESET 65226 +#define MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST 0x1000 + +#define MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE 65241 + +#define MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE 65242 + +#define MDIO_MMD_PCS_MV_TDR_STATUS 65245 +#define MDIO_MMD_PCS_MV_TDR_STATUS_MASK 0x0003 +#define MDIO_MMD_PCS_MV_TDR_STATUS_OFF 0x0001 +#define MDIO_MMD_PCS_MV_TDR_STATUS_ON 0x0002 +#define MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK 0xff00 +#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK 0x00f0 +#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT 0x0030 +#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN 0x00e0 +#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK 0x0070 +#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_IN_PROGR 0x0080 +#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_NOISE 0x0050 + +#define MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF 65246 + struct mmd_val { int devad; u32 regnum; @@ -715,6 +736,89 @@ static int mv88q222x_revb0_config_init(struct phy_device *phydev) return 0; } +static int mv88q222x_cable_test_start(struct phy_device *phydev) +{ + int ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF, 0x0058); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE, 0x00eb); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE, 0x010e); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET, + 0x0d90); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS, + MDIO_MMD_PCS_MV_TDR_STATUS_ON); + if (ret < 0) + return ret; + + /* According to the Marvell API the test is finished within 500 ms */ + msleep(500); + + return 0; +} + +static int mv88q222x_cable_test_get_status(struct phy_device *phydev, + bool *finished) +{ + int ret, status; + u32 dist; + + status = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS); + if (status < 0) + return status; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET, + MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST | 0xd90); + if (ret < 0) + return ret; + + /* Test could not be finished */ + if (FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_MASK, status) != + MDIO_MMD_PCS_MV_TDR_STATUS_OFF) + return -ETIMEDOUT; + + *finished = true; + /* Fault length reported in meters, convert to centimeters */ + dist = FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK, status) * 100; + switch (status & MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK) { + case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN: + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, + ETHTOOL_A_CABLE_RESULT_CODE_OPEN); + ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A, + dist); + break; + case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT: + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, + ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT); + ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A, + dist); + break; + case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK: + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, + ETHTOOL_A_CABLE_RESULT_CODE_OK); + break; + default: + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, + ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC); + } + + return 0; +} + static struct phy_driver mv88q2xxx_driver[] = { { .phy_id = MARVELL_PHY_ID_88Q2110, @@ -732,6 +836,7 @@ static struct phy_driver mv88q2xxx_driver[] = { { PHY_ID_MATCH_EXACT(PHY_ID_88Q2220_REVB0), .name = "mv88q2220", + .flags = PHY_POLL_CABLE_TEST, .probe = mv88q2xxx_probe, .get_features = mv88q2xxx_get_features, .config_aneg = mv88q222x_config_aneg, @@ -742,6 +847,8 @@ static struct phy_driver mv88q2xxx_driver[] = { .config_intr = mv88q2xxx_config_intr, .handle_interrupt = mv88q2xxx_handle_interrupt, .set_loopback = genphy_c45_loopback, + .cable_test_start = mv88q222x_cable_test_start, + .cable_test_get_status = mv88q222x_cable_test_get_status, .get_sqi = mv88q2xxx_get_sqi, .get_sqi_max = mv88q2xxx_get_sqi_max, .suspend = mv88q2xxx_suspend, From 3810e029e23e220487c33f77b56a762ef1dc8ff3 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:47 +0100 Subject: [PATCH 1400/2255] net: phy: marvell-88q2xxx: make mv88q2xxx_config_aneg generic Marvell 88Q2xxx devices follow the same scheme, after configuration they need a soft reset. Soft resets differ between devices, so we use the .soft_reset callback instead of creating .config_aneg callbacks for each device. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-11-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 11963d8176b2..5bc36cc68a20 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -365,7 +365,7 @@ static int mv88q2xxx_config_aneg(struct phy_device *phydev) if (ret) return ret; - return mv88q2xxx_soft_reset(phydev); + return phydev->drv->soft_reset(phydev); } static int mv88q2xxx_config_init(struct phy_device *phydev) From 969dd0cf295d6f19b577aea0b48a11c4087693e9 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:48 +0100 Subject: [PATCH 1401/2255] net: phy: marvell-88q2xxx: switch to mv88q2xxx_config_aneg Switch to mv88q2xxx_config_aneg for Marvell 88Q2220 devices and remove the mv88q222x_config_aneg function which is basically a copy of the mv88q2xxx_config_aneg function. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-12-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 5bc36cc68a20..58aa10d35731 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -686,17 +686,6 @@ static int mv88q222x_soft_reset(struct phy_device *phydev) return 0; } -static int mv88q222x_config_aneg(struct phy_device *phydev) -{ - int ret; - - ret = genphy_c45_config_aneg(phydev); - if (ret) - return ret; - - return mv88q222x_soft_reset(phydev); -} - static int mv88q222x_revb0_config_init(struct phy_device *phydev) { int ret, i; @@ -839,7 +828,7 @@ static struct phy_driver mv88q2xxx_driver[] = { .flags = PHY_POLL_CABLE_TEST, .probe = mv88q2xxx_probe, .get_features = mv88q2xxx_get_features, - .config_aneg = mv88q222x_config_aneg, + .config_aneg = mv88q2xxx_config_aneg, .aneg_done = genphy_c45_aneg_done, .config_init = mv88q222x_revb0_config_init, .read_status = mv88q2xxx_read_status, From ec2660946a57d35aa5f3b9a71ae0ab81e5cfcb83 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:49 +0100 Subject: [PATCH 1402/2255] net: phy: marvell-88q2xxx: cleanup mv88q2xxx_config_init mv88q2xxx_config_init calls genphy_c45_read_pma which is done by mv88q2xxx_read_status, it calls also mv88q2xxx_config_aneg which is also called by the PHY state machine. Let the PHY state machine handle the phydriver ops in their intendend way. Reviewed-by: Andrew Lunn Tested-by: Stefan Eichenberger Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-13-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 58aa10d35731..ebcc6b4046fb 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -370,20 +370,13 @@ static int mv88q2xxx_config_aneg(struct phy_device *phydev) static int mv88q2xxx_config_init(struct phy_device *phydev) { - int ret; - /* The 88Q2XXX PHYs do have the extended ability register available, but * register MDIO_PMA_EXTABLE where they should signalize it does not * work according to specification. Therefore, we force it here. */ phydev->pma_extable = MDIO_PMA_EXTABLE_BT1; - /* Read the current PHY configuration */ - ret = genphy_c45_read_pma(phydev); - if (ret) - return ret; - - return mv88q2xxx_config_aneg(phydev); + return 0; } static int mv88q2xxx_get_sqi(struct phy_device *phydev) From 923d3104f7945dc29c1740d038d4868a791a4d32 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:50 +0100 Subject: [PATCH 1403/2255] net: phy: marvell-88q2xxx: remove duplicated assignment of pma_extable Remove assignment of phydev->pma_extable in mv88q222x_revb0_config_init. It is already done in mv88q2xxx_config_init, just call mv88q2xxx_config_init. Reviewed-by: Andrew Lunn Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-14-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index ebcc6b4046fb..75740f378c66 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -701,12 +701,6 @@ static int mv88q222x_revb0_config_init(struct phy_device *phydev) return ret; } - /* The 88Q2XXX PHYs do have the extended ability register available, but - * register MDIO_PMA_EXTABLE where they should signalize it does not - * work according to specification. Therefore, we force it here. - */ - phydev->pma_extable = MDIO_PMA_EXTABLE_BT1; - /* Configure interrupt with default settings, output is driven low for * active interrupt and high for inactive. */ @@ -715,7 +709,7 @@ static int mv88q222x_revb0_config_init(struct phy_device *phydev) MDIO_MMD_PCS_MV_GPIO_INT_CTRL, MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS); - return 0; + return mv88q2xxx_config_init(phydev); } static int mv88q222x_cable_test_start(struct phy_device *phydev) From f29207d2e0fae525cece3ece038ca5ca90bf8990 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Sun, 18 Feb 2024 08:57:51 +0100 Subject: [PATCH 1404/2255] net: phy: marvell-88q2xxx: move interrupt configuration Move interrupt configuration from mv88q222x_revb0_config_init to mv88q2xxx_config_init. Same register and bits are used for the 88q2xxx devices. Reviewed-by: Andrew Lunn Reviewed-by: Stefan Eichenberger Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240218075753.18067-15-dima.fedrau@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 75740f378c66..6b4bd9883304 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -376,6 +376,14 @@ static int mv88q2xxx_config_init(struct phy_device *phydev) */ phydev->pma_extable = MDIO_PMA_EXTABLE_BT1; + /* Configure interrupt with default settings, output is driven low for + * active interrupt and high for inactive. + */ + if (phy_interrupt_is_valid(phydev)) + return phy_set_bits_mmd(phydev, MDIO_MMD_PCS, + MDIO_MMD_PCS_MV_GPIO_INT_CTRL, + MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS); + return 0; } @@ -701,14 +709,6 @@ static int mv88q222x_revb0_config_init(struct phy_device *phydev) return ret; } - /* Configure interrupt with default settings, output is driven low for - * active interrupt and high for inactive. - */ - if (phy_interrupt_is_valid(phydev)) - return phy_set_bits_mmd(phydev, MDIO_MMD_PCS, - MDIO_MMD_PCS_MV_GPIO_INT_CTRL, - MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS); - return mv88q2xxx_config_init(phydev); } From f796feabb9f5b1e5c48780a7a0023ab4b82336dd Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Feb 2024 12:00:01 +0100 Subject: [PATCH 1405/2255] udp: add local "peek offset enabled" flag We want to re-organize the struct sock layout. The sk_peek_off field location is problematic, as most protocols want it in the RX read area, while UDP wants it on a cacheline different from sk_receive_queue. Create a local (inside udp_sock) copy of the 'peek offset is enabled' flag and place it inside the same cacheline of reader_queue. Check such flag before reading sk_peek_off. This will save potential false sharing and cache misses in the fast-path. Tested under UDP flood with small packets. The struct sock layout update causes a 4% performance drop, and this patch restores completely the original tput. Signed-off-by: Paolo Abeni Reviewed-by: Eric Dumazet Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/67ab679c15fbf49fa05b3ffe05d91c47ab84f147.1708426665.git.pabeni@redhat.com Signed-off-by: Jakub Kicinski --- include/linux/udp.h | 10 ++++++++++ net/ipv4/af_inet.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/af_inet6.c | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/linux/udp.h b/include/linux/udp.h index d04188714dca..3748e82b627b 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -92,6 +92,9 @@ struct udp_sock { /* This fields follows rcvbuf value, and is touched by udp_recvmsg */ int forward_threshold; + + /* Cache friendly copy of sk->sk_peek_off >= 0 */ + bool peeking_with_offset; }; #define udp_test_bit(nr, sk) \ @@ -109,6 +112,13 @@ struct udp_sock { #define udp_sk(ptr) container_of_const(ptr, struct udp_sock, inet.sk) +static inline int udp_set_peek_off(struct sock *sk, int val) +{ + sk_set_peek_off(sk, val); + WRITE_ONCE(udp_sk(sk)->peeking_with_offset, val >= 0); + return 0; +} + static inline void udp_set_no_check6_tx(struct sock *sk, bool val) { udp_assign_bit(NO_CHECK6_TX, sk, val); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index ad278009e469..5daebdcbca32 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1103,7 +1103,7 @@ const struct proto_ops inet_dgram_ops = { .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .splice_eof = inet_splice_eof, - .set_peek_off = sk_set_peek_off, + .set_peek_off = udp_set_peek_off, #ifdef CONFIG_COMPAT .compat_ioctl = inet_compat_ioctl, #endif diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f631b0a21af4..38cce7cc51f6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1589,7 +1589,7 @@ int udp_init_sock(struct sock *sk) void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len) { - if (unlikely(READ_ONCE(sk->sk_peek_off) >= 0)) { + if (unlikely(READ_ONCE(udp_sk(sk)->peeking_with_offset))) { bool slow = lock_sock_fast(sk); sk_peek_offset_bwd(sk, len); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 959bfd9f6344..b90d46533cdc 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -736,7 +736,7 @@ const struct proto_ops inet6_dgram_ops = { .recvmsg = inet6_recvmsg, /* retpoline's sake */ .read_skb = udp_read_skb, .mmap = sock_no_mmap, - .set_peek_off = sk_set_peek_off, + .set_peek_off = udp_set_peek_off, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, #endif From 6d5c36565c169376e3c5fc54d01d7c6819381465 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 17 Feb 2024 22:14:25 +0100 Subject: [PATCH 1406/2255] PPPoL2TP: Add more code snippets The existing documentation was not telling that one has to create a PPP channel and a PPP interface to get PPPoL2TP data offloading working. Also, tunnel switching was not mentioned, so that people were thinking it was not supported, while it actually is. Signed-off-by: Samuel Thibault Acked-by: Tom Parkin Link: https://lore.kernel.org/r/20240217211425.qj576u3jmaa6yidf@begin Signed-off-by: Jakub Kicinski --- Documentation/networking/l2tp.rst | 137 ++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 7 deletions(-) diff --git a/Documentation/networking/l2tp.rst b/Documentation/networking/l2tp.rst index 7f383e99dbad..8496b467dea4 100644 --- a/Documentation/networking/l2tp.rst +++ b/Documentation/networking/l2tp.rst @@ -386,12 +386,19 @@ Sample userspace code: - Create session PPPoX data socket:: - struct sockaddr_pppol2tp sax; - int fd; - - /* Note, the tunnel socket must be bound already, else it - * will not be ready + /* Input: the L2TP tunnel UDP socket `tunnel_fd`, which needs to be + * bound already (both sockname and peername), otherwise it will not be + * ready. */ + + struct sockaddr_pppol2tp sax; + int session_fd; + int ret; + + session_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); + if (session_fd < 0) + return -errno; + sax.sa_family = AF_PPPOX; sax.sa_protocol = PX_PROTO_OL2TP; sax.pppol2tp.fd = tunnel_fd; @@ -406,12 +413,128 @@ Sample userspace code: /* session_fd is the fd of the session's PPPoL2TP socket. * tunnel_fd is the fd of the tunnel UDP / L2TPIP socket. */ - fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax)); - if (fd < 0 ) { + ret = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax)); + if (ret < 0 ) { + close(session_fd); return -errno; } + + return session_fd; + +L2TP control packets will still be available for read on `tunnel_fd`. + + - Create PPP channel:: + + /* Input: the session PPPoX data socket `session_fd` which was created + * as described above. + */ + + int ppp_chan_fd; + int chindx; + int ret; + + ret = ioctl(session_fd, PPPIOCGCHAN, &chindx); + if (ret < 0) + return -errno; + + ppp_chan_fd = open("/dev/ppp", O_RDWR); + if (ppp_chan_fd < 0) + return -errno; + + ret = ioctl(ppp_chan_fd, PPPIOCATTCHAN, &chindx); + if (ret < 0) { + close(ppp_chan_fd); + return -errno; + } + + return ppp_chan_fd; + +LCP PPP frames will be available for read on `ppp_chan_fd`. + + - Create PPP interface:: + + /* Input: the PPP channel `ppp_chan_fd` which was created as described + * above. + */ + + int ifunit = -1; + int ppp_if_fd; + int ret; + + ppp_if_fd = open("/dev/ppp", O_RDWR); + if (ppp_if_fd < 0) + return -errno; + + ret = ioctl(ppp_if_fd, PPPIOCNEWUNIT, &ifunit); + if (ret < 0) { + close(ppp_if_fd); + return -errno; + } + + ret = ioctl(ppp_chan_fd, PPPIOCCONNECT, &ifunit); + if (ret < 0) { + close(ppp_if_fd); + return -errno; + } + + return ppp_if_fd; + +IPCP/IPv6CP PPP frames will be available for read on `ppp_if_fd`. + +The ppp interface can then be configured as usual with netlink's +RTM_NEWLINK, RTM_NEWADDR, RTM_NEWROUTE, or ioctl's SIOCSIFMTU, SIOCSIFADDR, +SIOCSIFDSTADDR, SIOCSIFNETMASK, SIOCSIFFLAGS, or with the `ip` command. + + - Bridging L2TP sessions which have PPP pseudowire types (this is also called + L2TP tunnel switching or L2TP multihop) is supported by bridging the PPP + channels of the two L2TP sessions to be bridged:: + + /* Input: the session PPPoX data sockets `session_fd1` and `session_fd2` + * which were created as described further above. + */ + + int ppp_chan_fd; + int chindx1; + int chindx2; + int ret; + + ret = ioctl(session_fd1, PPPIOCGCHAN, &chindx1); + if (ret < 0) + return -errno; + + ret = ioctl(session_fd2, PPPIOCGCHAN, &chindx2); + if (ret < 0) + return -errno; + + ppp_chan_fd = open("/dev/ppp", O_RDWR); + if (ppp_chan_fd < 0) + return -errno; + + ret = ioctl(ppp_chan_fd, PPPIOCATTCHAN, &chindx1); + if (ret < 0) { + close(ppp_chan_fd); + return -errno; + } + + ret = ioctl(ppp_chan_fd, PPPIOCBRIDGECHAN, &chindx2); + close(ppp_chan_fd); + if (ret < 0) + return -errno; + return 0; +It can be noted that when bridging PPP channels, the PPP session is not locally +terminated, and no local PPP interface is created. PPP frames arriving on one +channel are directly passed to the other channel, and vice versa. + +The PPP channel does not need to be kept open. Only the session PPPoX data +sockets need to be kept open. + +More generally, it is also possible in the same way to e.g. bridge a PPPoL2TP +PPP channel with other types of PPP channels, such as PPPoE. + +See more details for the PPP side in ppp_generic.rst. + Old L2TPv2-only API ------------------- From 775cf70c409b0e54475921c1084792771fae50cb Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 6 Sep 2023 16:27:25 +0800 Subject: [PATCH 1407/2255] wifi: mt76: disable HW AMSDU when using fixed rate When using fixed rate, HW uses txd DW9 to store tx arrivial time if VTA is set. It would overwrite the msdu_id in txd and lead to token pending if amsdu is enable. Signed-off-by: Peter Chiu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index c7914643e9c0..630c6402ec25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -544,7 +544,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, val = FIELD_PREP(MT_TXD5_PID, pid); if (pid >= MT_PACKET_ID_FIRST) { val |= MT_TXD5_TX_STATUS_HOST; - amsdu_en = amsdu_en && !is_mt7921(dev); + amsdu_en = 0; } txwi[5] = cpu_to_le32(val); @@ -579,6 +579,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, spe_idx = 24 + phy_idx; txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx)); } + + txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); } } EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi); From 6178554066bc41445997cf0319489b625cefcc5f Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Fri, 8 Dec 2023 07:35:39 +0800 Subject: [PATCH 1408/2255] wifi: mt76: check txs format before getting skb by pid The PPDU TxS does not include the error bit so it cannot use to report status to mac80211. Signed-off-by: Peter Chiu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h | 5 +++++ drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h index bd2a92467a97..5f132115ebfc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h @@ -32,6 +32,11 @@ enum { MT_LMAC_PSMP0, }; +enum { + MT_TXS_MPDU_FMT = 0, + MT_TXS_PPDU_FMT = 2, +}; + #define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) #define MT_TX_FREE_WLAN_ID GENMASK(23, 14) #define MT_TX_FREE_COUNT GENMASK(12, 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 630c6402ec25..b841bf628d02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -716,6 +716,9 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff_head list; struct sk_buff *skb; + if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) == MT_TXS_PPDU_FMT) + return false; + mt76_tx_status_lock(dev, &list); skb = mt76_tx_status_skb_get(dev, wcid, pid, &list); if (skb) { From 350f63c9624b8fd407805c7dfb652a1c3d619862 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 18 Jan 2024 15:51:53 +0100 Subject: [PATCH 1409/2255] wifi: mt76: mt7915: fix error recovery with WED enabled Do not clear the interrupt mask register on MT7915, since that prevents MCU_CMD interrupts from being reported, thus causing timeouts during the reset sequence. Defer stopping WED until tx/rx processing activity has stopped. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index b01edbed969c..e45361111f9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1520,12 +1520,6 @@ void mt7915_mac_reset_work(struct work_struct *work) if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) return; - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { - mtk_wed_device_stop(&dev->mt76.mmio.wed); - if (!is_mt798x(&dev->mt76)) - mt76_wr(dev, MT_INT_WED_MASK_CSR, 0); - } - ieee80211_stop_queues(mt76_hw(dev)); if (ext_phy) ieee80211_stop_queues(ext_phy->hw); @@ -1545,6 +1539,9 @@ void mt7915_mac_reset_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_stop(&dev->mt76.mmio.wed); + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { From 0937f95ab07af6e663ae932d592f630d9eb591da Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Tue, 15 Aug 2023 17:28:30 +0800 Subject: [PATCH 1410/2255] wifi: mt76: mt7915: add locking for accessing mapped registers Sicne the mapping is global, mapped register access needs to be protected against concurrent access, otherwise a race condition might cause the reads or writes to go towards the wrong register Signed-off-by: Shayne Chen Signed-off-by: Peter Chiu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/mmio.c | 45 ++++++++++++++++--- .../wireless/mediatek/mt76/mt7915/mt7915.h | 1 + 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 3039f53e2245..dceb505987b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -490,6 +490,11 @@ static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) return dev->reg.map[i].maps + ofs; } + return 0; +} + +static u32 __mt7915_reg_remap_addr(struct mt7915_dev *dev, u32 addr) +{ if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) @@ -514,15 +519,30 @@ void mt7915_memcpy_fromio(struct mt7915_dev *dev, void *buf, u32 offset, { u32 addr = __mt7915_reg_addr(dev, offset); - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + if (addr) { + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + return; + } + + spin_lock_bh(&dev->reg_lock); + memcpy_fromio(buf, dev->mt76.mmio.regs + + __mt7915_reg_remap_addr(dev, offset), len); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7915_rr(struct mt76_dev *mdev, u32 offset) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - u32 addr = __mt7915_reg_addr(dev, offset); + u32 addr = __mt7915_reg_addr(dev, offset), val; - return dev->bus_ops->rr(mdev, addr); + if (addr) + return dev->bus_ops->rr(mdev, addr); + + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rr(mdev, __mt7915_reg_remap_addr(dev, offset)); + spin_unlock_bh(&dev->reg_lock); + + return val; } static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val) @@ -530,7 +550,14 @@ static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val) struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); u32 addr = __mt7915_reg_addr(dev, offset); - dev->bus_ops->wr(mdev, addr, val); + if (addr) { + dev->bus_ops->wr(mdev, addr, val); + return; + } + + spin_lock_bh(&dev->reg_lock); + dev->bus_ops->wr(mdev, __mt7915_reg_remap_addr(dev, offset), val); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) @@ -538,7 +565,14 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); u32 addr = __mt7915_reg_addr(dev, offset); - return dev->bus_ops->rmw(mdev, addr, mask, val); + if (addr) + return dev->bus_ops->rmw(mdev, addr, mask, val); + + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rmw(mdev, __mt7915_reg_remap_addr(dev, offset), mask, val); + spin_unlock_bh(&dev->reg_lock); + + return val; } #ifdef CONFIG_NET_MEDIATEK_SOC_WED @@ -707,6 +741,7 @@ static int mt7915_mmio_init(struct mt76_dev *mdev, dev = container_of(mdev, struct mt7915_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + spin_lock_init(&dev->reg_lock); switch (device_id) { case 0x7915: diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 4727d9c7b11d..6e79bc65f5a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -287,6 +287,7 @@ struct mt7915_dev { struct list_head sta_rc_list; struct list_head twt_list; + spinlock_t reg_lock; u32 hw_pattern; From 8b0fdca33d3d31687895ad78009193485c9aae2b Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Tue, 17 Oct 2023 16:32:51 +0800 Subject: [PATCH 1411/2255] wifi: mt76: mt7915: update mt798x_wmac_adie_patch_7976 Add support for a newer ADIE version Signed-off-by: Peter Chiu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/soc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index 8b4809703efc..f5b99917c08e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -516,7 +516,8 @@ static int mt798x_wmac_adie_patch_7976(struct mt7915_dev *dev, u8 adie) if (ret) return ret; - if (version == 0x8a00 || version == 0x8a10 || version == 0x8b00) { + if (version == 0x8a00 || version == 0x8a10 || + version == 0x8b00 || version == 0x8c10) { rg_xo_01 = 0x1d59080f; rg_xo_03 = 0x34c00fe0; } else { From 5302615954e3fb5d9d06281578ae975372304248 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 21 Dec 2023 11:26:48 +0800 Subject: [PATCH 1412/2255] dt-bindings: net: wireless: mt76: add interrupts description for MT7986 The mt7986 can support four interrupts to distribute the interrupts to different CPUs. Signed-off-by: Peter Chiu Reviewed-by: Krzysztof Kozlowski Signed-off-by: Felix Fietkau --- .../bindings/net/wireless/mediatek,mt76.yaml | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml index 252207adbc54..0c6835db397f 100644 --- a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml +++ b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml @@ -19,9 +19,6 @@ description: | Alternatively, it can specify the wireless part of the MT7628/MT7688 or MT7622/MT7986 SoC. -allOf: - - $ref: ieee80211.yaml# - properties: compatible: enum: @@ -38,7 +35,12 @@ properties: MT7986 should contain 3 regions consys, dcm, and sku, in this order. interrupts: - maxItems: 1 + minItems: 1 + items: + - description: major interrupt for rings + - description: additional interrupt for ring 19 + - description: additional interrupt for ring 4 + - description: additional interrupt for ring 5 power-domains: maxItems: 1 @@ -217,6 +219,23 @@ required: - compatible - reg +allOf: + - $ref: ieee80211.yaml# + - if: + properties: + compatible: + contains: + enum: + - mediatek,mt7986-wmac + then: + properties: + interrupts: + minItems: 4 + else: + properties: + interrupts: + maxItems: 1 + unevaluatedProperties: false examples: @@ -293,7 +312,10 @@ examples: reg = <0x18000000 0x1000000>, <0x10003000 0x1000>, <0x11d10000 0x1000>; - interrupts = ; + interrupts = , + , + , + ; clocks = <&topckgen 50>, <&topckgen 62>; clock-names = "mcu", "ap2conn"; From 030d2e287a902b44ef45e660cf1d73af23fe7d2e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 21 Dec 2023 10:41:18 +0100 Subject: [PATCH 1413/2255] wifi: mt76: mt7996: fix fw loading timeout Fix the following firmware loading error due to a wrong dma register configuration if wed is disabled. [ 8.245881] mt7996e_hif 0001:01:00.0: assign IRQ: got 128 [ 8.251308] mt7996e_hif 0001:01:00.0: enabling device (0000 -> 0002) [ 8.257674] mt7996e_hif 0001:01:00.0: enabling bus mastering [ 8.263488] mt7996e 0000:01:00.0: assign IRQ: got 126 [ 8.268537] mt7996e 0000:01:00.0: enabling device (0000 -> 0002) [ 8.274551] mt7996e 0000:01:00.0: enabling bus mastering [ 28.648773] mt7996e 0000:01:00.0: Message 00000010 (seq 1) timeout [ 28.654959] mt7996e 0000:01:00.0: Failed to get patch semaphore [ 29.661033] mt7996e: probe of 0000:01:00.0 failed with error -11 Suggested-by: Sujuan Chen" Fixes: 4920a3a1285f ("wifi: mt76: mt7996: set DMA mask to 36 bits for boards with more than 4GB of RAM") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 483ad81b6eec..fe37110e6687 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -237,7 +237,8 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | + MT_WFDMA0_GLO_CFG_EXT_EN); if (dev->hif2) mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, From 375c5eebbfa2b354f689e971c4d001798b8da4c7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 23 Dec 2023 11:43:06 +0800 Subject: [PATCH 1414/2255] wifi: mt76: usb: create a dedicated queue for psd traffic Create a dedicate queue for psd/mgmt traffic and do not rely on voice one. This is a preliminary patch to fix mt7921u/mt7925 usb dmasl configuration. Signed-off-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 5a0bcb5071bd..684e56af193b 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -767,7 +767,7 @@ static void mt76u_status_worker(struct mt76_worker *w) if (!test_bit(MT76_STATE_RUNNING, &dev->phy.state)) return; - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { q = dev->phy.q_tx[i]; if (!q) continue; @@ -928,14 +928,11 @@ static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac) static int mt76u_alloc_tx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j, err; + int i; for (i = 0; i <= MT_TXQ_PSD; i++) { - if (i >= IEEE80211_NUM_ACS) { - dev->phy.q_tx[i] = dev->phy.q_tx[0]; - continue; - } + struct mt76_queue *q; + int j, err; q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL); if (!q) @@ -969,7 +966,7 @@ static void mt76u_free_tx(struct mt76_dev *dev) mt76_worker_teardown(&dev->usb.status_worker); - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { struct mt76_queue *q; int j; @@ -999,7 +996,7 @@ void mt76u_stop_tx(struct mt76_dev *dev) dev_err(dev->dev, "timed out waiting for pending tx\n"); - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { q = dev->phy.q_tx[i]; if (!q) continue; @@ -1013,7 +1010,7 @@ void mt76u_stop_tx(struct mt76_dev *dev) /* On device removal we maight queue skb's, but mt76u_tx_kick() * will fail to submit urb, cleanup those skb's manually. */ - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { q = dev->phy.q_tx[i]; if (!q) continue; From 5304bf3b9915ba35aff3c9064fe37165d5471542 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 23 Dec 2023 11:43:07 +0800 Subject: [PATCH 1415/2255] wifi: mt76: usb: store usb endpoint in mt76_queue Store usb endpoint in mt76_queue structure and rework q2ep routine. Signed-off-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 10 ++---- .../wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +- drivers/net/wireless/mediatek/mt76/usb.c | 35 ++++++++++++------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b20c34d5a0f7..98fe533af20f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -210,6 +210,8 @@ struct mt76_queue { u16 first; u16 head; u16 tail; + u8 hw_idx; + u8 ep; int ndesc; int queued; int buf_size; @@ -217,7 +219,6 @@ struct mt76_queue { bool blocked; u8 buf_offset; - u8 hw_idx; u16 flags; struct mtk_wed_device *wed; @@ -1470,13 +1471,6 @@ static inline bool mt76u_urb_error(struct urb *urb) urb->status != -ENOENT; } -/* Map hardware queues to usb endpoints */ -static inline u8 q2ep(u8 qid) -{ - /* TODO: take management packets to queue 5 */ - return qid + 1; -} - static inline int mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len, int timeout, int ep) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 85a78dea4085..29b9a15f8dbe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -67,7 +67,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct mt76_tx_info *tx_info) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - int pid, len = tx_info->skb->len, ep = q2ep(dev->mphy.q_tx[qid]->hw_idx); + int pid, len = tx_info->skb->len, ep = dev->mphy.q_tx[qid]->ep; struct mt76x02_txwi *txwi; bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU; enum mt76_qsel qsel; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 684e56af193b..342c3aea549d 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -872,9 +872,8 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, if (err < 0) return err; - mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q2ep(q->hw_idx), - q->entry[idx].urb, mt76u_complete_tx, - &q->entry[idx]); + mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q->ep, q->entry[idx].urb, + mt76u_complete_tx, &q->entry[idx]); q->head = (q->head + 1) % q->ndesc; q->entry[idx].skb = tx_info.skb; @@ -906,9 +905,13 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) } } -static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac) +static void +mt76u_ac_to_hwq(struct mt76_dev *dev, struct mt76_queue *q, u8 qid) { - if (mt76_chip(dev) == 0x7663) { + u8 ac = qid < IEEE80211_NUM_ACS ? qid : IEEE80211_AC_BE; + + switch (mt76_chip(dev)) { + case 0x7663: { static const u8 lmac_queue_map[] = { /* ac to lmac mapping */ [IEEE80211_AC_BK] = 0, @@ -917,13 +920,20 @@ static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac) [IEEE80211_AC_VO] = 4, }; - if (WARN_ON(ac >= ARRAY_SIZE(lmac_queue_map))) - return 1; /* BE */ - - return lmac_queue_map[ac]; + q->hw_idx = lmac_queue_map[ac]; + q->ep = q->hw_idx + 1; + break; + } + case 0x7961: + case 0x7925: + q->hw_idx = mt76_ac_to_hwq(ac); + q->ep = qid == MT_TXQ_PSD ? MT_EP_OUT_HCCA : q->hw_idx + 1; + break; + default: + q->hw_idx = mt76_ac_to_hwq(ac); + q->ep = q->hw_idx + 1; + break; } - - return mt76_ac_to_hwq(ac); } static int mt76u_alloc_tx(struct mt76_dev *dev) @@ -939,8 +949,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) return -ENOMEM; spin_lock_init(&q->lock); - q->hw_idx = mt76u_ac_to_hwq(dev, i); - + mt76u_ac_to_hwq(dev, q, i); dev->phy.q_tx[i] = q; q->entry = devm_kcalloc(dev->dev, From 181fa345278478ff7c73511d8f51ebb3d13c501b Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Sat, 23 Dec 2023 11:43:08 +0800 Subject: [PATCH 1416/2255] wifi: mt76: mt792xu: enable dmashdl support dmashdl(DMA scheduler) was disable and may cause packets corruption without propoer resource handling. Enable this to control resources between usb-bus/pse/hardware-ac-queue. Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt792x_usb.c | 72 +++++++++---------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c index 589a3efb9f8c..b49668a4b784 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c @@ -121,44 +121,25 @@ static void mt792xu_uhw_wr(struct mt76_dev *dev, u32 addr, u32 val) static void mt792xu_dma_prefetch(struct mt792x_dev *dev) { - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0), - MT_WPDMA0_BASE_PTR_MASK, 0x80); +#define DMA_PREFETCH_CONF(_idx_, _cnt_, _base_) \ + mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL((_idx_)), \ + MT_WPDMA0_MAX_CNT_MASK | MT_WPDMA0_BASE_PTR_MASK, \ + FIELD_PREP(MT_WPDMA0_MAX_CNT_MASK, (_cnt_)) | \ + FIELD_PREP(MT_WPDMA0_BASE_PTR_MASK, (_base_))) - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1), - MT_WPDMA0_BASE_PTR_MASK, 0xc0); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2), - MT_WPDMA0_BASE_PTR_MASK, 0x100); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3), - MT_WPDMA0_BASE_PTR_MASK, 0x140); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4), - MT_WPDMA0_BASE_PTR_MASK, 0x180); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16), - MT_WPDMA0_BASE_PTR_MASK, 0x280); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17), - MT_WPDMA0_BASE_PTR_MASK, 0x2c0); + DMA_PREFETCH_CONF(0, 4, 0x080); + DMA_PREFETCH_CONF(1, 4, 0x0c0); + DMA_PREFETCH_CONF(2, 4, 0x100); + DMA_PREFETCH_CONF(3, 4, 0x140); + DMA_PREFETCH_CONF(4, 4, 0x180); + DMA_PREFETCH_CONF(16, 4, 0x280); + DMA_PREFETCH_CONF(17, 4, 0x2c0); } static void mt792xu_wfdma_init(struct mt792x_dev *dev) { + int i; + mt792xu_dma_prefetch(dev); mt76_clear(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_OMIT_RX_INFO); @@ -169,10 +150,27 @@ static void mt792xu_wfdma_init(struct mt792x_dev *dev) MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); - /* disable dmashdl */ - mt76_clear(dev, MT_UWFDMA0_GLO_CFG_EXT0, - MT_WFDMA0_CSR_TX_DMASHDL_ENABLE); - mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS); + mt76_rmw(dev, MT_DMASHDL_REFILL, MT_DMASHDL_REFILL_MASK, 0xffe00000); + mt76_clear(dev, MT_DMASHDL_PAGE, MT_DMASHDL_GROUP_SEQ_ORDER); + mt76_rmw(dev, MT_DMASHDL_PKT_MAX_SIZE, + MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 0)); + for (i = 0; i < 5; i++) + mt76_wr(dev, MT_DMASHDL_GROUP_QUOTA(i), + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0xfff)); + for (i = 5; i < 16; i++) + mt76_wr(dev, MT_DMASHDL_GROUP_QUOTA(i), + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x0) | + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x0)); + mt76_wr(dev, MT_DMASHDL_Q_MAP(0), 0x32013201); + mt76_wr(dev, MT_DMASHDL_Q_MAP(1), 0x32013201); + mt76_wr(dev, MT_DMASHDL_Q_MAP(2), 0x55555444); + mt76_wr(dev, MT_DMASHDL_Q_MAP(3), 0x55555444); + + mt76_wr(dev, MT_DMASHDL_SCHED_SET(0), 0x76540132); + mt76_wr(dev, MT_DMASHDL_SCHED_SET(1), 0xFEDCBA98); mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); } From 70b8250b30e2abbaa230e962a7198aa552654ce6 Mon Sep 17 00:00:00 2001 From: Dacio Romero Date: Fri, 22 Dec 2023 22:32:25 -0800 Subject: [PATCH 1417/2255] wifi: mt76: mt76x2u: add netgear wdna3100v3 to device table Netgear WDNA3100v3 has a chipset that's compatible with the mt76x2u driver and works without modification with the mainline kernel by writing to sysfs. Signed-off-by: Dacio Romero Acked-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index ca78e14251c2..e92bb871f231 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -18,6 +18,7 @@ static const struct usb_device_id mt76x2u_device_table[] = { { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ + { USB_DEVICE(0x0846, 0x9014) }, /* Netgear WNDA3100v3 */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ From 479146078a21ff2015cdd4e0467cba0559911915 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 29 Dec 2023 11:09:28 +0800 Subject: [PATCH 1418/2255] wifi: mt76: mt7925: fix connect to 80211b mode fail in 2Ghz band Driver should setting correct phy mode to firmware when in legacy mode. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index c5fd7116929b..1fc9ecb96bc4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1460,12 +1460,10 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, struct tlv *tlv; u8 af = 0, mm = 0; - if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa) - return; - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); phy = (struct sta_rec_phy *)tlv; phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, chandef->chan->band, sta); + phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); if (sta->deflink.ht_cap.ht_supported) { af = sta->deflink.ht_cap.ampdu_factor; mm = sta->deflink.ht_cap.ampdu_density; From 243cecc857735344473ea33a713cd5c2ec1fe347 Mon Sep 17 00:00:00 2001 From: "rong.yan" Date: Fri, 29 Dec 2023 11:09:29 +0800 Subject: [PATCH 1419/2255] wifi: mt76: mt7925: fix SAP no beacon issue in 5Ghz and 6Ghz band Driver should configure basic rate and phy mode for SAP mode. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: rong.yan Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 13 ++++++++++--- drivers/net/wireless/mediatek/mt76/mt7925/mcu.h | 3 ++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index ae6d0179727d..db96ddbeb9e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -935,6 +935,9 @@ enum { PHY_TYPE_INDEX_NUM }; +#define HR_DSSS_ERP_BASIC_RATE GENMASK(3, 0) +#define OFDM_BASIC_RATE (BIT(6) | BIT(8) | BIT(10)) + #define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) #define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) #define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 1fc9ecb96bc4..9a8db9b1a4f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2047,9 +2047,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; enum nl80211_band band = chandef->chan->band; struct mt76_connac_bss_basic_tlv *basic_req; - u8 idx, basic_phy; struct tlv *tlv; int conn_type; + u8 idx; tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*basic_req)); basic_req = (struct mt76_connac_bss_basic_tlv *)tlv; @@ -2060,8 +2060,10 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, sta); - basic_phy = mt76_connac_get_phy_mode_v2(phy, vif, band, sta); - basic_req->nonht_basic_phy = cpu_to_le16(basic_phy); + if (band == NL80211_BAND_2GHZ) + basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX); + else + basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX); memcpy(basic_req->bssid, vif->bss_conf.bssid, ETH_ALEN); basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, sta); @@ -2165,6 +2167,11 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, bmc = (struct bss_rate_tlv *)tlv; + if (band == NL80211_BAND_2GHZ) + bmc->basic_rate = cpu_to_le16(HR_DSSS_ERP_BASIC_RATE); + else + bmc->basic_rate = cpu_to_le16(OFDM_BASIC_RATE); + bmc->short_preamble = (band == NL80211_BAND_2GHZ); bmc->bc_fixed_rate = idx; bmc->mc_fixed_rate = idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 3c41e21303b1..0218fd2a0eb0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -334,7 +334,8 @@ struct bss_req_hdr { struct bss_rate_tlv { __le16 tag; __le16 len; - u8 __rsv1[4]; + u8 __rsv1[2]; + __le16 basic_rate; __le16 bc_trans; __le16 mc_trans; u8 short_preamble; From 2f475cb63eb304bdbb58c9b07b0547ca6c343012 Mon Sep 17 00:00:00 2001 From: Hao Zhang Date: Fri, 29 Dec 2023 11:09:30 +0800 Subject: [PATCH 1420/2255] wifi: mt76: mt7925: fix mcu query command fail Apply query command type properly to make the chip send the response back. Otherwise, we may see the command timeout in driver side. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Hao Zhang Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 9a8db9b1a4f2..4811fccbe30e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2850,12 +2850,16 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, if (cmd & __MCU_CMD_FIELD_UNI) { uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); - uni_txd->option = MCU_CMD_UNI_EXT_ACK; uni_txd->cid = cpu_to_le16(mcu_cmd); uni_txd->s2d_index = MCU_S2D_H2N; uni_txd->pkt_type = MCU_PKT_ID; uni_txd->seq = seq; + if (cmd & __MCU_CMD_FIELD_QUERY) + uni_txd->option = MCU_CMD_UNI_QUERY_ACK; + else + uni_txd->option = MCU_CMD_UNI_EXT_ACK; + goto exit; } From 9d89edb576e385267f40193bd3776157101a504a Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 29 Dec 2023 11:09:31 +0800 Subject: [PATCH 1421/2255] wifi: mt76: mt7925: fix wmm queue mapping Firmware uses access class index (ACI) for wmm parameters update, so convert mac80211 queue to ACI in mt7925_conf_tx(). Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 21 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 125a1be3cb64..5671e08dec65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1273,6 +1273,25 @@ mt7925_channel_switch_beacon(struct ieee80211_hw *hw, mt792x_mutex_release(dev); } +static int +mt7925_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + static const u8 mq_to_aci[] = { + [IEEE80211_AC_VO] = 3, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + }; + + /* firmware uses access class index */ + mvif->queue_params[mq_to_aci[queue]] = *params; + + return 0; +} + static int mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) @@ -1396,7 +1415,7 @@ const struct ieee80211_ops mt7925_ops = { .add_interface = mt7925_add_interface, .remove_interface = mt792x_remove_interface, .config = mt7925_config, - .conf_tx = mt792x_conf_tx, + .conf_tx = mt7925_conf_tx, .configure_filter = mt7925_configure_filter, .bss_info_changed = mt7925_bss_info_changed, .start_ap = mt7925_start_ap, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 4811fccbe30e..0299045b4b83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -895,7 +895,7 @@ int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) e = (struct edca *)tlv; e->set = WMM_PARAM_SET; - e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; + e->queue = ac; e->aifs = q->aifs; e->txop = cpu_to_le16(q->txop); From 6864bc734a48e90012cca8040cd0af72616666ca Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 29 Dec 2023 11:09:32 +0800 Subject: [PATCH 1422/2255] wifi: mt76: mt7925: fix fw download fail Add an address of fw region for fw download. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 3a20ba0d2492..ea7ffa16a4b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -66,7 +66,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || (is_mt7921(dev) && addr == 0x900000) || - (is_mt7925(dev) && addr == 0x900000) || + (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || (is_mt7996(dev) && addr == 0x900000) || (is_mt7992(dev) && addr == 0x900000)) cmd = MCU_CMD(PATCH_START_REQ); From 47916693ec7cd1b283ffa7554fc48ff4eec2daa1 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 29 Dec 2023 11:09:33 +0800 Subject: [PATCH 1423/2255] wifi: mt76: mt7925: fix WoW failed in encrypted mode When in suspend mode, WoW (Wake-on-WLAN) fails to wake the system remotely due to incorrect encryption mode settings. For the new mt7925 chipset, the old STA_REC_KEY_V2 command will send incorrect parameters to the firmware. Therefore, STA_REC_KEY_V3 has been introduced as a replacement for it. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7925/main.c | 3 +- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 86 ++++++++++--------- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 70 +++++++++++---- 4 files changed, 103 insertions(+), 57 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index db96ddbeb9e7..657a4d1f856b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -808,6 +808,7 @@ enum { STA_REC_MLD = 0x20, STA_REC_EHT = 0x22, STA_REC_PN_INFO = 0x26, + STA_REC_KEY_V3 = 0x27, STA_REC_HDRT = 0x28, STA_REC_HDR_TRANS = 0x2B, STA_REC_MAX_NUM diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 5671e08dec65..c74ba9642fc8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -359,6 +359,7 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mvif->sta.vif = mvif; mt76_wcid_init(&mvif->sta.wcid); mt7925_mac_wtbl_update(dev, idx, @@ -526,7 +527,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (cmd == SET_KEY && !mvif->mt76.cipher) { struct mt792x_phy *phy = mt792x_hw_phy(hw); - mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); + mvif->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); mt7925_mcu_add_bss_info(phy, mvif->mt76.ctx, vif, sta, true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 0299045b4b83..8c3233182083 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -921,61 +921,67 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, struct ieee80211_key_conf *key, enum set_key_cmd cmd) { + struct mt792x_sta *msta = container_of(wcid, struct mt792x_sta, wcid); struct sta_rec_sec_uni *sec; + struct mt792x_vif *mvif = msta->vif; + struct ieee80211_sta *sta; + struct ieee80211_vif *vif; struct tlv *tlv; - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); + sta = msta == &mvif->sta ? + NULL : + container_of((void *)msta, struct ieee80211_sta, drv_priv); + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec)); sec = (struct sta_rec_sec_uni *)tlv; - sec->add = cmd; + sec->bss_idx = mvif->mt76.idx; + sec->is_authenticator = 0; + sec->mgmt_prot = 0; + sec->wlan_idx = (u8)wcid->idx; + + if (sta) { + sec->tx_key = 1; + sec->key_type = 1; + memcpy(sec->peer_addr, sta->addr, ETH_ALEN); + } else { + memcpy(sec->peer_addr, vif->bss_conf.bssid, ETH_ALEN); + } if (cmd == SET_KEY) { - struct sec_key_uni *sec_key; u8 cipher; - cipher = mt76_connac_mcu_get_cipher(key->cipher); - if (cipher == MCU_CIPHER_NONE) + sec->add = 1; + cipher = mt7925_mcu_get_cipher(key->cipher); + if (cipher == CONNAC3_CIPHER_NONE) return -EOPNOTSUPP; - sec_key = &sec->key[0]; - sec_key->cipher_len = sizeof(*sec_key); - - if (cipher == MCU_CIPHER_BIP_CMAC_128) { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_AES_CCMP; - sec_key->key_id = sta_key_conf->keyidx; - sec_key->key_len = 16; - memcpy(sec_key->key, sta_key_conf->key, 16); - - sec_key = &sec->key[1]; - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; - sec_key->cipher_len = sizeof(*sec_key); - sec_key->key_len = 16; - memcpy(sec_key->key, key->key, 16); - sec->n_cipher = 2; + if (cipher == CONNAC3_CIPHER_BIP_CMAC_128) { + sec->cipher_id = CONNAC3_CIPHER_BIP_CMAC_128; + sec->key_id = sta_key_conf->keyidx; + sec->key_len = 32; + memcpy(sec->key, sta_key_conf->key, 16); + memcpy(sec->key + 16, key->key, 16); } else { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = cipher; - sec_key->key_id = key->keyidx; - sec_key->key_len = key->keylen; - memcpy(sec_key->key, key->key, key->keylen); + sec->cipher_id = cipher; + sec->key_id = key->keyidx; + sec->key_len = key->keylen; + memcpy(sec->key, key->key, key->keylen); - if (cipher == MCU_CIPHER_TKIP) { + if (cipher == CONNAC3_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ - memcpy(sec_key->key + 16, key->key + 24, 8); - memcpy(sec_key->key + 24, key->key + 16, 8); + memcpy(sec->key + 16, key->key + 24, 8); + memcpy(sec->key + 24, key->key + 16, 8); } /* store key_conf for BIP batch update */ - if (cipher == MCU_CIPHER_AES_CCMP) { + if (cipher == CONNAC3_CIPHER_AES_CCMP) { memcpy(sta_key_conf->key, key->key, key->keylen); sta_key_conf->keyidx = key->keyidx; } - - sec->n_cipher = 1; } } else { - sec->n_cipher = 0; + sec->add = 0; } return 0; @@ -2122,21 +2128,21 @@ mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) sec = (struct bss_sec_tlv *)tlv; switch (mvif->cipher) { - case MCU_CIPHER_GCMP_256: - case MCU_CIPHER_GCMP: + case CONNAC3_CIPHER_GCMP_256: + case CONNAC3_CIPHER_GCMP: sec->mode = MODE_WPA3_SAE; sec->status = 8; break; - case MCU_CIPHER_AES_CCMP: + case CONNAC3_CIPHER_AES_CCMP: sec->mode = MODE_WPA2_PSK; sec->status = 6; break; - case MCU_CIPHER_TKIP: + case CONNAC3_CIPHER_TKIP: sec->mode = MODE_WPA2_PSK; sec->status = 4; break; - case MCU_CIPHER_WEP104: - case MCU_CIPHER_WEP40: + case CONNAC3_CIPHER_WEP104: + case CONNAC3_CIPHER_WEP40: sec->mode = MODE_SHARED; sec->status = 0; break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 0218fd2a0eb0..9fce054e5065 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -159,6 +159,20 @@ enum { UNI_EVENT_SCAN_DONE_NLO = 3, }; +enum connac3_mcu_cipher_type { + CONNAC3_CIPHER_NONE = 0, + CONNAC3_CIPHER_WEP40 = 1, + CONNAC3_CIPHER_TKIP = 2, + CONNAC3_CIPHER_AES_CCMP = 4, + CONNAC3_CIPHER_WEP104 = 5, + CONNAC3_CIPHER_BIP_CMAC_128 = 6, + CONNAC3_CIPHER_WEP128 = 7, + CONNAC3_CIPHER_WAPI = 8, + CONNAC3_CIPHER_CCMP_256 = 10, + CONNAC3_CIPHER_GCMP = 11, + CONNAC3_CIPHER_GCMP_256 = 12, +}; + struct mt7925_mcu_scan_chinfo_event { u8 nr_chan; u8 alpha2[3]; @@ -383,25 +397,22 @@ struct sta_rec_eht { u8 _rsv2[3]; } __packed; -struct sec_key_uni { - __le16 wlan_idx; - u8 mgmt_prot; - u8 cipher_id; - u8 cipher_len; - u8 key_id; - u8 key_len; - u8 need_resp; - u8 key[32]; -} __packed; - struct sta_rec_sec_uni { __le16 tag; __le16 len; u8 add; - u8 n_cipher; - u8 rsv[2]; - - struct sec_key_uni key[2]; + u8 tx_key; + u8 key_type; + u8 is_authenticator; + u8 peer_addr[6]; + u8 bss_idx; + u8 cipher_id; + u8 key_id; + u8 key_len; + u8 wlan_idx; + u8 mgmt_prot; + u8 key[32]; + u8 key_rsc[16]; } __packed; struct sta_rec_hdr_trans { @@ -441,7 +452,7 @@ struct sta_rec_mld { sizeof(struct sta_rec_bfee) + \ sizeof(struct sta_rec_phy) + \ sizeof(struct sta_rec_ra) + \ - sizeof(struct sta_rec_sec) + \ + sizeof(struct sta_rec_sec_uni) + \ sizeof(struct sta_rec_ra_fixed) + \ sizeof(struct sta_rec_he_6g_capa) + \ sizeof(struct sta_rec_eht) + \ @@ -510,6 +521,33 @@ struct mt7925_wow_pattern_tlv { u8 rsv[4]; } __packed; +static inline enum connac3_mcu_cipher_type +mt7925_mcu_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return CONNAC3_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return CONNAC3_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return CONNAC3_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return CONNAC3_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return CONNAC3_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return CONNAC3_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return CONNAC3_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return CONNAC3_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return CONNAC3_CIPHER_WAPI; + default: + return CONNAC3_CIPHER_NONE; + } +} + int mt7925_mcu_set_dbdc(struct mt76_phy *phy); int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req); From d8cf7e1344727b80b4ec3dc17ca520238d55a88d Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 29 Dec 2023 11:09:34 +0800 Subject: [PATCH 1424/2255] wifi: mt76: mt7925: fix the wrong header translation config The header translation config should set to broadcast and unicast cases correctly, not only unicast case. And also remove the cmds of wtbl (wlan table) series, because these MCU commands have already been replaced by other commands in mt7925. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 8c3233182083..932ecf38672c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -814,6 +814,7 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct sta_rec_hdr_trans *hdr_trans; struct mt76_wcid *wcid; struct tlv *tlv; @@ -827,7 +828,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, else hdr_trans->from_ds = true; - wcid = (struct mt76_wcid *)sta->drv_priv; + if (sta) + wcid = (struct mt76_wcid *)sta->drv_priv; + else + wcid = &mvif->sta.wcid; + if (!wcid) return; @@ -1577,8 +1582,6 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, { struct mt76_vif *mvif = (struct mt76_vif *)info->vif->drv_priv; struct mt76_dev *dev = phy->dev; - struct wtbl_req_hdr *wtbl_hdr; - struct tlv *sta_wtbl; struct sk_buff *skb; skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, info->wcid, @@ -1602,30 +1605,11 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_state_v2_tlv(phy, skb, info->sta, info->vif, info->rcpi, info->state); - mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->sta); mt7925_mcu_sta_mld_tlv(skb, info->vif, info->sta); } - sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, - sizeof(struct tlv)); - - wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, info->wcid, - WTBL_RESET_AND_SET, - sta_wtbl, &skb); - if (IS_ERR(wtbl_hdr)) - return PTR_ERR(wtbl_hdr); - - if (info->enable) { - mt76_connac_mcu_wtbl_generic_tlv(dev, skb, info->vif, - info->sta, sta_wtbl, - wtbl_hdr); - mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, info->vif, info->wcid, - sta_wtbl, wtbl_hdr); - if (info->sta) - mt76_connac_mcu_wtbl_ht_tlv(dev, skb, info->sta, - sta_wtbl, wtbl_hdr, - true, true); - } + if (info->enable) + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->sta); return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); } From 9300ae0cd9e8f2407b20e0e67ee3ea03dc8b06af Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 29 Dec 2023 11:09:35 +0800 Subject: [PATCH 1425/2255] wifi: mt76: mt7925: add flow to avoid chip bt function fail A sub-process of Wifi L0.5 reset will make chip common partition enter low power, and have chance lead to Bluetooth host-to-chip command timeout, modify the software flow according to the chip's design to solve the problem. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Quan Zhou Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 1fd99a856541..74cfba7675be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -386,6 +386,8 @@ static int mt7925_pci_probe(struct pci_dev *pdev, dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + mt76_rmw_field(dev, MT_HW_EMI_CTL, MT_HW_EMI_CTL_SLPPROT_EN, 1); + ret = mt792x_wfsys_reset(dev); if (ret) goto err_free_dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h index a99af23e4b56..d7f9b24cd665 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h @@ -389,6 +389,9 @@ #define MT_HW_CHIPID 0x70010200 #define MT_HW_REV 0x70010204 +#define MT_HW_EMI_CTL 0x18011100 +#define MT_HW_EMI_CTL_SLPPROT_EN BIT(1) + #define MT_PCIE_MAC_BASE 0x10000 #define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) #define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) From 8536ef0aeae1177c4a59b043d4b1c41ddaa9df2a Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 29 Dec 2023 11:09:36 +0800 Subject: [PATCH 1426/2255] wifi: mt76: mt7925: add support to set ifs time by mcu command There's a race between driver and fw on some tx/rx control registers when setting ifs, which will cause accidental hw queue pause problems. Avoid this by setting ifs time with bss_info mcu command. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 33 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.h | 19 +++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index c74ba9642fc8..6179798a8845 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -711,7 +711,7 @@ static void mt7925_bss_info_changed(struct ieee80211_hw *hw, if (slottime != phy->slottime) { phy->slottime = slottime; - mt792x_mac_set_timeing(phy); + mt7925_mcu_set_timing(phy, vif); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 932ecf38672c..e1dd89a7a79c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2244,6 +2244,38 @@ mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, vif->bss_conf.he_bss_color.color : 0; } +static void +mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_phy *phy = mvif->phy; + struct bss_ifs_time_tlv *ifs_time; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time)); + ifs_time = (struct bss_ifs_time_tlv *)tlv; + ifs_time->slot_valid = true; + ifs_time->slot_time = cpu_to_le16(phy->slottime); +} + +int mt7925_mcu_set_timing(struct mt792x_phy *phy, + struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = phy->dev; + struct sk_buff *skb; + + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, + MT7925_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7925_mcu_bss_ifs_tlv(skb, vif); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD(BSS_INFO_UPDATE), true); +} + int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, struct ieee80211_vif *vif, @@ -2268,6 +2300,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, vif, sta); mt7925_mcu_bss_qos_tlv(skb, vif); mt7925_mcu_bss_mld_tlv(skb, vif, sta); + mt7925_mcu_bss_ifs_tlv(skb, vif); if (vif->bss_conf.he_support) { mt7925_mcu_bss_he_tlv(skb, vif, phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 9fce054e5065..2cf39276118e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -440,6 +440,22 @@ struct sta_rec_mld { } __packed link[2]; } __packed; +struct bss_ifs_time_tlv { + __le16 tag; + __le16 len; + u8 slot_valid; + u8 sifs_valid; + u8 rifs_valid; + u8 eifs_valid; + __le16 slot_time; + __le16 sifs_time; + __le16 rifs_time; + __le16 eifs_time; + u8 eifs_cck_valid; + u8 rsv; + __le16 eifs_cck_time; +} __packed; + #define MT7925_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_bf) + \ @@ -467,6 +483,7 @@ struct sta_rec_mld { sizeof(struct bss_mld_tlv) + \ sizeof(struct bss_info_uni_he) + \ sizeof(struct bss_info_uni_bss_color) + \ + sizeof(struct bss_ifs_time_tlv) + \ sizeof(struct tlv)) #define MT_CONNAC3_SKU_POWER_LIMIT 449 @@ -564,6 +581,8 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, int enable); +int mt7925_mcu_set_timing(struct mt792x_phy *phy, + struct ieee80211_vif *vif); int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); int mt7925_mcu_set_channel_domain(struct mt76_phy *phy); int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); From 0844947ccf64ea45edf6619ae2ba6dd9098b3308 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 29 Dec 2023 11:09:37 +0800 Subject: [PATCH 1427/2255] wifi: mt76: mt7925: update PCIe DMA settings Fix the wrong WFDMA settings to improve TX performance. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Deren Wu Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt792x_dma.c | 13 ++++++++++--- drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 5 +++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c index 488326ce5ed4..8fa36b59e738 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c @@ -123,14 +123,13 @@ static void mt792x_dma_prefetch(struct mt792x_dev *dev) int mt792x_dma_enable(struct mt792x_dev *dev) { - if (is_mt7925(&dev->mt76)) - mt76_rmw(dev, MT_UWFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28)); - /* configure perfetch settings */ mt792x_dma_prefetch(dev); /* reset dma idx */ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); + if (is_mt7925(&dev->mt76)) + mt76_wr(dev, MT_WFDMA0_RST_DRX_PTR, ~0); /* configure delay interrupt */ mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); @@ -140,12 +139,20 @@ int mt792x_dma_enable(struct mt792x_dev *dev) MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + FIELD_PREP(MT_WFDMA0_GLO_CFG_DMA_SIZE, 3) | + MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK | + MT_WFDMA0_GLO_CFG_RX_WB_DDONE | MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + if (is_mt7925(&dev->mt76)) { + mt76_rmw(dev, MT_UWFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28)); + mt76_set(dev, MT_WFDMA0_INT_RX_PRI, 0x0F00); + mt76_set(dev, MT_WFDMA0_INT_TX_PRI, 0x7F00); + } mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); /* enable interrupts for TX/RX rings */ diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h index d7f9b24cd665..458cfd0260b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h @@ -292,9 +292,12 @@ #define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY BIT(1) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) #define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY BIT(3) +#define MT_WFDMA0_GLO_CFG_DMA_SIZE GENMASK(5, 4) #define MT_WFDMA0_GLO_CFG_TX_WB_DDONE BIT(6) #define MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL BIT(9) +#define MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK BIT(11) #define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) +#define MT_WFDMA0_GLO_CFG_RX_WB_DDONE BIT(13) #define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN BIT(15) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) @@ -322,6 +325,8 @@ #define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) #define MT_WFDMA0_RST_DRX_PTR MT_WFDMA0(0x280) +#define MT_WFDMA0_INT_RX_PRI MT_WFDMA0(0x298) +#define MT_WFDMA0_INT_TX_PRI MT_WFDMA0(0x29c) #define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) #define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE BIT(6) #define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) From 396e41a74a88654f23e36c46d2995752c91654a5 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Sun, 24 Dec 2023 16:04:59 +0800 Subject: [PATCH 1428/2255] wifi: mt76: mt7925: support temperature sensor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow sensors tool to read radio's temperature, example: mt7925_phy8-pci-3b00 Adapter: PCI adapter temp1: +35.0°C Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/init.c | 56 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 36 ++++++++++++ .../wireless/mediatek/mt76/mt7925/mt7925.h | 1 + 3 files changed, 93 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index 8f9b7a2f376c..c4cbc8976046 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -2,11 +2,61 @@ /* Copyright (C) 2023 MediaTek Inc. */ #include +#include +#include +#include #include #include "mt7925.h" #include "mac.h" #include "mcu.h" +static ssize_t mt7925_thermal_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + switch (to_sensor_dev_attr(attr)->index) { + case 0: { + struct mt792x_phy *phy = dev_get_drvdata(dev); + struct mt792x_dev *mdev = phy->dev; + int temperature; + + mt792x_mutex_acquire(mdev); + temperature = mt7925_mcu_get_temperature(phy); + mt792x_mutex_release(mdev); + + if (temperature < 0) + return temperature; + /* display in millidegree Celsius */ + return sprintf(buf, "%u\n", temperature * 1000); + } + default: + return -EINVAL; + } +} +static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7925_thermal_temp, 0); + +static struct attribute *mt7925_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7925_hwmon); + +static int mt7925_thermal_init(struct mt792x_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct device *hwmon; + const char *name; + + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7925_%s", + wiphy_name(wiphy)); + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, + mt7925_hwmon_groups); + return PTR_ERR_OR_ZERO(hwmon); +} static void mt7925_regd_notifier(struct wiphy *wiphy, struct regulatory_request *req) @@ -142,6 +192,12 @@ static void mt7925_init_work(struct work_struct *work) return; } + ret = mt7925_thermal_init(&dev->phy); + if (ret) { + dev_err(dev->mt76.dev, "thermal init failed\n"); + return; + } + /* we support chip reset now */ dev->hw_init_done = true; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index e1dd89a7a79c..bd37cb8d734b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -656,6 +656,42 @@ int mt7925_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl) return ret; } +int mt7925_mcu_get_temperature(struct mt792x_phy *phy) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + u8 _rsv2[4]; + } __packed req = { + .tag = cpu_to_le16(0x0), + .len = cpu_to_le16(sizeof(req) - 4), + }; + struct mt7925_thermal_evt { + u8 rsv[4]; + __le32 temperature; + } __packed * evt; + struct mt792x_dev *dev = phy->dev; + int temperature, ret; + struct sk_buff *skb; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_WM_UNI_CMD_QUERY(THERMAL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + skb_pull(skb, 4 + sizeof(struct tlv)); + evt = (struct mt7925_thermal_evt *)skb->data; + + temperature = le32_to_cpu(evt->temperature); + + dev_kfree_skb(skb); + + return temperature; +} + static void mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 33785f526acf..8a4a71f6bcb6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -271,6 +271,7 @@ int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7925_mcu_config_sniffer(struct mt792x_vif *vif, struct ieee80211_chanctx_conf *ctx); +int mt7925_mcu_get_temperature(struct mt792x_phy *phy); int mt7925_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, From 9c9c25f1dcdd98fffda564d2073f26219c84a2c3 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Fri, 26 Jan 2024 17:09:12 +0800 Subject: [PATCH 1429/2255] wifi: mt76: mt7996: check txs format before getting skb by pid The PPDU TXS does not include the error bit so it cannot use to report status to mac80211. This patch fixes issue that STA wrongly detects if AP is still alive. Fixes: 2569ea5326e2 ("wifi: mt76: mt7996: enable PPDU-TxS to host") Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mac.c | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 53258488d49f..a8414fbb07c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1188,25 +1188,28 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, struct ieee80211_tx_info *info; struct sk_buff_head list; struct rate_info rate = {}; - struct sk_buff *skb; + struct sk_buff *skb = NULL; bool cck = false; u32 txrate, txs, mode, stbc; txs = le32_to_cpu(txs_data[0]); mt76_tx_status_lock(mdev, &list); - skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); - if (skb) { - info = IEEE80211_SKB_CB(skb); - if (!(txs & MT_TXS0_ACK_ERROR_MASK)) - info->flags |= IEEE80211_TX_STAT_ACK; + /* only report MPDU TXS */ + if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) == 0) { + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (skb) { + info = IEEE80211_SKB_CB(skb); + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) + info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ampdu_len = 1; - info->status.ampdu_ack_len = - !!(info->flags & IEEE80211_TX_STAT_ACK); + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = + !!(info->flags & IEEE80211_TX_STAT_ACK); - info->status.rates[0].idx = -1; + info->status.rates[0].idx = -1; + } } if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wcid->sta) { From 5c832c228f6a7ba7e900c5296ce0fb3844bafec5 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Fri, 26 Jan 2024 17:09:13 +0800 Subject: [PATCH 1430/2255] wifi: mt76: mt7996: fix TWT issues This patch fixes the following TWT issues: - Change table_mask to u16 to support up to 16 TWT stations - Reject TWT flows for duplicated establishment - Fix possible unaligned pointer - Remove unsupported TWT_CONTROL_WAKE_DUR_UNIT flag - The minimum TWT duration supported by mt7996 chipsets is 64. Reply with TWT_SETUP_CMD_DICTATE if the min_twt_dur is smaller than 64 Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mac.c | 53 ++++++++++++++++--- .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index a8414fbb07c8..63d34844c122 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -2530,6 +2530,34 @@ static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt) return 0; } +static bool +mt7996_mac_twt_param_equal(struct mt7996_sta *msta, + struct ieee80211_twt_params *twt_agrt) +{ + u16 type = le16_to_cpu(twt_agrt->req_type); + u8 exp; + int i; + + exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type); + for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) { + struct mt7996_twt_flow *f; + + if (!(msta->twt.flowid_mask & BIT(i))) + continue; + + f = &msta->twt.flow[i]; + if (f->duration == twt_agrt->min_twt_dur && + f->mantissa == twt_agrt->mantissa && + f->exp == exp && + f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) && + f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) && + f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER)) + return true; + } + + return false; +} + void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_twt_setup *twt) @@ -2541,8 +2569,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, enum ieee80211_twt_setup_cmd sta_setup_cmd; struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_twt_flow *flow; - int flowid, table_id; - u8 exp; + u8 flowid, table_id, exp; if (mt7996_mac_check_twt_req(twt)) goto out; @@ -2555,9 +2582,19 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) goto unlock; + if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) { + setup_cmd = TWT_SETUP_CMD_DICTATE; + twt_agrt->min_twt_dur = MT7996_MIN_TWT_DUR; + goto unlock; + } + + if (mt7996_mac_twt_param_equal(msta, twt_agrt)) + goto unlock; + flowid = ffs(~msta->twt.flowid_mask) - 1; - le16p_replace_bits(&twt_agrt->req_type, flowid, - IEEE80211_TWT_REQTYPE_FLOWID); + twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID); + twt_agrt->req_type |= le16_encode_bits(flowid, + IEEE80211_TWT_REQTYPE_FLOWID); table_id = ffs(~dev->twt.table_mask) - 1; exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type); @@ -2604,10 +2641,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, unlock: mutex_unlock(&dev->mt76.mutex); out: - le16p_replace_bits(&twt_agrt->req_type, setup_cmd, - IEEE80211_TWT_REQTYPE_SETUP_CMD); - twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) | - (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED); + twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD); + twt_agrt->req_type |= + le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD); + twt->control = twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED; } void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index bc73bcb47bf0..8154ad37827f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -53,6 +53,7 @@ #define MT7996_MAX_TWT_AGRT 16 #define MT7996_MAX_STA_TWT_AGRT 8 +#define MT7996_MIN_TWT_DUR 64 #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ @@ -320,7 +321,7 @@ struct mt7996_dev { struct rchan *relay_fwlog; struct { - u8 table_mask; + u16 table_mask; u8 n_agrt; } twt; From 5d5edc09197cd8c705b42a73cdf8ba03db53c033 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Fri, 26 Jan 2024 17:09:14 +0800 Subject: [PATCH 1431/2255] wifi: mt76: mt7996: disable AMSDU for non-data frames Disable AMSDU for non-data frames to prevent TX token leak issues. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 63d34844c122..0384fb059ddf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -732,6 +732,9 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi, FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); txwi[2] |= cpu_to_le32(val); + + if (wcid->amsdu) + txwi[3] |= cpu_to_le32(MT_TXD3_HW_AMSDU); } static void @@ -862,8 +865,6 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, val |= MT_TXD3_PROTECT_FRAME; if (info->flags & IEEE80211_TX_CTL_NO_ACK) val |= MT_TXD3_NO_ACK; - if (wcid->amsdu) - val |= MT_TXD3_HW_AMSDU; txwi[3] = cpu_to_le32(val); txwi[4] = 0; From d52c97592f06552a4289008602b5d5b724084ba7 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Fri, 26 Jan 2024 17:09:15 +0800 Subject: [PATCH 1432/2255] wifi: mt76: mt7996: fix incorrect interpretation of EHT MCS caps The EHT MCS map subfield of 20 MHz-Only is not present in the EHT capability of AP, so STA does not need to parse the subfield. Moreover, AP should parse the subfield only if STA is 20 MHz-Only, which can be confirmed by checking supported channel width in HE capability. Fixes: 92aa2da9fa49 ("wifi: mt76: mt7996: enable EHT support in firmware") Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: Benjamin Lin Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 3ec813077dc2..024e73c948d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1240,6 +1240,9 @@ mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) static void mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct ieee80211_vif *vif = container_of((void *)msta->vif, + struct ieee80211_vif, drv_priv); struct ieee80211_eht_mcs_nss_supp *mcs_map; struct ieee80211_eht_cap_elem_fixed *elem; struct sta_rec_eht *eht; @@ -1259,8 +1262,17 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info); eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]); - if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) - memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20)); + if (vif->type != NL80211_IFTYPE_STATION && + (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) { + memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, + sizeof(eht->mcs_map_bw20)); + return; + } + memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80)); memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160)); memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320)); From 5d197d37809b220616a0fb00856b9eeeafe1f69e Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Fri, 26 Jan 2024 17:09:16 +0800 Subject: [PATCH 1433/2255] wifi: mt76: mt7996: ensure 4-byte alignment for beacon commands If TLV includes beacon content, its length might not be 4-byte aligned. Make sure the length is aligned before sending beacon commands to FW. Signed-off-by: Benjamin Lin Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 14 +++++--------- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 4 ++-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 024e73c948d8..e46a9d4920a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -732,13 +732,10 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb) static struct tlv * mt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len) { - struct tlv *ptlv, tlv = { - .tag = cpu_to_le16(tag), - .len = cpu_to_le16(len), - }; + struct tlv *ptlv = skb_put(skb, len); - ptlv = skb_put(skb, len); - memcpy(ptlv, &tlv, sizeof(tlv)); + ptlv->tag = cpu_to_le16(tag); + ptlv->len = cpu_to_le16(len); return ptlv; } @@ -2522,7 +2519,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx); - len = sizeof(*bcn) + MT_TXD_SIZE + skb->len; + len = ALIGN(sizeof(*bcn) + MT_TXD_SIZE + skb->len, 4); tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len); bcn = (struct bss_bcn_content_tlv *)tlv; bcn->enable = en; @@ -2591,8 +2588,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, info->band = band; info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx); - len = sizeof(*discov) + MT_TXD_SIZE + skb->len; - + len = ALIGN(sizeof(*discov) + MT_TXD_SIZE + skb->len, 4); tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_OFFLOAD, len); discov = (struct bss_inband_discovery_tlv *)tlv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 36cacc495c75..43468bcaffc6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -800,10 +800,10 @@ enum { sizeof(struct sta_rec_hdr_trans) + \ sizeof(struct tlv)) -#define MT7996_MAX_BEACON_SIZE 1342 +#define MT7996_MAX_BEACON_SIZE 1338 #define MT7996_BEACON_UPDATE_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct bss_bcn_content_tlv) + \ - MT_TXD_SIZE + \ + 4 + MT_TXD_SIZE + \ sizeof(struct bss_bcn_cntdwn_tlv) + \ sizeof(struct bss_bcn_mbss_tlv)) #define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ From e1a491e856a8a36c46b39ecd07f3bba5a119d83a Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Fri, 26 Jan 2024 17:09:17 +0800 Subject: [PATCH 1434/2255] wifi: mt76: mt7996: fix HE beamformer phy cap for station vif Set correct beamformer capabilities for station vif in HE PHY capability IE. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 0cf0d1fe420a..1a1a60744272 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -1012,11 +1012,12 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy, /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3; - if (vif != NL80211_IFTYPE_AP) + if (!(vif == NL80211_IFTYPE_AP || vif == NL80211_IFTYPE_STATION)) return; elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; - elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + if (vif == NL80211_IFTYPE_AP) + elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, sts - 1) | From c3ee77ceed9c52bd9982486629fa632713f95498 Mon Sep 17 00:00:00 2001 From: Michael-CY Lee Date: Fri, 26 Jan 2024 17:09:18 +0800 Subject: [PATCH 1435/2255] wifi: mt76: mt7996: mark GCMP IGTK unsupported Since the FW does not support to handle the integrity and validation of IGTK in GCMP mode, return -EOPNOTSUPP to let it be handled by upper layer. Signed-off-by: Michael-CY Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 234e6495871b..0889a699d603 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -350,9 +350,12 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: + break; case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: - break; + if (key->keyidx == 6 || key->keyidx == 7) + break; + fallthrough; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: default: From d3ad99be7cc2d174126d908addd6bea2b157aa75 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Fri, 26 Jan 2024 17:09:19 +0800 Subject: [PATCH 1436/2255] wifi: mt76: mt7996: fix efuse reading issue The efuse data starts from the 48th bytes instead of 64th bytes in the returned event skb. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index e46a9d4920a8..b44abe2acc81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3547,7 +3547,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset) u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); u8 *buf = (u8 *)dev->mt76.eeprom.data + addr; - skb_pull(skb, 64); + skb_pull(skb, 48); memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE); } From 83877ed1ad2b179d14c08cf8f322587160b81d68 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Fri, 26 Jan 2024 17:09:20 +0800 Subject: [PATCH 1437/2255] wifi: mt76: mt7996: remove TXS queue setting DMA queue settings of TXS will be initialized by the firmware. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 1a1a60744272..5ae56b10f2b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -507,11 +507,6 @@ void mt7996_mac_init(struct mt7996_dev *dev) mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4); } - /* txs report queue */ - mt76_rmw_field(dev, MT_DMA_TCRF1(0), MT_DMA_TCRF1_QIDX, 0); - mt76_rmw_field(dev, MT_DMA_TCRF1(1), MT_DMA_TCRF1_QIDX, 6); - mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0); - /* rro module init */ if (is_mt7996(&dev->mt76)) mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); From 3687854d3e7e7fd760d939dd9e5a3520d5ab60fe Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Fri, 26 Jan 2024 17:09:21 +0800 Subject: [PATCH 1438/2255] wifi: mt76: mt7996: add locking for accessing mapped registers A race condition was observed when accessing mapped registers, so add locking to protect against concurrent access. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 64 ++++++++++++------- .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 9f2abfa273c9..efd4a767eb37 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -140,7 +140,6 @@ static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr) u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); - dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); @@ -155,7 +154,6 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); - dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, FIELD_PREP(MT_HIF_REMAP_L2_MASK, base)); @@ -165,26 +163,10 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) return MT_HIF_REMAP_BASE_L2 + offset; } -static void mt7996_reg_remap_restore(struct mt7996_dev *dev) -{ - /* remap to ori status */ - if (unlikely(dev->reg_l1_backup)) { - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup); - dev->reg_l1_backup = 0; - } - - if (dev->reg_l2_backup) { - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup); - dev->reg_l2_backup = 0; - } -} - static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) { int i; - mt7996_reg_remap_restore(dev); - if (addr < 0x100000) return addr; @@ -201,6 +183,11 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) return dev->reg.map[i].mapped + ofs; } + return 0; +} + +static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr) +{ if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) @@ -225,28 +212,60 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, { u32 addr = __mt7996_reg_addr(dev, offset); - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + if (addr) { + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + return; + } + + spin_lock_bh(&dev->reg_lock); + memcpy_fromio(buf, dev->mt76.mmio.regs + + __mt7996_reg_remap_addr(dev, offset), len); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset), val; - return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset)); + if (addr) + return dev->bus_ops->rr(mdev, addr); + + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rr(mdev, __mt7996_reg_remap_addr(dev, offset)); + spin_unlock_bh(&dev->reg_lock); + + return val; } static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset); - dev->bus_ops->wr(mdev, __mt7996_reg_addr(dev, offset), val); + if (addr) { + dev->bus_ops->wr(mdev, addr, val); + return; + } + + spin_lock_bh(&dev->reg_lock); + dev->bus_ops->wr(mdev, __mt7996_reg_remap_addr(dev, offset), val); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset); - return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); + if (addr) + return dev->bus_ops->rmw(mdev, addr, mask, val); + + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rmw(mdev, __mt7996_reg_remap_addr(dev, offset), mask, val); + spin_unlock_bh(&dev->reg_lock); + + return val; } #ifdef CONFIG_NET_MEDIATEK_SOC_WED @@ -421,6 +440,7 @@ static int mt7996_mmio_init(struct mt76_dev *mdev, dev = container_of(mdev, struct mt7996_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + spin_lock_init(&dev->reg_lock); switch (device_id) { case 0x7990: diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 8154ad37827f..36d1f247d55a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -325,8 +325,7 @@ struct mt7996_dev { u8 n_agrt; } twt; - u32 reg_l1_backup; - u32 reg_l2_backup; + spinlock_t reg_lock; u8 wtbl_size_group; }; From 098428c400ff2d0f32b7cc0dc003c8da4b69908d Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Fri, 26 Jan 2024 17:09:22 +0800 Subject: [PATCH 1439/2255] wifi: mt76: connac: set correct muar_idx for mt799x chipsets The MUAR (multicast unicast address) is an address mapping table that participates in the process of searching WTBL entries. For mt799x chipsets, the default muar index of BMC WTBL is 0xe. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 5 +++++ drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index fdde3d70b300..98d64d3d2993 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -227,6 +227,11 @@ static inline bool is_mt7992(struct mt76_dev *dev) return mt76_chip(dev) == 0x7992; } +static inline bool is_mt799x(struct mt76_dev *dev) +{ + return is_mt7996(dev) || is_mt7992(dev); +} + static inline bool is_mt7622(struct mt76_dev *dev) { if (!IS_ENABLED(CONFIG_MT7622_WMAC)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index ea7ffa16a4b1..9aff0c13efd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -283,6 +283,9 @@ __mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif, }; struct sk_buff *skb; + if (is_mt799x(dev) && !wcid->sta) + hdr.muar_idx = 0xe; + mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo, &hdr.wlan_idx_hi); skb = mt76_mcu_msg_alloc(dev, NULL, len); From de8882775156682ba358afc82cb575c92cf3d092 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Fri, 26 Jan 2024 17:09:23 +0800 Subject: [PATCH 1440/2255] wifi: mt76: mt7996: fix HIF_TXD_V2_1 value Sync the value of HIF_TXD_V2_1 with firmware to let it correctly fill TXD values for HW path. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: Benjamin Lin Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 5ae56b10f2b9..283df84f1b43 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -493,7 +493,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) void mt7996_mac_init(struct mt7996_dev *dev) { -#define HIF_TXD_V2_1 4 +#define HIF_TXD_V2_1 0x21 int i; mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); From 7b4f9cd6a5fc221895b1d9be83ee3c13c00d09ab Mon Sep 17 00:00:00 2001 From: Gen Xu Date: Sat, 27 Jan 2024 09:04:30 -0800 Subject: [PATCH 1441/2255] wifi: mt76: mt792x: fix ethtool warning Add a missing EHT related field to fix the following ethtool warning: [98179.287352] mt7921e 0003:01:00.0: ei: 74 SSTATS_LEN: 73 Fixes: c74df1c067f2 ("wifi: mt76: mt792x: introduce mt792x-lib module") Signed-off-by: Gen Xu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt792x_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 7872fbae7252..a405af8d9052 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -354,6 +354,7 @@ static const char mt792x_gstrings_stats[][ETH_GSTRING_LEN] = { "v_tx_bw_40", "v_tx_bw_80", "v_tx_bw_160", + "v_tx_bw_320", "v_tx_mcs_0", "v_tx_mcs_1", "v_tx_mcs_2", From 8a7386e787ef4d9649930bb09cdf55ccd2102346 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Dec 2023 13:07:29 +0100 Subject: [PATCH 1442/2255] wifi: mt76: move wed common utilities in wed.c Introduce wed.c in order to collect mt76 wed common codebase used by mt7915 and mt7996 drivers. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/dma.c | 106 +-------- drivers/net/wireless/mediatek/mt76/dma.h | 9 +- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 -- drivers/net/wireless/mediatek/mt76/mmio.c | 107 --------- drivers/net/wireless/mediatek/mt76/mt76.h | 39 +++- .../net/wireless/mediatek/mt76/mt7915/dma.c | 2 +- .../net/wireless/mediatek/mt76/mt7915/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7915/mmio.c | 10 +- .../net/wireless/mediatek/mt76/mt7996/dma.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 10 +- drivers/net/wireless/mediatek/mt76/wed.c | 213 ++++++++++++++++++ 13 files changed, 268 insertions(+), 252 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/wed.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index d6575fe18c6b..f7f2d9a8ab0f 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_MT792x_USB) += mt792x-usb.o mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ - tx.o agg-rx.o mcu.o + tx.o agg-rx.o mcu.o wed.o mt76-$(CONFIG_PCI) += pci.o mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 00230f106294..72a7bd5a8576 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -197,9 +197,8 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) q->tail = q->head; } -static void -__mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, - bool reset_idx) +void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx) { if (!q || !q->ndesc) return; @@ -219,8 +218,7 @@ __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, mt76_dma_sync_idx(dev, q); } -static void -mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) { __mt76_dma_queue_reset(dev, q, true); } @@ -632,9 +630,8 @@ free_skb: return ret; } -static int -mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, - bool allow_direct) +int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, + bool allow_direct) { int len = SKB_WITH_OVERHEAD(q->buf_size); int frames = 0; @@ -681,81 +678,6 @@ done: return frames; } -int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) -{ -#ifdef CONFIG_NET_MEDIATEK_SOC_WED - int ret = 0, type, ring; - u16 flags; - - if (!q || !q->ndesc) - return -EINVAL; - - flags = q->flags; - if (!q->wed || !mtk_wed_device_active(q->wed)) - q->flags &= ~MT_QFLAG_WED; - - if (!(q->flags & MT_QFLAG_WED)) - return 0; - - type = FIELD_GET(MT_QFLAG_WED_TYPE, q->flags); - ring = FIELD_GET(MT_QFLAG_WED_RING, q->flags); - - switch (type) { - case MT76_WED_Q_TX: - ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs, - reset); - if (!ret) - q->wed_regs = q->wed->tx_ring[ring].reg_base; - break; - case MT76_WED_Q_TXFREE: - /* WED txfree queue needs ring to be initialized before setup */ - q->flags = 0; - mt76_dma_queue_reset(dev, q); - mt76_dma_rx_fill(dev, q, false); - - ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); - if (!ret) - q->wed_regs = q->wed->txfree_ring.reg_base; - break; - case MT76_WED_Q_RX: - ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs, - reset); - if (!ret) - q->wed_regs = q->wed->rx_ring[ring].reg_base; - break; - case MT76_WED_RRO_Q_DATA: - q->flags &= ~MT_QFLAG_WED; - __mt76_dma_queue_reset(dev, q, false); - mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); - q->head = q->ndesc - 1; - q->queued = q->head; - break; - case MT76_WED_RRO_Q_MSDU_PG: - q->flags &= ~MT_QFLAG_WED; - __mt76_dma_queue_reset(dev, q, false); - mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); - q->head = q->ndesc - 1; - q->queued = q->head; - break; - case MT76_WED_RRO_Q_IND: - q->flags &= ~MT_QFLAG_WED; - mt76_dma_queue_reset(dev, q); - mt76_dma_rx_fill(dev, q, false); - mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); - break; - default: - ret = -EINVAL; - break; - } - q->flags = flags; - - return ret; -#else - return 0; -#endif -} -EXPORT_SYMBOL_GPL(mt76_dma_wed_setup); - static int mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize, @@ -800,7 +722,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (ret) return ret; - ret = mt76_dma_wed_setup(dev, q, false); + ret = mt76_wed_dma_setup(dev, q, false); if (ret) return ret; @@ -863,7 +785,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) mt76_dma_rx_cleanup(dev, q); /* reset WED rx queues */ - mt76_dma_wed_setup(dev, q, true); + mt76_wed_dma_setup(dev, q, true); if (mt76_queue_is_wed_tx_free(q)) return; @@ -1054,20 +976,6 @@ void mt76_dma_attach(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_dma_attach); -void mt76_dma_wed_reset(struct mt76_dev *dev) -{ - struct mt76_mmio *mmio = &dev->mmio; - - if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state)) - return; - - complete(&mmio->wed_reset); - - if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ)) - dev_err(dev->dev, "wed reset complete timeout\n"); -} -EXPORT_SYMBOL_GPL(mt76_dma_wed_reset); - void mt76_dma_cleanup(struct mt76_dev *dev) { int i; diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index c479cc6388ef..1de5a2b20f74 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -79,15 +79,18 @@ enum mt76_dma_wed_ind_reason { int mt76_dma_rx_poll(struct napi_struct *napi, int budget); void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); -int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); -void mt76_dma_wed_reset(struct mt76_dev *dev); +int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, + bool allow_direct); +void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx); +void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q); static inline void mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) { dev->queue_ops->reset_q(dev, q); if (mtk_wed_device_active(&dev->mmio.wed)) - mt76_dma_wed_setup(dev, q, true); + mt76_wed_dma_setup(dev, q, true); } static inline void diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 758e380fdf1d..e3ebadcd1499 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1854,19 +1854,3 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) return MT_DFS_STATE_ACTIVE; } EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); - -#ifdef CONFIG_NET_MEDIATEK_SOC_WED -int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct net_device *netdev, enum tc_setup_type type, - void *type_data) -{ - struct mt76_phy *phy = hw->priv; - struct mtk_wed_device *wed = &phy->dev->mmio.wed; - - if (!mtk_wed_device_active(wed)) - return -EOPNOTSUPP; - - return mtk_wed_device_setup_tc(wed, netdev, type, type_data); -} -EXPORT_SYMBOL_GPL(mt76_net_setup_tc); -#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index c3e0e23e0161..cd2e9737c3bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -85,113 +85,6 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, } EXPORT_SYMBOL_GPL(mt76_set_irq_mask); -#ifdef CONFIG_NET_MEDIATEK_SOC_WED -void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - int i; - - for (i = 0; i < dev->rx_token_size; i++) { - struct mt76_txwi_cache *t; - - t = mt76_rx_token_release(dev, i); - if (!t || !t->ptr) - continue; - - mt76_put_page_pool_buf(t->ptr, false); - t->ptr = NULL; - - mt76_put_rxwi(dev, t); - } - - mt76_free_pending_rxwi(dev); -} -EXPORT_SYMBOL_GPL(mt76_mmio_wed_release_rx_buf); - -u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; - struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; - int i, len = SKB_WITH_OVERHEAD(q->buf_size); - struct mt76_txwi_cache *t = NULL; - - for (i = 0; i < size; i++) { - enum dma_data_direction dir; - dma_addr_t addr; - u32 offset; - int token; - void *buf; - - t = mt76_get_rxwi(dev); - if (!t) - goto unmap; - - buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); - if (!buf) - goto unmap; - - addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; - dir = page_pool_get_dma_dir(q->page_pool); - dma_sync_single_for_device(dev->dma_dev, addr, len, dir); - - desc->buf0 = cpu_to_le32(addr); - token = mt76_rx_token_consume(dev, buf, t, addr); - if (token < 0) { - mt76_put_page_pool_buf(buf, false); - goto unmap; - } - - token = FIELD_PREP(MT_DMA_CTL_TOKEN, token); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - token |= FIELD_PREP(MT_DMA_CTL_SDP0_H, addr >> 32); -#endif - desc->token |= cpu_to_le32(token); - desc++; - } - - return 0; - -unmap: - if (t) - mt76_put_rxwi(dev, t); - mt76_mmio_wed_release_rx_buf(wed); - - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf); - -int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - - spin_lock_bh(&dev->token_lock); - dev->token_size = wed->wlan.token_start; - spin_unlock_bh(&dev->token_lock); - - return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ); -} -EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_enable); - -void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - - spin_lock_bh(&dev->token_lock); - dev->token_size = dev->drv->token_size; - spin_unlock_bh(&dev->token_lock); -} -EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable); - -void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - - complete(&dev->mmio.wed_reset_complete); -} -EXPORT_SYMBOL_GPL(mt76_mmio_wed_reset_complete); -#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ - void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) { static const struct mt76_bus_ops mt76_mmio_ops = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 98fe533af20f..ac969a88438b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1082,12 +1082,6 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); void mt76_pci_disable_aspm(struct pci_dev *pdev); -#ifdef CONFIG_NET_MEDIATEK_SOC_WED -int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct net_device *netdev, enum tc_setup_type type, - void *type_data); -#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ - static inline u16 mt76_chip(struct mt76_dev *dev) { return dev->rev >> 16; @@ -1098,13 +1092,34 @@ static inline u16 mt76_rev(struct mt76_dev *dev) return dev->rev & 0xffff; } +void mt76_wed_release_rx_buf(struct mtk_wed_device *wed); +void mt76_wed_offload_disable(struct mtk_wed_device *wed); +void mt76_wed_reset_complete(struct mtk_wed_device *wed); +void mt76_wed_dma_reset(struct mt76_dev *dev); +int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data); #ifdef CONFIG_NET_MEDIATEK_SOC_WED -u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); -void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); -int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed); -void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed); -void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed); -#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ +u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size); +int mt76_wed_offload_enable(struct mtk_wed_device *wed); +int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +#else +static inline u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + return 0; +} + +static inline int mt76_wed_offload_enable(struct mtk_wed_device *wed) +{ + return 0; +} + +static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, + bool reset) +{ + return 0; +} +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index c91a1c54027f..0baa82c8df5a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -614,7 +614,7 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) mtk_wed_device_dma_reset(wed); mt7915_dma_disable(dev, force); - mt76_dma_wed_reset(&dev->mt76); + mt76_wed_dma_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index df2d4279790d..3709d18da0e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1708,6 +1708,6 @@ const struct ieee80211_ops mt7915_ops = { .set_radar_background = mt7915_set_radar_background, #ifdef CONFIG_NET_MEDIATEK_SOC_WED .net_fill_forward_path = mt7915_net_fill_forward_path, - .net_setup_tc = mt76_net_setup_tc, + .net_setup_tc = mt76_wed_net_setup_tc, #endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index dceb505987b1..d6ecd698cdcd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -706,13 +706,13 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, } wed->wlan.init_buf = mt7915_wed_init_buf; - wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; - wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; - wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; - wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_wed_offload_enable; + wed->wlan.offload_disable = mt76_wed_offload_disable; + wed->wlan.init_rx_buf = mt76_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; wed->wlan.reset = mt7915_mmio_wed_reset; - wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; + wed->wlan.reset_complete = mt76_wed_reset_complete; dev->mt76.rx_token_size = wed->wlan.rx_npkt; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index fe37110e6687..73e633d0d700 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -695,7 +695,7 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force) mtk_wed_device_dma_reset(&dev->mt76.mmio.wed); mt7996_dma_disable(dev, force); - mt76_dma_wed_reset(&dev->mt76); + mt76_wed_dma_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 0889a699d603..f7da8d6dd903 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1502,6 +1502,6 @@ const struct ieee80211_ops mt7996_ops = { .set_radar_background = mt7996_set_radar_background, #ifdef CONFIG_NET_MEDIATEK_SOC_WED .net_fill_forward_path = mt7996_net_fill_forward_path, - .net_setup_tc = mt76_net_setup_tc, + .net_setup_tc = mt76_wed_net_setup_tc, #endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index efd4a767eb37..304e5fd14803 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -410,13 +410,13 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.amsdu_max_len = 1536; wed->wlan.init_buf = mt7996_wed_init_buf; - wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; - wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; - wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; - wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; + wed->wlan.init_rx_buf = mt76_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_wed_offload_enable; + wed->wlan.offload_disable = mt76_wed_offload_disable; if (!hif2) { wed->wlan.reset = mt7996_mmio_wed_reset; - wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; + wed->wlan.reset_complete = mt76_wed_reset_complete; } if (mtk_wed_device_attach(wed)) diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c new file mode 100644 index 000000000000..f89e4537555c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/wed.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2023 Lorenzo Bianconi + */ + +#include "mt76.h" +#include "dma.h" + +void mt76_wed_release_rx_buf(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + int i; + + for (i = 0; i < dev->rx_token_size; i++) { + struct mt76_txwi_cache *t; + + t = mt76_rx_token_release(dev, i); + if (!t || !t->ptr) + continue; + + mt76_put_page_pool_buf(t->ptr, false); + t->ptr = NULL; + + mt76_put_rxwi(dev, t); + } + + mt76_free_pending_rxwi(dev); +} +EXPORT_SYMBOL_GPL(mt76_wed_release_rx_buf); + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + int i, len = SKB_WITH_OVERHEAD(q->buf_size); + struct mt76_txwi_cache *t = NULL; + + for (i = 0; i < size; i++) { + enum dma_data_direction dir; + dma_addr_t addr; + u32 offset; + int token; + void *buf; + + t = mt76_get_rxwi(dev); + if (!t) + goto unmap; + + buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); + if (!buf) + goto unmap; + + addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; + dir = page_pool_get_dma_dir(q->page_pool); + dma_sync_single_for_device(dev->dma_dev, addr, len, dir); + + desc->buf0 = cpu_to_le32(addr); + token = mt76_rx_token_consume(dev, buf, t, addr); + if (token < 0) { + mt76_put_page_pool_buf(buf, false); + goto unmap; + } + + token = FIELD_PREP(MT_DMA_CTL_TOKEN, token); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + token |= FIELD_PREP(MT_DMA_CTL_SDP0_H, addr >> 32); +#endif + desc->token |= cpu_to_le32(token); + desc++; + } + + return 0; + +unmap: + if (t) + mt76_put_rxwi(dev, t); + mt76_wed_release_rx_buf(wed); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(mt76_wed_init_rx_buf); + +int mt76_wed_offload_enable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = wed->wlan.token_start; + spin_unlock_bh(&dev->token_lock); + + return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ); +} +EXPORT_SYMBOL_GPL(mt76_wed_offload_enable); + +int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) +{ + int ret = 0, type, ring; + u16 flags; + + if (!q || !q->ndesc) + return -EINVAL; + + flags = q->flags; + if (!q->wed || !mtk_wed_device_active(q->wed)) + q->flags &= ~MT_QFLAG_WED; + + if (!(q->flags & MT_QFLAG_WED)) + return 0; + + type = FIELD_GET(MT_QFLAG_WED_TYPE, q->flags); + ring = FIELD_GET(MT_QFLAG_WED_RING, q->flags); + + switch (type) { + case MT76_WED_Q_TX: + ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs, + reset); + if (!ret) + q->wed_regs = q->wed->tx_ring[ring].reg_base; + break; + case MT76_WED_Q_TXFREE: + /* WED txfree queue needs ring to be initialized before setup */ + q->flags = 0; + mt76_dma_queue_reset(dev, q); + mt76_dma_rx_fill(dev, q, false); + + ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); + if (!ret) + q->wed_regs = q->wed->txfree_ring.reg_base; + break; + case MT76_WED_Q_RX: + ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs, + reset); + if (!ret) + q->wed_regs = q->wed->rx_ring[ring].reg_base; + break; + case MT76_WED_RRO_Q_DATA: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_MSDU_PG: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_IND: + q->flags &= ~MT_QFLAG_WED; + mt76_dma_queue_reset(dev, q); + mt76_dma_rx_fill(dev, q, false); + mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); + break; + default: + ret = -EINVAL; + break; + } + q->flags = flags; + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_wed_dma_setup); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + +void mt76_wed_offload_disable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = dev->drv->token_size; + spin_unlock_bh(&dev->token_lock); +} +EXPORT_SYMBOL_GPL(mt76_wed_offload_disable); + +void mt76_wed_reset_complete(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + complete(&dev->mmio.wed_reset_complete); +} +EXPORT_SYMBOL_GPL(mt76_wed_reset_complete); + +int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data) +{ + struct mt76_phy *phy = hw->priv; + struct mtk_wed_device *wed = &phy->dev->mmio.wed; + + if (!mtk_wed_device_active(wed)) + return -EOPNOTSUPP; + + return mtk_wed_device_setup_tc(wed, netdev, type, type_data); +} +EXPORT_SYMBOL_GPL(mt76_wed_net_setup_tc); + +void mt76_wed_dma_reset(struct mt76_dev *dev) +{ + struct mt76_mmio *mmio = &dev->mmio; + + if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state)) + return; + + complete(&mmio->wed_reset); + + if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ)) + dev_err(dev->dev, "wed reset complete timeout\n"); +} +EXPORT_SYMBOL_GPL(mt76_wed_dma_reset); From 3c37da57131fe5a9fd3bbda94bf583812e0d543b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Dec 2023 10:15:19 +0100 Subject: [PATCH 1443/2255] wifi: mt76: set page_pool napi pointer for mmio devices In order to recycle skbs in the page_pool "hot" cache in napi_pp_put_page routine, set napi pointer for MMIO devices in mt76_create_page_pool(). Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 10 +++++++++- drivers/net/wireless/mediatek/mt76/mt76.h | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index e3ebadcd1499..068206e48aec 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -579,13 +579,18 @@ EXPORT_SYMBOL_GPL(mt76_unregister_phy); int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) { + bool is_qrx = mt76_queue_is_rx(dev, q); struct page_pool_params pp_params = { .order = 0, .flags = 0, .nid = NUMA_NO_NODE, .dev = dev->dma_dev, }; - int idx = q - dev->q_rx; + int idx = is_qrx ? q - dev->q_rx : -1; + + /* Allocate page_pools just for rx/wed_tx_free queues */ + if (!is_qrx && !mt76_queue_is_wed_tx_free(q)) + return 0; switch (idx) { case MT_RXQ_MAIN: @@ -604,6 +609,9 @@ int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) pp_params.dma_dir = DMA_FROM_DEVICE; pp_params.max_len = PAGE_SIZE; pp_params.offset = 0; + /* NAPI is available just for rx queues */ + if (idx >= 0 && idx < ARRAY_SIZE(dev->napi)) + pp_params.napi = &dev->napi[idx]; } q->page_pool = page_pool_create(&pp_params); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ac969a88438b..a91f6ddacbd9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1607,6 +1607,18 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, struct mt76_power_limits *dest, s8 target_power); +static inline bool mt76_queue_is_rx(struct mt76_dev *dev, struct mt76_queue *q) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) { + if (q == &dev->q_rx[i]) + return true; + } + + return false; +} + static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) { return (q->flags & MT_QFLAG_WED) && From 1f01276b7ab8e9af348bb8fe70613746867e763d Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Wed, 10 Jan 2024 17:54:57 +0800 Subject: [PATCH 1444/2255] wifi: mt76: mt7925: fix the wrong data type for scan command For the member of 'struct scan_req_tlv', replace data type of func_mask_ext from 'u8' to '__le32'. Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 2cf39276118e..2a0bbfe7bfa5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -222,7 +222,7 @@ struct scan_req_tlv { __le16 channel_dwell_time; /* channel Dwell interval */ __le16 timeout_value; __le16 probe_delay_time; - u8 func_mask_ext; + __le32 func_mask_ext; }; struct scan_ssid_tlv { From 926f9fb7df9edd94b13bb8b5c6d5ee12d94e3429 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Thu, 11 Jan 2024 14:18:56 +0800 Subject: [PATCH 1445/2255] wifi: mt76: mt792x: add the illegal value check for mtcl table of acpi The mtcl table provided regulatory information for 5.9/6Ghz channels and configured by platform venders. So, sometimes vendors may write illegal values, and therefore it is necessary to check and add corresponding handling for such cases. Signed-off-by: Leon Yen Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c index e7afea87e82e..c64562216caa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -353,11 +353,15 @@ static u8 mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl) { u8 config = 0; + u8 mode_6g, mode_5g9; - if (cl->cl6g[row] & BIT(column)) - config |= (cl->mode_6g & 0x3) << 2; + mode_6g = (cl->mode_6g > 0x02) ? 0 : cl->mode_6g; + mode_5g9 = (cl->mode_5g9 > 0x01) ? 0 : cl->mode_5g9; + + if ((cl->cl6g[row] & BIT(column)) || cl->mode_6g == 0x02) + config |= (mode_6g & 0x3) << 2; if (cl->version > 1 && cl->cl5g9[row] & BIT(column)) - config |= (cl->mode_5g9 & 0x3); + config |= (mode_5g9 & 0x3); return config; } From c957280ef6ab6bdf559a91ae693a6b34310697e3 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Sat, 13 Jan 2024 17:00:22 +0800 Subject: [PATCH 1446/2255] wifi: mt76: mt7921e: fix use-after-free in free_irq() From commit a304e1b82808 ("[PATCH] Debug shared irqs"), there is a test to make sure the shared irq handler should be able to handle the unexpected event after deregistration. For this case, let's apply MT76_REMOVED flag to indicate the device was removed and do not run into the resource access anymore. BUG: KASAN: use-after-free in mt7921_irq_handler+0xd8/0x100 [mt7921e] Read of size 8 at addr ffff88824a7d3b78 by task rmmod/11115 CPU: 28 PID: 11115 Comm: rmmod Tainted: G W L 5.17.0 #10 Hardware name: Micro-Star International Co., Ltd. MS-7D73/MPG B650I EDGE WIFI (MS-7D73), BIOS 1.81 01/05/2024 Call Trace: dump_stack_lvl+0x6f/0xa0 print_address_description.constprop.0+0x1f/0x190 ? mt7921_irq_handler+0xd8/0x100 [mt7921e] ? mt7921_irq_handler+0xd8/0x100 [mt7921e] kasan_report.cold+0x7f/0x11b ? mt7921_irq_handler+0xd8/0x100 [mt7921e] mt7921_irq_handler+0xd8/0x100 [mt7921e] free_irq+0x627/0xaa0 devm_free_irq+0x94/0xd0 ? devm_request_any_context_irq+0x160/0x160 ? kobject_put+0x18d/0x4a0 mt7921_pci_remove+0x153/0x190 [mt7921e] pci_device_remove+0xa2/0x1d0 __device_release_driver+0x346/0x6e0 driver_detach+0x1ef/0x2c0 bus_remove_driver+0xe7/0x2d0 ? __check_object_size+0x57/0x310 pci_unregister_driver+0x26/0x250 __do_sys_delete_module+0x307/0x510 ? free_module+0x6a0/0x6a0 ? fpregs_assert_state_consistent+0x4b/0xb0 ? rcu_read_lock_sched_held+0x10/0x70 ? syscall_enter_from_user_mode+0x20/0x70 ? trace_hardirqs_on+0x1c/0x130 do_syscall_64+0x5c/0x80 ? trace_hardirqs_on_prepare+0x72/0x160 ? do_syscall_64+0x68/0x80 ? trace_hardirqs_on_prepare+0x72/0x160 entry_SYSCALL_64_after_hwframe+0x44/0xae Reported-by: Mikhail Gavrilov Closes: https://lore.kernel.org/linux-wireless/CABXGCsOdvVwdLmSsC8TZ1jF0UOg_F_W3wqLECWX620PUkvNk=A@mail.gmail.com/ Fixes: 9270270d6219 ("wifi: mt76: mt7921: fix PCI DMA hang after reboot") Tested-by: Mikhail Gavrilov Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 1 + drivers/net/wireless/mediatek/mt76/mt792x_dma.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index dde26f327478..82cf3ce90b52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -387,6 +387,7 @@ static void mt7921_pci_remove(struct pci_dev *pdev) struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); mt7921e_unregister_device(dev); + set_bit(MT76_REMOVED, &mdev->phy.state); devm_free_irq(&pdev->dev, pdev->irq, dev); mt76_free_device(&dev->mt76); pci_free_irq_vectors(pdev); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c index 8fa36b59e738..5cc2d59b774a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c @@ -12,6 +12,8 @@ irqreturn_t mt792x_irq_handler(int irq, void *dev_instance) { struct mt792x_dev *dev = dev_instance; + if (test_bit(MT76_REMOVED, &dev->mt76.phy.state)) + return IRQ_NONE; mt76_wr(dev, dev->irq_map->host_irq_enable, 0); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) From a5a5f4413d91f395cb2d89829d376d7393ad48b9 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Sat, 13 Jan 2024 17:00:23 +0800 Subject: [PATCH 1447/2255] wifi: mt76: mt7925e: fix use-after-free in free_irq() From commit a304e1b82808 ("[PATCH] Debug shared irqs"), there is a test to make sure the shared irq handler should be able to handle the unexpected event after deregistration. For this case, let's apply MT76_REMOVED flag to indicate the device was removed and do not run into the resource access anymore. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 74cfba7675be..07b74d492ce1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -427,6 +427,7 @@ static void mt7925_pci_remove(struct pci_dev *pdev) struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); mt7925e_unregister_device(dev); + set_bit(MT76_REMOVED, &mdev->phy.state); devm_free_irq(&pdev->dev, pdev->irq, dev); mt76_free_device(&dev->mt76); pci_free_irq_vectors(pdev); From b6351ef9994ccb93b2447d396a0c517964dff2bc Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Tue, 16 Jan 2024 10:48:54 +0800 Subject: [PATCH 1448/2255] wifi: mt76: mt7921: fix incorrect type conversion for CLC command clc->len is defined as 32 bits in length, so it must also be operated on with 32 bits, not 16 bits. Fixes: fa6ad88e023d ("wifi: mt76: mt7921: fix country count limitation for CLC") Signed-off-by: Ming Yen Hsieh Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312112104.Zkc3QUHr-lkp@intel.com/ Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index f5582477c7e4..8b4ce32a2cd1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1272,7 +1272,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), }; int ret, valid_cnt = 0; - u16 buf_len = 0; + u32 buf_len = 0; u8 *pos; if (!clc) @@ -1283,7 +1283,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, if (mt76_find_power_limits_node(&dev->mt76)) req.cap |= CLC_CAP_DTS_EN; - buf_len = le16_to_cpu(clc->len) - sizeof(*clc); + buf_len = le32_to_cpu(clc->len) - sizeof(*clc); pos = clc->data; while (buf_len > 16) { struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos; From 07ce1d46372489d90f9cccebb3277d1af801c4b9 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Tue, 16 Jan 2024 10:48:55 +0800 Subject: [PATCH 1449/2255] wifi: mt76: mt792x: fix a potential loading failure of the 6Ghz channel config from ACPI In some case, the MTCL table will exist, but MTDS table will not. So the SAR will init fail. This patch make MTCL and MTDS can exist with no dependence. Fixes: f965333e491e ("mt76: mt7921: introduce ACPI SAR support") Signed-off-by: Ming Yen Hsieh Signed-off-by: Leon Yen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt792x_acpi_sar.c | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c index c64562216caa..e1d946fb2399 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -66,13 +66,15 @@ free: } /* MTCL : Country List Table for 6G band */ -static void +static int mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version) { - if (mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL) < 0) - *version = 1; - else - *version = 2; + int ret; + + *version = ((ret = mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL)) < 0) + ? 1 : 2; + + return ret; } /* MTDS : Dynamic SAR Power Table */ @@ -166,16 +168,16 @@ int mt792x_init_acpi_sar(struct mt792x_dev *dev) if (!asar) return -ENOMEM; - mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); + ret = mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); + if (ret) { + devm_kfree(dev->mt76.dev, asar->countrylist); + asar->countrylist = NULL; + } - /* MTDS is mandatory. Return error if table is invalid */ ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver); if (ret) { devm_kfree(dev->mt76.dev, asar->dyn); - devm_kfree(dev->mt76.dev, asar->countrylist); - devm_kfree(dev->mt76.dev, asar); - - return ret; + asar->dyn = NULL; } /* MTGS is optional */ @@ -290,7 +292,7 @@ int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; int i; - if (!phy->acpisar) + if (!phy->acpisar || !((struct mt792x_acpi_sar *)phy->acpisar)->dyn) return 0; /* When ACPI SAR enabled in HW, we should apply rules for .frp From 420ad9182c0199512dbceb68922c6d606eb36c9c Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Tue, 16 Jan 2024 10:48:56 +0800 Subject: [PATCH 1450/2255] wifi: mt76: mt792x: update the country list of EU for ACPI SAR This patch updates the EU country list to ensure the MTCL table works correctly. Signed-off-by: Ming Yen Hsieh Signed-off-by: Leon Yen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c index e1d946fb2399..9317f8ff2070 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -380,7 +380,7 @@ u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) "AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT", "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", - "PT", "RO", "MT", "SK", "SI", "ES", "CH", + "PT", "RO", "SK", "SI", "ES", "SE", "CH", }; struct mt792x_acpi_sar *sar = phy->acpisar; struct mt792x_asar_cl *cl; From c2b22e26755c77299e1dffa2e17374cd28f7f3a7 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Tue, 16 Jan 2024 10:48:57 +0800 Subject: [PATCH 1451/2255] wifi: mt76: mt7921: fix the unfinished command of regd_notifier before suspend Before entering suspend, we need to ensure that all MCU command are completed. In some cases, such as with regd_notifier, there is a chance that CLC commands, will be executed before suspend. Signed-off-by: Ming Yen Hsieh Signed-off-by: Leon Yen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt792x.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 48433c6d5e7d..ef0c721d26e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -138,9 +138,14 @@ mt7921_regd_notifier(struct wiphy *wiphy, if (pm->suspended) return; + dev->regd_in_progress = true; + mt792x_mutex_acquire(dev); mt7921_regd_update(dev); mt792x_mutex_release(dev); + + dev->regd_in_progress = false; + wake_up(&dev->wait); } int mt7921_mac_init(struct mt792x_dev *dev) @@ -261,6 +266,7 @@ int mt7921_register_device(struct mt792x_dev *dev) spin_lock_init(&dev->pm.wake.lock); mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); + init_waitqueue_head(&dev->wait); if (mt76_is_sdio(&dev->mt76)) init_waitqueue_head(&dev->mt76.sdio.wait); spin_lock_init(&dev->pm.txq_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 82cf3ce90b52..7037ef57651e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -410,6 +410,9 @@ static int mt7921_pci_suspend(struct device *device) if (err < 0) goto restore_suspend; + wait_event_timeout(dev->wait, + !dev->regd_in_progress, 5 * HZ); + err = mt76_connac_mcu_set_hif_suspend(mdev, true); if (err) goto restore_suspend; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 3c897b34aaa7..a8556de3d480 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -186,6 +186,8 @@ struct mt792x_dev { bool hw_init_done:1; bool fw_assert:1; bool has_eht:1; + bool regd_in_progress:1; + wait_queue_head_t wait; struct work_struct init_work; From 352d966126e66d825244f1185eb9f2d904c83dd4 Mon Sep 17 00:00:00 2001 From: Leon Yen Date: Tue, 6 Feb 2024 16:53:04 +0800 Subject: [PATCH 1452/2255] wifi: mt76: mt7921: fix a potential association failure upon resuming In multi-channel scenarios, the granted channel must be aborted before suspending. Otherwise, the firmware will be put into a wrong state, resulting in an association failure after resuming. With this patch, the granted channel will be aborted before suspending if necessary. Signed-off-by: Leon Yen Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 13 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 + drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7921/sdio.c | 2 ++ 4 files changed, 18 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 0d5adc5ddae3..ca36de34171b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -325,6 +325,19 @@ static void mt7921_roc_iter(void *priv, u8 *mac, mt7921_mcu_abort_roc(phy, mvif, phy->roc_token_id); } +void mt7921_roc_abort_sync(struct mt792x_dev *dev) +{ + struct mt792x_phy *phy = &dev->phy; + + del_timer_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + ieee80211_iterate_active_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_roc_iter, (void *)phy); +} +EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); + void mt7921_roc_work(struct work_struct *work) { struct mt792x_phy *phy; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 1cb21133992b..3016636d18c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -322,4 +322,5 @@ int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, enum mt7921_roc_req type, u8 token_id); int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, u8 token_id); +void mt7921_roc_abort_sync(struct mt792x_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 7037ef57651e..f85e7c90dd25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -406,6 +406,8 @@ static int mt7921_pci_suspend(struct device *device) cancel_delayed_work_sync(&pm->ps_work); cancel_work_sync(&pm->wake_work); + mt7921_roc_abort_sync(dev); + err = mt792x_mcu_drv_pmctrl(dev); if (err < 0) goto restore_suspend; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index a9ce1e746b95..004d942ee11a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -216,6 +216,8 @@ static int mt7921s_suspend(struct device *__dev) cancel_delayed_work_sync(&pm->ps_work); cancel_work_sync(&pm->wake_work); + mt7921_roc_abort_sync(dev); + err = mt792x_mcu_drv_pmctrl(dev); if (err < 0) goto restore_suspend; From 8cd725742eafa9226980d35dd3201b58be7241f5 Mon Sep 17 00:00:00 2001 From: Michael Lo Date: Wed, 7 Feb 2024 09:39:45 +0800 Subject: [PATCH 1453/2255] wifi: mt76: mt7921: fix suspend issue on MediaTek COB platform MediaTek's controller driver on COB platform (e.g. MT8188) is capable of controlling power supplies and reset pin of a component (e.g. a WIFI chip) in power-on and power-off process. Due to this optional feature, mt76 need to inform controller that mt76 need to keep power during suspend. Otherwise WIFI will be powered off when system enters suspend process. The "wakeup-source" property was used for the device that need this to go into suspend mode so that mt76 suspend handler doesn't fail and the system is able to enter into a suspend state. An example: wifi: mt7921@0 { wifi0{ reg = <0x0000 0 0 0 0>; wakeup-source; }; }; Signed-off-by: Michael Lo Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index f85e7c90dd25..cda853e86676 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "mt7921.h" #include "../mt76_connac2_mac.h" @@ -369,6 +370,9 @@ static int mt7921_pci_probe(struct pci_dev *pdev, if (ret) goto err_free_irq; + if (of_property_read_bool(dev->mt76.dev->of_node, "wakeup-source")) + device_init_wakeup(dev->mt76.dev, true); + return 0; err_free_irq: @@ -386,6 +390,9 @@ static void mt7921_pci_remove(struct pci_dev *pdev) struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + if (of_property_read_bool(dev->mt76.dev->of_node, "wakeup-source")) + device_init_wakeup(dev->mt76.dev, false); + mt7921e_unregister_device(dev); set_bit(MT76_REMOVED, &mdev->phy.state); devm_free_irq(&pdev->dev, pdev->irq, dev); From e9a46175a79fbc591c48d433020444b8fa2750ee Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Wed, 7 Feb 2024 11:31:23 +0800 Subject: [PATCH 1454/2255] wifi: mt76: fix the issue of missing txpwr settings from ch153 to ch177 Because the number of channels to be configured is calculated using the %, and it results in 0 when there's an exact division, this leads to some channels not having their tx power configured. Fixes: 7801da338856 ("wifi: mt76: mt7921: enable set txpower for UNII-4") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 9aff0c13efd7..af0c2b2aacb0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -2104,7 +2104,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, int j, msg_len, num_ch; struct sk_buff *skb; - num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len; + num_ch = i == batch_size - 1 ? n_chan - i * batch_len : batch_len; msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv); skb = mt76_mcu_msg_alloc(dev, NULL, msg_len); if (!skb) { From a1e163bd298d2ccb8fda5693c06e078ccb0554c7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 7 Feb 2024 13:11:13 +0000 Subject: [PATCH 1455/2255] wifi: mt76: Remove redundant assignment to variable tidno The variable tidno is being assigned a value that is not being read and is being re-assigned a new value a few statements later. The assignment is redundant and can be removed. Cleans up clang scan warning: drivers/net/wireless/mediatek/mt76/agg-rx.c:125:5: warning: Value stored to 'tidno' during its initialization is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 10cbd9e560e7..07c386c7b4d0 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -122,7 +122,7 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) struct ieee80211_bar *bar = mt76_skb_get_hdr(skb); struct mt76_wcid *wcid = status->wcid; struct mt76_rx_tid *tid; - u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; + u8 tidno; u16 seqno; if (!ieee80211_is_ctl(bar->frame_control)) From 8fa556045696fffd78fe5c3386c6e77d5a368098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 21 Feb 2024 09:12:38 +0100 Subject: [PATCH 1456/2255] dt-bindings: net: wireless: mt76: allow all 4 interrupts for MT7981 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT7981 (Filogic 820) is a low cost version of MT7986 (Filogic 830) with a similar wireless controller that also supports four interrupts. Cc: Peter Chiu Cc: Felix Fietkau Signed-off-by: Rafał Miłecki Acked-by: Conor Dooley Signed-off-by: Felix Fietkau --- .../devicetree/bindings/net/wireless/mediatek,mt76.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml index 0c6835db397f..eabceb849537 100644 --- a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml +++ b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml @@ -226,6 +226,7 @@ allOf: compatible: contains: enum: + - mediatek,mt7981-wmac - mediatek,mt7986-wmac then: properties: From ee076b73e576b0a052d5686d873346b285ae50ea Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:46 +0800 Subject: [PATCH 1457/2255] net: mctp: avoid confusion over local/peer dest/source addresses We have a double-swap of local and peer addresses in mctp_alloc_local_tag; the arguments in both call sites are swapped, but there is also a swap in the implementation of alloc_local_tag. This is opaque because we're using source/dest address references, which don't match the local/peer semantics. Avoid this confusion by naming the arguments as 'local' and 'peer', and remove the double swap. The calling order now matches mctp_key_alloc. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- include/net/mctp.h | 4 ++-- net/mctp/af_mctp.c | 2 +- net/mctp/route.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/mctp.h b/include/net/mctp.h index da86e106c91d..f937a325ea6f 100644 --- a/include/net/mctp.h +++ b/include/net/mctp.h @@ -87,7 +87,7 @@ struct mctp_sock { }; /* Key for matching incoming packets to sockets or reassembly contexts. - * Packets are matched on (src,dest,tag). + * Packets are matched on (peer EID, local EID, tag). * * Lifetime / locking requirements: * @@ -254,7 +254,7 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, void mctp_key_unref(struct mctp_sk_key *key); struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, - mctp_eid_t daddr, mctp_eid_t saddr, + mctp_eid_t local, mctp_eid_t peer, bool manual, u8 *tagp); /* routing <--> device interface */ diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c index f6be58b68c6f..d8197e9e233b 100644 --- a/net/mctp/af_mctp.c +++ b/net/mctp/af_mctp.c @@ -367,7 +367,7 @@ static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg) if (ctl.flags) return -EINVAL; - key = mctp_alloc_local_tag(msk, ctl.peer_addr, MCTP_ADDR_ANY, + key = mctp_alloc_local_tag(msk, MCTP_ADDR_ANY, ctl.peer_addr, true, &tag); if (IS_ERR(key)) return PTR_ERR(key); diff --git a/net/mctp/route.c b/net/mctp/route.c index 7a47a58aa54b..04d29e910af9 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -596,11 +596,11 @@ static void mctp_reserve_tag(struct net *net, struct mctp_sk_key *key, refcount_inc(&key->refs); } -/* Allocate a locally-owned tag value for (saddr, daddr), and reserve +/* Allocate a locally-owned tag value for (local, peer), and reserve * it for the socket msk */ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, - mctp_eid_t daddr, mctp_eid_t saddr, + mctp_eid_t local, mctp_eid_t peer, bool manual, u8 *tagp) { struct net *net = sock_net(&msk->sk); @@ -610,11 +610,11 @@ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, u8 tagbits; /* for NULL destination EIDs, we may get a response from any peer */ - if (daddr == MCTP_ADDR_NULL) - daddr = MCTP_ADDR_ANY; + if (peer == MCTP_ADDR_NULL) + peer = MCTP_ADDR_ANY; /* be optimistic, alloc now */ - key = mctp_key_alloc(msk, saddr, daddr, 0, GFP_KERNEL); + key = mctp_key_alloc(msk, local, peer, 0, GFP_KERNEL); if (!key) return ERR_PTR(-ENOMEM); @@ -635,8 +635,8 @@ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, if (tmp->tag & MCTP_HDR_FLAG_TO) continue; - if (!(mctp_address_matches(tmp->peer_addr, daddr) && - mctp_address_matches(tmp->local_addr, saddr))) + if (!(mctp_address_matches(tmp->peer_addr, peer) && + mctp_address_matches(tmp->local_addr, local))) continue; spin_lock(&tmp->lock); @@ -924,7 +924,7 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, key = mctp_lookup_prealloc_tag(msk, daddr, req_tag, &tag); else - key = mctp_alloc_local_tag(msk, daddr, saddr, + key = mctp_alloc_local_tag(msk, saddr, daddr, false, &tag); if (IS_ERR(key)) { From aee6479a458e2c5027e558cfe26c60c37f8efc80 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:47 +0800 Subject: [PATCH 1458/2255] net: mctp: Add some detail on the key allocation implementation We could do with a little more comment on where MCTP_ADDR_ANY will match in the key allocations. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/mctp/route.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/net/mctp/route.c b/net/mctp/route.c index 04d29e910af9..b4ad47bb0da5 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -73,6 +73,40 @@ static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb) return NULL; } +/* A note on the key allocations. + * + * struct net->mctp.keys contains our set of currently-allocated keys for + * MCTP tag management. The lookup tuple for these is the peer EID, + * local EID and MCTP tag. + * + * In some cases, the peer EID may be MCTP_EID_ANY: for example, when a + * broadcast message is sent, we may receive responses from any peer EID. + * Because the broadcast dest address is equivalent to ANY, we create + * a key with (local = local-eid, peer = ANY). This allows a match on the + * incoming broadcast responses from any peer. + * + * We perform lookups when packets are received, and when tags are allocated + * in two scenarios: + * + * - when a packet is sent, with a locally-owned tag: we need to find an + * unused tag value for the (local, peer) EID pair. + * + * - when a tag is manually allocated: we need to find an unused tag value + * for the peer EID, but don't have a specific local EID at that stage. + * + * in the latter case, on successful allocation, we end up with a tag with + * (local = ANY, peer = peer-eid). + * + * So, the key set allows both a local EID of ANY, as well as a peer EID of + * ANY in the lookup tuple. Both may be ANY if we prealloc for a broadcast. + * The matching (in mctp_key_match()) during lookup allows the match value to + * be ANY in either the dest or source addresses. + * + * When allocating (+ inserting) a tag, we need to check for conflicts amongst + * the existing tag set. This requires macthing either exactly on the local + * and peer addresses, or either being ANY. + */ + static bool mctp_key_match(struct mctp_sk_key *key, mctp_eid_t local, mctp_eid_t peer, u8 tag) { @@ -368,6 +402,9 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) * key lookup to find the socket, but don't use this * key for reassembly - we'll create a more specific * one for future packets if required (ie, !EOM). + * + * this lookup requires key->peer to be MCTP_ADDR_ANY, + * it doesn't match just any key->peer. */ any_key = mctp_lookup_key(net, skb, MCTP_ADDR_ANY, &f); if (any_key) { From fc944ecc4f1a287882d90441360a0ba61d45fd8b Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:48 +0800 Subject: [PATCH 1459/2255] net: mctp: make key lookups match the ANY address on either local or peer We may have an ANY address in either the local or peer address of a sk_key, and may want to match on an incoming daddr or saddr being ANY. Do this by altering the conflicting-tag lookup to also accept ANY as the local/peer address. We don't want mctp_address_matches to match on the requested EID being ANY, as that is a specific lookup case on packet input. Reported-by: Eric Chuang Reported-by: Anthony Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/mctp/route.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/mctp/route.c b/net/mctp/route.c index b4ad47bb0da5..0c2ed75a9e28 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -113,7 +113,7 @@ static bool mctp_key_match(struct mctp_sk_key *key, mctp_eid_t local, if (!mctp_address_matches(key->local_addr, local)) return false; - if (key->peer_addr != peer) + if (!mctp_address_matches(key->peer_addr, peer)) return false; if (key->tag != tag) @@ -672,8 +672,16 @@ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, if (tmp->tag & MCTP_HDR_FLAG_TO) continue; - if (!(mctp_address_matches(tmp->peer_addr, peer) && - mctp_address_matches(tmp->local_addr, local))) + /* Since we're avoiding conflicting entries, match peer and + * local addresses, including with a wildcard on ANY. See + * 'A note on key allocations' for background. + */ + if (peer != MCTP_ADDR_ANY && + !mctp_address_matches(tmp->peer_addr, peer)) + continue; + + if (local != MCTP_ADDR_ANY && + !mctp_address_matches(tmp->local_addr, local)) continue; spin_lock(&tmp->lock); From a1f4cf5791e7914f3e42f5462669353104fef8a9 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:49 +0800 Subject: [PATCH 1460/2255] net: mctp: tests: create test skbs with the correct net and device In our test skb creation functions, we're not setting up the net and device data. This doesn't matter at the moment, but we will want to add support for distinct net IDs in future. Set the ->net identifier on the test MCTP device, and ensure that test skbs are set up with the correct device-related data on creation. Create a helper for setting skb->dev and mctp_skb_cb->net. We have a few cases where we're calling __mctp_cb() to initialise the cb (which we need for the above) separately, so integrate this into the skb creation helpers. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/mctp/test/route-test.c | 23 +++++++++++++++-------- net/mctp/test/utils.c | 2 ++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index 92ea4158f7fc..714e5ae47629 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -79,6 +79,16 @@ static void mctp_test_route_destroy(struct kunit *test, kfree_rcu(&rt->rt, rcu); } +static void mctp_test_skb_set_dev(struct sk_buff *skb, + struct mctp_test_dev *dev) +{ + struct mctp_skb_cb *cb; + + cb = mctp_cb(skb); + cb->net = READ_ONCE(dev->mdev->net); + skb->dev = dev->ndev; +} + static struct sk_buff *mctp_test_create_skb(const struct mctp_hdr *hdr, unsigned int data_len) { @@ -91,6 +101,7 @@ static struct sk_buff *mctp_test_create_skb(const struct mctp_hdr *hdr, if (!skb) return NULL; + __mctp_cb(skb); memcpy(skb_put(skb, hdr_len), hdr, hdr_len); buf = skb_put(skb, data_len); @@ -111,6 +122,7 @@ static struct sk_buff *__mctp_test_create_skb_data(const struct mctp_hdr *hdr, if (!skb) return NULL; + __mctp_cb(skb); memcpy(skb_put(skb, hdr_len), hdr, hdr_len); memcpy(skb_put(skb, data_len), data, data_len); @@ -249,8 +261,6 @@ static void mctp_test_rx_input(struct kunit *test) skb = mctp_test_create_skb(¶ms->hdr, 1); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); - __mctp_cb(skb); - mctp_pkttype_receive(skb, dev->ndev, &mctp_packet_type, NULL); KUNIT_EXPECT_EQ(test, !!rt->pkts.qlen, params->input); @@ -344,8 +354,7 @@ static void mctp_test_route_input_sk(struct kunit *test) skb = mctp_test_create_skb_data(¶ms->hdr, ¶ms->type); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); - skb->dev = dev->ndev; - __mctp_cb(skb); + mctp_test_skb_set_dev(skb, dev); rc = mctp_route_input(&rt->rt, skb); @@ -417,8 +426,7 @@ static void mctp_test_route_input_sk_reasm(struct kunit *test) skb = mctp_test_create_skb_data(¶ms->hdrs[i], &c); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); - skb->dev = dev->ndev; - __mctp_cb(skb); + mctp_test_skb_set_dev(skb, dev); rc = mctp_route_input(&rt->rt, skb); } @@ -576,8 +584,7 @@ static void mctp_test_route_input_sk_keys(struct kunit *test) skb = mctp_test_create_skb_data(¶ms->hdr, &c); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); - skb->dev = dev->ndev; - __mctp_cb(skb); + mctp_test_skb_set_dev(skb, dev); rc = mctp_route_input(&rt->rt, skb); diff --git a/net/mctp/test/utils.c b/net/mctp/test/utils.c index e03ba66bbe18..565763eb0211 100644 --- a/net/mctp/test/utils.c +++ b/net/mctp/test/utils.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -54,6 +55,7 @@ struct mctp_test_dev *mctp_test_create_dev(void) rcu_read_lock(); dev->mdev = __mctp_dev_get(ndev); + dev->mdev->net = mctp_default_net(dev_net(ndev)); rcu_read_unlock(); return dev; From 43e6795574f5d75284a3cb21f5b76a5ffb98e8e6 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:50 +0800 Subject: [PATCH 1461/2255] net: mctp: separate key correlation across nets Currently, we lookup sk_keys from the entire struct net_namespace, which may contain multiple MCTP net IDs. In those cases we want to distinguish between endpoints with the same EID but different net ID. Add the net ID data to the struct mctp_sk_key, populate on add and filter on this during route lookup. For the ioctl interface, we use a default net of MCTP_INITIAL_DEFAULT_NET (ie., what will be in use for single-net configurations), but we'll extend the ioctl interface to provide net-specific tag allocation in an upcoming change. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- include/net/mctp.h | 2 ++ net/mctp/af_mctp.c | 4 ++-- net/mctp/route.c | 43 +++++++++++++++++++++++++++----------- net/mctp/test/route-test.c | 7 +++++-- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/include/net/mctp.h b/include/net/mctp.h index f937a325ea6f..0dfae6f51a32 100644 --- a/include/net/mctp.h +++ b/include/net/mctp.h @@ -133,6 +133,7 @@ struct mctp_sock { * - through an expiry timeout, on a per-socket timer */ struct mctp_sk_key { + unsigned int net; mctp_eid_t peer_addr; mctp_eid_t local_addr; /* MCTP_ADDR_ANY for local owned tags */ __u8 tag; /* incoming tag match; invert TO for local */ @@ -254,6 +255,7 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, void mctp_key_unref(struct mctp_sk_key *key); struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, + unsigned int netid, mctp_eid_t local, mctp_eid_t peer, bool manual, u8 *tagp); diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c index d8197e9e233b..05315a422ffb 100644 --- a/net/mctp/af_mctp.c +++ b/net/mctp/af_mctp.c @@ -367,8 +367,8 @@ static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg) if (ctl.flags) return -EINVAL; - key = mctp_alloc_local_tag(msk, MCTP_ADDR_ANY, ctl.peer_addr, - true, &tag); + key = mctp_alloc_local_tag(msk, MCTP_INITIAL_DEFAULT_NET, + MCTP_ADDR_ANY, ctl.peer_addr, true, &tag); if (IS_ERR(key)) return PTR_ERR(key); diff --git a/net/mctp/route.c b/net/mctp/route.c index 0c2ed75a9e28..28648a7ec866 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -107,9 +107,12 @@ static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb) * and peer addresses, or either being ANY. */ -static bool mctp_key_match(struct mctp_sk_key *key, mctp_eid_t local, - mctp_eid_t peer, u8 tag) +static bool mctp_key_match(struct mctp_sk_key *key, unsigned int net, + mctp_eid_t local, mctp_eid_t peer, u8 tag) { + if (key->net != net) + return false; + if (!mctp_address_matches(key->local_addr, local)) return false; @@ -126,7 +129,7 @@ static bool mctp_key_match(struct mctp_sk_key *key, mctp_eid_t local, * key exists. */ static struct mctp_sk_key *mctp_lookup_key(struct net *net, struct sk_buff *skb, - mctp_eid_t peer, + unsigned int netid, mctp_eid_t peer, unsigned long *irqflags) __acquires(&key->lock) { @@ -142,7 +145,7 @@ static struct mctp_sk_key *mctp_lookup_key(struct net *net, struct sk_buff *skb, spin_lock_irqsave(&net->mctp.keys_lock, flags); hlist_for_each_entry(key, &net->mctp.keys, hlist) { - if (!mctp_key_match(key, mh->dest, peer, tag)) + if (!mctp_key_match(key, netid, mh->dest, peer, tag)) continue; spin_lock(&key->lock); @@ -165,6 +168,7 @@ static struct mctp_sk_key *mctp_lookup_key(struct net *net, struct sk_buff *skb, } static struct mctp_sk_key *mctp_key_alloc(struct mctp_sock *msk, + unsigned int net, mctp_eid_t local, mctp_eid_t peer, u8 tag, gfp_t gfp) { @@ -174,6 +178,7 @@ static struct mctp_sk_key *mctp_key_alloc(struct mctp_sock *msk, if (!key) return NULL; + key->net = net; key->peer_addr = peer; key->local_addr = local; key->tag = tag; @@ -219,8 +224,8 @@ static int mctp_key_add(struct mctp_sk_key *key, struct mctp_sock *msk) } hlist_for_each_entry(tmp, &net->mctp.keys, hlist) { - if (mctp_key_match(tmp, key->local_addr, key->peer_addr, - key->tag)) { + if (mctp_key_match(tmp, key->net, key->local_addr, + key->peer_addr, key->tag)) { spin_lock(&tmp->lock); if (tmp->valid) rc = -EEXIST; @@ -361,6 +366,7 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) struct net *net = dev_net(skb->dev); struct mctp_sock *msk; struct mctp_hdr *mh; + unsigned int netid; unsigned long f; u8 tag, flags; int rc; @@ -379,6 +385,7 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) /* grab header, advance data ptr */ mh = mctp_hdr(skb); + netid = mctp_cb(skb)->net; skb_pull(skb, sizeof(struct mctp_hdr)); if (mh->ver != 1) @@ -392,7 +399,7 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) /* lookup socket / reasm context, exactly matching (src,dest,tag). * we hold a ref on the key, and key->lock held. */ - key = mctp_lookup_key(net, skb, mh->src, &f); + key = mctp_lookup_key(net, skb, netid, mh->src, &f); if (flags & MCTP_HDR_FLAG_SOM) { if (key) { @@ -406,7 +413,8 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) * this lookup requires key->peer to be MCTP_ADDR_ANY, * it doesn't match just any key->peer. */ - any_key = mctp_lookup_key(net, skb, MCTP_ADDR_ANY, &f); + any_key = mctp_lookup_key(net, skb, netid, + MCTP_ADDR_ANY, &f); if (any_key) { msk = container_of(any_key->sk, struct mctp_sock, sk); @@ -443,7 +451,7 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) * packets for this message */ if (!key) { - key = mctp_key_alloc(msk, mh->dest, mh->src, + key = mctp_key_alloc(msk, netid, mh->dest, mh->src, tag, GFP_ATOMIC); if (!key) { rc = -ENOMEM; @@ -637,6 +645,7 @@ static void mctp_reserve_tag(struct net *net, struct mctp_sk_key *key, * it for the socket msk */ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, + unsigned int netid, mctp_eid_t local, mctp_eid_t peer, bool manual, u8 *tagp) { @@ -651,7 +660,7 @@ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, peer = MCTP_ADDR_ANY; /* be optimistic, alloc now */ - key = mctp_key_alloc(msk, local, peer, 0, GFP_KERNEL); + key = mctp_key_alloc(msk, netid, local, peer, 0, GFP_KERNEL); if (!key) return ERR_PTR(-ENOMEM); @@ -668,6 +677,10 @@ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, * lock held, they don't change over the lifetime of the key. */ + /* tags are net-specific */ + if (tmp->net != netid) + continue; + /* if we don't own the tag, it can't conflict */ if (tmp->tag & MCTP_HDR_FLAG_TO) continue; @@ -716,6 +729,7 @@ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, } static struct mctp_sk_key *mctp_lookup_prealloc_tag(struct mctp_sock *msk, + unsigned int netid, mctp_eid_t daddr, u8 req_tag, u8 *tagp) { @@ -730,6 +744,9 @@ static struct mctp_sk_key *mctp_lookup_prealloc_tag(struct mctp_sock *msk, spin_lock_irqsave(&mns->keys_lock, flags); hlist_for_each_entry(tmp, &mns->keys, hlist) { + if (tmp->net != netid) + continue; + if (tmp->tag != req_tag) continue; @@ -910,6 +927,7 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, struct mctp_sk_key *key; struct mctp_hdr *hdr; unsigned long flags; + unsigned int netid; unsigned int mtu; mctp_eid_t saddr; bool ext_rt; @@ -960,16 +978,17 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, rc = 0; } spin_unlock_irqrestore(&rt->dev->addrs_lock, flags); + netid = READ_ONCE(rt->dev->net); if (rc) goto out_release; if (req_tag & MCTP_TAG_OWNER) { if (req_tag & MCTP_TAG_PREALLOC) - key = mctp_lookup_prealloc_tag(msk, daddr, + key = mctp_lookup_prealloc_tag(msk, netid, daddr, req_tag, &tag); else - key = mctp_alloc_local_tag(msk, saddr, daddr, + key = mctp_alloc_local_tag(msk, netid, saddr, daddr, false, &tag); if (IS_ERR(key)) { diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index 714e5ae47629..b3dbd3600d91 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -552,6 +552,7 @@ static void mctp_test_route_input_sk_keys(struct kunit *test) struct mctp_sock *msk; struct socket *sock; unsigned long flags; + unsigned int net; int rc; u8 c; @@ -559,6 +560,7 @@ static void mctp_test_route_input_sk_keys(struct kunit *test) dev = mctp_test_create_dev(); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + net = READ_ONCE(dev->mdev->net); rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); @@ -570,8 +572,9 @@ static void mctp_test_route_input_sk_keys(struct kunit *test) mns = &sock_net(sock->sk)->mctp; /* set the incoming tag according to test params */ - key = mctp_key_alloc(msk, params->key_local_addr, params->key_peer_addr, - params->key_tag, GFP_KERNEL); + key = mctp_key_alloc(msk, net, params->key_local_addr, + params->key_peer_addr, params->key_tag, + GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, key); From c16d2380e8fdd9fc1fd0e9c60e068f264b2d0ced Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:51 +0800 Subject: [PATCH 1462/2255] net: mctp: provide a more specific tag allocation ioctl Now that we have net-specific tags, extend the tag allocation ioctls (SIOCMCTPALLOCTAG / SIOCMCTPDROPTAG) to allow a network parameter to be passed to the tag allocation. We also add a local_addr member to the ioc struct, to allow for a future finer-grained tag allocation using local EIDs too. We don't add any specific support for that now though, so require MCTP_ADDR_ANY or MCTP_ADDR_NULL for those at present. The old ioctls will still work, but allocate for the default MCTP net. These are now marked as deprecated in the header. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- include/uapi/linux/mctp.h | 32 +++++++++++ net/mctp/af_mctp.c | 117 +++++++++++++++++++++++++++++++------- 2 files changed, 129 insertions(+), 20 deletions(-) diff --git a/include/uapi/linux/mctp.h b/include/uapi/linux/mctp.h index 154ab56651f1..e1db65df9359 100644 --- a/include/uapi/linux/mctp.h +++ b/include/uapi/linux/mctp.h @@ -50,7 +50,14 @@ struct sockaddr_mctp_ext { #define SIOCMCTPALLOCTAG (SIOCPROTOPRIVATE + 0) #define SIOCMCTPDROPTAG (SIOCPROTOPRIVATE + 1) +#define SIOCMCTPALLOCTAG2 (SIOCPROTOPRIVATE + 2) +#define SIOCMCTPDROPTAG2 (SIOCPROTOPRIVATE + 3) +/* Deprecated: use mctp_ioc_tag_ctl2 / TAG2 ioctls instead, which defines the + * MCTP network ID as part of the allocated tag. Using this assumes the default + * net ID for allocated tags, which may not give correct behaviour on system + * with multiple networks configured. + */ struct mctp_ioc_tag_ctl { mctp_eid_t peer_addr; @@ -65,4 +72,29 @@ struct mctp_ioc_tag_ctl { __u16 flags; }; +struct mctp_ioc_tag_ctl2 { + /* Peer details: network ID, peer EID, local EID. All set by the + * caller. + * + * Local EID must be MCTP_ADDR_NULL or MCTP_ADDR_ANY in current + * kernels. + */ + unsigned int net; + mctp_eid_t peer_addr; + mctp_eid_t local_addr; + + /* Set by caller, but no flags defined currently. Must be 0 */ + __u16 flags; + + /* For SIOCMCTPALLOCTAG2: must be passed as zero, kernel will + * populate with the allocated tag value. Returned tag value will + * always have TO and PREALLOC set. + * + * For SIOCMCTPDROPTAG2: userspace provides tag value to drop, from + * a prior SIOCMCTPALLOCTAG2 call (and so must have TO and PREALLOC set). + */ + __u8 tag; + +}; + #endif /* __UAPI_MCTP_H */ diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c index 05315a422ffb..de52a9191da0 100644 --- a/net/mctp/af_mctp.c +++ b/net/mctp/af_mctp.c @@ -350,30 +350,102 @@ static int mctp_getsockopt(struct socket *sock, int level, int optname, return -EINVAL; } -static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg) +/* helpers for reading/writing the tag ioc, handling compatibility across the + * two versions, and some basic API error checking + */ +static int mctp_ioctl_tag_copy_from_user(unsigned long arg, + struct mctp_ioc_tag_ctl2 *ctl, + bool tagv2) +{ + struct mctp_ioc_tag_ctl ctl_compat; + unsigned long size; + void *ptr; + int rc; + + if (tagv2) { + size = sizeof(*ctl); + ptr = ctl; + } else { + size = sizeof(ctl_compat); + ptr = &ctl_compat; + } + + rc = copy_from_user(ptr, (void __user *)arg, size); + if (rc) + return -EFAULT; + + if (!tagv2) { + /* compat, using defaults for new fields */ + ctl->net = MCTP_INITIAL_DEFAULT_NET; + ctl->peer_addr = ctl_compat.peer_addr; + ctl->local_addr = MCTP_ADDR_ANY; + ctl->flags = ctl_compat.flags; + ctl->tag = ctl_compat.tag; + } + + if (ctl->flags) + return -EINVAL; + + if (ctl->local_addr != MCTP_ADDR_ANY && + ctl->local_addr != MCTP_ADDR_NULL) + return -EINVAL; + + return 0; +} + +static int mctp_ioctl_tag_copy_to_user(unsigned long arg, + struct mctp_ioc_tag_ctl2 *ctl, + bool tagv2) +{ + struct mctp_ioc_tag_ctl ctl_compat; + unsigned long size; + void *ptr; + int rc; + + if (tagv2) { + ptr = ctl; + size = sizeof(*ctl); + } else { + ctl_compat.peer_addr = ctl->peer_addr; + ctl_compat.tag = ctl->tag; + ctl_compat.flags = ctl->flags; + + ptr = &ctl_compat; + size = sizeof(ctl_compat); + } + + rc = copy_to_user((void __user *)arg, ptr, size); + if (rc) + return -EFAULT; + + return 0; +} + +static int mctp_ioctl_alloctag(struct mctp_sock *msk, bool tagv2, + unsigned long arg) { struct net *net = sock_net(&msk->sk); struct mctp_sk_key *key = NULL; - struct mctp_ioc_tag_ctl ctl; + struct mctp_ioc_tag_ctl2 ctl; unsigned long flags; u8 tag; + int rc; - if (copy_from_user(&ctl, (void __user *)arg, sizeof(ctl))) - return -EFAULT; + rc = mctp_ioctl_tag_copy_from_user(arg, &ctl, tagv2); + if (rc) + return rc; if (ctl.tag) return -EINVAL; - if (ctl.flags) - return -EINVAL; - - key = mctp_alloc_local_tag(msk, MCTP_INITIAL_DEFAULT_NET, - MCTP_ADDR_ANY, ctl.peer_addr, true, &tag); + key = mctp_alloc_local_tag(msk, ctl.net, MCTP_ADDR_ANY, + ctl.peer_addr, true, &tag); if (IS_ERR(key)) return PTR_ERR(key); ctl.tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC; - if (copy_to_user((void __user *)arg, &ctl, sizeof(ctl))) { + rc = mctp_ioctl_tag_copy_to_user(arg, &ctl, tagv2); + if (rc) { unsigned long fl2; /* Unwind our key allocation: the keys list lock needs to be * taken before the individual key locks, and we need a valid @@ -385,28 +457,27 @@ static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg) __mctp_key_remove(key, net, fl2, MCTP_TRACE_KEY_DROPPED); mctp_key_unref(key); spin_unlock_irqrestore(&net->mctp.keys_lock, flags); - return -EFAULT; + return rc; } mctp_key_unref(key); return 0; } -static int mctp_ioctl_droptag(struct mctp_sock *msk, unsigned long arg) +static int mctp_ioctl_droptag(struct mctp_sock *msk, bool tagv2, + unsigned long arg) { struct net *net = sock_net(&msk->sk); - struct mctp_ioc_tag_ctl ctl; + struct mctp_ioc_tag_ctl2 ctl; unsigned long flags, fl2; struct mctp_sk_key *key; struct hlist_node *tmp; int rc; u8 tag; - if (copy_from_user(&ctl, (void __user *)arg, sizeof(ctl))) - return -EFAULT; - - if (ctl.flags) - return -EINVAL; + rc = mctp_ioctl_tag_copy_from_user(arg, &ctl, tagv2); + if (rc) + return rc; /* Must be a local tag, TO set, preallocated */ if ((ctl.tag & ~MCTP_TAG_MASK) != (MCTP_TAG_OWNER | MCTP_TAG_PREALLOC)) @@ -422,6 +493,7 @@ static int mctp_ioctl_droptag(struct mctp_sock *msk, unsigned long arg) */ spin_lock_irqsave(&key->lock, fl2); if (key->manual_alloc && + ctl.net == key->net && ctl.peer_addr == key->peer_addr && tag == key->tag) { __mctp_key_remove(key, net, fl2, @@ -439,12 +511,17 @@ static int mctp_ioctl_droptag(struct mctp_sock *msk, unsigned long arg) static int mctp_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk); + bool tagv2 = false; switch (cmd) { + case SIOCMCTPALLOCTAG2: case SIOCMCTPALLOCTAG: - return mctp_ioctl_alloctag(msk, arg); + tagv2 = cmd == SIOCMCTPALLOCTAG2; + return mctp_ioctl_alloctag(msk, tagv2, arg); case SIOCMCTPDROPTAG: - return mctp_ioctl_droptag(msk, arg); + case SIOCMCTPDROPTAG2: + tagv2 = cmd == SIOCMCTPDROPTAG2; + return mctp_ioctl_droptag(msk, tagv2, arg); } return -EINVAL; From 61b50531dc66b0b299da22580074d8960f99bb0c Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:52 +0800 Subject: [PATCH 1463/2255] net: mctp: tests: Add netid argument to __mctp_route_test_init We'll want to create net-specific test setups in an upcoming change, so allow the caller to provide a non-default netid. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/mctp/test/route-test.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index b3dbd3600d91..0880c3c04ace 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -293,7 +293,8 @@ KUNIT_ARRAY_PARAM(mctp_rx_input, mctp_rx_input_tests, static void __mctp_route_test_init(struct kunit *test, struct mctp_test_dev **devp, struct mctp_test_route **rtp, - struct socket **sockp) + struct socket **sockp, + unsigned int netid) { struct sockaddr_mctp addr = {0}; struct mctp_test_route *rt; @@ -303,6 +304,8 @@ static void __mctp_route_test_init(struct kunit *test, dev = mctp_test_create_dev(); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + if (netid != MCTP_NET_ANY) + WRITE_ONCE(dev->mdev->net, netid); rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); @@ -311,7 +314,7 @@ static void __mctp_route_test_init(struct kunit *test, KUNIT_ASSERT_EQ(test, rc, 0); addr.smctp_family = AF_MCTP; - addr.smctp_network = MCTP_NET_ANY; + addr.smctp_network = netid; addr.smctp_addr.s_addr = 8; addr.smctp_type = 0; rc = kernel_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); @@ -349,7 +352,7 @@ static void mctp_test_route_input_sk(struct kunit *test) params = test->param_value; - __mctp_route_test_init(test, &dev, &rt, &sock); + __mctp_route_test_init(test, &dev, &rt, &sock, MCTP_NET_ANY); skb = mctp_test_create_skb_data(¶ms->hdr, ¶ms->type); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); @@ -419,7 +422,7 @@ static void mctp_test_route_input_sk_reasm(struct kunit *test) params = test->param_value; - __mctp_route_test_init(test, &dev, &rt, &sock); + __mctp_route_test_init(test, &dev, &rt, &sock, MCTP_NET_ANY); for (i = 0; i < params->n_hdrs; i++) { c = i; From 9acdc089c08884c1f1b4567efcd7290781ee8e3a Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:53 +0800 Subject: [PATCH 1464/2255] net: mctp: tests: Add MCTP net isolation tests Add a couple of tests that excersise the new net-specific sk_key and bind lookups Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/mctp/test/route-test.c | 161 +++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index 0880c3c04ace..bad084525f17 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -678,6 +678,165 @@ static void mctp_route_input_sk_keys_to_desc( KUNIT_ARRAY_PARAM(mctp_route_input_sk_keys, mctp_route_input_sk_keys_tests, mctp_route_input_sk_keys_to_desc); +struct test_net { + unsigned int netid; + struct mctp_test_dev *dev; + struct mctp_test_route *rt; + struct socket *sock; + struct sk_buff *skb; + struct mctp_sk_key *key; + struct { + u8 type; + unsigned int data; + } msg; +}; + +static void +mctp_test_route_input_multiple_nets_bind_init(struct kunit *test, + struct test_net *t) +{ + struct mctp_hdr hdr = RX_HDR(1, 9, 8, FL_S | FL_E | FL_T(1) | FL_TO); + + t->msg.data = t->netid; + + __mctp_route_test_init(test, &t->dev, &t->rt, &t->sock, t->netid); + + t->skb = mctp_test_create_skb_data(&hdr, &t->msg); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, t->skb); + mctp_test_skb_set_dev(t->skb, t->dev); +} + +static void +mctp_test_route_input_multiple_nets_bind_fini(struct kunit *test, + struct test_net *t) +{ + __mctp_route_test_fini(test, t->dev, t->rt, t->sock); +} + +/* Test that skbs from different nets (otherwise identical) get routed to their + * corresponding socket via the sockets' bind() + */ +static void mctp_test_route_input_multiple_nets_bind(struct kunit *test) +{ + struct sk_buff *rx_skb1, *rx_skb2; + struct test_net t1, t2; + int rc; + + t1.netid = 1; + t2.netid = 2; + + t1.msg.type = 0; + t2.msg.type = 0; + + mctp_test_route_input_multiple_nets_bind_init(test, &t1); + mctp_test_route_input_multiple_nets_bind_init(test, &t2); + + rc = mctp_route_input(&t1.rt->rt, t1.skb); + KUNIT_ASSERT_EQ(test, rc, 0); + rc = mctp_route_input(&t2.rt->rt, t2.skb); + KUNIT_ASSERT_EQ(test, rc, 0); + + rx_skb1 = skb_recv_datagram(t1.sock->sk, MSG_DONTWAIT, &rc); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, rx_skb1); + KUNIT_EXPECT_EQ(test, rx_skb1->len, sizeof(t1.msg)); + KUNIT_EXPECT_EQ(test, + *(unsigned int *)skb_pull(rx_skb1, sizeof(t1.msg.data)), + t1.netid); + kfree_skb(rx_skb1); + + rx_skb2 = skb_recv_datagram(t2.sock->sk, MSG_DONTWAIT, &rc); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, rx_skb2); + KUNIT_EXPECT_EQ(test, rx_skb2->len, sizeof(t2.msg)); + KUNIT_EXPECT_EQ(test, + *(unsigned int *)skb_pull(rx_skb2, sizeof(t2.msg.data)), + t2.netid); + kfree_skb(rx_skb2); + + mctp_test_route_input_multiple_nets_bind_fini(test, &t1); + mctp_test_route_input_multiple_nets_bind_fini(test, &t2); +} + +static void +mctp_test_route_input_multiple_nets_key_init(struct kunit *test, + struct test_net *t) +{ + struct mctp_hdr hdr = RX_HDR(1, 9, 8, FL_S | FL_E | FL_T(1)); + struct mctp_sock *msk; + struct netns_mctp *mns; + unsigned long flags; + + t->msg.data = t->netid; + + __mctp_route_test_init(test, &t->dev, &t->rt, &t->sock, t->netid); + + msk = container_of(t->sock->sk, struct mctp_sock, sk); + + t->key = mctp_key_alloc(msk, t->netid, hdr.dest, hdr.src, 1, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, t->key); + + mns = &sock_net(t->sock->sk)->mctp; + spin_lock_irqsave(&mns->keys_lock, flags); + mctp_reserve_tag(&init_net, t->key, msk); + spin_unlock_irqrestore(&mns->keys_lock, flags); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, t->key); + t->skb = mctp_test_create_skb_data(&hdr, &t->msg); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, t->skb); + mctp_test_skb_set_dev(t->skb, t->dev); +} + +static void +mctp_test_route_input_multiple_nets_key_fini(struct kunit *test, + struct test_net *t) +{ + mctp_key_unref(t->key); + __mctp_route_test_fini(test, t->dev, t->rt, t->sock); +} + +/* test that skbs from different nets (otherwise identical) get routed to their + * corresponding socket via the sk_key + */ +static void mctp_test_route_input_multiple_nets_key(struct kunit *test) +{ + struct sk_buff *rx_skb1, *rx_skb2; + struct test_net t1, t2; + int rc; + + t1.netid = 1; + t2.netid = 2; + + /* use type 1 which is not bound */ + t1.msg.type = 1; + t2.msg.type = 1; + + mctp_test_route_input_multiple_nets_key_init(test, &t1); + mctp_test_route_input_multiple_nets_key_init(test, &t2); + + rc = mctp_route_input(&t1.rt->rt, t1.skb); + KUNIT_ASSERT_EQ(test, rc, 0); + rc = mctp_route_input(&t2.rt->rt, t2.skb); + KUNIT_ASSERT_EQ(test, rc, 0); + + rx_skb1 = skb_recv_datagram(t1.sock->sk, MSG_DONTWAIT, &rc); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, rx_skb1); + KUNIT_EXPECT_EQ(test, rx_skb1->len, sizeof(t1.msg)); + KUNIT_EXPECT_EQ(test, + *(unsigned int *)skb_pull(rx_skb1, sizeof(t1.msg.data)), + t1.netid); + kfree_skb(rx_skb1); + + rx_skb2 = skb_recv_datagram(t2.sock->sk, MSG_DONTWAIT, &rc); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, rx_skb2); + KUNIT_EXPECT_EQ(test, rx_skb2->len, sizeof(t2.msg)); + KUNIT_EXPECT_EQ(test, + *(unsigned int *)skb_pull(rx_skb2, sizeof(t2.msg.data)), + t2.netid); + kfree_skb(rx_skb2); + + mctp_test_route_input_multiple_nets_key_fini(test, &t1); + mctp_test_route_input_multiple_nets_key_fini(test, &t2); +} + static struct kunit_case mctp_test_cases[] = { KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), @@ -686,6 +845,8 @@ static struct kunit_case mctp_test_cases[] = { mctp_route_input_sk_reasm_gen_params), KUNIT_CASE_PARAM(mctp_test_route_input_sk_keys, mctp_route_input_sk_keys_gen_params), + KUNIT_CASE(mctp_test_route_input_multiple_nets_bind), + KUNIT_CASE(mctp_test_route_input_multiple_nets_key), {} }; From 1394c1dec1c619a46867ed32791a29695372bff8 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:54 +0800 Subject: [PATCH 1465/2255] net: mctp: copy skb ext data when fragmenting If we're fragmenting on local output, the original packet may contain ext data for the MCTP flows. We'll want this in the resulting fragment skbs too. So, do a skb_ext_copy() in the fragmentation path, and implement the MCTP-specific parts of an ext copy operation. Fixes: 67737c457281 ("mctp: Pass flow data & flow release events to drivers") Reported-by: Jian Zhang Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/core/skbuff.c | 8 ++++++++ net/mctp/route.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b9de3ee65ae6..1f918e602bc4 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -6849,6 +6849,14 @@ static struct skb_ext *skb_ext_maybe_cow(struct skb_ext *old, for (i = 0; i < sp->len; i++) xfrm_state_hold(sp->xvec[i]); } +#endif +#ifdef CONFIG_MCTP_FLOWS + if (old_active & (1 << SKB_EXT_MCTP)) { + struct mctp_flow *flow = skb_ext_get_ptr(old, SKB_EXT_MCTP); + + if (flow->key) + refcount_inc(&flow->key->refs); + } #endif __skb_ext_put(old); return new; diff --git a/net/mctp/route.c b/net/mctp/route.c index 28648a7ec866..34e513113509 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -905,6 +905,9 @@ static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb, /* copy message payload */ skb_copy_bits(skb, pos, skb_transport_header(skb2), size); + /* we need to copy the extensions, for MCTP flow data */ + skb_ext_copy(skb2, skb); + /* do route */ rc = rt->output(rt, skb2); if (rc) From 109a5331143da79eb2b63dee9c65188784edfbce Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:55 +0800 Subject: [PATCH 1466/2255] net: mctp: tests: Test that outgoing skbs have flow data populated When CONFIG_MCTP_FLOWS is enabled, outgoing skbs should have their SKB_EXT_MCTP extension set for drivers to consume. Add two tests for local-to-output routing that check for the flow extensions: one for the simple single-packet case, and one for fragmentation. We now make MCTP_TEST select MCTP_FLOWS, so we always get coverage of these flow tests. The tests are skippable if MCTP_FLOWS is (otherwise) disabled, but that would need manual config tweaking. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/mctp/Kconfig | 1 + net/mctp/test/route-test.c | 136 +++++++++++++++++++ tools/testing/kunit/configs/all_tests.config | 1 + 3 files changed, 138 insertions(+) diff --git a/net/mctp/Kconfig b/net/mctp/Kconfig index 3a5c0e70da77..d8d3413a37f7 100644 --- a/net/mctp/Kconfig +++ b/net/mctp/Kconfig @@ -14,6 +14,7 @@ menuconfig MCTP config MCTP_TEST bool "MCTP core tests" if !KUNIT_ALL_TESTS + select MCTP_FLOWS depends on MCTP=y && KUNIT=y default KUNIT_ALL_TESTS diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index bad084525f17..eb7e9ac95612 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -837,6 +837,140 @@ static void mctp_test_route_input_multiple_nets_key(struct kunit *test) mctp_test_route_input_multiple_nets_key_fini(test, &t2); } +#if IS_ENABLED(CONFIG_MCTP_FLOWS) + +static void mctp_test_flow_init(struct kunit *test, + struct mctp_test_dev **devp, + struct mctp_test_route **rtp, + struct socket **sock, + struct sk_buff **skbp, + unsigned int len) +{ + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct sk_buff *skb; + + /* we have a slightly odd routing setup here; the test route + * is for EID 8, which is our local EID. We don't do a routing + * lookup, so that's fine - all we require is a path through + * mctp_local_output, which will call rt->output on whatever + * route we provide + */ + __mctp_route_test_init(test, &dev, &rt, sock, MCTP_NET_ANY); + + /* Assign a single EID. ->addrs is freed on mctp netdev release */ + dev->mdev->addrs = kmalloc(sizeof(u8), GFP_KERNEL); + dev->mdev->num_addrs = 1; + dev->mdev->addrs[0] = 8; + + skb = alloc_skb(len + sizeof(struct mctp_hdr) + 1, GFP_KERNEL); + KUNIT_ASSERT_TRUE(test, skb); + __mctp_cb(skb); + skb_reserve(skb, sizeof(struct mctp_hdr) + 1); + memset(skb_put(skb, len), 0, len); + + /* take a ref for the route, we'll decrement in local output */ + refcount_inc(&rt->rt.refs); + + *devp = dev; + *rtp = rt; + *skbp = skb; +} + +static void mctp_test_flow_fini(struct kunit *test, + struct mctp_test_dev *dev, + struct mctp_test_route *rt, + struct socket *sock) +{ + __mctp_route_test_fini(test, dev, rt, sock); +} + +/* test that an outgoing skb has the correct MCTP extension data set */ +static void mctp_test_packet_flow(struct kunit *test) +{ + struct sk_buff *skb, *skb2; + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct mctp_flow *flow; + struct socket *sock; + u8 dst = 8; + int n, rc; + + mctp_test_flow_init(test, &dev, &rt, &sock, &skb, 30); + + rc = mctp_local_output(sock->sk, &rt->rt, skb, dst, MCTP_TAG_OWNER); + KUNIT_ASSERT_EQ(test, rc, 0); + + n = rt->pkts.qlen; + KUNIT_ASSERT_EQ(test, n, 1); + + skb2 = skb_dequeue(&rt->pkts); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb2); + + flow = skb_ext_find(skb2, SKB_EXT_MCTP); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, flow); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, flow->key); + KUNIT_ASSERT_PTR_EQ(test, flow->key->sk, sock->sk); + + kfree_skb(skb2); + mctp_test_flow_fini(test, dev, rt, sock); +} + +/* test that outgoing skbs, after fragmentation, all have the correct MCTP + * extension data set. + */ +static void mctp_test_fragment_flow(struct kunit *test) +{ + struct mctp_flow *flows[2]; + struct sk_buff *tx_skbs[2]; + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct sk_buff *skb; + struct socket *sock; + u8 dst = 8; + int n, rc; + + mctp_test_flow_init(test, &dev, &rt, &sock, &skb, 100); + + rc = mctp_local_output(sock->sk, &rt->rt, skb, dst, MCTP_TAG_OWNER); + KUNIT_ASSERT_EQ(test, rc, 0); + + n = rt->pkts.qlen; + KUNIT_ASSERT_EQ(test, n, 2); + + /* both resulting packets should have the same flow data */ + tx_skbs[0] = skb_dequeue(&rt->pkts); + tx_skbs[1] = skb_dequeue(&rt->pkts); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tx_skbs[0]); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tx_skbs[1]); + + flows[0] = skb_ext_find(tx_skbs[0], SKB_EXT_MCTP); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, flows[0]); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, flows[0]->key); + KUNIT_ASSERT_PTR_EQ(test, flows[0]->key->sk, sock->sk); + + flows[1] = skb_ext_find(tx_skbs[1], SKB_EXT_MCTP); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, flows[1]); + KUNIT_ASSERT_PTR_EQ(test, flows[1]->key, flows[0]->key); + + kfree_skb(tx_skbs[0]); + kfree_skb(tx_skbs[1]); + mctp_test_flow_fini(test, dev, rt, sock); +} + +#else +static void mctp_test_packet_flow(struct kunit *test) +{ + kunit_skip(test, "Requires CONFIG_MCTP_FLOWS=y"); +} + +static void mctp_test_fragment_flow(struct kunit *test) +{ + kunit_skip(test, "Requires CONFIG_MCTP_FLOWS=y"); +} +#endif + static struct kunit_case mctp_test_cases[] = { KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), @@ -847,6 +981,8 @@ static struct kunit_case mctp_test_cases[] = { mctp_route_input_sk_keys_gen_params), KUNIT_CASE(mctp_test_route_input_multiple_nets_bind), KUNIT_CASE(mctp_test_route_input_multiple_nets_key), + KUNIT_CASE(mctp_test_packet_flow), + KUNIT_CASE(mctp_test_fragment_flow), {} }; diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index 12da4c493867..a6cf69a665e8 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -23,6 +23,7 @@ CONFIG_USB4=y CONFIG_NET=y CONFIG_MCTP=y +CONFIG_MCTP_FLOWS=y CONFIG_INET=y CONFIG_MPTCP=y From d192eaf57f006072e8fffbbc5312da87ead86fc3 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Feb 2024 17:51:56 +0800 Subject: [PATCH 1467/2255] net: mctp: tests: Add a test for proper tag creation on local output Ensure we have the correct key parameters on sending a message. Signed-off-by: Jeremy Kerr Signed-off-by: Paolo Abeni --- net/mctp/test/route-test.c | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index eb7e9ac95612..77e5dd422258 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -971,6 +971,80 @@ static void mctp_test_fragment_flow(struct kunit *test) } #endif +/* Test that outgoing skbs cause a suitable tag to be created */ +static void mctp_test_route_output_key_create(struct kunit *test) +{ + const unsigned int netid = 50; + const u8 dst = 26, src = 15; + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct mctp_sk_key *key; + struct netns_mctp *mns; + unsigned long flags; + struct socket *sock; + struct sk_buff *skb; + bool empty, single; + const int len = 2; + int rc; + + dev = mctp_test_create_dev(); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + WRITE_ONCE(dev->mdev->net, netid); + + rt = mctp_test_create_route(&init_net, dev->mdev, dst, 68); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); + + rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock); + KUNIT_ASSERT_EQ(test, rc, 0); + + dev->mdev->addrs = kmalloc(sizeof(u8), GFP_KERNEL); + dev->mdev->num_addrs = 1; + dev->mdev->addrs[0] = src; + + skb = alloc_skb(sizeof(struct mctp_hdr) + 1 + len, GFP_KERNEL); + KUNIT_ASSERT_TRUE(test, skb); + __mctp_cb(skb); + skb_reserve(skb, sizeof(struct mctp_hdr) + 1 + len); + memset(skb_put(skb, len), 0, len); + + refcount_inc(&rt->rt.refs); + + mns = &sock_net(sock->sk)->mctp; + + /* We assume we're starting from an empty keys list, which requires + * preceding tests to clean up correctly! + */ + spin_lock_irqsave(&mns->keys_lock, flags); + empty = hlist_empty(&mns->keys); + spin_unlock_irqrestore(&mns->keys_lock, flags); + KUNIT_ASSERT_TRUE(test, empty); + + rc = mctp_local_output(sock->sk, &rt->rt, skb, dst, MCTP_TAG_OWNER); + KUNIT_ASSERT_EQ(test, rc, 0); + + key = NULL; + single = false; + spin_lock_irqsave(&mns->keys_lock, flags); + if (!hlist_empty(&mns->keys)) { + key = hlist_entry(mns->keys.first, struct mctp_sk_key, hlist); + single = hlist_is_singular_node(&key->hlist, &mns->keys); + } + spin_unlock_irqrestore(&mns->keys_lock, flags); + + KUNIT_ASSERT_NOT_NULL(test, key); + KUNIT_ASSERT_TRUE(test, single); + + KUNIT_EXPECT_EQ(test, key->net, netid); + KUNIT_EXPECT_EQ(test, key->local_addr, src); + KUNIT_EXPECT_EQ(test, key->peer_addr, dst); + /* key has incoming tag, so inverse of what we sent */ + KUNIT_EXPECT_FALSE(test, key->tag & MCTP_TAG_OWNER); + + sock_release(sock); + mctp_test_route_destroy(test, rt); + mctp_test_destroy_dev(dev); +} + static struct kunit_case mctp_test_cases[] = { KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), @@ -983,6 +1057,7 @@ static struct kunit_case mctp_test_cases[] = { KUNIT_CASE(mctp_test_route_input_multiple_nets_key), KUNIT_CASE(mctp_test_packet_flow), KUNIT_CASE(mctp_test_fragment_flow), + KUNIT_CASE(mctp_test_route_output_key_create), {} }; From 257bbf45af81bac9b0e38be530a554e2cff92700 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 20 Feb 2024 15:03:08 -0800 Subject: [PATCH 1468/2255] bnxt_en: Refactor ring reservation functions The current functions to reserve hardware rings pass in 6 different ring or resource types as parameters. Add a structure bnxt_hw_rings to consolidate all these parameters and pass the structure pointer instead to these functions. Add 2 related helper functions also. This makes the code cleaner and makes it easier to add new resources to be reserved. Reviewed-by: Ajit Khaparde Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 253 +++++++++++----------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 9 + 2 files changed, 132 insertions(+), 130 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 6f415425dc14..4a30eff0791b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7098,8 +7098,7 @@ int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings) static bool bnxt_rfs_supported(struct bnxt *bp); static struct hwrm_func_cfg_input * -__bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, - int ring_grps, int cp_rings, int stats, int vnics) +__bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { struct hwrm_func_cfg_input *req; u32 enables = 0; @@ -7108,52 +7107,51 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, return NULL; req->fid = cpu_to_le16(0xffff); - enables |= tx_rings ? FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS : 0; - req->num_tx_rings = cpu_to_le16(tx_rings); + enables |= hwr->tx ? FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS : 0; + req->num_tx_rings = cpu_to_le16(hwr->tx); if (BNXT_NEW_RM(bp)) { - enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0; - enables |= stats ? FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; + enables |= hwr->rx ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0; + enables |= hwr->stat ? FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0; - enables |= tx_rings + ring_grps ? + enables |= hwr->cp ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0; + enables |= hwr->tx + hwr->grp ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; - enables |= rx_rings ? - FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; + enables |= hwr->rx ? + FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; } else { - enables |= cp_rings ? + enables |= hwr->cp ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; - enables |= ring_grps ? + enables |= hwr->grp ? FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS | FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; } - enables |= vnics ? FUNC_CFG_REQ_ENABLES_NUM_VNICS : 0; + enables |= hwr->vnic ? FUNC_CFG_REQ_ENABLES_NUM_VNICS : 0; - req->num_rx_rings = cpu_to_le16(rx_rings); + req->num_rx_rings = cpu_to_le16(hwr->rx); if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, ring_grps); + u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, hwr->grp); - req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps); - req->num_msix = cpu_to_le16(cp_rings); + req->num_cmpl_rings = cpu_to_le16(hwr->tx + hwr->grp); + req->num_msix = cpu_to_le16(hwr->cp); req->num_rsscos_ctxs = cpu_to_le16(rss_ctx); } else { - req->num_cmpl_rings = cpu_to_le16(cp_rings); - req->num_hw_ring_grps = cpu_to_le16(ring_grps); + req->num_cmpl_rings = cpu_to_le16(hwr->cp); + req->num_hw_ring_grps = cpu_to_le16(hwr->grp); req->num_rsscos_ctxs = cpu_to_le16(1); if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) && bnxt_rfs_supported(bp)) req->num_rsscos_ctxs = - cpu_to_le16(ring_grps + 1); + cpu_to_le16(hwr->grp + 1); } - req->num_stat_ctxs = cpu_to_le16(stats); - req->num_vnics = cpu_to_le16(vnics); + req->num_stat_ctxs = cpu_to_le16(hwr->stat); + req->num_vnics = cpu_to_le16(hwr->vnic); } req->enables = cpu_to_le32(enables); return req; } static struct hwrm_func_vf_cfg_input * -__bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, - int ring_grps, int cp_rings, int stats, int vnics) +__bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { struct hwrm_func_vf_cfg_input *req; u32 enables = 0; @@ -7161,51 +7159,48 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, if (hwrm_req_init(bp, req, HWRM_FUNC_VF_CFG)) return NULL; - enables |= tx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0; - enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS | - FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; - enables |= stats ? FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; + enables |= hwr->tx ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0; + enables |= hwr->rx ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS | + FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; + enables |= hwr->stat ? FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - enables |= tx_rings + ring_grps ? + enables |= hwr->tx + hwr->grp ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; } else { - enables |= cp_rings ? - FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; - enables |= ring_grps ? + enables |= hwr->cp ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; + enables |= hwr->grp ? FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0; } - enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0; + enables |= hwr->vnic ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0; enables |= FUNC_VF_CFG_REQ_ENABLES_NUM_L2_CTXS; req->num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); - req->num_tx_rings = cpu_to_le16(tx_rings); - req->num_rx_rings = cpu_to_le16(rx_rings); + req->num_tx_rings = cpu_to_le16(hwr->tx); + req->num_rx_rings = cpu_to_le16(hwr->rx); if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, ring_grps); + u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, hwr->grp); - req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps); + req->num_cmpl_rings = cpu_to_le16(hwr->tx + hwr->grp); req->num_rsscos_ctxs = cpu_to_le16(rss_ctx); } else { - req->num_cmpl_rings = cpu_to_le16(cp_rings); - req->num_hw_ring_grps = cpu_to_le16(ring_grps); + req->num_cmpl_rings = cpu_to_le16(hwr->cp); + req->num_hw_ring_grps = cpu_to_le16(hwr->grp); req->num_rsscos_ctxs = cpu_to_le16(BNXT_VF_MAX_RSS_CTX); } - req->num_stat_ctxs = cpu_to_le16(stats); - req->num_vnics = cpu_to_le16(vnics); + req->num_stat_ctxs = cpu_to_le16(hwr->stat); + req->num_vnics = cpu_to_le16(hwr->vnic); req->enables = cpu_to_le32(enables); return req; } static int -bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, - int ring_grps, int cp_rings, int stats, int vnics) +bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { struct hwrm_func_cfg_input *req; int rc; - req = __bnxt_hwrm_reserve_pf_rings(bp, tx_rings, rx_rings, ring_grps, - cp_rings, stats, vnics); + req = __bnxt_hwrm_reserve_pf_rings(bp, hwr); if (!req) return -ENOMEM; @@ -7219,25 +7214,23 @@ bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, return rc; if (bp->hwrm_spec_code < 0x10601) - bp->hw_resc.resv_tx_rings = tx_rings; + bp->hw_resc.resv_tx_rings = hwr->tx; return bnxt_hwrm_get_rings(bp); } static int -bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, - int ring_grps, int cp_rings, int stats, int vnics) +bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { struct hwrm_func_vf_cfg_input *req; int rc; if (!BNXT_NEW_RM(bp)) { - bp->hw_resc.resv_tx_rings = tx_rings; + bp->hw_resc.resv_tx_rings = hwr->tx; return 0; } - req = __bnxt_hwrm_reserve_vf_rings(bp, tx_rings, rx_rings, ring_grps, - cp_rings, stats, vnics); + req = __bnxt_hwrm_reserve_vf_rings(bp, hwr); if (!req) return -ENOMEM; @@ -7248,15 +7241,12 @@ bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, return bnxt_hwrm_get_rings(bp); } -static int bnxt_hwrm_reserve_rings(struct bnxt *bp, int tx, int rx, int grp, - int cp, int stat, int vnic) +static int bnxt_hwrm_reserve_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { if (BNXT_PF(bp)) - return bnxt_hwrm_reserve_pf_rings(bp, tx, rx, grp, cp, stat, - vnic); + return bnxt_hwrm_reserve_pf_rings(bp, hwr); else - return bnxt_hwrm_reserve_vf_rings(bp, tx, rx, grp, cp, stat, - vnic); + return bnxt_hwrm_reserve_vf_rings(bp, hwr); } int bnxt_nq_rings_in_use(struct bnxt *bp) @@ -7352,47 +7342,60 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp) return false; } -static int __bnxt_reserve_rings(struct bnxt *bp) +static void bnxt_copy_reserved_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { struct bnxt_hw_resc *hw_resc = &bp->hw_resc; - int cp = bnxt_nq_rings_in_use(bp); - int tx = bp->tx_nr_rings; - int rx = bp->rx_nr_rings; - int grp, rx_rings, rc; - int vnic = 1, stat; + + hwr->tx = hw_resc->resv_tx_rings; + if (BNXT_NEW_RM(bp)) { + hwr->rx = hw_resc->resv_rx_rings; + hwr->cp = hw_resc->resv_irqs; + hwr->grp = hw_resc->resv_hw_ring_grps; + hwr->vnic = hw_resc->resv_vnics; + hwr->stat = hw_resc->resv_stat_ctxs; + } +} + +static bool bnxt_rings_ok(struct bnxt *bp, struct bnxt_hw_rings *hwr) +{ + return hwr->tx && hwr->rx && hwr->cp && hwr->grp && hwr->vnic && + hwr->stat; +} + +static int __bnxt_reserve_rings(struct bnxt *bp) +{ + struct bnxt_hw_rings hwr = {0}; + int rx_rings, rc; bool sh = false; int tx_cp; if (!bnxt_need_reserve_rings(bp)) return 0; + hwr.cp = bnxt_nq_rings_in_use(bp); + hwr.tx = bp->tx_nr_rings; + hwr.rx = bp->rx_nr_rings; + hwr.vnic = 1; if (bp->flags & BNXT_FLAG_SHARED_RINGS) sh = true; if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) - vnic = rx + 1; + hwr.vnic = hwr.rx + 1; if (bp->flags & BNXT_FLAG_AGG_RINGS) - rx <<= 1; - grp = bp->rx_nr_rings; - stat = bnxt_get_func_stat_ctxs(bp); + hwr.rx <<= 1; + hwr.grp = bp->rx_nr_rings; + hwr.stat = bnxt_get_func_stat_ctxs(bp); - rc = bnxt_hwrm_reserve_rings(bp, tx, rx, grp, cp, stat, vnic); + rc = bnxt_hwrm_reserve_rings(bp, &hwr); if (rc) return rc; - tx = hw_resc->resv_tx_rings; - if (BNXT_NEW_RM(bp)) { - rx = hw_resc->resv_rx_rings; - cp = hw_resc->resv_irqs; - grp = hw_resc->resv_hw_ring_grps; - vnic = hw_resc->resv_vnics; - stat = hw_resc->resv_stat_ctxs; - } + bnxt_copy_reserved_rings(bp, &hwr); - rx_rings = rx; + rx_rings = hwr.rx; if (bp->flags & BNXT_FLAG_AGG_RINGS) { - if (rx >= 2) { - rx_rings = rx >> 1; + if (hwr.rx >= 2) { + rx_rings = hwr.rx >> 1; } else { if (netif_running(bp->dev)) return -ENOMEM; @@ -7404,17 +7407,17 @@ static int __bnxt_reserve_rings(struct bnxt *bp) bnxt_set_ring_params(bp); } } - rx_rings = min_t(int, rx_rings, grp); - cp = min_t(int, cp, bp->cp_nr_rings); - if (stat > bnxt_get_ulp_stat_ctxs(bp)) - stat -= bnxt_get_ulp_stat_ctxs(bp); - cp = min_t(int, cp, stat); - rc = bnxt_trim_rings(bp, &rx_rings, &tx, cp, sh); + rx_rings = min_t(int, rx_rings, hwr.grp); + hwr.cp = min_t(int, hwr.cp, bp->cp_nr_rings); + if (hwr.stat > bnxt_get_ulp_stat_ctxs(bp)) + hwr.stat -= bnxt_get_ulp_stat_ctxs(bp); + hwr.cp = min_t(int, hwr.cp, hwr.stat); + rc = bnxt_trim_rings(bp, &rx_rings, &hwr.tx, hwr.cp, sh); if (bp->flags & BNXT_FLAG_AGG_RINGS) - rx = rx_rings << 1; - tx_cp = bnxt_num_tx_to_cp(bp, tx); - cp = sh ? max_t(int, tx_cp, rx_rings) : tx_cp + rx_rings; - bp->tx_nr_rings = tx; + hwr.rx = rx_rings << 1; + tx_cp = bnxt_num_tx_to_cp(bp, hwr.tx); + hwr.cp = sh ? max_t(int, tx_cp, rx_rings) : tx_cp + rx_rings; + bp->tx_nr_rings = hwr.tx; /* If we cannot reserve all the RX rings, reset the RSS map only * if absolutely necessary @@ -7431,9 +7434,9 @@ static int __bnxt_reserve_rings(struct bnxt *bp) } } bp->rx_nr_rings = rx_rings; - bp->cp_nr_rings = cp; + bp->cp_nr_rings = hwr.cp; - if (!tx || !rx || !cp || !grp || !vnic || !stat) + if (!bnxt_rings_ok(bp, &hwr)) return -ENOMEM; if (!netif_is_rxfh_configured(bp->dev)) @@ -7442,9 +7445,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp) return rc; } -static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, - int ring_grps, int cp_rings, int stats, - int vnics) +static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { struct hwrm_func_vf_cfg_input *req; u32 flags; @@ -7452,8 +7453,7 @@ static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, if (!BNXT_NEW_RM(bp)) return 0; - req = __bnxt_hwrm_reserve_vf_rings(bp, tx_rings, rx_rings, ring_grps, - cp_rings, stats, vnics); + req = __bnxt_hwrm_reserve_vf_rings(bp, hwr); flags = FUNC_VF_CFG_REQ_FLAGS_TX_ASSETS_TEST | FUNC_VF_CFG_REQ_FLAGS_RX_ASSETS_TEST | FUNC_VF_CFG_REQ_FLAGS_CMPL_ASSETS_TEST | @@ -7467,15 +7467,12 @@ static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, return hwrm_req_send_silent(bp, req); } -static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, - int ring_grps, int cp_rings, int stats, - int vnics) +static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { struct hwrm_func_cfg_input *req; u32 flags; - req = __bnxt_hwrm_reserve_pf_rings(bp, tx_rings, rx_rings, ring_grps, - cp_rings, stats, vnics); + req = __bnxt_hwrm_reserve_pf_rings(bp, hwr); flags = FUNC_CFG_REQ_FLAGS_TX_ASSETS_TEST; if (BNXT_NEW_RM(bp)) { flags |= FUNC_CFG_REQ_FLAGS_RX_ASSETS_TEST | @@ -7493,20 +7490,15 @@ static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, return hwrm_req_send_silent(bp, req); } -static int bnxt_hwrm_check_rings(struct bnxt *bp, int tx_rings, int rx_rings, - int ring_grps, int cp_rings, int stats, - int vnics) +static int bnxt_hwrm_check_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) { if (bp->hwrm_spec_code < 0x10801) return 0; if (BNXT_PF(bp)) - return bnxt_hwrm_check_pf_rings(bp, tx_rings, rx_rings, - ring_grps, cp_rings, stats, - vnics); + return bnxt_hwrm_check_pf_rings(bp, hwr); - return bnxt_hwrm_check_vf_rings(bp, tx_rings, rx_rings, ring_grps, - cp_rings, stats, vnics); + return bnxt_hwrm_check_vf_rings(bp, hwr); } static void bnxt_hwrm_coal_params_qcaps(struct bnxt *bp) @@ -12342,21 +12334,22 @@ static bool bnxt_rfs_supported(struct bnxt *bp) /* If runtime conditions support RFS */ static bool bnxt_rfs_capable(struct bnxt *bp) { - int vnics, max_vnics, max_rss_ctxs; + struct bnxt_hw_rings hwr = {0}; + int max_vnics, max_rss_ctxs; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return bnxt_rfs_supported(bp); if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp) || !bp->rx_nr_rings) return false; - vnics = 1 + bp->rx_nr_rings; + hwr.vnic = 1 + bp->rx_nr_rings; max_vnics = bnxt_get_max_func_vnics(bp); max_rss_ctxs = bnxt_get_max_func_rss_ctxs(bp); /* RSS contexts not a limiting factor */ if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) max_rss_ctxs = max_vnics; - if (vnics > max_vnics || vnics > max_rss_ctxs) { + if (hwr.vnic > max_vnics || hwr.vnic > max_rss_ctxs) { if (bp->rx_nr_rings > 1) netdev_warn(bp->dev, "Not enough resources to support NTUPLE filters, enough resources for up to %d rx rings\n", @@ -12367,15 +12360,16 @@ static bool bnxt_rfs_capable(struct bnxt *bp) if (!BNXT_NEW_RM(bp)) return true; - if (vnics == bp->hw_resc.resv_vnics) + if (hwr.vnic == bp->hw_resc.resv_vnics) return true; - bnxt_hwrm_reserve_rings(bp, 0, 0, 0, 0, 0, vnics); - if (vnics <= bp->hw_resc.resv_vnics) + bnxt_hwrm_reserve_rings(bp, &hwr); + if (hwr.vnic <= bp->hw_resc.resv_vnics) return true; netdev_warn(bp->dev, "Unable to reserve resources to support NTUPLE filters.\n"); - bnxt_hwrm_reserve_rings(bp, 0, 0, 0, 0, 0, 1); + hwr.vnic = 1; + bnxt_hwrm_reserve_rings(bp, &hwr); return false; } @@ -13299,9 +13293,8 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, int tx_xdp) { int max_rx, max_tx, max_cp, tx_sets = 1, tx_cp; - int tx_rings_needed, stats; + struct bnxt_hw_rings hwr = {0}; int rx_rings = rx; - int cp, vnics; if (tcs) tx_sets = tcs; @@ -13314,26 +13307,26 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, if (bp->flags & BNXT_FLAG_AGG_RINGS) rx_rings <<= 1; - tx_rings_needed = tx * tx_sets + tx_xdp; - if (max_tx < tx_rings_needed) + hwr.rx = rx_rings; + hwr.tx = tx * tx_sets + tx_xdp; + if (max_tx < hwr.tx) return -ENOMEM; - vnics = 1; + hwr.vnic = 1; if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5_PLUS)) == BNXT_FLAG_RFS) - vnics += rx; + hwr.vnic += rx; - tx_cp = __bnxt_num_tx_to_cp(bp, tx_rings_needed, tx_sets, tx_xdp); - cp = sh ? max_t(int, tx_cp, rx) : tx_cp + rx; - if (max_cp < cp) + tx_cp = __bnxt_num_tx_to_cp(bp, hwr.tx, tx_sets, tx_xdp); + hwr.cp = sh ? max_t(int, tx_cp, rx) : tx_cp + rx; + if (max_cp < hwr.cp) return -ENOMEM; - stats = cp; + hwr.stat = hwr.cp; if (BNXT_NEW_RM(bp)) { - cp += bnxt_get_ulp_msix_num(bp); - stats += bnxt_get_ulp_stat_ctxs(bp); + hwr.cp += bnxt_get_ulp_msix_num(bp); + hwr.stat += bnxt_get_ulp_stat_ctxs(bp); } - return bnxt_hwrm_check_rings(bp, tx_rings_needed, rx_rings, rx, cp, - stats, vnics); + return bnxt_hwrm_check_rings(bp, &hwr); } static void bnxt_unmap_bars(struct bnxt *bp, struct pci_dev *pdev) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 60bdd0673ec8..bb3b31f8d02f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1254,6 +1254,15 @@ struct bnxt_vnic_info { #define BNXT_VNIC_RFS_NEW_RSS_FLAG 0x10 }; +struct bnxt_hw_rings { + int tx; + int rx; + int grp; + int cp; + int stat; + int vnic; +}; + struct bnxt_hw_resc { u16 min_rsscos_ctxs; u16 max_rsscos_ctxs; From ae8186b2d4064699e182682cff2ddc1c9486be38 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 20 Feb 2024 15:03:09 -0800 Subject: [PATCH 1469/2255] bnxt_en: Explicitly specify P5 completion rings to reserve The current code assumes that every RX ring group and every TX ring requires a completion ring on P5_PLUS chips. Now that we have the bnxt_hw_rings structure, add the cp_p5 field so that it can be explicitly specified. This makes the logic more clear. Reviewed-by: Ajit Khaparde Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 19 ++++++++++++------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4a30eff0791b..4f3d2b1c9989 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7114,7 +7114,7 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) enables |= hwr->stat ? FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { enables |= hwr->cp ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0; - enables |= hwr->tx + hwr->grp ? + enables |= hwr->cp_p5 ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; enables |= hwr->rx ? FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; @@ -7131,7 +7131,7 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, hwr->grp); - req->num_cmpl_rings = cpu_to_le16(hwr->tx + hwr->grp); + req->num_cmpl_rings = cpu_to_le16(hwr->cp_p5); req->num_msix = cpu_to_le16(hwr->cp); req->num_rsscos_ctxs = cpu_to_le16(rss_ctx); } else { @@ -7164,7 +7164,7 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; enables |= hwr->stat ? FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - enables |= hwr->tx + hwr->grp ? + enables |= hwr->cp_p5 ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; } else { enables |= hwr->cp ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; @@ -7180,7 +7180,7 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, hwr->grp); - req->num_cmpl_rings = cpu_to_le16(hwr->tx + hwr->grp); + req->num_cmpl_rings = cpu_to_le16(hwr->cp_p5); req->num_rsscos_ctxs = cpu_to_le16(rss_ctx); } else { req->num_cmpl_rings = cpu_to_le16(hwr->cp); @@ -7350,6 +7350,8 @@ static void bnxt_copy_reserved_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) if (BNXT_NEW_RM(bp)) { hwr->rx = hw_resc->resv_rx_rings; hwr->cp = hw_resc->resv_irqs; + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) + hwr->cp_p5 = hw_resc->resv_cp_rings; hwr->grp = hw_resc->resv_hw_ring_grps; hwr->vnic = hw_resc->resv_vnics; hwr->stat = hw_resc->resv_stat_ctxs; @@ -7359,7 +7361,7 @@ static void bnxt_copy_reserved_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) static bool bnxt_rings_ok(struct bnxt *bp, struct bnxt_hw_rings *hwr) { return hwr->tx && hwr->rx && hwr->cp && hwr->grp && hwr->vnic && - hwr->stat; + hwr->stat && (hwr->cp_p5 || !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)); } static int __bnxt_reserve_rings(struct bnxt *bp) @@ -7378,8 +7380,9 @@ static int __bnxt_reserve_rings(struct bnxt *bp) hwr.vnic = 1; if (bp->flags & BNXT_FLAG_SHARED_RINGS) sh = true; - if ((bp->flags & BNXT_FLAG_RFS) && - !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) + hwr.cp_p5 = hwr.rx + hwr.tx; + else if (bp->flags & BNXT_FLAG_RFS) hwr.vnic = hwr.rx + 1; if (bp->flags & BNXT_FLAG_AGG_RINGS) hwr.rx <<= 1; @@ -13326,6 +13329,8 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, hwr.cp += bnxt_get_ulp_msix_num(bp); hwr.stat += bnxt_get_ulp_stat_ctxs(bp); } + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) + hwr.cp_p5 = hwr.tx + rx; return bnxt_hwrm_check_rings(bp, &hwr); } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index bb3b31f8d02f..681a579afcc2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1259,6 +1259,7 @@ struct bnxt_hw_rings { int rx; int grp; int cp; + int cp_p5; int stat; int vnic; }; From 438ba39b25fe71fc9cd862f30d25e54ed8f00603 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 20 Feb 2024 15:03:10 -0800 Subject: [PATCH 1470/2255] bnxt_en: Improve RSS context reservation infrastructure Add RSS context fields to struct bnxt_hw_rings and struct bnxt_hw_resc. With these, we can now specific the exact number of RSS contexts to reserve and store the reserved value. The original code relies on other resources to infer the number of RSS contexts to reserve and the reserved value is not stored. This improved infrastructure will make the RSS context accounting more complete and is needed by later patches. Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 57 ++++++++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 + 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4f3d2b1c9989..e6fad2a8b817 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7043,6 +7043,7 @@ static int bnxt_hwrm_get_rings(struct bnxt *bp) hw_resc->resv_hw_ring_grps = le32_to_cpu(resp->alloc_hw_ring_grps); hw_resc->resv_vnics = le16_to_cpu(resp->alloc_vnics); + hw_resc->resv_rsscos_ctxs = le16_to_cpu(resp->alloc_rsscos_ctx); cp = le16_to_cpu(resp->alloc_cmpl_rings); stats = le16_to_cpu(resp->alloc_stat_ctx); hw_resc->resv_irqs = cp; @@ -7116,32 +7117,23 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) enables |= hwr->cp ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0; enables |= hwr->cp_p5 ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; - enables |= hwr->rx ? - FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; } else { enables |= hwr->cp ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; enables |= hwr->grp ? - FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS | - FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; + FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0; } enables |= hwr->vnic ? FUNC_CFG_REQ_ENABLES_NUM_VNICS : 0; - + enables |= hwr->rss_ctx ? FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : + 0; req->num_rx_rings = cpu_to_le16(hwr->rx); + req->num_rsscos_ctxs = cpu_to_le16(hwr->rss_ctx); if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, hwr->grp); - req->num_cmpl_rings = cpu_to_le16(hwr->cp_p5); req->num_msix = cpu_to_le16(hwr->cp); - req->num_rsscos_ctxs = cpu_to_le16(rss_ctx); } else { req->num_cmpl_rings = cpu_to_le16(hwr->cp); req->num_hw_ring_grps = cpu_to_le16(hwr->grp); - req->num_rsscos_ctxs = cpu_to_le16(1); - if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) && - bnxt_rfs_supported(bp)) - req->num_rsscos_ctxs = - cpu_to_le16(hwr->grp + 1); } req->num_stat_ctxs = cpu_to_le16(hwr->stat); req->num_vnics = cpu_to_le16(hwr->vnic); @@ -7163,6 +7155,7 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) enables |= hwr->rx ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS | FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; enables |= hwr->stat ? FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; + enables |= hwr->rss_ctx ? FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { enables |= hwr->cp_p5 ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0; @@ -7177,15 +7170,12 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) req->num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); req->num_tx_rings = cpu_to_le16(hwr->tx); req->num_rx_rings = cpu_to_le16(hwr->rx); + req->num_rsscos_ctxs = cpu_to_le16(hwr->rss_ctx); if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, hwr->grp); - req->num_cmpl_rings = cpu_to_le16(hwr->cp_p5); - req->num_rsscos_ctxs = cpu_to_le16(rss_ctx); } else { req->num_cmpl_rings = cpu_to_le16(hwr->cp); req->num_hw_ring_grps = cpu_to_le16(hwr->grp); - req->num_rsscos_ctxs = cpu_to_le16(BNXT_VF_MAX_RSS_CTX); } req->num_stat_ctxs = cpu_to_le16(hwr->stat); req->num_vnics = cpu_to_le16(hwr->vnic); @@ -7289,6 +7279,20 @@ static int bnxt_get_func_stat_ctxs(struct bnxt *bp) return cp + ulp_stat; } +static int bnxt_get_total_rss_ctxs(struct bnxt *bp, struct bnxt_hw_rings *hwr) +{ + if (!hwr->grp) + return 0; + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) + return bnxt_get_nr_rss_ctxs(bp, hwr->grp); + + if (BNXT_VF(bp)) + return BNXT_VF_MAX_RSS_CTX; + if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) && bnxt_rfs_supported(bp)) + return hwr->grp + 1; + return 1; +} + /* Check if a default RSS map needs to be setup. This function is only * used on older firmware that does not require reserving RX rings. */ @@ -7355,6 +7359,7 @@ static void bnxt_copy_reserved_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) hwr->grp = hw_resc->resv_hw_ring_grps; hwr->vnic = hw_resc->resv_vnics; hwr->stat = hw_resc->resv_stat_ctxs; + hwr->rss_ctx = hw_resc->resv_rsscos_ctxs; } } @@ -7387,6 +7392,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp) if (bp->flags & BNXT_FLAG_AGG_RINGS) hwr.rx <<= 1; hwr.grp = bp->rx_nr_rings; + hwr.rss_ctx = bnxt_get_total_rss_ctxs(bp, &hwr); hwr.stat = bnxt_get_func_stat_ctxs(bp); rc = bnxt_hwrm_reserve_rings(bp, &hwr); @@ -11210,6 +11216,7 @@ static void bnxt_clear_reservations(struct bnxt *bp, bool fw_reset) hw_resc->resv_rx_rings = 0; hw_resc->resv_hw_ring_grps = 0; hw_resc->resv_vnics = 0; + hw_resc->resv_rsscos_ctxs = 0; if (!fw_reset) { bp->tx_nr_rings = 0; bp->rx_nr_rings = 0; @@ -12340,6 +12347,7 @@ static bool bnxt_rfs_capable(struct bnxt *bp) struct bnxt_hw_rings hwr = {0}; int max_vnics, max_rss_ctxs; + hwr.rss_ctx = 1; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return bnxt_rfs_supported(bp); if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp) || !bp->rx_nr_rings) @@ -12349,10 +12357,10 @@ static bool bnxt_rfs_capable(struct bnxt *bp) max_vnics = bnxt_get_max_func_vnics(bp); max_rss_ctxs = bnxt_get_max_func_rss_ctxs(bp); - /* RSS contexts not a limiting factor */ - if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) - max_rss_ctxs = max_vnics; - if (hwr.vnic > max_vnics || hwr.vnic > max_rss_ctxs) { + if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP)) + hwr.rss_ctx = hwr.vnic; + + if (hwr.vnic > max_vnics || hwr.rss_ctx > max_rss_ctxs) { if (bp->rx_nr_rings > 1) netdev_warn(bp->dev, "Not enough resources to support NTUPLE filters, enough resources for up to %d rx rings\n", @@ -12363,15 +12371,18 @@ static bool bnxt_rfs_capable(struct bnxt *bp) if (!BNXT_NEW_RM(bp)) return true; - if (hwr.vnic == bp->hw_resc.resv_vnics) + if (hwr.vnic == bp->hw_resc.resv_vnics && + hwr.rss_ctx <= bp->hw_resc.resv_rsscos_ctxs) return true; bnxt_hwrm_reserve_rings(bp, &hwr); - if (hwr.vnic <= bp->hw_resc.resv_vnics) + if (hwr.vnic <= bp->hw_resc.resv_vnics && + hwr.rss_ctx <= bp->hw_resc.resv_rsscos_ctxs) return true; netdev_warn(bp->dev, "Unable to reserve resources to support NTUPLE filters.\n"); hwr.vnic = 1; + hwr.rss_ctx = 0; bnxt_hwrm_reserve_rings(bp, &hwr); return false; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 681a579afcc2..4ff090981809 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1262,11 +1262,13 @@ struct bnxt_hw_rings { int cp_p5; int stat; int vnic; + int rss_ctx; }; struct bnxt_hw_resc { u16 min_rsscos_ctxs; u16 max_rsscos_ctxs; + u16 resv_rsscos_ctxs; u16 min_cp_rings; u16 max_cp_rings; u16 resv_cp_rings; From 9294299867734ceff303012cd6ec98990fbd78e6 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 20 Feb 2024 15:03:11 -0800 Subject: [PATCH 1471/2255] bnxt_en: Check additional resources in bnxt_check_rings() bnxt_check_rings() is called to check if we have enough resource assets to satisfy the new number of ethtool channels. If the asset test fails, the ethtool operation will fail gracefully. Otherwise we will proceed and commit to use the new number of channels. If it fails to allocate any resources, the chip will fail to come up. For completeness, check all possible resources before committing to the new settings. Add the missing ring group and RSS context asset tests in bnxt_check_rings(). Reviewed-by: Pavan Chebbi Reviewed-by: Somnath Kotur Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e6fad2a8b817..71ac165dfb52 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -13339,6 +13339,8 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, if (BNXT_NEW_RM(bp)) { hwr.cp += bnxt_get_ulp_msix_num(bp); hwr.stat += bnxt_get_ulp_stat_ctxs(bp); + hwr.grp = rx; + hwr.rss_ctx = bnxt_get_total_rss_ctxs(bp, &hwr); } if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) hwr.cp_p5 = hwr.tx + rx; From 8c81ae6c54c1273a1e08b10e1e2aa5bc321af10c Mon Sep 17 00:00:00 2001 From: Venkat Duvvuru Date: Tue, 20 Feb 2024 15:03:12 -0800 Subject: [PATCH 1472/2255] bnxt_en: Add bnxt_get_total_vnics() to calculate number of VNICs Refactor the code by adding a new function to calculate the number of required VNICs. This is used in multiple places when reserving or checking resources. Reviewed-by: Pavan Chebbi Signed-off-by: Venkat Duvvuru Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 28 ++++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 71ac165dfb52..95af3cd7dba0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7308,13 +7308,22 @@ static void bnxt_check_rss_tbl_no_rmgr(struct bnxt *bp) } } +static int bnxt_get_total_vnics(struct bnxt *bp, int rx_rings) +{ + if (bp->flags & BNXT_FLAG_RFS) { + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) + return rx_rings + 1; + } + return 1; +} + static bool bnxt_need_reserve_rings(struct bnxt *bp) { struct bnxt_hw_resc *hw_resc = &bp->hw_resc; int cp = bnxt_cp_rings_in_use(bp); int nq = bnxt_nq_rings_in_use(bp); int rx = bp->rx_nr_rings, stat; - int vnic = 1, grp = rx; + int vnic, grp = rx; if (hw_resc->resv_tx_rings != bp->tx_nr_rings && bp->hwrm_spec_code >= 0x10601) @@ -7329,9 +7338,9 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp) bnxt_check_rss_tbl_no_rmgr(bp); return false; } - if ((bp->flags & BNXT_FLAG_RFS) && - !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) - vnic = rx + 1; + + vnic = bnxt_get_total_vnics(bp, rx); + if (bp->flags & BNXT_FLAG_AGG_RINGS) rx <<= 1; stat = bnxt_get_func_stat_ctxs(bp); @@ -7382,13 +7391,13 @@ static int __bnxt_reserve_rings(struct bnxt *bp) hwr.cp = bnxt_nq_rings_in_use(bp); hwr.tx = bp->tx_nr_rings; hwr.rx = bp->rx_nr_rings; - hwr.vnic = 1; if (bp->flags & BNXT_FLAG_SHARED_RINGS) sh = true; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) hwr.cp_p5 = hwr.rx + hwr.tx; - else if (bp->flags & BNXT_FLAG_RFS) - hwr.vnic = hwr.rx + 1; + + hwr.vnic = bnxt_get_total_vnics(bp, hwr.rx); + if (bp->flags & BNXT_FLAG_AGG_RINGS) hwr.rx <<= 1; hwr.grp = bp->rx_nr_rings; @@ -13326,10 +13335,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, if (max_tx < hwr.tx) return -ENOMEM; - hwr.vnic = 1; - if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5_PLUS)) == - BNXT_FLAG_RFS) - hwr.vnic += rx; + hwr.vnic = bnxt_get_total_vnics(bp, rx); tx_cp = __bnxt_num_tx_to_cp(bp, hwr.tx, tx_sets, tx_xdp); hwr.cp = sh ? max_t(int, tx_cp, rx) : tx_cp + rx; From 5d5b90fb4e907c72ff0cddcd0f0c7a98facafaa2 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 20 Feb 2024 15:03:13 -0800 Subject: [PATCH 1473/2255] bnxt_en: Refactor bnxt_set_features() Refactor bnxt_set_features() function to have a common function to re-init. We'll need this to reinitialize when ntuple configuration changes. Reviewed-by: Kalesh AP Reviewed-by: Andy Gospodarek Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 95af3cd7dba0..2fe5262f6c41 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -12431,6 +12431,16 @@ static netdev_features_t bnxt_fix_features(struct net_device *dev, return features; } +static int bnxt_reinit_features(struct bnxt *bp, bool irq_re_init, + bool link_re_init, u32 flags, bool update_tpa) +{ + bnxt_close_nic(bp, irq_re_init, link_re_init); + bp->flags = flags; + if (update_tpa) + bnxt_set_ring_params(bp); + return bnxt_open_nic(bp, irq_re_init, link_re_init); +} + static int bnxt_set_features(struct net_device *dev, netdev_features_t features) { struct bnxt *bp = netdev_priv(dev); @@ -12479,14 +12489,9 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features) return rc; } - if (re_init) { - bnxt_close_nic(bp, false, false); - bp->flags = flags; - if (update_tpa) - bnxt_set_ring_params(bp); + if (re_init) + return bnxt_reinit_features(bp, false, false, flags, update_tpa); - return bnxt_open_nic(bp, false, false); - } if (update_tpa) { bp->flags = flags; rc = bnxt_set_tpa(bp, From ef4ee64e99903692f46b82b1f84c1173004dbb54 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 20 Feb 2024 15:03:14 -0800 Subject: [PATCH 1474/2255] bnxt_en: Define BNXT_VNIC_DEFAULT for the default vnic index Replace hard coded 0 index with more meaningful BNXT_VNIC_DEFAULT. Reviewed-by: Kalesh AP Reviewed-by: Somnath Kotur Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 39 ++++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 4 +- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 2fe5262f6c41..8877043febd2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4229,6 +4229,7 @@ static int bnxt_alloc_vnics(struct bnxt *bp) static void bnxt_init_vnics(struct bnxt *bp) { + struct bnxt_vnic_info *vnic0 = &bp->vnic_info[BNXT_VNIC_DEFAULT]; int i; for (i = 0; i < bp->nr_vnics; i++) { @@ -4242,7 +4243,7 @@ static void bnxt_init_vnics(struct bnxt *bp) vnic->fw_l2_ctx_id = INVALID_HW_RING_ID; if (bp->vnic_info[i].rss_hash_key) { - if (!i) { + if (i == BNXT_VNIC_DEFAULT) { u8 *key = (void *)vnic->rss_hash_key; int k; @@ -4268,8 +4269,7 @@ static void bnxt_init_vnics(struct bnxt *bp) bp->toeplitz_prefix |= key[k]; } } else { - memcpy(vnic->rss_hash_key, - bp->vnic_info[0].rss_hash_key, + memcpy(vnic->rss_hash_key, vnic0->rss_hash_key, HW_HASH_KEY_SIZE); } } @@ -5000,6 +5000,7 @@ static void bnxt_free_mem(struct bnxt *bp, bool irq_re_init) static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) { + struct bnxt_vnic_info *vnic0 = &bp->vnic_info[BNXT_VNIC_DEFAULT]; int i, j, rc, size, arr_size; void *bnapi; @@ -5128,8 +5129,8 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) if (rc) goto alloc_mem_err; - bp->vnic_info[0].flags |= BNXT_VNIC_RSS_FLAG | BNXT_VNIC_MCAST_FLAG | - BNXT_VNIC_UCAST_FLAG; + vnic0->flags |= BNXT_VNIC_RSS_FLAG | BNXT_VNIC_MCAST_FLAG | + BNXT_VNIC_UCAST_FLAG; rc = bnxt_alloc_vnic_attributes(bp); if (rc) goto alloc_mem_err; @@ -6178,7 +6179,7 @@ exit: static void bnxt_hwrm_update_rss_hash_cfg(struct bnxt *bp) { - struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; + struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; struct hwrm_vnic_rss_qcfg_output *resp; struct hwrm_vnic_rss_qcfg_input *req; @@ -6282,6 +6283,7 @@ static u32 bnxt_get_roce_vnic_mode(struct bnxt *bp) int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id) { + struct bnxt_vnic_info *vnic0 = &bp->vnic_info[BNXT_VNIC_DEFAULT]; struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; struct hwrm_vnic_cfg_input *req; unsigned int ring = 0, grp_idx; @@ -6311,8 +6313,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id) req->enables |= cpu_to_le32(VNIC_CFG_REQ_ENABLES_RSS_RULE | VNIC_CFG_REQ_ENABLES_MRU); } else if (vnic->flags & BNXT_VNIC_RFS_NEW_RSS_FLAG) { - req->rss_rule = - cpu_to_le16(bp->vnic_info[0].fw_rss_cos_lb_ctx[0]); + req->rss_rule = cpu_to_le16(vnic0->fw_rss_cos_lb_ctx[0]); req->enables |= cpu_to_le32(VNIC_CFG_REQ_ENABLES_RSS_RULE | VNIC_CFG_REQ_ENABLES_MRU); req->flags |= cpu_to_le32(VNIC_CFG_REQ_FLAGS_RSS_DFLT_CR_MODE); @@ -6409,7 +6410,7 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id, vnic_no_ring_grps: for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) vnic->fw_rss_cos_lb_ctx[i] = INVALID_HW_RING_ID; - if (vnic_id == 0) + if (vnic_id == BNXT_VNIC_DEFAULT) req->flags = cpu_to_le32(VNIC_ALLOC_REQ_FLAGS_DEFAULT); resp = hwrm_req_hold(bp, req); @@ -9896,7 +9897,7 @@ static bool bnxt_mc_list_updated(struct bnxt *, u32 *); static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) { - struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; + struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; int rc = 0; unsigned int rx_nr_rings = bp->rx_nr_rings; @@ -9925,7 +9926,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) rx_nr_rings--; /* default vnic 0 */ - rc = bnxt_hwrm_vnic_alloc(bp, 0, 0, rx_nr_rings); + rc = bnxt_hwrm_vnic_alloc(bp, BNXT_VNIC_DEFAULT, 0, rx_nr_rings); if (rc) { netdev_err(bp->dev, "hwrm vnic alloc failure rc: %x\n", rc); goto err_out; @@ -9934,7 +9935,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) if (BNXT_VF(bp)) bnxt_hwrm_func_qcfg(bp); - rc = bnxt_setup_vnic(bp, 0); + rc = bnxt_setup_vnic(bp, BNXT_VNIC_DEFAULT); if (rc) goto err_out; if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA) @@ -11594,7 +11595,7 @@ static void bnxt_cfg_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr if (fltr->type == BNXT_FLTR_TYPE_NTUPLE) { ntp_fltr = container_of(fltr, struct bnxt_ntuple_filter, base); - l2_fltr = bp->vnic_info[0].l2_filters[0]; + l2_fltr = bp->vnic_info[BNXT_VNIC_DEFAULT].l2_filters[0]; atomic_inc(&l2_fltr->refcnt); ntp_fltr->l2_fltr = l2_fltr; if (bnxt_hwrm_cfa_ntuple_filter_alloc(bp, ntp_fltr)) { @@ -12148,8 +12149,8 @@ void bnxt_get_ring_err_stats(struct bnxt *bp, static bool bnxt_mc_list_updated(struct bnxt *bp, u32 *rx_mask) { + struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; struct net_device *dev = bp->dev; - struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; struct netdev_hw_addr *ha; u8 *haddr; int mc_count = 0; @@ -12183,7 +12184,7 @@ static bool bnxt_mc_list_updated(struct bnxt *bp, u32 *rx_mask) static bool bnxt_uc_list_updated(struct bnxt *bp) { struct net_device *dev = bp->dev; - struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; + struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; struct netdev_hw_addr *ha; int off = 0; @@ -12210,7 +12211,7 @@ static void bnxt_set_rx_mode(struct net_device *dev) if (!test_bit(BNXT_STATE_OPEN, &bp->state)) return; - vnic = &bp->vnic_info[0]; + vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; mask = vnic->rx_mask; mask &= ~(CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS | CFA_L2_SET_RX_MASK_REQ_MASK_MCAST | @@ -12241,7 +12242,7 @@ static void bnxt_set_rx_mode(struct net_device *dev) static int bnxt_cfg_rx_mode(struct bnxt *bp) { struct net_device *dev = bp->dev; - struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; + struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; struct netdev_hw_addr *ha; int i, off = 0, rc; bool uc_update; @@ -14081,7 +14082,7 @@ u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys, if (skb) return skb_get_hash_raw(skb) & BNXT_NTP_FLTR_HASH_MASK; - vnic = &bp->vnic_info[0]; + vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; return bnxt_toeplitz(bp, fkeys, (void *)vnic->rss_hash_key); } @@ -14176,7 +14177,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, u32 flags; if (ether_addr_equal(dev->dev_addr, eth->h_dest)) { - l2_fltr = bp->vnic_info[0].l2_filters[0]; + l2_fltr = bp->vnic_info[BNXT_VNIC_DEFAULT].l2_filters[0]; atomic_inc(&l2_fltr->refcnt); } else { struct bnxt_l2_key key; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 4ff090981809..328bbf72acaf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1213,6 +1213,8 @@ struct bnxt_ring_grp_info { u16 cp_fw_ring_id; }; +#define BNXT_VNIC_DEFAULT 0 + struct bnxt_vnic_info { u16 fw_vnic_id; /* returned by Chimp during alloc */ #define BNXT_MAX_CTX_PER_VNIC 8 diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index dfb5944683f8..1d240a27455a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1314,7 +1314,7 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, if (!new_fltr) return -ENOMEM; - l2_fltr = bp->vnic_info[0].l2_filters[0]; + l2_fltr = bp->vnic_info[BNXT_VNIC_DEFAULT].l2_filters[0]; atomic_inc(&l2_fltr->refcnt); new_fltr->l2_fltr = l2_fltr; fmasks = &new_fltr->fmasks; @@ -1763,7 +1763,7 @@ static int bnxt_get_rxfh(struct net_device *dev, if (!bp->vnic_info) return 0; - vnic = &bp->vnic_info[0]; + vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; if (rxfh->indir && bp->rss_indir_tbl) { tbl_size = bnxt_get_rxfh_indir_size(dev); for (i = 0; i < tbl_size; i++) From 532c034e4b2b460a2d8584ce8f9e11f646c7f4e9 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 20 Feb 2024 15:03:15 -0800 Subject: [PATCH 1475/2255] bnxt_en: Provision for an additional VNIC for ntuple filters On newer chips that support the ring table index method for ntuple filters, the current scheme of using the same VNIC for both RSS and ntuple filters will not work in all cases. An ntuple filter can only be directed to a destination ring if that destination ring is also in the RSS indirection table. To support ntuple filters with any arbitratry RSS indirection table that may only include a subset of the rings, we need to use a separate VNIC for ntuple filters. This patch provisions the additional VNIC. The next patch will allocate additional VNIC from firmware and set it up. Reviewed-by: Somnath Kotur Reviewed-by: Kalesh AP Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 33 +++++++++++++++++++---- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 8877043febd2..0ca9dd397622 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4211,8 +4211,12 @@ static int bnxt_alloc_vnics(struct bnxt *bp) int num_vnics = 1; #ifdef CONFIG_RFS_ACCEL - if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5_PLUS)) == BNXT_FLAG_RFS) - num_vnics += bp->rx_nr_rings; + if (bp->flags & BNXT_FLAG_RFS) { + if (BNXT_SUPPORTS_NTUPLE_VNIC(bp)) + num_vnics++; + else if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) + num_vnics += bp->rx_nr_rings; + } #endif if (BNXT_CHIP_TYPE_NITRO_A0(bp)) @@ -7284,9 +7288,13 @@ static int bnxt_get_total_rss_ctxs(struct bnxt *bp, struct bnxt_hw_rings *hwr) { if (!hwr->grp) return 0; - if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) - return bnxt_get_nr_rss_ctxs(bp, hwr->grp); + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { + int rss_ctx = bnxt_get_nr_rss_ctxs(bp, hwr->grp); + if (BNXT_SUPPORTS_NTUPLE_VNIC(bp)) + rss_ctx *= hwr->vnic; + return rss_ctx; + } if (BNXT_VF(bp)) return BNXT_VF_MAX_RSS_CTX; if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) && bnxt_rfs_supported(bp)) @@ -7312,6 +7320,8 @@ static void bnxt_check_rss_tbl_no_rmgr(struct bnxt *bp) static int bnxt_get_total_vnics(struct bnxt *bp, int rx_rings) { if (bp->flags & BNXT_FLAG_RFS) { + if (BNXT_SUPPORTS_NTUPLE_VNIC(bp)) + return 2; if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) return rx_rings + 1; } @@ -8962,6 +8972,10 @@ static int bnxt_hwrm_cfa_adv_flow_mgnt_qcaps(struct bnxt *bp) CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V2_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2; + if (flags & + CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V3_SUPPORTED) + bp->fw_cap |= BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V3; + if (flags & CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO; @@ -12358,16 +12372,25 @@ static bool bnxt_rfs_capable(struct bnxt *bp) int max_vnics, max_rss_ctxs; hwr.rss_ctx = 1; + if (BNXT_SUPPORTS_NTUPLE_VNIC(bp)) { + /* 2 VNICS: default + Ntuple */ + hwr.vnic = 2; + hwr.rss_ctx = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) * + hwr.vnic; + goto check_reserve_vnic; + } if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return bnxt_rfs_supported(bp); if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp) || !bp->rx_nr_rings) return false; hwr.vnic = 1 + bp->rx_nr_rings; +check_reserve_vnic: max_vnics = bnxt_get_max_func_vnics(bp); max_rss_ctxs = bnxt_get_max_func_rss_ctxs(bp); - if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP)) + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && + !(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP)) hwr.rss_ctx = hwr.vnic; if (hwr.vnic > max_vnics || hwr.rss_ctx > max_rss_ctxs) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 328bbf72acaf..e9158407b181 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2328,12 +2328,16 @@ struct bnxt { #define BNXT_FW_CAP_BACKING_STORE_V2 BIT_ULL(36) #define BNXT_FW_CAP_VNIC_TUNNEL_TPA BIT_ULL(37) #define BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO BIT_ULL(38) + #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V3 BIT_ULL(39) u32 fw_dbg_cap; #define BNXT_NEW_RM(bp) ((bp)->fw_cap & BNXT_FW_CAP_NEW_RM) #define BNXT_PTP_USE_RTC(bp) (!BNXT_MH(bp) && \ ((bp)->fw_cap & BNXT_FW_CAP_PTP_RTC)) +#define BNXT_SUPPORTS_NTUPLE_VNIC(bp) \ + (BNXT_PF(bp) && ((bp)->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V3)) + u32 hwrm_spec_code; u16 hwrm_cmd_seq; u16 hwrm_cmd_kong_seq; From 93e90104bd1207a987241e2a696d53bb0b025a9e Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 20 Feb 2024 15:03:16 -0800 Subject: [PATCH 1476/2255] bnxt_en: Create and setup the additional VNIC for adding ntuple filters Allocate and setup the additional VNIC for ntuple filters if this new method is supported by the firmware. Even though this VNIC is only used for ntuple filters with direct ring destinations, we still setup the RSS hash to be identical to the default VNIC so that each RX packet will have the correct hash in the RX completion. This VNIC is always at VNIC index BNXT_VNIC_NTUPLE. Reviewed-by: Somnath Kotur Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 44 +++++++++++++++++------ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 ++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0ca9dd397622..b8ef6c2ba40c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5135,6 +5135,10 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) vnic0->flags |= BNXT_VNIC_RSS_FLAG | BNXT_VNIC_MCAST_FLAG | BNXT_VNIC_UCAST_FLAG; + if (BNXT_SUPPORTS_NTUPLE_VNIC(bp) && (bp->flags & BNXT_FLAG_RFS)) + bp->vnic_info[BNXT_VNIC_NTUPLE].flags |= + BNXT_VNIC_RSS_FLAG | BNXT_VNIC_NTUPLE_FLAG; + rc = bnxt_alloc_vnic_attributes(bp); if (rc) goto alloc_mem_err; @@ -6090,7 +6094,10 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, for (i = 0; i < tbl_size; i++) { u16 ring_id, j; - j = bp->rss_indir_tbl[i]; + if (vnic->flags & BNXT_VNIC_NTUPLE_FLAG) + j = ethtool_rxfh_indir_default(i, bp->rx_nr_rings); + else + j = bp->rss_indir_tbl[i]; rxr = &bp->rx_ring[j]; ring_id = rxr->rx_ring_struct.fw_ring_id; @@ -9844,10 +9851,28 @@ static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id) return __bnxt_setup_vnic(bp, vnic_id); } +static int bnxt_alloc_and_setup_vnic(struct bnxt *bp, u16 vnic_id, + u16 start_rx_ring_idx, int rx_rings) +{ + int rc; + + rc = bnxt_hwrm_vnic_alloc(bp, vnic_id, start_rx_ring_idx, rx_rings); + if (rc) { + netdev_err(bp->dev, "hwrm vnic %d alloc failure rc: %x\n", + vnic_id, rc); + return rc; + } + return bnxt_setup_vnic(bp, vnic_id); +} + static int bnxt_alloc_rfs_vnics(struct bnxt *bp) { int i, rc = 0; + if (BNXT_SUPPORTS_NTUPLE_VNIC(bp)) + return bnxt_alloc_and_setup_vnic(bp, BNXT_VNIC_NTUPLE, 0, + bp->rx_nr_rings); + if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) return 0; @@ -9863,14 +9888,7 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp) vnic->flags |= BNXT_VNIC_RFS_FLAG; if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) vnic->flags |= BNXT_VNIC_RFS_NEW_RSS_FLAG; - rc = bnxt_hwrm_vnic_alloc(bp, vnic_id, ring_id, 1); - if (rc) { - netdev_err(bp->dev, "hwrm vnic %d alloc failure rc: %x\n", - vnic_id, rc); - break; - } - rc = bnxt_setup_vnic(bp, vnic_id); - if (rc) + if (bnxt_alloc_and_setup_vnic(bp, vnic_id, ring_id, 1)) break; } return rc; @@ -12467,12 +12485,12 @@ static int bnxt_reinit_features(struct bnxt *bp, bool irq_re_init, static int bnxt_set_features(struct net_device *dev, netdev_features_t features) { + bool update_tpa = false, update_ntuple = false; struct bnxt *bp = netdev_priv(dev); u32 flags = bp->flags; u32 changes; int rc = 0; bool re_init = false; - bool update_tpa = false; flags &= ~BNXT_FLAG_ALL_CONFIG_FEATS; if (features & NETIF_F_GRO_HW) @@ -12503,6 +12521,9 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features) if (changes & ~BNXT_FLAG_TPA) re_init = true; + if (changes & BNXT_FLAG_RFS) + update_ntuple = true; + if (flags != bp->flags) { u32 old_flags = bp->flags; @@ -12513,6 +12534,9 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features) return rc; } + if (update_ntuple) + return bnxt_reinit_features(bp, true, false, flags, update_tpa); + if (re_init) return bnxt_reinit_features(bp, false, false, flags, update_tpa); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index e9158407b181..dd849e715c9b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1214,6 +1214,7 @@ struct bnxt_ring_grp_info { }; #define BNXT_VNIC_DEFAULT 0 +#define BNXT_VNIC_NTUPLE 1 struct bnxt_vnic_info { u16 fw_vnic_id; /* returned by Chimp during alloc */ @@ -1254,6 +1255,7 @@ struct bnxt_vnic_info { #define BNXT_VNIC_MCAST_FLAG 4 #define BNXT_VNIC_UCAST_FLAG 8 #define BNXT_VNIC_RFS_NEW_RSS_FLAG 0x10 +#define BNXT_VNIC_NTUPLE_FLAG 0x20 }; struct bnxt_hw_rings { From f6eff053a60c4c501baae29f245e66a67494dffb Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 20 Feb 2024 15:03:17 -0800 Subject: [PATCH 1477/2255] bnxt_en: Use the new VNIC to create ntuple filters The newly created vnic (BNXT_VNIC_NTUPLE) is ready to be used to create ntuple filters when supported by firmware. All RX rings can be used regardless of the RSS indirection setting on the default VNIC. Reviewed-by: Somnath Kotur Reviewed-by: Kalesh AP Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 33 ++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b8ef6c2ba40c..9968d67e6c77 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5785,6 +5785,29 @@ void bnxt_fill_ipv6_mask(__be32 mask[4]) mask[i] = cpu_to_be32(~0); } +static void +bnxt_cfg_rfs_ring_tbl_idx(struct bnxt *bp, + struct hwrm_cfa_ntuple_filter_alloc_input *req, + u16 rxq) +{ + if (BNXT_SUPPORTS_NTUPLE_VNIC(bp)) { + struct bnxt_vnic_info *vnic; + u32 enables; + + vnic = &bp->vnic_info[BNXT_VNIC_NTUPLE]; + req->dst_id = cpu_to_le16(vnic->fw_vnic_id); + enables = CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_RFS_RING_TBL_IDX; + req->enables |= cpu_to_le32(enables); + req->rfs_ring_tbl_idx = cpu_to_le16(rxq); + } else { + u32 flags; + + flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX; + req->flags |= cpu_to_le32(flags); + req->dst_id = cpu_to_le16(rxq); + } +} + int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, struct bnxt_ntuple_filter *fltr) { @@ -5794,7 +5817,6 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, struct flow_keys *keys = &fltr->fkeys; struct bnxt_l2_filter *l2_fltr; struct bnxt_vnic_info *vnic; - u32 flags = 0; int rc; rc = hwrm_req_init(bp, req, HWRM_CFA_NTUPLE_FILTER_ALLOC); @@ -5805,16 +5827,15 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, req->l2_filter_id = l2_fltr->base.filter_id; if (fltr->base.flags & BNXT_ACT_DROP) { - flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DROP; + req->flags = + cpu_to_le32(CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DROP); } else if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) { - flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX; - req->dst_id = cpu_to_le16(fltr->base.rxq); + bnxt_cfg_rfs_ring_tbl_idx(bp, req, fltr->base.rxq); } else { vnic = &bp->vnic_info[fltr->base.rxq + 1]; req->dst_id = cpu_to_le16(vnic->fw_vnic_id); } - req->flags = cpu_to_le32(flags); - req->enables = cpu_to_le32(BNXT_NTP_FLTR_FLAGS); + req->enables |= cpu_to_le32(BNXT_NTP_FLTR_FLAGS); req->ethertype = htons(ETH_P_IP); req->ip_addr_type = CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV4; From b546b57526953be2981113171ed586c4c50b1b0a Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Thu, 22 Feb 2024 17:03:00 +0200 Subject: [PATCH 1478/2255] selftests/bpf: update tcp_custom_syncookie to use scalar packet offset This commit updates tcp_custom_syncookie.c:tcp_parse_option() to use explicit packet offset (ctx->off) for packet access instead of ever moving pointer (ctx->ptr), this reduces verification complexity: - the tcp_parse_option() is passed as a callback to bpf_loop(); - suppose a checkpoint is created each time at function entry; - the ctx->ptr is tracked by verifier as PTR_TO_PACKET; - the ctx->ptr is incremented in tcp_parse_option(), thus umax_value field tracked for it is incremented as well; - on each next iteration of tcp_parse_option() checkpoint from a previous iteration can't be reused for state pruning, because PTR_TO_PACKET registers are considered equivalent only if old->umax_value >= cur->umax_value; - on the other hand, the ctx->off is a SCALAR, subject to widen_imprecise_scalars(); - it's exact bounds are eventually forgotten and it is tracked as unknown scalar at entry to tcp_parse_option(); - hence checkpoints created at the start of the function eventually converge. The change is similar to one applied in [0] to xdp_synproxy_kern.c. Comparing before and after with veristat yields following results: File Insns (A) Insns (B) Insns (DIFF) ------------------------------- --------- --------- ----------------- test_tcp_custom_syncookie.bpf.o 466657 12423 -454234 (-97.34%) [0] commit 977bc146d4eb ("selftests/bpf: track tcp payload offset as scalar in xdp_synproxy") Acked-by: Yonghong Song Signed-off-by: Eduard Zingerman Link: https://lore.kernel.org/r/20240222150300.14909-2-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/progs/test_tcp_custom_syncookie.c | 81 ++++++++++++------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c index a5501b29979a..c8e4553648bf 100644 --- a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c +++ b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c @@ -10,6 +10,8 @@ #include "test_siphash.h" #include "test_tcp_custom_syncookie.h" +#define MAX_PACKET_OFF 0xffff + /* Hash is calculated for each client and split into ISN and TS. * * MSB LSB @@ -52,16 +54,15 @@ static siphash_key_t test_key_siphash = { struct tcp_syncookie { struct __sk_buff *skb; + void *data; void *data_end; struct ethhdr *eth; struct iphdr *ipv4; struct ipv6hdr *ipv6; struct tcphdr *tcp; - union { - char *ptr; - __be32 *ptr32; - }; + __be32 *ptr32; struct bpf_tcp_req_attrs attrs; + u32 off; u32 cookie; u64 first; }; @@ -70,6 +71,7 @@ bool handled_syn, handled_ack; static int tcp_load_headers(struct tcp_syncookie *ctx) { + ctx->data = (void *)(long)ctx->skb->data; ctx->data_end = (void *)(long)ctx->skb->data_end; ctx->eth = (struct ethhdr *)(long)ctx->skb->data; @@ -134,6 +136,7 @@ static int tcp_reload_headers(struct tcp_syncookie *ctx) if (bpf_skb_change_tail(ctx->skb, data_len + 60 - ctx->tcp->doff * 4, 0)) goto err; + ctx->data = (void *)(long)ctx->skb->data; ctx->data_end = (void *)(long)ctx->skb->data_end; ctx->eth = (struct ethhdr *)(long)ctx->skb->data; if (ctx->ipv4) { @@ -195,47 +198,68 @@ err: return -1; } +static __always_inline void *next(struct tcp_syncookie *ctx, __u32 sz) +{ + __u64 off = ctx->off; + __u8 *data; + + /* Verifier forbids access to packet when offset exceeds MAX_PACKET_OFF */ + if (off > MAX_PACKET_OFF - sz) + return NULL; + + data = ctx->data + off; + barrier_var(data); + if (data + sz >= ctx->data_end) + return NULL; + + ctx->off += sz; + return data; +} + static int tcp_parse_option(__u32 index, struct tcp_syncookie *ctx) { - char opcode, opsize; + __u8 *opcode, *opsize, *wscale; + __u32 *tsval, *tsecr; + __u16 *mss; + __u32 off; - if (ctx->ptr + 1 > ctx->data_end) + off = ctx->off; + opcode = next(ctx, 1); + if (!opcode) goto stop; - opcode = *ctx->ptr++; - - if (opcode == TCPOPT_EOL) + if (*opcode == TCPOPT_EOL) goto stop; - if (opcode == TCPOPT_NOP) + if (*opcode == TCPOPT_NOP) goto next; - if (ctx->ptr + 1 > ctx->data_end) + opsize = next(ctx, 1); + if (!opsize) goto stop; - opsize = *ctx->ptr++; - - if (opsize < 2) + if (*opsize < 2) goto stop; - switch (opcode) { + switch (*opcode) { case TCPOPT_MSS: - if (opsize == TCPOLEN_MSS && ctx->tcp->syn && - ctx->ptr + (TCPOLEN_MSS - 2) < ctx->data_end) - ctx->attrs.mss = get_unaligned_be16(ctx->ptr); + mss = next(ctx, 2); + if (*opsize == TCPOLEN_MSS && ctx->tcp->syn && mss) + ctx->attrs.mss = get_unaligned_be16(mss); break; case TCPOPT_WINDOW: - if (opsize == TCPOLEN_WINDOW && ctx->tcp->syn && - ctx->ptr + (TCPOLEN_WINDOW - 2) < ctx->data_end) { + wscale = next(ctx, 1); + if (*opsize == TCPOLEN_WINDOW && ctx->tcp->syn && wscale) { ctx->attrs.wscale_ok = 1; - ctx->attrs.snd_wscale = *ctx->ptr; + ctx->attrs.snd_wscale = *wscale; } break; case TCPOPT_TIMESTAMP: - if (opsize == TCPOLEN_TIMESTAMP && - ctx->ptr + (TCPOLEN_TIMESTAMP - 2) < ctx->data_end) { - ctx->attrs.rcv_tsval = get_unaligned_be32(ctx->ptr); - ctx->attrs.rcv_tsecr = get_unaligned_be32(ctx->ptr + 4); + tsval = next(ctx, 4); + tsecr = next(ctx, 4); + if (*opsize == TCPOLEN_TIMESTAMP && tsval && tsecr) { + ctx->attrs.rcv_tsval = get_unaligned_be32(tsval); + ctx->attrs.rcv_tsecr = get_unaligned_be32(tsecr); if (ctx->tcp->syn && ctx->attrs.rcv_tsecr) ctx->attrs.tstamp_ok = 0; @@ -244,13 +268,12 @@ static int tcp_parse_option(__u32 index, struct tcp_syncookie *ctx) } break; case TCPOPT_SACK_PERM: - if (opsize == TCPOLEN_SACK_PERM && ctx->tcp->syn && - ctx->ptr + (TCPOLEN_SACK_PERM - 2) < ctx->data_end) + if (*opsize == TCPOLEN_SACK_PERM && ctx->tcp->syn) ctx->attrs.sack_ok = 1; break; } - ctx->ptr += opsize - 2; + ctx->off = off + *opsize; next: return 0; stop: @@ -259,7 +282,7 @@ stop: static void tcp_parse_options(struct tcp_syncookie *ctx) { - ctx->ptr = (char *)(ctx->tcp + 1); + ctx->off = (__u8 *)(ctx->tcp + 1) - (__u8 *)ctx->data, bpf_loop(40, tcp_parse_option, ctx, 0); } From c1bb68f6b2f6be5297c5fbad5caebf67d0dd3034 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Feb 2024 09:35:35 -0800 Subject: [PATCH 1479/2255] bpf, docs: Fix typos in instruction-set.rst * "BPF ADD" should be "BPF_ADD". * "src" should be "src_reg" in several places. The latter is the field name in the instruction. The former refers to the value of the register, or the immediate. * Add '' around field names in one sentence, for consistency with the rest of the document. Signed-off-by: Dave Thaler Acked-by: David Vernet Link: https://lore.kernel.org/r/20240221173535.16601-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/standardization/instruction-set.rst | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index 868d9f6177e3..45cffe94c752 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -178,8 +178,8 @@ Unused fields shall be cleared to zero. As discussed below in `64-bit immediate instructions`_, a 64-bit immediate instruction uses two 32-bit immediate values that are constructed as follows. The 64 bits following the basic instruction contain a pseudo instruction -using the same format but with opcode, dst_reg, src_reg, and offset all set to zero, -and imm containing the high 32 bits of the immediate value. +using the same format but with 'opcode', 'dst_reg', 'src_reg', and 'offset' all +set to zero, and imm containing the high 32 bits of the immediate value. This is depicted in the following figure:: @@ -392,27 +392,27 @@ otherwise identical operations, and indicates the base64 conformance group unless otherwise specified. The 'code' field encodes the operation as below: -======== ===== === =============================== ============================================= -code value src description notes -======== ===== === =============================== ============================================= -BPF_JA 0x0 0x0 PC += offset BPF_JMP | BPF_K only -BPF_JA 0x0 0x0 PC += imm BPF_JMP32 | BPF_K only -BPF_JEQ 0x1 any PC += offset if dst == src -BPF_JGT 0x2 any PC += offset if dst > src unsigned -BPF_JGE 0x3 any PC += offset if dst >= src unsigned -BPF_JSET 0x4 any PC += offset if dst & src -BPF_JNE 0x5 any PC += offset if dst != src -BPF_JSGT 0x6 any PC += offset if dst > src signed -BPF_JSGE 0x7 any PC += offset if dst >= src signed -BPF_CALL 0x8 0x0 call helper function by address BPF_JMP | BPF_K only, see `Helper functions`_ -BPF_CALL 0x8 0x1 call PC += imm BPF_JMP | BPF_K only, see `Program-local functions`_ -BPF_CALL 0x8 0x2 call helper function by BTF ID BPF_JMP | BPF_K only, see `Helper functions`_ -BPF_EXIT 0x9 0x0 return BPF_JMP | BPF_K only -BPF_JLT 0xa any PC += offset if dst < src unsigned -BPF_JLE 0xb any PC += offset if dst <= src unsigned -BPF_JSLT 0xc any PC += offset if dst < src signed -BPF_JSLE 0xd any PC += offset if dst <= src signed -======== ===== === =============================== ============================================= +======== ===== ======= =============================== ============================================= +code value src_reg description notes +======== ===== ======= =============================== ============================================= +BPF_JA 0x0 0x0 PC += offset BPF_JMP | BPF_K only +BPF_JA 0x0 0x0 PC += imm BPF_JMP32 | BPF_K only +BPF_JEQ 0x1 any PC += offset if dst == src +BPF_JGT 0x2 any PC += offset if dst > src unsigned +BPF_JGE 0x3 any PC += offset if dst >= src unsigned +BPF_JSET 0x4 any PC += offset if dst & src +BPF_JNE 0x5 any PC += offset if dst != src +BPF_JSGT 0x6 any PC += offset if dst > src signed +BPF_JSGE 0x7 any PC += offset if dst >= src signed +BPF_CALL 0x8 0x0 call helper function by address BPF_JMP | BPF_K only, see `Helper functions`_ +BPF_CALL 0x8 0x1 call PC += imm BPF_JMP | BPF_K only, see `Program-local functions`_ +BPF_CALL 0x8 0x2 call helper function by BTF ID BPF_JMP | BPF_K only, see `Helper functions`_ +BPF_EXIT 0x9 0x0 return BPF_JMP | BPF_K only +BPF_JLT 0xa any PC += offset if dst < src unsigned +BPF_JLE 0xb any PC += offset if dst <= src unsigned +BPF_JSLT 0xc any PC += offset if dst < src signed +BPF_JSLE 0xd any PC += offset if dst <= src signed +======== ===== ======= =============================== ============================================= The BPF program needs to store the return value into register R0 before doing a ``BPF_EXIT``. @@ -568,7 +568,7 @@ BPF_XOR 0xa0 atomic xor *(u32 *)(dst + offset) += src -``BPF_ATOMIC | BPF_DW | BPF_STX`` with 'imm' = BPF ADD means:: +``BPF_ATOMIC | BPF_DW | BPF_STX`` with 'imm' = BPF_ADD means:: *(u64 *)(dst + offset) += src @@ -601,24 +601,24 @@ and loaded back to ``R0``. ----------------------------- Instructions with the ``BPF_IMM`` 'mode' modifier use the wide instruction -encoding defined in `Instruction encoding`_, and use the 'src' field of the +encoding defined in `Instruction encoding`_, and use the 'src_reg' field of the basic instruction to hold an opcode subtype. The following table defines a set of ``BPF_IMM | BPF_DW | BPF_LD`` instructions -with opcode subtypes in the 'src' field, using new terms such as "map" +with opcode subtypes in the 'src_reg' field, using new terms such as "map" defined further below: -========================= ====== === ========================================= =========== ============== -opcode construction opcode src pseudocode imm type dst type -========================= ====== === ========================================= =========== ============== -BPF_IMM | BPF_DW | BPF_LD 0x18 0x0 dst = (next_imm << 32) | imm integer integer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x1 dst = map_by_fd(imm) map fd map -BPF_IMM | BPF_DW | BPF_LD 0x18 0x2 dst = map_val(map_by_fd(imm)) + next_imm map fd data pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x3 dst = var_addr(imm) variable id data pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x4 dst = code_addr(imm) integer code pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x5 dst = map_by_idx(imm) map index map -BPF_IMM | BPF_DW | BPF_LD 0x18 0x6 dst = map_val(map_by_idx(imm)) + next_imm map index data pointer -========================= ====== === ========================================= =========== ============== +========================= ====== ======= ========================================= =========== ============== +opcode construction opcode src_reg pseudocode imm type dst type +========================= ====== ======= ========================================= =========== ============== +BPF_IMM | BPF_DW | BPF_LD 0x18 0x0 dst = (next_imm << 32) | imm integer integer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x1 dst = map_by_fd(imm) map fd map +BPF_IMM | BPF_DW | BPF_LD 0x18 0x2 dst = map_val(map_by_fd(imm)) + next_imm map fd data pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x3 dst = var_addr(imm) variable id data pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x4 dst = code_addr(imm) integer code pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x5 dst = map_by_idx(imm) map index map +BPF_IMM | BPF_DW | BPF_LD 0x18 0x6 dst = map_val(map_by_idx(imm)) + next_imm map index data pointer +========================= ====== ======= ========================================= =========== ============== where From 89ee838130f470afcd02b30ca868f236a3f3b1d2 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Feb 2024 09:54:19 -0800 Subject: [PATCH 1480/2255] bpf, docs: specify which BPF_ABS and BPF_IND fields were zero Specifying which fields were unused allows IANA to only list as deprecated instructions that were actually used, leaving the rest as unassigned and possibly available for future use for something else. Signed-off-by: Dave Thaler Acked-by: David Vernet Link: https://lore.kernel.org/r/20240221175419.16843-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov --- Documentation/bpf/standardization/instruction-set.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index 45cffe94c752..f3269d6dd5e0 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -658,6 +658,7 @@ Legacy BPF Packet access instructions BPF previously introduced special instructions for access to packet data that were carried over from classic BPF. These instructions used an instruction class of BPF_LD, a size modifier of BPF_W, BPF_H, or BPF_B, and a -mode modifier of BPF_ABS or BPF_IND. However, these instructions are -deprecated and should no longer be used. All legacy packet access -instructions belong to the "legacy" conformance group. +mode modifier of BPF_ABS or BPF_IND. The 'dst_reg' and 'offset' fields were +set to zero, and 'src_reg' was set to zero for BPF_ABS. However, these +instructions are deprecated and should no longer be used. All legacy packet +access instructions belong to the "legacy" conformance group. From 58fd62e0aa50fdd20bc41a01e787001f3af8a925 Mon Sep 17 00:00:00 2001 From: Martin Kelly Date: Wed, 21 Feb 2024 13:18:38 -0800 Subject: [PATCH 1481/2255] bpf: Clarify batch lookup/lookup_and_delete semantics The batch lookup and lookup_and_delete APIs have two parameters, in_batch and out_batch, to facilitate iterative lookup/lookup_and_deletion operations for supported maps. Except NULL for in_batch at the start of these two batch operations, both parameters need to point to memory equal or larger than the respective map key size, except for various hashmaps (hash, percpu_hash, lru_hash, lru_percpu_hash) where the in_batch/out_batch memory size should be at least 4 bytes. Document these semantics to clarify the API. Signed-off-by: Martin Kelly Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20240221211838.1241578-1-martin.kelly@crowdstrike.com Signed-off-by: Martin KaFai Lau --- include/uapi/linux/bpf.h | 6 +++++- tools/include/uapi/linux/bpf.h | 6 +++++- tools/lib/bpf/bpf.h | 17 ++++++++++++----- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index d96708380e52..d2e6c5fcec01 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -617,7 +617,11 @@ union bpf_iter_link_info { * to NULL to begin the batched operation. After each subsequent * **BPF_MAP_LOOKUP_BATCH**, the caller should pass the resultant * *out_batch* as the *in_batch* for the next operation to - * continue iteration from the current point. + * continue iteration from the current point. Both *in_batch* and + * *out_batch* must point to memory large enough to hold a key, + * except for maps of type **BPF_MAP_TYPE_{HASH, PERCPU_HASH, + * LRU_HASH, LRU_PERCPU_HASH}**, for which batch parameters + * must be at least 4 bytes wide regardless of key size. * * The *keys* and *values* are output parameters which must point * to memory large enough to hold *count* items based on the key diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index d96708380e52..d2e6c5fcec01 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -617,7 +617,11 @@ union bpf_iter_link_info { * to NULL to begin the batched operation. After each subsequent * **BPF_MAP_LOOKUP_BATCH**, the caller should pass the resultant * *out_batch* as the *in_batch* for the next operation to - * continue iteration from the current point. + * continue iteration from the current point. Both *in_batch* and + * *out_batch* must point to memory large enough to hold a key, + * except for maps of type **BPF_MAP_TYPE_{HASH, PERCPU_HASH, + * LRU_HASH, LRU_PERCPU_HASH}**, for which batch parameters + * must be at least 4 bytes wide regardless of key size. * * The *keys* and *values* are output parameters which must point * to memory large enough to hold *count* items based on the key diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index ab2570d28aec..df0db2f0cdb7 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -190,10 +190,14 @@ LIBBPF_API int bpf_map_delete_batch(int fd, const void *keys, /** * @brief **bpf_map_lookup_batch()** allows for batch lookup of BPF map elements. * - * The parameter *in_batch* is the address of the first element in the batch to read. - * *out_batch* is an output parameter that should be passed as *in_batch* to subsequent - * calls to **bpf_map_lookup_batch()**. NULL can be passed for *in_batch* to indicate - * that the batched lookup starts from the beginning of the map. + * The parameter *in_batch* is the address of the first element in the batch to + * read. *out_batch* is an output parameter that should be passed as *in_batch* + * to subsequent calls to **bpf_map_lookup_batch()**. NULL can be passed for + * *in_batch* to indicate that the batched lookup starts from the beginning of + * the map. Both *in_batch* and *out_batch* must point to memory large enough to + * hold a single key, except for maps of type **BPF_MAP_TYPE_{HASH, PERCPU_HASH, + * LRU_HASH, LRU_PERCPU_HASH}**, for which the memory size must be at + * least 4 bytes wide regardless of key size. * * The *keys* and *values* are output parameters which must point to memory large enough to * hold *count* items based on the key and value size of the map *map_fd*. The *keys* @@ -226,7 +230,10 @@ LIBBPF_API int bpf_map_lookup_batch(int fd, void *in_batch, void *out_batch, * * @param fd BPF map file descriptor * @param in_batch address of the first element in batch to read, can pass NULL to - * get address of the first element in *out_batch* + * get address of the first element in *out_batch*. If not NULL, must be large + * enough to hold a key. For **BPF_MAP_TYPE_{HASH, PERCPU_HASH, LRU_HASH, + * LRU_PERCPU_HASH}**, the memory size must be at least 4 bytes wide regardless + * of key size. * @param out_batch output parameter that should be passed to next call as *in_batch* * @param keys pointer to an array of *count* keys * @param values pointer to an array large enough for *count* values From 3e0008336ae3153fb89b1a15bb877ddd38680fe6 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Wed, 21 Feb 2024 18:11:04 -0800 Subject: [PATCH 1482/2255] bpf: Check cfi_stubs before registering a struct_ops type. Recently, st_ops->cfi_stubs was introduced. However, the upcoming new struct_ops support (e.g. sched_ext) is not aware of this and does not provide its own cfi_stubs. The kernel ends up NULL dereferencing the st_ops->cfi_stubs. Considering struct_ops supports kernel module now, this NULL check is necessary. This patch is to reject struct_ops registration that does not provide a cfi_stubs. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240222021105.1180475-2-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/bpf_struct_ops.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 0d7be97a2411..a6019087b467 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -302,6 +302,11 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc, } sprintf(value_name, "%s%s", VALUE_PREFIX, st_ops->name); + if (!st_ops->cfi_stubs) { + pr_warn("struct_ops for %s has no cfi_stubs\n", st_ops->name); + return -EINVAL; + } + type_id = btf_find_by_name_kind(btf, st_ops->name, BTF_KIND_STRUCT); if (type_id < 0) { From e9bbda13a7b876451285ab15fb600b809e5e2290 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Wed, 21 Feb 2024 18:11:05 -0800 Subject: [PATCH 1483/2255] selftests/bpf: Test case for lacking CFI stub functions. Ensure struct_ops rejects the registration of struct_ops types without proper CFI stub functions. bpf_test_no_cfi.ko is a module that attempts to register a struct_ops type called "bpf_test_no_cfi_ops" with cfi_stubs of NULL and non-NULL value. The NULL one should fail, and the non-NULL one should succeed. The module can only be loaded successfully if these registrations yield the expected results. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240222021105.1180475-3-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/Makefile | 10 ++- .../selftests/bpf/bpf_test_no_cfi/Makefile | 19 +++++ .../bpf/bpf_test_no_cfi/bpf_test_no_cfi.c | 84 +++++++++++++++++++ .../bpf/prog_tests/test_struct_ops_no_cfi.c | 35 ++++++++ tools/testing/selftests/bpf/testing_helpers.c | 4 +- tools/testing/selftests/bpf/testing_helpers.h | 2 + 6 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_test_no_cfi/Makefile create mode 100644 tools/testing/selftests/bpf/bpf_test_no_cfi/bpf_test_no_cfi.c create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_no_cfi.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 9be69ff701ba..84cb5500e8ef 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -132,7 +132,7 @@ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_hw_metadata \ - xdp_features + xdp_features bpf_test_no_cfi.ko TEST_GEN_FILES += liburandom_read.so urandom_read sign-file uprobe_multi @@ -254,6 +254,12 @@ $(OUTPUT)/bpf_testmod.ko: $(VMLINUX_BTF) $(RESOLVE_BTFIDS) $(wildcard bpf_testmo $(Q)$(MAKE) $(submake_extras) RESOLVE_BTFIDS=$(RESOLVE_BTFIDS) -C bpf_testmod $(Q)cp bpf_testmod/bpf_testmod.ko $@ +$(OUTPUT)/bpf_test_no_cfi.ko: $(VMLINUX_BTF) $(RESOLVE_BTFIDS) $(wildcard bpf_test_no_cfi/Makefile bpf_test_no_cfi/*.[ch]) + $(call msg,MOD,,$@) + $(Q)$(RM) bpf_test_no_cfi/bpf_test_no_cfi.ko # force re-compilation + $(Q)$(MAKE) $(submake_extras) RESOLVE_BTFIDS=$(RESOLVE_BTFIDS) -C bpf_test_no_cfi + $(Q)cp bpf_test_no_cfi/bpf_test_no_cfi.ko $@ + DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool ifneq ($(CROSS_COMPILE),) CROSS_BPFTOOL := $(SCRATCH_DIR)/sbin/bpftool @@ -631,6 +637,7 @@ TRUNNER_EXTRA_SOURCES := test_progs.c \ flow_dissector_load.h \ ip_check_defrag_frags.h TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \ + $(OUTPUT)/bpf_test_no_cfi.ko \ $(OUTPUT)/liburandom_read.so \ $(OUTPUT)/xdp_synproxy \ $(OUTPUT)/sign-file \ @@ -759,6 +766,7 @@ EXTRA_CLEAN := $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \ feature bpftool \ $(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h *.subskel.h \ no_alu32 cpuv4 bpf_gcc bpf_testmod.ko \ + bpf_test_no_cfi.ko \ liburandom_read.so) .PHONY: docs docs-clean diff --git a/tools/testing/selftests/bpf/bpf_test_no_cfi/Makefile b/tools/testing/selftests/bpf/bpf_test_no_cfi/Makefile new file mode 100644 index 000000000000..ed5143b79edf --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_test_no_cfi/Makefile @@ -0,0 +1,19 @@ +BPF_TEST_NO_CFI_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +KDIR ?= $(abspath $(BPF_TEST_NO_CFI_DIR)/../../../../..) + +ifeq ($(V),1) +Q = +else +Q = @ +endif + +MODULES = bpf_test_no_cfi.ko + +obj-m += bpf_test_no_cfi.o + +all: + +$(Q)make -C $(KDIR) M=$(BPF_TEST_NO_CFI_DIR) modules + +clean: + +$(Q)make -C $(KDIR) M=$(BPF_TEST_NO_CFI_DIR) clean + diff --git a/tools/testing/selftests/bpf/bpf_test_no_cfi/bpf_test_no_cfi.c b/tools/testing/selftests/bpf/bpf_test_no_cfi/bpf_test_no_cfi.c new file mode 100644 index 000000000000..b1dd889d5d7d --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_test_no_cfi/bpf_test_no_cfi.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include +#include + +struct bpf_test_no_cfi_ops { + void (*fn_1)(void); + void (*fn_2)(void); +}; + +static int dummy_init(struct btf *btf) +{ + return 0; +} + +static int dummy_init_member(const struct btf_type *t, + const struct btf_member *member, + void *kdata, const void *udata) +{ + return 0; +} + +static int dummy_reg(void *kdata) +{ + return 0; +} + +static void dummy_unreg(void *kdata) +{ +} + +static const struct bpf_verifier_ops dummy_verifier_ops; + +static void bpf_test_no_cfi_ops__fn_1(void) +{ +} + +static void bpf_test_no_cfi_ops__fn_2(void) +{ +} + +static struct bpf_test_no_cfi_ops __test_no_cif_ops = { + .fn_1 = bpf_test_no_cfi_ops__fn_1, + .fn_2 = bpf_test_no_cfi_ops__fn_2, +}; + +static struct bpf_struct_ops test_no_cif_ops = { + .verifier_ops = &dummy_verifier_ops, + .init = dummy_init, + .init_member = dummy_init_member, + .reg = dummy_reg, + .unreg = dummy_unreg, + .name = "bpf_test_no_cfi_ops", + .owner = THIS_MODULE, +}; + +static int bpf_test_no_cfi_init(void) +{ + int ret; + + ret = register_bpf_struct_ops(&test_no_cif_ops, + bpf_test_no_cfi_ops); + if (!ret) + return -EINVAL; + + test_no_cif_ops.cfi_stubs = &__test_no_cif_ops; + ret = register_bpf_struct_ops(&test_no_cif_ops, + bpf_test_no_cfi_ops); + return ret; +} + +static void bpf_test_no_cfi_exit(void) +{ +} + +module_init(bpf_test_no_cfi_init); +module_exit(bpf_test_no_cfi_exit); + +MODULE_AUTHOR("Kuifeng Lee"); +MODULE_DESCRIPTION("BPF no cfi_stubs test module"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_no_cfi.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_no_cfi.c new file mode 100644 index 000000000000..106ea447965a --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_no_cfi.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include + +static void load_bpf_test_no_cfi(void) +{ + int fd; + int err; + + fd = open("bpf_test_no_cfi.ko", O_RDONLY); + if (!ASSERT_GE(fd, 0, "open")) + return; + + /* The module will try to register a struct_ops type without + * cfi_stubs and with cfi_stubs. + * + * The one without cfi_stub should fail. The module will be loaded + * successfully only if the result of the registration is as + * expected, or it fails. + */ + err = finit_module(fd, "", 0); + close(fd); + if (!ASSERT_OK(err, "finit_module")) + return; + + err = delete_module("bpf_test_no_cfi", 0); + ASSERT_OK(err, "delete_module"); +} + +void test_struct_ops_no_cfi(void) +{ + if (test__start_subtest("load_bpf_test_no_cfi")) + load_bpf_test_no_cfi(); +} diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index a59e56d804ee..28b6646662af 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -356,12 +356,12 @@ __u64 read_perf_max_sample_freq(void) return sample_freq; } -static int finit_module(int fd, const char *param_values, int flags) +int finit_module(int fd, const char *param_values, int flags) { return syscall(__NR_finit_module, fd, param_values, flags); } -static int delete_module(const char *name, int flags) +int delete_module(const char *name, int flags) { return syscall(__NR_delete_module, name, flags); } diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index d14de81727e6..d55f6ab12433 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -36,6 +36,8 @@ __u64 read_perf_max_sample_freq(void); int load_bpf_testmod(bool verbose); int unload_bpf_testmod(bool verbose); int kern_sync_rcu(void); +int finit_module(int fd, const char *param_values, int flags); +int delete_module(const char *name, int flags); static inline __u64 get_time_ns(void) { From 55bad79e33aeb670317290158a4b2ff71cdc8380 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 21 Feb 2024 17:25:17 +0100 Subject: [PATCH 1484/2255] bpf: allow more maps in sleepable bpf programs These 2 maps types are required for HID-BPF when a user wants to do IO with a device from a sleepable tracing point. Allowing BPF_MAP_TYPE_QUEUE (and therefore BPF_MAP_TYPE_STACK) allows for a BPF program to prepare from an IRQ the list of HID commands to send back to the device and then these commands can be retrieved from the sleepable trace point. Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20240221-hid-bpf-sleepable-v3-1-1fb378ca6301@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 011d54a1dc53..88e9d2e4c29f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -18022,6 +18022,8 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env, case BPF_MAP_TYPE_SK_STORAGE: case BPF_MAP_TYPE_TASK_STORAGE: case BPF_MAP_TYPE_CGRP_STORAGE: + case BPF_MAP_TYPE_QUEUE: + case BPF_MAP_TYPE_STACK: break; default: verbose(env, From dfe6625df48ec54c6dc9b86d361f26962d09de88 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 21 Feb 2024 17:25:18 +0100 Subject: [PATCH 1485/2255] bpf: introduce in_sleepable() helper No code change, but it'll allow to have only one place to change everything when we add in_sleepable in cur_state. Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20240221-hid-bpf-sleepable-v3-2-1fb378ca6301@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 88e9d2e4c29f..b787a6d67696 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5255,6 +5255,11 @@ bad_type: return -EINVAL; } +static bool in_sleepable(struct bpf_verifier_env *env) +{ + return env->prog->aux->sleepable; +} + /* The non-sleepable programs and sleepable programs with explicit bpf_rcu_read_lock() * can dereference RCU protected pointers and result is PTR_TRUSTED. */ @@ -5262,7 +5267,7 @@ static bool in_rcu_cs(struct bpf_verifier_env *env) { return env->cur_state->active_rcu_lock || env->cur_state->active_lock.ptr || - !env->prog->aux->sleepable; + !in_sleepable(env); } /* Once GCC supports btf_type_tag the following mechanism will be replaced with tag check */ @@ -10164,7 +10169,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EINVAL; } - if (!env->prog->aux->sleepable && fn->might_sleep) { + if (!in_sleepable(env) && fn->might_sleep) { verbose(env, "helper call might sleep in a non-sleepable prog\n"); return -EINVAL; } @@ -10194,7 +10199,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EINVAL; } - if (env->prog->aux->sleepable && is_storage_get_function(func_id)) + if (in_sleepable(env) && is_storage_get_function(func_id)) env->insn_aux_data[insn_idx].storage_get_func_atomic = true; } @@ -11535,7 +11540,7 @@ static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env) return true; fallthrough; default: - return env->prog->aux->sleepable; + return in_sleepable(env); } } @@ -12056,7 +12061,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, } sleepable = is_kfunc_sleepable(&meta); - if (sleepable && !env->prog->aux->sleepable) { + if (sleepable && !in_sleepable(env)) { verbose(env, "program must be sleepable to call sleepable kfunc %s\n", func_name); return -EACCES; } @@ -19669,7 +19674,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env) } if (is_storage_get_function(insn->imm)) { - if (!env->prog->aux->sleepable || + if (!in_sleepable(env) || env->insn_aux_data[i + delta].storage_get_func_atomic) insn_buf[0] = BPF_MOV64_IMM(BPF_REG_5, (__force __s32)GFP_ATOMIC); else From 2ab256e93249f5ac1da665861aa0f03fb4208d9c Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 21 Feb 2024 17:25:19 +0100 Subject: [PATCH 1486/2255] bpf: add is_async_callback_calling_insn() helper Currently we have a special case for BPF_FUNC_timer_set_callback, let's introduce a helper we can extend for the kfunc that will come in a later patch Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20240221-hid-bpf-sleepable-v3-3-1fb378ca6301@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b787a6d67696..1c34b91b9583 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -528,6 +528,11 @@ static bool is_sync_callback_calling_insn(struct bpf_insn *insn) (bpf_pseudo_kfunc_call(insn) && is_sync_callback_calling_kfunc(insn->imm)); } +static bool is_async_callback_calling_insn(struct bpf_insn *insn) +{ + return bpf_helper_call(insn) && is_async_callback_calling_function(insn->imm); +} + static bool is_storage_get_function(enum bpf_func_id func_id) { return func_id == BPF_FUNC_sk_storage_get || @@ -9445,9 +9450,7 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins return -EFAULT; } - if (insn->code == (BPF_JMP | BPF_CALL) && - insn->src_reg == 0 && - insn->imm == BPF_FUNC_timer_set_callback) { + if (is_async_callback_calling_insn(insn)) { struct bpf_verifier_state *async_cb; /* there is no real recursion here. timer callbacks are async */ @@ -15588,7 +15591,7 @@ static int visit_insn(int t, struct bpf_verifier_env *env) return DONE_EXPLORING; case BPF_CALL: - if (insn->src_reg == 0 && insn->imm == BPF_FUNC_timer_set_callback) + if (is_async_callback_calling_insn(insn)) /* Mark this call insn as a prune point to trigger * is_state_visited() check before call itself is * processed by __check_func_call(). Otherwise new From 9eda38dc9150c260ae74edd2e1fe2e2b6fc62cee Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 15 Feb 2024 09:05:00 +0100 Subject: [PATCH 1487/2255] net/af_iucv: fix virtual vs physical address confusion Fix virtual vs physical address confusion. This does not fix a bug since virtual and physical address spaces are currently the same. Signed-off-by: Alexander Gordeev Reviewed-by: Alexandra Winter Link: https://lore.kernel.org/r/20240215080500.2616848-1-agordeev@linux.ibm.com Signed-off-by: Jakub Kicinski --- net/iucv/af_iucv.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 498a0c35b7bb..4aa1c72e6c49 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1060,13 +1060,12 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg, int i; /* skip iucv_array lying in the headroom */ - iba[0].address = (u32)(addr_t)skb->data; + iba[0].address = (u32)virt_to_phys(skb->data); iba[0].length = (u32)skb_headlen(skb); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - iba[i + 1].address = - (u32)(addr_t)skb_frag_address(frag); + iba[i + 1].address = (u32)virt_to_phys(skb_frag_address(frag)); iba[i + 1].length = (u32)skb_frag_size(frag); } err = pr_iucv->message_send(iucv->path, &txmsg, @@ -1162,13 +1161,12 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, struct iucv_array *iba = (struct iucv_array *)skb->head; int i; - iba[0].address = (u32)(addr_t)skb->data; + iba[0].address = (u32)virt_to_phys(skb->data); iba[0].length = (u32)skb_headlen(skb); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - iba[i + 1].address = - (u32)(addr_t)skb_frag_address(frag); + iba[i + 1].address = (u32)virt_to_phys(skb_frag_address(frag)); iba[i + 1].length = (u32)skb_frag_size(frag); } rc = pr_iucv->message_receive(path, msg, From cbe30f99431d596a0dbe42863162bbf6cb21dd20 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 20 Feb 2024 09:17:37 +0000 Subject: [PATCH 1488/2255] net: microchip: lan743x: Fix spelling mistake "erro" -> "error" There is a spelling mistake in a netif_err message. Fix it. Signed-off-by: Colin Ian King Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240220091737.2676984-1-colin.i.king@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan743x_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 45e209a7d083..bd8aa83b47e5 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -1196,7 +1196,7 @@ static int lan743x_sgmii_config(struct lan743x_adapter *adapter) ret = lan743x_is_sgmii_2_5G_mode(adapter, &status); if (ret < 0) { netif_err(adapter, drv, adapter->netdev, - "erro %d SGMII get mode failed\n", ret); + "error %d SGMII get mode failed\n", ret); return ret; } From bcc115760ff32a5a256129a6eb39840288d269bd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 21 Feb 2024 11:52:41 +0100 Subject: [PATCH 1489/2255] octeon_ep_vf: Improve help text grammar Add missing articles. Fix plural vs. singular. Fix present vs. future. Reviewed-by: Simon Horman Reviewed-by: Sathesh B Edara Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/b3b97462c3d9eba2ec03dd6d597e63bf49a7365a.1708512706.git.geert+renesas@glider.be Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig b/drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig index dbd1267bda0c..e371a3ef0c49 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig @@ -8,12 +8,12 @@ config OCTEON_EP_VF depends on 64BIT depends on PCI help - This driver supports networking functionality of Marvell's + This driver supports the networking functionality of Marvell's Octeon PCI Endpoint NIC VF. - To know the list of devices supported by this driver, refer + To know the list of devices supported by this driver, refer to the documentation in . - To compile this drivers as a module, choose M here. Name of the - module is octeon_ep_vf. + To compile this driver as a module, choose M here. + The name of the module will be octeon_ep_vf. From 3e7a0dccf0703edd3a2d9e3361f672241c31773b Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 21 Feb 2024 08:17:32 -0800 Subject: [PATCH 1490/2255] ipv6/sit: Do not allocate stats in the driver With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the ipv6/sit driver and leverage the network core allocation. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20240221161732.3026127-1-leitao@debian.org Signed-off-by: Jakub Kicinski --- net/ipv6/sit.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index ed3a44aa1e9d..5ad01480854d 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1408,7 +1408,6 @@ static void ipip6_dev_free(struct net_device *dev) struct ip_tunnel *tunnel = netdev_priv(dev); dst_cache_destroy(&tunnel->dst_cache); - free_percpu(dev->tstats); } #define SIT_FEATURES (NETIF_F_SG | \ @@ -1437,6 +1436,8 @@ static void ipip6_tunnel_setup(struct net_device *dev) dev->features |= NETIF_F_LLTX; dev->features |= SIT_FEATURES; dev->hw_features |= SIT_FEATURES; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; + } static int ipip6_tunnel_init(struct net_device *dev) @@ -1449,16 +1450,11 @@ static int ipip6_tunnel_init(struct net_device *dev) strcpy(tunnel->parms.name, dev->name); ipip6_tunnel_bind_dev(dev); - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); - if (err) { - free_percpu(dev->tstats); - dev->tstats = NULL; + if (err) return err; - } + netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); netdev_lockdep_set_classes(dev); return 0; From a4634aa71fee11f5e3e13bf7d80ee1480a64ce70 Mon Sep 17 00:00:00 2001 From: Praveen Kumar Kannoju Date: Wed, 21 Feb 2024 13:57:52 +0530 Subject: [PATCH 1491/2255] bonding: rate-limit bonding driver inspect messages Through the routine bond_mii_monitor(), bonding driver inspects and commits the slave state changes. During the times when slave state change and failure in aqcuiring rtnl lock happen at the same time, the routine bond_mii_monitor() reschedules itself to come around after 1 msec to commit the new state. During this, it executes the routine bond_miimon_inspect() to re-inspect the state chane and prints the corresponding slave state on to the console. Hence we do see a message at every 1 msec till the rtnl lock is acquired and state chage is committed. This patch doesn't change how bond functions. It only simply limits this kind of log flood. Signed-off-by: Praveen Kumar Kannoju Reviewed-by: Simon Horman Reviewed-by: Hangbin Liu Acked-by: Jay Vosburgh Link: https://lore.kernel.org/r/20240221082752.4660-1-praveen.kannoju@oracle.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a8a6c5309518..ae1a561c4a0f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2611,7 +2611,7 @@ static int bond_miimon_inspect(struct bonding *bond) bond_propose_link_state(slave, BOND_LINK_FAIL); commit++; slave->delay = bond->params.downdelay; - if (slave->delay) { + if (slave->delay && net_ratelimit()) { slave_info(bond->dev, slave->dev, "link status down for %sinterface, disabling it in %d ms\n", (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) ? @@ -2625,9 +2625,10 @@ static int bond_miimon_inspect(struct bonding *bond) /* recovered before downdelay expired */ bond_propose_link_state(slave, BOND_LINK_UP); slave->last_link_up = jiffies; - slave_info(bond->dev, slave->dev, "link status up again after %d ms\n", - (bond->params.downdelay - slave->delay) * - bond->params.miimon); + if (net_ratelimit()) + slave_info(bond->dev, slave->dev, "link status up again after %d ms\n", + (bond->params.downdelay - slave->delay) * + bond->params.miimon); commit++; continue; } @@ -2649,7 +2650,7 @@ static int bond_miimon_inspect(struct bonding *bond) commit++; slave->delay = bond->params.updelay; - if (slave->delay) { + if (slave->delay && net_ratelimit()) { slave_info(bond->dev, slave->dev, "link status up, enabling it in %d ms\n", ignore_updelay ? 0 : bond->params.updelay * @@ -2659,9 +2660,10 @@ static int bond_miimon_inspect(struct bonding *bond) case BOND_LINK_BACK: if (!link_state) { bond_propose_link_state(slave, BOND_LINK_DOWN); - slave_info(bond->dev, slave->dev, "link status down again after %d ms\n", - (bond->params.updelay - slave->delay) * - bond->params.miimon); + if (net_ratelimit()) + slave_info(bond->dev, slave->dev, "link status down again after %d ms\n", + (bond->params.updelay - slave->delay) * + bond->params.miimon); commit++; continue; } From a818bd12538c1408c7480de31573cdb3c3c0926f Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Tue, 20 Feb 2024 10:37:35 +0530 Subject: [PATCH 1492/2255] net: stmmac: dwmac-qcom-ethqos: Add support for 2.5G SGMII Serdes phy needs to operate at 2500 mode for 2.5G speed and 1000 mode for 1G/100M/10M speed. Added changes to configure serdes phy and mac based on link speed. Changing serdes phy speed involves multiple register writes for serdes block. To avoid redundant write operations only update serdes phy when new speed is different. For 2500 speed MAC PCS autoneg needs to disabled. Added changes to disable MAC PCS autoneg if ANE parameter is not set. Signed-off-by: Sneh Shah Tested-by: Abhishek Chauhan # sa8775p-ride Reviewed-by: Abhishek Chauhan Signed-off-by: David S. Miller --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 26 +++++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_pcs.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 2691a250a5a7..3e7aa743ca97 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -106,6 +106,7 @@ struct qcom_ethqos { struct clk *link_clk; struct phy *serdes_phy; unsigned int speed; + int serdes_speed; phy_interface_t phy_mode; const struct ethqos_emac_por *por; @@ -606,19 +607,39 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) */ static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos) { + struct net_device *dev = platform_get_drvdata(ethqos->pdev); + struct stmmac_priv *priv = netdev_priv(dev); int val; val = readl(ethqos->mac_base + MAC_CTRL_REG); switch (ethqos->speed) { + case SPEED_2500: + val &= ~ETHQOS_MAC_CTRL_PORT_SEL; + rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + RGMII_IO_MACRO_CONFIG2); + if (ethqos->serdes_speed != SPEED_2500) + phy_set_speed(ethqos->serdes_phy, SPEED_2500); + ethqos->serdes_speed = SPEED_2500; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 0, 0, 0); + break; case SPEED_1000: val &= ~ETHQOS_MAC_CTRL_PORT_SEL; rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, RGMII_IO_MACRO_CONFIG2); + if (ethqos->serdes_speed != SPEED_1000) + phy_set_speed(ethqos->serdes_phy, SPEED_1000); + ethqos->serdes_speed = SPEED_1000; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); break; case SPEED_100: val |= ETHQOS_MAC_CTRL_PORT_SEL | ETHQOS_MAC_CTRL_SPEED_MODE; + if (ethqos->serdes_speed != SPEED_1000) + phy_set_speed(ethqos->serdes_phy, SPEED_1000); + ethqos->serdes_speed = SPEED_1000; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); break; case SPEED_10: val |= ETHQOS_MAC_CTRL_PORT_SEL; @@ -627,6 +648,10 @@ static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos) FIELD_PREP(RGMII_CONFIG_SGMII_CLK_DVDR, SGMII_10M_RX_CLK_DVDR), RGMII_IO_MACRO_CONFIG); + if (ethqos->serdes_speed != SPEED_1000) + phy_set_speed(ethqos->serdes_phy, ethqos->speed); + ethqos->serdes_speed = SPEED_1000; + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); break; } @@ -799,6 +824,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) "Failed to get serdes phy\n"); ethqos->speed = SPEED_1000; + ethqos->serdes_speed = SPEED_1000; ethqos_update_link_clk(ethqos, SPEED_1000); ethqos_set_func_clk_en(ethqos); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h index aefc121464b5..13a30e6df4c1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -110,6 +110,8 @@ static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane, /* Enable and restart the Auto-Negotiation */ if (ane) value |= GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_RAN; + else + value &= ~GMAC_AN_CTRL_ANE; /* In case of MAC-2-MAC connection, block is configured to operate * according to MAC conf register. From d455e805de706e8c1ce945a0202028c8d764b9bc Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 23 Feb 2024 17:20:32 +0200 Subject: [PATCH 1493/2255] wifi: ath11k: rearrange IRQ enable/disable in reset path For non WoW suspend/resume, ath11k host powers down whole hardware when suspend and powers up it when resume, the code path it goes through is very like the ath11k reset logic. In order to reuse that logic, rearrange IRQ handling in the reset path. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Signed-off-by: Kalle Valo Signed-off-by: Baochen Qiang Link: https://msgid.link/20240221024725.10057-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 922e67f8e04f..c78bce19bd75 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.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 @@ -1869,10 +1869,9 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) mutex_lock(&ab->core_lock); ath11k_thermal_unregister(ab); - ath11k_hif_irq_disable(ab); ath11k_dp_pdev_free(ab); ath11k_spectral_deinit(ab); - ath11k_hif_stop(ab); + ath11k_ce_cleanup_pipes(ab); ath11k_wmi_detach(ab); ath11k_dp_pdev_reo_cleanup(ab); mutex_unlock(&ab->core_lock); @@ -2127,6 +2126,9 @@ static void ath11k_core_reset(struct work_struct *work) time_left = wait_for_completion_timeout(&ab->recovery_start, ATH11K_RECOVER_START_TIMEOUT_HZ); + ath11k_hif_irq_disable(ab); + ath11k_hif_ce_irq_disable(ab); + ath11k_hif_power_down(ab); ath11k_hif_power_up(ab); From fbb2a14afe00a5691b43cd19c946472e59e16fc6 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 23 Feb 2024 17:20:33 +0200 Subject: [PATCH 1494/2255] wifi: ath11k: remove MHI LOOPBACK channels There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend: mhi mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhi mhi0_LOOPBACK: 0: Failed to reset channel, still resetting Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Signed-off-by: Kalle Valo Signed-off-by: Baochen Qiang Link: https://msgid.link/20240221024725.10057-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mhi.c | 56 --------------------------- 1 file changed, 56 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index b53659145fcf..3de7fa6f88d0 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -21,34 +21,6 @@ #define RDDM_DUMP_SIZE 0x420000 static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { - { - .num = 0, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 0, - .dir = DMA_TO_DEVICE, - .ee_mask = 0x4, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, - { - .num = 1, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 0, - .dir = DMA_FROM_DEVICE, - .ee_mask = 0x4, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, { .num = 20, .name = "IPCR", @@ -114,34 +86,6 @@ static struct mhi_controller_config ath11k_mhi_config_qca6390 = { }; static struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = { - { - .num = 0, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 1, - .dir = DMA_TO_DEVICE, - .ee_mask = 0x14, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, - { - .num = 1, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 1, - .dir = DMA_FROM_DEVICE, - .ee_mask = 0x14, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, { .num = 20, .name = "IPCR", From 5f3288a3487849542f948319a1a368adcc9ae7a0 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 23 Feb 2024 17:20:33 +0200 Subject: [PATCH 1495/2255] wifi: ath11k: do not dump SRNG statistics during resume Both the firmware reset feature and the power management suspend/resume feature share common power-down and power-up functionality. One aspect of the power-up functionality is the handling of the ATH11K_QMI_EVENT_FW_INIT_DONE event. When this event is received, a call is made to ath11k_hal_dump_srng_stats(), with the purpose to collect information that may be useful in debugging the cause of a firmware reset. Unfortunately, since this functionality is shared between both the firmware reset path and the power management resume path, the kernel log is flooded with messages during resume. Since these messages are not useful during resume, and in fact can be confusing and can increase the time it takes to resume, update the logic to only call ath11k_hal_dump_srng_stats() during firmware reset. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Signed-off-by: Kalle Valo Signed-off-by: Baochen Qiang Link: https://msgid.link/20240221024725.10057-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/qmi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 2c7cab62b9bb..5006f81f779b 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.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 @@ -3249,7 +3249,8 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) case ATH11K_QMI_EVENT_FW_INIT_DONE: clear_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) { - ath11k_hal_dump_srng_stats(ab); + if (ab->is_reset) + ath11k_hal_dump_srng_stats(ab); queue_work(ab->workqueue, &ab->restart_work); break; } From 361c90ed3647952fa01b3a4240129de077b4ce60 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 23 Feb 2024 17:20:33 +0200 Subject: [PATCH 1496/2255] wifi: ath11k: fix warning on DMA ring capabilities event We are seeing below warning in both reset and suspend/resume scenarios: [69663.691847] ath11k_pci 0000:02:00.0: Already processed, so ignoring dma ring caps This is because ab->num_db_cap is not cleared in ath11k_wmi_free_dbring_caps(), so clear it to avoid such warnings. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Signed-off-by: Kalle Valo Signed-off-by: Baochen Qiang Link: https://msgid.link/20240221024725.10057-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 90f1fdec9adc..34ab9631ff36 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.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 #include @@ -4857,6 +4857,7 @@ static void ath11k_wmi_free_dbring_caps(struct ath11k_base *ab) { kfree(ab->db_caps); ab->db_caps = NULL; + ab->num_db_cap = 0; } static int ath11k_wmi_tlv_dma_ring_caps(struct ath11k_base *ab, From 50556081e09b9e2b75a215694dd2d166de611f56 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 23 Feb 2024 17:20:33 +0200 Subject: [PATCH 1497/2255] wifi: ath11k: thermal: don't try to register multiple times Every time the firmware boots we call ath11k_core_qmi_firmware_ready() which ends up calling ath11k_thermal_register(). So we try to register thermal devices multiple times. And when we power off the firmware during suspend/hibernation (implemented in the next patch) we get a warning in resume: hwmon hwmon4: PM: parent phy0 should not be sleeping Workaround this similarly like ath11k_mac_register() does by testing ATH11K_FLAG_REGISTERED. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Signed-off-by: Kalle Valo Signed-off-by: Baochen Qiang Link: https://msgid.link/20240221024725.10057-6-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/thermal.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c index c29b11ab5bfa..41e7499f075f 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.c +++ b/drivers/net/wireless/ath/ath11k/thermal.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -163,6 +163,9 @@ int ath11k_thermal_register(struct ath11k_base *ab) struct ath11k_pdev *pdev; int i, ret; + if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; From 1098eb62433cd4e1a7d256c042528336e4e7bd45 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 23 Feb 2024 17:20:34 +0200 Subject: [PATCH 1498/2255] dt-bindings: net: wireless: qcom: Update maintainers Add Jeff Johnson as a maintainer of the qcom,ath1*k.yaml files. Signed-off-by: Jeff Johnson Acked-by: Krzysztof Kozlowski Signed-off-by: Kalle Valo Link: https://msgid.link/20240217-ath1xk-maintainer-v1-1-9f7ff5fb6bf4@quicinc.com --- Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml | 1 + .../devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml | 1 + Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml index 7758a55dd328..9b3ef4bc3732 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml @@ -8,6 +8,7 @@ title: Qualcomm Technologies ath10k wireless devices maintainers: - Kalle Valo + - Jeff Johnson description: Qualcomm Technologies, Inc. IEEE 802.11ac devices. diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml index 817f02a8b481..41d023797d7d 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml @@ -9,6 +9,7 @@ title: Qualcomm Technologies ath11k wireless devices (PCIe) maintainers: - Kalle Valo + - Jeff Johnson description: | Qualcomm Technologies IEEE 802.11ax PCIe devices diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml index 7d5f982a3d09..672282cdfc2f 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml @@ -9,6 +9,7 @@ title: Qualcomm Technologies ath11k wireless devices maintainers: - Kalle Valo + - Jeff Johnson description: | These are dt entries for Qualcomm Technologies, Inc. IEEE 802.11ax From d2efeb52c344c3e987d143dc5232f53f9b96c86a Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Tue, 20 Feb 2024 20:42:44 +0100 Subject: [PATCH 1499/2255] net: ethtool: avoid rebuilds on UTS_RELEASE change Currently, when you switch between branches or something like that and rebuild, net/ethtool/ioctl.c has to be built again because it depends on UTS_RELEASE. By instead referencing a string variable stored in another object file, this can be avoided. Signed-off-by: Jann Horn Reviewed-by: John Garry Link: https://lore.kernel.org/r/20240220194244.2056384-1-jannh@google.com Signed-off-by: Jakub Kicinski --- net/ethtool/ioctl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 1763e8b697e1..b419969c0dcb 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -26,12 +26,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include "common.h" /* State held across locks and calls for commands which have devlink fallback */ @@ -713,7 +713,8 @@ ethtool_get_drvinfo(struct net_device *dev, struct ethtool_devlink_compat *rsp) struct device *parent = dev->dev.parent; rsp->info.cmd = ETHTOOL_GDRVINFO; - strscpy(rsp->info.version, UTS_RELEASE, sizeof(rsp->info.version)); + strscpy(rsp->info.version, init_uts_ns.name.release, + sizeof(rsp->info.version)); if (ops->get_drvinfo) { ops->get_drvinfo(dev, &rsp->info); if (!rsp->info.bus_info[0] && parent) From 025f8ad20f2e3264d11683aa9cbbf0083eefbdcd Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 22 Feb 2024 15:03:10 +0100 Subject: [PATCH 1500/2255] net: mpls: error out if inner headers are not set mpls_gso_segment() assumes skb_inner_network_header() returns a valid result: mpls_hlen = skb_inner_network_header(skb) - skb_network_header(skb); if (unlikely(!mpls_hlen || mpls_hlen % MPLS_HLEN)) goto out; if (unlikely(!pskb_may_pull(skb, mpls_hlen))) With syzbot reproducer, skb_inner_network_header() yields 0, skb_network_header() returns 108, so this will "pskb_may_pull(skb, -108)))" which triggers a newly added DEBUG_NET_WARN_ON_ONCE() check: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 5068 at include/linux/skbuff.h:2723 pskb_may_pull_reason include/linux/skbuff.h:2723 [inline] WARNING: CPU: 0 PID: 5068 at include/linux/skbuff.h:2723 pskb_may_pull include/linux/skbuff.h:2739 [inline] WARNING: CPU: 0 PID: 5068 at include/linux/skbuff.h:2723 mpls_gso_segment+0x773/0xaa0 net/mpls/mpls_gso.c:34 [..] skb_mac_gso_segment+0x383/0x740 net/core/gso.c:53 nsh_gso_segment+0x40a/0xad0 net/nsh/nsh.c:108 skb_mac_gso_segment+0x383/0x740 net/core/gso.c:53 __skb_gso_segment+0x324/0x4c0 net/core/gso.c:124 skb_gso_segment include/net/gso.h:83 [inline] [..] sch_direct_xmit+0x11a/0x5f0 net/sched/sch_generic.c:327 [..] packet_sendmsg+0x46a9/0x6130 net/packet/af_packet.c:3113 [..] First iteration of this patch made mpls_hlen signed and changed test to error out to "mpls_hlen <= 0 || ..". Eric Dumazet said: > I was thinking about adding a debug check in skb_inner_network_header() > if inner_network_header is zero (that would mean it is not 'set' yet), > but this would trigger even after your patch. So add new skb_inner_network_header_was_set() helper and use that. The syzbot reproducer injects data via packet socket. The skb that gets allocated and passed down the stack has ->protocol set to NSH (0x894f) and gso_type set to SKB_GSO_UDP | SKB_GSO_DODGY. This gets passed to skb_mac_gso_segment(), which sees NSH as ptype to find a callback for. nsh_gso_segment() retrieves next type: proto = tun_p_to_eth_p(nsh_hdr(skb)->np); ... which is MPLS (TUN_P_MPLS_UC). It updates skb->protocol and then calls mpls_gso_segment(). Inner offsets are all 0, so mpls_gso_segment() ends up with a negative header size. In case more callers rely on silent handling of such large may_pull values we could also 'legalize' this behaviour, either replacing the debug check with (len > INT_MAX) test or removing it and instead adding a comment before existing if (unlikely(len > skb->len)) return SKB_DROP_REASON_PKT_TOO_SMALL; test in pskb_may_pull_reason(), saying that this check also implicitly takes care of callers that miscompute header sizes. Cc: Simon Horman Fixes: 219eee9c0d16 ("net: skbuff: add overflow debug check to pull/push helpers") Reported-by: syzbot+99d15fcdb0132a1e1a82@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/00000000000043b1310611e388aa@google.com/raw Signed-off-by: Florian Westphal Link: https://lore.kernel.org/r/20240222140321.14080-1-fw@strlen.de Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 5 +++++ net/mpls/mpls_gso.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 28c7cb7ce251..1470b74fb6d2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2894,6 +2894,11 @@ static inline void skb_set_inner_network_header(struct sk_buff *skb, skb->inner_network_header += offset; } +static inline bool skb_inner_network_header_was_set(const struct sk_buff *skb) +{ + return skb->inner_network_header > 0; +} + static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb) { return skb->head + skb->inner_mac_header; diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c index 533d082f0701..45d1e6a157fc 100644 --- a/net/mpls/mpls_gso.c +++ b/net/mpls/mpls_gso.c @@ -27,6 +27,9 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb, __be16 mpls_protocol; unsigned int mpls_hlen; + if (!skb_inner_network_header_was_set(skb)) + goto out; + skb_reset_network_header(skb); mpls_hlen = skb_inner_network_header(skb) - skb_network_header(skb); if (unlikely(!mpls_hlen || mpls_hlen % MPLS_HLEN)) From 3e596599372e7823d08c658fde85bfc8bae9ba83 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 21 Feb 2024 17:46:21 +0000 Subject: [PATCH 1501/2255] ps3/gelic: minor Kernel Doc corrections * Update the Kernel Doc for gelic_descr_set_tx_cmdstat() and gelic_net_setup_netdev() so that documented name and the actual name of the function match. * Move define of GELIC_ALIGN() so that it is no longer between gelic_alloc_card_net() and it's Kernel Doc. * Document netdev parameter of gelic_alloc_card_net() in a way consistent to the documentation of other netdev parameters in this file. Addresses the following warnings flagged by ./scripts/kernel-doc -none: .../ps3_gelic_net.c:711: warning: expecting prototype for gelic_net_set_txdescr_cmdstat(). Prototype was for gelic_descr_set_tx_cmdstat() instead .../ps3_gelic_net.c:1474: warning: expecting prototype for gelic_ether_setup_netdev(). Prototype was for gelic_net_setup_netdev() instead .../ps3_gelic_net.c:1528: warning: expecting prototype for gelic_alloc_card_net(). Prototype was for GELIC_ALIGN() instead .../ps3_gelic_net.c:1531: warning: Function parameter or struct member 'netdev' not described in 'gelic_alloc_card_net' Signed-off-by: Simon Horman Acked-by: Geoff Levand Link: https://lore.kernel.org/r/20240221-ps3-gelic-kdoc-v1-1-7629216d1340@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/toshiba/ps3_gelic_net.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c index d5b75af163d3..12b96ca66877 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c @@ -698,7 +698,7 @@ gelic_card_get_next_tx_descr(struct gelic_card *card) } /** - * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field + * gelic_descr_set_tx_cmdstat - sets the tx descriptor command field * @descr: descriptor structure to fill out * @skb: packet to consider * @@ -1461,7 +1461,7 @@ static void gelic_ether_setup_netdev_ops(struct net_device *netdev, } /** - * gelic_ether_setup_netdev - initialization of net_device + * gelic_net_setup_netdev - initialization of net_device * @netdev: net_device structure * @card: card structure * @@ -1518,14 +1518,16 @@ int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) return 0; } +#define GELIC_ALIGN (32) + /** * gelic_alloc_card_net - allocates net_device and card structure + * @netdev: interface device structure * * returns the card structure or NULL in case of errors * * the card and net_device structures are linked to each other */ -#define GELIC_ALIGN (32) static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev) { struct gelic_card *card; From 23fe265fbfbc0ae43fc862edb8e29ca16e5fa4d7 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 22 Feb 2024 09:00:40 +0000 Subject: [PATCH 1502/2255] rocker: Don't bother filling in ethtool driver version The version is same as the default, so don't bother filling it in. Signed-off-by: John Garry Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240222090042.12609-2-john.g.garry@oracle.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/rocker/rocker_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 9e59669a93dd..755db89db909 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "rocker_hw.h" #include "rocker.h" @@ -2227,7 +2226,6 @@ static void rocker_port_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { strscpy(drvinfo->driver, rocker_driver_name, sizeof(drvinfo->driver)); - strscpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version)); } static struct rocker_port_stats { From 0a4e1b453a8aee4a0942b6a0b55ffe0c87956cba Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 22 Feb 2024 09:00:41 +0000 Subject: [PATCH 1503/2255] net: team: Don't bother filling in ethtool driver version The version is same as the default, so don't bother filling it in. Signed-off-by: John Garry Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240222090042.12609-3-john.g.garry@oracle.com Signed-off-by: Jakub Kicinski --- drivers/net/team/team.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index f575f225d417..0a44bbdcfb7b 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #define DRV_NAME "team" @@ -2074,7 +2073,6 @@ static void team_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); - strscpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version)); } static int team_ethtool_get_link_ksettings(struct net_device *dev, From ac95b1fca034d50d42a058a9476e0fe555653d0d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 22 Feb 2024 14:43:49 +0100 Subject: [PATCH 1504/2255] tools: ynl: allow user to specify flag attr with bool values The flag attr presence in Netlink message indicates value "true", if it is missing in the message it means "false". Allow user to specify attrname with value "true"/"false" in json for flag attrs, treat "false" value properly. Signed-off-by: Jiri Pirko Reviewed-by: Donald Hunter Link: https://lore.kernel.org/r/20240222134351.224704-2-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index f45ee5f29bed..1c5c7662dc9a 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -459,6 +459,9 @@ class YnlFamily(SpecFamily): attr_payload += self._add_attr(attr['nested-attributes'], subname, subvalue, sub_attrs) elif attr["type"] == 'flag': + if not value: + # If value is absent or false then skip attribute creation. + return b'' attr_payload = b'' elif attr["type"] == 'string': attr_payload = str(value).encode('ascii') + b'\x00' From ffe10a4546feaae085a269f6e99680b9eda7d5a6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 22 Feb 2024 14:43:50 +0100 Subject: [PATCH 1505/2255] tools: ynl: process all scalar types encoding in single elif statement As a preparation to handle enums for scalar values, unify the processing of all scalar types in a single elif statement. Signed-off-by: Jiri Pirko Reviewed-by: Donald Hunter Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/20240222134351.224704-3-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 1c5c7662dc9a..e459a130170b 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -474,14 +474,14 @@ class YnlFamily(SpecFamily): attr_payload = self._encode_struct(attr.struct_name, value) else: raise Exception(f'Unknown type for binary attribute, value: {value}') - elif attr.is_auto_scalar: + elif attr['type'] in NlAttr.type_formats or attr.is_auto_scalar: scalar = int(value) - real_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64') - format = NlAttr.get_format(real_type, attr.byte_order) - attr_payload = format.pack(int(value)) - elif attr['type'] in NlAttr.type_formats: - format = NlAttr.get_format(attr['type'], attr.byte_order) - attr_payload = format.pack(int(value)) + if attr.is_auto_scalar: + attr_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64') + else: + attr_type = attr["type"] + format = NlAttr.get_format(attr_type, attr.byte_order) + attr_payload = format.pack(scalar) elif attr['type'] in "bitfield32": attr_payload = struct.pack("II", int(value["value"]), int(value["selector"])) elif attr['type'] == 'sub-message': From e8a6c515ff5f52e1ee24397116a05cd4fc1bae99 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 22 Feb 2024 14:43:51 +0100 Subject: [PATCH 1506/2255] tools: ynl: allow user to pass enum string instead of scalar value During decoding of messages coming from kernel, attribute values are converted to enum names in case the attribute type is enum of bitfield32. However, when user constructs json message, he has to pass plain scalar values. See "state" "selector" and "value" attributes in following examples: $ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml --do pin-set --json '{"id": 0, "parent-device": {"parent-id": 0, "state": 1}}' $ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/devlink.yaml --do port-set --json '{"bus-name": "pci", "dev-name": "0000:08:00.1", "port-index": 98304, "port-function": {"caps": {"selector": 1, "value": 1 }}}' Allow user to pass strings containing enum names, convert them to scalar values to be encoded into Netlink message: $ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml --do pin-set --json '{"id": 0, "parent-device": {"parent-id": 0, "state": "connected"}}' $ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/devlink.yaml --do port-set --json '{"bus-name": "pci", "dev-name": "0000:08:00.1", "port-index": 98304, "port-function": {"caps": {"selector": ["roce-bit"], "value": ["roce-bit"] }}}' Signed-off-by: Jiri Pirko Reviewed-by: Donald Hunter Link: https://lore.kernel.org/r/20240222134351.224704-4-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index e459a130170b..ac55aa5a3083 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -438,6 +438,26 @@ class YnlFamily(SpecFamily): self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP, mcast_id) + def _encode_enum(self, attr_spec, value): + enum = self.consts[attr_spec['enum']] + if enum.type == 'flags' or attr_spec.get('enum-as-flags', False): + scalar = 0 + if isinstance(value, str): + value = [value] + for single_value in value: + scalar += enum.entries[single_value].user_value(as_flags = True) + return scalar + else: + return enum.entries[value].user_value() + + def _get_scalar(self, attr_spec, value): + try: + return int(value) + except (ValueError, TypeError) as e: + if 'enum' not in attr_spec: + raise e + return self._encode_enum(attr_spec, value); + def _add_attr(self, space, name, value, search_attrs): try: attr = self.attr_sets[space][name] @@ -475,7 +495,7 @@ class YnlFamily(SpecFamily): else: raise Exception(f'Unknown type for binary attribute, value: {value}') elif attr['type'] in NlAttr.type_formats or attr.is_auto_scalar: - scalar = int(value) + scalar = self._get_scalar(attr, value) if attr.is_auto_scalar: attr_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64') else: @@ -483,7 +503,9 @@ class YnlFamily(SpecFamily): format = NlAttr.get_format(attr_type, attr.byte_order) attr_payload = format.pack(scalar) elif attr['type'] in "bitfield32": - attr_payload = struct.pack("II", int(value["value"]), int(value["selector"])) + scalar_value = self._get_scalar(attr, value["value"]) + scalar_selector = self._get_scalar(attr, value["selector"]) + attr_payload = struct.pack("II", scalar_value, scalar_selector) elif attr['type'] == 'sub-message': msg_format = self._resolve_selector(attr, search_attrs) attr_payload = b'' From 5fd5403964ecf047b03a9608a339bdc26a109f33 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 22 Feb 2024 14:28:19 -0800 Subject: [PATCH 1507/2255] genetlink: make info in GENL_REQ_ATTR_CHECK() const Make the local variable in GENL_REQ_ATTR_CHECK() const. genl_info_dump() returns a const pointer, so the macro is currently hard to use in genl dumps. Link: https://lore.kernel.org/r/20240222222819.156320-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- include/net/genetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index ecadba836ae5..9ece6e5a3ea8 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -153,7 +153,7 @@ static inline void *genl_info_userhdr(const struct genl_info *info) /* Report that a root attribute is missing */ #define GENL_REQ_ATTR_CHECK(info, attr) ({ \ - struct genl_info *__info = (info); \ + const struct genl_info *__info = (info); \ \ NL_REQ_ATTR_CHECK(__info->extack, NULL, __info->attrs, (attr)); \ }) From d662c5b3ce6dbed9d0991bc83001bbcc4a9bc2f8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 22 Feb 2024 15:48:31 -0800 Subject: [PATCH 1508/2255] tools: ynl: fix header guards devlink and ethtool have a trailing _ in the header guard. I must have copy/pasted it into new guards, assuming it's a headers_install artifact. This fixes build if system headers are old. Fixes: 8f109e91b852 ("tools: ynl: include dpll and mptcp_pm in C codegen") Acked-by: Nicolas Dichtel Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240222234831.179181-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/Makefile.deps | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps index e6154a1255f8..7dcec16da509 100644 --- a/tools/net/ynl/Makefile.deps +++ b/tools/net/ynl/Makefile.deps @@ -15,9 +15,9 @@ UAPI_PATH:=../../../../include/uapi/ get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2) CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h) -CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H_,dpll.h) +CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H,dpll.h) CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h) -CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H_,mptcp_pm.h) +CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H,mptcp_pm.h) CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h) CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_NETLINK_H,nfsd_netlink.h) From a7f08029e2e84ecafbfff50fcff976fafee72799 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 22 Feb 2024 08:51:13 +0100 Subject: [PATCH 1509/2255] net: dsa: microchip: Add support for bridge port isolation Implement bridge port isolation for KSZ switches. Enabling the isolation of switch ports from each other while maintaining connectivity with the CPU and other forwarding ports. For instance, to isolate swp1 and swp2 from each other, use the following commands: - bridge link set dev swp1 isolated on - bridge link set dev swp2 isolated on Signed-off-by: Oleksij Rempel Acked-by: Arun Ramadoss Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 55 +++++++++++++++++++++++--- drivers/net/dsa/microchip/ksz_common.h | 1 + 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 9ff5132f3ac6..f799be868274 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1897,6 +1897,29 @@ static void ksz_get_strings(struct dsa_switch *ds, int port, } } +/** + * ksz_update_port_member - Adjust port forwarding rules based on STP state and + * isolation settings. + * @dev: A pointer to the struct ksz_device representing the device. + * @port: The port number to adjust. + * + * This function dynamically adjusts the port membership configuration for a + * specified port and other device ports, based on Spanning Tree Protocol (STP) + * states and port isolation settings. Each port, including the CPU port, has a + * membership register, represented as a bitfield, where each bit corresponds + * to a port number. A set bit indicates permission to forward frames to that + * port. This function iterates over all ports, updating the membership register + * to reflect current forwarding permissions: + * + * 1. Forwards frames only to ports that are part of the same bridge group and + * in the BR_STATE_FORWARDING state. + * 2. Takes into account the isolation status of ports; ports in the + * BR_STATE_FORWARDING state with BR_ISOLATED configuration will not forward + * frames to each other, even if they are in the same bridge group. + * 3. Ensures that the CPU port is included in the membership based on its + * upstream port configuration, allowing for management and control traffic + * to flow as required. + */ static void ksz_update_port_member(struct ksz_device *dev, int port) { struct ksz_port *p = &dev->ports[port]; @@ -1925,7 +1948,14 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) if (other_p->stp_state != BR_STATE_FORWARDING) continue; - if (p->stp_state == BR_STATE_FORWARDING) { + /* At this point we know that "port" and "other" port [i] are in + * the same bridge group and that "other" port [i] is in + * forwarding stp state. If "port" is also in forwarding stp + * state, we can allow forwarding from port [port] to port [i]. + * Except if both ports are isolated. + */ + if (p->stp_state == BR_STATE_FORWARDING && + !(p->isolated && other_p->isolated)) { val |= BIT(port); port_member |= BIT(i); } @@ -1944,8 +1974,19 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) third_p = &dev->ports[j]; if (third_p->stp_state != BR_STATE_FORWARDING) continue; + third_dp = dsa_to_port(ds, j); - if (dsa_port_bridge_same(other_dp, third_dp)) + + /* Now we updating relation of the "other" port [i] to + * the "third" port [j]. We already know that "other" + * port [i] is in forwarding stp state and that "third" + * port [j] is in forwarding stp state too. + * We need to check if "other" port [i] and "third" port + * [j] are in the same bridge group and not isolated + * before allowing forwarding from port [i] to port [j]. + */ + if (dsa_port_bridge_same(other_dp, third_dp) && + !(other_p->isolated && third_p->isolated)) val |= BIT(j); } @@ -2698,7 +2739,7 @@ static int ksz_port_pre_bridge_flags(struct dsa_switch *ds, int port, struct switchdev_brport_flags flags, struct netlink_ext_ack *extack) { - if (flags.mask & ~BR_LEARNING) + if (flags.mask & ~(BR_LEARNING | BR_ISOLATED)) return -EINVAL; return 0; @@ -2711,8 +2752,12 @@ static int ksz_port_bridge_flags(struct dsa_switch *ds, int port, struct ksz_device *dev = ds->priv; struct ksz_port *p = &dev->ports[port]; - if (flags.mask & BR_LEARNING) { - p->learning = !!(flags.val & BR_LEARNING); + if (flags.mask & (BR_LEARNING | BR_ISOLATED)) { + if (flags.mask & BR_LEARNING) + p->learning = !!(flags.val & BR_LEARNING); + + if (flags.mask & BR_ISOLATED) + p->isolated = !!(flags.val & BR_ISOLATED); /* Make the change take effect immediately */ ksz_port_stp_state_set(ds, port, p->stp_state); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 060c5de9aa05..40c11b0d6b62 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -110,6 +110,7 @@ struct ksz_switch_macaddr { struct ksz_port { bool remove_tag; /* Remove Tag flag set, for ksz8795 only */ bool learning; + bool isolated; int stp_state; struct phy_device phydev; From 95f4fa1f459a69827d752bd55205af7c55b76e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Dautheribes?= Date: Thu, 22 Feb 2024 11:31:15 +0100 Subject: [PATCH 1510/2255] dt-bindings: net: dp83822: support configuring RMII master/slave mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add property ti,rmii-mode to support selecting the RMII operation mode between: - master mode (PHY operates from a 25MHz clock reference) - slave mode (PHY operates from a 50MHz clock reference) If not set, the operation mode is configured by hardware straps. Signed-off-by: Jérémie Dautheribes Acked-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- .../devicetree/bindings/net/ti,dp83822.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/net/ti,dp83822.yaml b/Documentation/devicetree/bindings/net/ti,dp83822.yaml index 8f4350be689c..8f23254c0458 100644 --- a/Documentation/devicetree/bindings/net/ti,dp83822.yaml +++ b/Documentation/devicetree/bindings/net/ti,dp83822.yaml @@ -80,6 +80,22 @@ properties: 10625, 11250, 11875, 12500, 13125, 13750, 14375, 15000] default: 10000 + ti,rmii-mode: + description: | + If present, select the RMII operation mode. Two modes are + available: + - RMII master, where the PHY operates from a 25MHz clock reference, + provided by a crystal or a CMOS-level oscillator + - RMII slave, where the PHY operates from a 50MHz clock reference, + provided by a CMOS-level oscillator + The RMII operation mode can also be configured by its straps. + If the strap pin is not set correctly or not set at all, then this can be + used to configure it. + $ref: /schemas/types.yaml#/definitions/string + enum: + - master + - slave + required: - reg From d2ed0774b6334ce3986c5efb17ab9c4095b8d969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Dautheribes?= Date: Thu, 22 Feb 2024 11:31:16 +0100 Subject: [PATCH 1511/2255] net: phy: dp83826: Add support for phy-mode configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TI DP83826 PHY can operate in either MII mode or RMII mode. By default, it is configured by straps. It can also be configured by writing to the bit 5 of register 0x17 - RMII and Status Register (RCSR). When phydev->interface is rmii, rmii mode must be enabled, otherwise mii mode must be set. This prevents misconfiguration of hw straps. Signed-off-by: Jérémie Dautheribes Reviewed-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/phy/dp83822.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index 30f2616ab1c2..2d8275e59dcc 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -100,6 +100,7 @@ #define DP83822_WOL_CLR_INDICATION BIT(11) /* RCSR bits */ +#define DP83822_RMII_MODE_EN BIT(5) #define DP83822_RGMII_MODE_EN BIT(9) #define DP83822_RX_CLK_SHIFT BIT(12) #define DP83822_TX_CLK_SHIFT BIT(11) @@ -500,6 +501,16 @@ static int dp83826_config_init(struct phy_device *phydev) u16 val, mask; int ret; + if (phydev->interface == PHY_INTERFACE_MODE_RMII) + ret = phy_set_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR, + DP83822_RMII_MODE_EN); + else + ret = phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR, + DP83822_RMII_MODE_EN); + + if (ret) + return ret; + if (dp83822->cfg_dac_minus != DP83826_CFG_DAC_MINUS_DEFAULT) { val = FIELD_PREP(DP83826_VOD_CFG1_MINUS_MDI_MASK, dp83822->cfg_dac_minus) | FIELD_PREP(DP83826_VOD_CFG1_MINUS_MDIX_MASK, From 2844a0d7cffe0567d1d3d18be227542bd1f15d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Dautheribes?= Date: Thu, 22 Feb 2024 11:31:17 +0100 Subject: [PATCH 1512/2255] net: phy: dp83826: support configuring RMII master/slave operation mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TI DP83826 PHY can operate between two RMII modes: - master mode (PHY operates from a 25MHz clock reference) - slave mode (PHY operates from a 50MHz clock reference) By default, the operation mode is configured by hardware straps. Add support to configure the operation mode from within the driver. Signed-off-by: Jérémie Dautheribes Signed-off-by: David S. Miller --- drivers/net/phy/dp83822.c | 43 ++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index 2d8275e59dcc..edc39ae4c241 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -101,6 +101,7 @@ /* RCSR bits */ #define DP83822_RMII_MODE_EN BIT(5) +#define DP83822_RMII_MODE_SEL BIT(7) #define DP83822_RGMII_MODE_EN BIT(9) #define DP83822_RX_CLK_SHIFT BIT(12) #define DP83822_TX_CLK_SHIFT BIT(11) @@ -495,21 +496,53 @@ static int dp83822_config_init(struct phy_device *phydev) return dp8382x_disable_wol(phydev); } +static int dp83826_config_rmii_mode(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + const char *of_val; + int ret; + + if (!device_property_read_string(dev, "ti,rmii-mode", &of_val)) { + if (strcmp(of_val, "master") == 0) { + ret = phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR, + DP83822_RMII_MODE_SEL); + } else if (strcmp(of_val, "slave") == 0) { + ret = phy_set_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR, + DP83822_RMII_MODE_SEL); + } else { + phydev_err(phydev, "Invalid value for ti,rmii-mode property (%s)\n", + of_val); + ret = -EINVAL; + } + + if (ret) + return ret; + } + + return 0; +} + static int dp83826_config_init(struct phy_device *phydev) { struct dp83822_private *dp83822 = phydev->priv; u16 val, mask; int ret; - if (phydev->interface == PHY_INTERFACE_MODE_RMII) + if (phydev->interface == PHY_INTERFACE_MODE_RMII) { ret = phy_set_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR, DP83822_RMII_MODE_EN); - else + if (ret) + return ret; + + ret = dp83826_config_rmii_mode(phydev); + if (ret) + return ret; + } else { ret = phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR, DP83822_RMII_MODE_EN); - - if (ret) - return ret; + if (ret) + return ret; + } if (dp83822->cfg_dac_minus != DP83826_CFG_DAC_MINUS_DEFAULT) { val = FIELD_PREP(DP83826_VOD_CFG1_MINUS_MDI_MASK, dp83822->cfg_dac_minus) | From e353ea9ce471331c13edffd5977eadd602d1bb80 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:08 +0000 Subject: [PATCH 1513/2255] rtnetlink: prepare nla_put_iflink() to run under RCU We want to be able to run rtnl_fill_ifinfo() under RCU protection instead of RTNL in the future. This patch prepares dev_get_iflink() and nla_put_iflink() to run either with RTNL or RCU held. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 4 ++-- drivers/net/can/vxcan.c | 2 +- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 2 +- drivers/net/ipvlan/ipvlan_main.c | 2 +- drivers/net/macsec.c | 2 +- drivers/net/macvlan.c | 2 +- drivers/net/netkit.c | 2 +- drivers/net/veth.c | 2 +- drivers/net/wireless/virtual/virt_wifi.c | 2 +- net/8021q/vlan_dev.c | 4 ++-- net/core/dev.c | 2 +- net/core/rtnetlink.c | 6 +++--- net/dsa/user.c | 2 +- net/ieee802154/6lowpan/core.c | 2 +- net/ipv6/ip6_tunnel.c | 2 +- net/xfrm/xfrm_interface_core.c | 2 +- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 7a5be705d718..6f2a688fccbf 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1272,10 +1272,10 @@ static int ipoib_get_iflink(const struct net_device *dev) /* parent interface */ if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) - return dev->ifindex; + return READ_ONCE(dev->ifindex); /* child/vlan interface */ - return priv->parent->ifindex; + return READ_ONCE(priv->parent->ifindex); } static u32 ipoib_addr_hash(struct ipoib_neigh_hash *htbl, u8 *daddr) diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 98c669ad5141..f7fabba707ea 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -119,7 +119,7 @@ static int vxcan_get_iflink(const struct net_device *dev) rcu_read_lock(); peer = rcu_dereference(priv->peer); - iflink = peer ? peer->ifindex : 0; + iflink = peer ? READ_ONCE(peer->ifindex) : 0; rcu_read_unlock(); return iflink; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 046b5f7d8e7c..9d2a9562c96f 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -98,7 +98,7 @@ static int rmnet_vnd_get_iflink(const struct net_device *dev) { struct rmnet_priv *priv = netdev_priv(dev); - return priv->real_dev->ifindex; + return READ_ONCE(priv->real_dev->ifindex); } static int rmnet_vnd_init(struct net_device *dev) diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index df7c43a109e1..5920f7e63352 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -349,7 +349,7 @@ static int ipvlan_get_iflink(const struct net_device *dev) { struct ipvl_dev *ipvlan = netdev_priv(dev); - return ipvlan->phy_dev->ifindex; + return READ_ONCE(ipvlan->phy_dev->ifindex); } static const struct net_device_ops ipvlan_netdev_ops = { diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 7f5426285c61..4b5513c9c2be 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3753,7 +3753,7 @@ static void macsec_get_stats64(struct net_device *dev, static int macsec_get_iflink(const struct net_device *dev) { - return macsec_priv(dev)->real_dev->ifindex; + return READ_ONCE(macsec_priv(dev)->real_dev->ifindex); } static const struct net_device_ops macsec_netdev_ops = { diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index a3cc665757e8..0cec2783a3e7 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1158,7 +1158,7 @@ static int macvlan_dev_get_iflink(const struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); - return vlan->lowerdev->ifindex; + return READ_ONCE(vlan->lowerdev->ifindex); } static const struct ethtool_ops macvlan_ethtool_ops = { diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c index 39171380ccf2..a4d2e76a8d58 100644 --- a/drivers/net/netkit.c +++ b/drivers/net/netkit.c @@ -145,7 +145,7 @@ static int netkit_get_iflink(const struct net_device *dev) rcu_read_lock(); peer = rcu_dereference(nk->peer); if (peer) - iflink = peer->ifindex; + iflink = READ_ONCE(peer->ifindex); rcu_read_unlock(); return iflink; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 500b9dfccd08..dd5aa8ab65a8 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1461,7 +1461,7 @@ static int veth_get_iflink(const struct net_device *dev) rcu_read_lock(); peer = rcu_dereference(priv->peer); - iflink = peer ? peer->ifindex : 0; + iflink = peer ? READ_ONCE(peer->ifindex) : 0; rcu_read_unlock(); return iflink; diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c index ba14d83353a4..6a84ec58d618 100644 --- a/drivers/net/wireless/virtual/virt_wifi.c +++ b/drivers/net/wireless/virtual/virt_wifi.c @@ -453,7 +453,7 @@ static int virt_wifi_net_device_get_iflink(const struct net_device *dev) { struct virt_wifi_netdev_priv *priv = netdev_priv(dev); - return priv->lowerdev->ifindex; + return READ_ONCE(priv->lowerdev->ifindex); } static const struct net_device_ops virt_wifi_ops = { diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index df5552518251..39876eff51d2 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -762,9 +762,9 @@ static void vlan_dev_netpoll_cleanup(struct net_device *dev) static int vlan_dev_get_iflink(const struct net_device *dev) { - struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; + const struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; - return real_dev->ifindex; + return READ_ONCE(real_dev->ifindex); } static int vlan_dev_fill_forward_path(struct net_device_path_ctx *ctx, diff --git a/net/core/dev.c b/net/core/dev.c index c588808be77f..0628d8ff1ed9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -641,7 +641,7 @@ int dev_get_iflink(const struct net_device *dev) if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink) return dev->netdev_ops->ndo_get_iflink(dev); - return dev->ifindex; + return READ_ONCE(dev->ifindex); } EXPORT_SYMBOL(dev_get_iflink); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c54dbe05c4c5..060543fe7919 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1611,10 +1611,10 @@ static int put_master_ifindex(struct sk_buff *skb, struct net_device *dev) static int nla_put_iflink(struct sk_buff *skb, const struct net_device *dev, bool force) { - int ifindex = dev_get_iflink(dev); + int iflink = dev_get_iflink(dev); - if (force || dev->ifindex != ifindex) - return nla_put_u32(skb, IFLA_LINK, ifindex); + if (force || READ_ONCE(dev->ifindex) != iflink) + return nla_put_u32(skb, IFLA_LINK, iflink); return 0; } diff --git a/net/dsa/user.c b/net/dsa/user.c index 4d53c76a9840..9c42a6edcdc8 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -352,7 +352,7 @@ void dsa_user_mii_bus_init(struct dsa_switch *ds) /* user device handling ****************************************************/ static int dsa_user_get_iflink(const struct net_device *dev) { - return dsa_user_to_conduit(dev)->ifindex; + return READ_ONCE(dsa_user_to_conduit(dev)->ifindex); } static int dsa_user_open(struct net_device *dev) diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index e643f52663f9..77b4e92027c5 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -93,7 +93,7 @@ static int lowpan_neigh_construct(struct net_device *dev, struct neighbour *n) static int lowpan_get_iflink(const struct net_device *dev) { - return lowpan_802154_dev(dev)->wdev->ifindex; + return READ_ONCE(lowpan_802154_dev(dev)->wdev->ifindex); } static const struct net_device_ops lowpan_netdev_ops = { diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 44406c28445d..5fd07581efaf 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1756,7 +1756,7 @@ int ip6_tnl_get_iflink(const struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); - return t->parms.link; + return READ_ONCE(t->parms.link); } EXPORT_SYMBOL(ip6_tnl_get_iflink); diff --git a/net/xfrm/xfrm_interface_core.c b/net/xfrm/xfrm_interface_core.c index dafefef3cf51..717855b9acf1 100644 --- a/net/xfrm/xfrm_interface_core.c +++ b/net/xfrm/xfrm_interface_core.c @@ -727,7 +727,7 @@ static int xfrmi_get_iflink(const struct net_device *dev) { struct xfrm_if *xi = netdev_priv(dev); - return xi->p.link; + return READ_ONCE(xi->p.link); } static const struct net_device_ops xfrmi_netdev_ops = { From 4ad268136421dc9813280c55940eca00796420e5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:09 +0000 Subject: [PATCH 1514/2255] ipv6: prepare inet6_fill_ifla6_attrs() for RCU We want to no longer hold RTNL while calling inet6_fill_ifla6_attrs() in the future. Add needed READ_ONCE()/WRITE_ONCE() annotations. Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 163 ++++++++++++++++++++++++-------------------- net/ipv6/ndisc.c | 2 +- 2 files changed, 90 insertions(+), 75 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c669ea266ab7..a56dad307fe3 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3492,7 +3492,8 @@ static void addrconf_dev_config(struct net_device *dev) /* this device type has no EUI support */ if (dev->type == ARPHRD_NONE && idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) - idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_RANDOM; + WRITE_ONCE(idev->cnf.addr_gen_mode, + IN6_ADDR_GEN_MODE_RANDOM); addrconf_addr_gen(idev, false); } @@ -3764,7 +3765,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, rt6_mtu_change(dev, dev->mtu); idev->cnf.mtu6 = dev->mtu; } - idev->tstamp = jiffies; + WRITE_ONCE(idev->tstamp, jiffies); inet6_ifinfo_notify(RTM_NEWLINK, idev); /* @@ -4006,7 +4007,7 @@ restart: ipv6_mc_down(idev); } - idev->tstamp = jiffies; + WRITE_ONCE(idev->tstamp, jiffies); idev->ra_mtu = 0; /* Last: Shot the device (if unregistered) */ @@ -5634,87 +5635,97 @@ errout: rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); } -static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, - __s32 *array, int bytes) +static void ipv6_store_devconf(const struct ipv6_devconf *cnf, + __s32 *array, int bytes) { BUG_ON(bytes < (DEVCONF_MAX * 4)); memset(array, 0, bytes); - array[DEVCONF_FORWARDING] = cnf->forwarding; - array[DEVCONF_HOPLIMIT] = cnf->hop_limit; - array[DEVCONF_MTU6] = cnf->mtu6; - array[DEVCONF_ACCEPT_RA] = cnf->accept_ra; - array[DEVCONF_ACCEPT_REDIRECTS] = cnf->accept_redirects; - array[DEVCONF_AUTOCONF] = cnf->autoconf; - array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; - array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; + array[DEVCONF_FORWARDING] = READ_ONCE(cnf->forwarding); + array[DEVCONF_HOPLIMIT] = READ_ONCE(cnf->hop_limit); + array[DEVCONF_MTU6] = READ_ONCE(cnf->mtu6); + array[DEVCONF_ACCEPT_RA] = READ_ONCE(cnf->accept_ra); + array[DEVCONF_ACCEPT_REDIRECTS] = READ_ONCE(cnf->accept_redirects); + array[DEVCONF_AUTOCONF] = READ_ONCE(cnf->autoconf); + array[DEVCONF_DAD_TRANSMITS] = READ_ONCE(cnf->dad_transmits); + array[DEVCONF_RTR_SOLICITS] = READ_ONCE(cnf->rtr_solicits); array[DEVCONF_RTR_SOLICIT_INTERVAL] = - jiffies_to_msecs(cnf->rtr_solicit_interval); + jiffies_to_msecs(READ_ONCE(cnf->rtr_solicit_interval)); array[DEVCONF_RTR_SOLICIT_MAX_INTERVAL] = - jiffies_to_msecs(cnf->rtr_solicit_max_interval); + jiffies_to_msecs(READ_ONCE(cnf->rtr_solicit_max_interval)); array[DEVCONF_RTR_SOLICIT_DELAY] = - jiffies_to_msecs(cnf->rtr_solicit_delay); - array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; + jiffies_to_msecs(READ_ONCE(cnf->rtr_solicit_delay)); + array[DEVCONF_FORCE_MLD_VERSION] = READ_ONCE(cnf->force_mld_version); array[DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL] = - jiffies_to_msecs(cnf->mldv1_unsolicited_report_interval); + jiffies_to_msecs(READ_ONCE(cnf->mldv1_unsolicited_report_interval)); array[DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL] = - jiffies_to_msecs(cnf->mldv2_unsolicited_report_interval); - array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; - array[DEVCONF_TEMP_VALID_LFT] = cnf->temp_valid_lft; - array[DEVCONF_TEMP_PREFERED_LFT] = cnf->temp_prefered_lft; - array[DEVCONF_REGEN_MAX_RETRY] = cnf->regen_max_retry; - array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; - array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; - array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr; - array[DEVCONF_RA_DEFRTR_METRIC] = cnf->ra_defrtr_metric; - array[DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT] = cnf->accept_ra_min_hop_limit; - array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; + jiffies_to_msecs(READ_ONCE(cnf->mldv2_unsolicited_report_interval)); + array[DEVCONF_USE_TEMPADDR] = READ_ONCE(cnf->use_tempaddr); + array[DEVCONF_TEMP_VALID_LFT] = READ_ONCE(cnf->temp_valid_lft); + array[DEVCONF_TEMP_PREFERED_LFT] = READ_ONCE(cnf->temp_prefered_lft); + array[DEVCONF_REGEN_MAX_RETRY] = READ_ONCE(cnf->regen_max_retry); + array[DEVCONF_MAX_DESYNC_FACTOR] = READ_ONCE(cnf->max_desync_factor); + array[DEVCONF_MAX_ADDRESSES] = READ_ONCE(cnf->max_addresses); + array[DEVCONF_ACCEPT_RA_DEFRTR] = READ_ONCE(cnf->accept_ra_defrtr); + array[DEVCONF_RA_DEFRTR_METRIC] = READ_ONCE(cnf->ra_defrtr_metric); + array[DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT] = + READ_ONCE(cnf->accept_ra_min_hop_limit); + array[DEVCONF_ACCEPT_RA_PINFO] = READ_ONCE(cnf->accept_ra_pinfo); #ifdef CONFIG_IPV6_ROUTER_PREF - array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; + array[DEVCONF_ACCEPT_RA_RTR_PREF] = READ_ONCE(cnf->accept_ra_rtr_pref); array[DEVCONF_RTR_PROBE_INTERVAL] = - jiffies_to_msecs(cnf->rtr_probe_interval); + jiffies_to_msecs(READ_ONCE(cnf->rtr_probe_interval)); #ifdef CONFIG_IPV6_ROUTE_INFO - array[DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN] = cnf->accept_ra_rt_info_min_plen; - array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; + array[DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN] = + READ_ONCE(cnf->accept_ra_rt_info_min_plen); + array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = + READ_ONCE(cnf->accept_ra_rt_info_max_plen); #endif #endif - array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; - array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; + array[DEVCONF_PROXY_NDP] = READ_ONCE(cnf->proxy_ndp); + array[DEVCONF_ACCEPT_SOURCE_ROUTE] = + READ_ONCE(cnf->accept_source_route); #ifdef CONFIG_IPV6_OPTIMISTIC_DAD - array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; - array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic; + array[DEVCONF_OPTIMISTIC_DAD] = READ_ONCE(cnf->optimistic_dad); + array[DEVCONF_USE_OPTIMISTIC] = READ_ONCE(cnf->use_optimistic); #endif #ifdef CONFIG_IPV6_MROUTE array[DEVCONF_MC_FORWARDING] = atomic_read(&cnf->mc_forwarding); #endif - array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; - array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; - array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; - array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; - array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; - array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; - array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; - array[DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = cnf->ignore_routes_with_linkdown; + array[DEVCONF_DISABLE_IPV6] = READ_ONCE(cnf->disable_ipv6); + array[DEVCONF_ACCEPT_DAD] = READ_ONCE(cnf->accept_dad); + array[DEVCONF_FORCE_TLLAO] = READ_ONCE(cnf->force_tllao); + array[DEVCONF_NDISC_NOTIFY] = READ_ONCE(cnf->ndisc_notify); + array[DEVCONF_SUPPRESS_FRAG_NDISC] = + READ_ONCE(cnf->suppress_frag_ndisc); + array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = + READ_ONCE(cnf->accept_ra_from_local); + array[DEVCONF_ACCEPT_RA_MTU] = READ_ONCE(cnf->accept_ra_mtu); + array[DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = + READ_ONCE(cnf->ignore_routes_with_linkdown); /* we omit DEVCONF_STABLE_SECRET for now */ - array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only; - array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast; - array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na; - array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down; - array[DEVCONF_SEG6_ENABLED] = cnf->seg6_enabled; + array[DEVCONF_USE_OIF_ADDRS_ONLY] = READ_ONCE(cnf->use_oif_addrs_only); + array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = + READ_ONCE(cnf->drop_unicast_in_l2_multicast); + array[DEVCONF_DROP_UNSOLICITED_NA] = READ_ONCE(cnf->drop_unsolicited_na); + array[DEVCONF_KEEP_ADDR_ON_DOWN] = READ_ONCE(cnf->keep_addr_on_down); + array[DEVCONF_SEG6_ENABLED] = READ_ONCE(cnf->seg6_enabled); #ifdef CONFIG_IPV6_SEG6_HMAC - array[DEVCONF_SEG6_REQUIRE_HMAC] = cnf->seg6_require_hmac; + array[DEVCONF_SEG6_REQUIRE_HMAC] = READ_ONCE(cnf->seg6_require_hmac); #endif - array[DEVCONF_ENHANCED_DAD] = cnf->enhanced_dad; - array[DEVCONF_ADDR_GEN_MODE] = cnf->addr_gen_mode; - array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy; - array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass; - array[DEVCONF_RPL_SEG_ENABLED] = cnf->rpl_seg_enabled; - array[DEVCONF_IOAM6_ENABLED] = cnf->ioam6_enabled; - array[DEVCONF_IOAM6_ID] = cnf->ioam6_id; - array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide; - array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier; - array[DEVCONF_ACCEPT_UNTRACKED_NA] = cnf->accept_untracked_na; - array[DEVCONF_ACCEPT_RA_MIN_LFT] = cnf->accept_ra_min_lft; + array[DEVCONF_ENHANCED_DAD] = READ_ONCE(cnf->enhanced_dad); + array[DEVCONF_ADDR_GEN_MODE] = READ_ONCE(cnf->addr_gen_mode); + array[DEVCONF_DISABLE_POLICY] = READ_ONCE(cnf->disable_policy); + array[DEVCONF_NDISC_TCLASS] = READ_ONCE(cnf->ndisc_tclass); + array[DEVCONF_RPL_SEG_ENABLED] = READ_ONCE(cnf->rpl_seg_enabled); + array[DEVCONF_IOAM6_ENABLED] = READ_ONCE(cnf->ioam6_enabled); + array[DEVCONF_IOAM6_ID] = READ_ONCE(cnf->ioam6_id); + array[DEVCONF_IOAM6_ID_WIDE] = READ_ONCE(cnf->ioam6_id_wide); + array[DEVCONF_NDISC_EVICT_NOCARRIER] = + READ_ONCE(cnf->ndisc_evict_nocarrier); + array[DEVCONF_ACCEPT_UNTRACKED_NA] = + READ_ONCE(cnf->accept_untracked_na); + array[DEVCONF_ACCEPT_RA_MIN_LFT] = READ_ONCE(cnf->accept_ra_min_lft); } static inline size_t inet6_ifla6_size(void) @@ -5794,13 +5805,14 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev, u32 ext_filter_mask) { - struct nlattr *nla; struct ifla_cacheinfo ci; + struct nlattr *nla; + u32 ra_mtu; - if (nla_put_u32(skb, IFLA_INET6_FLAGS, idev->if_flags)) + if (nla_put_u32(skb, IFLA_INET6_FLAGS, READ_ONCE(idev->if_flags))) goto nla_put_failure; ci.max_reasm_len = IPV6_MAXPLEN; - ci.tstamp = cstamp_delta(idev->tstamp); + ci.tstamp = cstamp_delta(READ_ONCE(idev->tstamp)); ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); ci.retrans_time = jiffies_to_msecs(NEIGH_VAR(idev->nd_parms, RETRANS_TIME)); if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci)) @@ -5832,11 +5844,12 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev, memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); read_unlock_bh(&idev->lock); - if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->cnf.addr_gen_mode)) + if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, + READ_ONCE(idev->cnf.addr_gen_mode))) goto nla_put_failure; - if (idev->ra_mtu && - nla_put_u32(skb, IFLA_INET6_RA_MTU, idev->ra_mtu)) + ra_mtu = READ_ONCE(idev->ra_mtu); + if (ra_mtu && nla_put_u32(skb, IFLA_INET6_RA_MTU, ra_mtu)) goto nla_put_failure; return 0; @@ -6037,7 +6050,7 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla, if (tb[IFLA_INET6_ADDR_GEN_MODE]) { u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); - idev->cnf.addr_gen_mode = mode; + WRITE_ONCE(idev->cnf.addr_gen_mode, mode); } return 0; @@ -6516,7 +6529,7 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write, } if (idev->cnf.addr_gen_mode != new_val) { - idev->cnf.addr_gen_mode = new_val; + WRITE_ONCE(idev->cnf.addr_gen_mode, new_val); addrconf_init_auto_addrs(idev->dev); } } else if (&net->ipv6.devconf_all->addr_gen_mode == ctl->data) { @@ -6527,7 +6540,8 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write, idev = __in6_dev_get(dev); if (idev && idev->cnf.addr_gen_mode != new_val) { - idev->cnf.addr_gen_mode = new_val; + WRITE_ONCE(idev->cnf.addr_gen_mode, + new_val); addrconf_init_auto_addrs(idev->dev); } } @@ -6592,14 +6606,15 @@ static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write, struct inet6_dev *idev = __in6_dev_get(dev); if (idev) { - idev->cnf.addr_gen_mode = - IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + WRITE_ONCE(idev->cnf.addr_gen_mode, + IN6_ADDR_GEN_MODE_STABLE_PRIVACY); } } } else { struct inet6_dev *idev = ctl->extra1; - idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + WRITE_ONCE(idev->cnf.addr_gen_mode, + IN6_ADDR_GEN_MODE_STABLE_PRIVACY); } out: diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 73cb31afe935..8523f0595b01 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1975,7 +1975,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void *buffer, if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)) idev->nd_parms->reachable_time = neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)); - idev->tstamp = jiffies; + WRITE_ONCE(idev->tstamp, jiffies); inet6_ifinfo_notify(RTM_NEWLINK, idev); in6_dev_put(idev); } From 8afc7a78d55de726b2747d7775c54def79509ec5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:10 +0000 Subject: [PATCH 1515/2255] ipv6: prepare inet6_fill_ifinfo() for RCU protection We want to use RCU protection instead of RTNL for inet6_fill_ifinfo(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 6 ++++-- net/core/dev.c | 4 ++-- net/ipv6/addrconf.c | 11 +++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f07c8374f29c..09023e44db4e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4354,8 +4354,10 @@ static inline bool netif_testing(const struct net_device *dev) */ static inline bool netif_oper_up(const struct net_device *dev) { - return (dev->operstate == IF_OPER_UP || - dev->operstate == IF_OPER_UNKNOWN /* backward compat */); + unsigned int operstate = READ_ONCE(dev->operstate); + + return operstate == IF_OPER_UP || + operstate == IF_OPER_UNKNOWN /* backward compat */; } /** diff --git a/net/core/dev.c b/net/core/dev.c index 0628d8ff1ed9..275fd5259a4a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8632,12 +8632,12 @@ unsigned int dev_get_flags(const struct net_device *dev) { unsigned int flags; - flags = (dev->flags & ~(IFF_PROMISC | + flags = (READ_ONCE(dev->flags) & ~(IFF_PROMISC | IFF_ALLMULTI | IFF_RUNNING | IFF_LOWER_UP | IFF_DORMANT)) | - (dev->gflags & (IFF_PROMISC | + (READ_ONCE(dev->gflags) & (IFF_PROMISC | IFF_ALLMULTI)); if (netif_running(dev)) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a56dad307fe3..daa81556d118 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -6062,6 +6062,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, struct net_device *dev = idev->dev; struct ifinfomsg *hdr; struct nlmsghdr *nlh; + int ifindex, iflink; void *protoinfo; nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags); @@ -6072,16 +6073,18 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, hdr->ifi_family = AF_INET6; hdr->__ifi_pad = 0; hdr->ifi_type = dev->type; - hdr->ifi_index = dev->ifindex; + ifindex = READ_ONCE(dev->ifindex); + hdr->ifi_index = ifindex; hdr->ifi_flags = dev_get_flags(dev); hdr->ifi_change = 0; + iflink = dev_get_iflink(dev); if (nla_put_string(skb, IFLA_IFNAME, dev->name) || (dev->addr_len && nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || - nla_put_u32(skb, IFLA_MTU, dev->mtu) || - (dev->ifindex != dev_get_iflink(dev) && - nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev))) || + nla_put_u32(skb, IFLA_MTU, READ_ONCE(dev->mtu)) || + (ifindex != iflink && + nla_put_u32(skb, IFLA_LINK, iflink)) || nla_put_u8(skb, IFLA_OPERSTATE, netif_running(dev) ? READ_ONCE(dev->operstate) : IF_OPER_DOWN)) goto nla_put_failure; From ac14ad9755d4f8f286fd2cd710aa5dcf9a3c777a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:11 +0000 Subject: [PATCH 1516/2255] ipv6: use xarray iterator to implement inet6_dump_ifinfo() Prepare inet6_dump_ifinfo() to run with RCU protection instead of RTNL and use for_each_netdev_dump() interface. Also properly return 0 at the end of a dump, avoiding an extra recvmsg() system call and RTNL acquisition. Note that RTNL-less dumps need core changes, coming later in the series. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 46 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index daa81556d118..6556136d2b8d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -6132,50 +6132,42 @@ static int inet6_valid_dump_ifinfo(const struct nlmsghdr *nlh, static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); - int h, s_h; - int idx = 0, s_idx; + struct { + unsigned long ifindex; + } *ctx = (void *)cb->ctx; struct net_device *dev; struct inet6_dev *idev; - struct hlist_head *head; + int err; /* only requests using strict checking can pass data to * influence the dump */ if (cb->strict_check) { - int err = inet6_valid_dump_ifinfo(cb->nlh, cb->extack); + err = inet6_valid_dump_ifinfo(cb->nlh, cb->extack); if (err < 0) return err; } - s_h = cb->args[0]; - s_idx = cb->args[1]; - + err = 0; rcu_read_lock(); - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - idev = __in6_dev_get(dev); - if (!idev) - goto cont; - if (inet6_fill_ifinfo(skb, idev, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWLINK, NLM_F_MULTI) < 0) - goto out; -cont: - idx++; + for_each_netdev_dump(net, dev, ctx->ifindex) { + idev = __in6_dev_get(dev); + if (!idev) + continue; + err = inet6_fill_ifinfo(skb, idev, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + RTM_NEWLINK, NLM_F_MULTI); + if (err < 0) { + if (likely(skb->len)) + err = skb->len; + break; } } -out: rcu_read_unlock(); - cb->args[1] = idx; - cb->args[0] = h; - return skb->len; + return err; } void inet6_ifinfo_notify(int event, struct inet6_dev *idev) From 6647b338fc5c6741736fe51a25fc2c0bec6398b8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:12 +0000 Subject: [PATCH 1517/2255] netlink: fix netlink_diag_dump() return value __netlink_diag_dump() returns 1 if the dump is not complete, zero if no error occurred. If err variable is zero, this means the dump is complete: We should not return skb->len in this case, but 0. This allows NLMSG_DONE to be appended to the skb. User space does not have to call us again only to get NLMSG_DONE. Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- net/netlink/diag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netlink/diag.c b/net/netlink/diag.c index e12c90d5f6ad..61981e01fd6f 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c @@ -207,7 +207,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) err = __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num); } - return err < 0 ? err : skb->len; + return err <= 0 ? err : skb->len; } static int netlink_diag_dump_done(struct netlink_callback *cb) From b5590270068c4324dac4a2b5a4a156e02e21339f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:13 +0000 Subject: [PATCH 1518/2255] netlink: hold nlk->cb_mutex longer in __netlink_dump_start() __netlink_dump_start() releases nlk->cb_mutex right before calling netlink_dump() which grabs it again. This seems dangerous, even if KASAN did not bother yet. Add a @lock_taken parameter to netlink_dump() to let it grab the mutex if called from netlink_recvmsg() only. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 9c962347cf85..94f3860526bf 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -130,7 +130,7 @@ static const char *const nlk_cb_mutex_key_strings[MAX_LINKS + 1] = { "nlk_cb_mutex-MAX_LINKS" }; -static int netlink_dump(struct sock *sk); +static int netlink_dump(struct sock *sk, bool lock_taken); /* nl_table locking explained: * Lookup and traversal are protected with an RCU read-side lock. Insertion @@ -1987,7 +1987,7 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, if (READ_ONCE(nlk->cb_running) && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { - ret = netlink_dump(sk); + ret = netlink_dump(sk, false); if (ret) { WRITE_ONCE(sk->sk_err, -ret); sk_error_report(sk); @@ -2196,7 +2196,7 @@ static int netlink_dump_done(struct netlink_sock *nlk, struct sk_buff *skb, return 0; } -static int netlink_dump(struct sock *sk) +static int netlink_dump(struct sock *sk, bool lock_taken) { struct netlink_sock *nlk = nlk_sk(sk); struct netlink_ext_ack extack = {}; @@ -2208,7 +2208,8 @@ static int netlink_dump(struct sock *sk) int alloc_min_size; int alloc_size; - mutex_lock(nlk->cb_mutex); + if (!lock_taken) + mutex_lock(nlk->cb_mutex); if (!nlk->cb_running) { err = -EINVAL; goto errout_skb; @@ -2365,9 +2366,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, WRITE_ONCE(nlk->cb_running, true); nlk->dump_done_errno = INT_MAX; - mutex_unlock(nlk->cb_mutex); - - ret = netlink_dump(sk); + ret = netlink_dump(sk, true); sock_put(sk); From e39951d965bf58b5aba7f61dc1140dcb8271af22 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:14 +0000 Subject: [PATCH 1519/2255] rtnetlink: change nlk->cb_mutex role In commit af65bdfce98d ("[NETLINK]: Switch cb_lock spinlock to mutex and allow to override it"), Patrick McHardy used a common mutex to protect both nlk->cb and the dump() operations. The override is used for rtnl dumps, registered with rntl_register() and rntl_register_module(). We want to be able to opt-out some dump() operations to not acquire RTNL, so we need to protect nlk->cb with a per socket mutex. This patch renames nlk->cb_def_mutex to nlk->nl_cb_mutex The optional pointer to the mutex used to protect dump() call is stored in nlk->dump_cb_mutex Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 32 ++++++++++++++++++-------------- net/netlink/af_netlink.h | 5 +++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 94f3860526bf..84cad7be6d43 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -636,7 +636,7 @@ static struct proto netlink_proto = { }; static int __netlink_create(struct net *net, struct socket *sock, - struct mutex *cb_mutex, int protocol, + struct mutex *dump_cb_mutex, int protocol, int kern) { struct sock *sk; @@ -651,15 +651,11 @@ static int __netlink_create(struct net *net, struct socket *sock, sock_init_data(sock, sk); nlk = nlk_sk(sk); - if (cb_mutex) { - nlk->cb_mutex = cb_mutex; - } else { - nlk->cb_mutex = &nlk->cb_def_mutex; - mutex_init(nlk->cb_mutex); - lockdep_set_class_and_name(nlk->cb_mutex, + mutex_init(&nlk->nl_cb_mutex); + lockdep_set_class_and_name(&nlk->nl_cb_mutex, nlk_cb_mutex_keys + protocol, nlk_cb_mutex_key_strings[protocol]); - } + nlk->dump_cb_mutex = dump_cb_mutex; init_waitqueue_head(&nlk->wait); sk->sk_destruct = netlink_sock_destruct; @@ -2209,7 +2205,7 @@ static int netlink_dump(struct sock *sk, bool lock_taken) int alloc_size; if (!lock_taken) - mutex_lock(nlk->cb_mutex); + mutex_lock(&nlk->nl_cb_mutex); if (!nlk->cb_running) { err = -EINVAL; goto errout_skb; @@ -2261,14 +2257,22 @@ static int netlink_dump(struct sock *sk, bool lock_taken) netlink_skb_set_owner_r(skb, sk); if (nlk->dump_done_errno > 0) { + struct mutex *extra_mutex = nlk->dump_cb_mutex; + cb->extack = &extack; + + if (extra_mutex) + mutex_lock(extra_mutex); nlk->dump_done_errno = cb->dump(skb, cb); + if (extra_mutex) + mutex_unlock(extra_mutex); + cb->extack = NULL; } if (nlk->dump_done_errno > 0 || skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { - mutex_unlock(nlk->cb_mutex); + mutex_unlock(&nlk->nl_cb_mutex); if (sk_filter(sk, skb)) kfree_skb(skb); @@ -2302,13 +2306,13 @@ static int netlink_dump(struct sock *sk, bool lock_taken) WRITE_ONCE(nlk->cb_running, false); module = cb->module; skb = cb->skb; - mutex_unlock(nlk->cb_mutex); + mutex_unlock(&nlk->nl_cb_mutex); module_put(module); consume_skb(skb); return 0; errout_skb: - mutex_unlock(nlk->cb_mutex); + mutex_unlock(&nlk->nl_cb_mutex); kfree_skb(skb); return err; } @@ -2331,7 +2335,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, } nlk = nlk_sk(sk); - mutex_lock(nlk->cb_mutex); + mutex_lock(&nlk->nl_cb_mutex); /* A dump is in progress... */ if (nlk->cb_running) { ret = -EBUSY; @@ -2382,7 +2386,7 @@ error_put: module_put(control->module); error_unlock: sock_put(sk); - mutex_unlock(nlk->cb_mutex); + mutex_unlock(&nlk->nl_cb_mutex); error_free: kfree_skb(skb); return ret; diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 2145979b9986..9751e29d4bbb 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -39,8 +39,9 @@ struct netlink_sock { bool cb_running; int dump_done_errno; struct netlink_callback cb; - struct mutex *cb_mutex; - struct mutex cb_def_mutex; + struct mutex nl_cb_mutex; + + struct mutex *dump_cb_mutex; void (*netlink_rcv)(struct sk_buff *skb); int (*netlink_bind)(struct net *net, int group); void (*netlink_unbind)(struct net *net, int group); From 386520e0ecc01004d3a29c70c5a77d4bbf8a8420 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:15 +0000 Subject: [PATCH 1520/2255] rtnetlink: add RTNL_FLAG_DUMP_UNLOCKED flag Similarly to RTNL_FLAG_DOIT_UNLOCKED, this new flag allows dump operations registered via rtnl_register() or rtnl_register_module() to opt-out from RTNL protection. Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- include/linux/netlink.h | 2 ++ include/net/rtnetlink.h | 1 + net/core/rtnetlink.c | 2 ++ net/netlink/af_netlink.c | 3 +++ 4 files changed, 8 insertions(+) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 1a4445bf2ab9..5df7340d4dab 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -291,6 +291,7 @@ struct netlink_callback { u16 answer_flags; u32 min_dump_alloc; unsigned int prev_seq, seq; + int flags; bool strict_check; union { u8 ctx[48]; @@ -323,6 +324,7 @@ struct netlink_dump_control { void *data; struct module *module; u32 min_dump_alloc; + int flags; }; int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 6506221c5fe3..3bfb80bad173 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -12,6 +12,7 @@ typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *); enum rtnl_link_flags { RTNL_FLAG_DOIT_UNLOCKED = BIT(0), RTNL_FLAG_BULK_DEL_SUPPORTED = BIT(1), + RTNL_FLAG_DUMP_UNLOCKED = BIT(2), }; enum rtnl_kinds { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 060543fe7919..1b26dfa5668d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -6532,6 +6532,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, } owner = link->owner; dumpit = link->dumpit; + flags = link->flags; if (type == RTM_GETLINK - RTM_BASE) min_dump_alloc = rtnl_calcit(skb, nlh); @@ -6549,6 +6550,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, .dump = dumpit, .min_dump_alloc = min_dump_alloc, .module = owner, + .flags = flags, }; err = netlink_dump_start(rtnl, skb, nlh, &c); /* netlink_dump_start() will keep a reference on diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 84cad7be6d43..be5792b638aa 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2261,6 +2261,8 @@ static int netlink_dump(struct sock *sk, bool lock_taken) cb->extack = &extack; + if (cb->flags & RTNL_FLAG_DUMP_UNLOCKED) + extra_mutex = NULL; if (extra_mutex) mutex_lock(extra_mutex); nlk->dump_done_errno = cb->dump(skb, cb); @@ -2355,6 +2357,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, cb->data = control->data; cb->module = control->module; cb->min_dump_alloc = control->min_dump_alloc; + cb->flags = control->flags; cb->skb = skb; cb->strict_check = nlk_test_bit(STRICT_CHK, NETLINK_CB(skb).sk); From 69fdb7e411b6d01eb08447e672302b69c9e176ad Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:16 +0000 Subject: [PATCH 1521/2255] ipv6: switch inet6_dump_ifinfo() to RCU protection No longer hold RTNL while calling inet6_dump_ifinfo() Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6556136d2b8d..a280614b3765 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -7462,7 +7462,7 @@ int __init addrconf_init(void) rtnl_af_register(&inet6_ops); err = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETLINK, - NULL, inet6_dump_ifinfo, 0); + NULL, inet6_dump_ifinfo, RTNL_FLAG_DUMP_UNLOCKED); if (err < 0) goto errout; From 22e36ea9f5d7707ae3d64c497d172f4ef735c353 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:17 +0000 Subject: [PATCH 1522/2255] inet: allow ip_valid_fib_dump_req() to be called with RTNL or RCU Add a new field into struct fib_dump_filter, to let callers tell if they use RTNL locking or RCU. This is used in the following patch, when inet_dump_fib() no longer holds RTNL. Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- include/net/ip_fib.h | 1 + net/ipv4/fib_frontend.c | 15 +++++++++++---- net/ipv4/ipmr.c | 4 +++- net/ipv6/ip6_fib.c | 7 +++++-- net/ipv6/ip6mr.c | 4 +++- net/mpls/af_mpls.c | 4 +++- 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index d4667b7797e3..9b2f69ba5e49 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -264,6 +264,7 @@ struct fib_dump_filter { bool filter_set; bool dump_routes; bool dump_exceptions; + bool rtnl_held; unsigned char protocol; unsigned char rt_type; unsigned int flags; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 390f4be7f7be..39f67990e01c 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -916,7 +916,8 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, struct rtmsg *rtm; int err, i; - ASSERT_RTNL(); + if (filter->rtnl_held) + ASSERT_RTNL(); if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { NL_SET_ERR_MSG(extack, "Invalid header for FIB dump request"); @@ -961,7 +962,10 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, break; case RTA_OIF: ifindex = nla_get_u32(tb[i]); - filter->dev = __dev_get_by_index(net, ifindex); + if (filter->rtnl_held) + filter->dev = __dev_get_by_index(net, ifindex); + else + filter->dev = dev_get_by_index_rcu(net, ifindex); if (!filter->dev) return -ENODEV; break; @@ -983,8 +987,11 @@ EXPORT_SYMBOL_GPL(ip_valid_fib_dump_req); static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { - struct fib_dump_filter filter = { .dump_routes = true, - .dump_exceptions = true }; + struct fib_dump_filter filter = { + .dump_routes = true, + .dump_exceptions = true, + .rtnl_held = true, + }; const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); unsigned int h, s_h; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 5561bce3a37e..0708ac6f6c58 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2587,7 +2587,9 @@ errout_free: static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { - struct fib_dump_filter filter = {}; + struct fib_dump_filter filter = { + .rtnl_held = true, + }; int err; if (cb->strict_check) { diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 6540d877d369..5c558dc1c683 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -620,8 +620,11 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { - struct rt6_rtnl_dump_arg arg = { .filter.dump_exceptions = true, - .filter.dump_routes = true }; + struct rt6_rtnl_dump_arg arg = { + .filter.dump_exceptions = true, + .filter.dump_routes = true, + .filter.rtnl_held = true, + }; const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); unsigned int h, s_h; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 1f19743f2540..cb0ee81a068a 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -2592,7 +2592,9 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; - struct fib_dump_filter filter = {}; + struct fib_dump_filter filter = { + .rtnl_held = true, + }; int err; if (cb->strict_check) { diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 1af29af65388..6dab883a08dd 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -2179,7 +2179,9 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct mpls_route __rcu **platform_label; - struct fib_dump_filter filter = {}; + struct fib_dump_filter filter = { + .rtnl_held = true, + }; unsigned int flags = NLM_F_MULTI; size_t platform_labels; unsigned int index; From 0ac3fa0c3b365f97c3969f391edf7b44d3bb210d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:18 +0000 Subject: [PATCH 1523/2255] nexthop: allow nexthop_mpath_fill_node() to be called without RTNL nexthop_mpath_fill_node() will be potentially called from contexts holding rcu_lock instead of RTNL. Suggested-by: Ido Schimmel Link: https://lore.kernel.org/all/ZdZDWVdjMaQkXBgW@shredder/ Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- include/net/nexthop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/nexthop.h b/include/net/nexthop.h index 6647ad509faa..77e99cba60ad 100644 --- a/include/net/nexthop.h +++ b/include/net/nexthop.h @@ -317,7 +317,7 @@ static inline int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh, u8 rt_family) { - struct nh_group *nhg = rtnl_dereference(nh->nh_grp); + struct nh_group *nhg = rcu_dereference_rtnl(nh->nh_grp); int i; for (i = 0; i < nhg->num_nh; i++) { From 4ce5dc9316de50e0da84beafe55d1344f829cece Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:19 +0000 Subject: [PATCH 1524/2255] inet: switch inet_dump_fib() to RCU protection No longer hold RTNL while calling inet_dump_fib(). Also change return value for a completed dump: Returning 0 instead of skb->len allows NLMSG_DONE to be appended to the skb. User space does not have to call us again to get a standalone NLMSG_DONE marker. Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 37 ++++++++++++++++++------------------- net/ipv4/fib_trie.c | 4 ++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 39f67990e01c..bf3a2214fe29 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -990,7 +990,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) struct fib_dump_filter filter = { .dump_routes = true, .dump_exceptions = true, - .rtnl_held = true, + .rtnl_held = false, }; const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); @@ -998,12 +998,13 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) unsigned int e = 0, s_e; struct fib_table *tb; struct hlist_head *head; - int dumped = 0, err; + int dumped = 0, err = 0; + rcu_read_lock(); if (cb->strict_check) { err = ip_valid_fib_dump_req(net, nlh, &filter, cb); if (err < 0) - return err; + goto unlock; } else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) { struct rtmsg *rtm = nlmsg_data(nlh); @@ -1012,29 +1013,28 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) /* ipv4 does not use prefix flag */ if (filter.flags & RTM_F_PREFIX) - return skb->len; + goto unlock; if (filter.table_id) { tb = fib_get_table(net, filter.table_id); if (!tb) { if (rtnl_msg_family(cb->nlh) != PF_INET) - return skb->len; + goto unlock; NL_SET_ERR_MSG(cb->extack, "ipv4: FIB table does not exist"); - return -ENOENT; + err = -ENOENT; + goto unlock; } - - rcu_read_lock(); err = fib_table_dump(tb, skb, cb, &filter); - rcu_read_unlock(); - return skb->len ? : err; + if (err < 0 && skb->len) + err = skb->len; + goto unlock; } s_h = cb->args[0]; s_e = cb->args[1]; - rcu_read_lock(); - + err = 0; for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { e = 0; head = &net->ipv4.fib_table_hash[h]; @@ -1047,9 +1047,8 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) err = fib_table_dump(tb, skb, cb, &filter); if (err < 0) { if (likely(skb->len)) - goto out; - - goto out_err; + err = skb->len; + goto out; } dumped = 1; next: @@ -1057,13 +1056,12 @@ next: } } out: - err = skb->len; -out_err: - rcu_read_unlock(); cb->args[1] = e; cb->args[0] = h; +unlock: + rcu_read_unlock(); return err; } @@ -1666,5 +1664,6 @@ void __init ip_fib_init(void) rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, 0); rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, 0); - rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, 0); + rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, + RTNL_FLAG_DUMP_UNLOCKED); } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 0fc7ab5832d1..f474106464d2 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2368,7 +2368,7 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, * and key == 0 means the dump has wrapped around and we are done. */ if (count && !key) - return skb->len; + return 0; while ((l = leaf_walk_rcu(&tp, key)) != NULL) { int err; @@ -2394,7 +2394,7 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, cb->args[3] = key; cb->args[2] = count; - return skb->len; + return 0; } void __init fib_trie_init(void) From 74808e72e0b2d7cac886151198c0330daadaee70 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:20 +0000 Subject: [PATCH 1525/2255] rtnetlink: make rtnl_fill_link_ifmap() RCU ready Use READ_ONCE() to read the following device fields: dev->mem_start dev->mem_end dev->base_addr dev->irq dev->dma dev->if_port Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1b26dfa5668d..2d83ab76a3c9 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1455,17 +1455,18 @@ static noinline_for_stack int rtnl_fill_vf(struct sk_buff *skb, return 0; } -static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev) +static int rtnl_fill_link_ifmap(struct sk_buff *skb, + const struct net_device *dev) { struct rtnl_link_ifmap map; memset(&map, 0, sizeof(map)); - map.mem_start = dev->mem_start; - map.mem_end = dev->mem_end; - map.base_addr = dev->base_addr; - map.irq = dev->irq; - map.dma = dev->dma; - map.port = dev->if_port; + map.mem_start = READ_ONCE(dev->mem_start); + map.mem_end = READ_ONCE(dev->mem_end); + map.base_addr = READ_ONCE(dev->base_addr); + map.irq = READ_ONCE(dev->irq); + map.dma = READ_ONCE(dev->dma); + map.port = READ_ONCE(dev->if_port); if (nla_put_64bit(skb, IFLA_MAP, sizeof(map), &map, IFLA_PAD)) return -EMSGSIZE; @@ -1875,9 +1876,6 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, goto nla_put_failure; } - if (rtnl_fill_link_ifmap(skb, dev)) - goto nla_put_failure; - if (dev->addr_len) { if (nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr) || nla_put(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast)) @@ -1927,6 +1925,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, rcu_read_lock(); if (rtnl_fill_link_af(skb, dev, ext_filter_mask)) goto nla_put_failure_rcu; + if (rtnl_fill_link_ifmap(skb, dev)) + goto nla_put_failure_rcu; + rcu_read_unlock(); if (rtnl_fill_prop_list(skb, dev)) From 0ec4e48c3a233820e0bce1f5ba9ed3e4520f90e9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Feb 2024 10:50:21 +0000 Subject: [PATCH 1526/2255] rtnetlink: provide RCU protection to rtnl_fill_prop_list() We want to be able to run rtnl_fill_ifinfo() under RCU protection instead of RTNL in the future. dev->name_node items are already rcu protected. Signed-off-by: Eric Dumazet Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2d83ab76a3c9..39f17d0b6cea 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1699,7 +1699,7 @@ static int rtnl_fill_alt_ifnames(struct sk_buff *skb, struct netdev_name_node *name_node; int count = 0; - list_for_each_entry(name_node, &dev->name_node->list, list) { + list_for_each_entry_rcu(name_node, &dev->name_node->list, list) { if (nla_put_string(skb, IFLA_ALT_IFNAME, name_node->name)) return -EMSGSIZE; count++; @@ -1707,6 +1707,7 @@ static int rtnl_fill_alt_ifnames(struct sk_buff *skb, return count; } +/* RCU protected. */ static int rtnl_fill_prop_list(struct sk_buff *skb, const struct net_device *dev) { @@ -1927,11 +1928,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, goto nla_put_failure_rcu; if (rtnl_fill_link_ifmap(skb, dev)) goto nla_put_failure_rcu; - - rcu_read_unlock(); - if (rtnl_fill_prop_list(skb, dev)) - goto nla_put_failure; + goto nla_put_failure_rcu; + rcu_read_unlock(); if (dev->dev.parent && nla_put_string(skb, IFLA_PARENT_DEV_NAME, From 0ffc3292c02b7f16dd23d841b8c4766c48edfdc7 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 22 Feb 2024 20:58:20 +0300 Subject: [PATCH 1527/2255] net: pcs: xpcs: Drop sentinel entry from 2500basex ifaces list There are currently only two methods (xpcs_find_compat() and xpcs_get_interfaces()) defined in the driver which loop over the available interfaces. All of them rely on the xpcs_compat::num_interfaces field value to get the total number of supported interfaces. Thus the interface arrays are supposed to be filled with actual interface IDs and there is no need in the dummy terminating ID placed at the end of the arrays. Based on the above drop the PHY_INTERFACE_MODE_MAX entry from the xpcs_2500basex_interfaces array and the PHY_INTERFACE_MODE_MAX-based conditional statement from the xpcs_get_interfaces() method as redundant. Signed-off-by: Serge Semin Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 52a7757ee419..9a46c054cd94 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -130,7 +130,6 @@ static const phy_interface_t xpcs_1000basex_interfaces[] = { static const phy_interface_t xpcs_2500basex_interfaces[] = { PHY_INTERFACE_MODE_2500BASEX, - PHY_INTERFACE_MODE_MAX, }; enum { @@ -636,8 +635,7 @@ void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) const struct xpcs_compat *compat = &xpcs->id->compat[i]; for (j = 0; j < compat->num_interfaces; j++) - if (compat->interface[j] < PHY_INTERFACE_MODE_MAX) - __set_bit(compat->interface[j], interfaces); + __set_bit(compat->interface[j], interfaces); } } EXPORT_SYMBOL_GPL(xpcs_get_interfaces); From e26802ebd29573cdca9bcc01c8731db9ffc3332b Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 22 Feb 2024 20:58:21 +0300 Subject: [PATCH 1528/2255] net: pcs: xpcs: Drop redundant workqueue.h include directive There is nothing CM workqueue-related in the driver. So the respective include directive can be dropped. While at it add an empty line delimiter between the generic and local path include directives to visually separate them. Signed-off-by: Serge Semin Tested-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 9a46c054cd94..6060f1cc6699 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -10,7 +10,7 @@ #include #include #include -#include + #include "pcs-xpcs.h" #define phylink_pcs_to_xpcs(pl_pcs) \ From f5151005d379d9ce42e327fd3b2d2aaef61cda81 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 22 Feb 2024 20:58:22 +0300 Subject: [PATCH 1529/2255] net: pcs: xpcs: Return EINVAL in the internal methods In particular the xpcs_soft_reset() and xpcs_do_config() functions currently return -1 if invalid auto-negotiation mode is specified. That value might be then passed to the generic kernel subsystems which require a standard kernel errno value. Even though the erroneous conditions are very specific (memory corruption or buggy driver implementation) using a hard-coded -1 literal doesn't seem correct anyway especially when it comes to passing it higher to the network subsystem or printing to the system log. Convert the hard-coded error values to -EINVAL then. Signed-off-by: Serge Semin Tested-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 6060f1cc6699..02262af336c4 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -292,7 +292,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs, dev = MDIO_MMD_VEND2; break; default: - return -1; + return -EINVAL; } ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET); @@ -889,7 +889,7 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, return ret; break; default: - return -1; + return -EINVAL; } if (compat->pma_config) { From 361dd531a11bc2c63c3c906a202a9c8a7675f3e7 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 22 Feb 2024 20:58:23 +0300 Subject: [PATCH 1530/2255] net: pcs: xpcs: Explicitly return error on caps validation If an unsupported interface is passed to the PCS validation callback there is no need in further link-modes calculations since the resultant array will be initialized with zeros which will be perceived by the phylink subsystem as error anyway (see phylink_validate_mac_and_pcs()). Instead let's explicitly return the -EINVAL error to inform the caller about the unsupported interface as it's done in the rest of the pcs_validate callbacks. Signed-off-by: Serge Semin Reviewed-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 02262af336c4..31525fe9c32e 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -613,14 +613,15 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, xpcs = phylink_pcs_to_xpcs(pcs); compat = xpcs_find_compat(xpcs->id, state->interface); + if (!compat) + return -EINVAL; /* Populate the supported link modes for this PHY interface type. * FIXME: what about the port modes and autoneg bit? This masks * all those away. */ - if (compat) - for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++) - set_bit(compat->supported[i], xpcs_supported); + for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++) + set_bit(compat->supported[i], xpcs_supported); linkmode_and(supported, supported, xpcs_supported); From 35c6bba552a8469e6423727fba6a73616fcabd51 Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Fri, 2 Feb 2024 01:45:12 -0500 Subject: [PATCH 1531/2255] net: ieee802154: at86rf230: convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Bo Liu Reviewed-by: Miquel Raynal Message-ID: <20240202064512.39259-1-liubo03@inspur.com> Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 164c7f605af5..6212164ffb36 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -316,7 +316,7 @@ static const struct regmap_config at86rf230_regmap_spi_config = { .val_bits = 8, .write_flag_mask = CMD_REG | CMD_WRITE, .read_flag_mask = CMD_REG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = AT86RF2XX_NUMREGS, .writeable_reg = at86rf230_reg_writeable, .readable_reg = at86rf230_reg_readable, From b0f413bc63ea39358ec42a7f16526b097cf1f3b4 Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Fri, 2 Feb 2024 01:46:11 -0500 Subject: [PATCH 1532/2255] net: ieee802154: mcr20a: convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Bo Liu Message-ID: <20240202064611.39346-1-liubo03@inspur.com> Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/mcr20a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c index 87abe3b46316..efb1be3c644e 100644 --- a/drivers/net/ieee802154/mcr20a.c +++ b/drivers/net/ieee802154/mcr20a.c @@ -251,7 +251,7 @@ static const struct regmap_config mcr20a_dar_regmap = { .val_bits = 8, .write_flag_mask = REGISTER_ACCESS | REGISTER_WRITE, .read_flag_mask = REGISTER_ACCESS | REGISTER_READ, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .writeable_reg = mcr20a_dar_writeable, .readable_reg = mcr20a_dar_readable, .volatile_reg = mcr20a_dar_volatile, @@ -387,7 +387,7 @@ static const struct regmap_config mcr20a_iar_regmap = { .val_bits = 8, .write_flag_mask = REGISTER_ACCESS | REGISTER_WRITE | IAR_INDEX, .read_flag_mask = REGISTER_ACCESS | REGISTER_READ | IAR_INDEX, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .writeable_reg = mcr20a_iar_writeable, .readable_reg = mcr20a_iar_readable, .volatile_reg = mcr20a_iar_volatile, From 36cc392d1ae142e82b38d137daaac282dd1aced1 Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Fri, 2 Feb 2024 01:46:59 -0500 Subject: [PATCH 1533/2255] net: ieee802154: mrf24j40: convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Bo Liu Message-ID: <20240202064659.39434-1-liubo03@inspur.com> Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/mrf24j40.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index ee4cfbf2c5cc..d3f42efc5d1a 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -388,7 +388,7 @@ static const struct regmap_config mrf24j40_short_regmap = { .pad_bits = 1, .write_flag_mask = MRF24J40_SHORT_WRITE, .read_flag_mask = MRF24J40_SHORT_READ, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = MRF24J40_SHORT_NUMREGS, .writeable_reg = mrf24j40_short_reg_writeable, .readable_reg = mrf24j40_short_reg_readable, @@ -495,7 +495,7 @@ static const struct regmap_config mrf24j40_long_regmap = { .pad_bits = 5, .write_flag_mask = MRF24J40_LONG_ACCESS, .read_flag_mask = MRF24J40_LONG_ACCESS, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = MRF24J40_LONG_NUMREGS, .writeable_reg = mrf24j40_long_reg_writeable, .readable_reg = mrf24j40_long_reg_readable, From 42683294cc0a9ba010de5d978fd23fd1e778b192 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 5 Feb 2024 13:53:54 -1000 Subject: [PATCH 1534/2255] ieee802154: ca8210: Drop spurious WQ_UNBOUND from alloc_ordered_workqueue() call Workqueue is in the process of cleaning up the distinction between unbound workqueues w/ @nr_active==1 and ordered workqueues. Explicit WQ_UNBOUND isn't needed for alloc_ordered_workqueue() and will trigger a warning in the future. Let's remove it. This doesn't cause any functional changes. Signed-off-by: Tejun Heo Reviewed-by: Miquel Raynal Message-ID: Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/ca8210.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 4ec0dab38872..f102f26cb0e3 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -2857,19 +2857,13 @@ static int ca8210_interrupt_init(struct spi_device *spi) */ static int ca8210_dev_com_init(struct ca8210_priv *priv) { - priv->mlme_workqueue = alloc_ordered_workqueue( - "MLME work queue", - WQ_UNBOUND - ); + priv->mlme_workqueue = alloc_ordered_workqueue("MLME work queue", 0); if (!priv->mlme_workqueue) { dev_crit(&priv->spi->dev, "alloc of mlme_workqueue failed!\n"); return -ENOMEM; } - priv->irq_workqueue = alloc_ordered_workqueue( - "ca8210 irq worker", - WQ_UNBOUND - ); + priv->irq_workqueue = alloc_ordered_workqueue("ca8210 irq worker", 0); if (!priv->irq_workqueue) { dev_crit(&priv->spi->dev, "alloc of irq_workqueue failed!\n"); destroy_workqueue(priv->mlme_workqueue); From bcd53aff4d0cce9c4bedf345e6f896e35f2fd4c5 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 23 Feb 2024 03:58:37 -0800 Subject: [PATCH 1535/2255] net/vsockmon: Leverage core stats allocator With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the vsockmon driver and leverage the network core allocation instead. Signed-off-by: Breno Leitao Reviewed-by: Eric Dumazet Reviewed-by: Stefano Garzarella Link: https://lore.kernel.org/r/20240223115839.3572852-1-leitao@debian.org Signed-off-by: Jakub Kicinski --- drivers/net/vsockmon.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/net/vsockmon.c b/drivers/net/vsockmon.c index b1bb1b04b664..a0b4dca36baf 100644 --- a/drivers/net/vsockmon.c +++ b/drivers/net/vsockmon.c @@ -13,19 +13,6 @@ #define DEFAULT_MTU (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + \ sizeof(struct af_vsockmon_hdr)) -static int vsockmon_dev_init(struct net_device *dev) -{ - dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); - if (!dev->lstats) - return -ENOMEM; - return 0; -} - -static void vsockmon_dev_uninit(struct net_device *dev) -{ - free_percpu(dev->lstats); -} - struct vsockmon { struct vsock_tap vt; }; @@ -79,8 +66,6 @@ static int vsockmon_change_mtu(struct net_device *dev, int new_mtu) } static const struct net_device_ops vsockmon_ops = { - .ndo_init = vsockmon_dev_init, - .ndo_uninit = vsockmon_dev_uninit, .ndo_open = vsockmon_open, .ndo_stop = vsockmon_close, .ndo_start_xmit = vsockmon_xmit, @@ -112,6 +97,7 @@ static void vsockmon_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->mtu = DEFAULT_MTU; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_LSTATS; } static struct rtnl_link_ops vsockmon_link_ops __read_mostly = { From 3a25e212306c2f9ecea5bee17ab90f5efad6e2a2 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 23 Feb 2024 03:58:38 -0800 Subject: [PATCH 1536/2255] net/vsockmon: Do not set zeroed statistics Do not set rtnl_link_stats64 fields to zero, since they are zeroed before ops->ndo_get_stats64 is called in core dev_get_stats() function. Signed-off-by: Breno Leitao Reviewed-by: Eric Dumazet Reviewed-by: Stefano Garzarella Reviewed-by: Jason Xing Link: https://lore.kernel.org/r/20240223115839.3572852-2-leitao@debian.org Signed-off-by: Jakub Kicinski --- drivers/net/vsockmon.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/vsockmon.c b/drivers/net/vsockmon.c index a0b4dca36baf..a1ba5169ed5d 100644 --- a/drivers/net/vsockmon.c +++ b/drivers/net/vsockmon.c @@ -46,9 +46,6 @@ static void vsockmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { dev_lstats_read(dev, &stats->rx_packets, &stats->rx_bytes); - - stats->tx_packets = 0; - stats->tx_bytes = 0; } static int vsockmon_is_valid_mtu(int new_mtu) From 5c237967e632c81db0504cffa26eaa19e7940650 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 23 Feb 2024 22:52:28 +0530 Subject: [PATCH 1537/2255] dt-bindings: net: cdns,macb: add sam9x7 ethernet interface Add documentation for sam9x7 ethernet interface. Signed-off-by: Varshini Rajendran Acked-by: Rob Herring Link: https://lore.kernel.org/r/20240223172228.671553-1-varshini.rajendran@microchip.com Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/cdns,macb.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/net/cdns,macb.yaml b/Documentation/devicetree/bindings/net/cdns,macb.yaml index bf8894a0257e..2c71e2cf3a2f 100644 --- a/Documentation/devicetree/bindings/net/cdns,macb.yaml +++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml @@ -59,6 +59,11 @@ properties: - cdns,gem # Generic - cdns,macb # Generic + - items: + - enum: + - microchip,sam9x7-gem # Microchip SAM9X7 gigabit ethernet interface + - const: microchip,sama7g5-gem # Microchip SAMA7G5 gigabit ethernet interface + reg: minItems: 1 items: From c3718936ec47ae811a7ce9a618b6cb1cda835bab Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Feb 2024 20:10:54 +0000 Subject: [PATCH 1538/2255] ipv6: anycast: complete RCU handling of struct ifacaddr6 struct ifacaddr6 are already freed after RCU grace period. Add __rcu qualifier to aca_next pointer, and idev->ac_list Add relevant rcu_assign_pointer() and dereference accessors. ipv6_chk_acast_dev() no longer needs to acquire idev->lock. /proc/net/anycast6 is now purely RCU protected, it no longer acquires idev->lock. Similarly in6_dump_addrs() can use RCU protection to iterate through anycast addresses. It was relying on a mixture of RCU and RTNL but next patches will get rid of RTNL there. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240223201054.220534-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/if_inet6.h | 4 +-- net/ipv6/addrconf.c | 4 +-- net/ipv6/anycast.c | 61 ++++++++++++++++-------------------------- 3 files changed, 27 insertions(+), 42 deletions(-) diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index f07642264c1e..238ad3349456 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -144,7 +144,7 @@ struct ipv6_ac_socklist { struct ifacaddr6 { struct in6_addr aca_addr; struct fib6_info *aca_rt; - struct ifacaddr6 *aca_next; + struct ifacaddr6 __rcu *aca_next; struct hlist_node aca_addr_lst; int aca_users; refcount_t aca_refcnt; @@ -196,7 +196,7 @@ struct inet6_dev { spinlock_t mc_report_lock; /* mld query report lock */ struct mutex mc_lock; /* mld global lock */ - struct ifacaddr6 *ac_list; + struct ifacaddr6 __rcu *ac_list; rwlock_t lock; refcount_t refcnt; __u32 if_flags; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a280614b3765..e27069ad938c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5314,8 +5314,8 @@ next: case ANYCAST_ADDR: fillargs->event = RTM_GETANYCAST; /* anycast address */ - for (ifaca = idev->ac_list; ifaca; - ifaca = ifaca->aca_next, ip_idx++) { + for (ifaca = rcu_dereference(idev->ac_list); ifaca; + ifaca = rcu_dereference(ifaca->aca_next), ip_idx++) { if (ip_idx < s_ip_idx) continue; err = inet6_fill_ifacaddr(skb, ifaca, fillargs); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index bb17f484ee2c..0f2506e35359 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -296,7 +296,8 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) goto out; } - for (aca = idev->ac_list; aca; aca = aca->aca_next) { + for (aca = rtnl_dereference(idev->ac_list); aca; + aca = rtnl_dereference(aca->aca_next)) { if (ipv6_addr_equal(&aca->aca_addr, addr)) { aca->aca_users++; err = 0; @@ -317,13 +318,13 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) goto out; } - aca->aca_next = idev->ac_list; - idev->ac_list = aca; - /* Hold this for addrconf_join_solict() below before we unlock, * it is already exposed via idev->ac_list. */ aca_get(aca); + aca->aca_next = idev->ac_list; + rcu_assign_pointer(idev->ac_list, aca); + write_unlock_bh(&idev->lock); ipv6_add_acaddr_hash(net, aca); @@ -350,7 +351,8 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr) write_lock_bh(&idev->lock); prev_aca = NULL; - for (aca = idev->ac_list; aca; aca = aca->aca_next) { + for (aca = rtnl_dereference(idev->ac_list); aca; + aca = rtnl_dereference(aca->aca_next)) { if (ipv6_addr_equal(&aca->aca_addr, addr)) break; prev_aca = aca; @@ -364,9 +366,9 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr) return 0; } if (prev_aca) - prev_aca->aca_next = aca->aca_next; + rcu_assign_pointer(prev_aca->aca_next, aca->aca_next); else - idev->ac_list = aca->aca_next; + rcu_assign_pointer(idev->ac_list, aca->aca_next); write_unlock_bh(&idev->lock); ipv6_del_acaddr_hash(aca); addrconf_leave_solict(idev, &aca->aca_addr); @@ -392,8 +394,8 @@ void ipv6_ac_destroy_dev(struct inet6_dev *idev) struct ifacaddr6 *aca; write_lock_bh(&idev->lock); - while ((aca = idev->ac_list) != NULL) { - idev->ac_list = aca->aca_next; + while ((aca = rtnl_dereference(idev->ac_list)) != NULL) { + rcu_assign_pointer(idev->ac_list, aca->aca_next); write_unlock_bh(&idev->lock); ipv6_del_acaddr_hash(aca); @@ -420,11 +422,10 @@ static bool ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *ad idev = __in6_dev_get(dev); if (idev) { - read_lock_bh(&idev->lock); - for (aca = idev->ac_list; aca; aca = aca->aca_next) + for (aca = rcu_dereference(idev->ac_list); aca; + aca = rcu_dereference(aca->aca_next)) if (ipv6_addr_equal(&aca->aca_addr, addr)) break; - read_unlock_bh(&idev->lock); return aca != NULL; } return false; @@ -477,30 +478,25 @@ bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, struct ac6_iter_state { struct seq_net_private p; struct net_device *dev; - struct inet6_dev *idev; }; #define ac6_seq_private(seq) ((struct ac6_iter_state *)(seq)->private) static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) { - struct ifacaddr6 *im = NULL; struct ac6_iter_state *state = ac6_seq_private(seq); struct net *net = seq_file_net(seq); + struct ifacaddr6 *im = NULL; - state->idev = NULL; for_each_netdev_rcu(net, state->dev) { struct inet6_dev *idev; + idev = __in6_dev_get(state->dev); if (!idev) continue; - read_lock_bh(&idev->lock); - im = idev->ac_list; - if (im) { - state->idev = idev; + im = rcu_dereference(idev->ac_list); + if (im) break; - } - read_unlock_bh(&idev->lock); } return im; } @@ -508,22 +504,17 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im) { struct ac6_iter_state *state = ac6_seq_private(seq); + struct inet6_dev *idev; - im = im->aca_next; + im = rcu_dereference(im->aca_next); while (!im) { - if (likely(state->idev != NULL)) - read_unlock_bh(&state->idev->lock); - state->dev = next_net_device_rcu(state->dev); - if (!state->dev) { - state->idev = NULL; + if (!state->dev) break; - } - state->idev = __in6_dev_get(state->dev); - if (!state->idev) + idev = __in6_dev_get(state->dev); + if (!idev) continue; - read_lock_bh(&state->idev->lock); - im = state->idev->ac_list; + im = rcu_dereference(idev->ac_list); } return im; } @@ -555,12 +546,6 @@ static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void ac6_seq_stop(struct seq_file *seq, void *v) __releases(RCU) { - struct ac6_iter_state *state = ac6_seq_private(seq); - - if (likely(state->idev != NULL)) { - read_unlock_bh(&state->idev->lock); - state->idev = NULL; - } rcu_read_unlock(); } From 9da74836740d9c753fb6cd270f7c75c5258836de Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 23 Feb 2024 21:17:53 +0100 Subject: [PATCH 1539/2255] selftests: mptcp: lib: catch duplicated subtest entries It is important to have a unique (sub)test name in TAP, because some CI environments drop tests with duplicated name. When adding a new subtest entry, an error message is printed in case of duplicated entries. If there were duplicated entries and if all features were expected to work, the script exits with an error at the end, after having printed all subtests in the TAP format. Thanks to that, the MPTCP CI will catch such issues early. Reviewed-by: Geliang Tang Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-1-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_lib.sh | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 3a2abae5993e..037cb3e84330 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -9,6 +9,7 @@ readonly KSFT_SKIP=4 readonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}" MPTCP_LIB_SUBTESTS=() +MPTCP_LIB_SUBTESTS_DUPLICATED=0 # only if supported (or forced) and not disabled, see no-color.org if { [ -t 1 ] || [ "${SELFTESTS_MPTCP_LIB_COLOR_FORCE:-}" = "1" ]; } && @@ -146,12 +147,26 @@ mptcp_lib_kversion_ge() { mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}" } +__mptcp_lib_result_check_duplicated() { + local subtest + + for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do + if [[ "${subtest}" == *" - ${KSFT_TEST}: ${*%% #*}" ]]; then + MPTCP_LIB_SUBTESTS_DUPLICATED=1 + mptcp_lib_print_err "Duplicated entry: ${*}" + break + fi + done +} + __mptcp_lib_result_add() { local result="${1}" shift local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1)) + __mptcp_lib_result_check_duplicated "${*}" + MPTCP_LIB_SUBTESTS+=("${result} ${id} - ${KSFT_TEST}: ${*}") } @@ -206,6 +221,12 @@ mptcp_lib_result_print_all_tap() { for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do printf "%s\n" "${subtest}" done + + if [ "${MPTCP_LIB_SUBTESTS_DUPLICATED}" = 1 ] && + mptcp_lib_expect_all_features; then + mptcp_lib_print_err "Duplicated test entries" + exit ${KSFT_FAIL} + fi } # get the value of keyword $1 in the line marked by keyword $2 From 28de50eeb734bbdbc1c4397134fa3501d3490a62 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 23 Feb 2024 21:17:54 +0100 Subject: [PATCH 1540/2255] mptcp: token kunit: set protocol As it would be done when initiating an MPTCP sock. This is not strictly needed for this test, but it will be when a later patch will check if the right protocol is being used when calling mptcp_sk(). Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-2-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- net/mptcp/token_test.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/mptcp/token_test.c b/net/mptcp/token_test.c index bfff53e668da..4fc39fa2e262 100644 --- a/net/mptcp/token_test.c +++ b/net/mptcp/token_test.c @@ -52,14 +52,19 @@ static struct mptcp_subflow_context *build_ctx(struct kunit *test) static struct mptcp_sock *build_msk(struct kunit *test) { struct mptcp_sock *msk; + struct sock *sk; msk = kunit_kzalloc(test, sizeof(struct mptcp_sock), GFP_USER); KUNIT_EXPECT_NOT_ERR_OR_NULL(test, msk); refcount_set(&((struct sock *)msk)->sk_refcnt, 1); sock_net_set((struct sock *)msk, &init_net); + sk = (struct sock *)msk; + /* be sure the token helpers can dereference sk->sk_prot */ - ((struct sock *)msk)->sk_prot = &tcp_prot; + sk->sk_prot = &tcp_prot; + sk->sk_protocol = IPPROTO_MPTCP; + return msk; } From dcc03f270d1e2f4b9715537d8deb734bd019e187 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 23 Feb 2024 21:17:55 +0100 Subject: [PATCH 1541/2255] mptcp: check the protocol in tcp_sk() with DEBUG_NET Fuzzers and static checkers might not detect when tcp_sk() is used with a non tcp_sock structure. This kind of mistake already happened a few times with MPTCP: when wrongly using TCP-specific helpers with mptcp_sock pointers. On the other hand, there are many 'tcp_xxx()' helpers that are taking a 'struct sock' pointer as arguments, and some of them are only looking at fields from 'struct sock', and nothing from 'struct tcp_sock'. It is then tempting to use them with a 'struct mptcp_sock'. So a new simple check is done when CONFIG_DEBUG_NET is enabled to tell kernel devs when a non-TCP socket is being used as a TCP one. 'tcp_sk()' macro is then re-defined to add a WARN when an unexpected socket is being used. Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-3-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index f89b197a9f92..026ed360bd72 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -348,6 +348,16 @@ static inline void msk_owned_by_me(const struct mptcp_sock *msk) sock_owned_by_me((const struct sock *)msk); } +#ifdef CONFIG_DEBUG_NET +/* MPTCP-specific: we might (indirectly) call this helper with the wrong sk */ +#undef tcp_sk +#define tcp_sk(ptr) ({ \ + typeof(ptr) _ptr = (ptr); \ + WARN_ON(_ptr->sk_protocol != IPPROTO_TCP); \ + container_of_const(_ptr, struct tcp_sock, inet_conn.icsk_inet.sk); \ +}) +#endif + #define mptcp_sk(ptr) container_of_const(ptr, struct mptcp_sock, sk.icsk_inet.sk) /* the msk socket don't use the backlog, also account for the bulk From 14d29ec5302caac945267b9586fad01ecddc700c Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 23 Feb 2024 21:17:56 +0100 Subject: [PATCH 1542/2255] mptcp: check the protocol in mptcp_sk() with DEBUG_NET Fuzzers and static checkers might not detect when mptcp_sk() is used with a non mptcp_sock structure. This is similar to the parent commit, where it is easy to use mptcp_sk() with a TCP sock, e.g. with a subflow sk. So a new simple check is done when CONFIG_DEBUG_NET is enabled to tell kernel devs when a non-MPTCP socket is being used as an MPTCP one. 'mptcp_sk()' macro is then defined differently: with an extra WARN to complain when an unexpected socket is being used. Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-4-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 026ed360bd72..051b100d9403 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -356,9 +356,15 @@ static inline void msk_owned_by_me(const struct mptcp_sock *msk) WARN_ON(_ptr->sk_protocol != IPPROTO_TCP); \ container_of_const(_ptr, struct tcp_sock, inet_conn.icsk_inet.sk); \ }) -#endif +#define mptcp_sk(ptr) ({ \ + typeof(ptr) _ptr = (ptr); \ + WARN_ON(_ptr->sk_protocol != IPPROTO_MPTCP); \ + container_of_const(_ptr, struct mptcp_sock, sk.icsk_inet.sk); \ +}) +#else /* !CONFIG_DEBUG_NET */ #define mptcp_sk(ptr) container_of_const(ptr, struct mptcp_sock, sk.icsk_inet.sk) +#endif /* the msk socket don't use the backlog, also account for the bulk * free memory From 488ccbe76cb4fb3dff87722c35dd5e2ea6c5f8d6 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Feb 2024 21:17:57 +0100 Subject: [PATCH 1543/2255] selftests: mptcp: netlink: drop duplicate var ret The variable 'ret' are defined twice in pm_netlink.sh. This patch drops this duplicate one that has been defined from the beginning, with commit eedbc685321b ("selftests: add PM netlink functional tests") Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-5-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/pm_netlink.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/pm_netlink.sh b/tools/testing/selftests/net/mptcp/pm_netlink.sh index 71899a3ffa7a..ebfefae71e13 100755 --- a/tools/testing/selftests/net/mptcp/pm_netlink.sh +++ b/tools/testing/selftests/net/mptcp/pm_netlink.sh @@ -28,7 +28,6 @@ sec=$(date +%s) rndh=$(printf %x $sec)-$(mktemp -u XXXXXX) ns1="ns1-$rndh" err=$(mktemp) -ret=0 cleanup() { From fccf7c922459c588eb71bdda5c53727e539442e8 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Feb 2024 21:17:58 +0100 Subject: [PATCH 1544/2255] selftests: mptcp: simult flows: define missing vars The variables 'large', 'small', 'sout', 'cout', 'capout' and 'size' are used in multiple functions, so they should be clearly defined as global variables at the top of the file. This patch redefines them at the beginning of simult_flows.sh. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-6-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/simult_flows.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh index 8f9ddb3ad4fe..ed0165c15a24 100755 --- a/tools/testing/selftests/net/mptcp/simult_flows.sh +++ b/tools/testing/selftests/net/mptcp/simult_flows.sh @@ -16,6 +16,12 @@ test_cnt=1 ret=0 bail=0 slack=50 +large="" +small="" +sout="" +cout="" +capout="" +size=0 usage() { echo "Usage: $0 [ -b ] [ -c ] [ -d ]" From 8c6f6b4bb53a904f922dfb90d566391d3feee32c Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Feb 2024 21:17:59 +0100 Subject: [PATCH 1545/2255] selftests: mptcp: join: change capture/checksum as bool To maintain consistency with other scripts, this patch changes vars 'capture' and 'checksum' as bool vars in mptcp_join. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-7-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/mptcp/mptcp_join.sh | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index c07386e21e0a..3f198743cb03 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -29,11 +29,11 @@ iptables="iptables" ip6tables="ip6tables" timeout_poll=30 timeout_test=$((timeout_poll * 2 + 1)) -capture=0 -checksum=0 +capture=false +checksum=false ip_mptcp=0 check_invert=0 -validate_checksum=0 +validate_checksum=false init=0 evts_ns1="" evts_ns2="" @@ -100,7 +100,7 @@ init_partial() ip netns exec $netns sysctl -q net.mptcp.pm_type=0 2>/dev/null || true ip netns exec $netns sysctl -q net.ipv4.conf.all.rp_filter=0 ip netns exec $netns sysctl -q net.ipv4.conf.default.rp_filter=0 - if [ $checksum -eq 1 ]; then + if $checksum; then ip netns exec $netns sysctl -q net.mptcp.checksum_enabled=1 fi done @@ -380,7 +380,7 @@ reset_with_checksum() ip netns exec $ns1 sysctl -q net.mptcp.checksum_enabled=$ns1_enable ip netns exec $ns2 sysctl -q net.mptcp.checksum_enabled=$ns2_enable - validate_checksum=1 + validate_checksum=true } reset_with_allow_join_id0() @@ -413,7 +413,7 @@ reset_with_allow_join_id0() setup_fail_rules() { check_invert=1 - validate_checksum=1 + validate_checksum=true local i="$1" local ip="${2:-4}" local tables @@ -1017,7 +1017,7 @@ do_transfer() :> "$sout" :> "$capout" - if [ $capture -eq 1 ]; then + if $capture; then local capuser if [ -z $SUDO_USER ] ; then capuser="" @@ -1119,7 +1119,7 @@ do_transfer() wait $spid local rets=$? - if [ $capture -eq 1 ]; then + if $capture; then sleep 1 kill $cappid fi @@ -1507,7 +1507,7 @@ chk_join_nr() else print_ok fi - if [ $validate_checksum -eq 1 ]; then + if $validate_checksum; then chk_csum_nr $csum_ns1 $csum_ns2 chk_fail_nr $fail_nr $fail_nr chk_rst_nr $rst_nr $rst_nr @@ -3664,10 +3664,10 @@ while getopts "${all_tests_args}cCih" opt; do tests+=("${all_tests[${opt}]}") ;; c) - capture=1 + capture=true ;; C) - checksum=1 + checksum=true ;; i) ip_mptcp=1 From e8ddc5f255c3e5371aed621fdda6dce227c69a68 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Feb 2024 21:18:00 +0100 Subject: [PATCH 1546/2255] selftests: mptcp: diag: change timeout_poll to 30 Even if it is set to 100ms from the beginning with commit df62f2ec3df6 ("selftests/mptcp: add diag interface tests"), there is no reason not to have it to 30ms like all the other tests. "diag.sh" is not supposed to be slower than the other ones. To maintain consistency with other scripts, this patch changes it to 30. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://lore.kernel.org/r/20240223-upstream-net-next-20240223-misc-improvements-v1-8-b6c8a10396bd@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/diag.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/diag.sh b/tools/testing/selftests/net/mptcp/diag.sh index 0a58ebb8b04c..8573326d326a 100755 --- a/tools/testing/selftests/net/mptcp/diag.sh +++ b/tools/testing/selftests/net/mptcp/diag.sh @@ -8,7 +8,7 @@ rndh=$(printf %x $sec)-$(mktemp -u XXXXXX) ns="ns1-$rndh" ksft_skip=4 test_cnt=1 -timeout_poll=100 +timeout_poll=30 timeout_test=$((timeout_poll * 2 + 1)) ret=0 From b38061fe9cfa90a781e9e59fc761191fc8b469a1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 20 Feb 2024 22:55:38 +0100 Subject: [PATCH 1547/2255] net: phy: simplify genphy_c45_ethtool_set_eee Simplify the function, no functional change intended. - Remove not needed variable unsupp, I think code is even better readable now. - Move setting phydev->eee_enabled out of the if clause - Simplify return value handling Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/442277c7-7431-4542-80b5-1d3d691714d7@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/phy/phy-c45.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index fa5145c9328e..3e95b8a15f44 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1561,10 +1561,8 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, if (!linkmode_empty(adv)) { __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp); - bool unsupp; - unsupp = linkmode_andnot(tmp, adv, phydev->supported_eee); - if (unsupp) { + if (linkmode_andnot(tmp, adv, phydev->supported_eee)) { phydev_warn(phydev, "At least some EEE link modes are not supported.\n"); return -EINVAL; } @@ -1573,18 +1571,15 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, } linkmode_copy(phydev->advertising_eee, adv); - phydev->eee_enabled = true; - } else { - phydev->eee_enabled = false; } + phydev->eee_enabled = data->eee_enabled; + ret = genphy_c45_an_config_eee_aneg(phydev); - if (ret < 0) - return ret; if (ret > 0) return phy_restart_aneg(phydev); - return 0; + return ret; } EXPORT_SYMBOL(genphy_c45_ethtool_set_eee); From 4b2274d3811a25831068025ce20bf2adbd48c101 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 23 Feb 2024 07:39:25 -0600 Subject: [PATCH 1548/2255] net: ipa: don't bother aborting system resume The IPA interrupt can fire if there is data to be delivered to a GSI channel that is suspended. This condition occurs in three scenarios. First, runtime power management automatically suspends the IPA hardware after half a second of inactivity. This has nothing to do with system suspend, so a SYSTEM IPA power flag is used to avoid calling pm_wakeup_dev_event() when runtime suspended. Second, if the system is suspended, the receipt of an IPA interrupt should trigger a system resume. Configuring the IPA interrupt for wakeup accomplishes this. Finally, if system suspend is underway and the IPA interrupt fires, we currently call pm_wakeup_dev_event() to abort the system suspend. The IPA driver correctly handles quiescing the hardware before suspending it, so there's really no need to abort a suspend in progress in the third case. We can simply quiesce and suspend things, and be done. Incoming data can still wake the system after it's suspended. The IPA interrupt has wakeup mode enabled, so if it fires *after* we've suspended, it will trigger a wakeup (if not disabled via sysfs). Stop calling pm_wakeup_dev_event() to abort a system suspend in progress in ipa_power_suspend_handler(). Signed-off-by: Alex Elder Signed-off-by: Paolo Abeni --- drivers/net/ipa/ipa_power.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index 128a816f6523..694bc71e0a17 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -220,8 +220,9 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) * system suspend, trigger a system resume. */ if (!__test_and_set_bit(IPA_POWER_FLAG_RESUMED, ipa->power->flags)) - if (test_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags)) - pm_wakeup_dev_event(&ipa->pdev->dev, 0, true); + if (test_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags)) { + ; + } /* Acknowledge/clear the suspend interrupt on all endpoints */ ipa_interrupt_suspend_clear_all(ipa->interrupt); From 54f19ff7676fc60572f1e4725908094032523a95 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 23 Feb 2024 07:39:26 -0600 Subject: [PATCH 1549/2255] net: ipa: kill IPA_POWER_FLAG_SYSTEM The SYSTEM IPA power flag is set, cleared, and tested. But nothing happens based on its value when tested, so it serves no purpose. Get rid of this flag. Signed-off-by: Alex Elder Signed-off-by: Paolo Abeni --- drivers/net/ipa/ipa_power.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index 694bc71e0a17..be9e859e853f 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -37,12 +37,10 @@ /** * enum ipa_power_flag - IPA power flags * @IPA_POWER_FLAG_RESUMED: Whether resume from suspend has been signaled - * @IPA_POWER_FLAG_SYSTEM: Hardware is system (not runtime) suspended * @IPA_POWER_FLAG_COUNT: Number of defined power flags */ enum ipa_power_flag { IPA_POWER_FLAG_RESUMED, - IPA_POWER_FLAG_SYSTEM, IPA_POWER_FLAG_COUNT, /* Last; not a flag */ }; @@ -173,8 +171,6 @@ static int ipa_suspend(struct device *dev) { struct ipa *ipa = dev_get_drvdata(dev); - __set_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags); - /* Increment the disable depth to ensure that the IRQ won't * be re-enabled until the matching _enable call in * ipa_resume(). We do this to ensure that the interrupt @@ -196,8 +192,6 @@ static int ipa_resume(struct device *dev) ret = pm_runtime_force_resume(dev); - __clear_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags); - /* Now that PM runtime is enabled again it's safe * to turn the IRQ back on and process any data * that was received during suspend. @@ -219,10 +213,9 @@ void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) * just to handle the interrupt, so we're done. If we are in a * system suspend, trigger a system resume. */ - if (!__test_and_set_bit(IPA_POWER_FLAG_RESUMED, ipa->power->flags)) - if (test_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags)) { - ; - } + if (!__test_and_set_bit(IPA_POWER_FLAG_RESUMED, ipa->power->flags)) { + ; + } /* Acknowledge/clear the suspend interrupt on all endpoints */ ipa_interrupt_suspend_clear_all(ipa->interrupt); From dae5d6e8f0ecbed0481a1a1cc11399f65b0a9b8a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 23 Feb 2024 07:39:27 -0600 Subject: [PATCH 1550/2255] net: ipa: kill the IPA_POWER_FLAG_RESUMED flag The IPA_POWER_FLAG_RESUMED was originally used to avoid calling pm_wakeup_dev_event() more than once when handling a SUSPEND interrupt. This call is no longer made, so there' no need for the flag, so get rid of it. That leaves no more IPA power flags usefully defined, so just get rid of the bitmap in the IPA power structure and the definition of the ipa_power_flag enumerated type. Signed-off-by: Alex Elder Signed-off-by: Paolo Abeni --- drivers/net/ipa/ipa_power.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index be9e859e853f..eee251d67f81 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -34,22 +34,11 @@ #define IPA_AUTOSUSPEND_DELAY 500 /* milliseconds */ -/** - * enum ipa_power_flag - IPA power flags - * @IPA_POWER_FLAG_RESUMED: Whether resume from suspend has been signaled - * @IPA_POWER_FLAG_COUNT: Number of defined power flags - */ -enum ipa_power_flag { - IPA_POWER_FLAG_RESUMED, - IPA_POWER_FLAG_COUNT, /* Last; not a flag */ -}; - /** * struct ipa_power - IPA power management information * @dev: IPA device pointer * @core: IPA core clock * @qmp: QMP handle for AOSS communication - * @flags: Boolean state flags * @interconnect_count: Number of elements in interconnect[] * @interconnect: Interconnect array */ @@ -57,7 +46,6 @@ struct ipa_power { struct device *dev; struct clk *core; struct qmp *qmp; - DECLARE_BITMAP(flags, IPA_POWER_FLAG_COUNT); u32 interconnect_count; struct icc_bulk_data interconnect[] __counted_by(interconnect_count); }; @@ -139,7 +127,6 @@ static int ipa_runtime_suspend(struct device *dev) /* Endpoints aren't usable until setup is complete */ if (ipa->setup_complete) { - __clear_bit(IPA_POWER_FLAG_RESUMED, ipa->power->flags); ipa_endpoint_suspend(ipa); gsi_suspend(&ipa->gsi); } @@ -209,14 +196,6 @@ u32 ipa_core_clock_rate(struct ipa *ipa) void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) { - /* To handle an IPA interrupt we will have resumed the hardware - * just to handle the interrupt, so we're done. If we are in a - * system suspend, trigger a system resume. - */ - if (!__test_and_set_bit(IPA_POWER_FLAG_RESUMED, ipa->power->flags)) { - ; - } - /* Acknowledge/clear the suspend interrupt on all endpoints */ ipa_interrupt_suspend_clear_all(ipa->interrupt); } From ef63ca78da2e5cfbf7b795345cb9649902b77022 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 23 Feb 2024 07:39:28 -0600 Subject: [PATCH 1551/2255] net: ipa: move ipa_interrupt_suspend_clear_all() up The next patch makes ipa_interrupt_suspend_clear_all() static, calling it only within "ipa_interrupt.c". Move its definition higher in the file so no declaration is needed. Signed-off-by: Alex Elder Signed-off-by: Paolo Abeni --- drivers/net/ipa/ipa_interrupt.c | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index a78c692f2d3c..e5e01655e8c2 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -43,6 +43,30 @@ struct ipa_interrupt { u32 enabled; }; +/* Clear the suspend interrupt for all endpoints that signaled it */ +void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt) +{ + struct ipa *ipa = interrupt->ipa; + u32 unit_count; + u32 unit; + + unit_count = DIV_ROUND_UP(ipa->endpoint_count, 32); + for (unit = 0; unit < unit_count; unit++) { + const struct reg *reg; + u32 val; + + reg = ipa_reg(ipa, IRQ_SUSPEND_INFO); + val = ioread32(ipa->reg_virt + reg_n_offset(reg, unit)); + + /* SUSPEND interrupt status isn't cleared on IPA version 3.0 */ + if (ipa->version == IPA_VERSION_3_0) + continue; + + reg = ipa_reg(ipa, IRQ_SUSPEND_CLR); + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, unit)); + } +} + /* Process a particular interrupt type that has been received */ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id) { @@ -205,30 +229,6 @@ ipa_interrupt_suspend_disable(struct ipa_interrupt *interrupt, u32 endpoint_id) ipa_interrupt_suspend_control(interrupt, endpoint_id, false); } -/* Clear the suspend interrupt for all endpoints that signaled it */ -void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt) -{ - struct ipa *ipa = interrupt->ipa; - u32 unit_count; - u32 unit; - - unit_count = DIV_ROUND_UP(ipa->endpoint_count, 32); - for (unit = 0; unit < unit_count; unit++) { - const struct reg *reg; - u32 val; - - reg = ipa_reg(ipa, IRQ_SUSPEND_INFO); - val = ioread32(ipa->reg_virt + reg_n_offset(reg, unit)); - - /* SUSPEND interrupt status isn't cleared on IPA version 3.0 */ - if (ipa->version == IPA_VERSION_3_0) - continue; - - reg = ipa_reg(ipa, IRQ_SUSPEND_CLR); - iowrite32(val, ipa->reg_virt + reg_n_offset(reg, unit)); - } -} - /* Simulate arrival of an IPA TX_SUSPEND interrupt */ void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt) { From 423df2e09d3b893ce83bc35ca81657829604968e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 23 Feb 2024 07:39:29 -0600 Subject: [PATCH 1552/2255] net: ipa: kill ipa_power_suspend_handler() Now that ipa_power_suspend_handler() is a trivial wrapper around ipa_interrupt_suspend_clear_all(), we can open-code it in the one place it's used, and get rid of the function. Signed-off-by: Alex Elder Signed-off-by: Paolo Abeni --- drivers/net/ipa/ipa_interrupt.c | 4 ++-- drivers/net/ipa/ipa_interrupt.h | 8 -------- drivers/net/ipa/ipa_power.c | 6 ------ drivers/net/ipa/ipa_power.h | 11 ----------- 4 files changed, 2 insertions(+), 27 deletions(-) diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index e5e01655e8c2..501962cc4e90 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -44,7 +44,7 @@ struct ipa_interrupt { }; /* Clear the suspend interrupt for all endpoints that signaled it */ -void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt) +static void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt) { struct ipa *ipa = interrupt->ipa; u32 unit_count; @@ -94,7 +94,7 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id) * caused the interrupt, so defer clearing until after * the handler has been called. */ - ipa_power_suspend_handler(ipa, irq_id); + ipa_interrupt_suspend_clear_all(interrupt); fallthrough; default: /* Silently ignore (and clear) any other condition */ diff --git a/drivers/net/ipa/ipa_interrupt.h b/drivers/net/ipa/ipa_interrupt.h index 12e3e798ccb3..53e1b71685c7 100644 --- a/drivers/net/ipa/ipa_interrupt.h +++ b/drivers/net/ipa/ipa_interrupt.h @@ -34,14 +34,6 @@ void ipa_interrupt_suspend_enable(struct ipa_interrupt *interrupt, void ipa_interrupt_suspend_disable(struct ipa_interrupt *interrupt, u32 endpoint_id); -/** - * ipa_interrupt_suspend_clear_all - clear all suspend interrupts - * @interrupt: IPA interrupt structure - * - * Clear the TX_SUSPEND interrupt for all endpoints that signaled it. - */ -void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt); - /** * ipa_interrupt_simulate_suspend() - Simulate TX_SUSPEND IPA interrupt * @interrupt: IPA interrupt structure diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index eee251d67f81..0f635b8356bf 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -194,12 +194,6 @@ u32 ipa_core_clock_rate(struct ipa *ipa) return ipa->power ? (u32)clk_get_rate(ipa->power->core) : 0; } -void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) -{ - /* Acknowledge/clear the suspend interrupt on all endpoints */ - ipa_interrupt_suspend_clear_all(ipa->interrupt); -} - static int ipa_power_retention_init(struct ipa_power *power) { struct qmp *qmp = qmp_get(power->dev); diff --git a/drivers/net/ipa/ipa_power.h b/drivers/net/ipa/ipa_power.h index 718aacf5e2b2..227cc04bea80 100644 --- a/drivers/net/ipa/ipa_power.h +++ b/drivers/net/ipa/ipa_power.h @@ -30,17 +30,6 @@ u32 ipa_core_clock_rate(struct ipa *ipa); */ void ipa_power_retention(struct ipa *ipa, bool enable); -/** - * ipa_power_suspend_handler() - Handler for SUSPEND IPA interrupts - * @ipa: IPA pointer - * @irq_id: IPA interrupt ID (unused) - * - * If an RX endpoint is suspended, and the IPA has a packet destined for - * that endpoint, the IPA generates a SUSPEND interrupt to inform the AP - * that it should resume the endpoint. - */ -void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id); - /** * ipa_power_setup() - Set up IPA power management * @ipa: IPA pointer From f9345952e74a77ba905b5a23252bffde48162ef3 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 23 Feb 2024 07:39:30 -0600 Subject: [PATCH 1553/2255] net: ipa: don't bother zeroing an already zero register In ipa_interrupt_suspend_clear_all(), if the SUSPEND_INFO register read contains no set bits, there's no interrupt condition to clear. Skip the write to the clear register in that case. Signed-off-by: Alex Elder Signed-off-by: Paolo Abeni --- drivers/net/ipa/ipa_interrupt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index 501962cc4e90..4d80bf77a532 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -59,7 +59,7 @@ static void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt) val = ioread32(ipa->reg_virt + reg_n_offset(reg, unit)); /* SUSPEND interrupt status isn't cleared on IPA version 3.0 */ - if (ipa->version == IPA_VERSION_3_0) + if (!val || ipa->version == IPA_VERSION_3_0) continue; reg = ipa_reg(ipa, IRQ_SUSPEND_CLR); From 2322467a0f5d6cf05752092938e6db1250a0b28e Mon Sep 17 00:00:00 2001 From: Ciprian Regus Date: Fri, 23 Feb 2024 18:21:27 +0200 Subject: [PATCH 1554/2255] net: ethernet: adi: adin1110: Reduce the MDIO_TRDONE poll interval In order to do a clause 22 access to the PHY registers of the ADIN1110, we have to write the MDIO frame to the ADIN1110_MDIOACC register, and then poll the MDIO_TRDONE bit (for a 1) in the same register. The device will set this bit to 1 once the internal MDIO transaction is done. In practice, this bit takes ~50 - 60 us to be set. The first attempt to poll the bit is right after the ADIN1110_MDIOACC register is written, so it will always be read as 0. The next check will only be done after 10 ms, which will result in the MDIO transactions taking a long time to complete. Reduce this polling interval to 100 us. Since this interval is short enough, switch the poll function to readx_poll_timeout_atomic() instead. Reviewed-by: Nuno Sa Signed-off-by: Ciprian Regus Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240223162129.154114-1-ciprian.regus@analog.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/adi/adin1110.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index d7c274af6d4d..8b4ef5121308 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -464,8 +464,9 @@ static int adin1110_mdio_read(struct mii_bus *bus, int phy_id, int reg) * bitfield of ADIN1110_MDIOACC register will contain * the requested register value. */ - ret = readx_poll_timeout(adin1110_read_mdio_acc, priv, val, - (val & ADIN1110_MDIO_TRDONE), 10000, 30000); + ret = readx_poll_timeout_atomic(adin1110_read_mdio_acc, priv, val, + (val & ADIN1110_MDIO_TRDONE), + 100, 30000); if (ret < 0) return ret; @@ -495,8 +496,9 @@ static int adin1110_mdio_write(struct mii_bus *bus, int phy_id, if (ret < 0) return ret; - return readx_poll_timeout(adin1110_read_mdio_acc, priv, val, - (val & ADIN1110_MDIO_TRDONE), 10000, 30000); + return readx_poll_timeout_atomic(adin1110_read_mdio_acc, priv, val, + (val & ADIN1110_MDIO_TRDONE), + 100, 30000); } /* ADIN1110 MAC-PHY contains an ADIN1100 PHY. From aceb147b20a2eda9a10bdd4b5650718f731ef3e1 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 22 Feb 2024 06:41:17 -0800 Subject: [PATCH 1555/2255] xfrm: Do not allocate stats in the driver With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the xfrm driver and leverage the network core allocation. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_interface_core.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/net/xfrm/xfrm_interface_core.c b/net/xfrm/xfrm_interface_core.c index 21d50d75c260..1a1f6613fda2 100644 --- a/net/xfrm/xfrm_interface_core.c +++ b/net/xfrm/xfrm_interface_core.c @@ -240,7 +240,6 @@ static void xfrmi_dev_free(struct net_device *dev) struct xfrm_if *xi = netdev_priv(dev); gro_cells_destroy(&xi->gro_cells); - free_percpu(dev->tstats); } static int xfrmi_create(struct net_device *dev) @@ -749,6 +748,7 @@ static void xfrmi_dev_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->needs_free_netdev = true; dev->priv_destructor = xfrmi_dev_free; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; netif_keep_dst(dev); eth_broadcast_addr(dev->broadcast); @@ -765,15 +765,9 @@ static int xfrmi_dev_init(struct net_device *dev) struct net_device *phydev = __dev_get_by_index(xi->net, xi->p.link); int err; - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - err = gro_cells_init(&xi->gro_cells, dev); - if (err) { - free_percpu(dev->tstats); + if (err) return err; - } dev->features |= NETIF_F_LLTX; dev->features |= XFRMI_FEATURES; From d0dc1e42109da515db92901ca07270930f15d619 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Fri, 23 Feb 2024 21:37:01 +0100 Subject: [PATCH 1556/2255] net: stmmac: mmc_core: Drop interrupt registers from stats The MMC IPC interrupt status and interrupt mask registers are of little use as Ethernet statistics, but incrementing counters based on the current interrupt and interrupt mask registers makes them actively misleading. For example, if the interrupt mask is set to 0x08420842, the current code will increment by that amount each iteration, leading to the following sequence of nonsense: mmc_rx_ipc_intr_mask: 969816526 mmc_rx_ipc_intr_mask: 1108361744 These registers have been included in the Ethernet statistics since the first version of MMC back in 2011 (commit 1c901a46d57). That commit also mentions the MMC interrupts as "something to add later (if actually useful)". If the registers are actually useful, they should probably be part of the Ethernet register dump instead of statistics, but for now, drop the counters for mmc_rx_ipc_intr and mmc_rx_ipc_intr_mask completely. Reviewed-by: Serge Semin Signed-off-by: Jesper Nilsson Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240223-stmmac_stats-v3-1-5d483c2a071a@axis.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/mmc.h | 4 ---- drivers/net/ethernet/stmicro/stmmac/mmc_core.c | 3 --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 -- 3 files changed, 9 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h index 14c9d2637dfe..dff02d75d519 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc.h +++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h @@ -86,10 +86,6 @@ struct stmmac_counters { unsigned int mmc_rx_discard_octets_gb; unsigned int mmc_rx_align_err_frames; - /* IPC */ - unsigned int mmc_rx_ipc_intr_mask; - unsigned int mmc_rx_ipc_intr; - /* IPv4 */ unsigned int mmc_rx_ipv4_gd; unsigned int mmc_rx_ipv4_hderr; diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index 8597c6abae8d..7eb477faa75a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c @@ -316,9 +316,6 @@ static void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc) mmc->mmc_rx_fifo_overflow += readl(mmcaddr + MMC_RX_FIFO_OVERFLOW); mmc->mmc_rx_vlan_frames_gb += readl(mmcaddr + MMC_RX_VLAN_FRAMES_GB); mmc->mmc_rx_watchdog_error += readl(mmcaddr + MMC_RX_WATCHDOG_ERROR); - /* IPC */ - mmc->mmc_rx_ipc_intr_mask += readl(mmcaddr + MMC_RX_IPC_INTR_MASK); - mmc->mmc_rx_ipc_intr += readl(mmcaddr + MMC_RX_IPC_INTR); /* IPv4 */ mmc->mmc_rx_ipv4_gd += readl(mmcaddr + MMC_RX_IPV4_GD); mmc->mmc_rx_ipv4_hderr += readl(mmcaddr + MMC_RX_IPV4_HDERR); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 0e44b84fb7e7..e1537a57815f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -243,8 +243,6 @@ static const struct stmmac_stats stmmac_mmc[] = { STMMAC_MMC_STAT(mmc_rx_discard_frames_gb), STMMAC_MMC_STAT(mmc_rx_discard_octets_gb), STMMAC_MMC_STAT(mmc_rx_align_err_frames), - STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask), - STMMAC_MMC_STAT(mmc_rx_ipc_intr), STMMAC_MMC_STAT(mmc_rx_ipv4_gd), STMMAC_MMC_STAT(mmc_rx_ipv4_hderr), STMMAC_MMC_STAT(mmc_rx_ipv4_nopay), From b819a8481a19043ca990980dd56b1a41389c665c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 23 Feb 2024 21:06:58 -0800 Subject: [PATCH 1557/2255] selftests: netdevsim: be less selective for FW for the devlink test Commit 6151ff9c7521 ("selftests: netdevsim: use suitable existing dummy file for flash test") introduced a nice trick to the devlink flashing test. Instead of user having to create a file under /lib/firmware we just pick the first one that already exists. Sadly, in AWS Linux there are no files directly under /lib/firmware, only in subdirectories. Don't limit the search to -maxdepth 1. We can use the %P print format to get the correct path for files inside subdirectories: $ find /lib/firmware -type f -printf '%P\n' | head -1 intel-ucode/06-1a-05 The full path is /lib/firmware/intel-ucode/06-1a-05 This works in GNU find, busybox doesn't have printf at all, so we're not making it worse. Signed-off-by: Jakub Kicinski Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240224050658.930272-1-kuba@kernel.org Signed-off-by: Paolo Abeni --- tools/testing/selftests/drivers/net/netdevsim/devlink.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh index 46e20b13473c..b5ea2526f23c 100755 --- a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh +++ b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh @@ -31,7 +31,7 @@ devlink_wait() fw_flash_test() { - DUMMYFILE=$(find /lib/firmware -maxdepth 1 -type f -printf '%f\n' |head -1) + DUMMYFILE=$(find /lib/firmware -type f -printf '%P\n' | head -1) RET=0 if [ -z "$DUMMYFILE" ] From ec1aae190c7729ffdd3603de311dc00f7ff988f9 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 16 Feb 2024 13:27:56 -0600 Subject: [PATCH 1558/2255] wifi: brcmfmac: fweh: Fix boot crash on Raspberry Pi 4 Fix boot crash on Raspberry Pi by moving the update to `event->datalen` before data is copied into flexible-array member `data` via `memcpy()`. Flexible-array member `data` was annotated with `__counted_by(datalen)` in commit 62d19b358088 ("wifi: brcmfmac: fweh: Add __counted_by for struct brcmf_fweh_queue_item and use struct_size()"). The intention of this is to gain visibility into the size of `data` at run-time through its _counter_ (in this case `datalen`), and with this have its accesses bounds-checked at run-time via CONFIG_FORTIFY_SOURCE and CONFIG_UBSAN_BOUNDS. To effectively accomplish the above, we shall update the counter (`datalen`), before the first access to the flexible array (`data`), which was also done in the mentioned commit. However, commit edec42821911 ("wifi: brcmfmac: allow per-vendor event handling") inadvertently caused a buffer overflow, detected by FORTIFY_SOURCE. It moved the `event->datalen = datalen;` update to after the first `data` access, at which point `event->datalen` was not yet updated from zero (after calling `kzalloc()`), leading to the overflow issue. This fix repositions the `event->datalen = datalen;` update before accessing `data`, restoring the intended buffer overflow protection. :) Fixes: edec42821911 ("wifi: brcmfmac: allow per-vendor event handling") Reported-by: Nathan Chancellor Closes: https://gist.github.com/nathanchance/e22f681f3bfc467f15cdf6605021aaa6 Tested-by: Nathan Chancellor Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Acked-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/Zc+3PFCUvLoVlpg8@neat --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index 0774f6c59226..f0b6a7607f16 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -497,12 +497,12 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, return; event->code = fwevt_idx; + event->datalen = datalen; event->ifidx = event_packet->msg.ifidx; /* use memcpy to get aligned event message */ memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); memcpy(event->data, data, datalen); - event->datalen = datalen; memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); brcmf_fweh_queue_event(fweh, event); From dc10daddfeb1252e9fd170da086ac2d43f8f7272 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Thu, 22 Feb 2024 14:42:56 +0800 Subject: [PATCH 1559/2255] wifi: rtw89: advertise missing extended scan feature Add support for random serial number in probe request and configure channel dwell time. Advertise corresponding feature flag NL80211_EXT_FEATURE_SCAN_RANDOM_SN and NL80211_EXT_FEATURE_SET_SCAN_DWELL. Use the scan request duration as channel dwell time when it is non-zero, otherwise use the default value. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240222064258.59782-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 2 ++ drivers/net/wireless/realtek/rtw89/fw.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index f697e3d898e6..d4bca8cd08f2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4505,6 +4505,8 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) hw->wiphy->max_remain_on_channel_duration = 1000; wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SCAN_RANDOM_SN); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); ret = rtw89_core_set_supported_band(rtwdev); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 63897351ca15..f654ad4c2546 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -5739,7 +5739,7 @@ int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, goto out; } - if (req->duration_mandatory) + if (req->duration) ch_info->period = req->duration; else if (channel->band == NL80211_BAND_6GHZ) ch_info->period = RTW89_CHANNEL_TIME_6G + @@ -5817,7 +5817,7 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, goto out; } - if (req->duration_mandatory) + if (req->duration) ch_info->period = req->duration; else if (channel->band == NL80211_BAND_6GHZ) ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G; From 6ebe995542d0aafcee234dc8cdf50cbb24279591 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Thu, 22 Feb 2024 14:42:57 +0800 Subject: [PATCH 1560/2255] wifi: rtw89: Update EHT PHY beamforming capability Adjust beamforming capabilities to accurately reflect the supported EHT features by WiFi 7 chip 8922A. It includes 1) Unset EHT CQI feedback and 16-subcarrier grouping. 2) Correct Beamformee SS value. 3) Enable partial and full bandwidth SU/MU feedback. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240222064258.59782-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index d4bca8cd08f2..d474b8d5df3d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3801,7 +3801,7 @@ static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, struct ieee80211_sta_eht_cap *eht_cap; struct rtw89_hal *hal = &rtwdev->hal; bool support_320mhz = false; - int sts = 3; + int sts = 8; u8 val; if (chip->chip_gen == RTW89_CHIP_AX) @@ -3845,18 +3845,16 @@ static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, eht_cap_elem->phy_cap_info[2] = 0; eht_cap_elem->phy_cap_info[3] = - IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | - IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK; + IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK; eht_cap_elem->phy_cap_info[4] = IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | u8_encode_bits(1, IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK); eht_cap_elem->phy_cap_info[5] = - IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US, IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); From 53fe234f15b9e45a699591828950b1c3416da239 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Thu, 22 Feb 2024 14:42:58 +0800 Subject: [PATCH 1561/2255] wifi: rtw89: pci: implement PCI CLK/ASPM/L1SS for WiFi 7 chips PCI CLK/ASPM/L1SS is power management mechanism used to reduce power consumption of PCI chip. The registers for setting of these features in WiFi 7 Chip are different from WiFi 6 chip, so separate them in generation information. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240222064258.59782-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 50 ++++++++++++++++---- drivers/net/wireless/realtek/rtw89/pci.h | 30 ++++++++++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 52 +++++++++++++++++++++ 3 files changed, 122 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 67d7294e488a..d4c8799d6f2e 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -3652,12 +3652,20 @@ static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev) static void rtw89_pci_clkreq_set(struct rtw89_dev *rtwdev, bool enable) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - int ret; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; if (rtw89_pci_disable_clkreq) return; + gen_def->clkreq_set(rtwdev, enable); +} + +static void rtw89_pci_clkreq_set_ax(struct rtw89_dev *rtwdev, bool enable) +{ + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + int ret; + ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_CLK_CTRL, PCIE_CLKDLY_HW_30US); if (ret) @@ -3689,24 +3697,31 @@ static void rtw89_pci_clkreq_set(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; - u8 value = 0; - int ret; + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; if (rtw89_pci_disable_aspm_l1) return; + gen_def->aspm_set(rtwdev, enable); +} + +static void rtw89_pci_aspm_set_ax(struct rtw89_dev *rtwdev, bool enable) +{ + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + u8 value = 0; + int ret; + ret = rtw89_pci_read_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, &value); if (ret) - rtw89_err(rtwdev, "failed to read ASPM Delay\n"); + rtw89_warn(rtwdev, "failed to read ASPM Delay\n"); - value &= ~(RTW89_L1DLY_MASK | RTW89_L0DLY_MASK); - value |= FIELD_PREP(RTW89_L1DLY_MASK, PCIE_L1DLY_16US) | - FIELD_PREP(RTW89_L0DLY_MASK, PCIE_L0SDLY_4US); + u8p_replace_bits(&value, PCIE_L1DLY_16US, RTW89_L1DLY_MASK); + u8p_replace_bits(&value, PCIE_L0SDLY_4US, RTW89_L0DLY_MASK); ret = rtw89_pci_write_config_byte(rtwdev, RTW89_PCIE_ASPM_CTRL, value); if (ret) - rtw89_err(rtwdev, "failed to read ASPM Delay\n"); + rtw89_warn(rtwdev, "failed to read ASPM Delay\n"); if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) { if (enable) @@ -3792,6 +3807,17 @@ static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev) } static void rtw89_pci_l1ss_set(struct rtw89_dev *rtwdev, bool enable) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + if (rtw89_pci_disable_l1ss) + return; + + gen_def->l1ss_set(rtwdev, enable); +} + +static void rtw89_pci_l1ss_set_ax(struct rtw89_dev *rtwdev, bool enable) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; int ret; @@ -4066,6 +4092,10 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_ax, .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_ax, + + .aspm_set = rtw89_pci_aspm_set_ax, + .clkreq_set = rtw89_pci_clkreq_set_ax, + .l1ss_set = rtw89_pci_l1ss_set_ax, }; EXPORT_SYMBOL(rtw89_pci_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 532f78eaf6df..c1954cb12030 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -282,6 +282,21 @@ #define B_BE_PCIE_EN_SWENT_L23 BIT(1) #define B_BE_SEL_REQ_EXIT_L1 BIT(0) +#define R_BE_PCIE_MIX_CFG 0x300C +#define B_BE_L1SS_TIMEOUT_CTRL BIT(18) +#define B_BE_ASPM_CTRL_L1 BIT(17) +#define B_BE_ASPM_CTRL_L0 BIT(16) +#define B_BE_XFER_PENDING_FW BIT(11) +#define B_BE_XFER_PENDING BIT(10) +#define B_BE_REQ_EXIT_L1 BIT(9) +#define B_BE_REQ_ENTR_L1 BIT(8) +#define B_BE_L1SUB_ENABLE BIT(0) + +#define R_BE_L1_CLK_CTRL 0x3010 +#define B_BE_RAS_SD_HOLD_LTSSM BIT(12) +#define B_BE_CLK_REQ_N BIT(1) +#define B_BE_CLK_PM_EN BIT(0) + #define R_BE_PCIE_LAT_CTRL 0x3044 #define B_BE_ELBI_PHY_REMAP_MASK GENMASK(29, 24) #define B_BE_SYS_SUS_L12_EN BIT(17) @@ -290,6 +305,8 @@ #define B_BE_RTK_LDO_POWER_LATENCY_MASK GENMASK(11, 10) #define B_BE_RTK_LDO_BIAS_LATENCY_MASK GENMASK(9, 8) #define B_BE_CLK_REQ_LAT_MASK GENMASK(7, 4) +#define B_BE_RTK_PM_SEL_OPT BIT(1) +#define B_BE_CLK_REQ_SEL BIT(0) #define R_BE_PCIE_HIMR0 0x30B0 #define B_BE_PCIE_HB1_IND_INTA_IMR BIT(31) @@ -1066,6 +1083,15 @@ enum rtw89_pcie_clkdly_hw { PCIE_CLKDLY_HW_200US = 0x5, }; +enum rtw89_pcie_clkdly_hw_v1 { + PCIE_CLKDLY_HW_V1_0 = 0, + PCIE_CLKDLY_HW_V1_16US = 0x1, + PCIE_CLKDLY_HW_V1_32US = 0x2, + PCIE_CLKDLY_HW_V1_64US = 0x3, + PCIE_CLKDLY_HW_V1_80US = 0x4, + PCIE_CLKDLY_HW_V1_96US = 0x5, +}; + enum mac_ax_bd_trunc_mode { MAC_AX_BD_NORM, MAC_AX_BD_TRUNC, @@ -1216,6 +1242,10 @@ struct rtw89_pci_gen_def { int (*lv1rst_stop_dma)(struct rtw89_dev *rtwdev); int (*lv1rst_start_dma)(struct rtw89_dev *rtwdev); + + void (*aspm_set)(struct rtw89_dev *rtwdev, bool enable); + void (*clkreq_set)(struct rtw89_dev *rtwdev, bool enable); + void (*l1ss_set)(struct rtw89_dev *rtwdev, bool enable); }; struct rtw89_pci_info { diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 5c9e39357773..0276d5d05925 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -19,6 +19,54 @@ enum pcie_rxbd_mode { #define PL0_TMR_MAC_1MS 0x27100 #define PL0_TMR_AUX_1MS 0x1E848 +static void rtw89_pci_aspm_set_be(struct rtw89_dev *rtwdev, bool enable) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct pci_dev *pdev = rtwpci->pdev; + u8 value = 0; + int ret; + + ret = pci_read_config_byte(pdev, RTW89_PCIE_ASPM_CTRL, &value); + if (ret) + rtw89_warn(rtwdev, "failed to read ASPM Delay\n"); + + u8p_replace_bits(&value, PCIE_L1DLY_16US, RTW89_L1DLY_MASK); + + ret = pci_write_config_byte(pdev, RTW89_PCIE_ASPM_CTRL, value); + if (ret) + rtw89_warn(rtwdev, "failed to write ASPM Delay\n"); + + if (enable) + rtw89_write32_set(rtwdev, R_AX_PCIE_MIX_CFG_V1, + B_BE_ASPM_CTRL_L1); + else + rtw89_write32_clr(rtwdev, R_AX_PCIE_MIX_CFG_V1, + B_BE_ASPM_CTRL_L1); +} + +static void rtw89_pci_l1ss_set_be(struct rtw89_dev *rtwdev, bool enable) +{ + if (enable) + rtw89_write32_set(rtwdev, R_BE_PCIE_MIX_CFG, + B_BE_L1SUB_ENABLE); + else + rtw89_write32_clr(rtwdev, R_BE_PCIE_MIX_CFG, + B_BE_L1SUB_ENABLE); +} + +static void rtw89_pci_clkreq_set_be(struct rtw89_dev *rtwdev, bool enable) +{ + rtw89_write32_mask(rtwdev, R_BE_PCIE_LAT_CTRL, B_BE_CLK_REQ_LAT_MASK, + PCIE_CLKDLY_HW_V1_0); + + if (enable) + rtw89_write32_set(rtwdev, R_BE_L1_CLK_CTRL, + B_BE_CLK_PM_EN); + else + rtw89_write32_clr(rtwdev, R_AX_L1_CLK_CTRL, + B_BE_CLK_PM_EN); +} + static void _patch_pcie_power_wake_be(struct rtw89_dev *rtwdev, bool power_up) { if (power_up) @@ -510,5 +558,9 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_be, .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_be, + + .aspm_set = rtw89_pci_aspm_set_be, + .clkreq_set = rtw89_pci_clkreq_set_be, + .l1ss_set = rtw89_pci_l1ss_set_be, }; EXPORT_SYMBOL(rtw89_pci_gen_be); From 379e5e83f9f9a0d3d3318fee2f363278e7ab08e7 Mon Sep 17 00:00:00 2001 From: Alexey Berezhok Date: Thu, 22 Feb 2024 15:29:23 +0300 Subject: [PATCH 1562/2255] wifi: brcmfmac: do not pass hidden SSID attribute as value directly In brcmf_cfg80211_start_ap() do not assume that NL80211_HIDDEN_SSID_NOT_IN_USE is zero but prefer an explicit check instead. Use local variable 'closednet' to pass in function call and use for error message. Compile tested only. Addition for the commit f20073f50dfd1 ("wifi: brcmfmac: do not cast hidden SSID attribute value to boolean"). Signed-off-by: Alexey Berezhok Acked-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240222122923.46691-1-a@bayrepo.ru --- .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index adf8a14feb49..54ff59a8c35c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5101,6 +5101,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, bool mbss; int is_11d; bool supports_11d; + bool closednet; brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", settings->chandef.chan->hw_value, @@ -5270,12 +5271,12 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, goto exit; } - err = brcmf_fil_iovar_int_set(ifp, "closednet", - settings->hidden_ssid); + closednet = + (settings->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); + err = brcmf_fil_iovar_int_set(ifp, "closednet", closednet); if (err) { bphy_err(drvr, "%s closednet error (%d)\n", - (settings->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) ? - "enabled" : "disabled", + (closednet ? "enabled" : "disabled"), err); goto exit; } From c4b04a802d8e3996e588cbbb47756b2f9d239d78 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Mon, 26 Feb 2024 15:49:11 +0100 Subject: [PATCH 1563/2255] bnxt_en: fix accessing vnic_info before allocating it bnxt_alloc_mem() dereferences ::vnic_info in the variable declaration block, but allocates it much later. As a result, the following crash happens on my setup: BUG: kernel NULL pointer dereference, address: 0000000000000090 fbcon: Taking over console #PF: supervisor write access in kernel mode #PF: error_code (0x0002) - not-present page PGD 12f382067 P4D 0 Oops: 8002 [#1] PREEMPT SMP NOPTI CPU: 47 PID: 2516 Comm: NetworkManager Not tainted 6.8.0-rc5-libeth+ #49 Hardware name: Intel Corporation M50CYP2SBSTD/M58CYP2SBSTD, BIOS SE5C620.86B.01.01.0088.2305172341 05/17/2023 RIP: 0010:bnxt_alloc_mem+0x1609/0x1910 [bnxt_en] Code: 81 c8 48 83 c8 08 31 c9 e9 d7 fe ff ff c7 44 24 Oc 00 00 00 00 49 89 d5 e9 2d fe ff ff 41 89 c6 e9 88 00 00 00 48 8b 44 24 50 <80> 88 90 00 00 00 Od 8b 43 74 a8 02 75 1e f6 83 14 02 00 00 80 74 RSP: 0018:ff3f25580f3432c8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ff15a5cfc45249e0 RCX: 0000002079777000 RDX: ff15a5dfb9767000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: ff15a5dfb9777000 R11: ffffff8000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000020 R15: ff15a5cfce34f540 FS: 000007fb9a160500(0000) GS:ff15a5dfbefc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CRO: 0000000080050033 CR2: 0000000000000090 CR3: 0000000109efc00Z CR4: 0000000000771ef0 DR0: 0000000000000000 DR1: 0000000000000000 DRZ: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: ? __die_body+0x68/0xb0 ? page_fault_oops+0x3a6/0x400 ? exc_page_fault+0x7a/0x1b0 ? asm_exc_page_fault+0x26/8x30 ? bnxt_alloc_mem+0x1609/0x1910 [bnxt_en] ? bnxt_alloc_mem+0x1389/8x1918 [bnxt_en] _bnxt_open_nic+0x198/0xa50 [bnxt_en] ? bnxt_hurm_if_change+0x287/0x3d0 [bnxt_en] bnxt_open+0xeb/0x1b0 [bnxt_en] _dev_open+0x12e/0x1f0 _dev_change_flags+0xb0/0x200 dev_change_flags+0x25/0x60 do_setlink+0x463/0x1260 ? sock_def_readable+0x14/0xc0 ? rtnl_getlink+0x4b9/0x590 ? _nla_validate_parse+0x91/0xfa0 rtnl_newlink+0xbac/0xe40 <...> Don't create a variable and dereference the first array member directly since it's used only once in the code. Fixes: ef4ee64e9990 ("bnxt_en: Define BNXT_VNIC_DEFAULT for the default vnic index") Signed-off-by: Alexander Lobakin Reviewed-by: Jiri Pirko Reviewed-by: Michael Chan Link: https://lore.kernel.org/r/20240226144911.1297336-1-aleksander.lobakin@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9968d67e6c77..a15e6d31fc22 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5004,7 +5004,6 @@ static void bnxt_free_mem(struct bnxt *bp, bool irq_re_init) static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) { - struct bnxt_vnic_info *vnic0 = &bp->vnic_info[BNXT_VNIC_DEFAULT]; int i, j, rc, size, arr_size; void *bnapi; @@ -5133,8 +5132,9 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) if (rc) goto alloc_mem_err; - vnic0->flags |= BNXT_VNIC_RSS_FLAG | BNXT_VNIC_MCAST_FLAG | - BNXT_VNIC_UCAST_FLAG; + bp->vnic_info[BNXT_VNIC_DEFAULT].flags |= BNXT_VNIC_RSS_FLAG | + BNXT_VNIC_MCAST_FLAG | + BNXT_VNIC_UCAST_FLAG; if (BNXT_SUPPORTS_NTUPLE_VNIC(bp) && (bp->flags & BNXT_FLAG_RFS)) bp->vnic_info[BNXT_VNIC_NTUPLE].flags |= BNXT_VNIC_RSS_FLAG | BNXT_VNIC_NTUPLE_FLAG; From f8cbf6bde4c8d5d32330bcceafa7b139fec89f97 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 24 Feb 2024 09:06:30 +0000 Subject: [PATCH 1564/2255] netlink: use kvmalloc() in netlink_alloc_large_skb() This is a followup of commit 234ec0b6034b ("netlink: fix potential sleeping issue in mqueue_flush_file"), because vfree_atomic() overhead is unfortunate for medium sized allocations. 1) If the allocation is smaller than PAGE_SIZE, do not bother with vmalloc() at all. Some arches have 64KB PAGE_SIZE, while NLMSG_GOODSIZE is smaller than 8KB. 2) Use kvmalloc(), which might allocate one high order page instead of vmalloc if memory is not too fragmented. Signed-off-by: Eric Dumazet Reviewed-by: Zhengchao Shao Link: https://lore.kernel.org/r/20240224090630.605917-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/netlink/af_netlink.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index be5792b638aa..765921cf1194 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1202,23 +1202,21 @@ struct sock *netlink_getsockbyfilp(struct file *filp) struct sk_buff *netlink_alloc_large_skb(unsigned int size, int broadcast) { + size_t head_size = SKB_HEAD_ALIGN(size); struct sk_buff *skb; void *data; - if (size <= NLMSG_GOODSIZE || broadcast) + if (head_size <= PAGE_SIZE || broadcast) return alloc_skb(size, GFP_KERNEL); - size = SKB_DATA_ALIGN(size) + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - - data = vmalloc(size); - if (data == NULL) + data = kvmalloc(head_size, GFP_KERNEL); + if (!data) return NULL; - skb = __build_skb(data, size); - if (skb == NULL) - vfree(data); - else + skb = __build_skb(data, head_size); + if (!skb) + kvfree(data); + else if (is_vmalloc_addr(data)) skb->destructor = netlink_skb_destructor; return skb; From e74cb1b422131615a0fe3bedd4ab2e38b7442d10 Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Thu, 1 Feb 2024 12:52:24 +0000 Subject: [PATCH 1565/2255] arm64: stacktrace: Implement arch_bpf_stack_walk() for the BPF JIT This will be used by bpf_throw() to unwind till the program marked as exception boundary and run the callback with the stack of the main program. This is required for supporting BPF exceptions on ARM64. Signed-off-by: Puranjay Mohan Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20240201125225.72796-2-puranjay12@gmail.com Signed-off-by: Alexei Starovoitov --- arch/arm64/kernel/stacktrace.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 7f88028a00c0..66cffc5fc0be 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -266,6 +267,31 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, kunwind_stack_walk(arch_kunwind_consume_entry, &data, task, regs); } +struct bpf_unwind_consume_entry_data { + bool (*consume_entry)(void *cookie, u64 ip, u64 sp, u64 fp); + void *cookie; +}; + +static bool +arch_bpf_unwind_consume_entry(const struct kunwind_state *state, void *cookie) +{ + struct bpf_unwind_consume_entry_data *data = cookie; + + return data->consume_entry(data->cookie, state->common.pc, 0, + state->common.fp); +} + +noinline noinstr void arch_bpf_stack_walk(bool (*consume_entry)(void *cookie, u64 ip, u64 sp, + u64 fp), void *cookie) +{ + struct bpf_unwind_consume_entry_data data = { + .consume_entry = consume_entry, + .cookie = cookie, + }; + + kunwind_stack_walk(arch_bpf_unwind_consume_entry, &data, current, NULL); +} + static bool dump_backtrace_entry(void *arg, unsigned long where) { char *loglvl = arg; From 22fc0e80aeb5c0c1377e6c02d7248f8fbf5df7fc Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Thu, 1 Feb 2024 12:52:25 +0000 Subject: [PATCH 1566/2255] bpf, arm64: support exceptions The prologue generation code has been modified to make the callback program use the stack of the program marked as exception boundary where callee-saved registers are already pushed. As the bpf_throw function never returns, if it clobbers any callee-saved registers, they would remain clobbered. So, the prologue of the exception-boundary program is modified to push R23 and R24 as well, which the callback will then recover in its epilogue. The Procedure Call Standard for the Arm 64-bit Architecture[1] states that registers r19 to r28 should be saved by the callee. BPF programs on ARM64 already save all callee-saved registers except r23 and r24. This patch adds an instruction in prologue of the program to save these two registers and another instruction in the epilogue to recover them. These extra instructions are only added if bpf_throw() is used. Otherwise the emitted prologue/epilogue remains unchanged. [1] https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst Signed-off-by: Puranjay Mohan Link: https://lore.kernel.org/r/20240201125225.72796-3-puranjay12@gmail.com Signed-off-by: Alexei Starovoitov --- arch/arm64/net/bpf_jit_comp.c | 85 +++++++++++++++----- tools/testing/selftests/bpf/DENYLIST.aarch64 | 1 - 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index cfd5434de483..20720ec346b8 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -285,7 +285,8 @@ static bool is_lsi_offset(int offset, int scale) /* Tail call offset to jump into */ #define PROLOGUE_OFFSET (BTI_INSNS + 2 + PAC_INSNS + 8) -static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf) +static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf, + bool is_exception_cb) { const struct bpf_prog *prog = ctx->prog; const bool is_main_prog = !bpf_is_subprog(prog); @@ -333,19 +334,34 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf) emit(A64_MOV(1, A64_R(9), A64_LR), ctx); emit(A64_NOP, ctx); - /* Sign lr */ - if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) - emit(A64_PACIASP, ctx); + if (!is_exception_cb) { + /* Sign lr */ + if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) + emit(A64_PACIASP, ctx); + /* Save FP and LR registers to stay align with ARM64 AAPCS */ + emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx); + emit(A64_MOV(1, A64_FP, A64_SP), ctx); - /* Save FP and LR registers to stay align with ARM64 AAPCS */ - emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx); - emit(A64_MOV(1, A64_FP, A64_SP), ctx); - - /* Save callee-saved registers */ - emit(A64_PUSH(r6, r7, A64_SP), ctx); - emit(A64_PUSH(r8, r9, A64_SP), ctx); - emit(A64_PUSH(fp, tcc, A64_SP), ctx); - emit(A64_PUSH(fpb, A64_R(28), A64_SP), ctx); + /* Save callee-saved registers */ + emit(A64_PUSH(r6, r7, A64_SP), ctx); + emit(A64_PUSH(r8, r9, A64_SP), ctx); + emit(A64_PUSH(fp, tcc, A64_SP), ctx); + emit(A64_PUSH(fpb, A64_R(28), A64_SP), ctx); + } else { + /* + * Exception callback receives FP of Main Program as third + * parameter + */ + emit(A64_MOV(1, A64_FP, A64_R(2)), ctx); + /* + * Main Program already pushed the frame record and the + * callee-saved registers. The exception callback will not push + * anything and re-use the main program's stack. + * + * 10 registers are on the stack + */ + emit(A64_SUB_I(1, A64_SP, A64_FP, 80), ctx); + } /* Set up BPF prog stack base register */ emit(A64_MOV(1, fp, A64_SP), ctx); @@ -365,6 +381,20 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf) emit_bti(A64_BTI_J, ctx); } + /* + * Program acting as exception boundary should save all ARM64 + * Callee-saved registers as the exception callback needs to recover + * all ARM64 Callee-saved registers in its epilogue. + */ + if (prog->aux->exception_boundary) { + /* + * As we are pushing two more registers, BPF_FP should be moved + * 16 bytes + */ + emit(A64_SUB_I(1, fp, fp, 16), ctx); + emit(A64_PUSH(A64_R(23), A64_R(24), A64_SP), ctx); + } + emit(A64_SUB_I(1, fpb, fp, ctx->fpb_offset), ctx); /* Stack must be multiples of 16B */ @@ -653,7 +683,7 @@ static void build_plt(struct jit_ctx *ctx) plt->target = (u64)&dummy_tramp; } -static void build_epilogue(struct jit_ctx *ctx) +static void build_epilogue(struct jit_ctx *ctx, bool is_exception_cb) { const u8 r0 = bpf2a64[BPF_REG_0]; const u8 r6 = bpf2a64[BPF_REG_6]; @@ -666,6 +696,15 @@ static void build_epilogue(struct jit_ctx *ctx) /* We're done with BPF stack */ emit(A64_ADD_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); + /* + * Program acting as exception boundary pushes R23 and R24 in addition + * to BPF callee-saved registers. Exception callback uses the boundary + * program's stack frame, so recover these extra registers in the above + * two cases. + */ + if (ctx->prog->aux->exception_boundary || is_exception_cb) + emit(A64_POP(A64_R(23), A64_R(24), A64_SP), ctx); + /* Restore x27 and x28 */ emit(A64_POP(fpb, A64_R(28), A64_SP), ctx); /* Restore fs (x25) and x26 */ @@ -1575,7 +1614,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) * BPF line info needs ctx->offset[i] to be the offset of * instruction[i] in jited image, so build prologue first. */ - if (build_prologue(&ctx, was_classic)) { + if (build_prologue(&ctx, was_classic, prog->aux->exception_cb)) { prog = orig_prog; goto out_off; } @@ -1586,7 +1625,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) } ctx.epilogue_offset = ctx.idx; - build_epilogue(&ctx); + build_epilogue(&ctx, prog->aux->exception_cb); build_plt(&ctx); extable_align = __alignof__(struct exception_table_entry); @@ -1614,7 +1653,7 @@ skip_init_ctx: ctx.idx = 0; ctx.exentry_idx = 0; - build_prologue(&ctx, was_classic); + build_prologue(&ctx, was_classic, prog->aux->exception_cb); if (build_body(&ctx, extra_pass)) { bpf_jit_binary_free(header); @@ -1622,7 +1661,7 @@ skip_init_ctx: goto out_off; } - build_epilogue(&ctx); + build_epilogue(&ctx, prog->aux->exception_cb); build_plt(&ctx); /* 3. Extra pass to validate JITed code. */ @@ -2310,3 +2349,13 @@ bool bpf_jit_supports_ptr_xchg(void) { return true; } + +bool bpf_jit_supports_exceptions(void) +{ + /* We unwind through both kernel frames starting from within bpf_throw + * call and BPF frames. Therefore we require FP unwinder to be enabled + * to walk kernel frames and reach BPF frames in the stack trace. + * ARM64 kernel is aways compiled with CONFIG_FRAME_POINTER=y + */ + return true; +} diff --git a/tools/testing/selftests/bpf/DENYLIST.aarch64 b/tools/testing/selftests/bpf/DENYLIST.aarch64 index 5c2cc7e8c5d0..0445ac38bc07 100644 --- a/tools/testing/selftests/bpf/DENYLIST.aarch64 +++ b/tools/testing/selftests/bpf/DENYLIST.aarch64 @@ -1,6 +1,5 @@ bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 -exceptions # JIT does not support calling kfunc bpf_throw: -524 fexit_sleep # The test never returns. The remaining tests cannot start. kprobe_multi_bench_attach # needs CONFIG_FPROBE kprobe_multi_test # needs CONFIG_FPROBE From d75fe63a0708bd28eac5cda1212fa5fd037297dc Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Sat, 24 Feb 2024 16:41:21 +0800 Subject: [PATCH 1567/2255] ipv6: raw: remove useless input parameter in rawv6_err The input parameter 'opt' in rawv6_err() is not used. Therefore, remove it. Signed-off-by: Zhengchao Shao Reviewed-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240224084121.2479603-1-shaozhengchao@huawei.com Signed-off-by: Jakub Kicinski --- net/ipv6/raw.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 03dbb874c363..479c4c2c1785 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -288,8 +288,7 @@ out: } static void rawv6_err(struct sock *sk, struct sk_buff *skb, - struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { bool recverr = inet6_test_bit(RECVERR6, sk); struct ipv6_pinfo *np = inet6_sk(sk); @@ -344,7 +343,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, if (!raw_v6_match(net, sk, nexthdr, &ip6h->saddr, &ip6h->daddr, inet6_iif(skb), inet6_iif(skb))) continue; - rawv6_err(sk, skb, NULL, type, code, inner_offset, info); + rawv6_err(sk, skb, type, code, inner_offset, info); } rcu_read_unlock(); } From 848e34ca203046c9b967034596828472f08e4ac7 Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Sat, 24 Feb 2024 19:19:32 +0100 Subject: [PATCH 1568/2255] net: wwan: t7xx: Prefer struct_size over open coded arithmetic This is an effort to get rid of all multiplications from allocation functions in order to prevent integer overflows [1][2]. As the "port_prox" variable is a pointer to "struct port_proxy" and this structure ends in a flexible array: struct port_proxy { [...] struct t7xx_port ports[]; }; the preferred way in the kernel is to use the struct_size() helper to do the arithmetic instead of the argument "size + size * count" in the devm_kzalloc() function. This way, the code is more readable and safer. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [1] Link: https://github.com/KSPP/linux/issues/160 [2] Signed-off-by: Erick Archer Reviewed-by: Sergey Ryazanov Link: https://lore.kernel.org/r/20240224181932.2720-1-erick.archer@gmx.com Signed-off-by: Jakub Kicinski --- drivers/net/wwan/t7xx/t7xx_port_proxy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c index 8f5e01705af2..7d6388bf1d7c 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c @@ -543,8 +543,10 @@ static int t7xx_proxy_alloc(struct t7xx_modem *md) struct device *dev = &md->t7xx_dev->pdev->dev; struct port_proxy *port_prox; - port_prox = devm_kzalloc(dev, sizeof(*port_prox) + - sizeof(struct t7xx_port) * T7XX_MAX_POSSIBLE_PORTS_NUM, + port_prox = devm_kzalloc(dev, + struct_size(port_prox, + ports, + T7XX_MAX_POSSIBLE_PORTS_NUM), GFP_KERNEL); if (!port_prox) return -ENOMEM; From 4440873f3655325f849366d75382aa05d09b5575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jones=20Syue=20=E8=96=9B=E6=87=B7=E5=AE=97?= Date: Mon, 26 Feb 2024 02:24:52 +0000 Subject: [PATCH 1569/2255] bonding: 802.3ad replace MAC_ADDRESS_EQUAL with __agg_has_partner Replace macro MAC_ADDRESS_EQUAL() for null_mac_addr checking with inline function__agg_has_partner(). When MAC_ADDRESS_EQUAL() is verifiying aggregator's partner mac addr with null_mac_addr, means that seeing if aggregator has a valid partner or not. Using __agg_has_partner() makes it more clear to understand. In ad_port_selection_logic(), since aggregator->partner_system and port->partner_oper.system has been compared first as a prerequisite, it is safe to replace the upcoming MAC_ADDRESS_EQUAL() for null_mac_addr checking with __agg_has_partner(). Delete null_mac_addr, which is not required anymore in bond_3ad.c, since all references to it are gone. Signed-off-by: Jones Syue Reviewed-by: Hangbin Liu Reviewed-by: Jiri Pirko Acked-by: Jay Vosburgh Link: https://lore.kernel.org/r/SI2PR04MB5097BCA8FF2A2F03D9A5A3EEDC5A2@SI2PR04MB5097.apcprd04.prod.outlook.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_3ad.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index f2942e8c6c91..c6807e473ab7 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -82,10 +82,6 @@ enum ad_link_speed_type { #define MAC_ADDRESS_EQUAL(A, B) \ ether_addr_equal_64bits((const u8 *)A, (const u8 *)B) -static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = { - 0, 0, 0, 0, 0, 0 -}; - static const u16 ad_ticks_per_sec = 1000 / AD_TIMER_INTERVAL; static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; @@ -1588,7 +1584,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) (aggregator->partner_system_priority == port->partner_oper.system_priority) && (aggregator->partner_oper_aggregator_key == port->partner_oper.key) ) && - ((!MAC_ADDRESS_EQUAL(&(port->partner_oper.system), &(null_mac_addr)) && /* partner answers */ + ((__agg_has_partner(aggregator) && /* partner answers */ !aggregator->is_individual) /* but is not individual OR */ ) ) { @@ -2036,9 +2032,7 @@ static void ad_enable_collecting(struct port *port) */ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) { - if (port->aggregator && - !MAC_ADDRESS_EQUAL(&port->aggregator->partner_system, - &(null_mac_addr))) { + if (port->aggregator && __agg_has_partner(port->aggregator)) { slave_dbg(port->slave->bond->dev, port->slave->dev, "Disabling distributing on port %d (LAG %d)\n", port->actor_port_number, @@ -2078,9 +2072,7 @@ static void ad_enable_collecting_distributing(struct port *port, static void ad_disable_collecting_distributing(struct port *port, bool *update_slave_arr) { - if (port->aggregator && - !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system), - &(null_mac_addr))) { + if (port->aggregator && __agg_has_partner(port->aggregator)) { slave_dbg(port->slave->bond->dev, port->slave->dev, "Disabling port %d (LAG %d)\n", port->actor_port_number, From 28001bb1955fcfa63e535848c4289fcd7bb88daf Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Sun, 25 Feb 2024 13:29:53 -0300 Subject: [PATCH 1570/2255] dt-bindings: net: dsa: realtek: reset-gpios is not required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'reset-gpios' should not be mandatory. although they might be required for some devices if the switch reset was left asserted by a previous driver, such as the bootloader. Signed-off-by: Luiz Angelo Daros de Luca Cc: devicetree@vger.kernel.org Acked-by: Arınç ÜNAL Acked-by: Rob Herring Reviewed-by: Linus Walleij Reviewed-by: Alvin Šipraga Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/dsa/realtek.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/dsa/realtek.yaml b/Documentation/devicetree/bindings/net/dsa/realtek.yaml index cce692f57b08..46e113df77c8 100644 --- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml +++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml @@ -127,7 +127,6 @@ else: - mdc-gpios - mdio-gpios - mdio - - reset-gpios required: - compatible From 5fc2d68fc81801162188995e4d3dc0b26747dd76 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Sun, 25 Feb 2024 13:29:54 -0300 Subject: [PATCH 1571/2255] dt-bindings: net: dsa: realtek: add reset controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Realtek switches can use a reset controller instead of reset-gpios. Signed-off-by: Luiz Angelo Daros de Luca Cc: devicetree@vger.kernel.org Acked-by: Arınç ÜNAL Reviewed-by: Linus Walleij Reviewed-by: Alvin Šipraga Acked-by: Rob Herring Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/dsa/realtek.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/realtek.yaml b/Documentation/devicetree/bindings/net/dsa/realtek.yaml index 46e113df77c8..70b6bda3cf98 100644 --- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml +++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml @@ -59,6 +59,9 @@ properties: description: GPIO to be used to reset the whole device maxItems: 1 + resets: + maxItems: 1 + realtek,disable-leds: type: boolean description: | From 56998aa6b7f0f31ce8df23c00701af2d8e8a1f1a Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Sun, 25 Feb 2024 13:29:55 -0300 Subject: [PATCH 1572/2255] net: dsa: realtek: support reset controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for resetting the device using a reset controller, complementing the existing GPIO reset functionality (reset-gpios). Although the reset is optional and the driver performs a soft reset during setup, if the initial reset pin state was asserted, the driver will not detect the device until the reset is deasserted. Signed-off-by: Luiz Angelo Daros de Luca Reviewed-by: Linus Walleij Reviewed-by: Alvin Šipraga Signed-off-by: David S. Miller --- drivers/net/dsa/realtek/realtek.h | 2 ++ drivers/net/dsa/realtek/rtl83xx.c | 42 +++++++++++++++++++++++++++---- drivers/net/dsa/realtek/rtl83xx.h | 2 ++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index b80bfde1ad04..e0b1aa01337b 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -12,6 +12,7 @@ #include #include #include +#include #define REALTEK_HW_STOP_DELAY 25 /* msecs */ #define REALTEK_HW_START_DELAY 100 /* msecs */ @@ -48,6 +49,7 @@ struct rtl8366_vlan_4k { struct realtek_priv { struct device *dev; + struct reset_control *reset_ctl; struct gpio_desc *reset; struct gpio_desc *mdc; struct gpio_desc *mdio; diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c index 801873754df2..d2e876805393 100644 --- a/drivers/net/dsa/realtek/rtl83xx.c +++ b/drivers/net/dsa/realtek/rtl83xx.c @@ -184,6 +184,13 @@ rtl83xx_probe(struct device *dev, "realtek,disable-leds"); /* TODO: if power is software controlled, set up any regulators here */ + priv->reset_ctl = devm_reset_control_get_optional(dev, NULL); + if (IS_ERR(priv->reset_ctl)) { + ret = PTR_ERR(priv->reset_ctl); + dev_err_probe(dev, ret, "failed to get reset control\n"); + return ERR_CAST(priv->reset_ctl); + } + priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(priv->reset)) { dev_err(dev, "failed to get RESET GPIO\n"); @@ -192,11 +199,11 @@ rtl83xx_probe(struct device *dev, dev_set_drvdata(dev, priv); - if (priv->reset) { - gpiod_set_value(priv->reset, 1); + if (priv->reset_ctl || priv->reset) { + rtl83xx_reset_assert(priv); dev_dbg(dev, "asserted RESET\n"); msleep(REALTEK_HW_STOP_DELAY); - gpiod_set_value(priv->reset, 0); + rtl83xx_reset_deassert(priv); msleep(REALTEK_HW_START_DELAY); dev_dbg(dev, "deasserted RESET\n"); } @@ -292,11 +299,36 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA); void rtl83xx_remove(struct realtek_priv *priv) { /* leave the device reset asserted */ - if (priv->reset) - gpiod_set_value(priv->reset, 1); + rtl83xx_reset_assert(priv); } EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); +void rtl83xx_reset_assert(struct realtek_priv *priv) +{ + int ret; + + ret = reset_control_assert(priv->reset_ctl); + if (ret) + dev_warn(priv->dev, + "Failed to assert the switch reset control: %pe\n", + ERR_PTR(ret)); + + gpiod_set_value(priv->reset, true); +} + +void rtl83xx_reset_deassert(struct realtek_priv *priv) +{ + int ret; + + ret = reset_control_deassert(priv->reset_ctl); + if (ret) + dev_warn(priv->dev, + "Failed to deassert the switch reset control: %pe\n", + ERR_PTR(ret)); + + gpiod_set_value(priv->reset, false); +} + MODULE_AUTHOR("Luiz Angelo Daros de Luca "); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Realtek DSA switches common module"); diff --git a/drivers/net/dsa/realtek/rtl83xx.h b/drivers/net/dsa/realtek/rtl83xx.h index 0ddff33df6b0..c8a0ff8fd75e 100644 --- a/drivers/net/dsa/realtek/rtl83xx.h +++ b/drivers/net/dsa/realtek/rtl83xx.h @@ -18,5 +18,7 @@ int rtl83xx_register_switch(struct realtek_priv *priv); void rtl83xx_unregister_switch(struct realtek_priv *priv); void rtl83xx_shutdown(struct realtek_priv *priv); void rtl83xx_remove(struct realtek_priv *priv); +void rtl83xx_reset_assert(struct realtek_priv *priv); +void rtl83xx_reset_deassert(struct realtek_priv *priv); #endif /* _RTL83XX_H */ From 12a686c2e761f1f1f6e6e2117a9ab9c6de2ac8a7 Mon Sep 17 00:00:00 2001 From: Adam Li Date: Mon, 26 Feb 2024 02:24:52 +0000 Subject: [PATCH 1573/2255] net: make SK_MEMORY_PCPU_RESERV tunable This patch adds /proc/sys/net/core/mem_pcpu_rsv sysctl file, to make SK_MEMORY_PCPU_RESERV tunable. Commit 3cd3399dd7a8 ("net: implement per-cpu reserves for memory_allocated") introduced per-cpu forward alloc cache: "Implement a per-cpu cache of +1/-1 MB, to reduce number of changes to sk->sk_prot->memory_allocated, which would otherwise be cause of false sharing." sk_prot->memory_allocated points to global atomic variable: atomic_long_t tcp_memory_allocated ____cacheline_aligned_in_smp; If increasing the per-cpu cache size from 1MB to e.g. 16MB, changes to sk->sk_prot->memory_allocated can be further reduced. Performance may be improved on system with many cores. Signed-off-by: Adam Li Reviewed-by: Christoph Lameter (Ampere) Signed-off-by: David S. Miller --- Documentation/admin-guide/sysctl/net.rst | 5 +++++ include/net/sock.h | 5 +++-- net/core/sock.c | 1 + net/core/sysctl_net_core.c | 9 +++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst index 396091651955..7250c0542828 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -206,6 +206,11 @@ Will increase power usage. Default: 0 (off) +mem_pcpu_rsv +------------ + +Per-cpu reserved forward alloc cache size in page units. Default 1MB per CPU. + rmem_default ------------ diff --git a/include/net/sock.h b/include/net/sock.h index 796a902cf4c1..09a0cde8bf52 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1443,6 +1443,7 @@ sk_memory_allocated(const struct sock *sk) /* 1 MB per cpu, in page units */ #define SK_MEMORY_PCPU_RESERVE (1 << (20 - PAGE_SHIFT)) +extern int sysctl_mem_pcpu_rsv; static inline void sk_memory_allocated_add(struct sock *sk, int amt) @@ -1451,7 +1452,7 @@ sk_memory_allocated_add(struct sock *sk, int amt) preempt_disable(); local_reserve = __this_cpu_add_return(*sk->sk_prot->per_cpu_fw_alloc, amt); - if (local_reserve >= SK_MEMORY_PCPU_RESERVE) { + if (local_reserve >= READ_ONCE(sysctl_mem_pcpu_rsv)) { __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve); atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); } @@ -1465,7 +1466,7 @@ sk_memory_allocated_sub(struct sock *sk, int amt) preempt_disable(); local_reserve = __this_cpu_sub_return(*sk->sk_prot->per_cpu_fw_alloc, amt); - if (local_reserve <= -SK_MEMORY_PCPU_RESERVE) { + if (local_reserve <= -READ_ONCE(sysctl_mem_pcpu_rsv)) { __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve); atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); } diff --git a/net/core/sock.c b/net/core/sock.c index 8d86886e39fa..df2ac54a8f74 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -283,6 +283,7 @@ __u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX; EXPORT_SYMBOL(sysctl_rmem_max); __u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX; __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; +int sysctl_mem_pcpu_rsv __read_mostly = SK_MEMORY_PCPU_RESERVE; int sysctl_tstamp_allow_data __read_mostly = 1; diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 0f0cb1465e08..986f15e5d6c4 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -30,6 +30,7 @@ static int int_3600 = 3600; static int min_sndbuf = SOCK_MIN_SNDBUF; static int min_rcvbuf = SOCK_MIN_RCVBUF; static int max_skb_frags = MAX_SKB_FRAGS; +static int min_mem_pcpu_rsv = SK_MEMORY_PCPU_RESERVE; static int net_msg_warn; /* Unused, but still a sysctl */ @@ -407,6 +408,14 @@ static struct ctl_table net_core_table[] = { .proc_handler = proc_dointvec_minmax, .extra1 = &min_rcvbuf, }, + { + .procname = "mem_pcpu_rsv", + .data = &sysctl_mem_pcpu_rsv, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &min_mem_pcpu_rsv, + }, { .procname = "dev_weight", .data = &weight_p, From 48e4704aedb9f17213206dc649fdac90f94cb749 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:18 +0800 Subject: [PATCH 1574/2255] tcp: add a dropreason definitions and prepare for cookie check Adding one drop reason to detect the condition of skb dropped because of hook points in cookie check and extending NO_SOCKET to consider another two cases can be used later. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/dropreason-core.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h index 6d3a20163260..a871f061558d 100644 --- a/include/net/dropreason-core.h +++ b/include/net/dropreason-core.h @@ -54,6 +54,7 @@ FN(NEIGH_QUEUEFULL) \ FN(NEIGH_DEAD) \ FN(TC_EGRESS) \ + FN(SECURITY_HOOK) \ FN(QDISC_DROP) \ FN(CPU_BACKLOG) \ FN(XDP) \ @@ -105,7 +106,13 @@ enum skb_drop_reason { SKB_CONSUMED, /** @SKB_DROP_REASON_NOT_SPECIFIED: drop reason is not specified */ SKB_DROP_REASON_NOT_SPECIFIED, - /** @SKB_DROP_REASON_NO_SOCKET: socket not found */ + /** + * @SKB_DROP_REASON_NO_SOCKET: no valid socket that can be used. + * Reason could be one of three cases: + * 1) no established/listening socket found during lookup process + * 2) no valid request socket during 3WHS process + * 3) no valid child socket during 3WHS process + */ SKB_DROP_REASON_NO_SOCKET, /** @SKB_DROP_REASON_PKT_TOO_SMALL: packet size is too small */ SKB_DROP_REASON_PKT_TOO_SMALL, @@ -271,6 +278,8 @@ enum skb_drop_reason { SKB_DROP_REASON_NEIGH_DEAD, /** @SKB_DROP_REASON_TC_EGRESS: dropped in TC egress HOOK */ SKB_DROP_REASON_TC_EGRESS, + /** @SKB_DROP_REASON_SECURITY_HOOK: dropped due to security HOOK */ + SKB_DROP_REASON_SECURITY_HOOK, /** * @SKB_DROP_REASON_QDISC_DROP: dropped by qdisc when packet outputting ( * failed to enqueue to current qdisc) From 65be4393f363c4bd5c388ddf3e3eb4abee2b1f79 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:19 +0800 Subject: [PATCH 1575/2255] tcp: directly drop skb in cookie check for ipv4 Only move the skb drop from tcp_v4_do_rcv() to cookie_v4_check() itself, no other changes made. It can help us refine the specific drop reasons later. Signed-off-by: Jason Xing Reviewed-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/syncookies.c | 4 ++++ net/ipv4/tcp_ipv4.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index be88bf586ff9..38f331da6677 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -408,6 +408,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) struct rtable *rt; __u8 rcv_wscale; int full_space; + SKB_DR(reason); if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || !th->ack || th->rst) @@ -477,10 +478,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) */ if (ret) inet_sk(ret)->cork.fl.u.ip4 = fl4; + else + goto out_drop; out: return ret; out_free: reqsk_free(req); out_drop: + kfree_skb_reason(skb, reason); return NULL; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0c50c5a32b84..0a944e109088 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1915,7 +1915,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) struct sock *nsk = tcp_v4_cookie_check(sk, skb); if (!nsk) - goto discard; + return 0; if (nsk != sk) { if (tcp_child_process(sk, nsk, skb)) { rsk = nsk; From a4a69a3719ec55f677b8481f58215b6338b781e5 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:20 +0800 Subject: [PATCH 1576/2255] tcp: use drop reasons in cookie check for ipv4 Now it's time to use the prepared definitions to refine this part. Four reasons used might enough for now, I think. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- net/ipv4/syncookies.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 38f331da6677..7972ad3d7c73 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -421,8 +421,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) if (IS_ERR(req)) goto out; } - if (!req) + if (!req) { + SKB_DR_SET(reason, NO_SOCKET); goto out_drop; + } ireq = inet_rsk(req); @@ -434,8 +436,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) */ RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); - if (security_inet_conn_request(sk, skb, req)) + if (security_inet_conn_request(sk, skb, req)) { + SKB_DR_SET(reason, SECURITY_HOOK); goto out_free; + } tcp_ao_syncookie(sk, skb, req, AF_INET); @@ -452,8 +456,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi_common(&fl4)); rt = ip_route_output_key(net, &fl4); - if (IS_ERR(rt)) + if (IS_ERR(rt)) { + SKB_DR_SET(reason, IP_OUTNOROUTES); goto out_free; + } /* Try to redo what tcp_v4_send_synack did. */ req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); @@ -476,10 +482,11 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) /* ip_queue_xmit() depends on our flow being setup * Normal sockets get it right from inet_csk_route_child_sock() */ - if (ret) - inet_sk(ret)->cork.fl.u.ip4 = fl4; - else + if (!ret) { + SKB_DR_SET(reason, NO_SOCKET); goto out_drop; + } + inet_sk(ret)->cork.fl.u.ip4 = fl4; out: return ret; out_free: From ed43e76cdcc497e2b27d84db27e7df5612be2643 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:21 +0800 Subject: [PATCH 1577/2255] tcp: directly drop skb in cookie check for ipv6 Like previous patch does, only moving skb drop logical code to cookie_v6_check() for later refinement. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- net/ipv6/syncookies.c | 4 ++++ net/ipv6/tcp_ipv6.c | 5 +---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 6b9c69278819..ea0d9954a29f 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -177,6 +177,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) struct sock *ret = sk; __u8 rcv_wscale; int full_space; + SKB_DR(reason); if (!READ_ONCE(net->ipv4.sysctl_tcp_syncookies) || !th->ack || th->rst) @@ -256,10 +257,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq->ecn_ok &= cookie_ecn_ok(net, dst); ret = tcp_get_cookie_sock(sk, skb, req, dst); + if (!ret) + goto out_drop; out: return ret; out_free: reqsk_free(req); out_drop: + kfree_skb_reason(skb, reason); return NULL; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 57b25b1fc9d9..0c180bb8187f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1653,11 +1653,8 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) if (sk->sk_state == TCP_LISTEN) { struct sock *nsk = tcp_v6_cookie_check(sk, skb); - if (!nsk) - goto discard; - if (nsk != sk) { - if (tcp_child_process(sk, nsk, skb)) + if (nsk && tcp_child_process(sk, nsk, skb)) goto reset; if (opt_skb) __kfree_skb(opt_skb); From 253541a3c1e43f6b42033f78d2289a216af58387 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:22 +0800 Subject: [PATCH 1578/2255] tcp: use drop reasons in cookie check for ipv6 Like what I did to ipv4 mode, refine this part: adding more drop reasons for better tracing. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- net/ipv6/syncookies.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index ea0d9954a29f..8bad0a44a0a6 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -190,16 +190,20 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (IS_ERR(req)) goto out; } - if (!req) + if (!req) { + SKB_DR_SET(reason, NO_SOCKET); goto out_drop; + } ireq = inet_rsk(req); ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; - if (security_inet_conn_request(sk, skb, req)) + if (security_inet_conn_request(sk, skb, req)) { + SKB_DR_SET(reason, SECURITY_HOOK); goto out_free; + } if (ipv6_opt_accepted(sk, skb, &TCP_SKB_CB(skb)->header.h6) || np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || @@ -236,8 +240,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) security_req_classify_flow(req, flowi6_to_flowi_common(&fl6)); dst = ip6_dst_lookup_flow(net, sk, &fl6, final_p); - if (IS_ERR(dst)) + if (IS_ERR(dst)) { + SKB_DR_SET(reason, IP_OUTNOROUTES); goto out_free; + } } req->rsk_window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); @@ -257,8 +263,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq->ecn_ok &= cookie_ecn_ok(net, dst); ret = tcp_get_cookie_sock(sk, skb, req, dst); - if (!ret) + if (!ret) { + SKB_DR_SET(reason, NO_SOCKET); goto out_drop; + } out: return ret; out_free: From 3d359faba191c95e97ac6699b0163e797812bfca Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:23 +0800 Subject: [PATCH 1579/2255] tcp: introduce dropreasons in receive path Soon later patches can use these relatively more accurate reasons to recognise and find out the cause. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/dropreason-core.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h index a871f061558d..9707ab54fdd5 100644 --- a/include/net/dropreason-core.h +++ b/include/net/dropreason-core.h @@ -30,6 +30,7 @@ FN(TCP_AOFAILURE) \ FN(SOCKET_BACKLOG) \ FN(TCP_FLAGS) \ + FN(TCP_ABORT_ON_DATA) \ FN(TCP_ZEROWINDOW) \ FN(TCP_OLD_DATA) \ FN(TCP_OVERWINDOW) \ @@ -37,6 +38,7 @@ FN(TCP_RFC7323_PAWS) \ FN(TCP_OLD_SEQUENCE) \ FN(TCP_INVALID_SEQUENCE) \ + FN(TCP_INVALID_ACK_SEQUENCE) \ FN(TCP_RESET) \ FN(TCP_INVALID_SYN) \ FN(TCP_CLOSE) \ @@ -204,6 +206,11 @@ enum skb_drop_reason { SKB_DROP_REASON_SOCKET_BACKLOG, /** @SKB_DROP_REASON_TCP_FLAGS: TCP flags invalid */ SKB_DROP_REASON_TCP_FLAGS, + /** + * @SKB_DROP_REASON_TCP_ABORT_ON_DATA: abort on data, corresponding to + * LINUX_MIB_TCPABORTONDATA + */ + SKB_DROP_REASON_TCP_ABORT_ON_DATA, /** * @SKB_DROP_REASON_TCP_ZEROWINDOW: TCP receive window size is zero, * see LINUX_MIB_TCPZEROWINDOWDROP @@ -228,13 +235,19 @@ enum skb_drop_reason { SKB_DROP_REASON_TCP_OFOMERGE, /** * @SKB_DROP_REASON_TCP_RFC7323_PAWS: PAWS check, corresponding to - * LINUX_MIB_PAWSESTABREJECTED + * LINUX_MIB_PAWSESTABREJECTED, LINUX_MIB_PAWSACTIVEREJECTED */ SKB_DROP_REASON_TCP_RFC7323_PAWS, /** @SKB_DROP_REASON_TCP_OLD_SEQUENCE: Old SEQ field (duplicate packet) */ SKB_DROP_REASON_TCP_OLD_SEQUENCE, /** @SKB_DROP_REASON_TCP_INVALID_SEQUENCE: Not acceptable SEQ field */ SKB_DROP_REASON_TCP_INVALID_SEQUENCE, + /** + * @SKB_DROP_REASON_TCP_INVALID_ACK_SEQUENCE: Not acceptable ACK SEQ + * field because ack sequence is not in the window between snd_una + * and snd_nxt + */ + SKB_DROP_REASON_TCP_INVALID_ACK_SEQUENCE, /** @SKB_DROP_REASON_TCP_RESET: Invalid RST packet */ SKB_DROP_REASON_TCP_RESET, /** From e615e3a24ed6f1a501f9b5426ec0b476fded4d22 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:24 +0800 Subject: [PATCH 1580/2255] tcp: add more specific possible drop reasons in tcp_rcv_synsent_state_process() This patch does two things: 1) add two more new reasons 2) only change the return value(1) to various drop reason values for the future use For now, we still cannot trace those two reasons. We'll implement the full function in the subsequent patch in this series. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 74c03f0a6c0c..83308cca1610 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6361,6 +6361,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, TCP_TIMEOUT_MIN, TCP_RTO_MAX); + SKB_DR_SET(reason, TCP_INVALID_ACK_SEQUENCE); goto reset_and_undo; } @@ -6369,6 +6370,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tcp_time_stamp_ts(tp))) { NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSACTIVEREJECTED); + SKB_DR_SET(reason, TCP_RFC7323_PAWS); goto reset_and_undo; } @@ -6572,7 +6574,8 @@ discard_and_undo: reset_and_undo: tcp_clear_options(&tp->rx_opt); tp->rx_opt.mss_clamp = saved_clamp; - return 1; + /* we can reuse/return @reason to its caller to handle the exception */ + return reason; } static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) From 7d6ed9afde8547723f6f96f81f984cc6c48eef52 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:25 +0800 Subject: [PATCH 1581/2255] tcp: add dropreasons in tcp_rcv_state_process() In this patch, I equipped this function with more dropreasons, but it still doesn't work yet, which I will do later. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_input.c | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 33bf92dff0af..af2a4dcd4518 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -348,7 +348,7 @@ void tcp_wfree(struct sk_buff *skb); void tcp_write_timer_handler(struct sock *sk); void tcp_delack_timer_handler(struct sock *sk); int tcp_ioctl(struct sock *sk, int cmd, int *karg); -int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb); +enum skb_drop_reason tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb); void tcp_rcv_established(struct sock *sk, struct sk_buff *skb); void tcp_rcv_space_adjust(struct sock *sk); int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 83308cca1610..5d874817a78d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6619,7 +6619,8 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) * address independent. */ -int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +enum skb_drop_reason +tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); @@ -6635,7 +6636,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) case TCP_LISTEN: if (th->ack) - return 1; + return SKB_DROP_REASON_TCP_FLAGS; if (th->rst) { SKB_DR_SET(reason, TCP_RESET); @@ -6704,8 +6705,12 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) FLAG_NO_CHALLENGE_ACK); if ((int)reason <= 0) { - if (sk->sk_state == TCP_SYN_RECV) - return 1; /* send one RST */ + if (sk->sk_state == TCP_SYN_RECV) { + /* send one RST */ + if (!reason) + return SKB_DROP_REASON_TCP_OLD_ACK; + return -reason; + } /* accept old ack during closing */ if ((int)reason < 0) { tcp_send_challenge_ack(sk); @@ -6781,7 +6786,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) if (READ_ONCE(tp->linger2) < 0) { tcp_done(sk); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - return 1; + return SKB_DROP_REASON_TCP_ABORT_ON_DATA; } if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { @@ -6790,7 +6795,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) tcp_fastopen_active_disable(sk); tcp_done(sk); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - return 1; + return SKB_DROP_REASON_TCP_ABORT_ON_DATA; } tmo = tcp_fin_time(sk); @@ -6855,7 +6860,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); tcp_reset(sk, skb); - return 1; + return SKB_DROP_REASON_TCP_ABORT_ON_DATA; } } fallthrough; From b9825695930546af725b1e686b8eaf4c71201728 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:26 +0800 Subject: [PATCH 1582/2255] tcp: make the dropreason really work when calling tcp_rcv_state_process() Update three callers including both ipv4 and ipv6 and let the dropreason mechanism work in reality. Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/tcp.h | 4 ++-- net/ipv4/tcp_ipv4.c | 3 ++- net/ipv4/tcp_minisocks.c | 10 +++++----- net/ipv6/tcp_ipv6.c | 3 ++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index af2a4dcd4518..6ae35199d3b3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -396,8 +396,8 @@ enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, struct request_sock *req, bool fastopen, bool *lost_race); -int tcp_child_process(struct sock *parent, struct sock *child, - struct sk_buff *skb); +enum skb_drop_reason tcp_child_process(struct sock *parent, struct sock *child, + struct sk_buff *skb); void tcp_enter_loss(struct sock *sk); void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, int newly_lost, int flag); void tcp_clear_retrans(struct tcp_sock *tp); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0a944e109088..c79e25549972 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1926,7 +1926,8 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) } else sock_rps_save_rxhash(sk, skb); - if (tcp_rcv_state_process(sk, skb)) { + reason = tcp_rcv_state_process(sk, skb); + if (reason) { rsk = sk; goto reset; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 9e85f2a0bddd..52040b0e2616 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -911,11 +911,11 @@ EXPORT_SYMBOL(tcp_check_req); * be created. */ -int tcp_child_process(struct sock *parent, struct sock *child, - struct sk_buff *skb) +enum skb_drop_reason tcp_child_process(struct sock *parent, struct sock *child, + struct sk_buff *skb) __releases(&((child)->sk_lock.slock)) { - int ret = 0; + enum skb_drop_reason reason = SKB_NOT_DROPPED_YET; int state = child->sk_state; /* record sk_napi_id and sk_rx_queue_mapping of child. */ @@ -923,7 +923,7 @@ int tcp_child_process(struct sock *parent, struct sock *child, tcp_segs_in(tcp_sk(child), skb); if (!sock_owned_by_user(child)) { - ret = tcp_rcv_state_process(child, skb); + reason = tcp_rcv_state_process(child, skb); /* Wakeup parent, send SIGIO */ if (state == TCP_SYN_RECV && child->sk_state != state) parent->sk_data_ready(parent); @@ -937,6 +937,6 @@ int tcp_child_process(struct sock *parent, struct sock *child, bh_unlock_sock(child); sock_put(child); - return ret; + return reason; } EXPORT_SYMBOL(tcp_child_process); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0c180bb8187f..4f8464e04b7f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1663,7 +1663,8 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) } else sock_rps_save_rxhash(sk, skb); - if (tcp_rcv_state_process(sk, skb)) + reason = tcp_rcv_state_process(sk, skb); + if (reason) goto reset; if (opt_skb) goto ipv6_pktoptions; From ee01defe25bad09a37b68dd051a7e931d1e4cd91 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Mon, 26 Feb 2024 11:22:27 +0800 Subject: [PATCH 1583/2255] tcp: make dropreason in tcp_child_process() work It's time to let it work right now. We've already prepared for this:) Signed-off-by: Jason Xing Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 12 +++++++----- net/ipv6/tcp_ipv6.c | 16 ++++++++++------ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c79e25549972..a22ee5838751 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1907,7 +1907,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; } - reason = SKB_DROP_REASON_NOT_SPECIFIED; if (tcp_checksum_complete(skb)) goto csum_err; @@ -1917,7 +1916,8 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) if (!nsk) return 0; if (nsk != sk) { - if (tcp_child_process(sk, nsk, skb)) { + reason = tcp_child_process(sk, nsk, skb); + if (reason) { rsk = nsk; goto reset; } @@ -2276,10 +2276,12 @@ process: if (nsk == sk) { reqsk_put(req); tcp_v4_restore_cb(skb); - } else if (tcp_child_process(sk, nsk, skb)) { - tcp_v4_send_reset(nsk, skb); - goto discard_and_relse; } else { + drop_reason = tcp_child_process(sk, nsk, skb); + if (drop_reason) { + tcp_v4_send_reset(nsk, skb); + goto discard_and_relse; + } sock_put(sk); return 0; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4f8464e04b7f..f677f0fa5196 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1623,7 +1623,6 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) if (np->rxopt.all) opt_skb = skb_clone_and_charge_r(skb, sk); - reason = SKB_DROP_REASON_NOT_SPECIFIED; if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ struct dst_entry *dst; @@ -1654,8 +1653,11 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) struct sock *nsk = tcp_v6_cookie_check(sk, skb); if (nsk != sk) { - if (nsk && tcp_child_process(sk, nsk, skb)) - goto reset; + if (nsk) { + reason = tcp_child_process(sk, nsk, skb); + if (reason) + goto reset; + } if (opt_skb) __kfree_skb(opt_skb); return 0; @@ -1854,10 +1856,12 @@ process: if (nsk == sk) { reqsk_put(req); tcp_v6_restore_cb(skb); - } else if (tcp_child_process(sk, nsk, skb)) { - tcp_v6_send_reset(nsk, skb); - goto discard_and_relse; } else { + drop_reason = tcp_child_process(sk, nsk, skb); + if (drop_reason) { + tcp_v6_send_reset(nsk, skb); + goto discard_and_relse; + } sock_put(sk); return 0; } From 3e46ec180ed91a2833f6cd637f919dcf2b53408c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 Feb 2024 13:29:13 +0100 Subject: [PATCH 1584/2255] dt-bindings: net: ethernet-controller: drop redundant type from label dtschema defines label as string, so $ref in other bindings is redundant. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/ethernet-controller.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml b/Documentation/devicetree/bindings/net/ethernet-controller.yaml index d14d123ad7a0..b2785b03139f 100644 --- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml @@ -14,7 +14,6 @@ properties: pattern: "^ethernet(@.*)?$" label: - $ref: /schemas/types.yaml#/definitions/string description: Human readable label on a port of a box. local-mac-address: From 5fa918a33563e050d45fb8f260f9240b2039f432 Mon Sep 17 00:00:00 2001 From: Justin Iurman Date: Mon, 26 Feb 2024 14:14:10 +0100 Subject: [PATCH 1585/2255] uapi: ioam6: API for netlink multicast events Add new api to support ioam6 events for generic netlink multicast. A first "trace" event is added to the list of ioam6 events, which will represent an IOAM Pre-allocated Trace Option-Type. It provides another solution to share IOAM data with user space. Reviewed-by: David Ahern Signed-off-by: Justin Iurman Signed-off-by: David S. Miller --- include/uapi/linux/ioam6_genl.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/uapi/linux/ioam6_genl.h b/include/uapi/linux/ioam6_genl.h index ca4b22833754..1733fbc51fb5 100644 --- a/include/uapi/linux/ioam6_genl.h +++ b/include/uapi/linux/ioam6_genl.h @@ -49,4 +49,24 @@ enum { #define IOAM6_CMD_MAX (__IOAM6_CMD_MAX - 1) +#define IOAM6_GENL_EV_GRP_NAME "ioam6_events" + +enum ioam6_event_type { + IOAM6_EVENT_UNSPEC, + IOAM6_EVENT_TRACE, +}; + +enum ioam6_event_attr { + IOAM6_EVENT_ATTR_UNSPEC, + + IOAM6_EVENT_ATTR_TRACE_NAMESPACE, /* u16 */ + IOAM6_EVENT_ATTR_TRACE_NODELEN, /* u8 */ + IOAM6_EVENT_ATTR_TRACE_TYPE, /* u32 */ + IOAM6_EVENT_ATTR_TRACE_DATA, /* Binary */ + + __IOAM6_EVENT_ATTR_MAX +}; + +#define IOAM6_EVENT_ATTR_MAX (__IOAM6_EVENT_ATTR_MAX - 1) + #endif /* _UAPI_LINUX_IOAM6_GENL_H */ From 67c8e4bb4f54ad22ca0ce4700c8728ffd73acb66 Mon Sep 17 00:00:00 2001 From: Justin Iurman Date: Mon, 26 Feb 2024 14:14:11 +0100 Subject: [PATCH 1586/2255] net: ioam6: multicast event Add a multicast group to the ioam6 generic netlink family and provide ioam6_event() to send an ioam6 event to the multicast group. Reviewed-by: David Ahern Signed-off-by: Justin Iurman Signed-off-by: David S. Miller --- include/net/ioam6.h | 4 +++ net/ipv6/ioam6.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/include/net/ioam6.h b/include/net/ioam6.h index 781d2d8b2f29..2cbbee6e806a 100644 --- a/include/net/ioam6.h +++ b/include/net/ioam6.h @@ -12,6 +12,7 @@ #include #include #include +#include #include struct ioam6_namespace { @@ -65,4 +66,7 @@ void ioam6_exit(void); int ioam6_iptunnel_init(void); void ioam6_iptunnel_exit(void); +void ioam6_event(enum ioam6_event_type type, struct net *net, gfp_t gfp, + void *opt, unsigned int opt_len); + #endif /* _NET_IOAM6_H */ diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c index 571f0e4d9cf3..5fa923f06632 100644 --- a/net/ipv6/ioam6.c +++ b/net/ipv6/ioam6.c @@ -612,6 +612,68 @@ static const struct genl_ops ioam6_genl_ops[] = { }, }; +#define IOAM6_GENL_EV_GRP_OFFSET 0 + +static const struct genl_multicast_group ioam6_mcgrps[] = { + [IOAM6_GENL_EV_GRP_OFFSET] = { .name = IOAM6_GENL_EV_GRP_NAME, + .flags = GENL_MCAST_CAP_NET_ADMIN }, +}; + +static int ioam6_event_put_trace(struct sk_buff *skb, + struct ioam6_trace_hdr *trace, + unsigned int len) +{ + if (nla_put_u16(skb, IOAM6_EVENT_ATTR_TRACE_NAMESPACE, + be16_to_cpu(trace->namespace_id)) || + nla_put_u8(skb, IOAM6_EVENT_ATTR_TRACE_NODELEN, trace->nodelen) || + nla_put_u32(skb, IOAM6_EVENT_ATTR_TRACE_TYPE, + be32_to_cpu(trace->type_be32)) || + nla_put(skb, IOAM6_EVENT_ATTR_TRACE_DATA, + len - sizeof(struct ioam6_trace_hdr) - trace->remlen * 4, + trace->data + trace->remlen * 4)) + return 1; + + return 0; +} + +void ioam6_event(enum ioam6_event_type type, struct net *net, gfp_t gfp, + void *opt, unsigned int opt_len) +{ + struct nlmsghdr *nlh; + struct sk_buff *skb; + + if (!genl_has_listeners(&ioam6_genl_family, net, + IOAM6_GENL_EV_GRP_OFFSET)) + return; + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!skb) + return; + + nlh = genlmsg_put(skb, 0, 0, &ioam6_genl_family, 0, type); + if (!nlh) + goto nla_put_failure; + + switch (type) { + case IOAM6_EVENT_UNSPEC: + WARN_ON_ONCE(1); + break; + case IOAM6_EVENT_TRACE: + if (ioam6_event_put_trace(skb, (struct ioam6_trace_hdr *)opt, + opt_len)) + goto nla_put_failure; + break; + } + + genlmsg_end(skb, nlh); + genlmsg_multicast_netns(&ioam6_genl_family, net, skb, 0, + IOAM6_GENL_EV_GRP_OFFSET, gfp); + return; + +nla_put_failure: + nlmsg_free(skb); +} + static struct genl_family ioam6_genl_family __ro_after_init = { .name = IOAM6_GENL_NAME, .version = IOAM6_GENL_VERSION, @@ -620,6 +682,8 @@ static struct genl_family ioam6_genl_family __ro_after_init = { .ops = ioam6_genl_ops, .n_ops = ARRAY_SIZE(ioam6_genl_ops), .resv_start_op = IOAM6_CMD_NS_SET_SCHEMA + 1, + .mcgrps = ioam6_mcgrps, + .n_mcgrps = ARRAY_SIZE(ioam6_mcgrps), .module = THIS_MODULE, }; From f655c78d6225f585ef60a9d93ffb79d507ff3ad3 Mon Sep 17 00:00:00 2001 From: Justin Iurman Date: Mon, 26 Feb 2024 14:14:12 +0100 Subject: [PATCH 1587/2255] net: exthdrs: ioam6: send trace event If we're processing an IOAM Pre-allocated Trace Option-Type (the only one supported currently), then send the trace as an ioam6 event to the netlink multicast group. This way, user space apps will be able to collect IOAM data. Reviewed-by: David Ahern Signed-off-by: Justin Iurman Signed-off-by: David S. Miller --- net/ipv6/exthdrs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 02e9ffb63af1..727792907d6c 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -50,6 +50,7 @@ #endif #include #include +#include #include #include @@ -954,6 +955,9 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff) + optoff + sizeof(*hdr)); ioam6_fill_trace_data(skb, ns, trace, true); + + ioam6_event(IOAM6_EVENT_TRACE, dev_net(skb->dev), + GFP_ATOMIC, (void *)trace, hdr->opt_len - 2); break; default: break; From 26311cd112d05abe8cbe87189c93fa25cc25709b Mon Sep 17 00:00:00 2001 From: Sarosh Hasan Date: Mon, 26 Feb 2024 15:12:26 +0530 Subject: [PATCH 1588/2255] net: stmmac: dwmac-qcom-ethqos: Update link clock rate only for RGMII Updating link clock rate for different speeds is only needed when using RGMII, as that mode requires changing clock speed when the link speed changes. Let's restrict updating the link clock speed in ethqos_update_link_clk() to just RGMII. Other modes such as SGMII only need to enable the link clock (which is already done in probe). Signed-off-by: Sarosh Hasan Reviewed-by: Andrew Lunn Reviewed-by: Andrew Halaney Tested-by: Andrew Halaney # sa8775p-ride Reviewed-by: Abhishek Chauhan Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 3e7aa743ca97..e254b21fdb59 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -170,6 +170,9 @@ static void rgmii_dump(void *priv) static void ethqos_update_link_clk(struct qcom_ethqos *ethqos, unsigned int speed) { + if (!phy_interface_mode_is_rgmii(ethqos->phy_mode)) + return; + switch (speed) { case SPEED_1000: ethqos->link_clk_rate = RGMII_1000_NOM_CLK_FREQ; From 2e26b6dfade4db750809b9231cce49498bb71767 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Tue, 27 Feb 2024 08:57:45 +0800 Subject: [PATCH 1589/2255] ipv6: raw: remove useless input parameter in rawv6_get/seticmpfilter The input parameter 'level' in rawv6_get/seticmpfilter is not used. Therefore, remove it. Signed-off-by: Zhengchao Shao Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ipv6/raw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 479c4c2c1785..76e6eb3b643d 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -934,7 +934,7 @@ do_confirm: goto done; } -static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, +static int rawv6_seticmpfilter(struct sock *sk, int optname, sockptr_t optval, int optlen) { switch (optname) { @@ -951,7 +951,7 @@ static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, return 0; } -static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, +static int rawv6_geticmpfilter(struct sock *sk, int optname, char __user *optval, int __user *optlen) { int len; @@ -1037,7 +1037,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, case SOL_ICMPV6: if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; - return rawv6_seticmpfilter(sk, level, optname, optval, optlen); + return rawv6_seticmpfilter(sk, optname, optval, optlen); case SOL_IPV6: if (optname == IPV6_CHECKSUM || optname == IPV6_HDRINCL) @@ -1098,7 +1098,7 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, case SOL_ICMPV6: if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; - return rawv6_geticmpfilter(sk, level, optname, optval, optlen); + return rawv6_geticmpfilter(sk, optname, optval, optlen); case SOL_IPV6: if (optname == IPV6_CHECKSUM || optname == IPV6_HDRINCL) From 576b2015e7e02460a690769fb81a561cc748b877 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 Feb 2024 11:40:23 +0100 Subject: [PATCH 1590/2255] wifi: b43: silence sparse warnings sparse complains on this code about casts that lose bits due to the usage of bitwise not, but really we do want 16 bits only, so clarify that by using masks. Signed-off-by: Johannes Berg Signed-off-by: Kalle Valo Link: https://msgid.link/20240223114023.c64e2d348453.Iccc4ace1116721a044e5f31f40ea7709e72145f3@changeid --- drivers/net/wireless/broadcom/b43/phy_ht.c | 6 +++--- drivers/net/wireless/broadcom/b43/phy_n.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/phy_ht.c b/drivers/net/wireless/broadcom/b43/phy_ht.c index d050971d150a..26a226126bc4 100644 --- a/drivers/net/wireless/broadcom/b43/phy_ht.c +++ b/drivers/net/wireless/broadcom/b43/phy_ht.c @@ -322,8 +322,8 @@ static void b43_phy_ht_bphy_reset(struct b43_wldev *dev, bool reset) B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX); else b43_phy_mask(dev, B43_PHY_B_BBCFG, - (u16)~(B43_PHY_B_BBCFG_RSTCCA | - B43_PHY_B_BBCFG_RSTRX)); + 0xffff & ~(B43_PHY_B_BBCFG_RSTCCA | + B43_PHY_B_BBCFG_RSTRX)); b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp); } @@ -551,7 +551,7 @@ static void b43_phy_ht_tx_power_ctl(struct b43_wldev *dev, bool enable) phy_ht->tx_pwr_idx[i] = b43_phy_read(dev, status_regs[i]); } - b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1, ~en_bits); + b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1, 0xffff & ~en_bits); } else { b43_phy_set(dev, B43_PHY_HT_TXPCTL_CMD_C1, en_bits); diff --git a/drivers/net/wireless/broadcom/b43/phy_n.c b/drivers/net/wireless/broadcom/b43/phy_n.c index 2c0c019a815d..4bb005b93f2c 100644 --- a/drivers/net/wireless/broadcom/b43/phy_n.c +++ b/drivers/net/wireless/broadcom/b43/phy_n.c @@ -6246,7 +6246,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4); /* Take BPHY out of the reset */ b43_phy_mask(dev, B43_PHY_B_BBCFG, - (u16)~(B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX)); + ~(B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX) & 0xffff); b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16); } @@ -6377,7 +6377,7 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, } else if (channel_type == NL80211_CHAN_HT40MINUS) { b43_phy_mask(dev, B43_NPHY_RXCTL, ~B43_NPHY_RXCTL_BSELU20); if (phy->rev >= 7) - b43_phy_mask(dev, 0x310, (u16)~0x8000); + b43_phy_mask(dev, 0x310, 0x7fff); } if (phy->rev >= 19) { From 17672ced7d734a7d0647a26956c269b9098387a6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 Feb 2024 11:40:24 +0100 Subject: [PATCH 1591/2255] wifi: brcmsmac: silence sparse warnings sparse complains on this code about casts that lose bits due to the usage of bitwise not, but really we do want 16 bits only, so clarify that by using masks. Signed-off-by: Johannes Berg Signed-off-by: Kalle Valo Link: https://msgid.link/20240223114023.06e5ade90bcd.I41a0cbae1fa259cfbf5fa117ddfce908877475a2@changeid --- .../broadcom/brcm80211/brcmsmac/phy/phy_lcn.c | 2 +- .../broadcom/brcm80211/brcmsmac/phy/phy_n.c | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c index 7717eb85a1db..aae2cf95fe95 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c @@ -3299,7 +3299,7 @@ wlc_lcnphy_run_samples(struct brcms_phy *pi, if (iqcalmode) { - and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15)); + and_phy_reg(pi, 0x453, 0xffff & ~(0x1 << 15)); or_phy_reg(pi, 0x453, (0x1 << 15)); } else { write_phy_reg(pi, 0x63f, 1); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index cd9b502a6a9f..d69879e1bd87 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -17582,7 +17582,7 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) or_phy_reg(pi, 0x122, (0x1 << 0)); if (NREV_GE(pi->pubpi.phy_rev, 3)) - and_phy_reg(pi, 0x1e7, (u16) (~(0x1 << 15))); + and_phy_reg(pi, 0x1e7, 0x7fff); else or_phy_reg(pi, 0x1e7, (0x1 << 15)); @@ -18081,7 +18081,7 @@ wlc_phy_rfctrlintc_override_nphy(struct brcms_phy *pi, u8 field, u16 value, (0x1 << 10)); and_phy_reg(pi, 0x2ff, (u16) - ~(0x3 << 14)); + 0xffff & ~(0x3 << 14)); or_phy_reg(pi, 0x2ff, (0x1 << 13)); or_phy_reg(pi, 0x2ff, (0x1 << 0)); } else { @@ -21048,7 +21048,7 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, (val | MAC_PHY_FORCE_CLK)); and_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG), - (u16) (~(BBCFG_RESETCCA | BBCFG_RESETRX))); + 0xffff & ~(BBCFG_RESETCCA | BBCFG_RESETRX)); bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), val); } @@ -21282,7 +21282,8 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) bcma_set16(pi->d11core, D11REGOFFS(psm_gpio_oe), mask); - bcma_mask16(pi->d11core, D11REGOFFS(psm_gpio_out), ~mask); + bcma_mask16(pi->d11core, D11REGOFFS(psm_gpio_out), + 0xffff & ~mask); if (lut_init) { write_phy_reg(pi, 0xf8, 0x02d8); @@ -23192,7 +23193,7 @@ void wlc_phy_stopplayback_nphy(struct brcms_phy *pi) or_phy_reg(pi, 0xc3, NPHY_sampleCmd_STOP); else if (playback_status & 0x2) and_phy_reg(pi, 0xc2, - (u16) ~NPHY_iqloCalCmdGctl_IQLO_CAL_EN); + 0xffff & ~NPHY_iqloCalCmdGctl_IQLO_CAL_EN); and_phy_reg(pi, 0xc3, (u16) ~(0x1 << 2)); @@ -28197,8 +28198,9 @@ void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type) if (NREV_GE(pi->pubpi.phy_rev, 3)) and_phy_reg(pi, 0x1e7, - (u16) (~((0x1 << 15) | - (0x1 << 14) | (0x1 << 13)))); + 0xffff & ~((0x1 << 15) | + (0x1 << 14) | + (0x1 << 13))); else and_phy_reg(pi, 0x1e7, (u16) (~((0x1 << 14) | (0x1 << 13)))); From e06324303662fc23bb91e4e9d86650fb8c6d8398 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 Feb 2024 11:40:25 +0100 Subject: [PATCH 1592/2255] wifi: rt2x00: silence sparse warnings Clearly writing __le32 was intended here, so just put the right casts into the code to silence sparse about it. Signed-off-by: Johannes Berg Signed-off-by: Kalle Valo Link: https://msgid.link/20240223114023.ce0c714124e9.I2b5710b761f63522574fbe7654d37151c31e0b77@changeid --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index aaf31857ae1e..3bb81bcff0ac 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -10946,13 +10946,13 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) /* Apparently the data is read from end to start */ reg = rt2800_register_read_lock(rt2x00dev, efuse_data3_reg); /* The returned value is in CPU order, but eeprom is le */ - *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); + *(__le32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); reg = rt2800_register_read_lock(rt2x00dev, efuse_data2_reg); - *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); + *(__le32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); reg = rt2800_register_read_lock(rt2x00dev, efuse_data1_reg); - *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg); + *(__le32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg); reg = rt2800_register_read_lock(rt2x00dev, efuse_data0_reg); - *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg); + *(__le32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg); mutex_unlock(&rt2x00dev->csr_mutex); } From 5a391813e7ef5f12a55e3266a6832732916c7c10 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 Feb 2024 11:40:27 +0100 Subject: [PATCH 1593/2255] wifi: zd1211rw: silence sparse warnings This code wants to compare the obtained value, but as it also has a special type for register addresses to find places doing such compares and calculations wrong, we need explicit casts here to silence sparse. Signed-off-by: Johannes Berg Signed-off-by: Kalle Valo Link: https://msgid.link/20240223114023.976fcd59e97a.I0bba4ef7dc2847ce8ab5ec229149e1a09413b8b9@changeid --- drivers/net/wireless/zydas/zd1211rw/zd_usb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index 8505d84eeed6..f3b567a13ded 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -380,7 +380,7 @@ static inline void handle_regs_int(struct urb *urb) spin_lock_irqsave(&intr->lock, flags); int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2)); - if (int_num == CR_INTERRUPT) { + if (int_num == (u16)CR_INTERRUPT) { struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context)); spin_lock(&mac->lock); memcpy(&mac->intr_buffer, urb->transfer_buffer, @@ -416,7 +416,8 @@ out: spin_unlock_irqrestore(&intr->lock, flags); /* CR_INTERRUPT might override read_reg too. */ - if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled)) + if (int_num == (u16)CR_INTERRUPT && + atomic_read(&intr->read_regs_enabled)) handle_regs_int_override(urb); } From a7e178259c5bc900da762b33d3a20b7ee1206f07 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Fri, 23 Feb 2024 21:34:32 +0800 Subject: [PATCH 1594/2255] wifi: rtl8xxxu: fix mixed declarations in rtl8xxxu_set_aifs() Moving struct ieee80211_sta *sta variable definition to the front of the code to fix the ISO C90 forbids mixed declarations and code warning. Fixes: 43532c050f8e ("wifi: rtl8xxxu: support multiple interfaces in set_aifs()") Signed-off-by: Shiji Yang Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/TYAP286MB03157A408E0D69F2F6FBD88ABC552@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index efddbe402f0d..4a49f8f9d80f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4919,11 +4919,11 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time) int i; for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { + struct ieee80211_sta *sta; + if (!priv->vifs[i]) continue; - struct ieee80211_sta *sta; - rcu_read_lock(); sta = ieee80211_find_sta(priv->vifs[i], priv->vifs[i]->bss_conf.bssid); if (sta) From 416eb60317c64676d158dffea150762930ec008f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 Feb 2024 10:01:46 +0100 Subject: [PATCH 1595/2255] bitfield: suppress "dubious: x & !y" sparse warning There's a somewhat common pattern of using FIELD_PREP() even for single bits, e.g. cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP, !!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP)); which might as well be written as if (params.flags & HAL_SRNG_FLAGS_MSI_SWAP) cmd->info1 |= HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP; (since info1 is fully initialized to start with), but in a long chain of FIELD_PREP() this really seems fine. However, it triggers a sparse warning, in the check in the macro for whether a constant value fits into the mask, as this contains a "& (_val)". In this case, this really is always intentional, so just suppress the warning by adding "0+" to the expression, indicating explicitly that this is correct. Signed-off-by: Johannes Berg Signed-off-by: Kalle Valo Link: https://msgid.link/20240223100146.d243b6b1a9a1.I033828b1187c6bccf086e31400f7e933bb8373e7@changeid --- include/linux/bitfield.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index ebfa12f69501..63928f173223 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -66,7 +66,8 @@ _pfx "mask is not constant"); \ BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \ BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ - ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ + ~((_mask) >> __bf_shf(_mask)) & \ + (0 + (_val)) : 0, \ _pfx "value too large for the field"); \ BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ __bf_cast_unsigned(_reg, ~0ull), \ From 17206c116d756268824db0acb272e2ac4230bd36 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:07 -0600 Subject: [PATCH 1596/2255] net: usb: r8152: Use linkmode helpers for EEE Make use of the existing linkmode helpers for converting PHY EEE register values into links modes, now that ethtool_keee uses link modes, rather than u32 values. Rework determining if EEE is active to make is similar as to how phylib decides, and make use of a phylib helper to validate if EEE is valid in for the current link mode. This then requires that PHYLIB is selected. Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/usb/Kconfig | 1 + drivers/net/usb/r8152.c | 33 ++++++++++++++++----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 3fd7dccf0f9c..3c360d4f0635 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -99,6 +99,7 @@ config USB_RTL8150 config USB_RTL8152 tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" select MII + select PHYLIB select CRC32 select CRYPTO select CRYPTO_HASH diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 3d806b3ff425..6d0dc2c967c4 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -8924,30 +8925,29 @@ static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) static int r8152_get_eee(struct r8152 *tp, struct ethtool_keee *eee) { - u32 lp, adv, supported = 0; + __ETHTOOL_DECLARE_LINK_MODE_MASK(common); u16 val; val = r8152_mmd_read(tp, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); - supported = mmd_eee_cap_to_ethtool_sup_t(val); + mii_eee_cap1_mod_linkmode_t(eee->supported, val); val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV); - adv = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(eee->advertised, val); val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); - lp = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(eee->lp_advertised, val); eee->eee_enabled = tp->eee_en; - eee->eee_active = !!(supported & adv & lp); - eee->supported_u32 = supported; - eee->advertised_u32 = tp->eee_adv; - eee->lp_advertised_u32 = lp; + + linkmode_and(common, eee->advertised, eee->lp_advertised); + eee->eee_active = phy_check_valid(tp->speed, tp->duplex, common); return 0; } static int r8152_set_eee(struct r8152 *tp, struct ethtool_keee *eee) { - u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised_u32); + u16 val = linkmode_to_mii_eee_cap1_t(eee->advertised); tp->eee_en = eee->eee_enabled; tp->eee_adv = val; @@ -8959,23 +8959,22 @@ static int r8152_set_eee(struct r8152 *tp, struct ethtool_keee *eee) static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee) { - u32 lp, adv, supported = 0; + __ETHTOOL_DECLARE_LINK_MODE_MASK(common); u16 val; val = ocp_reg_read(tp, OCP_EEE_ABLE); - supported = mmd_eee_cap_to_ethtool_sup_t(val); + mii_eee_cap1_mod_linkmode_t(eee->supported, val); val = ocp_reg_read(tp, OCP_EEE_ADV); - adv = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(eee->advertised, val); val = ocp_reg_read(tp, OCP_EEE_LPABLE); - lp = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(eee->lp_advertised, val); eee->eee_enabled = tp->eee_en; - eee->eee_active = !!(supported & adv & lp); - eee->supported_u32 = supported; - eee->advertised_u32 = tp->eee_adv; - eee->lp_advertised_u32 = lp; + + linkmode_and(common, eee->advertised, eee->lp_advertised); + eee->eee_active = phy_check_valid(tp->speed, tp->duplex, common); return 0; } From 93e6da6cce4ab4313a3644c17519cb7726b4afd4 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:08 -0600 Subject: [PATCH 1597/2255] net: usb: ax88179_178a: Use linkmode helpers for EEE Make use of the existing linkmode helpers for converting PHY EEE register values into links modes, now that ethtool_keee uses link modes, rather than u32 values. Signed-off-by: Andrew Lunn Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/usb/ax88179_178a.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index d6168eaa286f..88e084534853 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -676,21 +676,21 @@ ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_keee *data) MDIO_MMD_PCS); if (val < 0) return val; - data->supported_u32 = mmd_eee_cap_to_ethtool_sup_t(val); + mii_eee_cap1_mod_linkmode_t(data->supported, val); /* Get advertisement EEE */ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV, MDIO_MMD_AN); if (val < 0) return val; - data->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(data->advertised, val); /* Get LP advertisement EEE */ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN); if (val < 0) return val; - data->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); + mii_eee_cap1_mod_linkmode_t(data->lp_advertised, val); return 0; } @@ -698,7 +698,7 @@ ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_keee *data) static int ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_keee *data) { - u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised_u32); + u16 tmp16 = linkmode_to_mii_eee_cap1_t(data->advertised); return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, tmp16); @@ -1663,7 +1663,7 @@ static int ax88179_reset(struct usbnet *dev) ax88179_disable_eee(dev); ax88179_ethtool_get_eee(dev, &eee_data); - eee_data.advertised_u32 = 0; + linkmode_zero(eee_data.advertised); ax88179_ethtool_set_eee(dev, &eee_data); /* Restart autoneg */ From 9f8b8adca800d08c9dd736531bb4250ac6adc4dc Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:09 -0600 Subject: [PATCH 1598/2255] net: qlogic: qede: Use linkmode helpers for EEE Make use of the existing linkmode helpers for bit manipulation of EEE advertise, support and link partner support. The aim is to drop the restricted _u32 variants in the near future. Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- .../net/ethernet/qlogic/qede/qede_ethtool.c | 60 ++++++++++++------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index dfa15619fd78..ae3ebf0cf999 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1789,18 +1789,26 @@ static int qede_get_eee(struct net_device *dev, struct ethtool_keee *edata) return -EOPNOTSUPP; } - if (current_link.eee.adv_caps & QED_EEE_1G_ADV) - edata->advertised_u32 = ADVERTISED_1000baseT_Full; - if (current_link.eee.adv_caps & QED_EEE_10G_ADV) - edata->advertised_u32 |= ADVERTISED_10000baseT_Full; - if (current_link.sup_caps & QED_EEE_1G_ADV) - edata->supported_u32 = ADVERTISED_1000baseT_Full; - if (current_link.sup_caps & QED_EEE_10G_ADV) - edata->supported_u32 |= ADVERTISED_10000baseT_Full; - if (current_link.eee.lp_adv_caps & QED_EEE_1G_ADV) - edata->lp_advertised_u32 = ADVERTISED_1000baseT_Full; - if (current_link.eee.lp_adv_caps & QED_EEE_10G_ADV) - edata->lp_advertised_u32 |= ADVERTISED_10000baseT_Full; + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + edata->advertised, + current_link.eee.adv_caps & QED_EEE_1G_ADV); + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + edata->advertised, + current_link.eee.adv_caps & QED_EEE_10G_ADV); + + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + edata->supported, + current_link.sup_caps & QED_EEE_1G_ADV); + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + edata->supported, + current_link.sup_caps & QED_EEE_10G_ADV); + + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + edata->lp_advertised, + current_link.eee.lp_adv_caps & QED_EEE_1G_ADV); + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + edata->lp_advertised, + current_link.eee.lp_adv_caps & QED_EEE_10G_ADV); edata->tx_lpi_timer = current_link.eee.tx_lpi_timer; edata->eee_enabled = current_link.eee.enable; @@ -1812,9 +1820,12 @@ static int qede_get_eee(struct net_device *dev, struct ethtool_keee *edata) static int qede_set_eee(struct net_device *dev, struct ethtool_keee *edata) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = {}; + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = {}; struct qede_dev *edev = netdev_priv(dev); struct qed_link_output current_link; struct qed_link_params params; + bool unsupp; if (!edev->ops->common->can_link_change(edev->cdev)) { DP_INFO(edev, "Link settings are not allowed to be changed\n"); @@ -1832,21 +1843,26 @@ static int qede_set_eee(struct net_device *dev, struct ethtool_keee *edata) memset(¶ms, 0, sizeof(params)); params.override_flags |= QED_LINK_OVERRIDE_EEE_CONFIG; - if (!(edata->advertised_u32 & (ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)) || - ((edata->advertised_u32 & (ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)) != - edata->advertised_u32)) { + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + supported); + + unsupp = linkmode_andnot(tmp, edata->advertised, supported); + if (unsupp) { DP_VERBOSE(edev, QED_MSG_DEBUG, - "Invalid advertised capabilities %d\n", - edata->advertised_u32); + "Invalid advertised capabilities %*pb\n", + __ETHTOOL_LINK_MODE_MASK_NBITS, edata->advertised); return -EINVAL; } - if (edata->advertised_u32 & ADVERTISED_1000baseT_Full) + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + edata->advertised)) params.eee.adv_caps = QED_EEE_1G_ADV; - if (edata->advertised_u32 & ADVERTISED_10000baseT_Full) - params.eee.adv_caps |= QED_EEE_10G_ADV; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + edata->advertised)) + params.eee.adv_caps = QED_EEE_10G_ADV; + params.eee.enable = edata->eee_enabled; params.eee.tx_lpi_enable = edata->tx_lpi_enabled; params.eee.tx_lpi_timer = edata->tx_lpi_timer; From 9356b6db9d051e9d939dd0f9ae7a0514103ef228 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:10 -0600 Subject: [PATCH 1599/2255] net: ethernet: ixgbe: Convert EEE to use linkmodes Convert the tables to make use of ETHTOOL link mode bits, rather than the old u32 SUPPORTED speeds. Make use of the linkmode helps to set bits and compare linkmodes. As a result, the _u32 members of keee are no longer used, a step towards removing them. Signed-off-by: Andrew Lunn Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index b1e7338a4ed1..633bac1543dd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -3403,30 +3403,31 @@ static int ixgbe_get_module_eeprom(struct net_device *dev, static const struct { ixgbe_link_speed mac_speed; - u32 supported; + u32 link_mode; } ixgbe_ls_map[] = { - { IXGBE_LINK_SPEED_10_FULL, SUPPORTED_10baseT_Full }, - { IXGBE_LINK_SPEED_100_FULL, SUPPORTED_100baseT_Full }, - { IXGBE_LINK_SPEED_1GB_FULL, SUPPORTED_1000baseT_Full }, - { IXGBE_LINK_SPEED_2_5GB_FULL, SUPPORTED_2500baseX_Full }, - { IXGBE_LINK_SPEED_10GB_FULL, SUPPORTED_10000baseT_Full }, + { IXGBE_LINK_SPEED_10_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT }, + { IXGBE_LINK_SPEED_100_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT }, + { IXGBE_LINK_SPEED_1GB_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT }, + { IXGBE_LINK_SPEED_2_5GB_FULL, ETHTOOL_LINK_MODE_2500baseX_Full_BIT }, + { IXGBE_LINK_SPEED_10GB_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT }, }; static const struct { u32 lp_advertised; - u32 mac_speed; + u32 link_mode; } ixgbe_lp_map[] = { - { FW_PHY_ACT_UD_2_100M_TX_EEE, SUPPORTED_100baseT_Full }, - { FW_PHY_ACT_UD_2_1G_T_EEE, SUPPORTED_1000baseT_Full }, - { FW_PHY_ACT_UD_2_10G_T_EEE, SUPPORTED_10000baseT_Full }, - { FW_PHY_ACT_UD_2_1G_KX_EEE, SUPPORTED_1000baseKX_Full }, - { FW_PHY_ACT_UD_2_10G_KX4_EEE, SUPPORTED_10000baseKX4_Full }, - { FW_PHY_ACT_UD_2_10G_KR_EEE, SUPPORTED_10000baseKR_Full}, + { FW_PHY_ACT_UD_2_100M_TX_EEE, ETHTOOL_LINK_MODE_100baseT_Full_BIT }, + { FW_PHY_ACT_UD_2_1G_T_EEE, ETHTOOL_LINK_MODE_1000baseT_Full_BIT }, + { FW_PHY_ACT_UD_2_10G_T_EEE, ETHTOOL_LINK_MODE_10000baseT_Full_BIT }, + { FW_PHY_ACT_UD_2_1G_KX_EEE, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT }, + { FW_PHY_ACT_UD_2_10G_KX4_EEE, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT }, + { FW_PHY_ACT_UD_2_10G_KR_EEE, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT}, }; static int ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(common); u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; struct ixgbe_hw *hw = &adapter->hw; int rc; @@ -3436,28 +3437,29 @@ ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata) if (rc) return rc; - edata->lp_advertised_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_lp_map); ++i) { if (info[0] & ixgbe_lp_map[i].lp_advertised) - edata->lp_advertised_u32 |= ixgbe_lp_map[i].mac_speed; + linkmode_set_bit(ixgbe_lp_map[i].link_mode, + edata->lp_advertised); } - edata->supported_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed) - edata->supported_u32 |= ixgbe_ls_map[i].supported; + linkmode_set_bit(ixgbe_lp_map[i].link_mode, + edata->supported); } - edata->advertised_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed) - edata->advertised_u32 |= ixgbe_ls_map[i].supported; + linkmode_set_bit(ixgbe_lp_map[i].link_mode, + edata->advertised); } - edata->eee_enabled = !!edata->advertised_u32; + edata->eee_enabled = !linkmode_empty(edata->advertised); edata->tx_lpi_enabled = edata->eee_enabled; - if (edata->advertised_u32 & edata->lp_advertised_u32) - edata->eee_active = true; + + linkmode_and(common, edata->advertised, edata->lp_advertised); + edata->eee_active = !linkmode_empty(common); return 0; } @@ -3504,7 +3506,7 @@ static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_keee *edata) return -EINVAL; } - if (eee_data.advertised_u32 != edata->advertised_u32) { + if (!linkmode_equal(eee_data.advertised, edata->advertised)) { e_err(drv, "Setting EEE advertised speeds is not supported\n"); return -EINVAL; From 01cf893bf0f4ee47737674ca5448183a326041c6 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:11 -0600 Subject: [PATCH 1600/2255] net: intel: i40e/igc: Remove setting Autoneg in EEE capabilities Energy Efficient Ethernet should always be negotiated with the link peer. Don't include SUPPORTED_Autoneg in the results of get_eee() for supported, advertised or lp_advertised, since it is assumed. Additionally, ethtool(1) ignores the set bit, and no other driver sets this. Reviewed-by: Jacob Keller Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 7 +------ drivers/net/ethernet/intel/igc/igc_ethtool.c | 4 ---- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 1b5473358e1a..42e7e6cdaa6d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5664,16 +5664,12 @@ static int i40e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) if (phy_cfg.eee_capability == 0) return -EOPNOTSUPP; - edata->supported_u32 = SUPPORTED_Autoneg; - edata->lp_advertised_u32 = edata->supported_u32; - /* Get current configuration */ status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_cfg, NULL); if (status) return -EAGAIN; - edata->advertised_u32 = phy_cfg.eee_capability ? SUPPORTED_Autoneg : 0U; - edata->eee_enabled = !!edata->advertised_u32; + edata->eee_enabled = !!phy_cfg.eee_capability; edata->tx_lpi_enabled = pf->stats.tx_lpi_status; edata->eee_active = pf->stats.tx_lpi_status && pf->stats.rx_lpi_status; @@ -5691,7 +5687,6 @@ static int i40e_is_eee_param_supported(struct net_device *netdev, u32 value; const char *name; } param[] = { - {edata->advertised_u32 & ~SUPPORTED_Autoneg, "advertise"}, {edata->tx_lpi_timer, "tx-timer"}, {edata->tx_lpi_enabled != pf->stats.tx_lpi_status, "tx-lpi"} }; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 47c797dd2cd9..ac92d10a3e97 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1634,7 +1634,6 @@ static int igc_ethtool_get_eee(struct net_device *netdev, mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); *edata = adapter->eee; - edata->supported_u32 = SUPPORTED_Autoneg; eeer = rd32(IGC_EEER); @@ -1647,9 +1646,6 @@ static int igc_ethtool_get_eee(struct net_device *netdev, edata->eee_enabled = hw->dev_spec._base.eee_enable; - edata->advertised_u32 = SUPPORTED_Autoneg; - edata->lp_advertised_u32 = SUPPORTED_Autoneg; - /* Report correct negotiated EEE status for devices that * wrongly report EEE at half-duplex */ From 02de1741eaf1ad0f242dbe7682a1e0d7595481c0 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:12 -0600 Subject: [PATCH 1601/2255] net: intel: e1000e: Use linkmode helpers for EEE Make use of the existing linkmode helpers for converting PHY EEE register values into links modes, now that ethtool_keee uses link modes, rather than u32 values. Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000e/ethtool.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index ff243ae71b78..dc553c51d79a 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -2223,16 +2223,16 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data); if (ret_val) goto release; - edata->supported_u32 = mmd_eee_cap_to_ethtool_sup_t(phy_data); + mii_eee_cap1_mod_linkmode_t(edata->supported, phy_data); /* EEE Advertised */ - edata->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); + mii_eee_cap1_mod_linkmode_t(edata->advertised, adapter->eee_advert); /* EEE Link Partner Advertised */ ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data); if (ret_val) goto release; - edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); + mii_eee_cap1_mod_linkmode_t(edata->lp_advertised, phy_data); /* EEE PCS Status */ ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data); @@ -2265,6 +2265,8 @@ release: static int e1000e_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct e1000_adapter *adapter = netdev_priv(netdev); + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = {}; + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = {}; struct e1000_hw *hw = &adapter->hw; struct ethtool_keee eee_curr; s32 ret_val; @@ -2283,12 +2285,17 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_keee *edata) return -EINVAL; } - if (edata->advertised_u32 & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) { + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + supported); + + if (linkmode_andnot(tmp, edata->advertised, supported)) { e_err("EEE advertisement supports only 100TX and/or 1000T full-duplex\n"); return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); + adapter->eee_advert = linkmode_to_mii_eee_cap1_t(edata->advertised); hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled; From 41b9797de4d60370285b98246a9870ae69850875 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:13 -0600 Subject: [PATCH 1602/2255] net: intel: igb: Use linkmode helpers for EEE Make use of the existing linkmode helpers for converting PHY EEE register values into links modes, now that ethtool_keee uses link modes, rather than u32 values. Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb_ethtool.c | 35 +++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index b87b23d2151c..99977a22b843 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -3038,11 +3038,13 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) (hw->phy.media_type != e1000_media_type_copper)) return -EOPNOTSUPP; - edata->supported_u32 = (SUPPORTED_1000baseT_Full | - SUPPORTED_100baseT_Full); + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + edata->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + edata->supported); if (!hw->dev_spec._82575.eee_disable) - edata->advertised_u32 = - mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); + mii_eee_cap1_mod_linkmode_t(edata->advertised, + adapter->eee_advert); /* The IPCNFG and EEER registers are not supported on I354. */ if (hw->mac.type == e1000_i354) { @@ -3068,7 +3070,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) if (ret_val) return -ENODATA; - edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); + mii_eee_cap1_mod_linkmode_t(edata->lp_advertised, phy_data); break; case e1000_i354: case e1000_i210: @@ -3079,7 +3081,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) if (ret_val) return -ENODATA; - edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); + mii_eee_cap1_mod_linkmode_t(edata->lp_advertised, phy_data); break; default: @@ -3099,7 +3101,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) edata->eee_enabled = false; edata->eee_active = false; edata->tx_lpi_enabled = false; - edata->advertised_u32 &= ~edata->advertised_u32; + linkmode_zero(edata->advertised); } return 0; @@ -3109,6 +3111,8 @@ static int igb_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct igb_adapter *adapter = netdev_priv(netdev); + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = {}; + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = {}; struct e1000_hw *hw = &adapter->hw; struct ethtool_keee eee_curr; bool adv1g_eee = true, adv100m_eee = true; @@ -3138,14 +3142,21 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } - if (!edata->advertised_u32 || (edata->advertised_u32 & - ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) { + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + supported); + if (linkmode_andnot(tmp, edata->advertised, supported)) { dev_err(&adapter->pdev->dev, "EEE Advertisement supports only 100Tx and/or 100T full duplex\n"); return -EINVAL; } - adv100m_eee = !!(edata->advertised_u32 & ADVERTISE_100_FULL); - adv1g_eee = !!(edata->advertised_u32 & ADVERTISE_1000_FULL); + adv100m_eee = linkmode_test_bit( + ETHTOOL_LINK_MODE_100baseT_Full_BIT, + edata->advertised); + adv1g_eee = linkmode_test_bit( + ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + edata->advertised); } else if (!edata->eee_enabled) { dev_err(&adapter->pdev->dev, @@ -3153,7 +3164,7 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); + adapter->eee_advert = linkmode_to_mii_eee_cap1_t(edata->advertised); if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) { hw->dev_spec._82575.eee_disable = !edata->eee_enabled; adapter->flags |= IGB_FLAG_EEE; From 1e45b5f28a57f5cc89dfa7d3eaf2c65d5ba3cc0e Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:14 -0600 Subject: [PATCH 1603/2255] net: intel: igc: Use linkmode helpers for EEE Make use of the existing linkmode helpers for converting PHY EEE register values into links modes, now that ethtool_keee uses link modes, rather than u32 values. Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igc/igc_ethtool.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index ac92d10a3e97..1a64f1ca6ca8 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1630,8 +1630,8 @@ static int igc_ethtool_get_eee(struct net_device *netdev, u32 eeer; if (hw->dev_spec._base.eee_enable) - edata->advertised_u32 = - mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); + mii_eee_cap1_mod_linkmode_t(edata->advertised, + adapter->eee_advert); *edata = adapter->eee; @@ -1653,7 +1653,7 @@ static int igc_ethtool_get_eee(struct net_device *netdev, edata->eee_enabled = false; edata->eee_active = false; edata->tx_lpi_enabled = false; - edata->advertised_u32 &= ~edata->advertised_u32; + linkmode_zero(edata->advertised); } return 0; @@ -1695,7 +1695,8 @@ static int igc_ethtool_set_eee(struct net_device *netdev, return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); + adapter->eee_advert = linkmode_to_mii_eee_cap1_t(edata->advertised); + if (hw->dev_spec._base.eee_enable != edata->eee_enabled) { hw->dev_spec._base.eee_enable = edata->eee_enabled; adapter->flags |= IGC_FLAG_EEE; From 292fac464b012200c4e99d08974fed3bc087b848 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 Feb 2024 19:29:15 -0600 Subject: [PATCH 1604/2255] net: ethtool: eee: Remove legacy _u32 from keee All MAC drivers have been converted to use the link mode members of keee. So remove the _u32 values, and the code in the ethtool core to convert the legacy _u32 values to link modes. Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- include/linux/ethtool.h | 3 --- net/ethtool/eee.c | 31 ++++--------------------------- net/ethtool/ioctl.c | 29 ++++++++++------------------- 3 files changed, 14 insertions(+), 49 deletions(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index b90c33607594..9901e563f706 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -226,9 +226,6 @@ struct ethtool_keee { __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised); __ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertised); - u32 supported_u32; - u32 advertised_u32; - u32 lp_advertised_u32; u32 tx_lpi_timer; bool tx_lpi_enabled; bool eee_active; diff --git a/net/ethtool/eee.c b/net/ethtool/eee.c index db6faa18fe41..bf398973eb8a 100644 --- a/net/ethtool/eee.c +++ b/net/ethtool/eee.c @@ -4,9 +4,6 @@ #include "common.h" #include "bitset.h" -#define EEE_MODES_COUNT \ - (sizeof_field(struct ethtool_keee, supported_u32) * BITS_PER_BYTE) - struct eee_req_info { struct ethnl_req_info base; }; @@ -41,15 +38,6 @@ static int eee_prepare_data(const struct ethnl_req_info *req_base, ret = dev->ethtool_ops->get_eee(dev, eee); ethnl_ops_complete(dev); - if (!ret && !ethtool_eee_use_linkmodes(eee)) { - ethtool_convert_legacy_u32_to_link_mode(eee->supported, - eee->supported_u32); - ethtool_convert_legacy_u32_to_link_mode(eee->advertised, - eee->advertised_u32); - ethtool_convert_legacy_u32_to_link_mode(eee->lp_advertised, - eee->lp_advertised_u32); - } - return ret; } @@ -62,11 +50,6 @@ static int eee_reply_size(const struct ethnl_req_info *req_base, int len = 0; int ret; - BUILD_BUG_ON(sizeof(eee->advertised_u32) * BITS_PER_BYTE != - EEE_MODES_COUNT); - BUILD_BUG_ON(sizeof(eee->lp_advertised_u32) * BITS_PER_BYTE != - EEE_MODES_COUNT); - /* MODES_OURS */ ret = ethnl_bitset_size(eee->advertised, eee->supported, __ETHTOOL_LINK_MODE_MASK_NBITS, @@ -154,16 +137,10 @@ ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info) if (ret < 0) return ret; - if (ethtool_eee_use_linkmodes(&eee)) { - ret = ethnl_update_bitset(eee.advertised, - __ETHTOOL_LINK_MODE_MASK_NBITS, - tb[ETHTOOL_A_EEE_MODES_OURS], - link_mode_names, info->extack, &mod); - } else { - ret = ethnl_update_bitset32(&eee.advertised_u32, EEE_MODES_COUNT, - tb[ETHTOOL_A_EEE_MODES_OURS], - link_mode_names, info->extack, &mod); - } + ret = ethnl_update_bitset(eee.advertised, + __ETHTOOL_LINK_MODE_MASK_NBITS, + tb[ETHTOOL_A_EEE_MODES_OURS], + link_mode_names, info->extack, &mod); if (ret < 0) return ret; ethnl_update_bool(&eee.eee_enabled, tb[ETHTOOL_A_EEE_ENABLED], &mod); diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index b419969c0dcb..317308bdbda9 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1514,9 +1514,6 @@ static void eee_to_keee(struct ethtool_keee *keee, { memset(keee, 0, sizeof(*keee)); - keee->supported_u32 = eee->supported; - keee->advertised_u32 = eee->advertised; - keee->lp_advertised_u32 = eee->lp_advertised; keee->eee_active = eee->eee_active; keee->eee_enabled = eee->eee_enabled; keee->tx_lpi_enabled = eee->tx_lpi_enabled; @@ -1533,6 +1530,8 @@ static void eee_to_keee(struct ethtool_keee *keee, static void keee_to_eee(struct ethtool_eee *eee, const struct ethtool_keee *keee) { + bool overflow; + memset(eee, 0, sizeof(*eee)); eee->eee_active = keee->eee_active; @@ -1540,22 +1539,14 @@ static void keee_to_eee(struct ethtool_eee *eee, eee->tx_lpi_enabled = keee->tx_lpi_enabled; eee->tx_lpi_timer = keee->tx_lpi_timer; - if (ethtool_eee_use_linkmodes(keee)) { - bool overflow; - - overflow = !ethtool_convert_link_mode_to_legacy_u32(&eee->supported, - keee->supported); - ethtool_convert_link_mode_to_legacy_u32(&eee->advertised, - keee->advertised); - ethtool_convert_link_mode_to_legacy_u32(&eee->lp_advertised, - keee->lp_advertised); - if (overflow) - pr_warn("Ethtool ioctl interface doesn't support passing EEE linkmodes beyond bit 32\n"); - } else { - eee->supported = keee->supported_u32; - eee->advertised = keee->advertised_u32; - eee->lp_advertised = keee->lp_advertised_u32; - } + overflow = !ethtool_convert_link_mode_to_legacy_u32(&eee->supported, + keee->supported); + ethtool_convert_link_mode_to_legacy_u32(&eee->advertised, + keee->advertised); + ethtool_convert_link_mode_to_legacy_u32(&eee->lp_advertised, + keee->lp_advertised); + if (overflow) + pr_warn("Ethtool ioctl interface doesn't support passing EEE linkmodes beyond bit 32\n"); } static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) From 1cca1bddf9ef080503c15378cecf4877f7510015 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 23 Feb 2024 13:31:11 +0800 Subject: [PATCH 1605/2255] wifi: ath11k: decrease MHI channel buffer length to 8KB Currently buf_len field of ath11k_mhi_config_qca6390 is assigned with 0, making MHI use a default size, 64KB, to allocate channel buffers. This is likely to fail in some scenarios where system memory is highly fragmented and memory compaction or reclaim is not allowed. There is a fail report which is caused by it: kworker/u32:45: page allocation failure: order:4, mode:0x40c00(GFP_NOIO|__GFP_COMP), nodemask=(null),cpuset=/,mems_allowed=0 CPU: 0 PID: 19318 Comm: kworker/u32:45 Not tainted 6.8.0-rc3-1.gae4495f-default #1 openSUSE Tumbleweed (unreleased) 493b6d5b382c603654d7a81fc3c144d59a1dfceb Workqueue: events_unbound async_run_entry_fn Call Trace: dump_stack_lvl+0x47/0x60 warn_alloc+0x13a/0x1b0 ? srso_alias_return_thunk+0x5/0xfbef5 ? __alloc_pages_direct_compact+0xab/0x210 __alloc_pages_slowpath.constprop.0+0xd3e/0xda0 __alloc_pages+0x32d/0x350 ? mhi_prepare_channel+0x127/0x2d0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814] __kmalloc_large_node+0x72/0x110 __kmalloc+0x37c/0x480 ? mhi_map_single_no_bb+0x77/0xf0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814] ? mhi_prepare_channel+0x127/0x2d0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814] mhi_prepare_channel+0x127/0x2d0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814] __mhi_prepare_for_transfer+0x44/0x80 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814] ? __pfx_____mhi_prepare_for_transfer+0x10/0x10 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814] device_for_each_child+0x5c/0xa0 ? __pfx_pci_pm_resume+0x10/0x10 ath11k_core_resume+0x65/0x100 [ath11k a5094e22d7223135c40d93c8f5321cf09fd85e4e] ? srso_alias_return_thunk+0x5/0xfbef5 ath11k_pci_pm_resume+0x32/0x60 [ath11k_pci 830b7bfc3ea80ebef32e563cafe2cb55e9cc73ec] ? srso_alias_return_thunk+0x5/0xfbef5 dpm_run_callback+0x8c/0x1e0 device_resume+0x104/0x340 ? __pfx_dpm_watchdog_handler+0x10/0x10 async_resume+0x1d/0x30 async_run_entry_fn+0x32/0x120 process_one_work+0x168/0x330 worker_thread+0x2f5/0x410 ? __pfx_worker_thread+0x10/0x10 kthread+0xe8/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x34/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 Actually those buffers are used only by QMI target -> host communication. And for WCN6855 and QCA6390, the largest packet size for that is less than 6KB. So change buf_len field to 8KB, which results in order 1 allocation if page size is 4KB. In this way, we can at least save some memory, and as well as decrease the possibility of allocation failure in those scenarios. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Reported-by: Vlastimil Babka Closes: https://lore.kernel.org/ath11k/96481a45-3547-4d23-ad34-3a8f1d90c1cd@suse.cz/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240223053111.29170-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mhi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 3de7fa6f88d0..522175aac5e7 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -78,7 +78,7 @@ static struct mhi_controller_config ath11k_mhi_config_qca6390 = { .max_channels = 128, .timeout_ms = 2000, .use_bounce_buf = false, - .buf_len = 0, + .buf_len = 8192, .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qca6390), .ch_cfg = ath11k_mhi_channels_qca6390, .num_events = ARRAY_SIZE(ath11k_mhi_events_qca6390), From ee3b63586b30cf9a488712a4a67f18117f064428 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 23 Feb 2024 13:45:05 +0800 Subject: [PATCH 1606/2255] wifi: ath12k: add rcu lock for ath12k_wmi_p2p_noa_event() Warning will appear when running P2P GO: WARNING: suspicious RCU usage drivers/net/wireless/ath/ath12k/mac.c:583 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 no locks held by swapper/0/0. stack backtrace: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 6.8.0-rc4-wt-ath+ #4 Call Trace: dump_stack_lvl+0x82/0xa0 dump_stack+0x14/0x20 lockdep_rcu_suspicious+0x214/0x3b0 ath12k_mac_get_ar_by_vdev_id+0x192/0x220 [ath12k] ath12k_wmi_op_rx+0x2d7/0x1b40 [ath12k] ath12k_mac_get_ar_by_vdev_id() requires its callers to have called rcu_read_lock(), but in ath12k_wmi_p2p_noa_event() it is called without doing so, and hence the warning was triggered. Add rcu_read_lock() and rcu_read_unlock() to avoid warning. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 9411eecb60cb ("wifi: ath12k: implement handling of P2P NoA event") Reported-by: Kalle Valo Closes: https://lore.kernel.org/linux-wireless/87o7cusyvw.fsf@kernel.org/ Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240223054505.438839-1-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 838161dd9098..9d69a1769926 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6736,18 +6736,21 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, "wmi tlv p2p noa vdev_id %i descriptors %u\n", vdev_id, le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)); + rcu_read_lock(); ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); if (!ar) { ath12k_warn(ab, "invalid vdev id %d in P2P NoA event\n", vdev_id); ret = -EINVAL; - goto out; + goto unlock; } ath12k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa); ret = 0; +unlock: + rcu_read_unlock(); out: kfree(tb); return ret; From 766cf07c402342280a468e16f94a0d3fc7e98942 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 23 Feb 2024 07:39:31 -0800 Subject: [PATCH 1607/2255] wifi: ath11k: constify MHI channel and controller configs Unlike the event configuration which can be modified by MHI, the channel and controller configurations are expected to be const. And since they are not modified locally, constify them to prevent runtime modification. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240223-mhi-const-wifi-ath11k-v1-1-51b9d42d2639@quicinc.com --- drivers/net/wireless/ath/ath11k/mhi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 522175aac5e7..fb4ecf9a103e 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -20,7 +20,7 @@ #define MHI_TIMEOUT_DEFAULT_MS 20000 #define RDDM_DUMP_SIZE 0x420000 -static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { +static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { { .num = 20, .name = "IPCR", @@ -74,7 +74,7 @@ static struct mhi_event_config ath11k_mhi_events_qca6390[] = { }, }; -static struct mhi_controller_config ath11k_mhi_config_qca6390 = { +static const struct mhi_controller_config ath11k_mhi_config_qca6390 = { .max_channels = 128, .timeout_ms = 2000, .use_bounce_buf = false, @@ -85,7 +85,7 @@ static struct mhi_controller_config ath11k_mhi_config_qca6390 = { .event_cfg = ath11k_mhi_events_qca6390, }; -static struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = { +static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = { { .num = 20, .name = "IPCR", @@ -139,7 +139,7 @@ static struct mhi_event_config ath11k_mhi_events_qcn9074[] = { }, }; -static struct mhi_controller_config ath11k_mhi_config_qcn9074 = { +static const struct mhi_controller_config ath11k_mhi_config_qcn9074 = { .max_channels = 30, .timeout_ms = 10000, .use_bounce_buf = false, @@ -328,7 +328,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) { struct ath11k_base *ab = ab_pci->ab; struct mhi_controller *mhi_ctrl; - struct mhi_controller_config *ath11k_mhi_config; + const struct mhi_controller_config *ath11k_mhi_config; int ret; mhi_ctrl = mhi_alloc_controller(); From 776c9c93bb0511d04e6222546499e5ea20ad51b0 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 26 Feb 2024 20:07:45 +0200 Subject: [PATCH 1608/2255] wifi: ath12k: fix license in p2p.c and p2p.h ath12k uses BSD-3-Clause-Clear, not ISC. Signed-off-by: Kalle Valo Link: https://msgid.link/20240226180745.3195805-1-kvalo@kernel.org --- drivers/net/wireless/ath/ath12k/p2p.c | 2 +- drivers/net/wireless/ath/ath12k/p2p.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c index 61e919b23b16..d334df720032 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.c +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h index b6f177fe4ff4..5768139a7844 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.h +++ b/drivers/net/wireless/ath/ath12k/p2p.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.. */ From 451c3cab9a65e656c3b3d106831fc02d56b8c34a Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Wed, 28 Feb 2024 14:18:23 +0000 Subject: [PATCH 1609/2255] arm64: patching: implement text_poke API The text_poke API is used to implement functions like memcpy() and memset() for instruction memory (RO+X). The implementation is similar to the x86 version. This will be used by the BPF JIT to write and modify BPF programs. There could be more users of this in the future. Signed-off-by: Puranjay Mohan Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20240228141824.119877-2-puranjay12@gmail.com Signed-off-by: Alexei Starovoitov --- arch/arm64/include/asm/patching.h | 2 + arch/arm64/kernel/patching.c | 75 +++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/arch/arm64/include/asm/patching.h b/arch/arm64/include/asm/patching.h index 68908b82b168..587bdb91ab7a 100644 --- a/arch/arm64/include/asm/patching.h +++ b/arch/arm64/include/asm/patching.h @@ -8,6 +8,8 @@ int aarch64_insn_read(void *addr, u32 *insnp); int aarch64_insn_write(void *addr, u32 insn); int aarch64_insn_write_literal_u64(void *addr, u64 val); +void *aarch64_insn_set(void *dst, u32 insn, size_t len); +void *aarch64_insn_copy(void *dst, void *src, size_t len); int aarch64_insn_patch_text_nosync(void *addr, u32 insn); int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); diff --git a/arch/arm64/kernel/patching.c b/arch/arm64/kernel/patching.c index b4835f6d594b..255534930368 100644 --- a/arch/arm64/kernel/patching.c +++ b/arch/arm64/kernel/patching.c @@ -105,6 +105,81 @@ noinstr int aarch64_insn_write_literal_u64(void *addr, u64 val) return ret; } +typedef void text_poke_f(void *dst, void *src, size_t patched, size_t len); + +static void *__text_poke(text_poke_f func, void *addr, void *src, size_t len) +{ + unsigned long flags; + size_t patched = 0; + size_t size; + void *waddr; + void *ptr; + + raw_spin_lock_irqsave(&patch_lock, flags); + + while (patched < len) { + ptr = addr + patched; + size = min_t(size_t, PAGE_SIZE - offset_in_page(ptr), + len - patched); + + waddr = patch_map(ptr, FIX_TEXT_POKE0); + func(waddr, src, patched, size); + patch_unmap(FIX_TEXT_POKE0); + + patched += size; + } + raw_spin_unlock_irqrestore(&patch_lock, flags); + + flush_icache_range((uintptr_t)addr, (uintptr_t)addr + len); + + return addr; +} + +static void text_poke_memcpy(void *dst, void *src, size_t patched, size_t len) +{ + copy_to_kernel_nofault(dst, src + patched, len); +} + +static void text_poke_memset(void *dst, void *src, size_t patched, size_t len) +{ + u32 c = *(u32 *)src; + + memset32(dst, c, len / 4); +} + +/** + * aarch64_insn_copy - Copy instructions into (an unused part of) RX memory + * @dst: address to modify + * @src: source of the copy + * @len: length to copy + * + * Useful for JITs to dump new code blocks into unused regions of RX memory. + */ +noinstr void *aarch64_insn_copy(void *dst, void *src, size_t len) +{ + /* A64 instructions must be word aligned */ + if ((uintptr_t)dst & 0x3) + return NULL; + + return __text_poke(text_poke_memcpy, dst, src, len); +} + +/** + * aarch64_insn_set - memset for RX memory regions. + * @dst: address to modify + * @insn: value to set + * @len: length of memory region. + * + * Useful for JITs to fill regions of RX memory with illegal instructions. + */ +noinstr void *aarch64_insn_set(void *dst, u32 insn, size_t len) +{ + if ((uintptr_t)dst & 0x3) + return NULL; + + return __text_poke(text_poke_memset, dst, &insn, len); +} + int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn) { u32 *tp = addr; From 1dad391daef129e01e28206b8d586608ff026548 Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Wed, 28 Feb 2024 14:18:24 +0000 Subject: [PATCH 1610/2255] bpf, arm64: use bpf_prog_pack for memory management Use bpf_jit_binary_pack_alloc for memory management of JIT binaries in ARM64 BPF JIT. The bpf_jit_binary_pack_alloc creates a pair of RW and RX buffers. The JIT writes the program into the RW buffer. When the JIT is done, the program is copied to the final RX buffer with bpf_jit_binary_pack_finalize. Implement bpf_arch_text_copy() and bpf_arch_text_invalidate() for ARM64 JIT as these functions are required by bpf_jit_binary_pack allocator. Signed-off-by: Puranjay Mohan Acked-by: Song Liu Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20240228141824.119877-3-puranjay12@gmail.com Signed-off-by: Alexei Starovoitov --- arch/arm64/net/bpf_jit_comp.c | 139 ++++++++++++++++++++++++++++------ 1 file changed, 115 insertions(+), 24 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 20720ec346b8..5afc7a525eca 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -76,6 +76,7 @@ struct jit_ctx { int *offset; int exentry_idx; __le32 *image; + __le32 *ro_image; u32 stack_size; int fpb_offset; }; @@ -205,6 +206,14 @@ static void jit_fill_hole(void *area, unsigned int size) *ptr++ = cpu_to_le32(AARCH64_BREAK_FAULT); } +int bpf_arch_text_invalidate(void *dst, size_t len) +{ + if (!aarch64_insn_set(dst, AARCH64_BREAK_FAULT, len)) + return -EINVAL; + + return 0; +} + static inline int epilogue_offset(const struct jit_ctx *ctx) { int to = ctx->epilogue_offset; @@ -746,7 +755,8 @@ static int add_exception_handler(const struct bpf_insn *insn, struct jit_ctx *ctx, int dst_reg) { - off_t offset; + off_t ins_offset; + off_t fixup_offset; unsigned long pc; struct exception_table_entry *ex; @@ -763,12 +773,17 @@ static int add_exception_handler(const struct bpf_insn *insn, return -EINVAL; ex = &ctx->prog->aux->extable[ctx->exentry_idx]; - pc = (unsigned long)&ctx->image[ctx->idx - 1]; + pc = (unsigned long)&ctx->ro_image[ctx->idx - 1]; - offset = pc - (long)&ex->insn; - if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN)) + /* + * This is the relative offset of the instruction that may fault from + * the exception table itself. This will be written to the exception + * table and if this instruction faults, the destination register will + * be set to '0' and the execution will jump to the next instruction. + */ + ins_offset = pc - (long)&ex->insn; + if (WARN_ON_ONCE(ins_offset >= 0 || ins_offset < INT_MIN)) return -ERANGE; - ex->insn = offset; /* * Since the extable follows the program, the fixup offset is always @@ -777,12 +792,25 @@ static int add_exception_handler(const struct bpf_insn *insn, * bits. We don't need to worry about buildtime or runtime sort * modifying the upper bits because the table is already sorted, and * isn't part of the main exception table. + * + * The fixup_offset is set to the next instruction from the instruction + * that may fault. The execution will jump to this after handling the + * fault. */ - offset = (long)&ex->fixup - (pc + AARCH64_INSN_SIZE); - if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, offset)) + fixup_offset = (long)&ex->fixup - (pc + AARCH64_INSN_SIZE); + if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, fixup_offset)) return -ERANGE; - ex->fixup = FIELD_PREP(BPF_FIXUP_OFFSET_MASK, offset) | + /* + * The offsets above have been calculated using the RO buffer but we + * need to use the R/W buffer for writes. + * switch ex to rw buffer for writing. + */ + ex = (void *)ctx->image + ((void *)ex - (void *)ctx->ro_image); + + ex->insn = ins_offset; + + ex->fixup = FIELD_PREP(BPF_FIXUP_OFFSET_MASK, fixup_offset) | FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg); ex->type = EX_TYPE_BPF; @@ -1550,7 +1578,8 @@ static inline void bpf_flush_icache(void *start, void *end) struct arm64_jit_data { struct bpf_binary_header *header; - u8 *image; + u8 *ro_image; + struct bpf_binary_header *ro_header; struct jit_ctx ctx; }; @@ -1559,12 +1588,14 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) int image_size, prog_size, extable_size, extable_align, extable_offset; struct bpf_prog *tmp, *orig_prog = prog; struct bpf_binary_header *header; + struct bpf_binary_header *ro_header; struct arm64_jit_data *jit_data; bool was_classic = bpf_prog_was_classic(prog); bool tmp_blinded = false; bool extra_pass = false; struct jit_ctx ctx; u8 *image_ptr; + u8 *ro_image_ptr; if (!prog->jit_requested) return orig_prog; @@ -1591,8 +1622,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) } if (jit_data->ctx.offset) { ctx = jit_data->ctx; - image_ptr = jit_data->image; + ro_image_ptr = jit_data->ro_image; + ro_header = jit_data->ro_header; header = jit_data->header; + image_ptr = (void *)header + ((void *)ro_image_ptr + - (void *)ro_header); extra_pass = true; prog_size = sizeof(u32) * ctx.idx; goto skip_init_ctx; @@ -1637,18 +1671,27 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) /* also allocate space for plt target */ extable_offset = round_up(prog_size + PLT_TARGET_SIZE, extable_align); image_size = extable_offset + extable_size; - header = bpf_jit_binary_alloc(image_size, &image_ptr, - sizeof(u32), jit_fill_hole); - if (header == NULL) { + ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, + sizeof(u32), &header, &image_ptr, + jit_fill_hole); + if (!ro_header) { prog = orig_prog; goto out_off; } /* 2. Now, the actual pass. */ + /* + * Use the image(RW) for writing the JITed instructions. But also save + * the ro_image(RX) for calculating the offsets in the image. The RW + * image will be later copied to the RX image from where the program + * will run. The bpf_jit_binary_pack_finalize() will do this copy in the + * final step. + */ ctx.image = (__le32 *)image_ptr; + ctx.ro_image = (__le32 *)ro_image_ptr; if (extable_size) - prog->aux->extable = (void *)image_ptr + extable_offset; + prog->aux->extable = (void *)ro_image_ptr + extable_offset; skip_init_ctx: ctx.idx = 0; ctx.exentry_idx = 0; @@ -1656,9 +1699,8 @@ skip_init_ctx: build_prologue(&ctx, was_classic, prog->aux->exception_cb); if (build_body(&ctx, extra_pass)) { - bpf_jit_binary_free(header); prog = orig_prog; - goto out_off; + goto out_free_hdr; } build_epilogue(&ctx, prog->aux->exception_cb); @@ -1666,34 +1708,44 @@ skip_init_ctx: /* 3. Extra pass to validate JITed code. */ if (validate_ctx(&ctx)) { - bpf_jit_binary_free(header); prog = orig_prog; - goto out_off; + goto out_free_hdr; } /* And we're done. */ if (bpf_jit_enable > 1) bpf_jit_dump(prog->len, prog_size, 2, ctx.image); - bpf_flush_icache(header, ctx.image + ctx.idx); - if (!prog->is_func || extra_pass) { if (extra_pass && ctx.idx != jit_data->ctx.idx) { pr_err_once("multi-func JIT bug %d != %d\n", ctx.idx, jit_data->ctx.idx); - bpf_jit_binary_free(header); prog->bpf_func = NULL; prog->jited = 0; prog->jited_len = 0; + goto out_free_hdr; + } + if (WARN_ON(bpf_jit_binary_pack_finalize(prog, ro_header, + header))) { + /* ro_header has been freed */ + ro_header = NULL; + prog = orig_prog; goto out_off; } - bpf_jit_binary_lock_ro(header); + /* + * The instructions have now been copied to the ROX region from + * where they will execute. Now the data cache has to be cleaned to + * the PoU and the I-cache has to be invalidated for the VAs. + */ + bpf_flush_icache(ro_header, ctx.ro_image + ctx.idx); } else { jit_data->ctx = ctx; - jit_data->image = image_ptr; + jit_data->ro_image = ro_image_ptr; jit_data->header = header; + jit_data->ro_header = ro_header; } - prog->bpf_func = (void *)ctx.image; + + prog->bpf_func = (void *)ctx.ro_image; prog->jited = 1; prog->jited_len = prog_size; @@ -1714,6 +1766,14 @@ out: bpf_jit_prog_release_other(prog, prog == orig_prog ? tmp : orig_prog); return prog; + +out_free_hdr: + if (header) { + bpf_arch_text_copy(&ro_header->size, &header->size, + sizeof(header->size)); + bpf_jit_binary_pack_free(ro_header, header); + } + goto out_off; } bool bpf_jit_supports_kfunc_call(void) @@ -1721,6 +1781,13 @@ bool bpf_jit_supports_kfunc_call(void) return true; } +void *bpf_arch_text_copy(void *dst, void *src, size_t len) +{ + if (!aarch64_insn_copy(dst, src, len)) + return ERR_PTR(-EINVAL); + return dst; +} + u64 bpf_jit_alloc_exec_limit(void) { return VMALLOC_END - VMALLOC_START; @@ -2359,3 +2426,27 @@ bool bpf_jit_supports_exceptions(void) */ return true; } + +void bpf_jit_free(struct bpf_prog *prog) +{ + if (prog->jited) { + struct arm64_jit_data *jit_data = prog->aux->jit_data; + struct bpf_binary_header *hdr; + + /* + * If we fail the final pass of JIT (from jit_subprogs), + * the program may not be finalized yet. Call finalize here + * before freeing it. + */ + if (jit_data) { + bpf_arch_text_copy(&jit_data->ro_header->size, &jit_data->header->size, + sizeof(jit_data->header->size)); + kfree(jit_data); + } + hdr = bpf_jit_binary_pack_hdr(prog); + bpf_jit_binary_pack_free(hdr, NULL); + WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(prog)); + } + + bpf_prog_unlock_free(prog); +} From 3bfe90527d6387e19078c9f774d6328448bac201 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 26 Feb 2024 14:58:06 -0800 Subject: [PATCH 1611/2255] tools: ynl: protect from old OvS headers Since commit 7c59c9c8f202 ("tools: ynl: generate code for ovs families") we need relatively recent OvS headers to get YNL to compile. Add the direct include workaround to fix compilation on less up-to-date OSes like CentOS 9. Reviewed-by: Donald Hunter Link: https://lore.kernel.org/r/20240226225806.1301152-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/Makefile.deps | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps index 7dcec16da509..07373c5a7afe 100644 --- a/tools/net/ynl/Makefile.deps +++ b/tools/net/ynl/Makefile.deps @@ -21,3 +21,6 @@ CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h) CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H,mptcp_pm.h) CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h) CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_NETLINK_H,nfsd_netlink.h) +CFLAGS_ovs_datapath:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) +CFLAGS_ovs_flow:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) +CFLAGS_ovs_vport:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) From 21f6986d19b01ecda3d8ae2e79780aa3603d4eeb Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:18 -0800 Subject: [PATCH 1612/2255] tools: ynl: give up on libmnl for auto-ints The temporary auto-int helpers are not really correct. We can't treat signed and unsigned ints the same when determining whether we need full 8B. I realized this before sending the patch to add support in libmnl. Unfortunately, that patch has not been merged, so time to fix our local helpers. Use the mnl* name for now, subsequent patches will address that. Acked-by: Nicolas Dichtel Reviewed-by: Donald Hunter Link: https://lore.kernel.org/r/20240227223032.1835527-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 45 ++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 7491da8e7555..eaa0d432366c 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -125,20 +125,47 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); -#ifndef MNL_HAS_AUTO_SCALARS -static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) +/* Attribute helpers */ + +static inline __u64 mnl_attr_get_uint(const struct nlattr *attr) { - if (mnl_attr_get_payload_len(attr) == 4) + switch (mnl_attr_get_payload_len(attr)) { + case 4: return mnl_attr_get_u32(attr); - return mnl_attr_get_u64(attr); + case 8: + return mnl_attr_get_u64(attr); + default: + return 0; + } +} + +static inline __s64 mnl_attr_get_sint(const struct nlattr *attr) +{ + switch (mnl_attr_get_payload_len(attr)) { + case 4: + return mnl_attr_get_u32(attr); + case 8: + return mnl_attr_get_u64(attr); + default: + return 0; + } } static inline void -mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) +mnl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data) { - if ((uint32_t)data == (uint64_t)data) - return mnl_attr_put_u32(nlh, type, data); - return mnl_attr_put_u64(nlh, type, data); + if ((__u32)data == (__u64)data) + mnl_attr_put_u32(nlh, type, data); + else + mnl_attr_put_u64(nlh, type, data); +} + +static inline void +mnl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) +{ + if ((__s32)data == (__s64)data) + mnl_attr_put_u32(nlh, type, data); + else + mnl_attr_put_u64(nlh, type, data); } #endif -#endif From 5600c580383acb655f0fd8d4963cbea52f056938 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:19 -0800 Subject: [PATCH 1613/2255] tools: ynl: create local attribute helpers Don't use mnl attr helpers, we're trying to remove the libmnl dependency. Create both signed and unsigned helpers, libmnl had unsigned helpers, so code generator no longer needs the mnl_type() hack. The new helpers are written from first principles, but are hopefully not too buggy. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 196 ++++++++++++++++++++++++++++++++--- tools/net/ynl/lib/ynl.c | 44 ++++---- tools/net/ynl/ynl-gen-c.py | 61 ++++------- 3 files changed, 227 insertions(+), 74 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index eaa0d432366c..d42d44a77dcb 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -127,45 +127,213 @@ int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); /* Attribute helpers */ -static inline __u64 mnl_attr_get_uint(const struct nlattr *attr) +static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh) { - switch (mnl_attr_get_payload_len(attr)) { + return (char *)nlh + nlh->nlmsg_len; +} + +static inline unsigned int ynl_attr_type(const struct nlattr *attr) +{ + return attr->nla_type & NLA_TYPE_MASK; +} + +static inline unsigned int ynl_attr_data_len(const struct nlattr *attr) +{ + return attr->nla_len - NLA_HDRLEN; +} + +static inline void *ynl_attr_data(const struct nlattr *attr) +{ + return (unsigned char *)attr + NLA_HDRLEN; +} + +static inline struct nlattr * +ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type) +{ + struct nlattr *attr; + + attr = ynl_nlmsg_end_addr(nlh); + attr->nla_type = attr_type | NLA_F_NESTED; + nlh->nlmsg_len += NLA_HDRLEN; + + return attr; +} + +static inline void +ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr) +{ + attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr; +} + +static inline void +ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type, + const void *value, size_t size) +{ + struct nlattr *attr; + + attr = ynl_nlmsg_end_addr(nlh); + attr->nla_type = attr_type; + attr->nla_len = NLA_HDRLEN + size; + + memcpy(ynl_attr_data(attr), value, size); + + nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); +} + +static inline void +ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str) +{ + struct nlattr *attr; + const char *end; + + attr = ynl_nlmsg_end_addr(nlh); + attr->nla_type = attr_type; + + end = stpcpy(ynl_attr_data(attr), str); + attr->nla_len = + NLA_HDRLEN + NLA_ALIGN(end - (char *)ynl_attr_data(attr)); + + nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); +} + +static inline const char *ynl_attr_get_str(const struct nlattr *attr) +{ + return (const char *)ynl_attr_data(attr); +} + +static inline __s8 ynl_attr_get_s8(const struct nlattr *attr) +{ + return *(__s8 *)ynl_attr_data(attr); +} + +static inline __s16 ynl_attr_get_s16(const struct nlattr *attr) +{ + return *(__s16 *)ynl_attr_data(attr); +} + +static inline __s32 ynl_attr_get_s32(const struct nlattr *attr) +{ + return *(__s32 *)ynl_attr_data(attr); +} + +static inline __s64 ynl_attr_get_s64(const struct nlattr *attr) +{ + __s64 tmp; + + memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); + return tmp; +} + +static inline __u8 ynl_attr_get_u8(const struct nlattr *attr) +{ + return *(__u8 *)ynl_attr_data(attr); +} + +static inline __u16 ynl_attr_get_u16(const struct nlattr *attr) +{ + return *(__u16 *)ynl_attr_data(attr); +} + +static inline __u32 ynl_attr_get_u32(const struct nlattr *attr) +{ + return *(__u32 *)ynl_attr_data(attr); +} + +static inline __u64 ynl_attr_get_u64(const struct nlattr *attr) +{ + __u64 tmp; + + memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); + return tmp; +} + +static inline void +ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline __u64 ynl_attr_get_uint(const struct nlattr *attr) +{ + switch (ynl_attr_data_len(attr)) { case 4: - return mnl_attr_get_u32(attr); + return ynl_attr_get_u32(attr); case 8: - return mnl_attr_get_u64(attr); + return ynl_attr_get_u64(attr); default: return 0; } } -static inline __s64 mnl_attr_get_sint(const struct nlattr *attr) +static inline __s64 ynl_attr_get_sint(const struct nlattr *attr) { - switch (mnl_attr_get_payload_len(attr)) { + switch (ynl_attr_data_len(attr)) { case 4: - return mnl_attr_get_u32(attr); + return ynl_attr_get_s32(attr); case 8: - return mnl_attr_get_u64(attr); + return ynl_attr_get_s64(attr); default: return 0; } } static inline void -mnl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data) +ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data) { if ((__u32)data == (__u64)data) - mnl_attr_put_u32(nlh, type, data); + ynl_attr_put_u32(nlh, type, data); else - mnl_attr_put_u64(nlh, type, data); + ynl_attr_put_u64(nlh, type, data); } static inline void -mnl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) +ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) { if ((__s32)data == (__s64)data) - mnl_attr_put_u32(nlh, type, data); + ynl_attr_put_s32(nlh, type, data); else - mnl_attr_put_u64(nlh, type, data); + ynl_attr_put_s64(nlh, type, data); } #endif diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 6e6d474c8366..b9ed587af676 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -94,7 +94,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, mnl_attr_for_each_payload(start, data_len) { astart_off = (char *)attr - (char *)start; - aend_off = astart_off + mnl_attr_get_payload_len(attr); + aend_off = astart_off + ynl_attr_data_len(attr); if (aend_off <= off) continue; @@ -106,7 +106,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, off -= astart_off; - type = mnl_attr_get_type(attr); + type = ynl_attr_type(attr); if (ynl_err_walk_report_one(policy, type, str, str_sz, &n)) return n; @@ -124,8 +124,8 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, } off -= sizeof(struct nlattr); - start = mnl_attr_get_payload(attr); - end = start + mnl_attr_get_payload_len(attr); + start = ynl_attr_data(attr); + end = start + ynl_attr_data_len(attr); return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest, &str[n], str_sz - n, nest_pol); @@ -153,8 +153,8 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, mnl_attr_for_each(attr, nlh, hlen) { unsigned int len, type; - len = mnl_attr_get_payload_len(attr); - type = mnl_attr_get_type(attr); + len = ynl_attr_data_len(attr); + type = ynl_attr_type(attr); if (type > NLMSGERR_ATTR_MAX) continue; @@ -169,7 +169,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, return MNL_CB_ERROR; break; case NLMSGERR_ATTR_MSG: - str = mnl_attr_get_payload(attr); + str = ynl_attr_get_str(attr); if (str[len - 1]) return MNL_CB_ERROR; break; @@ -185,7 +185,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, unsigned int n, off; void *start, *end; - ys->err.attr_offs = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]); + ys->err.attr_offs = ynl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]); n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ", str ? " (" : ""); @@ -211,7 +211,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, void *start, *end; int n2; - type = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]); + type = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]); n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ", bad_attr[0] ? ", " : (str ? " (" : "")); @@ -222,7 +222,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, nest_pol = ys->req_policy; if (tb[NLMSGERR_ATTR_MISS_NEST]) { - off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]); + off = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]); off -= sizeof(struct nlmsghdr); off -= ys->family->hdr_len; @@ -314,9 +314,9 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) unsigned int type, len; unsigned char *data; - data = mnl_attr_get_payload(attr); - len = mnl_attr_get_payload_len(attr); - type = mnl_attr_get_type(attr); + data = ynl_attr_data(attr); + len = ynl_attr_data_len(attr); + type = ynl_attr_type(attr); if (type > yarg->rsp_policy->max_attr) { yerr(yarg->ys, YNL_ERROR_INTERNAL, "Internal error, validating unknown attribute"); @@ -514,11 +514,11 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) i = 0; mnl_attr_for_each_nested(entry, mcasts) { mnl_attr_for_each_nested(attr, entry) { - if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_ID) - ys->mcast_groups[i].id = mnl_attr_get_u32(attr); - if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) { + if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_ID) + ys->mcast_groups[i].id = ynl_attr_get_u32(attr); + if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) { strncpy(ys->mcast_groups[i].name, - mnl_attr_get_str(attr), + ynl_attr_get_str(attr), GENL_NAMSIZ - 1); ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0; } @@ -536,19 +536,19 @@ static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data) bool found_id = true; mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GROUPS) + if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GROUPS) if (ynl_get_family_info_mcast(ys, attr)) return MNL_CB_ERROR; - if (mnl_attr_get_type(attr) != CTRL_ATTR_FAMILY_ID) + if (ynl_attr_type(attr) != CTRL_ATTR_FAMILY_ID) continue; - if (mnl_attr_get_payload_len(attr) != sizeof(__u16)) { + if (ynl_attr_data_len(attr) != sizeof(__u16)) { yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID"); return MNL_CB_ERROR; } - ys->family_id = mnl_attr_get_u16(attr); + ys->family_id = ynl_attr_get_u16(attr); found_id = true; } @@ -566,7 +566,7 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) int err; nlh = ynl_gemsg_start_req(ys, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1); - mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name); + ynl_attr_put_str(nlh, CTRL_ATTR_FAMILY_NAME, family_name); err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len); if (err < 0) { diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 7fc1aa788f6f..99a3eb7b158b 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -168,15 +168,6 @@ class Type(SpecAttr): spec = self._attr_policy(policy) cw.p(f"\t[{self.enum_name}] = {spec},") - def _mnl_type(self): - # mnl does not have helpers for signed integer types - # turn signed type into unsigned - # this only makes sense for scalar types - t = self.type - if t[0] == 's': - t = 'u' + t[1:] - return t - def _attr_typol(self): raise Exception(f"Type policy not implemented for class type {self.type}") @@ -192,7 +183,7 @@ class Type(SpecAttr): ri.cw.p(f"{line};") def _attr_put_simple(self, ri, var, put_type): - line = f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})" + line = f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})" self._attr_put_line(ri, var, line) def attr_put(self, ri, var): @@ -357,9 +348,6 @@ class TypeScalar(Type): else: self.type_name = '__' + self.type - def mnl_type(self): - return self._mnl_type() - def _attr_policy(self, policy): if 'flags-mask' in self.checks or self.is_bitfield: if self.is_bitfield: @@ -387,10 +375,10 @@ class TypeScalar(Type): return [f'{self.type_name} {self.c_name}{self.byte_order_comment}'] def attr_put(self, ri, var): - self._attr_put_simple(ri, var, self.mnl_type()) + self._attr_put_simple(ri, var, self.type) def _attr_get(self, ri, var): - return f"{var}->{self.c_name} = mnl_attr_get_{self.mnl_type()}(attr);", None, None + return f"{var}->{self.c_name} = ynl_attr_get_{self.type}(attr);", None, None def _setter_lines(self, ri, member, presence): return [f"{member} = {self.c_name};"] @@ -404,7 +392,7 @@ class TypeFlag(Type): return '.type = YNL_PT_FLAG, ' def attr_put(self, ri, var): - self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, 0, NULL)") + self._attr_put_line(ri, var, f"ynl_attr_put(nlh, {self.enum_name}, NULL, 0)") def _attr_get(self, ri, var): return [], None, None @@ -446,15 +434,15 @@ class TypeString(Type): cw.p(f"\t[{self.enum_name}] = {spec},") def attr_put(self, ri, var): - self._attr_put_simple(ri, var, 'strz') + self._attr_put_simple(ri, var, 'str') def _attr_get(self, ri, var): len_mem = var + '->_present.' + self.c_name + '_len' return [f"{len_mem} = len;", f"{var}->{self.c_name} = malloc(len + 1);", - f"memcpy({var}->{self.c_name}, mnl_attr_get_str(attr), len);", + f"memcpy({var}->{self.c_name}, ynl_attr_get_str(attr), len);", f"{var}->{self.c_name}[len] = 0;"], \ - ['len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));'], \ + ['len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr));'], \ ['unsigned int len;'] def _setter_lines(self, ri, member, presence): @@ -493,15 +481,15 @@ class TypeBinary(Type): return mem def attr_put(self, ri, var): - self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, " + - f"{var}->_present.{self.c_name}_len, {var}->{self.c_name})") + self._attr_put_line(ri, var, f"ynl_attr_put(nlh, {self.enum_name}, " + + f"{var}->{self.c_name}, {var}->_present.{self.c_name}_len)") def _attr_get(self, ri, var): len_mem = var + '->_present.' + self.c_name + '_len' return [f"{len_mem} = len;", f"{var}->{self.c_name} = malloc(len);", - f"memcpy({var}->{self.c_name}, mnl_attr_get_payload(attr), len);"], \ - ['len = mnl_attr_get_payload_len(attr);'], \ + f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \ + ['len = ynl_attr_data_len(attr);'], \ ['unsigned int len;'] def _setter_lines(self, ri, member, presence): @@ -526,11 +514,11 @@ class TypeBitfield32(Type): return f"NLA_POLICY_BITFIELD32({mask})" def attr_put(self, ri, var): - line = f"mnl_attr_put(nlh, {self.enum_name}, sizeof(struct nla_bitfield32), &{var}->{self.c_name})" + line = f"ynl_attr_put(nlh, {self.enum_name}, &{var}->{self.c_name}, sizeof(struct nla_bitfield32))" self._attr_put_line(ri, var, line) def _attr_get(self, ri, var): - return f"memcpy(&{var}->{self.c_name}, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32));", None, None + return f"memcpy(&{var}->{self.c_name}, ynl_attr_data(attr), sizeof(struct nla_bitfield32));", None, None def _setter_lines(self, ri, member, presence): return [f"memcpy(&{member}, {self.c_name}, sizeof(struct nla_bitfield32));"] @@ -589,9 +577,6 @@ class TypeMultiAttr(Type): def presence_type(self): return 'count' - def mnl_type(self): - return self._mnl_type() - def _complex_member_type(self, ri): if 'type' not in self.attr or self.attr['type'] == 'nest': return self.nested_struct_type @@ -625,9 +610,9 @@ class TypeMultiAttr(Type): def attr_put(self, ri, var): if self.attr['type'] in scalars: - put_type = self.mnl_type() + put_type = self.type ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") - ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);") + ri.cw.p(f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);") elif 'type' not in self.attr or self.attr['type'] == 'nest': ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " + @@ -690,8 +675,8 @@ class TypeNestTypeValue(Type): local_vars += [f'__u32 {", ".join(tv_names)};'] for level in self.attr["type-value"]: level = c_lower(level) - get_lines += [f'attr_{level} = mnl_attr_get_payload({prev});'] - get_lines += [f'{level} = mnl_attr_get_type(attr_{level});'] + get_lines += [f'attr_{level} = ynl_attr_data({prev});'] + get_lines += [f'{level} = ynl_attr_type(attr_{level});'] prev = 'attr_' + level tv_args = f", {', '.join(tv_names)}" @@ -1612,12 +1597,12 @@ def put_req_nested(ri, struct): ri.cw.block_start() ri.cw.write_func_lvar('struct nlattr *nest;') - ri.cw.p("nest = mnl_attr_nest_start(nlh, attr_type);") + ri.cw.p("nest = ynl_attr_nest_start(nlh, attr_type);") for _, arg in struct.member_list(): arg.attr_put(ri, "obj") - ri.cw.p("mnl_attr_nest_end(nlh, nest);") + ri.cw.p("ynl_attr_nest_end(nlh, nest);") ri.cw.nl() ri.cw.p('return 0;') @@ -1674,7 +1659,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.nl() ri.cw.block_start(line=iter_line) - ri.cw.p('unsigned int type = mnl_attr_get_type(attr);') + ri.cw.p('unsigned int type = ynl_attr_type(attr);') ri.cw.nl() first = True @@ -1696,7 +1681,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})") ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") - ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, mnl_attr_get_type(attr)))") + ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, ynl_attr_type(attr)))") ri.cw.p('return MNL_CB_ERROR;') ri.cw.p('i++;') ri.cw.block_end() @@ -1712,13 +1697,13 @@ def _multi_parse(ri, struct, init_lines, local_vars): if 'nested-attributes' in aspec: ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") ri.cw.block_start(line=iter_line) - ri.cw.block_start(line=f"if (mnl_attr_get_type(attr) == {aspec.enum_name})") + ri.cw.block_start(line=f"if (ynl_attr_type(attr) == {aspec.enum_name})") if 'nested-attributes' in aspec: ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr))") ri.cw.p('return MNL_CB_ERROR;') elif aspec.type in scalars: - ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{aspec.mnl_type()}(attr);") + ri.cw.p(f"dst->{aspec.c_name}[i] = ynl_attr_get_{aspec.type}(attr);") else: raise Exception('Nest parsing type not supported yet') ri.cw.p('i++;') From 66fcdad0884223eb9dfa9b76161dca7917e6e03b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:20 -0800 Subject: [PATCH 1614/2255] tools: ynl: create local for_each helpers Create ynl_attr_for_each*() iteration helpers. Use them instead of the mnl ones. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-4-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 47 ++++++++++++++++++++++++++++++++++++ tools/net/ynl/lib/ynl.c | 12 ++++----- tools/net/ynl/ynl-gen-c.py | 8 +++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index d42d44a77dcb..a339732450c3 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -147,6 +147,53 @@ static inline void *ynl_attr_data(const struct nlattr *attr) return (unsigned char *)attr + NLA_HDRLEN; } +static inline void *ynl_attr_data_end(const struct nlattr *attr) +{ + return ynl_attr_data(attr) + ynl_attr_data_len(attr); +} + +#define ynl_attr_for_each(attr, nlh, fixed_hdr_sz) \ + for ((attr) = ynl_attr_first(nlh, (nlh)->nlmsg_len, \ + NLMSG_HDRLEN + fixed_hdr_sz); attr; \ + (attr) = ynl_attr_next(ynl_nlmsg_end_addr(nlh), attr)) + +#define ynl_attr_for_each_nested(attr, outer) \ + for ((attr) = ynl_attr_first(outer, outer->nla_len, \ + sizeof(struct nlattr)); attr; \ + (attr) = ynl_attr_next(ynl_attr_data_end(outer), attr)) + +#define ynl_attr_for_each_payload(start, len, attr) \ + for ((attr) = ynl_attr_first(start, len, 0); attr; \ + (attr) = ynl_attr_next(start + len, attr)) + +static inline struct nlattr * +ynl_attr_if_good(const void *end, struct nlattr *attr) +{ + if (attr + 1 > (const struct nlattr *)end) + return NULL; + if (ynl_attr_data_end(attr) > end) + return NULL; + return attr; +} + +static inline struct nlattr * +ynl_attr_next(const void *end, const struct nlattr *prev) +{ + struct nlattr *attr; + + attr = (void *)((char *)prev + NLA_ALIGN(prev->nla_len)); + return ynl_attr_if_good(end, attr); +} + +static inline struct nlattr * +ynl_attr_first(const void *start, size_t len, size_t skip) +{ + struct nlattr *attr; + + attr = (void *)((char *)start + NLMSG_ALIGN(skip)); + return ynl_attr_if_good(start + len, attr); +} + static inline struct nlattr * ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type) { diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index b9ed587af676..0f71e69b70c0 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -92,7 +92,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, data_len = end - start; - mnl_attr_for_each_payload(start, data_len) { + ynl_attr_for_each_payload(start, data_len, attr) { astart_off = (char *)attr - (char *)start; aend_off = astart_off + ynl_attr_data_len(attr); if (aend_off <= off) @@ -150,7 +150,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, return MNL_CB_OK; } - mnl_attr_for_each(attr, nlh, hlen) { + ynl_attr_for_each(attr, nlh, hlen) { unsigned int len, type; len = ynl_attr_data_len(attr); @@ -500,7 +500,7 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) const struct nlattr *entry, *attr; unsigned int i; - mnl_attr_for_each_nested(attr, mcasts) + ynl_attr_for_each_nested(attr, mcasts) ys->n_mcast_groups++; if (!ys->n_mcast_groups) @@ -512,8 +512,8 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) return MNL_CB_ERROR; i = 0; - mnl_attr_for_each_nested(entry, mcasts) { - mnl_attr_for_each_nested(attr, entry) { + ynl_attr_for_each_nested(entry, mcasts) { + ynl_attr_for_each_nested(attr, entry) { if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_ID) ys->mcast_groups[i].id = ynl_attr_get_u32(attr); if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) { @@ -535,7 +535,7 @@ static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data) const struct nlattr *attr; bool found_id = true; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + ynl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GROUPS) if (ynl_get_family_info_mcast(ys, attr)) return MNL_CB_ERROR; diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 99a3eb7b158b..eabce06f03d9 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -650,7 +650,7 @@ class TypeArrayNest(Type): def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] get_lines = [f'attr_{self.c_name} = attr;', - 'mnl_attr_for_each_nested(attr2, attr)', + 'ynl_attr_for_each_nested(attr2, attr)', f'\t{var}->n_{self.c_name}++;'] return get_lines, None, local_vars @@ -1612,11 +1612,11 @@ def put_req_nested(ri, struct): def _multi_parse(ri, struct, init_lines, local_vars): if struct.nested: - iter_line = "mnl_attr_for_each_nested(attr, nested)" + iter_line = "ynl_attr_for_each_nested(attr, nested)" else: if ri.fixed_hdr: local_vars += ['void *hdr;'] - iter_line = "mnl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)" + iter_line = "ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)" array_nests = set() multi_attrs = set() @@ -1679,7 +1679,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};") ri.cw.p('i = 0;') ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") - ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})") + ri.cw.block_start(line=f"ynl_attr_for_each_nested(attr, attr_{aspec.c_name})") ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, ynl_attr_type(attr)))") ri.cw.p('return MNL_CB_ERROR;') From 0b3ece44220887e7cf1e7469867fdd8ce9986c16 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:21 -0800 Subject: [PATCH 1615/2255] tools: ynl: create local nlmsg access helpers Create helpers for accessing payloads of struct nlmsg. Use them instead of the libmnl ones. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-5-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 39 +++++++++++++++++++++++++++++++++++- tools/net/ynl/lib/ynl.c | 24 ++++++++++------------ tools/net/ynl/ynl-gen-c.py | 6 +++--- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index a339732450c3..1dfa09497be8 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -125,13 +125,50 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); -/* Attribute helpers */ +/* Netlink message handling helpers */ + +static inline struct nlmsghdr *ynl_nlmsg_put_header(void *buf) +{ + struct nlmsghdr *nlh = buf; + + memset(nlh, 0, sizeof(*nlh)); + nlh->nlmsg_len = NLMSG_HDRLEN; + + return nlh; +} + +static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh) +{ + return nlh->nlmsg_len - NLMSG_HDRLEN; +} + +static inline void *ynl_nlmsg_data(const struct nlmsghdr *nlh) +{ + return (unsigned char *)nlh + NLMSG_HDRLEN; +} + +static inline void * +ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset) +{ + return (unsigned char *)nlh + NLMSG_HDRLEN + offset; +} static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh) { return (char *)nlh + nlh->nlmsg_len; } +static inline void * +ynl_nlmsg_put_extra_header(struct nlmsghdr *nlh, unsigned int size) +{ + void *tail = ynl_nlmsg_end_addr(nlh); + + nlh->nlmsg_len += NLMSG_ALIGN(size); + return tail; +} + +/* Netlink attribute helpers */ + static inline unsigned int ynl_attr_type(const struct nlattr *attr) { return attr->nla_type & NLA_TYPE_MASK; diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 0f71e69b70c0..5f303d6e751f 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -190,9 +190,8 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ", str ? " (" : ""); - start = mnl_nlmsg_get_payload_offset(ys->nlh, - ys->family->hdr_len); - end = mnl_nlmsg_get_payload_tail(ys->nlh); + start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len); + end = ynl_nlmsg_end_addr(ys->nlh); off = ys->err.attr_offs; off -= sizeof(struct nlmsghdr); @@ -216,9 +215,8 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ", bad_attr[0] ? ", " : (str ? " (" : "")); - start = mnl_nlmsg_get_payload_offset(ys->nlh, - ys->family->hdr_len); - end = mnl_nlmsg_get_payload_tail(ys->nlh); + start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len); + end = ynl_nlmsg_end_addr(ys->nlh); nest_pol = ys->req_policy; if (tb[NLMSGERR_ATTR_MISS_NEST]) { @@ -259,7 +257,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, static int ynl_cb_error(const struct nlmsghdr *nlh, void *data) { - const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); + const struct nlmsgerr *err = ynl_nlmsg_data(nlh); struct ynl_parse_arg *yarg = data; unsigned int hlen; int code; @@ -270,7 +268,7 @@ static int ynl_cb_error(const struct nlmsghdr *nlh, void *data) hlen = sizeof(*err); if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) - hlen += mnl_nlmsg_get_payload_len(&err->msg); + hlen += ynl_nlmsg_data_len(&err->msg); ynl_ext_ack_check(yarg->ys, nlh, hlen); @@ -413,7 +411,7 @@ struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags) ynl_err_reset(ys); - nlh = ys->nlh = mnl_nlmsg_put_header(ys->tx_buf); + nlh = ys->nlh = ynl_nlmsg_put_header(ys->tx_buf); nlh->nlmsg_type = id; nlh->nlmsg_flags = flags; nlh->nlmsg_seq = ++ys->seq; @@ -435,7 +433,7 @@ ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags, gehdr.cmd = cmd; gehdr.version = version; - data = mnl_nlmsg_put_extra_header(nlh, sizeof(gehdr)); + data = ynl_nlmsg_put_extra_header(nlh, sizeof(gehdr)); memcpy(data, &gehdr, sizeof(gehdr)); return nlh; @@ -718,7 +716,7 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh) struct genlmsghdr *gehdr; int ret; - gehdr = mnl_nlmsg_get_payload(nlh); + gehdr = ynl_nlmsg_data(nlh); if (gehdr->cmd >= ys->family->ntf_info_size) return MNL_CB_ERROR; info = &ys->family->ntf_info[gehdr->cmd]; @@ -808,13 +806,13 @@ ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd) { struct genlmsghdr *gehdr; - if (mnl_nlmsg_get_payload_len(nlh) < sizeof(*gehdr)) { + if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) { yerr(ys, YNL_ERROR_INV_RESP, "Kernel responded with truncated message"); return -1; } - gehdr = mnl_nlmsg_get_payload(nlh); + gehdr = ynl_nlmsg_data(nlh); if (gehdr->cmd != rsp_cmd) return ynl_ntf_parse(ys, nlh); diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index eabce06f03d9..90d7bf4849fc 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1650,7 +1650,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.p(f'dst->{arg} = {arg};') if ri.fixed_hdr: - ri.cw.p('hdr = mnl_nlmsg_get_payload_offset(nlh, sizeof(struct genlmsghdr));') + ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));') ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));") for anest in sorted(all_multi): aspec = struct[anest] @@ -1794,7 +1794,7 @@ def print_req(ri): if ri.fixed_hdr: ri.cw.p("hdr_len = sizeof(req->_hdr);") - ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);") + ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") ri.cw.nl() @@ -1857,7 +1857,7 @@ def print_dump(ri): if ri.fixed_hdr: ri.cw.p("hdr_len = sizeof(req->_hdr);") - ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);") + ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") ri.cw.nl() From 7600875f295f4591eebbb3744ad5de3b4f8e4117 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:22 -0800 Subject: [PATCH 1616/2255] tools: ynl: create local ARRAY_SIZE() helper libc doesn't have an ARRAY_SIZE() create one locally. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-6-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 3 +++ tools/net/ynl/ynl-gen-c.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 1dfa09497be8..7f24d07692bf 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -27,6 +27,9 @@ enum ynl_policy_type { YNL_PT_BITFIELD32, }; +#define YNL_ARRAY_SIZE(array) (sizeof(array) ? \ + sizeof(array) / sizeof(array[0]) : 0) + struct ynl_policy_attr { enum ynl_policy_type type; unsigned int len; diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 90d7bf4849fc..407902b903e0 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1535,7 +1535,7 @@ def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): cw.block_start() if enum and enum.type == 'flags': cw.p(f'{arg_name} = ffs({arg_name}) - 1;') - cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))') + cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)YNL_ARRAY_SIZE({map_name}))') cw.p('return NULL;') cw.p(f'return {map_name}[{arg_name}];') cw.block_end() @@ -2569,7 +2569,7 @@ def render_user_family(family, cw, prototype): cw.p('.hdr_len\t= sizeof(struct genlmsghdr),') if family.ntfs: cw.p(f".ntf_info\t= {family['name']}_ntf_info,") - cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),") + cw.p(f".ntf_info_size\t= YNL_ARRAY_SIZE({family['name']}_ntf_info),") cw.block_end(line=';') From d62c5d487cfe41b2d47e790acc72a062308fb0f0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:23 -0800 Subject: [PATCH 1617/2255] tools: ynl: make yarg the first member of struct ynl_dump_state All YNL parsing code expects a pointer to struct ynl_parse_arg AKA yarg. For dump was pass in struct ynl_dump_state, which works fine, because struct ynl_dump_state and struct ynl_parse_arg have identical layout for the members that matter.. but it's a bit hacky. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-7-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 3 +-- tools/net/ynl/lib/ynl.c | 5 ++--- tools/net/ynl/ynl-gen-c.py | 5 +++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 7f24d07692bf..c44b53c8d084 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -104,8 +104,7 @@ struct ynl_req_state { }; struct ynl_dump_state { - struct ynl_sock *ys; - struct ynl_policy_nest *rsp_policy; + struct ynl_parse_arg yarg; void *first; struct ynl_dump_list_type *last; size_t alloc_sz; diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 5f303d6e751f..88456c7bb1ec 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -864,7 +864,7 @@ static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data) struct ynl_parse_arg yarg = {}; int ret; - ret = ynl_check_alien(ds->ys, nlh, ds->rsp_cmd); + ret = ynl_check_alien(ds->yarg.ys, nlh, ds->rsp_cmd); if (ret) return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK; @@ -878,8 +878,7 @@ static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data) ds->last->next = obj; ds->last = obj; - yarg.ys = ds->ys; - yarg.rsp_policy = ds->rsp_policy; + yarg = ds->yarg; yarg.data = &obj->data; return ds->cb(nlh, &yarg); diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 407902b903e0..6f57c9f00e7a 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1844,14 +1844,15 @@ def print_dump(ri): ri.cw.write_func_lvar(local_vars) - ri.cw.p('yds.ys = ys;') + ri.cw.p('yds.yarg.ys = ys;') + ri.cw.p(f"yds.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") + ri.cw.p("yds.yarg.data = NULL;") ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});") ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;") if ri.op.value is not None: ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_name};') else: ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};') - ri.cw.p(f"yds.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") From 9c29a113165fc473e6f91f40e59ece94d287f95d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:24 -0800 Subject: [PATCH 1618/2255] tools: ynl-gen: remove unused parse code Commit f2ba1e5e2208 ("tools: ynl-gen: stop generating common notification handlers") removed the last caller of the parse_cb_run() helper. We no longer need to export ynl_cb_array. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-8-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 2 -- tools/net/ynl/lib/ynl.c | 2 +- tools/net/ynl/ynl-gen-c.py | 8 -------- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index c44b53c8d084..ef16fcbd9f68 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -83,8 +83,6 @@ struct ynl_ntf_base_type { unsigned char data[] __attribute__((aligned(8))); }; -extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; - struct nlmsghdr * ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); struct nlmsghdr * diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 88456c7bb1ec..ad77ce6a1128 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -297,7 +297,7 @@ static int ynl_cb_noop(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } -mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE] = { +static mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE] = { [NLMSG_NOOP] = ynl_cb_noop, [NLMSG_ERROR] = ynl_cb_error, [NLMSG_DONE] = ynl_cb_done, diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 6f57c9f00e7a..289a04f2cfaa 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -40,14 +40,6 @@ class BaseNlLib: def get_family_id(self): return 'ys->family_id' - def parse_cb_run(self, cb, data, is_dump=False, indent=1): - ind = '\n\t\t' + '\t' * indent + ' ' - if is_dump: - return f"mnl_cb_run2(ys->rx_buf, len, 0, 0, {cb}, {data},{ind}ynl_cb_array, NLMSG_MIN_TYPE)" - else: - return f"mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,{ind}{cb}, {data},{ind}" + \ - "ynl_cb_array, NLMSG_MIN_TYPE)" - class Type(SpecAttr): def __init__(self, family, attr_set, attr, value): From 2f22f0b313f4c11e524c68e34165e62d8276e442 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:25 -0800 Subject: [PATCH 1619/2255] tools: ynl: wrap recv() + mnl_cb_run2() into a single helper All callers to mnl_cb_run2() call mnl_socket_recvfrom() right before. Wrap the two in a helper, take typed arguments (struct ynl_parse_arg), instead of hoping that all callers remember that parser error handling requires yarg. In case of ynl_sock_read_family() we will no longer check for kernel returning no data, but that would be a kernel bug, not worth complicating the code to catch this. Calling mnl_cb_run2() on an empty buffer is legal and results in STOP (1). Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-9-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.c | 56 +++++++++++++---------------------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index ad77ce6a1128..7c0f404526a0 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -491,6 +491,19 @@ int ynl_cb_null(const struct nlmsghdr *nlh, void *data) return MNL_CB_ERROR; } +static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, mnl_cb_t cb) +{ + struct ynl_sock *ys = yarg->ys; + ssize_t len; + + len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); + if (len < 0) + return len; + + return mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, + cb, yarg, ynl_cb_array, NLMSG_MIN_TYPE); +} + /* Init/fini and genetlink boiler plate */ static int ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) @@ -572,14 +585,7 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) return err; } - err = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); - if (err <= 0) { - perr(ys, "failed to receive the socket family info"); - return err; - } - err = mnl_cb_run2(ys->rx_buf, err, ys->seq, ys->portid, - ynl_get_family_info_cb, &yarg, - ynl_cb_array, ARRAY_SIZE(ynl_cb_array)); + err = ynl_sock_read_msgs(&yarg, ynl_get_family_info_cb); if (err < 0) { free(ys->mcast_groups); perr(ys, "failed to receive the socket family info - no such family?"); @@ -755,7 +761,6 @@ static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data) int ynl_ntf_check(struct ynl_sock *ys) { struct ynl_parse_arg yarg = { .ys = ys, }; - ssize_t len; int err; do { @@ -770,14 +775,7 @@ int ynl_ntf_check(struct ynl_sock *ys) if (err < 1) return err; - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, - MNL_SOCKET_BUFFER_SIZE); - if (len < 0) - return len; - - err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, - ynl_ntf_trampoline, &yarg, - ynl_cb_array, NLMSG_MIN_TYPE); + err = ynl_sock_read_msgs(&yarg, ynl_ntf_trampoline); if (err < 0) return err; } while (err > 0); @@ -834,7 +832,6 @@ static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data) int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, struct ynl_req_state *yrs) { - ssize_t len; int err; err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); @@ -842,19 +839,10 @@ int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, return err; do { - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, - MNL_SOCKET_BUFFER_SIZE); - if (len < 0) - return len; - - err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, - ynl_req_trampoline, yrs, - ynl_cb_array, NLMSG_MIN_TYPE); - if (err < 0) - return err; + err = ynl_sock_read_msgs(&yrs->yarg, ynl_req_trampoline); } while (err > 0); - return 0; + return err; } static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data) @@ -896,7 +884,6 @@ static void *ynl_dump_end(struct ynl_dump_state *ds) int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, struct ynl_dump_state *yds) { - ssize_t len; int err; err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); @@ -904,14 +891,7 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, return err; do { - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, - MNL_SOCKET_BUFFER_SIZE); - if (len < 0) - goto err_close_list; - - err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, - ynl_dump_trampoline, yds, - ynl_cb_array, NLMSG_MIN_TYPE); + err = ynl_sock_read_msgs(&yds->yarg, ynl_dump_trampoline); if (err < 0) goto err_close_list; } while (err > 0); From 1621378aab19e6197fe95dc76d1825ef91d40e49 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:26 -0800 Subject: [PATCH 1620/2255] tools: ynl: use ynl_sock_read_msgs() for ACK handling ynl_recv_ack() is simple and it's the only user of mnl_cb_run(). Now that ynl_sock_read_msgs() exists it's actually less code to use ynl_sock_read_msgs() instead of being special. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-10-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 3 --- tools/net/ynl/lib/ynl.c | 34 ++++++++++++++-------------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index ef16fcbd9f68..42f7d29fbee0 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -90,9 +90,6 @@ ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); -int ynl_recv_ack(struct ynl_sock *ys, int ret); -int ynl_cb_null(const struct nlmsghdr *nlh, void *data); - /* YNL specific helpers used by the auto-generated code */ struct ynl_req_state { diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 7c0f404526a0..f830990b3f4a 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -462,26 +462,7 @@ ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version) cmd, version); } -int ynl_recv_ack(struct ynl_sock *ys, int ret) -{ - struct ynl_parse_arg yarg = { .ys = ys, }; - - if (!ret) { - yerr(ys, YNL_ERROR_EXPECT_ACK, - "Expecting an ACK but nothing received"); - return -1; - } - - ret = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); - if (ret < 0) { - perr(ys, "Socket receive failed"); - return ret; - } - return mnl_cb_run(ys->rx_buf, ret, ys->seq, ys->portid, - ynl_cb_null, &yarg); -} - -int ynl_cb_null(const struct nlmsghdr *nlh, void *data) +static int ynl_cb_null(const struct nlmsghdr *nlh, void *data) { struct ynl_parse_arg *yarg = data; @@ -504,6 +485,19 @@ static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, mnl_cb_t cb) cb, yarg, ynl_cb_array, NLMSG_MIN_TYPE); } +static int ynl_recv_ack(struct ynl_sock *ys, int ret) +{ + struct ynl_parse_arg yarg = { .ys = ys, }; + + if (!ret) { + yerr(ys, YNL_ERROR_EXPECT_ACK, + "Expecting an ACK but nothing received"); + return -1; + } + + return ynl_sock_read_msgs(&yarg, ynl_cb_null); +} + /* Init/fini and genetlink boiler plate */ static int ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) From 766c4b5460f4edf3fd51ef8696f89fa207bf95f8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:27 -0800 Subject: [PATCH 1621/2255] tools: ynl: stop using mnl_cb_run2() There's only one set of callbacks in YNL, for netlink control messages, and most of them are trivial. So implement the message walking directly without depending on mnl_cb_run2(). Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-11-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.c | 63 ++++++++++++++++++++++++++++------------- tools/net/ynl/lib/ynl.h | 1 + 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index f830990b3f4a..fd658aaff345 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -255,10 +255,10 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, return MNL_CB_OK; } -static int ynl_cb_error(const struct nlmsghdr *nlh, void *data) +static int +ynl_cb_error(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { const struct nlmsgerr *err = ynl_nlmsg_data(nlh); - struct ynl_parse_arg *yarg = data; unsigned int hlen; int code; @@ -275,9 +275,8 @@ static int ynl_cb_error(const struct nlmsghdr *nlh, void *data) return code ? MNL_CB_ERROR : MNL_CB_STOP; } -static int ynl_cb_done(const struct nlmsghdr *nlh, void *data) +static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_parse_arg *yarg = data; int err; err = *(int *)NLMSG_DATA(nlh); @@ -292,18 +291,6 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, void *data) return MNL_CB_STOP; } -static int ynl_cb_noop(const struct nlmsghdr *nlh, void *data) -{ - return MNL_CB_OK; -} - -static mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE] = { - [NLMSG_NOOP] = ynl_cb_noop, - [NLMSG_ERROR] = ynl_cb_error, - [NLMSG_DONE] = ynl_cb_done, - [NLMSG_OVERRUN] = ynl_cb_noop, -}; - /* Attribute validation */ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) @@ -475,14 +462,52 @@ static int ynl_cb_null(const struct nlmsghdr *nlh, void *data) static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, mnl_cb_t cb) { struct ynl_sock *ys = yarg->ys; - ssize_t len; + const struct nlmsghdr *nlh; + ssize_t len, rem; + int ret; len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); if (len < 0) return len; - return mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, - cb, yarg, ynl_cb_array, NLMSG_MIN_TYPE); + ret = MNL_CB_STOP; + for (rem = len; rem > 0; NLMSG_NEXT(nlh, rem)) { + nlh = (struct nlmsghdr *)&ys->rx_buf[len - rem]; + if (!NLMSG_OK(nlh, rem)) { + yerr(yarg->ys, YNL_ERROR_INV_RESP, + "Invalid message or trailing data in the response."); + return MNL_CB_ERROR; + } + + if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) { + /* TODO: handle this better */ + yerr(yarg->ys, YNL_ERROR_DUMP_INTER, + "Dump interrupted / inconsistent, please retry."); + return MNL_CB_ERROR; + } + + switch (nlh->nlmsg_type) { + case 0: + yerr(yarg->ys, YNL_ERROR_INV_RESP, + "Invalid message type in the response."); + return MNL_CB_ERROR; + case NLMSG_NOOP: + case NLMSG_OVERRUN ... NLMSG_MIN_TYPE - 1: + ret = MNL_CB_OK; + break; + case NLMSG_ERROR: + ret = ynl_cb_error(nlh, yarg); + break; + case NLMSG_DONE: + ret = ynl_cb_done(nlh, yarg); + break; + default: + ret = cb(nlh, yarg); + break; + } + } + + return ret; } static int ynl_recv_ack(struct ynl_sock *ys, int ret) diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index ce77a6d76ce0..4849c142fce0 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -12,6 +12,7 @@ enum ynl_error_code { YNL_ERROR_NONE = 0, __YNL_ERRNO_END = 4096, YNL_ERROR_INTERNAL, + YNL_ERROR_DUMP_INTER, YNL_ERROR_EXPECT_ACK, YNL_ERROR_EXPECT_MSG, YNL_ERROR_UNEXPECT_MSG, From dd0973d71e1feb36fd396aea7094f89888be7e42 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:28 -0800 Subject: [PATCH 1622/2255] tools: ynl: switch away from mnl_cb_t All YNL parsing callbacks take struct ynl_parse_arg as the argument. Make that official by using a local callback type instead of mnl_cb_t. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-12-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 11 ++++++++--- tools/net/ynl/lib/ynl.c | 25 ++++++++++++------------- tools/net/ynl/ynl-gen-c.py | 3 +-- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 42f7d29fbee0..5c0bd90c116b 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -6,6 +6,8 @@ #include #include +struct ynl_parse_arg; + /* * YNL internals / low level stuff */ @@ -30,6 +32,9 @@ enum ynl_policy_type { #define YNL_ARRAY_SIZE(array) (sizeof(array) ? \ sizeof(array) / sizeof(array[0]) : 0) +typedef int (*ynl_parse_cb_t)(const struct nlmsghdr *nlh, + struct ynl_parse_arg *yarg); + struct ynl_policy_attr { enum ynl_policy_type type; unsigned int len; @@ -94,7 +99,7 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); struct ynl_req_state { struct ynl_parse_arg yarg; - mnl_cb_t cb; + ynl_parse_cb_t cb; __u32 rsp_cmd; }; @@ -103,13 +108,13 @@ struct ynl_dump_state { void *first; struct ynl_dump_list_type *last; size_t alloc_sz; - mnl_cb_t cb; + ynl_parse_cb_t cb; __u32 rsp_cmd; }; struct ynl_ntf_info { struct ynl_policy_nest *policy; - mnl_cb_t cb; + ynl_parse_cb_t cb; size_t alloc_sz; void (*free)(struct ynl_ntf_base_type *ntf); }; diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index fd658aaff345..27fb596aa791 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -449,17 +449,15 @@ ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version) cmd, version); } -static int ynl_cb_null(const struct nlmsghdr *nlh, void *data) +static int ynl_cb_null(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_parse_arg *yarg = data; - yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG, "Received a message when none were expected"); return MNL_CB_ERROR; } -static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, mnl_cb_t cb) +static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) { struct ynl_sock *ys = yarg->ys; const struct nlmsghdr *nlh; @@ -558,9 +556,9 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) return 0; } -static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data) +static int +ynl_get_family_info_cb(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_parse_arg *yarg = data; struct ynl_sock *ys = yarg->ys; const struct nlattr *attr; bool found_id = true; @@ -770,10 +768,9 @@ err_free: return MNL_CB_ERROR; } -static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data) +static int +ynl_ntf_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_parse_arg *yarg = data; - return ynl_ntf_parse(yarg->ys, nlh); } @@ -836,9 +833,10 @@ ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd) return 0; } -static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data) +static +int ynl_req_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_req_state *yrs = data; + struct ynl_req_state *yrs = (void *)yarg; int ret; ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd); @@ -864,9 +862,10 @@ int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, return err; } -static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data) +static int +ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data) { - struct ynl_dump_state *ds = data; + struct ynl_dump_state *ds = (void *)data; struct ynl_dump_list_type *obj; struct ynl_parse_arg yarg = {}; int ret; diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 289a04f2cfaa..15a9d3b2eed3 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1737,10 +1737,9 @@ def parse_rsp_msg(ri, deref=False): return func_args = ['const struct nlmsghdr *nlh', - 'void *data'] + 'struct ynl_parse_arg *yarg'] local_vars = [f'{type_name(ri, "reply", deref=deref)} *dst;', - 'struct ynl_parse_arg *yarg = data;', 'const struct nlattr *attr;'] init_lines = ['dst = yarg->data;'] From 50042e8051fe6246e188b24f0b9bed7822582435 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:29 -0800 Subject: [PATCH 1623/2255] tools: ynl: switch away from MNL_CB_* Create a local version of the MNL_CB_* parser control values. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-13-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 6 ++++ tools/net/ynl/lib/ynl.c | 54 ++++++++++++++++++------------------ tools/net/ynl/ynl-gen-c.py | 14 +++++----- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 5c0bd90c116b..a3a9367aacbe 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -29,6 +29,12 @@ enum ynl_policy_type { YNL_PT_BITFIELD32, }; +enum ynl_parse_result { + YNL_PARSE_CB_ERROR = -1, + YNL_PARSE_CB_STOP = 0, + YNL_PARSE_CB_OK = 1, +}; + #define YNL_ARRAY_SIZE(array) (sizeof(array) ? \ sizeof(array) / sizeof(array[0]) : 0) diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 27fb596aa791..968ab679b5e3 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -147,7 +147,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) { yerr_msg(ys, "%s", strerror(ys->err.code)); - return MNL_CB_OK; + return YNL_PARSE_CB_OK; } ynl_attr_for_each(attr, nlh, hlen) { @@ -166,12 +166,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, case NLMSGERR_ATTR_MISS_TYPE: case NLMSGERR_ATTR_MISS_NEST: if (len != sizeof(__u32)) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; break; case NLMSGERR_ATTR_MSG: str = ynl_attr_get_str(attr); if (str[len - 1]) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; break; default: break; @@ -252,7 +252,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, else yerr_msg(ys, "%s", strerror(ys->err.code)); - return MNL_CB_OK; + return YNL_PARSE_CB_OK; } static int @@ -272,7 +272,7 @@ ynl_cb_error(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) ynl_ext_ack_check(yarg->ys, nlh, hlen); - return code ? MNL_CB_ERROR : MNL_CB_STOP; + return code ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_STOP; } static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) @@ -286,9 +286,9 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) ynl_ext_ack_check(yarg->ys, nlh, sizeof(int)); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } - return MNL_CB_STOP; + return YNL_PARSE_CB_STOP; } /* Attribute validation */ @@ -454,7 +454,7 @@ static int ynl_cb_null(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG, "Received a message when none were expected"); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) @@ -468,30 +468,30 @@ static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) if (len < 0) return len; - ret = MNL_CB_STOP; + ret = YNL_PARSE_CB_STOP; for (rem = len; rem > 0; NLMSG_NEXT(nlh, rem)) { nlh = (struct nlmsghdr *)&ys->rx_buf[len - rem]; if (!NLMSG_OK(nlh, rem)) { yerr(yarg->ys, YNL_ERROR_INV_RESP, "Invalid message or trailing data in the response."); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) { /* TODO: handle this better */ yerr(yarg->ys, YNL_ERROR_DUMP_INTER, "Dump interrupted / inconsistent, please retry."); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } switch (nlh->nlmsg_type) { case 0: yerr(yarg->ys, YNL_ERROR_INV_RESP, "Invalid message type in the response."); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; case NLMSG_NOOP: case NLMSG_OVERRUN ... NLMSG_MIN_TYPE - 1: - ret = MNL_CB_OK; + ret = YNL_PARSE_CB_OK; break; case NLMSG_ERROR: ret = ynl_cb_error(nlh, yarg); @@ -537,7 +537,7 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) ys->mcast_groups = calloc(ys->n_mcast_groups, sizeof(*ys->mcast_groups)); if (!ys->mcast_groups) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; i = 0; ynl_attr_for_each_nested(entry, mcasts) { @@ -566,14 +566,14 @@ ynl_get_family_info_cb(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) ynl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GROUPS) if (ynl_get_family_info_mcast(ys, attr)) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; if (ynl_attr_type(attr) != CTRL_ATTR_FAMILY_ID) continue; if (ynl_attr_data_len(attr) != sizeof(__u16)) { yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID"); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } ys->family_id = ynl_attr_get_u16(attr); @@ -582,9 +582,9 @@ ynl_get_family_info_cb(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) if (!found_id) { yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing"); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } - return MNL_CB_OK; + return YNL_PARSE_CB_OK; } static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) @@ -741,10 +741,10 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh) gehdr = ynl_nlmsg_data(nlh); if (gehdr->cmd >= ys->family->ntf_info_size) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; info = &ys->family->ntf_info[gehdr->cmd]; if (!info->cb) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; rsp = calloc(1, info->alloc_sz); rsp->free = info->free; @@ -752,7 +752,7 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh) yarg.rsp_policy = info->policy; ret = info->cb(nlh, &yarg); - if (ret <= MNL_CB_STOP) + if (ret <= YNL_PARSE_CB_STOP) goto err_free; rsp->family = nlh->nlmsg_type; @@ -761,11 +761,11 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh) *ys->ntf_last_next = rsp; ys->ntf_last_next = &rsp->next; - return MNL_CB_OK; + return YNL_PARSE_CB_OK; err_free: info->free(rsp); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } static int @@ -812,7 +812,7 @@ void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd) int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg) { yerr(yarg->ys, YNL_ERROR_INV_RESP, "Error parsing response: %s", msg); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } static int @@ -841,7 +841,7 @@ int ynl_req_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd); if (ret) - return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK; + return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK; return yrs->cb(nlh, &yrs->yarg); } @@ -872,11 +872,11 @@ ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data) ret = ynl_check_alien(ds->yarg.ys, nlh, ds->rsp_cmd); if (ret) - return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK; + return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK; obj = calloc(1, ds->alloc_sz); if (!obj) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; if (!ds->first) ds->first = obj; diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 15a9d3b2eed3..375d5f5e3052 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -200,7 +200,7 @@ class Type(SpecAttr): if not self.is_multi_val(): ri.cw.p("if (ynl_attr_validate(yarg, attr))") - ri.cw.p("return MNL_CB_ERROR;") + ri.cw.p("return YNL_PARSE_CB_ERROR;") if self.presence_type() == 'bit': ri.cw.p(f"{var}->_present.{self.c_name} = 1;") @@ -247,7 +247,7 @@ class TypeUnused(Type): return [] def _attr_get(self, ri, var): - return ['return MNL_CB_ERROR;'], None, None + return ['return YNL_PARSE_CB_ERROR;'], None, None def _attr_typol(self): return '.type = YNL_PT_REJECT, ' @@ -543,7 +543,7 @@ class TypeNest(Type): def _attr_get(self, ri, var): get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))", - "return MNL_CB_ERROR;"] + "return YNL_PARSE_CB_ERROR;"] init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", f"parg.data = &{var}->{self.c_name};"] return get_lines, init_lines, None @@ -1674,7 +1674,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_start(line=f"ynl_attr_for_each_nested(attr, attr_{aspec.c_name})") ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, ynl_attr_type(attr)))") - ri.cw.p('return MNL_CB_ERROR;') + ri.cw.p('return YNL_PARSE_CB_ERROR;') ri.cw.p('i++;') ri.cw.block_end() ri.cw.block_end() @@ -1693,7 +1693,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): if 'nested-attributes' in aspec: ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr))") - ri.cw.p('return MNL_CB_ERROR;') + ri.cw.p('return YNL_PARSE_CB_ERROR;') elif aspec.type in scalars: ri.cw.p(f"dst->{aspec.c_name}[i] = ynl_attr_get_{aspec.type}(attr);") else: @@ -1707,7 +1707,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): if struct.nested: ri.cw.p('return 0;') else: - ri.cw.p('return MNL_CB_OK;') + ri.cw.p('return YNL_PARSE_CB_OK;') ri.cw.block_end() ri.cw.nl() @@ -1750,7 +1750,7 @@ def parse_rsp_msg(ri, deref=False): else: # Empty reply ri.cw.block_start() - ri.cw.p('return MNL_CB_OK;') + ri.cw.p('return YNL_PARSE_CB_OK;') ri.cw.block_end() ri.cw.nl() From 5ac6868daa0e34856506baf43c89e6d4fd5635c8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:30 -0800 Subject: [PATCH 1624/2255] tools: ynl: stop using mnl socket helpers Most libmnl socket helpers can be replaced by direct calls to the underlying libc API. We need portid, the netlink manpage suggests we bind() address of zero. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-14-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 2 ++ tools/net/ynl/lib/ynl.c | 60 +++++++++++++++++++++++------------- tools/net/ynl/lib/ynl.h | 2 +- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index a3a9367aacbe..5150ef1dacda 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -35,6 +35,8 @@ enum ynl_parse_result { YNL_PARSE_CB_OK = 1, }; +#define YNL_SOCKET_BUFFER_SIZE (1 << 17) + #define YNL_ARRAY_SIZE(array) (sizeof(array) ? \ sizeof(array) / sizeof(array[0]) : 0) diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 968ab679b5e3..9d028929117a 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -3,10 +3,12 @@ #include #include #include +#include +#include #include - #include #include +#include #include "ynl.h" @@ -464,7 +466,7 @@ static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) ssize_t len, rem; int ret; - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); + len = recv(ys->socket, ys->rx_buf, YNL_SOCKET_BUFFER_SIZE, 0); if (len < 0) return len; @@ -596,7 +598,7 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) nlh = ynl_gemsg_start_req(ys, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1); ynl_attr_put_str(nlh, CTRL_ATTR_FAMILY_NAME, family_name); - err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len); + err = send(ys->socket, nlh, nlh->nlmsg_len, 0); if (err < 0) { perr(ys, "failed to request socket family info"); return err; @@ -621,38 +623,54 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) struct ynl_sock * ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse) { + struct sockaddr_nl addr; struct ynl_sock *ys; + socklen_t addrlen; int one = 1; - ys = malloc(sizeof(*ys) + 2 * MNL_SOCKET_BUFFER_SIZE); + ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE); if (!ys) return NULL; memset(ys, 0, sizeof(*ys)); ys->family = yf; ys->tx_buf = &ys->raw_buf[0]; - ys->rx_buf = &ys->raw_buf[MNL_SOCKET_BUFFER_SIZE]; + ys->rx_buf = &ys->raw_buf[YNL_SOCKET_BUFFER_SIZE]; ys->ntf_last_next = &ys->ntf_first; - ys->sock = mnl_socket_open(NETLINK_GENERIC); - if (!ys->sock) { + ys->socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + if (ys->socket < 0) { __perr(yse, "failed to create a netlink socket"); goto err_free_sock; } - if (mnl_socket_setsockopt(ys->sock, NETLINK_CAP_ACK, - &one, sizeof(one))) { + if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_CAP_ACK, + &one, sizeof(one))) { __perr(yse, "failed to enable netlink ACK"); goto err_close_sock; } - if (mnl_socket_setsockopt(ys->sock, NETLINK_EXT_ACK, - &one, sizeof(one))) { + if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_EXT_ACK, + &one, sizeof(one))) { __perr(yse, "failed to enable netlink ext ACK"); goto err_close_sock; } + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + if (bind(ys->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + __perr(yse, "unable to bind to a socket address"); + goto err_close_sock;; + } + + memset(&addr, 0, sizeof(addr)); + addrlen = sizeof(addr); + if (getsockname(ys->socket, (struct sockaddr *)&addr, &addrlen) < 0) { + __perr(yse, "unable to read socket address"); + goto err_close_sock;; + } + ys->portid = addr.nl_pid; ys->seq = random(); - ys->portid = mnl_socket_get_portid(ys->sock); + if (ynl_sock_read_family(ys, yf->name)) { if (yse) @@ -663,7 +681,7 @@ ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse) return ys; err_close_sock: - mnl_socket_close(ys->sock); + close(ys->socket); err_free_sock: free(ys); return NULL; @@ -673,7 +691,7 @@ void ynl_sock_destroy(struct ynl_sock *ys) { struct ynl_ntf_base_type *ntf; - mnl_socket_close(ys->sock); + close(ys->socket); while ((ntf = ynl_ntf_dequeue(ys))) ynl_ntf_free(ntf); free(ys->mcast_groups); @@ -700,9 +718,9 @@ int ynl_subscribe(struct ynl_sock *ys, const char *grp_name) return -1; } - err = mnl_socket_setsockopt(ys->sock, NETLINK_ADD_MEMBERSHIP, - &ys->mcast_groups[i].id, - sizeof(ys->mcast_groups[i].id)); + err = setsockopt(ys->socket, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &ys->mcast_groups[i].id, + sizeof(ys->mcast_groups[i].id)); if (err < 0) { perr(ys, "Subscribing to multicast group failed"); return -1; @@ -713,7 +731,7 @@ int ynl_subscribe(struct ynl_sock *ys, const char *grp_name) int ynl_socket_get_fd(struct ynl_sock *ys) { - return mnl_socket_get_fd(ys->sock); + return ys->socket; } struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys) @@ -785,7 +803,7 @@ int ynl_ntf_check(struct ynl_sock *ys) */ struct pollfd pfd = { }; - pfd.fd = mnl_socket_get_fd(ys->sock); + pfd.fd = ys->socket; pfd.events = POLLIN; err = poll(&pfd, 1, 1); if (err < 1) @@ -851,7 +869,7 @@ int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, { int err; - err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); + err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0); if (err < 0) return err; @@ -904,7 +922,7 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, { int err; - err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); + err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0); if (err < 0) return err; diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index 4849c142fce0..dbeeef8ce91a 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -59,7 +59,7 @@ struct ynl_sock { /* private: */ const struct ynl_family *family; - struct mnl_socket *sock; + int socket; __u32 seq; __u32 portid; __u16 family_id; From 73395b43819b00365f0971e0e0e023d9fb341346 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:31 -0800 Subject: [PATCH 1625/2255] tools: ynl: remove the libmnl dependency We don't use libmnl any more. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-15-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl-priv.h | 4 +--- tools/net/ynl/lib/ynl.c | 1 - tools/net/ynl/samples/Makefile | 2 +- tools/net/ynl/ynl-gen-c.py | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 5150ef1dacda..a8099fab035d 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -2,8 +2,8 @@ #ifndef __YNL_C_PRIV_H #define __YNL_C_PRIV_H 1 +#include #include -#include #include struct ynl_parse_arg; @@ -12,8 +12,6 @@ struct ynl_parse_arg; * YNL internals / low level stuff */ -/* Generic mnl helper code */ - enum ynl_policy_type { YNL_PT_REJECT = 1, YNL_PT_IGNORE, diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 9d028929117a..f8a66ae88ba9 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index 28bdb1557a54..1d33e98e3ffe 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -9,7 +9,7 @@ ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif -LDLIBS=-lmnl ../lib/ynl.a ../generated/protos.a +LDLIBS=../lib/ynl.a ../generated/protos.a SRCS=$(wildcard *.c) BINS=$(patsubst %.c,%,${SRCS}) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 375d5f5e3052..2f5febfe66a1 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2677,7 +2677,6 @@ def main(): if args.mode == "user": if not args.header: - cw.p("#include ") cw.p("#include ") cw.nl() for one in args.user_header: From 7c4a38bf1eba9398d03e706823ec3b08b0a960de Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Feb 2024 14:30:32 -0800 Subject: [PATCH 1626/2255] tools: ynl: use MSG_DONTWAIT for getting notifications To stick to libmnl wrappers in the past we had to use poll() to check if there are any outstanding notifications on the socket. This is no longer necessary, we can use MSG_DONTWAIT. Acked-by: Nicolas Dichtel Link: https://lore.kernel.org/r/20240227223032.1835527-16-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index f8a66ae88ba9..86729119e1ef 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -458,16 +458,20 @@ static int ynl_cb_null(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) return YNL_PARSE_CB_ERROR; } -static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) +static int +__ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb, int flags) { struct ynl_sock *ys = yarg->ys; const struct nlmsghdr *nlh; ssize_t len, rem; int ret; - len = recv(ys->socket, ys->rx_buf, YNL_SOCKET_BUFFER_SIZE, 0); - if (len < 0) + len = recv(ys->socket, ys->rx_buf, YNL_SOCKET_BUFFER_SIZE, flags); + if (len < 0) { + if (flags & MSG_DONTWAIT && errno == EAGAIN) + return YNL_PARSE_CB_STOP; return len; + } ret = YNL_PARSE_CB_STOP; for (rem = len; rem > 0; NLMSG_NEXT(nlh, rem)) { @@ -509,6 +513,11 @@ static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) return ret; } +static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) +{ + return __ynl_sock_read_msgs(yarg, cb, 0); +} + static int ynl_recv_ack(struct ynl_sock *ys, int ret) { struct ynl_parse_arg yarg = { .ys = ys, }; @@ -797,18 +806,8 @@ int ynl_ntf_check(struct ynl_sock *ys) int err; do { - /* libmnl doesn't let us pass flags to the recv to make - * it non-blocking so we need to poll() or peek() :| - */ - struct pollfd pfd = { }; - - pfd.fd = ys->socket; - pfd.events = POLLIN; - err = poll(&pfd, 1, 1); - if (err < 1) - return err; - - err = ynl_sock_read_msgs(&yarg, ynl_ntf_trampoline); + err = __ynl_sock_read_msgs(&yarg, ynl_ntf_trampoline, + MSG_DONTWAIT); if (err < 0) return err; } while (err > 0); From d4f01c5e477afecb0baede359e4b19b9882872fa Mon Sep 17 00:00:00 2001 From: Chengming Zhou Date: Wed, 28 Feb 2024 03:06:58 +0000 Subject: [PATCH 1627/2255] net: remove SLAB_MEM_SPREAD flag usage The SLAB_MEM_SPREAD flag used to be implemented in SLAB, which was removed as of v6.8-rc1, so it became a dead flag since the commit 16a1d968358a ("mm/slab: remove mm/slab.c and slab_def.h"). And the series[1] went on to mark it obsolete to avoid confusion for users. Here we can just remove all its users, which has no functional change. [1] https://lore.kernel.org/all/20240223-slab-cleanup-flags-v2-1-02f1753e8303@suse.cz/ Signed-off-by: Chengming Zhou Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240228030658.3512782-1-chengming.zhou@linux.dev Signed-off-by: Jakub Kicinski --- net/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/socket.c b/net/socket.c index ed3df2f749bf..7e9c8fc9a5b4 100644 --- a/net/socket.c +++ b/net/socket.c @@ -343,7 +343,7 @@ static void init_inodecache(void) 0, (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | - SLAB_MEM_SPREAD | SLAB_ACCOUNT), + SLAB_ACCOUNT), init_once); BUG_ON(sock_inode_cachep == NULL); } From e83ddcea65491efe29e12765996966509aa795d3 Mon Sep 17 00:00:00 2001 From: Catalin Popescu Date: Mon, 26 Feb 2024 17:23:39 +0100 Subject: [PATCH 1628/2255] net: phy: dp83826: disable WOL at init Commit d1d77120bc28 ("net: phy: dp83826: support TX data voltage tuning") introduced a regression in that WOL is not disabled by default for DP83826. WOL should normally be enabled through ethtool. Fixes: d1d77120bc28 ("net: phy: dp83826: support TX data voltage tuning") Signed-off-by: Catalin Popescu Link: https://lore.kernel.org/r/20240226162339.696461-1-catalin.popescu@leica-geosystems.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/dp83822.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index edc39ae4c241..95178e26a060 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -572,7 +572,7 @@ static int dp83826_config_init(struct phy_device *phydev) return ret; } - return 0; + return dp8382x_disable_wol(phydev); } static int dp8382x_config_init(struct phy_device *phydev) From 0598f8f3bb77893a13105d47bb7dfe42f1dc1f4e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Feb 2024 09:24:09 +0000 Subject: [PATCH 1629/2255] inet: annotate devconf data-races Add READ_ONCE() in ipv4_devconf_get() and corresponding WRITE_ONCE() in ipv4_devconf_set() Add IPV4_DEVCONF_RO() and IPV4_DEVCONF_ALL_RO() macros, and use them when reading devconf fields. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240227092411.2315725-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/linux/inetdevice.h | 14 ++++++++------ net/ipv4/devinet.c | 21 +++++++++++---------- net/ipv4/igmp.c | 4 ++-- net/ipv4/proc.c | 2 +- net/ipv4/route.c | 4 ++-- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index ddb27fc0ee8c..cb5280e6cc21 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -53,13 +53,15 @@ struct in_device { }; #define IPV4_DEVCONF(cnf, attr) ((cnf).data[IPV4_DEVCONF_ ## attr - 1]) +#define IPV4_DEVCONF_RO(cnf, attr) READ_ONCE(IPV4_DEVCONF(cnf, attr)) #define IPV4_DEVCONF_ALL(net, attr) \ IPV4_DEVCONF((*(net)->ipv4.devconf_all), attr) +#define IPV4_DEVCONF_ALL_RO(net, attr) READ_ONCE(IPV4_DEVCONF_ALL(net, attr)) -static inline int ipv4_devconf_get(struct in_device *in_dev, int index) +static inline int ipv4_devconf_get(const struct in_device *in_dev, int index) { index--; - return in_dev->cnf.data[index]; + return READ_ONCE(in_dev->cnf.data[index]); } static inline void ipv4_devconf_set(struct in_device *in_dev, int index, @@ -67,7 +69,7 @@ static inline void ipv4_devconf_set(struct in_device *in_dev, int index, { index--; set_bit(index, in_dev->cnf.state); - in_dev->cnf.data[index] = val; + WRITE_ONCE(in_dev->cnf.data[index], val); } static inline void ipv4_devconf_setall(struct in_device *in_dev) @@ -81,18 +83,18 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) ipv4_devconf_set((in_dev), IPV4_DEVCONF_ ## attr, (val)) #define IN_DEV_ANDCONF(in_dev, attr) \ - (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) && \ + (IPV4_DEVCONF_ALL_RO(dev_net(in_dev->dev), attr) && \ IN_DEV_CONF_GET((in_dev), attr)) #define IN_DEV_NET_ORCONF(in_dev, net, attr) \ - (IPV4_DEVCONF_ALL(net, attr) || \ + (IPV4_DEVCONF_ALL_RO(net, attr) || \ IN_DEV_CONF_GET((in_dev), attr)) #define IN_DEV_ORCONF(in_dev, attr) \ IN_DEV_NET_ORCONF(in_dev, dev_net(in_dev->dev), attr) #define IN_DEV_MAXCONF(in_dev, attr) \ - (max(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr), \ + (max(IPV4_DEVCONF_ALL_RO(dev_net(in_dev->dev), attr), \ IN_DEV_CONF_GET((in_dev), attr))) #define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index bc74f131fe4d..ca75d0fff1d1 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1982,7 +1982,7 @@ static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev, return -EMSGSIZE; for (i = 0; i < IPV4_DEVCONF_MAX; i++) - ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i]; + ((u32 *) nla_data(nla))[i] = READ_ONCE(in_dev->cnf.data[i]); return 0; } @@ -2068,9 +2068,9 @@ static int inet_netconf_msgsize_devconf(int type) } static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, - struct ipv4_devconf *devconf, u32 portid, - u32 seq, int event, unsigned int flags, - int type) + const struct ipv4_devconf *devconf, + u32 portid, u32 seq, int event, + unsigned int flags, int type) { struct nlmsghdr *nlh; struct netconfmsg *ncm; @@ -2095,27 +2095,28 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, if ((all || type == NETCONFA_FORWARDING) && nla_put_s32(skb, NETCONFA_FORWARDING, - IPV4_DEVCONF(*devconf, FORWARDING)) < 0) + IPV4_DEVCONF_RO(*devconf, FORWARDING)) < 0) goto nla_put_failure; if ((all || type == NETCONFA_RP_FILTER) && nla_put_s32(skb, NETCONFA_RP_FILTER, - IPV4_DEVCONF(*devconf, RP_FILTER)) < 0) + IPV4_DEVCONF_RO(*devconf, RP_FILTER)) < 0) goto nla_put_failure; if ((all || type == NETCONFA_MC_FORWARDING) && nla_put_s32(skb, NETCONFA_MC_FORWARDING, - IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0) + IPV4_DEVCONF_RO(*devconf, MC_FORWARDING)) < 0) goto nla_put_failure; if ((all || type == NETCONFA_BC_FORWARDING) && nla_put_s32(skb, NETCONFA_BC_FORWARDING, - IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0) + IPV4_DEVCONF_RO(*devconf, BC_FORWARDING)) < 0) goto nla_put_failure; if ((all || type == NETCONFA_PROXY_NEIGH) && nla_put_s32(skb, NETCONFA_PROXY_NEIGH, - IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0) + IPV4_DEVCONF_RO(*devconf, PROXY_ARP)) < 0) goto nla_put_failure; if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0) + IPV4_DEVCONF_RO(*devconf, + IGNORE_ROUTES_WITH_LINKDOWN)) < 0) goto nla_put_failure; out: diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index efeeca2b1328..717e97a389a8 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -120,12 +120,12 @@ */ #define IGMP_V1_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 1 || \ + (IPV4_DEVCONF_ALL_RO(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 1 || \ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 1 || \ ((in_dev)->mr_v1_seen && \ time_before(jiffies, (in_dev)->mr_v1_seen))) #define IGMP_V2_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 2 || \ + (IPV4_DEVCONF_ALL_RO(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 2 || \ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 2 || \ ((in_dev)->mr_v2_seen && \ time_before(jiffies, (in_dev)->mr_v2_seen))) diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 5f4654ebff48..914bc9c35cc7 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -395,7 +395,7 @@ static int snmp_seq_show_ipstats(struct seq_file *seq, void *v) seq_printf(seq, " %s", snmp4_ipstats_list[i].name); seq_printf(seq, "\nIp: %d %d", - IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2, + IPV4_DEVCONF_ALL_RO(net, FORWARDING) ? 1 : 2, READ_ONCE(net->ipv4.sysctl_ip_default_ttl)); BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b512288d6fcc..c8f76f56dc16 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2313,7 +2313,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (IN_DEV_BFORWARD(in_dev)) goto make_route; /* not do cache if bc_forwarding is enabled */ - if (IPV4_DEVCONF_ALL(net, BC_FORWARDING)) + if (IPV4_DEVCONF_ALL_RO(net, BC_FORWARDING)) do_cache = false; goto brd_input; } @@ -2993,7 +2993,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, #ifdef CONFIG_IP_MROUTE if (ipv4_is_multicast(dst) && !ipv4_is_local_multicast(dst) && - IPV4_DEVCONF_ALL(net, MC_FORWARDING)) { + IPV4_DEVCONF_ALL_RO(net, MC_FORWARDING)) { int err = ipmr_get_route(net, skb, fl4->saddr, fl4->daddr, r, portid); From bbcf91053bb622c4c26a9bfc998d3b0c59227f10 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Feb 2024 09:24:10 +0000 Subject: [PATCH 1630/2255] inet: do not use RTNL in inet_netconf_get_devconf() "ip -4 netconf show dev XXXX" no longer acquires RTNL. Return -ENODEV instead of -EINVAL if no netdev or idev can be found. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240227092411.2315725-3-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/devinet.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ca75d0fff1d1..f045a34e90b9 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -2205,21 +2205,20 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb, struct netlink_ext_ack *extack) { struct net *net = sock_net(in_skb->sk); - struct nlattr *tb[NETCONFA_MAX+1]; + struct nlattr *tb[NETCONFA_MAX + 1]; + const struct ipv4_devconf *devconf; + struct in_device *in_dev = NULL; + struct net_device *dev = NULL; struct sk_buff *skb; - struct ipv4_devconf *devconf; - struct in_device *in_dev; - struct net_device *dev; int ifindex; int err; err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack); if (err) - goto errout; + return err; - err = -EINVAL; if (!tb[NETCONFA_IFINDEX]) - goto errout; + return -EINVAL; ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); switch (ifindex) { @@ -2230,10 +2229,10 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb, devconf = net->ipv4.devconf_dflt; break; default: - dev = __dev_get_by_index(net, ifindex); - if (!dev) - goto errout; - in_dev = __in_dev_get_rtnl(dev); + err = -ENODEV; + dev = dev_get_by_index(net, ifindex); + if (dev) + in_dev = in_dev_get(dev); if (!in_dev) goto errout; devconf = &in_dev->cnf; @@ -2257,6 +2256,9 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb, } err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); errout: + if (in_dev) + in_dev_put(in_dev); + dev_put(dev); return err; } @@ -2826,5 +2828,6 @@ void __init devinet_init(void) rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0); rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0); rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf, - inet_netconf_dump_devconf, 0); + inet_netconf_dump_devconf, + RTNL_FLAG_DOIT_UNLOCKED); } From 167487070d644a285ed863516c80b3c35ec929d6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Feb 2024 09:24:11 +0000 Subject: [PATCH 1631/2255] inet: use xa_array iterator to implement inet_netconf_dump_devconf() 1) inet_netconf_dump_devconf() can run under RCU protection instead of RTNL. 2) properly return 0 at the end of a dump, avoiding an an extra recvmsg() system call. 3) Do not use inet_base_seq() anymore, for_each_netdev_dump() has nice properties. Restarting a GETDEVCONF dump if a device has been added/removed or if net->ipv4.dev_addr_genid has changed is moot. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240227092411.2315725-4-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/devinet.c | 101 +++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 58 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index f045a34e90b9..af741af61830 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -2267,11 +2267,13 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb, { const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); - int h, s_h; - int idx, s_idx; + struct { + unsigned long ifindex; + unsigned int all_default; + } *ctx = (void *)cb->ctx; + const struct in_device *in_dev; struct net_device *dev; - struct in_device *in_dev; - struct hlist_head *head; + int err = 0; if (cb->strict_check) { struct netlink_ext_ack *extack = cb->extack; @@ -2288,64 +2290,47 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb, } } - s_h = cb->args[0]; - s_idx = idx = cb->args[1]; - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - rcu_read_lock(); - cb->seq = inet_base_seq(net); - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) - goto cont; - - if (inet_netconf_fill_devconf(skb, dev->ifindex, - &in_dev->cnf, - NETLINK_CB(cb->skb).portid, - nlh->nlmsg_seq, - RTM_NEWNETCONF, - NLM_F_MULTI, - NETCONFA_ALL) < 0) { - rcu_read_unlock(); - goto done; - } - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - rcu_read_unlock(); - } - if (h == NETDEV_HASHENTRIES) { - if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, - net->ipv4.devconf_all, - NETLINK_CB(cb->skb).portid, - nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) + rcu_read_lock(); + for_each_netdev_dump(net, dev, ctx->ifindex) { + in_dev = __in_dev_get_rcu(dev); + if (!in_dev) + continue; + err = inet_netconf_fill_devconf(skb, dev->ifindex, + &in_dev->cnf, + NETLINK_CB(cb->skb).portid, + nlh->nlmsg_seq, + RTM_NEWNETCONF, NLM_F_MULTI, + NETCONFA_ALL); + if (err < 0) goto done; - else - h++; } - if (h == NETDEV_HASHENTRIES + 1) { - if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, - net->ipv4.devconf_dflt, - NETLINK_CB(cb->skb).portid, - nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) + if (ctx->all_default == 0) { + err = inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, + net->ipv4.devconf_all, + NETLINK_CB(cb->skb).portid, + nlh->nlmsg_seq, + RTM_NEWNETCONF, NLM_F_MULTI, + NETCONFA_ALL); + if (err < 0) goto done; - else - h++; + ctx->all_default++; + } + if (ctx->all_default == 1) { + err = inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, + net->ipv4.devconf_dflt, + NETLINK_CB(cb->skb).portid, + nlh->nlmsg_seq, + RTM_NEWNETCONF, NLM_F_MULTI, + NETCONFA_ALL); + if (err < 0) + goto done; + ctx->all_default++; } done: - cb->args[0] = h; - cb->args[1] = idx; - - return skb->len; + if (err < 0 && likely(skb->len)) + err = skb->len; + rcu_read_unlock(); + return err; } #ifdef CONFIG_SYSCTL @@ -2829,5 +2814,5 @@ void __init devinet_init(void) rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0); rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf, inet_netconf_dump_devconf, - RTNL_FLAG_DOIT_UNLOCKED); + RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED); } From 9ff74d77180a0b0b2705f62bd4dbd313e964ebf8 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Tue, 27 Feb 2024 17:36:04 +0800 Subject: [PATCH 1632/2255] netlabel: remove impossible return value in netlbl_bitmap_walk Since commit 446fda4f2682 ("[NetLabel]: CIPSOv4 engine"), *bitmap_walk function only returns -1. Nearly 18 years have passed, -2 scenes never come up, so there's no need to consider it. Signed-off-by: Zhengchao Shao Reviewed-by: Jiri Pirko Acked-by: Paul Moore Link: https://lore.kernel.org/r/20240227093604.3574241-1-shaozhengchao@huawei.com Signed-off-by: Jakub Kicinski --- net/ipv4/cipso_ipv4.c | 5 +---- net/ipv6/calipso.c | 5 +---- net/netlabel/netlabel_kapi.c | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index d048aa833293..8b17d83e5fde 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -864,11 +864,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, net_clen_bits, net_spot + 1, 1); - if (net_spot < 0) { - if (net_spot == -2) - return -EFAULT; + if (net_spot < 0) return 0; - } switch (doi_def->type) { case CIPSO_V4_MAP_PASS: diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c index 1578ed9e97d8..eb8ee1e9373a 100644 --- a/net/ipv6/calipso.c +++ b/net/ipv6/calipso.c @@ -657,11 +657,8 @@ static int calipso_map_cat_ntoh(const struct calipso_doi *doi_def, net_clen_bits, spot + 1, 1); - if (spot < 0) { - if (spot == -2) - return -EFAULT; + if (spot < 0) return 0; - } ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, spot, diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 7b844581ebee..1ba4f58e1d35 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -876,7 +876,7 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, * Description: * Starting at @offset, walk the bitmap from left to right until either the * desired bit is found or we reach the end. Return the bit offset, -1 if - * not found, or -2 if error. + * not found. */ int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len, u32 offset, u8 state) From 8a7746982ed797e1f511dece56c6675f0f845d6f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 27 Feb 2024 19:04:18 +0200 Subject: [PATCH 1633/2255] selftests: vxlan_mdb: Avoid duplicate test names Rename some test cases to avoid overlapping test names which is problematic for the kernel test robot. No changes in the test's logic. Suggested-by: Yujie Liu Signed-off-by: Ido Schimmel Link: https://lore.kernel.org/r/20240227170418.491442-1-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/test_vxlan_mdb.sh | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/net/test_vxlan_mdb.sh b/tools/testing/selftests/net/test_vxlan_mdb.sh index 84a05a9e46d8..74ff9fb2a6f0 100755 --- a/tools/testing/selftests/net/test_vxlan_mdb.sh +++ b/tools/testing/selftests/net/test_vxlan_mdb.sh @@ -1014,10 +1014,10 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 port vx0" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010" - log_test $? 254 "Flush by port" + log_test $? 254 "Flush by port - matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 port veth0" - log_test $? 255 "Flush by wrong port" + log_test $? 255 "Flush by port - non-matching" # Check that when flushing by source VNI only entries programmed with # the specified source VNI are flushed and the rest are not. @@ -1030,9 +1030,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 src_vni 10010" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010" - log_test $? 254 "Flush by specified source VNI" + log_test $? 254 "Flush by source VNI - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10011" - log_test $? 0 "Flush by unspecified source VNI" + log_test $? 0 "Flush by source VNI - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" @@ -1058,9 +1058,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 proto bgp" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep \"proto bgp\"" - log_test $? 1 "Flush by specified routing protocol" + log_test $? 1 "Flush by routing protocol - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep \"proto zebra\"" - log_test $? 0 "Flush by unspecified routing protocol" + log_test $? 0 "Flush by routing protocol - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" @@ -1075,9 +1075,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 dst 198.51.100.2" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 198.51.100.2" - log_test $? 1 "Flush by specified destination IP - IPv4" + log_test $? 1 "Flush by IPv4 destination IP - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 198.51.100.1" - log_test $? 0 "Flush by unspecified destination IP - IPv4" + log_test $? 0 "Flush by IPv4 destination IP - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" @@ -1089,9 +1089,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 dst 2001:db8:1000::2" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 2001:db8:1000::2" - log_test $? 1 "Flush by specified destination IP - IPv6" + log_test $? 1 "Flush by IPv6 destination IP - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 2001:db8:1000::1" - log_test $? 0 "Flush by unspecified destination IP - IPv6" + log_test $? 0 "Flush by IPv6 destination IP - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" @@ -1104,9 +1104,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 dst_port 11111" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep \"dst_port 11111\"" - log_test $? 1 "Flush by specified UDP destination port" + log_test $? 1 "Flush by UDP destination port - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep \"dst_port 22222\"" - log_test $? 0 "Flush by unspecified UDP destination port" + log_test $? 0 "Flush by UDP destination port - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" @@ -1121,9 +1121,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 dst_port 4789" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 198.51.100.1" - log_test $? 1 "Flush by device's UDP destination port" + log_test $? 1 "Flush by device's UDP destination port - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 198.51.100.2" - log_test $? 0 "Flush by unspecified UDP destination port" + log_test $? 0 "Flush by device's UDP destination port - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" @@ -1136,9 +1136,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 vni 20010" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep \" vni 20010\"" - log_test $? 1 "Flush by specified destination VNI" + log_test $? 1 "Flush by destination VNI - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep \" vni 20011\"" - log_test $? 0 "Flush by unspecified destination VNI" + log_test $? 0 "Flush by destination VNI - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" @@ -1153,9 +1153,9 @@ flush() run_cmd "bridge -n $ns1_v4 mdb flush dev vx0 vni 10010" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 198.51.100.1" - log_test $? 1 "Flush by destination VNI equal to source VNI" + log_test $? 1 "Flush by destination VNI equal to source VNI - matching" run_cmd "bridge -n $ns1_v4 -d -s mdb get dev vx0 grp 239.1.1.1 src_vni 10010 | grep 198.51.100.2" - log_test $? 0 "Flush by unspecified destination VNI" + log_test $? 0 "Flush by destination VNI equal to source VNI - non-matching" run_cmd "bridge -n $ns1_v4 mdb flush dev vx0" From d35150c79ffcd730e3c9f20cf128288606e3bf3b Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 27 Feb 2024 10:23:36 -0800 Subject: [PATCH 1634/2255] net: bridge: Do not allocate stats in the driver With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the bridge driver and leverage the network core allocation. Signed-off-by: Breno Leitao Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20240227182338.2739884-1-leitao@debian.org Signed-off-by: Jakub Kicinski --- net/bridge/br_device.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 874cec75a818..4f636f7b0555 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -113,26 +113,18 @@ static int br_dev_init(struct net_device *dev) struct net_bridge *br = netdev_priv(dev); int err; - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - err = br_fdb_hash_init(br); - if (err) { - free_percpu(dev->tstats); + if (err) return err; - } err = br_mdb_hash_init(br); if (err) { - free_percpu(dev->tstats); br_fdb_hash_fini(br); return err; } err = br_vlan_init(br); if (err) { - free_percpu(dev->tstats); br_mdb_hash_fini(br); br_fdb_hash_fini(br); return err; @@ -140,7 +132,6 @@ static int br_dev_init(struct net_device *dev) err = br_multicast_init_stats(br); if (err) { - free_percpu(dev->tstats); br_vlan_flush(br); br_mdb_hash_fini(br); br_fdb_hash_fini(br); @@ -159,7 +150,6 @@ static void br_dev_uninit(struct net_device *dev) br_vlan_flush(br); br_mdb_hash_fini(br); br_fdb_hash_fini(br); - free_percpu(dev->tstats); } static int br_dev_open(struct net_device *dev) @@ -496,6 +486,7 @@ void br_dev_setup(struct net_device *dev) dev->hw_features = COMMON_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; dev->vlan_features = COMMON_FEATURES; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; br->dev = dev; spin_lock_init(&br->lock); From 82a48affb36f1fee36fe415051a8947d42861108 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 27 Feb 2024 10:23:37 -0800 Subject: [PATCH 1635/2255] net: bridge: Exit if multicast_init_stats fails If br_multicast_init_stats() fails, there is no need to set lockdep classes. Just return from the error path. Signed-off-by: Breno Leitao Acked-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20240227182338.2739884-2-leitao@debian.org Signed-off-by: Jakub Kicinski --- net/bridge/br_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 4f636f7b0555..c366ccc8b3db 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -135,10 +135,11 @@ static int br_dev_init(struct net_device *dev) br_vlan_flush(br); br_mdb_hash_fini(br); br_fdb_hash_fini(br); + return err; } netdev_lockdep_set_classes(dev); - return err; + return 0; } static void br_dev_uninit(struct net_device *dev) From 99123622050f10ca9148a0fffba2de0afd6cdfff Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Feb 2024 19:27:21 +0000 Subject: [PATCH 1636/2255] tcp: remove some holes in struct tcp_sock By moving some fields around, this patch shrinks holes size from 56 to 32, saving 24 bytes on 64bit arches. After the patch pahole gives the following for 'struct tcp_sock': /* size: 2304, cachelines: 36, members: 162 */ /* sum members: 2234, holes: 6, sum holes: 32 */ /* sum bitfield members: 34 bits, bit holes: 5, sum bit holes: 14 bits */ /* padding: 32 */ /* paddings: 3, sum paddings: 10 */ /* forced alignments: 1, forced holes: 1, sum forced holes: 12 */ Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240227192721.3558982-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/linux/tcp.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index a1c47a6d69b0..988a30ef6bfe 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -264,10 +264,10 @@ struct tcp_sock { u32 pushed_seq; /* Last pushed seq, required to talk to windows */ u32 lsndtime; u32 mdev_us; /* medium deviation */ + u32 rtt_seq; /* sequence number to update rttvar */ u64 tcp_wstamp_ns; /* departure time for next sent data packet */ u64 tcp_clock_cache; /* cache last tcp_clock_ns() (see tcp_mstamp_refresh()) */ u64 tcp_mstamp; /* most recent packet received/sent */ - u32 rtt_seq; /* sequence number to update rttvar */ struct list_head tsorted_sent_queue; /* time-sorted sent but un-SACKed skbs */ struct sk_buff *highest_sack; /* skb just after the highest * skb with SACKed bit set @@ -350,7 +350,6 @@ struct tcp_sock { u32 dsack_dups; /* RFC4898 tcpEStatsStackDSACKDups * total number of DSACK blocks received */ - u32 last_oow_ack_time; /* timestamp of last out-of-window ACK */ u32 compressed_ack_rcv_nxt; struct list_head tsq_node; /* anchor in tsq_tasklet.head list */ @@ -384,12 +383,12 @@ struct tcp_sock { syn_fastopen_ch:1, /* Active TFO re-enabling probe */ syn_data_acked:1;/* data in SYN is acked by SYN-ACK */ + u8 keepalive_probes; /* num of allowed keep alive probes */ u32 tcp_tx_delay; /* delay (in usec) added to TX packets */ /* RTT measurement */ u32 mdev_max_us; /* maximal mdev for the last rtt period */ - u8 keepalive_probes; /* num of allowed keep alive probes */ u32 reord_seen; /* number of data packet reordering events */ /* @@ -402,6 +401,7 @@ struct tcp_sock { u32 prior_cwnd; /* cwnd right before starting loss recovery */ u32 prr_delivered; /* Number of newly delivered packets to * receiver in Recovery. */ + u32 last_oow_ack_time; /* timestamp of last out-of-window ACK */ struct hrtimer pacing_timer; struct hrtimer compressed_ack_timer; @@ -477,8 +477,8 @@ struct tcp_sock { bool is_mptcp; #endif #if IS_ENABLED(CONFIG_SMC) - bool (*smc_hs_congested)(const struct sock *sk); bool syn_smc; /* SYN includes SMC */ + bool (*smc_hs_congested)(const struct sock *sk); #endif #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO) From 1200097fa8f0d8e8ddfe5c554d8fa2bc03b2df92 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Feb 2024 21:01:04 +0000 Subject: [PATCH 1637/2255] net: call skb_defer_free_flush() from __napi_busy_loop() skb_defer_free_flush() is currently called from net_rx_action() and napi_threaded_poll(). We should also call it from __napi_busy_loop() otherwise there is the risk the percpu queue can grow until an IPI is forced from skb_attempt_defer_free() adding a latency spike. Signed-off-by: Eric Dumazet Cc: Samiullah Khawaja Acked-by: Stanislav Fomichev Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240227210105.3815474-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/core/dev.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 275fd5259a4a..053fac78305c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6173,6 +6173,27 @@ struct napi_struct *napi_by_id(unsigned int napi_id) return NULL; } +static void skb_defer_free_flush(struct softnet_data *sd) +{ + struct sk_buff *skb, *next; + + /* Paired with WRITE_ONCE() in skb_attempt_defer_free() */ + if (!READ_ONCE(sd->defer_list)) + return; + + spin_lock(&sd->defer_lock); + skb = sd->defer_list; + sd->defer_list = NULL; + sd->defer_count = 0; + spin_unlock(&sd->defer_lock); + + while (skb != NULL) { + next = skb->next; + napi_consume_skb(skb, 1); + skb = next; + } +} + #if defined(CONFIG_NET_RX_BUSY_POLL) static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule) @@ -6297,6 +6318,7 @@ count: if (work > 0) __NET_ADD_STATS(dev_net(napi->dev), LINUX_MIB_BUSYPOLLRXPACKETS, work); + skb_defer_free_flush(this_cpu_ptr(&softnet_data)); local_bh_enable(); if (!loop_end || loop_end(loop_end_arg, start_time)) @@ -6726,27 +6748,6 @@ static int napi_thread_wait(struct napi_struct *napi) return -1; } -static void skb_defer_free_flush(struct softnet_data *sd) -{ - struct sk_buff *skb, *next; - - /* Paired with WRITE_ONCE() in skb_attempt_defer_free() */ - if (!READ_ONCE(sd->defer_list)) - return; - - spin_lock(&sd->defer_lock); - skb = sd->defer_list; - sd->defer_list = NULL; - sd->defer_count = 0; - spin_unlock(&sd->defer_lock); - - while (skb != NULL) { - next = skb->next; - napi_consume_skb(skb, 1); - skb = next; - } -} - static int napi_threaded_poll(void *data) { struct napi_struct *napi = data; From 67ea41d19d2aad2da2bcaeb7992c4fff9dc28a8f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Feb 2024 22:22:59 +0000 Subject: [PATCH 1638/2255] inet6: expand rcu_read_lock() scope in inet6_dump_addr() I missed that inet6_dump_addr() is calling in6_dump_addrs() from two points. First one under RTNL protection, and second one under rcu_read_lock(). Since we want to remove RTNL use from inet6_dump_addr() very soon, no longer assume in6_dump_addrs() is protected by RTNL (even if this is still the case). Use rcu_read_lock() earlier to fix this lockdep splat: WARNING: suspicious RCU usage 6.8.0-rc5-syzkaller-01618-gf8cbf6bde4c8 #0 Not tainted net/ipv6/addrconf.c:5317 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 3 locks held by syz-executor.2/8834: #0: ffff88802f554678 (nlk_cb_mutex-ROUTE){+.+.}-{3:3}, at: __netlink_dump_start+0x119/0x780 net/netlink/af_netlink.c:2338 #1: ffffffff8f377a88 (rtnl_mutex){+.+.}-{3:3}, at: netlink_dump+0x676/0xda0 net/netlink/af_netlink.c:2265 #2: ffff88807e5f0580 (&ndev->lock){++--}-{2:2}, at: in6_dump_addrs+0xb8/0x1de0 net/ipv6/addrconf.c:5279 stack backtrace: CPU: 1 PID: 8834 Comm: syz-executor.2 Not tainted 6.8.0-rc5-syzkaller-01618-gf8cbf6bde4c8 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/25/2024 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x1e7/0x2e0 lib/dump_stack.c:106 lockdep_rcu_suspicious+0x220/0x340 kernel/locking/lockdep.c:6712 in6_dump_addrs+0x1b47/0x1de0 net/ipv6/addrconf.c:5317 inet6_dump_addr+0x1597/0x1690 net/ipv6/addrconf.c:5428 netlink_dump+0x6a6/0xda0 net/netlink/af_netlink.c:2266 __netlink_dump_start+0x59d/0x780 net/netlink/af_netlink.c:2374 netlink_dump_start include/linux/netlink.h:340 [inline] rtnetlink_rcv_msg+0xcf7/0x10d0 net/core/rtnetlink.c:6555 netlink_rcv_skb+0x1e3/0x430 net/netlink/af_netlink.c:2547 netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline] netlink_unicast+0x7ea/0x980 net/netlink/af_netlink.c:1361 netlink_sendmsg+0x8e0/0xcb0 net/netlink/af_netlink.c:1902 sock_sendmsg_nosec net/socket.c:730 [inline] __sock_sendmsg+0x221/0x270 net/socket.c:745 ____sys_sendmsg+0x525/0x7d0 net/socket.c:2584 ___sys_sendmsg net/socket.c:2638 [inline] __sys_sendmsg+0x2b0/0x3a0 net/socket.c:2667 Fixes: c3718936ec47 ("ipv6: anycast: complete RCU handling of struct ifacaddr6") Reported-by: syzbot Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240227222259.4081489-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/addrconf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e27069ad938c..953a95898e4a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5300,9 +5300,9 @@ next: fillargs->event = RTM_GETMULTICAST; /* multicast address */ - for (ifmca = rtnl_dereference(idev->mc_list); + for (ifmca = rcu_dereference(idev->mc_list); ifmca; - ifmca = rtnl_dereference(ifmca->next), ip_idx++) { + ifmca = rcu_dereference(ifmca->next), ip_idx++) { if (ip_idx < s_ip_idx) continue; err = inet6_fill_ifmcaddr(skb, ifmca, fillargs); @@ -5410,6 +5410,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, s_idx = idx = cb->args[1]; s_ip_idx = cb->args[2]; + rcu_read_lock(); if (cb->strict_check) { err = inet6_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, skb->sk, cb); @@ -5434,7 +5435,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, } } - rcu_read_lock(); cb->seq = inet6_base_seq(tgt_net); for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; @@ -5456,10 +5456,10 @@ cont: } } done: - rcu_read_unlock(); cb->args[0] = h; cb->args[1] = idx; put_tgt_net: + rcu_read_unlock(); if (fillargs.netnsid >= 0) put_net(tgt_net); From 5c5b0c444be3e851046f1c1074459b8d15d2a0f9 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Tue, 27 Feb 2024 18:54:21 +0100 Subject: [PATCH 1639/2255] net: dsa: mv88e6xxx: rename mv88e6xxx_g2_scratch_gpio_set_smi The name mv88e6xxx_g2_scratch_gpio_set_smi is a bit ambiguous as it appears to only be applicable to the 6390 family, so lets rename it to mv88e6390_g2_scratch_gpio_set_smi to make it more obvious. Signed-off-by: Robert Marko Reviewed-by: Andrew Lunn Signed-off-by: Paolo Abeni --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- drivers/net/dsa/mv88e6xxx/global2.h | 2 +- drivers/net/dsa/mv88e6xxx/global2_scratch.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 9caecb4dfbfa..f9378fca8305 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3712,7 +3712,7 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, if (external) { mv88e6xxx_reg_lock(chip); - err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); + err = mv88e6390_g2_scratch_gpio_set_smi(chip, true); mv88e6xxx_reg_unlock(chip); if (err) diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index d9434f7cae53..20fefa08f54e 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -378,7 +378,7 @@ extern const struct mv88e6xxx_avb_ops mv88e6390_avb_ops; extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops; -int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, +int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, bool external); int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port); int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin); diff --git a/drivers/net/dsa/mv88e6xxx/global2_scratch.c b/drivers/net/dsa/mv88e6xxx/global2_scratch.c index a9d6e40321a2..0e15efd898f2 100644 --- a/drivers/net/dsa/mv88e6xxx/global2_scratch.c +++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c @@ -240,7 +240,7 @@ const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = { }; /** - * mv88e6xxx_g2_scratch_gpio_set_smi - set gpio muxing for external smi + * mv88e6390_g2_scratch_gpio_set_smi - set gpio muxing for external smi * @chip: chip private data * @external: set mux for external smi, or free for gpio usage * @@ -248,7 +248,7 @@ const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = { * an external SMI interface, or they may be made free for other * GPIO uses. */ -int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, +int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, bool external) { int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG; From e3ab3267a0bbedc37725bb845a332ec33b247263 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Tue, 27 Feb 2024 18:54:22 +0100 Subject: [PATCH 1640/2255] net: dsa: mv88e6xxx: add Amethyst specific SMI GPIO function The existing mv88e6390_g2_scratch_gpio_set_smi() cannot be used on the 88E6393X as it requires certain P0_MODE, it also checks the CPU mode as it impacts the bit setting value. This is all irrelevant for Amethyst (MV88E6191X/6193X/6393X) as only the default value of the SMI_PHY Config bit is set to CPU_MGD bootstrap pin value but it can be changed without restrictions so that GPIO pins 9 and 10 are used as SMI pins. So, introduce Amethyst specific function and call that if the Amethyst family wants to setup the external PHY. Reviewed-by: Andrew Lunn Signed-off-by: Robert Marko Signed-off-by: Paolo Abeni --- drivers/net/dsa/mv88e6xxx/chip.c | 5 +++- drivers/net/dsa/mv88e6xxx/global2.h | 2 ++ drivers/net/dsa/mv88e6xxx/global2_scratch.c | 31 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index f9378fca8305..9ed1821184ec 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3712,7 +3712,10 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, if (external) { mv88e6xxx_reg_lock(chip); - err = mv88e6390_g2_scratch_gpio_set_smi(chip, true); + if (chip->info->family == MV88E6XXX_FAMILY_6393) + err = mv88e6393x_g2_scratch_gpio_set_smi(chip, true); + else + err = mv88e6390_g2_scratch_gpio_set_smi(chip, true); mv88e6xxx_reg_unlock(chip); if (err) diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 20fefa08f54e..82f9b410de0b 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -380,6 +380,8 @@ extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops; int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, bool external); +int mv88e6393x_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, + bool external); int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port); int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin); int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats); diff --git a/drivers/net/dsa/mv88e6xxx/global2_scratch.c b/drivers/net/dsa/mv88e6xxx/global2_scratch.c index 0e15efd898f2..61ab6cc4fbfc 100644 --- a/drivers/net/dsa/mv88e6xxx/global2_scratch.c +++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c @@ -290,6 +290,37 @@ int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); } +/** + * mv88e6393x_g2_scratch_gpio_set_smi - set gpio muxing for external smi + * @chip: chip private data + * @external: set mux for external smi, or free for gpio usage + * + * MV88E6191X/6193X/6393X GPIO pins 9 and 10 can be configured as an + * external SMI interface or as regular GPIO-s. + * + * They however have a different register layout then the existing + * function. + */ + +int mv88e6393x_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, + bool external) +{ + int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG; + int err; + u8 val; + + err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val); + if (err) + return err; + + if (external) + val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; + else + val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; + + return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); +} + /** * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes * @chip: chip private data From 8b2b1e62cdb9ce36886e77c90a9594e41f3a2112 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Wed, 28 Feb 2024 15:25:05 +0800 Subject: [PATCH 1641/2255] ipv4: raw: remove useless input parameter in do_raw_set/getsockopt The input parameter 'level' in do_raw_set/getsockopt() is not used. Therefore, remove it. Signed-off-by: Zhengchao Shao Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240228072505.640550-1-shaozhengchao@huawei.com Signed-off-by: Paolo Abeni --- net/ipv4/raw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index aea89326c697..7d2bdfd7e7d7 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -815,7 +815,7 @@ static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *o out: return ret; } -static int do_raw_setsockopt(struct sock *sk, int level, int optname, +static int do_raw_setsockopt(struct sock *sk, int optname, sockptr_t optval, unsigned int optlen) { if (optname == ICMP_FILTER) { @@ -832,11 +832,11 @@ static int raw_setsockopt(struct sock *sk, int level, int optname, { if (level != SOL_RAW) return ip_setsockopt(sk, level, optname, optval, optlen); - return do_raw_setsockopt(sk, level, optname, optval, optlen); + return do_raw_setsockopt(sk, optname, optval, optlen); } -static int do_raw_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +static int do_raw_getsockopt(struct sock *sk, int optname, + char __user *optval, int __user *optlen) { if (optname == ICMP_FILTER) { if (inet_sk(sk)->inet_num != IPPROTO_ICMP) @@ -852,7 +852,7 @@ static int raw_getsockopt(struct sock *sk, int level, int optname, { if (level != SOL_RAW) return ip_getsockopt(sk, level, optname, optval, optlen); - return do_raw_getsockopt(sk, level, optname, optval, optlen); + return do_raw_getsockopt(sk, optname, optval, optlen); } static int raw_ioctl(struct sock *sk, int cmd, int *karg) From 39de85775cfbd1da2c4f9523110cddb1eb4adcb7 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Wed, 28 Feb 2024 19:24:47 +0800 Subject: [PATCH 1642/2255] net: stmmac: fix typo in comment This is just a trivial fix for a typo in a comment, no functional changes. Reviewed-by: Serge Semin Signed-off-by: Yanteng Si Link: https://lore.kernel.org/r/20240228112447.1490926-1-siyanteng@loongson.cn Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h index 358e7dcb6a9a..17d9120db5fe 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h @@ -92,7 +92,7 @@ #define DMA_TBS_FTOV BIT(0) #define DMA_TBS_DEF_FTOS (DMA_TBS_FTOS | DMA_TBS_FTOV) -/* Following DMA defines are chanels oriented */ +/* Following DMA defines are channel-oriented */ #define DMA_CHAN_BASE_ADDR 0x00001100 #define DMA_CHAN_BASE_OFFSET 0x80 From 3e2f544dd8a33b2f650b32920b9bef103da2a7cd Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 28 Feb 2024 03:31:21 -0800 Subject: [PATCH 1643/2255] net: get stats64 if device if driver is configured If the network driver is relying in the net core to do stats allocation, then we want to dev_get_tstats64() instead of netdev_stats_to_stats64(), since there are per-cpu stats that needs to be taken in consideration. This will also simplify the drivers in regard to statistics. Once the driver sets NETDEV_PCPU_STAT_TSTATS, it doesn't not need to allocate the stacks, neither it needs to set `.ndo_get_stats64 = dev_get_tstats64` for the generic stats collection function anymore. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- net/core/dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 053fac78305c..34b39c03e97d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10702,6 +10702,8 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, ops->ndo_get_stats64(dev, storage); } else if (ops->ndo_get_stats) { netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev)); + } else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) { + dev_get_tstats64(dev, storage); } else { netdev_stats_to_stats64(storage, &dev->stats); } From fa0cd90213695b928410484264b38982757a5c28 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 28 Feb 2024 03:31:22 -0800 Subject: [PATCH 1644/2255] net: sit: Do not set .ndo_get_stats64 If the driver is using the network core allocation mechanism, by setting NETDEV_PCPU_STAT_TSTATS, as this driver is, then, it doesn't need to set the dev_get_tstats64() generic .ndo_get_stats64 function pointer. Since the network core calls it automatically, and .ndo_get_stats64 should only be set if the driver needs special treatment. This simplifies the driver, since all the generic statistics is now handled by core. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni --- net/ipv6/sit.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 5ad01480854d..655c9b1a19b8 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1398,7 +1398,6 @@ static const struct net_device_ops ipip6_netdev_ops = { .ndo_uninit = ipip6_tunnel_uninit, .ndo_start_xmit = sit_tunnel_xmit, .ndo_siocdevprivate = ipip6_tunnel_siocdevprivate, - .ndo_get_stats64 = dev_get_tstats64, .ndo_get_iflink = ip_tunnel_get_iflink, .ndo_tunnel_ctl = ipip6_tunnel_ctl, }; From ba132d841d5637655273c28d30751c8d18ac189b Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 13:51:30 +0000 Subject: [PATCH 1645/2255] rxrpc: Record the Tx serial in the rxrpc_txbuf and retransmit trace Each Rx protocol packet contains a per-connection monotonically increasing serial number used to correlate outgoing messages with their replies - something that can be used for RTT calculation. Note this value in the rxrpc_txbuf struct in addition to the wire header and then log it in the rxrpc_retransmit trace for reference. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- include/trace/events/rxrpc.h | 10 +++++++--- net/rxrpc/ar-internal.h | 1 + net/rxrpc/call_event.c | 6 +++--- net/rxrpc/output.c | 36 +++++++++++++++++------------------- net/rxrpc/txbuf.c | 1 + 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 87b8de9b6c1c..9add56980485 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -1506,25 +1506,29 @@ TRACE_EVENT(rxrpc_drop_ack, ); TRACE_EVENT(rxrpc_retransmit, - TP_PROTO(struct rxrpc_call *call, rxrpc_seq_t seq, s64 expiry), + TP_PROTO(struct rxrpc_call *call, rxrpc_seq_t seq, + rxrpc_serial_t serial, s64 expiry), - TP_ARGS(call, seq, expiry), + TP_ARGS(call, seq, serial, expiry), TP_STRUCT__entry( __field(unsigned int, call) __field(rxrpc_seq_t, seq) + __field(rxrpc_serial_t, serial) __field(s64, expiry) ), TP_fast_assign( __entry->call = call->debug_id; __entry->seq = seq; + __entry->serial = serial; __entry->expiry = expiry; ), - TP_printk("c=%08x q=%x xp=%lld", + TP_printk("c=%08x q=%x r=%x xp=%lld", __entry->call, __entry->seq, + __entry->serial, __entry->expiry) ); diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 7818aae1be8e..f76125755810 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -794,6 +794,7 @@ struct rxrpc_txbuf { ktime_t last_sent; /* Time at which last transmitted */ refcount_t ref; rxrpc_seq_t seq; /* Sequence number of this packet */ + rxrpc_serial_t serial; /* Last serial number transmitted with */ unsigned int call_debug_id; unsigned int debug_id; unsigned int len; /* Amount of data in buffer */ diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 0f78544d043b..a4c309976719 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -160,7 +160,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) goto no_further_resend; found_txb: - if (after(ntohl(txb->wire.serial), call->acks_highest_serial)) + if (after(txb->serial, call->acks_highest_serial)) continue; /* Ack point not yet reached */ rxrpc_see_txbuf(txb, rxrpc_txbuf_see_unacked); @@ -170,7 +170,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) set_bit(RXRPC_TXBUF_RESENT, &txb->flags); } - trace_rxrpc_retransmit(call, txb->seq, + trace_rxrpc_retransmit(call, txb->seq, txb->serial, ktime_to_ns(ktime_sub(txb->last_sent, max_age))); @@ -197,7 +197,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) break; /* Not transmitted yet */ if (ack && ack->reason == RXRPC_ACK_PING_RESPONSE && - before(ntohl(txb->wire.serial), ntohl(ack->serial))) + before(txb->serial, ntohl(ack->serial))) goto do_resend; /* Wasn't accounted for by a more recent ping. */ if (ktime_after(txb->last_sent, max_age)) { diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 4a292f860ae3..bad96a983e12 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -189,7 +189,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) struct rxrpc_connection *conn; struct msghdr msg; struct kvec iov[1]; - rxrpc_serial_t serial; size_t len, n; int ret, rtt_slot = -1; u16 rwind; @@ -216,15 +215,15 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) iov[0].iov_len = sizeof(txb->wire) + sizeof(txb->ack) + n; len = iov[0].iov_len; - serial = rxrpc_get_next_serial(conn); - txb->wire.serial = htonl(serial); - trace_rxrpc_tx_ack(call->debug_id, serial, + txb->serial = rxrpc_get_next_serial(conn); + txb->wire.serial = htonl(txb->serial); + trace_rxrpc_tx_ack(call->debug_id, txb->serial, ntohl(txb->ack.firstPacket), ntohl(txb->ack.serial), txb->ack.reason, txb->ack.nAcks, rwind); if (txb->ack.reason == RXRPC_ACK_PING) - rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_ping); + rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_ping); rxrpc_inc_stat(call->rxnet, stat_tx_ack_send); @@ -235,7 +234,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) ret = do_udp_sendmsg(conn->local->socket, &msg, len); call->peer->last_tx_at = ktime_get_seconds(); if (ret < 0) { - trace_rxrpc_tx_fail(call->debug_id, serial, ret, + trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, rxrpc_tx_point_call_ack); } else { trace_rxrpc_tx_packet(call->debug_id, &txb->wire, @@ -247,7 +246,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) if (!__rxrpc_call_is_complete(call)) { if (ret < 0) - rxrpc_cancel_rtt_probe(call, serial, rtt_slot); + rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); rxrpc_set_keepalive(call); } @@ -327,15 +326,14 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) struct rxrpc_connection *conn = call->conn; struct msghdr msg; struct kvec iov[1]; - rxrpc_serial_t serial; size_t len; int ret, rtt_slot = -1; _enter("%x,{%d}", txb->seq, txb->len); - /* Each transmission of a Tx packet needs a new serial number */ - serial = rxrpc_get_next_serial(conn); - txb->wire.serial = htonl(serial); + /* Each transmission of a Tx packet+ needs a new serial number */ + txb->serial = rxrpc_get_next_serial(conn); + txb->wire.serial = htonl(txb->serial); if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) && txb->seq == 1) @@ -388,7 +386,7 @@ dont_set_request_ack: static int lose; if ((lose++ & 7) == 7) { ret = 0; - trace_rxrpc_tx_data(call, txb->seq, serial, + trace_rxrpc_tx_data(call, txb->seq, txb->serial, txb->wire.flags, test_bit(RXRPC_TXBUF_RESENT, &txb->flags), true); @@ -396,7 +394,7 @@ dont_set_request_ack: } } - trace_rxrpc_tx_data(call, txb->seq, serial, txb->wire.flags, + trace_rxrpc_tx_data(call, txb->seq, txb->serial, txb->wire.flags, test_bit(RXRPC_TXBUF_RESENT, &txb->flags), false); /* Track what we've attempted to transmit at least once so that the @@ -415,7 +413,7 @@ dont_set_request_ack: txb->last_sent = ktime_get_real(); if (txb->wire.flags & RXRPC_REQUEST_ACK) - rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data); + rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); /* send the packet by UDP * - returns -EMSGSIZE if UDP would have to fragment the packet @@ -429,8 +427,8 @@ dont_set_request_ack: if (ret < 0) { rxrpc_inc_stat(call->rxnet, stat_tx_data_send_fail); - rxrpc_cancel_rtt_probe(call, serial, rtt_slot); - trace_rxrpc_tx_fail(call->debug_id, serial, ret, + rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); + trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, rxrpc_tx_point_call_data_nofrag); } else { trace_rxrpc_tx_packet(call->debug_id, &txb->wire, @@ -489,7 +487,7 @@ send_fragmentable: txb->last_sent = ktime_get_real(); if (txb->wire.flags & RXRPC_REQUEST_ACK) - rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data); + rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); switch (conn->local->srx.transport.family) { case AF_INET6: @@ -508,8 +506,8 @@ send_fragmentable: if (ret < 0) { rxrpc_inc_stat(call->rxnet, stat_tx_data_send_fail); - rxrpc_cancel_rtt_probe(call, serial, rtt_slot); - trace_rxrpc_tx_fail(call->debug_id, serial, ret, + rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); + trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, rxrpc_tx_point_call_data_frag); } else { trace_rxrpc_tx_packet(call->debug_id, &txb->wire, diff --git a/net/rxrpc/txbuf.c b/net/rxrpc/txbuf.c index d43be8512386..f2903c81cf5b 100644 --- a/net/rxrpc/txbuf.c +++ b/net/rxrpc/txbuf.c @@ -34,6 +34,7 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, txb->flags = 0; txb->ack_why = 0; txb->seq = call->tx_prepared + 1; + txb->serial = 0; txb->wire.epoch = htonl(call->conn->proto.epoch); txb->wire.cid = htonl(call->cid); txb->wire.callNumber = htonl(call->call_id); From 12bdff73a147aebcea8efae2b395ef0c27448909 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 15:01:10 +0000 Subject: [PATCH 1646/2255] rxrpc: Convert rxrpc_txbuf::flags into a mask and don't use atomics Convert the transmission buffer flags into a mask and use | and & rather than bitops functions (atomic ops are not required as only the I/O thread can manipulate them once submitted for transmission). The bottom byte can then correspond directly to the Rx protocol header flags. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- include/trace/events/rxrpc.h | 12 +++++------- net/rxrpc/ar-internal.h | 8 ++++---- net/rxrpc/call_event.c | 8 ++++---- net/rxrpc/input.c | 2 +- net/rxrpc/output.c | 27 +++++++++++++-------------- net/rxrpc/sendmsg.c | 10 ++++------ net/rxrpc/txbuf.c | 4 ++-- 7 files changed, 33 insertions(+), 38 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 9add56980485..33888f688325 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -1084,9 +1084,9 @@ TRACE_EVENT(rxrpc_tx_packet, TRACE_EVENT(rxrpc_tx_data, TP_PROTO(struct rxrpc_call *call, rxrpc_seq_t seq, - rxrpc_serial_t serial, u8 flags, bool retrans, bool lose), + rxrpc_serial_t serial, unsigned int flags, bool lose), - TP_ARGS(call, seq, serial, flags, retrans, lose), + TP_ARGS(call, seq, serial, flags, lose), TP_STRUCT__entry( __field(unsigned int, call) @@ -1094,8 +1094,7 @@ TRACE_EVENT(rxrpc_tx_data, __field(rxrpc_serial_t, serial) __field(u32, cid) __field(u32, call_id) - __field(u8, flags) - __field(bool, retrans) + __field(u16, flags) __field(bool, lose) ), @@ -1106,7 +1105,6 @@ TRACE_EVENT(rxrpc_tx_data, __entry->seq = seq; __entry->serial = serial; __entry->flags = flags; - __entry->retrans = retrans; __entry->lose = lose; ), @@ -1116,8 +1114,8 @@ TRACE_EVENT(rxrpc_tx_data, __entry->call_id, __entry->serial, __entry->seq, - __entry->flags, - __entry->retrans ? " *RETRANS*" : "", + __entry->flags & RXRPC_TXBUF_WIRE_FLAGS, + __entry->flags & RXRPC_TXBUF_RESENT ? " *RETRANS*" : "", __entry->lose ? " *LOSE*" : "") ); diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index f76125755810..54d1dc97cb0f 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -800,9 +800,9 @@ struct rxrpc_txbuf { unsigned int len; /* Amount of data in buffer */ unsigned int space; /* Remaining data space */ unsigned int offset; /* Offset of fill point */ - unsigned long flags; -#define RXRPC_TXBUF_LAST 0 /* Set if last packet in Tx phase */ -#define RXRPC_TXBUF_RESENT 1 /* Set if has been resent */ + unsigned int flags; +#define RXRPC_TXBUF_WIRE_FLAGS 0xff /* The wire protocol flags */ +#define RXRPC_TXBUF_RESENT 0x100 /* Set if has been resent */ u8 /*enum rxrpc_propose_ack_trace*/ ack_why; /* If ack, why */ struct { /* The packet for encrypting and DMA'ing. We align it such @@ -822,7 +822,7 @@ struct rxrpc_txbuf { static inline bool rxrpc_sending_to_server(const struct rxrpc_txbuf *txb) { - return txb->wire.flags & RXRPC_CLIENT_INITIATED; + return txb->flags & RXRPC_CLIENT_INITIATED; } static inline bool rxrpc_sending_to_client(const struct rxrpc_txbuf *txb) diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index a4c309976719..77eacbfc5d45 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -84,7 +84,7 @@ void rxrpc_send_ACK(struct rxrpc_call *call, u8 ack_reason, txb->ack_why = why; txb->wire.seq = 0; txb->wire.type = RXRPC_PACKET_TYPE_ACK; - txb->wire.flags |= RXRPC_SLOW_START_OK; + txb->flags |= RXRPC_SLOW_START_OK; txb->ack.bufferSpace = 0; txb->ack.maxSkew = 0; txb->ack.firstPacket = 0; @@ -167,7 +167,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) if (list_empty(&txb->tx_link)) { list_add_tail(&txb->tx_link, &retrans_queue); - set_bit(RXRPC_TXBUF_RESENT, &txb->flags); + txb->flags |= RXRPC_TXBUF_RESENT; } trace_rxrpc_retransmit(call, txb->seq, txb->serial, @@ -210,7 +210,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) unacked = true; if (list_empty(&txb->tx_link)) { list_add_tail(&txb->tx_link, &retrans_queue); - set_bit(RXRPC_TXBUF_RESENT, &txb->flags); + txb->flags |= RXRPC_TXBUF_RESENT; rxrpc_inc_stat(call->rxnet, stat_tx_data_retrans); } } @@ -320,7 +320,7 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call) call->tx_top = txb->seq; list_add_tail(&txb->call_link, &call->tx_buffer); - if (txb->wire.flags & RXRPC_LAST_PACKET) + if (txb->flags & RXRPC_LAST_PACKET) rxrpc_close_tx_phase(call); rxrpc_transmit_one(call, txb); diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index 9691de00ade7..c435b50c33f4 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -212,7 +212,7 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to, list_for_each_entry_rcu(txb, &call->tx_buffer, call_link, false) { if (before_eq(txb->seq, call->acks_hard_ack)) continue; - if (test_bit(RXRPC_TXBUF_LAST, &txb->flags)) { + if (txb->flags & RXRPC_LAST_PACKET) { set_bit(RXRPC_CALL_TX_LAST, &call->flags); rot_last = true; } diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index bad96a983e12..8344ece5358a 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -205,7 +205,8 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) msg.msg_flags = 0; if (txb->ack.reason == RXRPC_ACK_PING) - txb->wire.flags |= RXRPC_REQUEST_ACK; + txb->flags |= RXRPC_REQUEST_ACK; + txb->wire.flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; n = rxrpc_fill_out_ack(conn, call, txb, &rwind); if (n == 0) @@ -239,7 +240,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) } else { trace_rxrpc_tx_packet(call->debug_id, &txb->wire, rxrpc_tx_point_call_ack); - if (txb->wire.flags & RXRPC_REQUEST_ACK) + if (txb->flags & RXRPC_REQUEST_ACK) call->peer->rtt_last_req = ktime_get_real(); } rxrpc_tx_backoff(call, ret); @@ -357,13 +358,13 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) * service call, lest OpenAFS incorrectly send us an ACK with some * soft-ACKs in it and then never follow up with a proper hard ACK. */ - if (txb->wire.flags & RXRPC_REQUEST_ACK) + if (txb->flags & RXRPC_REQUEST_ACK) why = rxrpc_reqack_already_on; - else if (test_bit(RXRPC_TXBUF_LAST, &txb->flags) && rxrpc_sending_to_client(txb)) + else if ((txb->flags & RXRPC_LAST_PACKET) && rxrpc_sending_to_client(txb)) why = rxrpc_reqack_no_srv_last; else if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) why = rxrpc_reqack_ack_lost; - else if (test_bit(RXRPC_TXBUF_RESENT, &txb->flags)) + else if (txb->flags & RXRPC_TXBUF_RESENT) why = rxrpc_reqack_retrans; else if (call->cong_mode == RXRPC_CALL_SLOW_START && call->cong_cwnd <= 2) why = rxrpc_reqack_slow_start; @@ -379,7 +380,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) rxrpc_inc_stat(call->rxnet, stat_why_req_ack[why]); trace_rxrpc_req_ack(call->debug_id, txb->seq, why); if (why != rxrpc_reqack_no_srv_last) - txb->wire.flags |= RXRPC_REQUEST_ACK; + txb->flags |= RXRPC_REQUEST_ACK; dont_set_request_ack: if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { @@ -387,15 +388,12 @@ dont_set_request_ack: if ((lose++ & 7) == 7) { ret = 0; trace_rxrpc_tx_data(call, txb->seq, txb->serial, - txb->wire.flags, - test_bit(RXRPC_TXBUF_RESENT, &txb->flags), - true); + txb->flags, true); goto done; } } - trace_rxrpc_tx_data(call, txb->seq, txb->serial, txb->wire.flags, - test_bit(RXRPC_TXBUF_RESENT, &txb->flags), false); + trace_rxrpc_tx_data(call, txb->seq, txb->serial, txb->flags, false); /* Track what we've attempted to transmit at least once so that the * retransmission algorithm doesn't try to resend what we haven't sent @@ -411,8 +409,9 @@ dont_set_request_ack: if (txb->len >= call->peer->maxdata) goto send_fragmentable; + txb->wire.flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; txb->last_sent = ktime_get_real(); - if (txb->wire.flags & RXRPC_REQUEST_ACK) + if (txb->flags & RXRPC_REQUEST_ACK) rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); /* send the packet by UDP @@ -442,7 +441,7 @@ dont_set_request_ack: done: if (ret >= 0) { call->tx_last_sent = txb->last_sent; - if (txb->wire.flags & RXRPC_REQUEST_ACK) { + if (txb->flags & RXRPC_REQUEST_ACK) { call->peer->rtt_last_req = txb->last_sent; if (call->peer->rtt_count > 1) { unsigned long nowj = jiffies, ack_lost_at; @@ -486,7 +485,7 @@ send_fragmentable: _debug("send fragment"); txb->last_sent = ktime_get_real(); - if (txb->wire.flags & RXRPC_REQUEST_ACK) + if (txb->flags & RXRPC_REQUEST_ACK) rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); switch (conn->local->srx.transport.family) { diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index 5677d5690a02..25c7c1d4f4c6 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -240,7 +240,7 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, rxrpc_notify_end_tx_t notify_end_tx) { rxrpc_seq_t seq = txb->seq; - bool last = test_bit(RXRPC_TXBUF_LAST, &txb->flags), poke; + bool poke, last = txb->flags & RXRPC_LAST_PACKET; rxrpc_inc_stat(call->rxnet, stat_tx_data); @@ -394,13 +394,11 @@ reload: /* add the packet to the send queue if it's now full */ if (!txb->space || (msg_data_left(msg) == 0 && !more)) { - if (msg_data_left(msg) == 0 && !more) { - txb->wire.flags |= RXRPC_LAST_PACKET; - __set_bit(RXRPC_TXBUF_LAST, &txb->flags); - } + if (msg_data_left(msg) == 0 && !more) + txb->flags |= RXRPC_LAST_PACKET; else if (call->tx_top - call->acks_hard_ack < call->tx_winsize) - txb->wire.flags |= RXRPC_MORE_PACKETS; + txb->flags |= RXRPC_MORE_PACKETS; ret = call->security->secure_packet(call, txb); if (ret < 0) diff --git a/net/rxrpc/txbuf.c b/net/rxrpc/txbuf.c index f2903c81cf5b..48d5a8f644e5 100644 --- a/net/rxrpc/txbuf.c +++ b/net/rxrpc/txbuf.c @@ -31,7 +31,7 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, txb->space = sizeof(txb->data); txb->len = 0; txb->offset = 0; - txb->flags = 0; + txb->flags = call->conn->out_clientflag; txb->ack_why = 0; txb->seq = call->tx_prepared + 1; txb->serial = 0; @@ -40,7 +40,7 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, txb->wire.callNumber = htonl(call->call_id); txb->wire.seq = htonl(txb->seq); txb->wire.type = packet_type; - txb->wire.flags = call->conn->out_clientflag; + txb->wire.flags = 0; txb->wire.userStatus = 0; txb->wire.securityIndex = call->security_ix; txb->wire._rsvd = 0; From 41b8debba79ca4a4aee35f2e3c66bfc7bb6691ee Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 14:37:52 +0000 Subject: [PATCH 1647/2255] rxrpc: Note cksum in txbuf Add a field to rxrpc_txbuf in which to store the checksum to go in the header as this may get overwritten in the wire header struct when transmitting as part of a jumbo packet. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/ar-internal.h | 1 + net/rxrpc/output.c | 1 + net/rxrpc/rxkad.c | 2 +- net/rxrpc/txbuf.c | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 54d1dc97cb0f..c9a2882627aa 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -803,6 +803,7 @@ struct rxrpc_txbuf { unsigned int flags; #define RXRPC_TXBUF_WIRE_FLAGS 0xff /* The wire protocol flags */ #define RXRPC_TXBUF_RESENT 0x100 /* Set if has been resent */ + __be16 cksum; /* Checksum to go in header */ u8 /*enum rxrpc_propose_ack_trace*/ ack_why; /* If ack, why */ struct { /* The packet for encrypting and DMA'ing. We align it such diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 8344ece5358a..828b145edc56 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -335,6 +335,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) /* Each transmission of a Tx packet+ needs a new serial number */ txb->serial = rxrpc_get_next_serial(conn); txb->wire.serial = htonl(txb->serial); + txb->wire.cksum = txb->cksum; if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) && txb->seq == 1) diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index 6b32d61d4cdc..28c9ce763be4 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -378,7 +378,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) y = (y >> 16) & 0xffff; if (y == 0) y = 1; /* zero checksums are not permitted */ - txb->wire.cksum = htons(y); + txb->cksum = htons(y); switch (call->conn->security_level) { case RXRPC_SECURITY_PLAIN: diff --git a/net/rxrpc/txbuf.c b/net/rxrpc/txbuf.c index 48d5a8f644e5..7273615afe94 100644 --- a/net/rxrpc/txbuf.c +++ b/net/rxrpc/txbuf.c @@ -35,6 +35,7 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, txb->ack_why = 0; txb->seq = call->tx_prepared + 1; txb->serial = 0; + txb->cksum = 0; txb->wire.epoch = htonl(call->conn->proto.epoch); txb->wire.cid = htonl(call->cid); txb->wire.callNumber = htonl(call->call_id); From 17469ae0582aaacad36e8e858f58b86c369f21ef Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 26 Jan 2024 16:17:03 +0000 Subject: [PATCH 1648/2255] rxrpc: Fix the names of the fields in the ACK trailer struct From AFS-3.3 a trailer containing extra info was added to the ACK packet format - but AF_RXRPC has the names of some of the fields mixed up compared to other AFS implementations. Rename the struct and the fields to make them match. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- include/trace/events/rxrpc.h | 2 +- net/rxrpc/conn_event.c | 16 ++++++++-------- net/rxrpc/input.c | 22 +++++++++++----------- net/rxrpc/output.c | 14 +++++++------- net/rxrpc/protocol.h | 6 +++--- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 33888f688325..c730cd732348 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -83,7 +83,7 @@ EM(rxrpc_badmsg_bad_abort, "bad-abort") \ EM(rxrpc_badmsg_bad_jumbo, "bad-jumbo") \ EM(rxrpc_badmsg_short_ack, "short-ack") \ - EM(rxrpc_badmsg_short_ack_info, "short-ack-info") \ + EM(rxrpc_badmsg_short_ack_trailer, "short-ack-trailer") \ EM(rxrpc_badmsg_short_hdr, "short-hdr") \ EM(rxrpc_badmsg_unsupported_packet, "unsup-pkt") \ EM(rxrpc_badmsg_zero_call, "zero-call") \ diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c index 1f251d758cb9..598b4ee389fc 100644 --- a/net/rxrpc/conn_event.c +++ b/net/rxrpc/conn_event.c @@ -88,7 +88,7 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, struct rxrpc_ackpacket ack; }; } __attribute__((packed)) pkt; - struct rxrpc_ackinfo ack_info; + struct rxrpc_acktrailer trailer; size_t len; int ret, ioc; u32 serial, mtu, call_id, padding; @@ -122,8 +122,8 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, iov[0].iov_len = sizeof(pkt.whdr); iov[1].iov_base = &padding; iov[1].iov_len = 3; - iov[2].iov_base = &ack_info; - iov[2].iov_len = sizeof(ack_info); + iov[2].iov_base = &trailer; + iov[2].iov_len = sizeof(trailer); serial = rxrpc_get_next_serial(conn); @@ -158,14 +158,14 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, pkt.ack.serial = htonl(skb ? sp->hdr.serial : 0); pkt.ack.reason = skb ? RXRPC_ACK_DUPLICATE : RXRPC_ACK_IDLE; pkt.ack.nAcks = 0; - ack_info.rxMTU = htonl(rxrpc_rx_mtu); - ack_info.maxMTU = htonl(mtu); - ack_info.rwind = htonl(rxrpc_rx_window_size); - ack_info.jumbo_max = htonl(rxrpc_rx_jumbo_max); + trailer.maxMTU = htonl(rxrpc_rx_mtu); + trailer.ifMTU = htonl(mtu); + trailer.rwind = htonl(rxrpc_rx_window_size); + trailer.jumbo_max = htonl(rxrpc_rx_jumbo_max); pkt.whdr.flags |= RXRPC_SLOW_START_OK; padding = 0; iov[0].iov_len += sizeof(pkt.ack); - len += sizeof(pkt.ack) + 3 + sizeof(ack_info); + len += sizeof(pkt.ack) + 3 + sizeof(trailer); ioc = 3; trace_rxrpc_tx_ack(chan->call_debug_id, serial, diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index c435b50c33f4..ea2df62e05e7 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -670,14 +670,14 @@ static void rxrpc_complete_rtt_probe(struct rxrpc_call *call, /* * Process the extra information that may be appended to an ACK packet */ -static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb, - struct rxrpc_ackinfo *ackinfo) +static void rxrpc_input_ack_trailer(struct rxrpc_call *call, struct sk_buff *skb, + struct rxrpc_acktrailer *trailer) { struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_peer *peer; unsigned int mtu; bool wake = false; - u32 rwind = ntohl(ackinfo->rwind); + u32 rwind = ntohl(trailer->rwind); if (rwind > RXRPC_TX_MAX_WINDOW) rwind = RXRPC_TX_MAX_WINDOW; @@ -691,7 +691,7 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb, if (call->cong_ssthresh > rwind) call->cong_ssthresh = rwind; - mtu = min(ntohl(ackinfo->rxMTU), ntohl(ackinfo->maxMTU)); + mtu = min(ntohl(trailer->maxMTU), ntohl(trailer->ifMTU)); peer = call->peer; if (mtu < peer->maxdata) { @@ -837,7 +837,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) struct rxrpc_ack_summary summary = { 0 }; struct rxrpc_ackpacket ack; struct rxrpc_skb_priv *sp = rxrpc_skb(skb); - struct rxrpc_ackinfo info; + struct rxrpc_acktrailer trailer; rxrpc_serial_t ack_serial, acked_serial; rxrpc_seq_t first_soft_ack, hard_ack, prev_pkt, since; int nr_acks, offset, ioffset; @@ -917,11 +917,11 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) goto send_response; } - info.rxMTU = 0; + trailer.maxMTU = 0; ioffset = offset + nr_acks + 3; - if (skb->len >= ioffset + sizeof(info) && - skb_copy_bits(skb, ioffset, &info, sizeof(info)) < 0) - return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack_info); + if (skb->len >= ioffset + sizeof(trailer) && + skb_copy_bits(skb, ioffset, &trailer, sizeof(trailer)) < 0) + return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack_trailer); if (nr_acks > 0) skb_condense(skb); @@ -950,8 +950,8 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) } /* Parse rwind and mtu sizes if provided. */ - if (info.rxMTU) - rxrpc_input_ackinfo(call, skb, &info); + if (trailer.maxMTU) + rxrpc_input_ack_trailer(call, skb, &trailer); if (first_soft_ack == 0) return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_zero); diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 828b145edc56..3803bf900a46 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -83,7 +83,7 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, struct rxrpc_txbuf *txb, u16 *_rwind) { - struct rxrpc_ackinfo ackinfo; + struct rxrpc_acktrailer trailer; unsigned int qsize, sack, wrap, to; rxrpc_seq_t window, wtop; int rsize; @@ -126,16 +126,16 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, qsize = (window - 1) - call->rx_consumed; rsize = max_t(int, call->rx_winsize - qsize, 0); *_rwind = rsize; - ackinfo.rxMTU = htonl(rxrpc_rx_mtu); - ackinfo.maxMTU = htonl(mtu); - ackinfo.rwind = htonl(rsize); - ackinfo.jumbo_max = htonl(jmax); + trailer.maxMTU = htonl(rxrpc_rx_mtu); + trailer.ifMTU = htonl(mtu); + trailer.rwind = htonl(rsize); + trailer.jumbo_max = htonl(jmax); *ackp++ = 0; *ackp++ = 0; *ackp++ = 0; - memcpy(ackp, &ackinfo, sizeof(ackinfo)); - return txb->ack.nAcks + 3 + sizeof(ackinfo); + memcpy(ackp, &trailer, sizeof(trailer)); + return txb->ack.nAcks + 3 + sizeof(trailer); } /* diff --git a/net/rxrpc/protocol.h b/net/rxrpc/protocol.h index e8ee4af43ca8..4fe6b4d20ada 100644 --- a/net/rxrpc/protocol.h +++ b/net/rxrpc/protocol.h @@ -135,9 +135,9 @@ struct rxrpc_ackpacket { /* * ACK packets can have a further piece of information tagged on the end */ -struct rxrpc_ackinfo { - __be32 rxMTU; /* maximum Rx MTU size (bytes) [AFS 3.3] */ - __be32 maxMTU; /* maximum interface MTU size (bytes) [AFS 3.3] */ +struct rxrpc_acktrailer { + __be32 maxMTU; /* maximum Rx MTU size (bytes) [AFS 3.3] */ + __be32 ifMTU; /* maximum interface MTU size (bytes) [AFS 3.3] */ __be32 rwind; /* Rx window size (packets) [AFS 3.4] */ __be32 jumbo_max; /* max packets to stick into a jumbo packet [AFS 3.5] */ }; From d73f3a7488754b01a9b86154763f266dcde6ca4e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 30 Jan 2024 16:39:15 +0000 Subject: [PATCH 1649/2255] rxrpc: Strip barriers and atomics off of timer tracking Strip the atomic ops and barriering off of the call timer tracking as this is handled solely within the I/O thread, except for expect_term_by which is set by sendmsg(). Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/call_event.c | 32 ++++++++++++++++---------------- net/rxrpc/conn_client.c | 4 ++-- net/rxrpc/input.c | 15 ++++++--------- net/rxrpc/output.c | 18 ++++++++---------- 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 77eacbfc5d45..84eedbb49fcb 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -27,7 +27,7 @@ void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial, unsigned long ping_at = now + rxrpc_idle_ack_delay; if (time_before(ping_at, call->ping_at)) { - WRITE_ONCE(call->ping_at, ping_at); + call->ping_at = ping_at; rxrpc_reduce_call_timer(call, ping_at, now, rxrpc_timer_set_for_ping); trace_rxrpc_propose_ack(call, why, RXRPC_ACK_PING, serial); @@ -53,7 +53,7 @@ void rxrpc_propose_delay_ACK(struct rxrpc_call *call, rxrpc_serial_t serial, ack_at += READ_ONCE(call->tx_backoff); ack_at += now; if (time_before(ack_at, call->delay_ack_at)) { - WRITE_ONCE(call->delay_ack_at, ack_at); + call->delay_ack_at = ack_at; rxrpc_reduce_call_timer(call, ack_at, now, rxrpc_timer_set_for_ack); } @@ -220,7 +220,7 @@ no_resend: resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(now, oldest))); resend_at += jiffies + rxrpc_get_rto_backoff(call->peer, !list_empty(&retrans_queue)); - WRITE_ONCE(call->resend_at, resend_at); + call->resend_at = resend_at; if (unacked) rxrpc_congestion_timeout(call); @@ -260,7 +260,7 @@ static void rxrpc_begin_service_reply(struct rxrpc_call *call) unsigned long now = jiffies; rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SEND_REPLY); - WRITE_ONCE(call->delay_ack_at, now + MAX_JIFFY_OFFSET); + call->delay_ack_at = now + MAX_JIFFY_OFFSET; if (call->ackr_reason == RXRPC_ACK_DELAY) call->ackr_reason = 0; trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now); @@ -399,13 +399,13 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) /* If we see our async-event poke, check for timeout trippage. */ now = jiffies; - t = READ_ONCE(call->expect_rx_by); + t = call->expect_rx_by; if (time_after_eq(now, t)) { trace_rxrpc_timer(call, rxrpc_timer_exp_normal, now); expired = true; } - t = READ_ONCE(call->expect_req_by); + t = call->expect_req_by; if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST && time_after_eq(now, t)) { trace_rxrpc_timer(call, rxrpc_timer_exp_idle, now); @@ -418,41 +418,41 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) expired = true; } - t = READ_ONCE(call->delay_ack_at); + t = call->delay_ack_at; if (time_after_eq(now, t)) { trace_rxrpc_timer(call, rxrpc_timer_exp_ack, now); - cmpxchg(&call->delay_ack_at, t, now + MAX_JIFFY_OFFSET); + call->delay_ack_at = now + MAX_JIFFY_OFFSET; rxrpc_send_ACK(call, RXRPC_ACK_DELAY, 0, rxrpc_propose_ack_ping_for_lost_ack); } - t = READ_ONCE(call->ack_lost_at); + t = call->ack_lost_at; if (time_after_eq(now, t)) { trace_rxrpc_timer(call, rxrpc_timer_exp_lost_ack, now); - cmpxchg(&call->ack_lost_at, t, now + MAX_JIFFY_OFFSET); + call->ack_lost_at = now + MAX_JIFFY_OFFSET; set_bit(RXRPC_CALL_EV_ACK_LOST, &call->events); } - t = READ_ONCE(call->keepalive_at); + t = call->keepalive_at; if (time_after_eq(now, t)) { trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now); - cmpxchg(&call->keepalive_at, t, now + MAX_JIFFY_OFFSET); + call->keepalive_at = now + MAX_JIFFY_OFFSET; rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, rxrpc_propose_ack_ping_for_keepalive); } - t = READ_ONCE(call->ping_at); + t = call->ping_at; if (time_after_eq(now, t)) { trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now); - cmpxchg(&call->ping_at, t, now + MAX_JIFFY_OFFSET); + call->ping_at = now + MAX_JIFFY_OFFSET; rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, rxrpc_propose_ack_ping_for_keepalive); } - t = READ_ONCE(call->resend_at); + t = call->resend_at; if (time_after_eq(now, t)) { trace_rxrpc_timer(call, rxrpc_timer_exp_resend, now); - cmpxchg(&call->resend_at, t, now + MAX_JIFFY_OFFSET); + call->resend_at = now + MAX_JIFFY_OFFSET; resend = true; } diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 3b9b267a4431..d25bf1cf3670 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -636,7 +636,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call test_bit(RXRPC_CALL_EXPOSED, &call->flags)) { unsigned long final_ack_at = jiffies + 2; - WRITE_ONCE(chan->final_ack_at, final_ack_at); + chan->final_ack_at = final_ack_at; smp_wmb(); /* vs rxrpc_process_delayed_final_acks() */ set_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags); rxrpc_reduce_conn_timer(conn, final_ack_at); @@ -770,7 +770,7 @@ next: conn_expires_at = conn->idle_timestamp + expiry; - now = READ_ONCE(jiffies); + now = jiffies; if (time_after(conn_expires_at, now)) goto not_yet_expired; } diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index ea2df62e05e7..e53a49accc16 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -288,14 +288,12 @@ static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun, static bool rxrpc_receiving_reply(struct rxrpc_call *call) { struct rxrpc_ack_summary summary = { 0 }; - unsigned long now, timo; + unsigned long now; rxrpc_seq_t top = READ_ONCE(call->tx_top); if (call->ackr_reason) { now = jiffies; - timo = now + MAX_JIFFY_OFFSET; - - WRITE_ONCE(call->delay_ack_at, timo); + call->delay_ack_at = now + MAX_JIFFY_OFFSET; trace_rxrpc_timer(call, rxrpc_timer_init_for_reply, now); } @@ -594,7 +592,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) if (timo) { now = jiffies; expect_req_by = now + timo; - WRITE_ONCE(call->expect_req_by, expect_req_by); + call->expect_req_by = now + timo; rxrpc_reduce_call_timer(call, expect_req_by, now, rxrpc_timer_set_for_idle); } @@ -1048,11 +1046,10 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb) timo = READ_ONCE(call->next_rx_timo); if (timo) { - unsigned long now = jiffies, expect_rx_by; + unsigned long now = jiffies; - expect_rx_by = now + timo; - WRITE_ONCE(call->expect_rx_by, expect_rx_by); - rxrpc_reduce_call_timer(call, expect_rx_by, now, + call->expect_rx_by = now + timo; + rxrpc_reduce_call_timer(call, call->expect_rx_by, now, rxrpc_timer_set_for_normal); } diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 3803bf900a46..2386b01b2231 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -67,11 +67,10 @@ static void rxrpc_tx_backoff(struct rxrpc_call *call, int ret) */ static void rxrpc_set_keepalive(struct rxrpc_call *call) { - unsigned long now = jiffies, keepalive_at = call->next_rx_timo / 6; + unsigned long now = jiffies; - keepalive_at += now; - WRITE_ONCE(call->keepalive_at, keepalive_at); - rxrpc_reduce_call_timer(call, keepalive_at, now, + call->keepalive_at = now + call->next_rx_timo / 6; + rxrpc_reduce_call_timer(call, call->keepalive_at, now, rxrpc_timer_set_for_keepalive); } @@ -449,7 +448,7 @@ done: ack_lost_at = rxrpc_get_rto_backoff(call->peer, false); ack_lost_at += nowj; - WRITE_ONCE(call->ack_lost_at, ack_lost_at); + call->ack_lost_at = ack_lost_at; rxrpc_reduce_call_timer(call, ack_lost_at, nowj, rxrpc_timer_set_for_lost_ack); } @@ -458,11 +457,10 @@ done: if (txb->seq == 1 && !test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, &call->flags)) { - unsigned long nowj = jiffies, expect_rx_by; + unsigned long nowj = jiffies; - expect_rx_by = nowj + call->next_rx_timo; - WRITE_ONCE(call->expect_rx_by, expect_rx_by); - rxrpc_reduce_call_timer(call, expect_rx_by, nowj, + call->expect_rx_by = nowj + call->next_rx_timo; + rxrpc_reduce_call_timer(call, call->expect_rx_by, nowj, rxrpc_timer_set_for_normal); } @@ -724,7 +722,7 @@ void rxrpc_transmit_one(struct rxrpc_call *call, struct rxrpc_txbuf *txb) unsigned long now = jiffies; unsigned long resend_at = now + call->peer->rto_j; - WRITE_ONCE(call->resend_at, resend_at); + call->resend_at = resend_at; rxrpc_reduce_call_timer(call, resend_at, now, rxrpc_timer_set_for_send); } From 693f9c13ec890b0ab36dfb9a5441fdce47255737 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 22:29:58 +0000 Subject: [PATCH 1650/2255] rxrpc: Remove atomic handling on some fields only used in I/O thread call->tx_transmitted and call->acks_prev_seq don't need to be managed with cmpxchg() and barriers as it's only used within the singular I/O thread. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/call_event.c | 10 ++++------ net/rxrpc/output.c | 8 +++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 84eedbb49fcb..1184518dcdb8 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -115,7 +115,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) struct rxrpc_skb_priv *sp; struct rxrpc_txbuf *txb; unsigned long resend_at; - rxrpc_seq_t transmitted = READ_ONCE(call->tx_transmitted); + rxrpc_seq_t transmitted = call->tx_transmitted; ktime_t now, max_age, oldest, ack_ts; bool unacked = false; unsigned int i; @@ -184,16 +184,14 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) * seen. Anything between the soft-ACK table and that point will get * ACK'd or NACK'd in due course, so don't worry about it here; here we * need to consider retransmitting anything beyond that point. - * - * Note that ACK for a packet can beat the update of tx_transmitted. */ - if (after_eq(READ_ONCE(call->acks_prev_seq), READ_ONCE(call->tx_transmitted))) + if (after_eq(call->acks_prev_seq, call->tx_transmitted)) goto no_further_resend; list_for_each_entry_from(txb, &call->tx_buffer, call_link) { - if (before_eq(txb->seq, READ_ONCE(call->acks_prev_seq))) + if (before_eq(txb->seq, call->acks_prev_seq)) continue; - if (after(txb->seq, READ_ONCE(call->tx_transmitted))) + if (after(txb->seq, call->tx_transmitted)) break; /* Not transmitted yet */ if (ack && ack->reason == RXRPC_ACK_PING_RESPONSE && diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 2386b01b2231..1e039b6f4494 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -397,12 +397,10 @@ dont_set_request_ack: /* Track what we've attempted to transmit at least once so that the * retransmission algorithm doesn't try to resend what we haven't sent - * yet. However, this can race as we can receive an ACK before we get - * to this point. But, OTOH, if we won't get an ACK mentioning this - * packet unless the far side received it (though it could have - * discarded it anyway and NAK'd it). + * yet. */ - cmpxchg(&call->tx_transmitted, txb->seq - 1, txb->seq); + if (txb->seq == call->tx_transmitted + 1) + call->tx_transmitted = txb->seq; /* send the packet with the don't fragment bit set if we currently * think it's small enough */ From d32636982ce967110588c8445660b85685e26e5a Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 22:38:31 +0000 Subject: [PATCH 1651/2255] rxrpc: Do lazy DF flag resetting Don't reset the DF flag after transmission, but rather set it when needed since it should be a fast op now that we call IP directly. This includes turning it off for RESPONSE packets and, for the moment, ACK packets. In future, we will need to turn it on for ACK packets used to do path MTU discovery. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/output.c | 4 ++-- net/rxrpc/rxkad.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 1e039b6f4494..8aa8ba32eacc 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -231,6 +231,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) txb->ack.previousPacket = htonl(call->rx_highest_seq); iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len); + rxrpc_local_dont_fragment(conn->local, false); ret = do_udp_sendmsg(conn->local->socket, &msg, len); call->peer->last_tx_at = ktime_get_seconds(); if (ret < 0) { @@ -406,6 +407,7 @@ dont_set_request_ack: * think it's small enough */ if (txb->len >= call->peer->maxdata) goto send_fragmentable; + rxrpc_local_dont_fragment(conn->local, true); txb->wire.flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; txb->last_sent = ktime_get_real(); @@ -492,8 +494,6 @@ send_fragmentable: rxrpc_inc_stat(call->rxnet, stat_tx_data_send_frag); ret = do_udp_sendmsg(conn->local->socket, &msg, len); conn->peer->last_tx_at = ktime_get_seconds(); - - rxrpc_local_dont_fragment(conn->local, true); break; default: diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index 28c9ce763be4..e451ac90bfee 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -726,7 +726,6 @@ static int rxkad_send_response(struct rxrpc_connection *conn, rxrpc_local_dont_fragment(conn->local, false); ret = kernel_sendmsg(conn->local->socket, &msg, iov, 3, len); - rxrpc_local_dont_fragment(conn->local, true); if (ret < 0) { trace_rxrpc_tx_fail(conn->debug_id, serial, ret, rxrpc_tx_point_rxkad_response); From 1ac6a8536c2cbb12b593f0f4ffd7816b15a484fa Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 22:49:19 +0000 Subject: [PATCH 1652/2255] rxrpc: Merge together DF/non-DF branches of data Tx function Merge together the DF and non-DF branches of the transmission function and always set the flag to the right thing before transmitting. If we see -EMSGSIZE from udp_sendmsg(), turn off DF and retry. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/output.c | 54 +++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 8aa8ba32eacc..e2c9e645fcfb 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -323,8 +323,9 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call) */ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) { - enum rxrpc_req_ack_trace why; struct rxrpc_connection *conn = call->conn; + enum rxrpc_req_ack_trace why; + enum rxrpc_tx_point frag; struct msghdr msg; struct kvec iov[1]; size_t len; @@ -405,11 +406,16 @@ dont_set_request_ack: /* send the packet with the don't fragment bit set if we currently * think it's small enough */ - if (txb->len >= call->peer->maxdata) - goto send_fragmentable; - rxrpc_local_dont_fragment(conn->local, true); + if (txb->len >= call->peer->maxdata) { + rxrpc_local_dont_fragment(conn->local, false); + frag = rxrpc_tx_point_call_data_frag; + } else { + rxrpc_local_dont_fragment(conn->local, true); + frag = rxrpc_tx_point_call_data_nofrag; + } txb->wire.flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; +retry: txb->last_sent = ktime_get_real(); if (txb->flags & RXRPC_REQUEST_ACK) rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); @@ -435,8 +441,11 @@ dont_set_request_ack: } rxrpc_tx_backoff(call, ret); - if (ret == -EMSGSIZE) - goto send_fragmentable; + if (ret == -EMSGSIZE && frag == rxrpc_tx_point_call_data_frag) { + rxrpc_local_dont_fragment(conn->local, false); + frag = rxrpc_tx_point_call_data_frag; + goto retry; + } done: if (ret >= 0) { @@ -478,39 +487,6 @@ done: _leave(" = %d [%u]", ret, call->peer->maxdata); return ret; - -send_fragmentable: - /* attempt to send this message with fragmentation enabled */ - _debug("send fragment"); - - txb->last_sent = ktime_get_real(); - if (txb->flags & RXRPC_REQUEST_ACK) - rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); - - switch (conn->local->srx.transport.family) { - case AF_INET6: - case AF_INET: - rxrpc_local_dont_fragment(conn->local, false); - rxrpc_inc_stat(call->rxnet, stat_tx_data_send_frag); - ret = do_udp_sendmsg(conn->local->socket, &msg, len); - conn->peer->last_tx_at = ktime_get_seconds(); - break; - - default: - BUG(); - } - - if (ret < 0) { - rxrpc_inc_stat(call->rxnet, stat_tx_data_send_fail); - rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); - trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, - rxrpc_tx_point_call_data_frag); - } else { - trace_rxrpc_tx_packet(call->debug_id, &txb->wire, - rxrpc_tx_point_call_data_frag); - } - rxrpc_tx_backoff(call, ret); - goto done; } /* From ff342bdc59f4a7431d0b58ce8bc2ef7d44cff15f Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 23:07:43 +0000 Subject: [PATCH 1653/2255] rxrpc: Add a kvec[] to the rxrpc_txbuf struct Add a kvec[] to the rxrpc_txbuf struct to point to the contributory buffers for a packet. Start with just a single element for now, but this will be expanded later. Make the ACK sending function use it, which means that rxrpc_fill_out_ack() doesn't need to return the size of the sack table, padding and trailer. Make the data sending code use it, both in where sendmsg() packages code up into txbufs and where those txbufs are transmitted. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/ar-internal.h | 2 ++ net/rxrpc/output.c | 33 ++++++++++++--------------------- net/rxrpc/sendmsg.c | 8 +++++--- net/rxrpc/txbuf.c | 3 +++ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index c9a2882627aa..c6731f43a2d5 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -805,6 +805,8 @@ struct rxrpc_txbuf { #define RXRPC_TXBUF_RESENT 0x100 /* Set if has been resent */ __be16 cksum; /* Checksum to go in header */ u8 /*enum rxrpc_propose_ack_trace*/ ack_why; /* If ack, why */ + u8 nr_kvec; + struct kvec kvec[1]; struct { /* The packet for encrypting and DMA'ing. We align it such * that data[] aligns correctly for any crypto blocksize. diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index e2c9e645fcfb..f2b10c3e4cc2 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -77,10 +77,10 @@ static void rxrpc_set_keepalive(struct rxrpc_call *call) /* * Fill out an ACK packet. */ -static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, - struct rxrpc_call *call, - struct rxrpc_txbuf *txb, - u16 *_rwind) +static void rxrpc_fill_out_ack(struct rxrpc_connection *conn, + struct rxrpc_call *call, + struct rxrpc_txbuf *txb, + u16 *_rwind) { struct rxrpc_acktrailer trailer; unsigned int qsize, sack, wrap, to; @@ -134,7 +134,9 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, *ackp++ = 0; *ackp++ = 0; memcpy(ackp, &trailer, sizeof(trailer)); - return txb->ack.nAcks + 3 + sizeof(trailer); + txb->kvec[0].iov_len = sizeof(txb->wire) + + sizeof(txb->ack) + txb->ack.nAcks + 3 + sizeof(trailer); + txb->len = txb->kvec[0].iov_len; } /* @@ -187,8 +189,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) { struct rxrpc_connection *conn; struct msghdr msg; - struct kvec iov[1]; - size_t len, n; int ret, rtt_slot = -1; u16 rwind; @@ -207,13 +207,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) txb->flags |= RXRPC_REQUEST_ACK; txb->wire.flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; - n = rxrpc_fill_out_ack(conn, call, txb, &rwind); - if (n == 0) - return 0; - - iov[0].iov_base = &txb->wire; - iov[0].iov_len = sizeof(txb->wire) + sizeof(txb->ack) + n; - len = iov[0].iov_len; + rxrpc_fill_out_ack(conn, call, txb, &rwind); txb->serial = rxrpc_get_next_serial(conn); txb->wire.serial = htonl(txb->serial); @@ -230,9 +224,9 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) /* Grab the highest received seq as late as possible */ txb->ack.previousPacket = htonl(call->rx_highest_seq); - iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len); + iov_iter_kvec(&msg.msg_iter, WRITE, txb->kvec, txb->nr_kvec, txb->len); rxrpc_local_dont_fragment(conn->local, false); - ret = do_udp_sendmsg(conn->local->socket, &msg, len); + ret = do_udp_sendmsg(conn->local->socket, &msg, txb->len); call->peer->last_tx_at = ktime_get_seconds(); if (ret < 0) { trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, @@ -327,7 +321,6 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) enum rxrpc_req_ack_trace why; enum rxrpc_tx_point frag; struct msghdr msg; - struct kvec iov[1]; size_t len; int ret, rtt_slot = -1; @@ -342,10 +335,8 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) txb->seq == 1) txb->wire.userStatus = RXRPC_USERSTATUS_SERVICE_UPGRADE; - iov[0].iov_base = &txb->wire; - iov[0].iov_len = sizeof(txb->wire) + txb->len; - len = iov[0].iov_len; - iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len); + len = txb->kvec[0].iov_len; + iov_iter_kvec(&msg.msg_iter, WRITE, txb->kvec, txb->nr_kvec, len); msg.msg_name = &call->peer->srx.transport; msg.msg_namelen = call->peer->srx.transport_len; diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index 25c7c1d4f4c6..1e81046ea8a6 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -362,7 +362,7 @@ reload: if (!txb) goto maybe_error; - txb->offset = offset; + txb->offset = offset + sizeof(struct rxrpc_wire_header); txb->space -= offset; txb->space = min_t(size_t, chunk, txb->space); } @@ -374,8 +374,8 @@ reload: size_t copy = min_t(size_t, txb->space, msg_data_left(msg)); _debug("add %zu", copy); - if (!copy_from_iter_full(txb->data + txb->offset, copy, - &msg->msg_iter)) + if (!copy_from_iter_full(txb->kvec[0].iov_base + txb->offset, + copy, &msg->msg_iter)) goto efault; _debug("added"); txb->space -= copy; @@ -404,6 +404,8 @@ reload: if (ret < 0) goto out; + txb->kvec[0].iov_len += txb->len; + txb->len = txb->kvec[0].iov_len; rxrpc_queue_packet(rx, call, txb, notify_end_tx); txb = NULL; } diff --git a/net/rxrpc/txbuf.c b/net/rxrpc/txbuf.c index 7273615afe94..91e96cda6dc7 100644 --- a/net/rxrpc/txbuf.c +++ b/net/rxrpc/txbuf.c @@ -36,6 +36,9 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, txb->seq = call->tx_prepared + 1; txb->serial = 0; txb->cksum = 0; + txb->nr_kvec = 1; + txb->kvec[0].iov_base = &txb->wire; + txb->kvec[0].iov_len = sizeof(txb->wire); txb->wire.epoch = htonl(call->conn->proto.epoch); txb->wire.cid = htonl(call->cid); txb->wire.callNumber = htonl(call->call_id); From 44125d5aaddadfe37a97e642218df184871187be Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 26 Jan 2024 10:47:39 +0000 Subject: [PATCH 1654/2255] rxrpc: Split up the DATA packet transmission function Split (sub)packet preparation and timestamping out of the DATA packet transmission function to make it easier to glue multiple txbufs together into a jumbo DATA packet. This will require preparation and timestamping of all the subpackets in a txbuf, and these functions provide convenient points to place the required iteration. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/ar-internal.h | 1 - net/rxrpc/output.c | 98 +++++++++++++++++++++++++++++------------ 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index c6731f43a2d5..54550ab62adc 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -1166,7 +1166,6 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net) */ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb); int rxrpc_send_abort_packet(struct rxrpc_call *); -int rxrpc_send_data_packet(struct rxrpc_call *, struct rxrpc_txbuf *); void rxrpc_send_conn_abort(struct rxrpc_connection *conn); void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb); void rxrpc_send_keepalive(struct rxrpc_peer *); diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index f2b10c3e4cc2..25b8fc9aef97 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -313,37 +313,23 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call) } /* - * send a packet through the transport endpoint + * Prepare a (sub)packet for transmission. */ -int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) +static void rxrpc_prepare_data_subpacket(struct rxrpc_call *call, struct rxrpc_txbuf *txb, + rxrpc_serial_t serial) { - struct rxrpc_connection *conn = call->conn; + struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; enum rxrpc_req_ack_trace why; - enum rxrpc_tx_point frag; - struct msghdr msg; - size_t len; - int ret, rtt_slot = -1; + struct rxrpc_connection *conn = call->conn; _enter("%x,{%d}", txb->seq, txb->len); - /* Each transmission of a Tx packet+ needs a new serial number */ - txb->serial = rxrpc_get_next_serial(conn); - txb->wire.serial = htonl(txb->serial); - txb->wire.cksum = txb->cksum; + txb->serial = serial; if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) && txb->seq == 1) txb->wire.userStatus = RXRPC_USERSTATUS_SERVICE_UPGRADE; - len = txb->kvec[0].iov_len; - iov_iter_kvec(&msg.msg_iter, WRITE, txb->kvec, txb->nr_kvec, len); - - msg.msg_name = &call->peer->srx.transport; - msg.msg_namelen = call->peer->srx.transport_len; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - /* If our RTT cache needs working on, request an ACK. Also request * ACKs if a DATA packet appears to have been lost. * @@ -376,6 +362,59 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) txb->flags |= RXRPC_REQUEST_ACK; dont_set_request_ack: + whdr->flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; + whdr->serial = htonl(txb->serial); + whdr->cksum = txb->cksum; + + trace_rxrpc_tx_data(call, txb->seq, txb->serial, txb->flags, false); +} + +/* + * Prepare a packet for transmission. + */ +static size_t rxrpc_prepare_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) +{ + rxrpc_serial_t serial; + + /* Each transmission of a Tx packet needs a new serial number */ + serial = rxrpc_get_next_serial(call->conn); + + rxrpc_prepare_data_subpacket(call, txb, serial); + + return txb->len; +} + +/* + * Set the times on a packet before transmission + */ +static int rxrpc_tstamp_data_packets(struct rxrpc_call *call, struct rxrpc_txbuf *txb) +{ + ktime_t tstamp = ktime_get_real(); + int rtt_slot = -1; + + txb->last_sent = tstamp; + if (txb->flags & RXRPC_REQUEST_ACK) + rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); + + return rtt_slot; +} + +/* + * send a packet through the transport endpoint + */ +static int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) +{ + struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; + struct rxrpc_connection *conn = call->conn; + enum rxrpc_tx_point frag; + struct msghdr msg; + size_t len; + int ret, rtt_slot = -1; + + _enter("%x,{%d}", txb->seq, txb->len); + + len = rxrpc_prepare_data_packet(call, txb); + if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { static int lose; if ((lose++ & 7) == 7) { @@ -386,7 +425,13 @@ dont_set_request_ack: } } - trace_rxrpc_tx_data(call, txb->seq, txb->serial, txb->flags, false); + iov_iter_kvec(&msg.msg_iter, WRITE, txb->kvec, txb->nr_kvec, len); + + msg.msg_name = &call->peer->srx.transport; + msg.msg_namelen = call->peer->srx.transport_len; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; /* Track what we've attempted to transmit at least once so that the * retransmission algorithm doesn't try to resend what we haven't sent @@ -405,11 +450,8 @@ dont_set_request_ack: frag = rxrpc_tx_point_call_data_nofrag; } - txb->wire.flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; retry: - txb->last_sent = ktime_get_real(); - if (txb->flags & RXRPC_REQUEST_ACK) - rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); + rtt_slot = rxrpc_tstamp_data_packets(call, txb); /* send the packet by UDP * - returns -EMSGSIZE if UDP would have to fragment the packet @@ -424,11 +466,9 @@ retry: if (ret < 0) { rxrpc_inc_stat(call->rxnet, stat_tx_data_send_fail); rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); - trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, - rxrpc_tx_point_call_data_nofrag); + trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, frag); } else { - trace_rxrpc_tx_packet(call->debug_id, &txb->wire, - rxrpc_tx_point_call_data_nofrag); + trace_rxrpc_tx_packet(call->debug_id, whdr, frag); } rxrpc_tx_backoff(call, ret); From a1c9af4d4467354132417c2d8db10d6e928a7f77 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 30 Jan 2024 08:24:58 +0000 Subject: [PATCH 1655/2255] rxrpc: Don't pick values out of the wire header when setting up security Don't pick values out of the wire header in rxkad when setting up DATA packet security, but rather use other sources. This makes it easier to get rid of txb->wire. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/rxkad.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index e451ac90bfee..ef0849c8329c 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -259,7 +259,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call, _enter(""); - check = txb->seq ^ ntohl(txb->wire.callNumber); + check = txb->seq ^ call->call_id; hdr->data_size = htonl((u32)check << 16 | txb->len); txb->len += sizeof(struct rxkad_level1_hdr); @@ -302,7 +302,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, _enter(""); - check = txb->seq ^ ntohl(txb->wire.callNumber); + check = txb->seq ^ call->call_id; rxkhdr->data_size = htonl(txb->len | (u32)check << 16); rxkhdr->checksum = 0; @@ -362,9 +362,9 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) memcpy(&iv, call->conn->rxkad.csum_iv.x, sizeof(iv)); /* calculate the security checksum */ - x = (ntohl(txb->wire.cid) & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT); + x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT); x |= txb->seq & 0x3fffffff; - crypto.buf[0] = txb->wire.callNumber; + crypto.buf[0] = htonl(call->call_id); crypto.buf[1] = htonl(x); sg_init_one(&sg, crypto.buf, 8); From 99afb28c676cc36747cdb18ffaa6692a60888853 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 30 Jan 2024 08:35:25 +0000 Subject: [PATCH 1656/2255] rxrpc: Move rxrpc_send_ACK() to output.c with rxrpc_send_ack_packet() Move rxrpc_send_ACK() to output.c to so that it is with rxrpc_send_ack_packet() prior to merging the two. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/ar-internal.h | 4 ++-- net/rxrpc/call_event.c | 37 ------------------------------------- net/rxrpc/output.c | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 54550ab62adc..a8795ef0d669 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -873,7 +873,6 @@ int rxrpc_user_charge_accept(struct rxrpc_sock *, unsigned long); */ void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial, enum rxrpc_propose_ack_trace why); -void rxrpc_send_ACK(struct rxrpc_call *, u8, rxrpc_serial_t, enum rxrpc_propose_ack_trace); void rxrpc_propose_delay_ACK(struct rxrpc_call *, rxrpc_serial_t, enum rxrpc_propose_ack_trace); void rxrpc_shrink_call_tx_buffer(struct rxrpc_call *); @@ -1164,7 +1163,8 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net) /* * output.c */ -int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb); +void rxrpc_send_ACK(struct rxrpc_call *call, u8 ack_reason, + rxrpc_serial_t serial, enum rxrpc_propose_ack_trace why); int rxrpc_send_abort_packet(struct rxrpc_call *); void rxrpc_send_conn_abort(struct rxrpc_connection *conn); void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb); diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 1184518dcdb8..e19ea54dce54 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -61,43 +61,6 @@ void rxrpc_propose_delay_ACK(struct rxrpc_call *call, rxrpc_serial_t serial, trace_rxrpc_propose_ack(call, why, RXRPC_ACK_DELAY, serial); } -/* - * Queue an ACK for immediate transmission. - */ -void rxrpc_send_ACK(struct rxrpc_call *call, u8 ack_reason, - rxrpc_serial_t serial, enum rxrpc_propose_ack_trace why) -{ - struct rxrpc_txbuf *txb; - - if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) - return; - - rxrpc_inc_stat(call->rxnet, stat_tx_acks[ack_reason]); - - txb = rxrpc_alloc_txbuf(call, RXRPC_PACKET_TYPE_ACK, - rcu_read_lock_held() ? GFP_ATOMIC | __GFP_NOWARN : GFP_NOFS); - if (!txb) { - kleave(" = -ENOMEM"); - return; - } - - txb->ack_why = why; - txb->wire.seq = 0; - txb->wire.type = RXRPC_PACKET_TYPE_ACK; - txb->flags |= RXRPC_SLOW_START_OK; - txb->ack.bufferSpace = 0; - txb->ack.maxSkew = 0; - txb->ack.firstPacket = 0; - txb->ack.previousPacket = 0; - txb->ack.serial = htonl(serial); - txb->ack.reason = ack_reason; - txb->ack.nAcks = 0; - - trace_rxrpc_send_ack(call, why, ack_reason, serial); - rxrpc_send_ack_packet(call, txb); - rxrpc_put_txbuf(txb, rxrpc_txbuf_put_ack_tx); -} - /* * Handle congestion being detected by the retransmit timeout. */ diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 25b8fc9aef97..ec9ae9c6c492 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -185,7 +185,7 @@ static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call, /* * Transmit an ACK packet. */ -int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) +static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) { struct rxrpc_connection *conn; struct msghdr msg; @@ -248,6 +248,43 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) return ret; } +/* + * Queue an ACK for immediate transmission. + */ +void rxrpc_send_ACK(struct rxrpc_call *call, u8 ack_reason, + rxrpc_serial_t serial, enum rxrpc_propose_ack_trace why) +{ + struct rxrpc_txbuf *txb; + + if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) + return; + + rxrpc_inc_stat(call->rxnet, stat_tx_acks[ack_reason]); + + txb = rxrpc_alloc_txbuf(call, RXRPC_PACKET_TYPE_ACK, + rcu_read_lock_held() ? GFP_ATOMIC | __GFP_NOWARN : GFP_NOFS); + if (!txb) { + kleave(" = -ENOMEM"); + return; + } + + txb->ack_why = why; + txb->wire.seq = 0; + txb->wire.type = RXRPC_PACKET_TYPE_ACK; + txb->flags |= RXRPC_SLOW_START_OK; + txb->ack.bufferSpace = 0; + txb->ack.maxSkew = 0; + txb->ack.firstPacket = 0; + txb->ack.previousPacket = 0; + txb->ack.serial = htonl(serial); + txb->ack.reason = ack_reason; + txb->ack.nAcks = 0; + + trace_rxrpc_send_ack(call, why, ack_reason, serial); + rxrpc_send_ack_packet(call, txb); + rxrpc_put_txbuf(txb, rxrpc_txbuf_put_ack_tx); +} + /* * Send an ABORT call packet. */ From 896880ff30866f386ebed14ab81ce1ad3710cfc4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 22 Feb 2024 07:56:15 -0800 Subject: [PATCH 1657/2255] bpf: Replace bpf_lpm_trie_key 0-length array with flexible array Replace deprecated 0-length array in struct bpf_lpm_trie_key with flexible array. Found with GCC 13: ../kernel/bpf/lpm_trie.c:207:51: warning: array subscript i is outside array bounds of 'const __u8[0]' {aka 'const unsigned char[]'} [-Warray-bounds=] 207 | *(__be16 *)&key->data[i]); | ^~~~~~~~~~~~~ ../include/uapi/linux/swab.h:102:54: note: in definition of macro '__swab16' 102 | #define __swab16(x) (__u16)__builtin_bswap16((__u16)(x)) | ^ ../include/linux/byteorder/generic.h:97:21: note: in expansion of macro '__be16_to_cpu' 97 | #define be16_to_cpu __be16_to_cpu | ^~~~~~~~~~~~~ ../kernel/bpf/lpm_trie.c:206:28: note: in expansion of macro 'be16_to_cpu' 206 | u16 diff = be16_to_cpu(*(__be16 *)&node->data[i] ^ | ^~~~~~~~~~~ In file included from ../include/linux/bpf.h:7: ../include/uapi/linux/bpf.h:82:17: note: while referencing 'data' 82 | __u8 data[0]; /* Arbitrary size */ | ^~~~ And found at run-time under CONFIG_FORTIFY_SOURCE: UBSAN: array-index-out-of-bounds in kernel/bpf/lpm_trie.c:218:49 index 0 is out of range for type '__u8 [*]' Changing struct bpf_lpm_trie_key is difficult since has been used by userspace. For example, in Cilium: struct egress_gw_policy_key { struct bpf_lpm_trie_key lpm_key; __u32 saddr; __u32 daddr; }; While direct references to the "data" member haven't been found, there are static initializers what include the final member. For example, the "{}" here: struct egress_gw_policy_key in_key = { .lpm_key = { 32 + 24, {} }, .saddr = CLIENT_IP, .daddr = EXTERNAL_SVC_IP & 0Xffffff, }; To avoid the build time and run time warnings seen with a 0-sized trailing array for struct bpf_lpm_trie_key, introduce a new struct that correctly uses a flexible array for the trailing bytes, struct bpf_lpm_trie_key_u8. As part of this, include the "header" portion (which is just the "prefixlen" member), so it can be used by anything building a bpf_lpr_trie_key that has trailing members that aren't a u8 flexible array (like the self-test[1]), which is named struct bpf_lpm_trie_key_hdr. Unfortunately, C++ refuses to parse the __struct_group() helper, so it is not possible to define struct bpf_lpm_trie_key_hdr directly in struct bpf_lpm_trie_key_u8, so we must open-code the union directly. Adjust the kernel code to use struct bpf_lpm_trie_key_u8 through-out, and for the selftest to use struct bpf_lpm_trie_key_hdr. Add a comment to the UAPI header directing folks to the two new options. Reported-by: Mark Rutland Signed-off-by: Kees Cook Signed-off-by: Daniel Borkmann Acked-by: Gustavo A. R. Silva Closes: https://paste.debian.net/hidden/ca500597/ Link: https://lore.kernel.org/all/202206281009.4332AA33@keescook/ [1] Link: https://lore.kernel.org/bpf/20240222155612.it.533-kees@kernel.org --- Documentation/bpf/map_lpm_trie.rst | 2 +- include/uapi/linux/bpf.h | 19 +++++++++++++++++- kernel/bpf/lpm_trie.c | 20 +++++++++---------- samples/bpf/map_perf_test_user.c | 2 +- samples/bpf/xdp_router_ipv4_user.c | 2 +- tools/include/uapi/linux/bpf.h | 19 +++++++++++++++++- .../selftests/bpf/progs/map_ptr_kern.c | 2 +- tools/testing/selftests/bpf/test_lpm_map.c | 18 ++++++++--------- 8 files changed, 59 insertions(+), 25 deletions(-) diff --git a/Documentation/bpf/map_lpm_trie.rst b/Documentation/bpf/map_lpm_trie.rst index 74d64a30f500..f9cd579496c9 100644 --- a/Documentation/bpf/map_lpm_trie.rst +++ b/Documentation/bpf/map_lpm_trie.rst @@ -17,7 +17,7 @@ significant byte. LPM tries may be created with a maximum prefix length that is a multiple of 8, in the range from 8 to 2048. The key used for lookup and update -operations is a ``struct bpf_lpm_trie_key``, extended by +operations is a ``struct bpf_lpm_trie_key_u8``, extended by ``max_prefixlen/8`` bytes. - For IPv4 addresses the data length is 4 bytes diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index d2e6c5fcec01..a241f407c234 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -77,12 +77,29 @@ struct bpf_insn { __s32 imm; /* signed immediate constant */ }; -/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */ +/* Deprecated: use struct bpf_lpm_trie_key_u8 (when the "data" member is needed for + * byte access) or struct bpf_lpm_trie_key_hdr (when using an alternative type for + * the trailing flexible array member) instead. + */ struct bpf_lpm_trie_key { __u32 prefixlen; /* up to 32 for AF_INET, 128 for AF_INET6 */ __u8 data[0]; /* Arbitrary size */ }; +/* Header for bpf_lpm_trie_key structs */ +struct bpf_lpm_trie_key_hdr { + __u32 prefixlen; +}; + +/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry, with trailing byte array. */ +struct bpf_lpm_trie_key_u8 { + union { + struct bpf_lpm_trie_key_hdr hdr; + __u32 prefixlen; + }; + __u8 data[]; /* Arbitrary size */ +}; + struct bpf_cgroup_storage_key { __u64 cgroup_inode_id; /* cgroup inode id */ __u32 attach_type; /* program attach type (enum bpf_attach_type) */ diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c index b32be680da6c..050fe1ebf0f7 100644 --- a/kernel/bpf/lpm_trie.c +++ b/kernel/bpf/lpm_trie.c @@ -164,13 +164,13 @@ static inline int extract_bit(const u8 *data, size_t index) */ static size_t longest_prefix_match(const struct lpm_trie *trie, const struct lpm_trie_node *node, - const struct bpf_lpm_trie_key *key) + const struct bpf_lpm_trie_key_u8 *key) { u32 limit = min(node->prefixlen, key->prefixlen); u32 prefixlen = 0, i = 0; BUILD_BUG_ON(offsetof(struct lpm_trie_node, data) % sizeof(u32)); - BUILD_BUG_ON(offsetof(struct bpf_lpm_trie_key, data) % sizeof(u32)); + BUILD_BUG_ON(offsetof(struct bpf_lpm_trie_key_u8, data) % sizeof(u32)); #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(CONFIG_64BIT) @@ -229,7 +229,7 @@ static void *trie_lookup_elem(struct bpf_map *map, void *_key) { struct lpm_trie *trie = container_of(map, struct lpm_trie, map); struct lpm_trie_node *node, *found = NULL; - struct bpf_lpm_trie_key *key = _key; + struct bpf_lpm_trie_key_u8 *key = _key; if (key->prefixlen > trie->max_prefixlen) return NULL; @@ -309,7 +309,7 @@ static long trie_update_elem(struct bpf_map *map, struct lpm_trie *trie = container_of(map, struct lpm_trie, map); struct lpm_trie_node *node, *im_node = NULL, *new_node = NULL; struct lpm_trie_node __rcu **slot; - struct bpf_lpm_trie_key *key = _key; + struct bpf_lpm_trie_key_u8 *key = _key; unsigned long irq_flags; unsigned int next_bit; size_t matchlen = 0; @@ -437,7 +437,7 @@ out: static long trie_delete_elem(struct bpf_map *map, void *_key) { struct lpm_trie *trie = container_of(map, struct lpm_trie, map); - struct bpf_lpm_trie_key *key = _key; + struct bpf_lpm_trie_key_u8 *key = _key; struct lpm_trie_node __rcu **trim, **trim2; struct lpm_trie_node *node, *parent; unsigned long irq_flags; @@ -536,7 +536,7 @@ out: sizeof(struct lpm_trie_node)) #define LPM_VAL_SIZE_MIN 1 -#define LPM_KEY_SIZE(X) (sizeof(struct bpf_lpm_trie_key) + (X)) +#define LPM_KEY_SIZE(X) (sizeof(struct bpf_lpm_trie_key_u8) + (X)) #define LPM_KEY_SIZE_MAX LPM_KEY_SIZE(LPM_DATA_SIZE_MAX) #define LPM_KEY_SIZE_MIN LPM_KEY_SIZE(LPM_DATA_SIZE_MIN) @@ -565,7 +565,7 @@ static struct bpf_map *trie_alloc(union bpf_attr *attr) /* copy mandatory map attributes */ bpf_map_init_from_attr(&trie->map, attr); trie->data_size = attr->key_size - - offsetof(struct bpf_lpm_trie_key, data); + offsetof(struct bpf_lpm_trie_key_u8, data); trie->max_prefixlen = trie->data_size * 8; spin_lock_init(&trie->lock); @@ -616,7 +616,7 @@ static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key) { struct lpm_trie_node *node, *next_node = NULL, *parent, *search_root; struct lpm_trie *trie = container_of(map, struct lpm_trie, map); - struct bpf_lpm_trie_key *key = _key, *next_key = _next_key; + struct bpf_lpm_trie_key_u8 *key = _key, *next_key = _next_key; struct lpm_trie_node **node_stack = NULL; int err = 0, stack_ptr = -1; unsigned int next_bit; @@ -703,7 +703,7 @@ find_leftmost: } do_copy: next_key->prefixlen = next_node->prefixlen; - memcpy((void *)next_key + offsetof(struct bpf_lpm_trie_key, data), + memcpy((void *)next_key + offsetof(struct bpf_lpm_trie_key_u8, data), next_node->data, trie->data_size); free_stack: kfree(node_stack); @@ -715,7 +715,7 @@ static int trie_check_btf(const struct bpf_map *map, const struct btf_type *key_type, const struct btf_type *value_type) { - /* Keys must have struct bpf_lpm_trie_key embedded. */ + /* Keys must have struct bpf_lpm_trie_key_u8 embedded. */ return BTF_INFO_KIND(key_type->info) != BTF_KIND_STRUCT ? -EINVAL : 0; } diff --git a/samples/bpf/map_perf_test_user.c b/samples/bpf/map_perf_test_user.c index d2fbcf963cdf..07ff471ed6ae 100644 --- a/samples/bpf/map_perf_test_user.c +++ b/samples/bpf/map_perf_test_user.c @@ -370,7 +370,7 @@ static void run_perf_test(int tasks) static void fill_lpm_trie(void) { - struct bpf_lpm_trie_key *key; + struct bpf_lpm_trie_key_u8 *key; unsigned long value = 0; unsigned int i; int r; diff --git a/samples/bpf/xdp_router_ipv4_user.c b/samples/bpf/xdp_router_ipv4_user.c index 9d41db09c480..266fdd0b025d 100644 --- a/samples/bpf/xdp_router_ipv4_user.c +++ b/samples/bpf/xdp_router_ipv4_user.c @@ -91,7 +91,7 @@ static int recv_msg(struct sockaddr_nl sock_addr, int sock) static void read_route(struct nlmsghdr *nh, int nll) { char dsts[24], gws[24], ifs[16], dsts_len[24], metrics[24]; - struct bpf_lpm_trie_key *prefix_key; + struct bpf_lpm_trie_key_u8 *prefix_key; struct rtattr *rt_attr; struct rtmsg *rt_msg; int rtm_family; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index d2e6c5fcec01..a241f407c234 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -77,12 +77,29 @@ struct bpf_insn { __s32 imm; /* signed immediate constant */ }; -/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */ +/* Deprecated: use struct bpf_lpm_trie_key_u8 (when the "data" member is needed for + * byte access) or struct bpf_lpm_trie_key_hdr (when using an alternative type for + * the trailing flexible array member) instead. + */ struct bpf_lpm_trie_key { __u32 prefixlen; /* up to 32 for AF_INET, 128 for AF_INET6 */ __u8 data[0]; /* Arbitrary size */ }; +/* Header for bpf_lpm_trie_key structs */ +struct bpf_lpm_trie_key_hdr { + __u32 prefixlen; +}; + +/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry, with trailing byte array. */ +struct bpf_lpm_trie_key_u8 { + union { + struct bpf_lpm_trie_key_hdr hdr; + __u32 prefixlen; + }; + __u8 data[]; /* Arbitrary size */ +}; + struct bpf_cgroup_storage_key { __u64 cgroup_inode_id; /* cgroup inode id */ __u32 attach_type; /* program attach type (enum bpf_attach_type) */ diff --git a/tools/testing/selftests/bpf/progs/map_ptr_kern.c b/tools/testing/selftests/bpf/progs/map_ptr_kern.c index 3325da17ec81..efaf622c28dd 100644 --- a/tools/testing/selftests/bpf/progs/map_ptr_kern.c +++ b/tools/testing/selftests/bpf/progs/map_ptr_kern.c @@ -316,7 +316,7 @@ struct lpm_trie { } __attribute__((preserve_access_index)); struct lpm_key { - struct bpf_lpm_trie_key trie_key; + struct bpf_lpm_trie_key_hdr trie_key; __u32 data; }; diff --git a/tools/testing/selftests/bpf/test_lpm_map.c b/tools/testing/selftests/bpf/test_lpm_map.c index c028d621c744..d98c72dc563e 100644 --- a/tools/testing/selftests/bpf/test_lpm_map.c +++ b/tools/testing/selftests/bpf/test_lpm_map.c @@ -211,7 +211,7 @@ static void test_lpm_map(int keysize) volatile size_t n_matches, n_matches_after_delete; size_t i, j, n_nodes, n_lookups; struct tlpm_node *t, *list = NULL; - struct bpf_lpm_trie_key *key; + struct bpf_lpm_trie_key_u8 *key; uint8_t *data, *value; int r, map; @@ -331,8 +331,8 @@ static void test_lpm_map(int keysize) static void test_lpm_ipaddr(void) { LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); - struct bpf_lpm_trie_key *key_ipv4; - struct bpf_lpm_trie_key *key_ipv6; + struct bpf_lpm_trie_key_u8 *key_ipv4; + struct bpf_lpm_trie_key_u8 *key_ipv6; size_t key_size_ipv4; size_t key_size_ipv6; int map_fd_ipv4; @@ -423,7 +423,7 @@ static void test_lpm_ipaddr(void) static void test_lpm_delete(void) { LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); - struct bpf_lpm_trie_key *key; + struct bpf_lpm_trie_key_u8 *key; size_t key_size; int map_fd; __u64 value; @@ -532,7 +532,7 @@ static void test_lpm_delete(void) static void test_lpm_get_next_key(void) { LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC); - struct bpf_lpm_trie_key *key_p, *next_key_p; + struct bpf_lpm_trie_key_u8 *key_p, *next_key_p; size_t key_size; __u32 value = 0; int map_fd; @@ -693,9 +693,9 @@ static void *lpm_test_command(void *arg) { int i, j, ret, iter, key_size; struct lpm_mt_test_info *info = arg; - struct bpf_lpm_trie_key *key_p; + struct bpf_lpm_trie_key_u8 *key_p; - key_size = sizeof(struct bpf_lpm_trie_key) + sizeof(__u32); + key_size = sizeof(*key_p) + sizeof(__u32); key_p = alloca(key_size); for (iter = 0; iter < info->iter; iter++) for (i = 0; i < MAX_TEST_KEYS; i++) { @@ -717,7 +717,7 @@ static void *lpm_test_command(void *arg) ret = bpf_map_lookup_elem(info->map_fd, key_p, &value); assert(ret == 0 || errno == ENOENT); } else { - struct bpf_lpm_trie_key *next_key_p = alloca(key_size); + struct bpf_lpm_trie_key_u8 *next_key_p = alloca(key_size); ret = bpf_map_get_next_key(info->map_fd, key_p, next_key_p); assert(ret == 0 || errno == ENOENT || errno == ENOMEM); } @@ -752,7 +752,7 @@ static void test_lpm_multi_thread(void) /* create a trie */ value_size = sizeof(__u32); - key_size = sizeof(struct bpf_lpm_trie_key) + value_size; + key_size = sizeof(struct bpf_lpm_trie_key_hdr) + value_size; map_fd = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, NULL, key_size, value_size, 100, &opts); /* create 4 threads to test update, delete, lookup and get_next_key */ From 3644d285462a60c80ac225d508fcfe705640d2b4 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Wed, 28 Feb 2024 22:45:19 -0800 Subject: [PATCH 1658/2255] libbpf: Set btf_value_type_id of struct bpf_map for struct_ops. For a struct_ops map, btf_value_type_id is the type ID of it's struct type. This value is required by bpftool to generate skeleton including pointers of shadow types. The code generator gets the type ID from bpf_map__btf_value_type_id() in order to get the type information of the struct type of a map. Signed-off-by: Kui-Feng Lee Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240229064523.2091270-2-thinker.li@gmail.com --- tools/lib/bpf/libbpf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 01f407591a92..c759628f4250 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1229,6 +1229,7 @@ static int init_struct_ops_maps(struct bpf_object *obj, const char *sec_name, map->name = strdup(var_name); if (!map->name) return -ENOMEM; + map->btf_value_type_id = type_id; map->def.type = BPF_MAP_TYPE_STRUCT_OPS; map->def.key_size = sizeof(int); @@ -4857,6 +4858,10 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b create_attr.btf_value_type_id = 0; map->btf_key_type_id = 0; map->btf_value_type_id = 0; + break; + case BPF_MAP_TYPE_STRUCT_OPS: + create_attr.btf_value_type_id = 0; + break; default: break; } From 69e4a9d2b3f5adf5af4feeab0a9f505da971265a Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Wed, 28 Feb 2024 22:45:20 -0800 Subject: [PATCH 1659/2255] libbpf: Convert st_ops->data to shadow type. Convert st_ops->data to the shadow type of the struct_ops map. The shadow type of a struct_ops type is a variant of the original struct type providing a way to access/change the values in the maps of the struct_ops type. bpf_map__initial_value() will return st_ops->data for struct_ops types. The skeleton is going to use it as the pointer to the shadow type of the original struct type. One of the main differences between the original struct type and the shadow type is that all function pointers of the shadow type are converted to pointers of struct bpf_program. Users can replace these bpf_program pointers with other BPF programs. The st_ops->progs[] will be updated before updating the value of a map to reflect the changes made by users. Signed-off-by: Kui-Feng Lee Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240229064523.2091270-3-thinker.li@gmail.com --- tools/lib/bpf/libbpf.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index c759628f4250..6c2979f1b471 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1014,6 +1014,19 @@ static bool bpf_map__is_struct_ops(const struct bpf_map *map) return map->def.type == BPF_MAP_TYPE_STRUCT_OPS; } +static bool is_valid_st_ops_program(struct bpf_object *obj, + const struct bpf_program *prog) +{ + int i; + + for (i = 0; i < obj->nr_programs; i++) { + if (&obj->programs[i] == prog) + return prog->type == BPF_PROG_TYPE_STRUCT_OPS; + } + + return false; +} + /* Init the map's fields that depend on kern_btf */ static int bpf_map__init_kern_struct_ops(struct bpf_map *map) { @@ -1102,9 +1115,16 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map) if (btf_is_ptr(mtype)) { struct bpf_program *prog; - prog = st_ops->progs[i]; + /* Update the value from the shadow type */ + prog = *(void **)mdata; + st_ops->progs[i] = prog; if (!prog) continue; + if (!is_valid_st_ops_program(obj, prog)) { + pr_warn("struct_ops init_kern %s: member %s is not a struct_ops program\n", + map->name, mname); + return -ENOTSUP; + } kern_mtype = skip_mods_and_typedefs(kern_btf, kern_mtype->type, @@ -9310,7 +9330,9 @@ static struct bpf_map *find_struct_ops_map_by_offset(struct bpf_object *obj, return NULL; } -/* Collect the reloc from ELF and populate the st_ops->progs[] */ +/* Collect the reloc from ELF, populate the st_ops->progs[], and update + * st_ops->data for shadow type. + */ static int bpf_object__collect_st_ops_relos(struct bpf_object *obj, Elf64_Shdr *shdr, Elf_Data *data) { @@ -9424,6 +9446,14 @@ static int bpf_object__collect_st_ops_relos(struct bpf_object *obj, } st_ops->progs[member_idx] = prog; + + /* st_ops->data will be exposed to users, being returned by + * bpf_map__initial_value() as a pointer to the shadow + * type. All function pointers in the original struct type + * should be converted to a pointer to struct bpf_program + * in the shadow type. + */ + *((struct bpf_program **)(st_ops->data + moff)) = prog; } return 0; @@ -9882,6 +9912,12 @@ int bpf_map__set_initial_value(struct bpf_map *map, void *bpf_map__initial_value(struct bpf_map *map, size_t *psize) { + if (bpf_map__is_struct_ops(map)) { + if (psize) + *psize = map->def.value_size; + return map->st_ops->data; + } + if (!map->mmaped) return NULL; *psize = map->def.value_size; From a7b0fa352eafef95bd0d736ca94965d3f884ad18 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Wed, 28 Feb 2024 22:45:21 -0800 Subject: [PATCH 1660/2255] bpftool: Generated shadow variables for struct_ops maps. Declares and defines a pointer of the shadow type for each struct_ops map. The code generator will create an anonymous struct type as the shadow type for each struct_ops map. The shadow type is translated from the original struct type of the map. The user of the skeleton use pointers of them to access the values of struct_ops maps. However, shadow types only supports certain types of fields, including scalar types and function pointers. Any fields of unsupported types are translated into an array of characters to occupy the space of the original field. Function pointers are translated into pointers of the struct bpf_program. Additionally, padding fields are generated to occupy the space between two consecutive fields. The pointers of shadow types of struct_osp maps are initialized when *__open_opts() in skeletons are called. For a map called FOO, the user can access it through the pointer at skel->struct_ops.FOO. Signed-off-by: Kui-Feng Lee Signed-off-by: Andrii Nakryiko Reviewed-by: Quentin Monnet Link: https://lore.kernel.org/bpf/20240229064523.2091270-4-thinker.li@gmail.com --- tools/bpf/bpftool/gen.c | 237 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index a9334c57e859..1f579eacd9d4 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -55,6 +55,20 @@ static bool str_has_suffix(const char *str, const char *suffix) return true; } +static const struct btf_type * +resolve_func_ptr(const struct btf *btf, __u32 id, __u32 *res_id) +{ + const struct btf_type *t; + + t = skip_mods_and_typedefs(btf, id, NULL); + if (!btf_is_ptr(t)) + return NULL; + + t = skip_mods_and_typedefs(btf, t->type, res_id); + + return btf_is_func_proto(t) ? t : NULL; +} + static void get_obj_name(char *name, const char *file) { char file_copy[PATH_MAX]; @@ -909,6 +923,207 @@ codegen_progs_skeleton(struct bpf_object *obj, size_t prog_cnt, bool populate_li } } +static int walk_st_ops_shadow_vars(struct btf *btf, const char *ident, + const struct btf_type *map_type, __u32 map_type_id) +{ + LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts, .indent_level = 3); + const struct btf_type *member_type; + __u32 offset, next_offset = 0; + const struct btf_member *m; + struct btf_dump *d = NULL; + const char *member_name; + __u32 member_type_id; + int i, err = 0, n; + int size; + + d = btf_dump__new(btf, codegen_btf_dump_printf, NULL, NULL); + if (!d) + return -errno; + + n = btf_vlen(map_type); + for (i = 0, m = btf_members(map_type); i < n; i++, m++) { + member_type = skip_mods_and_typedefs(btf, m->type, &member_type_id); + member_name = btf__name_by_offset(btf, m->name_off); + + offset = m->offset / 8; + if (next_offset < offset) + printf("\t\t\tchar __padding_%d[%d];\n", i, offset - next_offset); + + switch (btf_kind(member_type)) { + case BTF_KIND_INT: + case BTF_KIND_FLOAT: + case BTF_KIND_ENUM: + case BTF_KIND_ENUM64: + /* scalar type */ + printf("\t\t\t"); + opts.field_name = member_name; + err = btf_dump__emit_type_decl(d, member_type_id, &opts); + if (err) { + p_err("Failed to emit type declaration for %s: %d", member_name, err); + goto out; + } + printf(";\n"); + + size = btf__resolve_size(btf, member_type_id); + if (size < 0) { + p_err("Failed to resolve size of %s: %d\n", member_name, size); + err = size; + goto out; + } + + next_offset = offset + size; + break; + + case BTF_KIND_PTR: + if (resolve_func_ptr(btf, m->type, NULL)) { + /* Function pointer */ + printf("\t\t\tstruct bpf_program *%s;\n", member_name); + + next_offset = offset + sizeof(void *); + break; + } + /* All pointer types are unsupported except for + * function pointers. + */ + fallthrough; + + default: + /* Unsupported types + * + * Types other than scalar types and function + * pointers are currently not supported in order to + * prevent conflicts in the generated code caused + * by multiple definitions. For instance, if the + * struct type FOO is used in a struct_ops map, + * bpftool has to generate definitions for FOO, + * which may result in conflicts if FOO is defined + * in different skeleton files. + */ + size = btf__resolve_size(btf, member_type_id); + if (size < 0) { + p_err("Failed to resolve size of %s: %d\n", member_name, size); + err = size; + goto out; + } + printf("\t\t\tchar __unsupported_%d[%d];\n", i, size); + + next_offset = offset + size; + break; + } + } + + /* Cannot fail since it must be a struct type */ + size = btf__resolve_size(btf, map_type_id); + if (next_offset < (__u32)size) + printf("\t\t\tchar __padding_end[%d];\n", size - next_offset); + +out: + btf_dump__free(d); + + return err; +} + +/* Generate the pointer of the shadow type for a struct_ops map. + * + * This function adds a pointer of the shadow type for a struct_ops map. + * The members of a struct_ops map can be exported through a pointer to a + * shadow type. The user can access these members through the pointer. + * + * A shadow type includes not all members, only members of some types. + * They are scalar types and function pointers. The function pointers are + * translated to the pointer of the struct bpf_program. The scalar types + * are translated to the original type without any modifiers. + * + * Unsupported types will be translated to a char array to occupy the same + * space as the original field, being renamed as __unsupported_*. The user + * should treat these fields as opaque data. + */ +static int gen_st_ops_shadow_type(const char *obj_name, struct btf *btf, const char *ident, + const struct bpf_map *map) +{ + const struct btf_type *map_type; + const char *type_name; + __u32 map_type_id; + int err; + + map_type_id = bpf_map__btf_value_type_id(map); + if (map_type_id == 0) + return -EINVAL; + map_type = btf__type_by_id(btf, map_type_id); + if (!map_type) + return -EINVAL; + + type_name = btf__name_by_offset(btf, map_type->name_off); + + printf("\t\tstruct %s__%s__%s {\n", obj_name, ident, type_name); + + err = walk_st_ops_shadow_vars(btf, ident, map_type, map_type_id); + if (err) + return err; + + printf("\t\t} *%s;\n", ident); + + return 0; +} + +static int gen_st_ops_shadow(const char *obj_name, struct btf *btf, struct bpf_object *obj) +{ + int err, st_ops_cnt = 0; + struct bpf_map *map; + char ident[256]; + + if (!btf) + return 0; + + /* Generate the pointers to shadow types of + * struct_ops maps. + */ + bpf_object__for_each_map(map, obj) { + if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS) + continue; + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + + if (st_ops_cnt == 0) /* first struct_ops map */ + printf("\tstruct {\n"); + st_ops_cnt++; + + err = gen_st_ops_shadow_type(obj_name, btf, ident, map); + if (err) + return err; + } + + if (st_ops_cnt) + printf("\t} struct_ops;\n"); + + return 0; +} + +/* Generate the code to initialize the pointers of shadow types. */ +static void gen_st_ops_shadow_init(struct btf *btf, struct bpf_object *obj) +{ + struct bpf_map *map; + char ident[256]; + + if (!btf) + return; + + /* Initialize the pointers to_ops shadow types of + * struct_ops maps. + */ + bpf_object__for_each_map(map, obj) { + if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS) + continue; + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + codegen("\ + \n\ + obj->struct_ops.%1$s = bpf_map__initial_value(obj->maps.%1$s, NULL);\n\ + \n\ + ", ident); + } +} + static int do_skeleton(int argc, char **argv) { char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")]; @@ -1052,6 +1267,11 @@ static int do_skeleton(int argc, char **argv) printf("\t} maps;\n"); } + btf = bpf_object__btf(obj); + err = gen_st_ops_shadow(obj_name, btf, obj); + if (err) + goto out; + if (prog_cnt) { printf("\tstruct {\n"); bpf_object__for_each_program(prog, obj) { @@ -1075,7 +1295,6 @@ static int do_skeleton(int argc, char **argv) printf("\t} links;\n"); } - btf = bpf_object__btf(obj); if (btf) { err = codegen_datasecs(obj, obj_name); if (err) @@ -1133,6 +1352,12 @@ static int do_skeleton(int argc, char **argv) if (err) \n\ goto err_out; \n\ \n\ + ", obj_name); + + gen_st_ops_shadow_init(btf, obj); + + codegen("\ + \n\ return obj; \n\ err_out: \n\ %1$s__destroy(obj); \n\ @@ -1442,6 +1667,10 @@ static int do_subskeleton(int argc, char **argv) printf("\t} maps;\n"); } + err = gen_st_ops_shadow(obj_name, btf, obj); + if (err) + goto out; + if (prog_cnt) { printf("\tstruct {\n"); bpf_object__for_each_program(prog, obj) { @@ -1553,6 +1782,12 @@ static int do_subskeleton(int argc, char **argv) if (err) \n\ goto err; \n\ \n\ + "); + + gen_st_ops_shadow_init(btf, obj); + + codegen("\ + \n\ return obj; \n\ err: \n\ %1$s__destroy(obj); \n\ From f2e81192e07e87897ff1296c96775eceea8f582a Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Wed, 28 Feb 2024 22:45:22 -0800 Subject: [PATCH 1661/2255] bpftool: Add an example for struct_ops map and shadow type. The example in bpftool-gen.8 explains how to use the pointer of the shadow type to change the value of a field of a struct_ops map. Signed-off-by: Kui-Feng Lee Signed-off-by: Andrii Nakryiko Reviewed-by: Quentin Monnet Link: https://lore.kernel.org/bpf/20240229064523.2091270-5-thinker.li@gmail.com --- .../bpf/bpftool/Documentation/bpftool-gen.rst | 58 +++++++++++++++++-- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-gen.rst b/tools/bpf/bpftool/Documentation/bpftool-gen.rst index 5006e724d1bc..5e60825818dd 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-gen.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-gen.rst @@ -257,18 +257,48 @@ EXAMPLES return 0; } -This is example BPF application with two BPF programs and a mix of BPF maps -and global variables. Source code is split across two source code files. +**$ cat example3.bpf.c** + +:: + + #include + #include + #include + /* This header file is provided by the bpf_testmod module. */ + #include "bpf_testmod.h" + + int test_2_result = 0; + + /* bpf_Testmod.ko calls this function, passing a "4" + * and testmod_map->data. + */ + SEC("struct_ops/test_2") + void BPF_PROG(test_2, int a, int b) + { + test_2_result = a + b; + } + + SEC(".struct_ops") + struct bpf_testmod_ops testmod_map = { + .test_2 = (void *)test_2, + .data = 0x1, + }; + +This is example BPF application with three BPF programs and a mix of BPF +maps and global variables. Source code is split across three source code +files. **$ clang --target=bpf -g example1.bpf.c -o example1.bpf.o** **$ clang --target=bpf -g example2.bpf.c -o example2.bpf.o** -**$ bpftool gen object example.bpf.o example1.bpf.o example2.bpf.o** +**$ clang --target=bpf -g example3.bpf.c -o example3.bpf.o** -This set of commands compiles *example1.bpf.c* and *example2.bpf.c* -individually and then statically links respective object files into the final -BPF ELF object file *example.bpf.o*. +**$ bpftool gen object example.bpf.o example1.bpf.o example2.bpf.o example3.bpf.o** + +This set of commands compiles *example1.bpf.c*, *example2.bpf.c* and +*example3.bpf.c* individually and then statically links respective object +files into the final BPF ELF object file *example.bpf.o*. **$ bpftool gen skeleton example.bpf.o name example | tee example.skel.h** @@ -291,7 +321,15 @@ BPF ELF object file *example.bpf.o*. struct bpf_map *data; struct bpf_map *bss; struct bpf_map *my_map; + struct bpf_map *testmod_map; } maps; + struct { + struct example__testmod_map__bpf_testmod_ops { + const struct bpf_program *test_1; + const struct bpf_program *test_2; + int data; + } *testmod_map; + } struct_ops; struct { struct bpf_program *handle_sys_enter; struct bpf_program *handle_sys_exit; @@ -304,6 +342,7 @@ BPF ELF object file *example.bpf.o*. struct { int x; } data; + int test_2_result; } *bss; struct example__data { _Bool global_flag; @@ -342,10 +381,16 @@ BPF ELF object file *example.bpf.o*. skel->rodata->param1 = 128; + /* Change the value through the pointer of shadow type */ + skel->struct_ops.testmod_map->data = 13; + err = example__load(skel); if (err) goto cleanup; + /* The result of the function test_2() */ + printf("test_2_result: %d\n", skel->bss->test_2_result); + err = example__attach(skel); if (err) goto cleanup; @@ -372,6 +417,7 @@ BPF ELF object file *example.bpf.o*. :: + test_2_result: 17 my_map name: my_map sys_enter prog FD: 8 my_static_var: 7 From 0623e73317940d052216fb6eef4efd55a0a7f602 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Wed, 28 Feb 2024 22:45:23 -0800 Subject: [PATCH 1662/2255] selftests/bpf: Test if shadow types work correctly. Change the values of fields, including scalar types and function pointers, and check if the struct_ops map works as expected. The test changes the field "test_2" of "testmod_1" from the pointer to test_2() to pointer to test_3() and the field "data" to 13. The function test_2() and test_3() both compute a new value for "test_2_result", but in different way. By checking the value of "test_2_result", it ensures the struct_ops map works as expected with changes through shadow types. Signed-off-by: Kui-Feng Lee Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240229064523.2091270-6-thinker.li@gmail.com --- .../selftests/bpf/bpf_testmod/bpf_testmod.c | 11 ++++++++++- .../selftests/bpf/bpf_testmod/bpf_testmod.h | 8 ++++++++ .../bpf/prog_tests/test_struct_ops_module.c | 19 +++++++++++++++---- .../selftests/bpf/progs/struct_ops_module.c | 8 ++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 66787e99ba1b..098ddd067224 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -539,6 +539,15 @@ static int bpf_testmod_ops_init_member(const struct btf_type *t, const struct btf_member *member, void *kdata, const void *udata) { + if (member->offset == offsetof(struct bpf_testmod_ops, data) * 8) { + /* For data fields, this function has to copy it and return + * 1 to indicate that the data has been handled by the + * struct_ops type, or the verifier will reject the map if + * the value of the data field is not zero. + */ + ((struct bpf_testmod_ops *)kdata)->data = ((struct bpf_testmod_ops *)udata)->data; + return 1; + } return 0; } @@ -559,7 +568,7 @@ static int bpf_dummy_reg(void *kdata) * initialized, so we need to check for NULL. */ if (ops->test_2) - ops->test_2(4, 3); + ops->test_2(4, ops->data); return 0; } diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h index c3b0cf788f9f..971458acfac3 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h @@ -35,6 +35,14 @@ struct bpf_testmod_ops { void (*test_2)(int a, int b); /* Used to test nullable arguments. */ int (*test_maybe_null)(int dummy, struct task_struct *task); + + /* The following fields are used to test shadow copies. */ + char onebyte; + struct { + int a; + int b; + } unsupported; + int data; }; #endif /* _BPF_TESTMOD_H */ diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c index 8d833f0c7580..7d6facf46ebb 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c +++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c @@ -32,17 +32,23 @@ cleanup: static void test_struct_ops_load(void) { - DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts); struct struct_ops_module *skel; struct bpf_map_info info = {}; struct bpf_link *link; int err; u32 len; - skel = struct_ops_module__open_opts(&opts); + skel = struct_ops_module__open(); if (!ASSERT_OK_PTR(skel, "struct_ops_module_open")) return; + skel->struct_ops.testmod_1->data = 13; + skel->struct_ops.testmod_1->test_2 = skel->progs.test_3; + /* Since test_2() is not being used, it should be disabled from + * auto-loading, or it will fail to load. + */ + bpf_program__set_autoload(skel->progs.test_2, false); + err = struct_ops_module__load(skel); if (!ASSERT_OK(err, "struct_ops_module_load")) goto cleanup; @@ -56,8 +62,13 @@ static void test_struct_ops_load(void) link = bpf_map__attach_struct_ops(skel->maps.testmod_1); ASSERT_OK_PTR(link, "attach_test_mod_1"); - /* test_2() will be called from bpf_dummy_reg() in bpf_testmod.c */ - ASSERT_EQ(skel->bss->test_2_result, 7, "test_2_result"); + /* test_3() will be called from bpf_dummy_reg() in bpf_testmod.c + * + * In bpf_testmod.c it will pass 4 and 13 (the value of data) to + * .test_2. So, the value of test_2_result should be 20 (4 + 13 + + * 3). + */ + ASSERT_EQ(skel->bss->test_2_result, 20, "check_shadow_variables"); bpf_link__destroy(link); diff --git a/tools/testing/selftests/bpf/progs/struct_ops_module.c b/tools/testing/selftests/bpf/progs/struct_ops_module.c index b78746b3cef3..25952fa09348 100644 --- a/tools/testing/selftests/bpf/progs/struct_ops_module.c +++ b/tools/testing/selftests/bpf/progs/struct_ops_module.c @@ -21,9 +21,17 @@ void BPF_PROG(test_2, int a, int b) test_2_result = a + b; } +SEC("struct_ops/test_3") +int BPF_PROG(test_3, int a, int b) +{ + test_2_result = a + b + 3; + return a + b + 3; +} + SEC(".struct_ops.link") struct bpf_testmod_ops testmod_1 = { .test_1 = (void *)test_1, .test_2 = (void *)test_2, + .data = 0x1, }; From 096361b15577a583afcc28179a08c75cf95e9dae Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:25 +0000 Subject: [PATCH 1663/2255] ipv6: add ipv6_devconf_read_txrx cacheline_group IPv6 TX and RX fast path use the following fields: - disable_ipv6 - hop_limit - mtu6 - forwarding - disable_policy - proxy_ndp Place them in a group to increase data locality. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/ipv6.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index ef3aa060a289..383a0ea2ab91 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -3,6 +3,7 @@ #define _IPV6_H #include +#include #define ipv6_optlen(p) (((p)->hdrlen+1) << 3) #define ipv6_authlen(p) (((p)->hdrlen+2) << 2) @@ -10,9 +11,16 @@ * This structure contains configuration options per IPv6 link. */ struct ipv6_devconf { - __s32 forwarding; + /* RX & TX fastpath fields. */ + __cacheline_group_begin(ipv6_devconf_read_txrx); + __s32 disable_ipv6; __s32 hop_limit; __s32 mtu6; + __s32 forwarding; + __s32 disable_policy; + __s32 proxy_ndp; + __cacheline_group_end(ipv6_devconf_read_txrx); + __s32 accept_ra; __s32 accept_redirects; __s32 autoconf; @@ -45,7 +53,6 @@ struct ipv6_devconf { __s32 accept_ra_rt_info_max_plen; #endif #endif - __s32 proxy_ndp; __s32 accept_source_route; __s32 accept_ra_from_local; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD @@ -55,7 +62,6 @@ struct ipv6_devconf { #ifdef CONFIG_IPV6_MROUTE atomic_t mc_forwarding; #endif - __s32 disable_ipv6; __s32 drop_unicast_in_l2_multicast; __s32 accept_dad; __s32 force_tllao; @@ -76,7 +82,6 @@ struct ipv6_devconf { #endif __u32 enhanced_dad; __u32 addr_gen_mode; - __s32 disable_policy; __s32 ndisc_tclass; __s32 rpl_seg_enabled; __u32 ioam6_id; From d289ab65b89c1d4d88417cb6c03e923f21f95fae Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:26 +0000 Subject: [PATCH 1664/2255] ipv6: annotate data-races around cnf.disable_ipv6 disable_ipv6 is read locklessly, add appropriate READ_ONCE() and WRITE_ONCE() annotations. v2: do not preload net before rtnl_trylock() in addrconf_disable_ipv6() (Jiri) Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 9 +++++---- net/ipv6/ip6_input.c | 4 ++-- net/ipv6/ip6_output.c | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9e949403c136..c965400fb934 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4214,7 +4214,7 @@ static void addrconf_dad_work(struct work_struct *w) if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) && ipv6_addr_equal(&ifp->addr, &addr)) { /* DAD failed for link-local based on MAC */ - idev->cnf.disable_ipv6 = 1; + WRITE_ONCE(idev->cnf.disable_ipv6, 1); pr_info("%s: IPv6 being disabled!\n", ifp->idev->dev->name); @@ -6389,7 +6389,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf) idev = __in6_dev_get(dev); if (idev) { int changed = (!idev->cnf.disable_ipv6) ^ (!newf); - idev->cnf.disable_ipv6 = newf; + + WRITE_ONCE(idev->cnf.disable_ipv6, newf); if (changed) dev_disable_change(idev); } @@ -6406,7 +6407,7 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf) net = (struct net *)table->extra2; old = *p; - *p = newf; + WRITE_ONCE(*p, newf); if (p == &net->ipv6.devconf_dflt->disable_ipv6) { rtnl_unlock(); @@ -6414,7 +6415,7 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf) } if (p == &net->ipv6.devconf_all->disable_ipv6) { - net->ipv6.devconf_dflt->disable_ipv6 = newf; + WRITE_ONCE(net->ipv6.devconf_dflt->disable_ipv6, newf); addrconf_disable_change(net, newf); } else if ((!newf) ^ (!old)) dev_disable_change((struct inet6_dev *)table->extra1); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index b8378814532c..1ba97933c74f 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -168,9 +168,9 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, SKB_DR_SET(reason, NOT_SPECIFIED); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || - !idev || unlikely(idev->cnf.disable_ipv6)) { + !idev || unlikely(READ_ONCE(idev->cnf.disable_ipv6))) { __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); - if (idev && unlikely(idev->cnf.disable_ipv6)) + if (idev && unlikely(READ_ONCE(idev->cnf.disable_ipv6))) SKB_DR_SET(reason, IPV6DISABLED); goto drop; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 31b86fe661aa..0559bd000585 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -234,7 +234,7 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb) skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; - if (unlikely(idev->cnf.disable_ipv6)) { + if (unlikely(READ_ONCE(idev->cnf.disable_ipv6))) { IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); kfree_skb_reason(skb, SKB_DROP_REASON_IPV6DISABLED); return 0; From 553ced03b227c99f0bf68d86f7b45ed7125563f2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:27 +0000 Subject: [PATCH 1665/2255] ipv6: addrconf_disable_ipv6() optimization Writing over /proc/sys/net/ipv6/conf/default/disable_ipv6 does not need to hold RTNL. v3: remove a wrong change (Jakub Kicinski feedback) Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c965400fb934..6975685f55ea 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -6399,21 +6399,20 @@ static void addrconf_disable_change(struct net *net, __s32 newf) static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf) { - struct net *net; + struct net *net = (struct net *)table->extra2; int old; + if (p == &net->ipv6.devconf_dflt->disable_ipv6) { + WRITE_ONCE(*p, newf); + return 0; + } + if (!rtnl_trylock()) return restart_syscall(); - net = (struct net *)table->extra2; old = *p; WRITE_ONCE(*p, newf); - if (p == &net->ipv6.devconf_dflt->disable_ipv6) { - rtnl_unlock(); - return 0; - } - if (p == &net->ipv6.devconf_all->disable_ipv6) { WRITE_ONCE(net->ipv6.devconf_dflt->disable_ipv6, newf); addrconf_disable_change(net, newf); From e7135f484994494a38071e3653a83d21d305f50c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:28 +0000 Subject: [PATCH 1666/2255] ipv6: annotate data-races around cnf.mtu6 idev->cnf.mtu6 might be read locklessly, add appropriate READ_ONCE() and WRITE_ONCE() annotations. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/ip6_route.h | 2 +- net/ipv6/addrconf.c | 4 ++-- net/ipv6/ndisc.c | 4 ++-- net/ipv6/route.c | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 52a51c69aa9d..a30c6aa9e5cf 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -332,7 +332,7 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst rcu_read_lock(); idev = __in6_dev_get(dst->dev); if (idev) - mtu = idev->cnf.mtu6; + mtu = READ_ONCE(idev->cnf.mtu6); rcu_read_unlock(); out: diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6975685f55ea..1b534edc7ca2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3671,7 +3671,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, if (idev) { rt6_mtu_change(dev, dev->mtu); - idev->cnf.mtu6 = dev->mtu; + WRITE_ONCE(idev->cnf.mtu6, dev->mtu); break; } @@ -3763,7 +3763,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) { rt6_mtu_change(dev, dev->mtu); - idev->cnf.mtu6 = dev->mtu; + WRITE_ONCE(idev->cnf.mtu6, dev->mtu); } WRITE_ONCE(idev->tstamp, jiffies); inet6_ifinfo_notify(RTM_NEWLINK, idev); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 8523f0595b01..e96d79cd34d2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1578,8 +1578,8 @@ skip_routeinfo: if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) { ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu); - } else if (in6_dev->cnf.mtu6 != mtu) { - in6_dev->cnf.mtu6 = mtu; + } else if (READ_ONCE(in6_dev->cnf.mtu6) != mtu) { + WRITE_ONCE(in6_dev->cnf.mtu6, mtu); fib6_metric_set(rt, RTAX_MTU, mtu); rt6_mtu_change(skb->dev, mtu); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 707d65bc9c0e..66c685b0b619 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1596,7 +1596,7 @@ static unsigned int fib6_mtu(const struct fib6_result *res) rcu_read_lock(); idev = __in6_dev_get(dev); - mtu = idev->cnf.mtu6; + mtu = READ_ONCE(idev->cnf.mtu6); rcu_read_unlock(); } @@ -3249,8 +3249,8 @@ u32 ip6_mtu_from_fib6(const struct fib6_result *res, mtu = IPV6_MIN_MTU; idev = __in6_dev_get(dev); - if (idev && idev->cnf.mtu6 > mtu) - mtu = idev->cnf.mtu6; + if (idev) + mtu = max_t(u32, mtu, READ_ONCE(idev->cnf.mtu6)); } mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); From e0bb2675fea2783c45bb95d74f00c55156720863 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:29 +0000 Subject: [PATCH 1667/2255] ipv6: annotate data-races around cnf.hop_limit idev->cnf.hop_limit and net->ipv6.devconf_all->hop_limit might be read locklessly, add appropriate READ_ONCE() and WRITE_ONCE() annotations. Signed-off-by: Eric Dumazet Acked-by: Florian Westphal # for netfilter parts Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/action.c | 2 +- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/ndisc.c | 2 +- net/ipv6/netfilter/nf_reject_ipv6.c | 4 ++-- net/ipv6/output_core.c | 4 ++-- net/netfilter/nf_synproxy_core.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c index 2b383d92d7f5..2c3f62907958 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/action.c +++ b/drivers/net/ethernet/netronome/nfp/flower/action.c @@ -460,7 +460,7 @@ nfp_fl_set_tun(struct nfp_app *app, struct nfp_fl_set_tun *set_tun, set_tun->ttl = ip6_dst_hoplimit(dst); dst_release(dst); } else { - set_tun->ttl = net->ipv6.devconf_all->hop_limit; + set_tun->ttl = READ_ONCE(net->ipv6.devconf_all->hop_limit); } #endif } else { diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 56c3c467f9de..f61d977ac052 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1346,7 +1346,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, } if (val < 0) - val = sock_net(sk)->ipv6.devconf_all->hop_limit; + val = READ_ONCE(sock_net(sk)->ipv6.devconf_all->hop_limit); break; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e96d79cd34d2..9c9c31268432 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1423,7 +1423,7 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) if (in6_dev->cnf.accept_ra_min_hop_limit < 256 && ra_msg->icmph.icmp6_hop_limit) { if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) { - in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; + WRITE_ONCE(in6_dev->cnf.hop_limit, ra_msg->icmph.icmp6_hop_limit); fib6_metric_set(rt, RTAX_HOPLIMIT, ra_msg->icmph.icmp6_hop_limit); } else { diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index 196dd4ecb5e2..dedee264b8f6 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c @@ -83,7 +83,7 @@ struct sk_buff *nf_reject_skb_v6_tcp_reset(struct net *net, skb_reserve(nskb, LL_MAX_HEADER); nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, - net->ipv6.devconf_all->hop_limit); + READ_ONCE(net->ipv6.devconf_all->hop_limit)); nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen); nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); @@ -124,7 +124,7 @@ struct sk_buff *nf_reject_skb_v6_unreach(struct net *net, skb_reserve(nskb, LL_MAX_HEADER); nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6, - net->ipv6.devconf_all->hop_limit); + READ_ONCE(net->ipv6.devconf_all->hop_limit)); skb_reset_transport_header(nskb); icmp6h = skb_put_zero(nskb, sizeof(struct icmp6hdr)); diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index b5205311f372..806d4b5dd1e6 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -111,9 +111,9 @@ int ip6_dst_hoplimit(struct dst_entry *dst) rcu_read_lock(); idev = __in6_dev_get(dev); if (idev) - hoplimit = idev->cnf.hop_limit; + hoplimit = READ_ONCE(idev->cnf.hop_limit); else - hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit; + hoplimit = READ_ONCE(dev_net(dev)->ipv6.devconf_all->hop_limit); rcu_read_unlock(); } return hoplimit; diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c index fbbc4fd37349..5b140c12b7df 100644 --- a/net/netfilter/nf_synproxy_core.c +++ b/net/netfilter/nf_synproxy_core.c @@ -800,7 +800,7 @@ synproxy_build_ip_ipv6(struct net *net, struct sk_buff *skb, skb_reset_network_header(skb); iph = skb_put(skb, sizeof(*iph)); ip6_flow_hdr(iph, 0, 0); - iph->hop_limit = net->ipv6.devconf_all->hop_limit; + iph->hop_limit = READ_ONCE(net->ipv6.devconf_all->hop_limit); iph->nexthdr = IPPROTO_TCP; iph->saddr = *saddr; iph->daddr = *daddr; From 32f754176e889cdfe989ef08ece19859427755df Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:30 +0000 Subject: [PATCH 1668/2255] ipv6: annotate data-races around cnf.forwarding idev->cnf.forwarding and net->ipv6.devconf_all->forwarding might be read locklessly, add appropriate READ_ONCE() and WRITE_ONCE() annotations. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/usb/cdc_mbim.c | 2 +- include/net/ipv6.h | 8 +++++--- net/core/filter.c | 2 +- net/ipv6/addrconf.c | 10 ++++++---- net/ipv6/ip6_output.c | 2 +- net/ipv6/ndisc.c | 11 ++++++----- net/ipv6/route.c | 4 ++-- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index cd4083e0b3b9..e13e4920ee9b 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -339,7 +339,7 @@ static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci) in6_dev = in6_dev_get(netdev); if (!in6_dev) goto out; - is_router = !!in6_dev->cnf.forwarding; + is_router = !!READ_ONCE(in6_dev->cnf.forwarding); in6_dev_put(in6_dev); /* ipv6_stub != NULL if in6_dev_get returned an inet6_dev */ diff --git a/include/net/ipv6.h b/include/net/ipv6.h index cf25ea21d770..88a8e554f7a1 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -534,13 +534,15 @@ static inline int ipv6_hopopt_jumbo_remove(struct sk_buff *skb) return 0; } -static inline bool ipv6_accept_ra(struct inet6_dev *idev) +static inline bool ipv6_accept_ra(const struct inet6_dev *idev) { + s32 accept_ra = READ_ONCE(idev->cnf.accept_ra); + /* If forwarding is enabled, RA are not accepted unless the special * hybrid mode (accept_ra=2) is enabled. */ - return idev->cnf.forwarding ? idev->cnf.accept_ra == 2 : - idev->cnf.accept_ra; + return READ_ONCE(idev->cnf.forwarding) ? accept_ra == 2 : + accept_ra; } #define IPV6_FRAG_HIGH_THRESH (4 * 1024*1024) /* 4194304 */ diff --git a/net/core/filter.c b/net/core/filter.c index 358870408a51..58e8e1a70aa7 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5988,7 +5988,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, return -ENODEV; idev = __in6_dev_get_safely(dev); - if (unlikely(!idev || !idev->cnf.forwarding)) + if (unlikely(!idev || !READ_ONCE(idev->cnf.forwarding))) return BPF_FIB_LKUP_RET_FWD_DISABLED; if (flags & BPF_FIB_LOOKUP_OUTPUT) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1b534edc7ca2..ec99e393f6a9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -551,7 +551,8 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, goto out; if ((all || type == NETCONFA_FORWARDING) && - nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) + nla_put_s32(skb, NETCONFA_FORWARDING, + READ_ONCE(devconf->forwarding)) < 0) goto nla_put_failure; #ifdef CONFIG_IPV6_MROUTE if ((all || type == NETCONFA_MC_FORWARDING) && @@ -869,7 +870,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf) idev = __in6_dev_get(dev); if (idev) { int changed = (!idev->cnf.forwarding) ^ (!newf); - idev->cnf.forwarding = newf; + + WRITE_ONCE(idev->cnf.forwarding, newf); if (changed) dev_forward_change(idev); } @@ -886,7 +888,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) net = (struct net *)table->extra2; old = *p; - *p = newf; + WRITE_ONCE(*p, newf); if (p == &net->ipv6.devconf_dflt->forwarding) { if ((!newf) ^ (!old)) @@ -901,7 +903,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) if (p == &net->ipv6.devconf_all->forwarding) { int old_dflt = net->ipv6.devconf_dflt->forwarding; - net->ipv6.devconf_dflt->forwarding = newf; + WRITE_ONCE(net->ipv6.devconf_dflt->forwarding, newf); if ((!newf) ^ (!old_dflt)) inet6_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_FORWARDING, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0559bd000585..444be8c84cc5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -501,7 +501,7 @@ int ip6_forward(struct sk_buff *skb) u32 mtu; idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif)); - if (net->ipv6.devconf_all->forwarding == 0) + if (READ_ONCE(net->ipv6.devconf_all->forwarding) == 0) goto error; if (skb->pkt_type != PACKET_HOST) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 9c9c31268432..1fb5e37bc78b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -903,7 +903,7 @@ have_ifp: } if (ipv6_chk_acast_addr(net, dev, &msg->target) || - (idev->cnf.forwarding && + (READ_ONCE(idev->cnf.forwarding) && (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) && (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && @@ -929,7 +929,7 @@ have_ifp: } if (is_router < 0) - is_router = idev->cnf.forwarding; + is_router = READ_ONCE(idev->cnf.forwarding); if (dad) { ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target, @@ -1080,7 +1080,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb) * Note that we don't do a (daddr == all-routers-mcast) check. */ new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE; - if (!neigh && lladdr && idev && idev->cnf.forwarding) { + if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) { if (accept_untracked_na(dev, saddr)) { neigh = neigh_create(&nd_tbl, &msg->target, dev); new_state = NUD_STALE; @@ -1100,7 +1100,8 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb) * has already sent a NA to us. */ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && - net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp && + READ_ONCE(net->ipv6.devconf_all->forwarding) && + net->ipv6.devconf_all->proxy_ndp && pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { /* XXX: idev->cnf.proxy_ndp */ goto out; @@ -1148,7 +1149,7 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb) } /* Don't accept RS if we're not in router mode */ - if (!idev->cnf.forwarding) + if (!READ_ONCE(idev->cnf.forwarding)) goto out; /* diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 66c685b0b619..6a2b53de4818 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2220,7 +2220,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, strict |= flags & RT6_LOOKUP_F_IFACE; strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE; - if (net->ipv6.devconf_all->forwarding == 0) + if (READ_ONCE(net->ipv6.devconf_all->forwarding) == 0) strict |= RT6_LOOKUP_F_REACHABLE; rcu_read_lock(); @@ -4149,7 +4149,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu in6_dev = __in6_dev_get(skb->dev); if (!in6_dev) return; - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) + if (READ_ONCE(in6_dev->cnf.forwarding) || !in6_dev->cnf.accept_redirects) return; /* RFC2461 8.1: From ddea75d344dd87cf7f5d79efb1aab80b493f8393 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:31 +0000 Subject: [PATCH 1669/2255] ipv6: annotate data-races in ndisc_router_discovery() Annotate reads from in6_dev->cnf.XXX fields, as they could change concurrently. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1fb5e37bc78b..f6430db24940 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1319,7 +1319,7 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) if (old_if_flags != in6_dev->if_flags) send_ifinfo_notify = true; - if (!in6_dev->cnf.accept_ra_defrtr) { + if (!READ_ONCE(in6_dev->cnf.accept_ra_defrtr)) { ND_PRINTK(2, info, "RA: %s, defrtr is false for dev: %s\n", __func__, skb->dev->name); @@ -1327,7 +1327,8 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) } lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); - if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_lft) { + if (lifetime != 0 && + lifetime < READ_ONCE(in6_dev->cnf.accept_ra_min_lft)) { ND_PRINTK(2, info, "RA: router lifetime (%ds) is too short: %s\n", lifetime, skb->dev->name); @@ -1338,7 +1339,7 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) * accept_ra_from_local is set to true. */ net = dev_net(in6_dev->dev); - if (!in6_dev->cnf.accept_ra_from_local && + if (!READ_ONCE(in6_dev->cnf.accept_ra_from_local) && ipv6_chk_addr(net, &ipv6_hdr(skb)->saddr, in6_dev->dev, 0)) { ND_PRINTK(2, info, "RA from local address detected on dev: %s: default router ignored\n", @@ -1350,7 +1351,7 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) pref = ra_msg->icmph.icmp6_router_pref; /* 10b is handled as if it were 00b (medium) */ if (pref == ICMPV6_ROUTER_PREF_INVALID || - !in6_dev->cnf.accept_ra_rtr_pref) + !READ_ONCE(in6_dev->cnf.accept_ra_rtr_pref)) pref = ICMPV6_ROUTER_PREF_MEDIUM; #endif /* routes added from RAs do not use nexthop objects */ @@ -1421,10 +1422,12 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) spin_unlock_bh(&table->tb6_lock); } - if (in6_dev->cnf.accept_ra_min_hop_limit < 256 && + if (READ_ONCE(in6_dev->cnf.accept_ra_min_hop_limit) < 256 && ra_msg->icmph.icmp6_hop_limit) { - if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) { - WRITE_ONCE(in6_dev->cnf.hop_limit, ra_msg->icmph.icmp6_hop_limit); + if (READ_ONCE(in6_dev->cnf.accept_ra_min_hop_limit) <= + ra_msg->icmph.icmp6_hop_limit) { + WRITE_ONCE(in6_dev->cnf.hop_limit, + ra_msg->icmph.icmp6_hop_limit); fib6_metric_set(rt, RTAX_HOPLIMIT, ra_msg->icmph.icmp6_hop_limit); } else { @@ -1506,7 +1509,7 @@ skip_linkparms: } #ifdef CONFIG_IPV6_ROUTE_INFO - if (!in6_dev->cnf.accept_ra_from_local && + if (!READ_ONCE(in6_dev->cnf.accept_ra_from_local) && ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, in6_dev->dev, 0)) { ND_PRINTK(2, info, @@ -1515,7 +1518,7 @@ skip_linkparms: goto skip_routeinfo; } - if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { + if (READ_ONCE(in6_dev->cnf.accept_ra_rtr_pref) && ndopts.nd_opts_ri) { struct nd_opt_hdr *p; for (p = ndopts.nd_opts_ri; p; @@ -1527,14 +1530,14 @@ skip_linkparms: continue; #endif if (ri->prefix_len == 0 && - !in6_dev->cnf.accept_ra_defrtr) + !READ_ONCE(in6_dev->cnf.accept_ra_defrtr)) continue; if (ri->lifetime != 0 && - ntohl(ri->lifetime) < in6_dev->cnf.accept_ra_min_lft) + ntohl(ri->lifetime) < READ_ONCE(in6_dev->cnf.accept_ra_min_lft)) continue; - if (ri->prefix_len < in6_dev->cnf.accept_ra_rt_info_min_plen) + if (ri->prefix_len < READ_ONCE(in6_dev->cnf.accept_ra_rt_info_min_plen)) continue; - if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) + if (ri->prefix_len > READ_ONCE(in6_dev->cnf.accept_ra_rt_info_max_plen)) continue; rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3, &ipv6_hdr(skb)->saddr); @@ -1554,7 +1557,7 @@ skip_routeinfo: } #endif - if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { + if (READ_ONCE(in6_dev->cnf.accept_ra_pinfo) && ndopts.nd_opts_pi) { struct nd_opt_hdr *p; for (p = ndopts.nd_opts_pi; p; @@ -1565,7 +1568,7 @@ skip_routeinfo: } } - if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) { + if (ndopts.nd_opts_mtu && READ_ONCE(in6_dev->cnf.accept_ra_mtu)) { __be32 n; u32 mtu; From fca34cc075996767fbbdb6252be9ddd21c34c920 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:32 +0000 Subject: [PATCH 1670/2255] ipv6: annotate data-races around idev->cnf.ignore_routes_with_linkdown idev->cnf.ignore_routes_with_linkdown can be used without any locks, add appropriate annotations. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/addrconf.h | 2 +- net/ipv6/addrconf.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 30d6f1e84e46..9d06eb945509 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -417,7 +417,7 @@ static inline bool ip6_ignore_linkdown(const struct net_device *dev) if (unlikely(!idev)) return true; - return !!idev->cnf.ignore_routes_with_linkdown; + return !!READ_ONCE(idev->cnf.ignore_routes_with_linkdown); } void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ec99e393f6a9..82b8d90afb6a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -566,7 +566,7 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - devconf->ignore_routes_with_linkdown) < 0) + READ_ONCE(devconf->ignore_routes_with_linkdown)) < 0) goto nla_put_failure; out: @@ -935,7 +935,7 @@ static void addrconf_linkdown_change(struct net *net, __s32 newf) if (idev) { int changed = (!idev->cnf.ignore_routes_with_linkdown) ^ (!newf); - idev->cnf.ignore_routes_with_linkdown = newf; + WRITE_ONCE(idev->cnf.ignore_routes_with_linkdown, newf); if (changed) inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF, @@ -956,7 +956,7 @@ static int addrconf_fixup_linkdown(struct ctl_table *table, int *p, int newf) net = (struct net *)table->extra2; old = *p; - *p = newf; + WRITE_ONCE(*p, newf); if (p == &net->ipv6.devconf_dflt->ignore_routes_with_linkdown) { if ((!newf) ^ (!old)) @@ -970,7 +970,7 @@ static int addrconf_fixup_linkdown(struct ctl_table *table, int *p, int newf) } if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) { - net->ipv6.devconf_dflt->ignore_routes_with_linkdown = newf; + WRITE_ONCE(net->ipv6.devconf_dflt->ignore_routes_with_linkdown, newf); addrconf_linkdown_change(net, newf); if ((!newf) ^ (!old)) inet6_netconf_notify_devconf(net, From e248948a4471c6efca19f7c5e657b30ee67a6485 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:33 +0000 Subject: [PATCH 1671/2255] ipv6: annotate data-races in rt6_probe() Use READ_ONCE() while reading idev->cnf.rtr_probe_interval while its value could be changed. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/route.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6a2b53de4818..1b897c57c55f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -645,14 +645,15 @@ static void rt6_probe(struct fib6_nh *fib6_nh) write_lock_bh(&neigh->lock); if (!(neigh->nud_state & NUD_VALID) && time_after(jiffies, - neigh->updated + idev->cnf.rtr_probe_interval)) { + neigh->updated + + READ_ONCE(idev->cnf.rtr_probe_interval))) { work = kmalloc(sizeof(*work), GFP_ATOMIC); if (work) __neigh_set_probe_once(neigh); } write_unlock_bh(&neigh->lock); } else if (time_after(jiffies, last_probe + - idev->cnf.rtr_probe_interval)) { + READ_ONCE(idev->cnf.rtr_probe_interval))) { work = kmalloc(sizeof(*work), GFP_ATOMIC); } From a8fbd4d90720b6c930661ed593d54aba77cec3c2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:34 +0000 Subject: [PATCH 1672/2255] ipv6: annotate data-races around devconf->proxy_ndp devconf->proxy_ndp can be read and written locklessly, add appropriate annotations. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 3 ++- net/ipv6/ip6_output.c | 2 +- net/ipv6/ndisc.c | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 82b8d90afb6a..409aa5ddb856 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -561,7 +561,8 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, goto nla_put_failure; #endif if ((all || type == NETCONFA_PROXY_NEIGH) && - nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) + nla_put_s32(skb, NETCONFA_PROXY_NEIGH, + READ_ONCE(devconf->proxy_ndp)) < 0) goto nla_put_failure; if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 444be8c84cc5..f08af3f4e54f 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -552,7 +552,7 @@ int ip6_forward(struct sk_buff *skb) } /* XXX: idev->cnf.proxy_ndp? */ - if (net->ipv6.devconf_all->proxy_ndp && + if (READ_ONCE(net->ipv6.devconf_all->proxy_ndp) && pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) { int proxied = ip6_forward_proxy_check(skb); if (proxied > 0) { diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f6430db24940..4114918f12c8 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -904,7 +904,8 @@ have_ifp: if (ipv6_chk_acast_addr(net, dev, &msg->target) || (READ_ONCE(idev->cnf.forwarding) && - (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) && + (READ_ONCE(net->ipv6.devconf_all->proxy_ndp) || + READ_ONCE(idev->cnf.proxy_ndp)) && (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && @@ -1101,7 +1102,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb) */ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && READ_ONCE(net->ipv6.devconf_all->forwarding) && - net->ipv6.devconf_all->proxy_ndp && + READ_ONCE(net->ipv6.devconf_all->proxy_ndp) && pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { /* XXX: idev->cnf.proxy_ndp */ goto out; From 624d5aec487cf8c2955d9c5880685714f7fe8e6f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:35 +0000 Subject: [PATCH 1673/2255] ipv6: annotate data-races around devconf->disable_policy idev->cnf.disable_policy and net->ipv6.devconf_all->disable_policy can be read locklessly. Add appropriate annotations on reads and writes. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 +- net/ipv6/ip6_output.c | 4 ++-- net/ipv6/route.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 409aa5ddb856..44340ff82da5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -6699,7 +6699,7 @@ int addrconf_disable_policy(struct ctl_table *ctl, int *valp, int val) if (!rtnl_trylock()) return restart_syscall(); - *valp = val; + WRITE_ONCE(*valp, val); net = (struct net *)ctl->extra2; if (valp == &net->ipv6.devconf_dflt->disable_policy) { diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f08af3f4e54f..b9dd3a66e423 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -513,8 +513,8 @@ int ip6_forward(struct sk_buff *skb) if (skb_warn_if_lro(skb)) goto drop; - if (!net->ipv6.devconf_all->disable_policy && - (!idev || !idev->cnf.disable_policy) && + if (!READ_ONCE(net->ipv6.devconf_all->disable_policy) && + (!idev || !READ_ONCE(idev->cnf.disable_policy)) && !xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); goto drop; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1b897c57c55f..a92fcac902ae 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4584,8 +4584,8 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net, f6i->dst_nocount = true; if (!anycast && - (net->ipv6.devconf_all->disable_policy || - idev->cnf.disable_policy)) + (READ_ONCE(net->ipv6.devconf_all->disable_policy) || + READ_ONCE(idev->cnf.disable_policy))) f6i->dst_nopolicy = true; } From 45b90ec9a214ff7fbde8190126301a07387c46e5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:36 +0000 Subject: [PATCH 1674/2255] ipv6: addrconf_disable_policy() optimization Writing over /proc/sys/net/ipv6/conf/default/disable_policy does not need to hold RTNL. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 44340ff82da5..0e7135a206b0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -6693,20 +6693,19 @@ void addrconf_disable_policy_idev(struct inet6_dev *idev, int val) static int addrconf_disable_policy(struct ctl_table *ctl, int *valp, int val) { + struct net *net = (struct net *)ctl->extra2; struct inet6_dev *idev; - struct net *net; + + if (valp == &net->ipv6.devconf_dflt->disable_policy) { + WRITE_ONCE(*valp, val); + return 0; + } if (!rtnl_trylock()) return restart_syscall(); WRITE_ONCE(*valp, val); - net = (struct net *)ctl->extra2; - if (valp == &net->ipv6.devconf_dflt->disable_policy) { - rtnl_unlock(); - return 0; - } - if (valp == &net->ipv6.devconf_all->disable_policy) { struct net_device *dev; From 2aba913f99debce6cd1c7f606d69d094d1202559 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:37 +0000 Subject: [PATCH 1675/2255] ipv6/addrconf: annotate data-races around devconf fields (I) Annotate lockless reads and writes on following devconf fields: - regen_min_advance - regen_max_retry - dad_transmits - use_tempaddr - max_addresses - max_desync_factor - temp_valid_lft - rtr_solicits - rtr_solicit_max_interval - rtr_solicit_interval - rtr_solicit_delay - enhanced_dad - accept_redirects Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 67 +++++++++++++++++++++++++-------------------- net/ipv6/route.c | 3 +- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0e7135a206b0..bcfe725f8fbd 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1359,11 +1359,12 @@ out: in6_ifa_put(ifp); } -static unsigned long ipv6_get_regen_advance(struct inet6_dev *idev) +static unsigned long ipv6_get_regen_advance(const struct inet6_dev *idev) { - return idev->cnf.regen_min_advance + idev->cnf.regen_max_retry * - idev->cnf.dad_transmits * - max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; + return READ_ONCE(idev->cnf.regen_min_advance) + + READ_ONCE(idev->cnf.regen_max_retry) * + READ_ONCE(idev->cnf.dad_transmits) * + max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; } static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) @@ -1384,7 +1385,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) retry: in6_dev_hold(idev); - if (idev->cnf.use_tempaddr <= 0) { + if (READ_ONCE(idev->cnf.use_tempaddr) <= 0) { write_unlock_bh(&idev->lock); pr_info("%s: use_tempaddr is disabled\n", __func__); in6_dev_put(idev); @@ -1392,8 +1393,8 @@ retry: goto out; } spin_lock_bh(&ifp->lock); - if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { - idev->cnf.use_tempaddr = -1; /*XXX*/ + if (ifp->regen_count++ >= READ_ONCE(idev->cnf.regen_max_retry)) { + WRITE_ONCE(idev->cnf.use_tempaddr, -1); /*XXX*/ spin_unlock_bh(&ifp->lock); write_unlock_bh(&idev->lock); pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", @@ -1415,7 +1416,7 @@ retry: */ cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft); max_desync_factor = min_t(long, - idev->cnf.max_desync_factor, + READ_ONCE(idev->cnf.max_desync_factor), cnf_temp_preferred_lft - regen_advance); if (unlikely(idev->desync_factor > max_desync_factor)) { @@ -1432,7 +1433,7 @@ retry: memset(&cfg, 0, sizeof(cfg)); cfg.valid_lft = min_t(__u32, ifp->valid_lft, - idev->cnf.temp_valid_lft + age); + READ_ONCE(idev->cnf.temp_valid_lft) + age); cfg.preferred_lft = cnf_temp_preferred_lft + age - idev->desync_factor; cfg.preferred_lft = min_t(__u32, if_public_preferred_lft, cfg.preferred_lft); cfg.preferred_lft = min_t(__u32, cfg.valid_lft, cfg.preferred_lft); @@ -1685,7 +1686,7 @@ static int ipv6_get_saddr_eval(struct net *net, */ int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? !!(dst->prefs & IPV6_PREFER_SRC_TMP) : - score->ifa->idev->cnf.use_tempaddr >= 2; + READ_ONCE(score->ifa->idev->cnf.use_tempaddr) >= 2; ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; break; } @@ -2168,6 +2169,7 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp) { struct inet6_dev *idev = ifp->idev; struct net *net = dev_net(idev->dev); + int max_addresses; if (addrconf_dad_end(ifp)) { in6_ifa_put(ifp); @@ -2205,9 +2207,9 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp) spin_unlock_bh(&ifp->lock); - if (idev->cnf.max_addresses && - ipv6_count_addresses(idev) >= - idev->cnf.max_addresses) + max_addresses = READ_ONCE(idev->cnf.max_addresses); + if (max_addresses && + ipv6_count_addresses(idev) >= max_addresses) goto lock_errdad; net_info_ratelimited("%s: generating new stable privacy address because of DAD conflict\n", @@ -2604,11 +2606,11 @@ static void manage_tempaddrs(struct inet6_dev *idev, * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively. */ age = (now - ift->cstamp) / HZ; - max_valid = idev->cnf.temp_valid_lft - age; + max_valid = READ_ONCE(idev->cnf.temp_valid_lft) - age; if (max_valid < 0) max_valid = 0; - max_prefered = idev->cnf.temp_prefered_lft - + max_prefered = READ_ONCE(idev->cnf.temp_prefered_lft) - idev->desync_factor - age; if (max_prefered < 0) max_prefered = 0; @@ -2641,7 +2643,7 @@ static void manage_tempaddrs(struct inet6_dev *idev, if (list_empty(&idev->tempaddr_list) && (valid_lft || prefered_lft)) create = true; - if (create && idev->cnf.use_tempaddr > 0) { + if (create && READ_ONCE(idev->cnf.use_tempaddr) > 0) { /* When a new public address is created as described * in [ADDRCONF], also create a new temporary address. */ @@ -2669,7 +2671,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, int create = 0, update_lft = 0; if (!ifp && valid_lft) { - int max_addresses = in6_dev->cnf.max_addresses; + int max_addresses = READ_ONCE(in6_dev->cnf.max_addresses); struct ifa6_config cfg = { .pfx = addr, .plen = pinfo->prefix_len, @@ -4028,6 +4030,7 @@ static void addrconf_rs_timer(struct timer_list *t) struct inet6_dev *idev = from_timer(idev, t, rs_timer); struct net_device *dev = idev->dev; struct in6_addr lladdr; + int rtr_solicits; write_lock(&idev->lock); if (idev->dead || !(idev->if_flags & IF_READY)) @@ -4040,7 +4043,9 @@ static void addrconf_rs_timer(struct timer_list *t) if (idev->if_flags & IF_RA_RCVD) goto out; - if (idev->rs_probes++ < idev->cnf.rtr_solicits || idev->cnf.rtr_solicits < 0) { + rtr_solicits = READ_ONCE(idev->cnf.rtr_solicits); + + if (idev->rs_probes++ < rtr_solicits || rtr_solicits < 0) { write_unlock(&idev->lock); if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) ndisc_send_rs(dev, &lladdr, @@ -4050,11 +4055,12 @@ static void addrconf_rs_timer(struct timer_list *t) write_lock(&idev->lock); idev->rs_interval = rfc3315_s14_backoff_update( - idev->rs_interval, idev->cnf.rtr_solicit_max_interval); + idev->rs_interval, + READ_ONCE(idev->cnf.rtr_solicit_max_interval)); /* The wait after the last probe can be shorter */ addrconf_mod_rs_timer(idev, (idev->rs_probes == - idev->cnf.rtr_solicits) ? - idev->cnf.rtr_solicit_delay : + READ_ONCE(idev->cnf.rtr_solicits)) ? + READ_ONCE(idev->cnf.rtr_solicit_delay) : idev->rs_interval); } else { /* @@ -4075,24 +4081,25 @@ put: */ static void addrconf_dad_kick(struct inet6_ifaddr *ifp) { - unsigned long rand_num; struct inet6_dev *idev = ifp->idev; + unsigned long rand_num; u64 nonce; if (ifp->flags & IFA_F_OPTIMISTIC) rand_num = 0; else - rand_num = get_random_u32_below(idev->cnf.rtr_solicit_delay ? : 1); + rand_num = get_random_u32_below( + READ_ONCE(idev->cnf.rtr_solicit_delay) ? : 1); nonce = 0; - if (idev->cnf.enhanced_dad || - dev_net(idev->dev)->ipv6.devconf_all->enhanced_dad) { + if (READ_ONCE(idev->cnf.enhanced_dad) || + READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->enhanced_dad)) { do get_random_bytes(&nonce, 6); while (nonce == 0); } ifp->dad_nonce = nonce; - ifp->dad_probes = idev->cnf.dad_transmits; + ifp->dad_probes = READ_ONCE(idev->cnf.dad_transmits); addrconf_mod_dad_work(ifp, rand_num); } @@ -4331,7 +4338,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id, send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp); send_rs = send_mld && ipv6_accept_ra(ifp->idev) && - ifp->idev->cnf.rtr_solicits != 0 && + READ_ONCE(ifp->idev->cnf.rtr_solicits) != 0 && (dev->flags & IFF_LOOPBACK) == 0 && (dev->type != ARPHRD_TUNNEL) && !netif_is_team_port(dev); @@ -4366,7 +4373,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id, write_lock_bh(&ifp->idev->lock); spin_lock(&ifp->lock); ifp->idev->rs_interval = rfc3315_s14_backoff_init( - ifp->idev->cnf.rtr_solicit_interval); + READ_ONCE(ifp->idev->cnf.rtr_solicit_interval)); ifp->idev->rs_probes = 1; ifp->idev->if_flags |= IF_RS_SENT; addrconf_mod_rs_timer(ifp->idev, ifp->idev->rs_interval); @@ -5915,7 +5922,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token, return -EINVAL; } - if (idev->cnf.rtr_solicits == 0) { + if (READ_ONCE(idev->cnf.rtr_solicits) == 0) { NL_SET_ERR_MSG(extack, "Router solicitation is disabled on device"); return -EINVAL; @@ -5948,7 +5955,7 @@ update_lft: if (update_rs) { idev->if_flags |= IF_RS_SENT; idev->rs_interval = rfc3315_s14_backoff_init( - idev->cnf.rtr_solicit_interval); + READ_ONCE(idev->cnf.rtr_solicit_interval)); idev->rs_probes = 1; addrconf_mod_rs_timer(idev, idev->rs_interval); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a92fcac902ae..2cecb1c5a58f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4150,7 +4150,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu in6_dev = __in6_dev_get(skb->dev); if (!in6_dev) return; - if (READ_ONCE(in6_dev->cnf.forwarding) || !in6_dev->cnf.accept_redirects) + if (READ_ONCE(in6_dev->cnf.forwarding) || + !READ_ONCE(in6_dev->cnf.accept_redirects)) return; /* RFC2461 8.1: From 2f0ff05a44302c91af54a5f9efe1b65b7681540e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:38 +0000 Subject: [PATCH 1676/2255] ipv6/addrconf: annotate data-races around devconf fields (II) Final (?) round of this series. Annotate lockless reads on following devconf fields, because they be changed concurrently from /proc/net/ipv6/conf. - accept_dad - optimistic_dad - use_optimistic - use_oif_addrs_only - ra_honor_pio_life - keep_addr_on_down - ndisc_notify - ndisc_evict_nocarrier - suppress_frag_ndisc - addr_gen_mode - seg6_enabled - ioam6_enabled - ioam6_id - ioam6_id_wide - drop_unicast_in_l2_multicast - mldv[12]_unsolicited_report_interval - force_mld_version - force_tllao - accept_untracked_na - drop_unsolicited_na - accept_source_route Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 49 +++++++++++++++++++++++--------------------- net/ipv6/exthdrs.c | 16 ++++++++------- net/ipv6/ioam6.c | 8 ++++---- net/ipv6/ip6_input.c | 2 +- net/ipv6/mcast.c | 14 ++++++------- net/ipv6/ndisc.c | 18 ++++++++-------- net/ipv6/seg6_hmac.c | 8 +++++--- 7 files changed, 61 insertions(+), 54 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index bcfe725f8fbd..436d9a6e6a82 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1557,15 +1557,17 @@ static inline int ipv6_saddr_preferred(int type) return 0; } -static bool ipv6_use_optimistic_addr(struct net *net, - struct inet6_dev *idev) +static bool ipv6_use_optimistic_addr(const struct net *net, + const struct inet6_dev *idev) { #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (!idev) return false; - if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad) + if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) && + !READ_ONCE(idev->cnf.optimistic_dad)) return false; - if (!net->ipv6.devconf_all->use_optimistic && !idev->cnf.use_optimistic) + if (!READ_ONCE(net->ipv6.devconf_all->use_optimistic) && + !READ_ONCE(idev->cnf.use_optimistic)) return false; return true; @@ -1574,13 +1576,14 @@ static bool ipv6_use_optimistic_addr(struct net *net, #endif } -static bool ipv6_allow_optimistic_dad(struct net *net, - struct inet6_dev *idev) +static bool ipv6_allow_optimistic_dad(const struct net *net, + const struct inet6_dev *idev) { #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (!idev) return false; - if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad) + if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) && + !READ_ONCE(idev->cnf.optimistic_dad)) return false; return true; @@ -1862,7 +1865,7 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, idev = __in6_dev_get(dst_dev); if ((dst_type & IPV6_ADDR_MULTICAST) || dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL || - (idev && idev->cnf.use_oif_addrs_only)) { + (idev && READ_ONCE(idev->cnf.use_oif_addrs_only))) { use_oif_addr = true; } } @@ -2683,8 +2686,8 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, }; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD - if ((net->ipv6.devconf_all->optimistic_dad || - in6_dev->cnf.optimistic_dad) && + if ((READ_ONCE(net->ipv6.devconf_all->optimistic_dad) || + READ_ONCE(in6_dev->cnf.optimistic_dad)) && !net->ipv6.devconf_all->forwarding && sllao) cfg.ifa_flags |= IFA_F_OPTIMISTIC; #endif @@ -2733,7 +2736,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, */ update_lft = !create && stored_lft; - if (update_lft && !in6_dev->cnf.ra_honor_pio_life) { + if (update_lft && !READ_ONCE(in6_dev->cnf.ra_honor_pio_life)) { const u32 minimum_lft = min_t(u32, stored_lft, MIN_VALID_LIFETIME); valid_lft = max(valid_lft, minimum_lft); @@ -3317,8 +3320,8 @@ void addrconf_add_linklocal(struct inet6_dev *idev, struct inet6_ifaddr *ifp; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD - if ((dev_net(idev->dev)->ipv6.devconf_all->optimistic_dad || - idev->cnf.optimistic_dad) && + if ((READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->optimistic_dad) || + READ_ONCE(idev->cnf.optimistic_dad)) && !dev_net(idev->dev)->ipv6.devconf_all->forwarding) cfg.ifa_flags |= IFA_F_OPTIMISTIC; #endif @@ -3890,10 +3893,10 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister) */ if (!unregister && !idev->cnf.disable_ipv6) { /* aggregate the system setting and interface setting */ - int _keep_addr = net->ipv6.devconf_all->keep_addr_on_down; + int _keep_addr = READ_ONCE(net->ipv6.devconf_all->keep_addr_on_down); if (!_keep_addr) - _keep_addr = idev->cnf.keep_addr_on_down; + _keep_addr = READ_ONCE(idev->cnf.keep_addr_on_down); keep_addr = (_keep_addr > 0); } @@ -4119,8 +4122,8 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp) net = dev_net(dev); if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || - (net->ipv6.devconf_all->accept_dad < 1 && - idev->cnf.accept_dad < 1) || + (READ_ONCE(net->ipv6.devconf_all->accept_dad) < 1 && + READ_ONCE(idev->cnf.accept_dad) < 1) || !(ifp->flags&IFA_F_TENTATIVE) || ifp->flags & IFA_F_NODAD) { bool send_na = false; @@ -4212,8 +4215,8 @@ static void addrconf_dad_work(struct work_struct *w) action = DAD_ABORT; ifp->state = INET6_IFADDR_STATE_POSTDAD; - if ((dev_net(idev->dev)->ipv6.devconf_all->accept_dad > 1 || - idev->cnf.accept_dad > 1) && + if ((READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->accept_dad) > 1 || + READ_ONCE(idev->cnf.accept_dad) > 1) && !idev->cnf.disable_ipv6 && !(ifp->flags & IFA_F_STABLE_PRIVACY)) { struct in6_addr addr; @@ -4352,8 +4355,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id, /* send unsolicited NA if enabled */ if (send_na && - (ifp->idev->cnf.ndisc_notify || - dev_net(dev)->ipv6.devconf_all->ndisc_notify)) { + (READ_ONCE(ifp->idev->cnf.ndisc_notify) || + READ_ONCE(dev_net(dev)->ipv6.devconf_all->ndisc_notify))) { ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifp->addr, /*router=*/ !!ifp->idev->cnf.forwarding, /*solicited=*/ false, /*override=*/ true, @@ -6541,7 +6544,7 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write, } else if (&net->ipv6.devconf_all->addr_gen_mode == ctl->data) { struct net_device *dev; - net->ipv6.devconf_dflt->addr_gen_mode = new_val; + WRITE_ONCE(net->ipv6.devconf_dflt->addr_gen_mode, new_val); for_each_netdev(net, dev) { idev = __in6_dev_get(dev); if (idev && @@ -6553,7 +6556,7 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write, } } - *((u32 *)ctl->data) = new_val; + WRITE_ONCE(*((u32 *)ctl->data), new_val); } out: diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 727792907d6c..26f1e4a5ade0 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -379,9 +379,8 @@ static int ipv6_srh_rcv(struct sk_buff *skb) idev = __in6_dev_get(skb->dev); - accept_seg6 = net->ipv6.devconf_all->seg6_enabled; - if (accept_seg6 > idev->cnf.seg6_enabled) - accept_seg6 = idev->cnf.seg6_enabled; + accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled), + READ_ONCE(idev->cnf.seg6_enabled)); if (!accept_seg6) { kfree_skb(skb); @@ -655,10 +654,13 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) struct ipv6_rt_hdr *hdr; struct rt0_hdr *rthdr; struct net *net = dev_net(skb->dev); - int accept_source_route = net->ipv6.devconf_all->accept_source_route; + int accept_source_route; - if (idev && accept_source_route > idev->cnf.accept_source_route) - accept_source_route = idev->cnf.accept_source_route; + accept_source_route = READ_ONCE(net->ipv6.devconf_all->accept_source_route); + + if (idev) + accept_source_route = min(accept_source_route, + READ_ONCE(idev->cnf.accept_source_route)); if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || !pskb_may_pull(skb, (skb_transport_offset(skb) + @@ -919,7 +921,7 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff) goto drop; /* Ignore if IOAM is not enabled on ingress */ - if (!__in6_dev_get(skb->dev)->cnf.ioam6_enabled) + if (!READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_enabled)) goto ignore; /* Truncated Option header */ diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c index 5fa923f06632..08c929513065 100644 --- a/net/ipv6/ioam6.c +++ b/net/ipv6/ioam6.c @@ -727,7 +727,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb, if (!skb->dev) raw16 = IOAM6_U16_UNAVAILABLE; else - raw16 = (__force u16)__in6_dev_get(skb->dev)->cnf.ioam6_id; + raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id); *(__be16 *)data = cpu_to_be16(raw16); data += sizeof(__be16); @@ -735,7 +735,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb, if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) raw16 = IOAM6_U16_UNAVAILABLE; else - raw16 = (__force u16)__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id; + raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id); *(__be16 *)data = cpu_to_be16(raw16); data += sizeof(__be16); @@ -822,7 +822,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb, if (!skb->dev) raw32 = IOAM6_U32_UNAVAILABLE; else - raw32 = __in6_dev_get(skb->dev)->cnf.ioam6_id_wide; + raw32 = READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id_wide); *(__be32 *)data = cpu_to_be32(raw32); data += sizeof(__be32); @@ -830,7 +830,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb, if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) raw32 = IOAM6_U32_UNAVAILABLE; else - raw32 = __in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide; + raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide); *(__be32 *)data = cpu_to_be32(raw32); data += sizeof(__be32); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 1ba97933c74f..133610a49da6 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -236,7 +236,7 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, if (!ipv6_addr_is_multicast(&hdr->daddr) && (skb->pkt_type == PACKET_BROADCAST || skb->pkt_type == PACKET_MULTICAST) && - idev->cnf.drop_unicast_in_l2_multicast) { + READ_ONCE(idev->cnf.drop_unicast_in_l2_multicast)) { SKB_DR_SET(reason, UNICAST_IN_L2_MULTICAST); goto err; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 76ee1615ff2a..7ba01d8cfbae 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -159,9 +159,9 @@ static int unsolicited_report_interval(struct inet6_dev *idev) int iv; if (mld_in_v1_mode(idev)) - iv = idev->cnf.mldv1_unsolicited_report_interval; + iv = READ_ONCE(idev->cnf.mldv1_unsolicited_report_interval); else - iv = idev->cnf.mldv2_unsolicited_report_interval; + iv = READ_ONCE(idev->cnf.mldv2_unsolicited_report_interval); return iv > 0 ? iv : 1; } @@ -1202,15 +1202,15 @@ static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, static int mld_force_mld_version(const struct inet6_dev *idev) { + const struct net *net = dev_net(idev->dev); + int all_force; + + all_force = READ_ONCE(net->ipv6.devconf_all->force_mld_version); /* Normally, both are 0 here. If enforcement to a particular is * being used, individual device enforcement will have a lower * precedence over 'all' device (.../conf/all/force_mld_version). */ - - if (dev_net(idev->dev)->ipv6.devconf_all->force_mld_version != 0) - return dev_net(idev->dev)->ipv6.devconf_all->force_mld_version; - else - return idev->cnf.force_mld_version; + return all_force ?: READ_ONCE(idev->cnf.force_mld_version); } static bool mld_in_v2_mode_only(const struct inet6_dev *idev) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 4114918f12c8..ae134634c323 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -451,7 +451,7 @@ static void ip6_nd_hdr(struct sk_buff *skb, rcu_read_lock(); idev = __in6_dev_get(skb->dev); - tclass = idev ? idev->cnf.ndisc_tclass : 0; + tclass = idev ? READ_ONCE(idev->cnf.ndisc_tclass) : 0; rcu_read_unlock(); skb_push(skb, sizeof(*hdr)); @@ -535,7 +535,7 @@ void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr, src_addr = solicited_addr; if (ifp->flags & IFA_F_OPTIMISTIC) override = false; - inc_opt |= ifp->idev->cnf.force_tllao; + inc_opt |= READ_ONCE(ifp->idev->cnf.force_tllao); in6_ifa_put(ifp); } else { if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, @@ -974,7 +974,7 @@ static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr) { struct inet6_dev *idev = __in6_dev_get(dev); - switch (idev->cnf.accept_untracked_na) { + switch (READ_ONCE(idev->cnf.accept_untracked_na)) { case 0: /* Don't accept untracked na (absent in neighbor cache) */ return 0; case 1: /* Create new entries from na if currently untracked */ @@ -1025,7 +1025,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb) * drop_unsolicited_na takes precedence over accept_untracked_na */ if (!msg->icmph.icmp6_solicited && idev && - idev->cnf.drop_unsolicited_na) + READ_ONCE(idev->cnf.drop_unsolicited_na)) return reason; if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) @@ -1818,7 +1818,7 @@ static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb) if (!idev) return true; if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED && - idev->cnf.suppress_frag_ndisc) { + READ_ONCE(idev->cnf.suppress_frag_ndisc)) { net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n"); return true; } @@ -1895,8 +1895,8 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, idev = in6_dev_get(dev); if (!idev) break; - if (idev->cnf.ndisc_notify || - net->ipv6.devconf_all->ndisc_notify) + if (READ_ONCE(idev->cnf.ndisc_notify) || + READ_ONCE(net->ipv6.devconf_all->ndisc_notify)) ndisc_send_unsol_na(dev); in6_dev_put(idev); break; @@ -1905,8 +1905,8 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, if (!idev) evict_nocarrier = true; else { - evict_nocarrier = idev->cnf.ndisc_evict_nocarrier && - net->ipv6.devconf_all->ndisc_evict_nocarrier; + evict_nocarrier = READ_ONCE(idev->cnf.ndisc_evict_nocarrier) && + READ_ONCE(net->ipv6.devconf_all->ndisc_evict_nocarrier); in6_dev_put(idev); } diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c index d43c50a7310d..861e0366f549 100644 --- a/net/ipv6/seg6_hmac.c +++ b/net/ipv6/seg6_hmac.c @@ -241,6 +241,7 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb) struct sr6_tlv_hmac *tlv; struct ipv6_sr_hdr *srh; struct inet6_dev *idev; + int require_hmac; idev = __in6_dev_get(skb->dev); @@ -248,16 +249,17 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb) tlv = seg6_get_tlv_hmac(srh); + require_hmac = READ_ONCE(idev->cnf.seg6_require_hmac); /* mandatory check but no tlv */ - if (idev->cnf.seg6_require_hmac > 0 && !tlv) + if (require_hmac > 0 && !tlv) return false; /* no check */ - if (idev->cnf.seg6_require_hmac < 0) + if (require_hmac < 0) return true; /* check only if present */ - if (idev->cnf.seg6_require_hmac == 0 && !tlv) + if (require_hmac == 0 && !tlv) return true; /* now, seg6_require_hmac >= 0 && tlv */ From 2a02f8379bde89472cddb49dc8e55a17e0b68eed Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Feb 2024 13:54:39 +0000 Subject: [PATCH 1677/2255] ipv6: use xa_array iterator to implement inet6_netconf_dump_devconf() 1) inet6_netconf_dump_devconf() can run under RCU protection instead of RTNL. 2) properly return 0 at the end of a dump, avoiding an an extra recvmsg() system call. 3) Do not use inet6_base_seq() anymore, for_each_netdev_dump() has nice properties. Restarting a GETDEVCONF dump if a device has been added/removed or if net->ipv6.dev_addr_genid has changed is moot. Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 102 +++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 58 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 436d9a6e6a82..2f84e6ecf19f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -727,17 +727,18 @@ static u32 inet6_base_seq(const struct net *net) return res; } - static int inet6_netconf_dump_devconf(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); - int h, s_h; - int idx, s_idx; + struct { + unsigned long ifindex; + unsigned int all_default; + } *ctx = (void *)cb->ctx; struct net_device *dev; struct inet6_dev *idev; - struct hlist_head *head; + int err = 0; if (cb->strict_check) { struct netlink_ext_ack *extack = cb->extack; @@ -754,64 +755,48 @@ static int inet6_netconf_dump_devconf(struct sk_buff *skb, } } - s_h = cb->args[0]; - s_idx = idx = cb->args[1]; - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - rcu_read_lock(); - cb->seq = inet6_base_seq(net); - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - idev = __in6_dev_get(dev); - if (!idev) - goto cont; - - if (inet6_netconf_fill_devconf(skb, dev->ifindex, - &idev->cnf, - NETLINK_CB(cb->skb).portid, - nlh->nlmsg_seq, - RTM_NEWNETCONF, - NLM_F_MULTI, - NETCONFA_ALL) < 0) { - rcu_read_unlock(); - goto done; - } - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - rcu_read_unlock(); - } - if (h == NETDEV_HASHENTRIES) { - if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, - net->ipv6.devconf_all, - NETLINK_CB(cb->skb).portid, - nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) + rcu_read_lock(); + for_each_netdev_dump(net, dev, ctx->ifindex) { + idev = __in6_dev_get(dev); + if (!idev) + continue; + err = inet6_netconf_fill_devconf(skb, dev->ifindex, + &idev->cnf, + NETLINK_CB(cb->skb).portid, + nlh->nlmsg_seq, + RTM_NEWNETCONF, + NLM_F_MULTI, + NETCONFA_ALL); + if (err < 0) goto done; - else - h++; } - if (h == NETDEV_HASHENTRIES + 1) { - if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, - net->ipv6.devconf_dflt, - NETLINK_CB(cb->skb).portid, - nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) + if (ctx->all_default == 0) { + err = inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, + net->ipv6.devconf_all, + NETLINK_CB(cb->skb).portid, + nlh->nlmsg_seq, + RTM_NEWNETCONF, NLM_F_MULTI, + NETCONFA_ALL); + if (err < 0) goto done; - else - h++; + ctx->all_default++; + } + if (ctx->all_default == 1) { + err = inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, + net->ipv6.devconf_dflt, + NETLINK_CB(cb->skb).portid, + nlh->nlmsg_seq, + RTM_NEWNETCONF, NLM_F_MULTI, + NETCONFA_ALL); + if (err < 0) + goto done; + ctx->all_default++; } done: - cb->args[0] = h; - cb->args[1] = idx; - - return skb->len; + if (err < 0 && likely(skb->len)) + err = skb->len; + rcu_read_unlock(); + return err; } #ifdef CONFIG_SYSCTL @@ -7503,7 +7488,8 @@ int __init addrconf_init(void) err = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf, inet6_netconf_dump_devconf, - RTNL_FLAG_DOIT_UNLOCKED); + RTNL_FLAG_DOIT_UNLOCKED | + RTNL_FLAG_DUMP_UNLOCKED); if (err < 0) goto errout; err = ipv6_addr_label_rtnl_register(); From f29f9199c2d2b3c258f577f438885288016847ed Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 28 Feb 2024 15:05:29 +0100 Subject: [PATCH 1678/2255] Simplify net_dbg_ratelimited() dummy There is no need to wrap calls to the no_printk() helper inside an always-false check, as no_printk() already does that internally. Signed-off-by: Geert Uytterhoeven Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/net.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/linux/net.h b/include/linux/net.h index c9b4a63791a4..15df6d5f27a7 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -299,10 +299,7 @@ do { \ net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__) #else #define net_dbg_ratelimited(fmt, ...) \ - do { \ - if (0) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ - } while (0) + no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) #endif #define net_get_random_once(buf, nbytes) \ From f058b2dd70b1a5503dff899010aeb53b436091e5 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Wed, 28 Feb 2024 18:24:09 +0100 Subject: [PATCH 1679/2255] net: phy: qcom: qca808x: add helper for checking for 1G only model There are 2 versions of QCA808x, one 2.5G capable and one 1G capable. Currently, this matter only in the .get_features call however, it will be required for filling supported interface modes so lets add a helper that can be reused. Signed-off-by: Robert Marko Signed-off-by: David S. Miller --- drivers/net/phy/qcom/qca808x.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 2acf852fb4de..a4c61a8e07c3 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -156,6 +156,17 @@ static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); } +static bool qca808x_is_1g_only(struct phy_device *phydev) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); + if (ret < 0) + return true; + + return !!(QCA808X_PHY_CHIP_TYPE_1G & ret); +} + static int qca808x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -350,11 +361,7 @@ static int qca808x_get_features(struct phy_device *phydev) * existed in the bit0 of MMD1.21, we need to remove it manually if * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); - if (ret < 0) - return ret; - - if (QCA808X_PHY_CHIP_TYPE_1G & ret) + if (qca808x_is_1g_only(phydev)) linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); return 0; From cb28f702960695e26597c332b0e46776e825cc34 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Wed, 28 Feb 2024 18:24:10 +0100 Subject: [PATCH 1680/2255] net: phy: qcom: qca808x: fill in possible_interfaces Currently QCA808x driver does not fill the possible_interfaces. 2.5G QCA808x support SGMII and 2500Base-X while 1G model only supports SGMII, so fill the possible_interfaces accordingly. Signed-off-by: Robert Marko Reviewed-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/phy/qcom/qca808x.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index a4c61a8e07c3..5048304ccc9e 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -167,6 +167,16 @@ static bool qca808x_is_1g_only(struct phy_device *phydev) return !!(QCA808X_PHY_CHIP_TYPE_1G & ret); } +static void qca808x_fill_possible_interfaces(struct phy_device *phydev) +{ + unsigned long *possible = phydev->possible_interfaces; + + __set_bit(PHY_INTERFACE_MODE_SGMII, possible); + + if (!qca808x_is_1g_only(phydev)) + __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible); +} + static int qca808x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -231,6 +241,8 @@ static int qca808x_config_init(struct phy_device *phydev) } } + qca808x_fill_possible_interfaces(phydev); + /* Configure adc threshold as 100mv for the link 10M */ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, QCA808X_ADC_THRESHOLD_MASK, From edac4b1132972cf086d59f3919febecc1430ebca Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 28 Feb 2024 14:53:55 -0800 Subject: [PATCH 1681/2255] dt-bindings: net: brcm,unimac-mdio: Add asp-v2.2 The ASP 2.2 Ethernet controller uses a brcm unimac. Signed-off-by: Justin Chen Acked-by: Krzysztof Kozlowski Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/brcm,unimac-mdio.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/brcm,unimac-mdio.yaml b/Documentation/devicetree/bindings/net/brcm,unimac-mdio.yaml index 6684810fcbf0..23dfe0838dca 100644 --- a/Documentation/devicetree/bindings/net/brcm,unimac-mdio.yaml +++ b/Documentation/devicetree/bindings/net/brcm,unimac-mdio.yaml @@ -24,6 +24,7 @@ properties: - brcm,genet-mdio-v5 - brcm,asp-v2.0-mdio - brcm,asp-v2.1-mdio + - brcm,asp-v2.2-mdio - brcm,unimac-mdio reg: From 5682a878e7f1f2c559bb09993181ed1a05315331 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 28 Feb 2024 14:53:56 -0800 Subject: [PATCH 1682/2255] dt-bindings: net: brcm,asp-v2.0: Add asp-v2.2 Add support for ASP 2.2. Signed-off-by: Justin Chen Acked-by: Florian Fainelli Acked-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml b/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml index 75d8138298fb..660e2ca42daf 100644 --- a/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml +++ b/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml @@ -15,6 +15,10 @@ description: Broadcom Ethernet controller first introduced with 72165 properties: compatible: oneOf: + - items: + - enum: + - brcm,bcm74165b0-asp + - const: brcm,asp-v2.2 - items: - enum: - brcm,bcm74165-asp From 1d472eb5b6701810e0b25ae5cea40a9908019780 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 28 Feb 2024 14:53:57 -0800 Subject: [PATCH 1683/2255] net: bcmasp: Add support for ASP 2.2 ASP 2.2 improves power savings during low power modes. A new register was added to toggle to a slower clock during low power modes. EEE was broken for ASP 2.0/2.1. A HW workaround was added for ASP 2.2 that requires toggling a chicken bit. Signed-off-by: Justin Chen Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/asp2/bcmasp.c | 73 +++++++++++++++++-- drivers/net/ethernet/broadcom/asp2/bcmasp.h | 18 ++++- .../net/ethernet/broadcom/asp2/bcmasp_intf.c | 6 ++ 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index 80245c65cc90..100c69f3307a 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -972,7 +972,26 @@ static void bcmasp_core_init(struct bcmasp_priv *priv) ASP_INTR2_CLEAR); } -static void bcmasp_core_clock_select(struct bcmasp_priv *priv, bool slow) +static void bcmasp_core_clock_select_many(struct bcmasp_priv *priv, bool slow) +{ + u32 reg; + + reg = ctrl2_core_rl(priv, ASP_CTRL2_CORE_CLOCK_SELECT); + if (slow) + reg &= ~ASP_CTRL2_CORE_CLOCK_SELECT_MAIN; + else + reg |= ASP_CTRL2_CORE_CLOCK_SELECT_MAIN; + ctrl2_core_wl(priv, reg, ASP_CTRL2_CORE_CLOCK_SELECT); + + reg = ctrl2_core_rl(priv, ASP_CTRL2_CPU_CLOCK_SELECT); + if (slow) + reg &= ~ASP_CTRL2_CPU_CLOCK_SELECT_MAIN; + else + reg |= ASP_CTRL2_CPU_CLOCK_SELECT_MAIN; + ctrl2_core_wl(priv, reg, ASP_CTRL2_CPU_CLOCK_SELECT); +} + +static void bcmasp_core_clock_select_one(struct bcmasp_priv *priv, bool slow) { u32 reg; @@ -1166,6 +1185,24 @@ static void bcmasp_wol_irq_destroy_per_intf(struct bcmasp_priv *priv) } } +static void bcmasp_eee_fixup(struct bcmasp_intf *intf, bool en) +{ + u32 reg, phy_lpi_overwrite; + + reg = rx_edpkt_core_rl(intf->parent, ASP_EDPKT_SPARE_REG); + phy_lpi_overwrite = intf->internal_phy ? ASP_EDPKT_SPARE_REG_EPHY_LPI : + ASP_EDPKT_SPARE_REG_GPHY_LPI; + + if (en) + reg |= phy_lpi_overwrite; + else + reg &= ~phy_lpi_overwrite; + + rx_edpkt_core_wl(intf->parent, reg, ASP_EDPKT_SPARE_REG); + + usleep_range(50, 100); +} + static struct bcmasp_hw_info v20_hw_info = { .rx_ctrl_flush = ASP_RX_CTRL_FLUSH, .umac2fb = UMAC2FB_OFFSET, @@ -1178,6 +1215,7 @@ static const struct bcmasp_plat_data v20_plat_data = { .init_wol = bcmasp_init_wol_per_intf, .enable_wol = bcmasp_enable_wol_per_intf, .destroy_wol = bcmasp_wol_irq_destroy_per_intf, + .core_clock_select = bcmasp_core_clock_select_one, .hw_info = &v20_hw_info, }; @@ -1194,17 +1232,39 @@ static const struct bcmasp_plat_data v21_plat_data = { .init_wol = bcmasp_init_wol_shared, .enable_wol = bcmasp_enable_wol_shared, .destroy_wol = bcmasp_wol_irq_destroy_shared, + .core_clock_select = bcmasp_core_clock_select_one, .hw_info = &v21_hw_info, }; +static const struct bcmasp_plat_data v22_plat_data = { + .init_wol = bcmasp_init_wol_shared, + .enable_wol = bcmasp_enable_wol_shared, + .destroy_wol = bcmasp_wol_irq_destroy_shared, + .core_clock_select = bcmasp_core_clock_select_many, + .hw_info = &v21_hw_info, + .eee_fixup = bcmasp_eee_fixup, +}; + +static void bcmasp_set_pdata(struct bcmasp_priv *priv, const struct bcmasp_plat_data *pdata) +{ + priv->init_wol = pdata->init_wol; + priv->enable_wol = pdata->enable_wol; + priv->destroy_wol = pdata->destroy_wol; + priv->core_clock_select = pdata->core_clock_select; + priv->eee_fixup = pdata->eee_fixup; + priv->hw_info = pdata->hw_info; +} + static const struct of_device_id bcmasp_of_match[] = { { .compatible = "brcm,asp-v2.0", .data = &v20_plat_data }, { .compatible = "brcm,asp-v2.1", .data = &v21_plat_data }, + { .compatible = "brcm,asp-v2.2", .data = &v22_plat_data }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, bcmasp_of_match); static const struct of_device_id bcmasp_mdio_of_match[] = { + { .compatible = "brcm,asp-v2.2-mdio", }, { .compatible = "brcm,asp-v2.1-mdio", }, { .compatible = "brcm,asp-v2.0-mdio", }, { /* sentinel */ }, @@ -1265,16 +1325,13 @@ static int bcmasp_probe(struct platform_device *pdev) if (!pdata) return dev_err_probe(dev, -EINVAL, "unable to find platform data\n"); - priv->init_wol = pdata->init_wol; - priv->enable_wol = pdata->enable_wol; - priv->destroy_wol = pdata->destroy_wol; - priv->hw_info = pdata->hw_info; + bcmasp_set_pdata(priv, pdata); /* Enable all clocks to ensure successful probing */ bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0); /* Switch to the main clock */ - bcmasp_core_clock_select(priv, false); + priv->core_clock_select(priv, false); bcmasp_intr2_mask_set_all(priv); bcmasp_intr2_clear_all(priv); @@ -1381,7 +1438,7 @@ static int __maybe_unused bcmasp_suspend(struct device *d) */ bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE); - bcmasp_core_clock_select(priv, true); + priv->core_clock_select(priv, true); clk_disable_unprepare(priv->clk); @@ -1399,7 +1456,7 @@ static int __maybe_unused bcmasp_resume(struct device *d) return ret; /* Switch to the main clock domain */ - bcmasp_core_clock_select(priv, false); + priv->core_clock_select(priv, false); /* Re-enable all clocks for re-initialization */ bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0); diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index 312bf9b6576e..61598dc070b1 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -33,6 +33,12 @@ #define ASP_WAKEUP_INTR2_FILT_1 BIT(3) #define ASP_WAKEUP_INTR2_FW BIT(4) +#define ASP_CTRL2_OFFSET 0x2000 +#define ASP_CTRL2_CORE_CLOCK_SELECT 0x0 +#define ASP_CTRL2_CORE_CLOCK_SELECT_MAIN BIT(0) +#define ASP_CTRL2_CPU_CLOCK_SELECT 0x4 +#define ASP_CTRL2_CPU_CLOCK_SELECT_MAIN BIT(0) + #define ASP_TX_ANALYTICS_OFFSET 0x4c000 #define ASP_TX_ANALYTICS_CTRL 0x0 @@ -134,8 +140,11 @@ enum asp_rx_net_filter_block { #define ASP_EDPKT_RX_PKT_CNT 0x138 #define ASP_EDPKT_HDR_EXTR_CNT 0x13c #define ASP_EDPKT_HDR_OUT_CNT 0x140 +#define ASP_EDPKT_SPARE_REG 0x174 +#define ASP_EDPKT_SPARE_REG_EPHY_LPI BIT(4) +#define ASP_EDPKT_SPARE_REG_GPHY_LPI BIT(3) -#define ASP_CTRL 0x101000 +#define ASP_CTRL_OFFSET 0x101000 #define ASP_CTRL_ASP_SW_INIT 0x04 #define ASP_CTRL_ASP_SW_INIT_ACPUSS_CORE BIT(0) #define ASP_CTRL_ASP_SW_INIT_ASP_TX BIT(1) @@ -372,6 +381,8 @@ struct bcmasp_plat_data { void (*init_wol)(struct bcmasp_priv *priv); void (*enable_wol)(struct bcmasp_intf *intf, bool en); void (*destroy_wol)(struct bcmasp_priv *priv); + void (*core_clock_select)(struct bcmasp_priv *priv, bool slow); + void (*eee_fixup)(struct bcmasp_intf *priv, bool en); struct bcmasp_hw_info *hw_info; }; @@ -390,6 +401,8 @@ struct bcmasp_priv { void (*init_wol)(struct bcmasp_priv *priv); void (*enable_wol)(struct bcmasp_intf *intf, bool en); void (*destroy_wol)(struct bcmasp_priv *priv); + void (*core_clock_select)(struct bcmasp_priv *priv, bool slow); + void (*eee_fixup)(struct bcmasp_intf *intf, bool en); void __iomem *base; struct bcmasp_hw_info *hw_info; @@ -530,7 +543,8 @@ BCMASP_CORE_IO_MACRO(rx_analytics, ASP_RX_ANALYTICS_OFFSET); BCMASP_CORE_IO_MACRO(rx_ctrl, ASP_RX_CTRL_OFFSET); BCMASP_CORE_IO_MACRO(rx_filter, ASP_RX_FILTER_OFFSET); BCMASP_CORE_IO_MACRO(rx_edpkt, ASP_EDPKT_OFFSET); -BCMASP_CORE_IO_MACRO(ctrl, ASP_CTRL); +BCMASP_CORE_IO_MACRO(ctrl, ASP_CTRL_OFFSET); +BCMASP_CORE_IO_MACRO(ctrl2, ASP_CTRL2_OFFSET); struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv, struct device_node *ndev_dn, int i); diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index e429876c7291..36e6fae937ea 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -1333,6 +1333,9 @@ static void bcmasp_suspend_to_wol(struct bcmasp_intf *intf) ASP_WAKEUP_INTR2_MASK_CLEAR); } + if (intf->eee.eee_enabled && intf->parent->eee_fixup) + intf->parent->eee_fixup(intf, true); + netif_dbg(intf, wol, ndev, "entered WOL mode\n"); } @@ -1381,6 +1384,9 @@ static void bcmasp_resume_from_wol(struct bcmasp_intf *intf) { u32 reg; + if (intf->eee.eee_enabled && intf->parent->eee_fixup) + intf->parent->eee_fixup(intf, false); + reg = umac_rl(intf, UMC_MPD_CTRL); reg &= ~UMC_MPD_CTRL_MPD_EN; umac_wl(intf, reg, UMC_MPD_CTRL); From 9112fc0109fc0037ac3b8b633a169e78b4e23ca1 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 28 Feb 2024 14:53:58 -0800 Subject: [PATCH 1684/2255] net: phy: mdio-bcm-unimac: Add asp v2.2 support Add mdio compat string for ASP 2.0 ethernet driver. Signed-off-by: Justin Chen Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/mdio/mdio-bcm-unimac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c index 6fe08427fdd4..f40eb50bb978 100644 --- a/drivers/net/mdio/mdio-bcm-unimac.c +++ b/drivers/net/mdio/mdio-bcm-unimac.c @@ -334,6 +334,7 @@ static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops, NULL, unimac_mdio_resume); static const struct of_device_id unimac_mdio_ids[] = { + { .compatible = "brcm,asp-v2.2-mdio", }, { .compatible = "brcm,asp-v2.1-mdio", }, { .compatible = "brcm,asp-v2.0-mdio", }, { .compatible = "brcm,genet-mdio-v5", }, From 4688f4f41cfa76638a37db3837cc485e5c83d307 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 28 Feb 2024 14:53:59 -0800 Subject: [PATCH 1685/2255] net: bcmasp: Keep buffers through power management There is no advantage of freeing and re-allocating buffers through suspend and resume. This waste cycles and makes suspend/resume time longer. We also open ourselves to failed allocations in systems with heavy memory fragmentation. Signed-off-by: Justin Chen Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/asp2/bcmasp.h | 1 + .../net/ethernet/broadcom/asp2/bcmasp_intf.c | 194 ++++++++---------- 2 files changed, 86 insertions(+), 109 deletions(-) diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index 61598dc070b1..127a5340625e 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -315,6 +315,7 @@ struct bcmasp_intf { struct bcmasp_desc *rx_edpkt_cpu; dma_addr_t rx_edpkt_dma_addr; dma_addr_t rx_edpkt_dma_read; + dma_addr_t rx_edpkt_dma_valid; /* RX buffer prefetcher ring*/ void *rx_ring_cpu; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index 36e6fae937ea..25b03d32d791 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -674,40 +674,78 @@ static void bcmasp_adj_link(struct net_device *dev) phy_print_status(phydev); } -static int bcmasp_init_rx(struct bcmasp_intf *intf) +static int bcmasp_alloc_buffers(struct bcmasp_intf *intf) { struct device *kdev = &intf->parent->pdev->dev; struct page *buffer_pg; - dma_addr_t dma; - void *p; - u32 reg; - int ret; + /* Alloc RX */ intf->rx_buf_order = get_order(RING_BUFFER_SIZE); buffer_pg = alloc_pages(GFP_KERNEL, intf->rx_buf_order); if (!buffer_pg) return -ENOMEM; - dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE, - DMA_FROM_DEVICE); - if (dma_mapping_error(kdev, dma)) { - __free_pages(buffer_pg, intf->rx_buf_order); - return -ENOMEM; - } intf->rx_ring_cpu = page_to_virt(buffer_pg); - intf->rx_ring_dma = dma; - intf->rx_ring_dma_valid = intf->rx_ring_dma + RING_BUFFER_SIZE - 1; + intf->rx_ring_dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(kdev, intf->rx_ring_dma)) + goto free_rx_buffer; - p = dma_alloc_coherent(kdev, DESC_RING_SIZE, &intf->rx_edpkt_dma_addr, + intf->rx_edpkt_cpu = dma_alloc_coherent(kdev, DESC_RING_SIZE, + &intf->rx_edpkt_dma_addr, GFP_KERNEL); + if (!intf->rx_edpkt_cpu) + goto free_rx_buffer_dma; + + /* Alloc TX */ + intf->tx_spb_cpu = dma_alloc_coherent(kdev, DESC_RING_SIZE, + &intf->tx_spb_dma_addr, GFP_KERNEL); + if (!intf->tx_spb_cpu) + goto free_rx_edpkt_dma; + + intf->tx_cbs = kcalloc(DESC_RING_COUNT, sizeof(struct bcmasp_tx_cb), GFP_KERNEL); - if (!p) { - ret = -ENOMEM; - goto free_rx_ring; - } - intf->rx_edpkt_cpu = p; + if (!intf->tx_cbs) + goto free_tx_spb_dma; - netif_napi_add(intf->ndev, &intf->rx_napi, bcmasp_rx_poll); + return 0; +free_tx_spb_dma: + dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, + intf->tx_spb_dma_addr); +free_rx_edpkt_dma: + dma_free_coherent(kdev, DESC_RING_SIZE, intf->rx_edpkt_cpu, + intf->rx_edpkt_dma_addr); +free_rx_buffer_dma: + dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, + DMA_FROM_DEVICE); +free_rx_buffer: + __free_pages(buffer_pg, intf->rx_buf_order); + + return -ENOMEM; +} + +static void bcmasp_reclaim_free_buffers(struct bcmasp_intf *intf) +{ + struct device *kdev = &intf->parent->pdev->dev; + + /* RX buffers */ + dma_free_coherent(kdev, DESC_RING_SIZE, intf->rx_edpkt_cpu, + intf->rx_edpkt_dma_addr); + dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, + DMA_FROM_DEVICE); + __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order); + + /* TX buffers */ + dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, + intf->tx_spb_dma_addr); + kfree(intf->tx_cbs); +} + +static void bcmasp_init_rx(struct bcmasp_intf *intf) +{ + /* Restart from index 0 */ + intf->rx_ring_dma_valid = intf->rx_ring_dma + RING_BUFFER_SIZE - 1; + intf->rx_edpkt_dma_valid = intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1); intf->rx_edpkt_dma_read = intf->rx_edpkt_dma_addr; intf->rx_edpkt_index = 0; @@ -733,64 +771,23 @@ static int bcmasp_init_rx(struct bcmasp_intf *intf) rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_WRITE); rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_READ); rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_BASE); - rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1), - RX_EDPKT_DMA_END); - rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1), - RX_EDPKT_DMA_VALID); + rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_valid, RX_EDPKT_DMA_END); + rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_valid, RX_EDPKT_DMA_VALID); - reg = UMAC2FB_CFG_DEFAULT_EN | - ((intf->channel + 11) << UMAC2FB_CFG_CHID_SHIFT); - reg |= (0xd << UMAC2FB_CFG_OK_SEND_SHIFT); - umac2fb_wl(intf, reg, UMAC2FB_CFG); - - return 0; - -free_rx_ring: - dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, - DMA_FROM_DEVICE); - __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order); - - return ret; + umac2fb_wl(intf, UMAC2FB_CFG_DEFAULT_EN | ((intf->channel + 11) << + UMAC2FB_CFG_CHID_SHIFT) | (0xd << UMAC2FB_CFG_OK_SEND_SHIFT), + UMAC2FB_CFG); } -static void bcmasp_reclaim_free_all_rx(struct bcmasp_intf *intf) + +static void bcmasp_init_tx(struct bcmasp_intf *intf) { - struct device *kdev = &intf->parent->pdev->dev; - - dma_free_coherent(kdev, DESC_RING_SIZE, intf->rx_edpkt_cpu, - intf->rx_edpkt_dma_addr); - dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, - DMA_FROM_DEVICE); - __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order); -} - -static int bcmasp_init_tx(struct bcmasp_intf *intf) -{ - struct device *kdev = &intf->parent->pdev->dev; - void *p; - int ret; - - p = dma_alloc_coherent(kdev, DESC_RING_SIZE, &intf->tx_spb_dma_addr, - GFP_KERNEL); - if (!p) - return -ENOMEM; - - intf->tx_spb_cpu = p; + /* Restart from index 0 */ intf->tx_spb_dma_valid = intf->tx_spb_dma_addr + DESC_RING_SIZE - 1; intf->tx_spb_dma_read = intf->tx_spb_dma_addr; - - intf->tx_cbs = kcalloc(DESC_RING_COUNT, sizeof(struct bcmasp_tx_cb), - GFP_KERNEL); - if (!intf->tx_cbs) { - ret = -ENOMEM; - goto free_tx_spb; - } - intf->tx_spb_index = 0; intf->tx_spb_clean_index = 0; - netif_napi_add_tx(intf->ndev, &intf->tx_napi, bcmasp_tx_poll); - /* Make sure channels are disabled */ tx_spb_ctrl_wl(intf, 0x0, TX_SPB_CTRL_ENABLE); tx_epkt_core_wl(intf, 0x0, TX_EPKT_C_CFG_MISC); @@ -806,26 +803,6 @@ static int bcmasp_init_tx(struct bcmasp_intf *intf) tx_spb_dma_wq(intf, intf->tx_spb_dma_addr, TX_SPB_DMA_BASE); tx_spb_dma_wq(intf, intf->tx_spb_dma_valid, TX_SPB_DMA_END); tx_spb_dma_wq(intf, intf->tx_spb_dma_valid, TX_SPB_DMA_VALID); - - return 0; - -free_tx_spb: - dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, - intf->tx_spb_dma_addr); - - return ret; -} - -static void bcmasp_reclaim_free_all_tx(struct bcmasp_intf *intf) -{ - struct device *kdev = &intf->parent->pdev->dev; - - /* Free descriptors */ - dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, - intf->tx_spb_dma_addr); - - /* Free cbs */ - kfree(intf->tx_cbs); } static void bcmasp_ephy_enable_set(struct bcmasp_intf *intf, bool enable) @@ -915,10 +892,7 @@ static void bcmasp_netif_deinit(struct net_device *dev) bcmasp_enable_rx_irq(intf, 0); netif_napi_del(&intf->tx_napi); - bcmasp_reclaim_free_all_tx(intf); - netif_napi_del(&intf->rx_napi); - bcmasp_reclaim_free_all_rx(intf); } static int bcmasp_stop(struct net_device *dev) @@ -932,6 +906,8 @@ static int bcmasp_stop(struct net_device *dev) bcmasp_netif_deinit(dev); + bcmasp_reclaim_free_buffers(intf); + phy_disconnect(dev->phydev); /* Disable internal EPHY or external PHY */ @@ -1073,17 +1049,12 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect) intf->old_link = -1; intf->old_pause = -1; - ret = bcmasp_init_tx(intf); - if (ret) - goto err_phy_disconnect; - - /* Turn on asp */ + bcmasp_init_tx(intf); + netif_napi_add_tx(intf->ndev, &intf->tx_napi, bcmasp_tx_poll); bcmasp_enable_tx(intf, 1); - ret = bcmasp_init_rx(intf); - if (ret) - goto err_reclaim_tx; - + bcmasp_init_rx(intf); + netif_napi_add(intf->ndev, &intf->rx_napi, bcmasp_rx_poll); bcmasp_enable_rx(intf, 1); /* Turn on UniMAC TX/RX */ @@ -1097,12 +1068,6 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect) return 0; -err_reclaim_tx: - netif_napi_del(&intf->tx_napi); - bcmasp_reclaim_free_all_tx(intf); -err_phy_disconnect: - if (phydev) - phy_disconnect(phydev); err_phy_disable: if (intf->internal_phy) bcmasp_ephy_enable_set(intf, false); @@ -1118,13 +1083,24 @@ static int bcmasp_open(struct net_device *dev) netif_dbg(intf, ifup, dev, "bcmasp open\n"); - ret = clk_prepare_enable(intf->parent->clk); + ret = bcmasp_alloc_buffers(intf); if (ret) return ret; - ret = bcmasp_netif_init(dev, true); + ret = clk_prepare_enable(intf->parent->clk); if (ret) + goto err_free_mem; + + ret = bcmasp_netif_init(dev, true); + if (ret) { clk_disable_unprepare(intf->parent->clk); + goto err_free_mem; + } + + return ret; + +err_free_mem: + bcmasp_reclaim_free_buffers(intf); return ret; } From cc7f105e7604477a9f40171331d35153e65a6ce3 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 28 Feb 2024 14:54:00 -0800 Subject: [PATCH 1686/2255] net: bcmasp: Add support for PHY interrupts Hook up the phy interrupts for internal phys to reduce mdio traffic and improve responsiveness of link changes. Signed-off-by: Justin Chen Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/asp2/bcmasp.c | 17 +++++++++++++++++ drivers/net/ethernet/broadcom/asp2/bcmasp.h | 4 ++++ .../net/ethernet/broadcom/asp2/bcmasp_intf.c | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index 100c69f3307a..a806dadc4196 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -31,6 +31,20 @@ static void _intr2_mask_set(struct bcmasp_priv *priv, u32 mask) priv->irq_mask |= mask; } +void bcmasp_enable_phy_irq(struct bcmasp_intf *intf, int en) +{ + struct bcmasp_priv *priv = intf->parent; + + /* Only supported with internal phys */ + if (!intf->internal_phy) + return; + + if (en) + _intr2_mask_clear(priv, ASP_INTR2_PHY_EVENT(intf->channel)); + else + _intr2_mask_set(priv, ASP_INTR2_PHY_EVENT(intf->channel)); +} + void bcmasp_enable_tx_irq(struct bcmasp_intf *intf, int en) { struct bcmasp_priv *priv = intf->parent; @@ -79,6 +93,9 @@ static void bcmasp_intr2_handling(struct bcmasp_intf *intf, u32 status) __napi_schedule_irqoff(&intf->tx_napi); } } + + if (status & ASP_INTR2_PHY_EVENT(intf->channel)) + phy_mac_interrupt(intf->ndev->phydev); } static irqreturn_t bcmasp_isr(int irq, void *data) diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index 127a5340625e..f93cb3da44b0 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -19,6 +19,8 @@ #define ASP_INTR2_TX_DESC(intr) BIT((intr) + 14) #define ASP_INTR2_UMC0_WAKE BIT(22) #define ASP_INTR2_UMC1_WAKE BIT(28) +#define ASP_INTR2_PHY_EVENT(intr) ((intr) ? BIT(30) | BIT(31) : \ + BIT(24) | BIT(25)) #define ASP_WAKEUP_INTR2_OFFSET 0x1200 #define ASP_WAKEUP_INTR2_STATUS 0x0 @@ -556,6 +558,8 @@ void bcmasp_enable_tx_irq(struct bcmasp_intf *intf, int en); void bcmasp_enable_rx_irq(struct bcmasp_intf *intf, int en); +void bcmasp_enable_phy_irq(struct bcmasp_intf *intf, int en); + void bcmasp_flush_rx_port(struct bcmasp_intf *intf); extern const struct ethtool_ops bcmasp_ethtool_ops; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index 25b03d32d791..dd06b68b33ed 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -382,6 +382,7 @@ static void bcmasp_netif_start(struct net_device *dev) bcmasp_enable_rx_irq(intf, 1); bcmasp_enable_tx_irq(intf, 1); + bcmasp_enable_phy_irq(intf, 1); phy_start(dev->phydev); } @@ -890,6 +891,7 @@ static void bcmasp_netif_deinit(struct net_device *dev) /* Disable interrupts */ bcmasp_enable_tx_irq(intf, 0); bcmasp_enable_rx_irq(intf, 0); + bcmasp_enable_phy_irq(intf, 0); netif_napi_del(&intf->tx_napi); netif_napi_del(&intf->rx_napi); @@ -1028,6 +1030,9 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect) goto err_phy_disable; } + if (intf->internal_phy) + dev->phydev->irq = PHY_MAC_INTERRUPT; + /* Indicate that the MAC is responsible for PHY PM */ phydev->mac_managed_pm = true; } else if (!intf->wolopts) { From e74048650eaff6674895f2220d0545f5e5920cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Wed, 28 Feb 2024 16:59:08 -0800 Subject: [PATCH 1687/2255] selftests/landlock: Redefine TEST_F() as TEST_F_FORK() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This has the effect of creating a new test process for either TEST_F() or TEST_F_FORK(), which doesn't change tests but will ease potential backports. See next commit for the TEST_F_FORK() merge into TEST_F(). Cc: Günther Noack Cc: Kees Cook Cc: Shuah Khan Cc: Will Drewry Signed-off-by: Mickaël Salaün Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/landlock/common.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index e64bbdf0e86e..f40146d40763 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -37,7 +37,7 @@ struct __test_metadata *_metadata, \ FIXTURE_DATA(fixture_name) *self, \ const FIXTURE_VARIANT(fixture_name) *variant); \ - TEST_F(fixture_name, test_name) \ + __TEST_F_IMPL(fixture_name, test_name, -1, TEST_TIMEOUT_DEFAULT) \ { \ int status; \ const pid_t child = fork(); \ @@ -80,6 +80,10 @@ __attribute__((unused)) *variant) /* clang-format on */ +/* Makes backporting easier. */ +#undef TEST_F +#define TEST_F(fixture_name, test_name) TEST_F_FORK(fixture_name, test_name) + #ifndef landlock_create_ruleset static inline int landlock_create_ruleset(const struct landlock_ruleset_attr *const attr, From 0710a1a73fb45033ebb06073e374ab7d44a05f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Wed, 28 Feb 2024 16:59:09 -0800 Subject: [PATCH 1688/2255] selftests/harness: Merge TEST_F_FORK() into TEST_F() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace Landlock-specific TEST_F_FORK() with an improved TEST_F() which brings four related changes: Run TEST_F()'s tests in a grandchild process to make it possible to drop privileges and delegate teardown to the parent. Compared to TEST_F_FORK(), simplify handling of the test grandchild process thanks to vfork(2), and makes it generic (e.g. no explicit conversion between exit code and _metadata). Compared to TEST_F_FORK(), run teardown even when tests failed with an assert thanks to commit 63e6b2a42342 ("selftests/harness: Run TEARDOWN for ASSERT failures"). Simplify the test harness code by removing the no_print and step fields which are not used. I added this feature just after I made kselftest_harness.h more broadly available but this step counter remained even though it wasn't needed after all. See commit 369130b63178 ("selftests: Enhance kselftest_harness.h to print which assert failed"). Replace spaces with tabs in one line of __TEST_F_IMPL(). Cc: Günther Noack Cc: Shuah Khan Cc: Will Drewry Signed-off-by: Mickaël Salaün Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest_harness.h | 56 +++++++++---------- tools/testing/selftests/landlock/common.h | 62 +-------------------- 2 files changed, 27 insertions(+), 91 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index e05ac8261046..ad49832457af 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -95,14 +95,6 @@ * E.g., #define TH_LOG_ENABLED 1 * * If no definition is provided, logging is enabled by default. - * - * If there is no way to print an error message for the process running the - * test (e.g. not allowed to write to stderr), it is still possible to get the - * ASSERT_* number for which the test failed. This behavior can be enabled by - * writing `_metadata->no_print = true;` before the check sequence that is - * unable to print. When an error occur, instead of printing an error message - * and calling `abort(3)`, the test process call `_exit(2)` with the assert - * number as argument, which is then printed by the parent process. */ #define TH_LOG(fmt, ...) do { \ if (TH_LOG_ENABLED) \ @@ -363,6 +355,11 @@ * Defines a test that depends on a fixture (e.g., is part of a test case). * Very similar to TEST() except that *self* is the setup instance of fixture's * datatype exposed for use by the implementation. + * + * The @test_name code is run in a separate process sharing the same memory + * (i.e. vfork), which means that the test process can update its privileges + * without impacting the related FIXTURE_TEARDOWN() (e.g. to remove files from + * a directory where write access was dropped). */ #define TEST_F(fixture_name, test_name) \ __TEST_F_IMPL(fixture_name, test_name, -1, TEST_TIMEOUT_DEFAULT) @@ -384,15 +381,28 @@ { \ /* fixture data is alloced, setup, and torn down per call. */ \ FIXTURE_DATA(fixture_name) self; \ + pid_t child = 1; \ memset(&self, 0, sizeof(FIXTURE_DATA(fixture_name))); \ if (setjmp(_metadata->env) == 0) { \ fixture_name##_setup(_metadata, &self, variant->data); \ /* Let setup failure terminate early. */ \ - if (!_metadata->passed || _metadata->skip) \ + if (!_metadata->passed || _metadata->skip) \ return; \ _metadata->setup_completed = true; \ - fixture_name##_##test_name(_metadata, &self, variant->data); \ + /* Use the same _metadata. */ \ + child = vfork(); \ + if (child == 0) { \ + fixture_name##_##test_name(_metadata, &self, variant->data); \ + _exit(0); \ + } \ + if (child < 0) { \ + ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \ + _metadata->passed = 0; \ + } \ } \ + if (child == 0) \ + /* Child failed and updated the shared _metadata. */ \ + _exit(0); \ if (_metadata->setup_completed) \ fixture_name##_teardown(_metadata, &self, variant->data); \ __test_check_assert(_metadata); \ @@ -694,18 +704,12 @@ for (; _metadata->trigger; _metadata->trigger = \ __bail(_assert, _metadata)) -#define __INC_STEP(_metadata) \ - /* Keep "step" below 255 (which is used for "SKIP" reporting). */ \ - if (_metadata->passed && _metadata->step < 253) \ - _metadata->step++; - #define is_signed_type(var) (!!(((__typeof__(var))(-1)) < (__typeof__(var))1)) #define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \ /* Avoid multiple evaluation of the cases */ \ __typeof__(_expected) __exp = (_expected); \ __typeof__(_seen) __seen = (_seen); \ - if (_assert) __INC_STEP(_metadata); \ if (!(__exp _t __seen)) { \ /* Report with actual signedness to avoid weird output. */ \ switch (is_signed_type(__exp) * 2 + is_signed_type(__seen)) { \ @@ -751,7 +755,6 @@ #define __EXPECT_STR(_expected, _seen, _t, _assert) do { \ const char *__exp = (_expected); \ const char *__seen = (_seen); \ - if (_assert) __INC_STEP(_metadata); \ if (!(strcmp(__exp, __seen) _t 0)) { \ __TH_LOG("Expected '%s' %s '%s'.", __exp, #_t, __seen); \ _metadata->passed = 0; \ @@ -837,8 +840,6 @@ struct __test_metadata { int trigger; /* extra handler after the evaluation */ int timeout; /* seconds to wait for test timeout */ bool timed_out; /* did this test timeout instead of exiting? */ - __u8 step; - bool no_print; /* manual trigger when TH_LOG_STREAM is not available */ bool aborted; /* stopped test due to failed ASSERT */ bool setup_completed; /* did setup finish? */ jmp_buf env; /* for exiting out of test early */ @@ -873,11 +874,8 @@ static inline int __bail(int for_realz, struct __test_metadata *t) static inline void __test_check_assert(struct __test_metadata *t) { - if (t->aborted) { - if (t->no_print) - _exit(t->step); + if (t->aborted) abort(); - } } struct __test_metadata *__active_test; @@ -954,13 +952,12 @@ void __wait_for_test(struct __test_metadata *t) case 0: t->passed = 1; break; - /* Other failure, assume step report. */ + /* Failure */ default: t->passed = 0; fprintf(TH_LOG_STREAM, - "# %s: Test failed at step #%d\n", - t->name, - WEXITSTATUS(status)); + "# %s: Test failed\n", + t->name); } } } else if (WIFSIGNALED(status)) { @@ -1114,8 +1111,6 @@ void __run_test(struct __fixture_metadata *f, t->passed = 1; t->skip = 0; t->trigger = 0; - t->step = 1; - t->no_print = 0; memset(t->results->reason, 0, sizeof(t->results->reason)); ksft_print_msg(" RUN %s%s%s.%s ...\n", @@ -1137,8 +1132,7 @@ void __run_test(struct __fixture_metadata *f, /* Pass is exit 0 */ if (t->passed) _exit(0); - /* Something else happened, report the step. */ - _exit(t->step); + _exit(1); } else { __wait_for_test(t); } diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index f40146d40763..401e2eb092a3 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -23,66 +23,8 @@ #define __maybe_unused __attribute__((__unused__)) #endif -/* - * TEST_F_FORK() is useful when a test drop privileges but the corresponding - * FIXTURE_TEARDOWN() requires them (e.g. to remove files from a directory - * where write actions are denied). For convenience, FIXTURE_TEARDOWN() is - * also called when the test failed, but not when FIXTURE_SETUP() failed. For - * this to be possible, we must not call abort() but instead exit smoothly - * (hence the step print). - */ -/* clang-format off */ -#define TEST_F_FORK(fixture_name, test_name) \ - static void fixture_name##_##test_name##_child( \ - struct __test_metadata *_metadata, \ - FIXTURE_DATA(fixture_name) *self, \ - const FIXTURE_VARIANT(fixture_name) *variant); \ - __TEST_F_IMPL(fixture_name, test_name, -1, TEST_TIMEOUT_DEFAULT) \ - { \ - int status; \ - const pid_t child = fork(); \ - if (child < 0) \ - abort(); \ - if (child == 0) { \ - _metadata->no_print = 1; \ - fixture_name##_##test_name##_child(_metadata, self, variant); \ - if (_metadata->skip) \ - _exit(255); \ - if (_metadata->passed) \ - _exit(0); \ - _exit(_metadata->step); \ - } \ - if (child != waitpid(child, &status, 0)) \ - abort(); \ - if (WIFSIGNALED(status) || !WIFEXITED(status)) { \ - _metadata->passed = 0; \ - _metadata->step = 1; \ - return; \ - } \ - switch (WEXITSTATUS(status)) { \ - case 0: \ - _metadata->passed = 1; \ - break; \ - case 255: \ - _metadata->passed = 1; \ - _metadata->skip = 1; \ - break; \ - default: \ - _metadata->passed = 0; \ - _metadata->step = WEXITSTATUS(status); \ - break; \ - } \ - } \ - static void fixture_name##_##test_name##_child( \ - struct __test_metadata __attribute__((unused)) *_metadata, \ - FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \ - const FIXTURE_VARIANT(fixture_name) \ - __attribute__((unused)) *variant) -/* clang-format on */ - -/* Makes backporting easier. */ -#undef TEST_F -#define TEST_F(fixture_name, test_name) TEST_F_FORK(fixture_name, test_name) +/* TEST_F_FORK() should not be used for new tests. */ +#define TEST_F_FORK(fixture_name, test_name) TEST_F(fixture_name, test_name) #ifndef landlock_create_ruleset static inline int From a724707976b0bcf5eb6f4637dead0cc380659940 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:10 -0800 Subject: [PATCH 1689/2255] selftests: kselftest_harness: use KSFT_* exit codes Now that we no longer need low exit codes to communicate assertion steps - use normal KSFT exit codes. Acked-by: Kees Cook Tested-by: Jakub Sitnicki Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest_harness.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index ad49832457af..62ce258b0853 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -936,7 +936,7 @@ void __wait_for_test(struct __test_metadata *t) fprintf(TH_LOG_STREAM, "# %s: Test terminated by timeout\n", t->name); } else if (WIFEXITED(status)) { - if (WEXITSTATUS(status) == 255) { + if (WEXITSTATUS(status) == KSFT_SKIP) { /* SKIP */ t->passed = 1; t->skip = 1; @@ -949,7 +949,7 @@ void __wait_for_test(struct __test_metadata *t) } else { switch (WEXITSTATUS(status)) { /* Success */ - case 0: + case KSFT_PASS: t->passed = 1; break; /* Failure */ @@ -1128,11 +1128,10 @@ void __run_test(struct __fixture_metadata *f, setpgrp(); t->fn(t, variant); if (t->skip) - _exit(255); - /* Pass is exit 0 */ + _exit(KSFT_SKIP); if (t->passed) - _exit(0); - _exit(1); + _exit(KSFT_PASS); + _exit(KSFT_FAIL); } else { __wait_for_test(t); } From 38c957f07038278b98af7223a411c0daa54bd1b4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:11 -0800 Subject: [PATCH 1690/2255] selftests: kselftest_harness: generate test name once Since we added variant support generating full test case name takes 4 string arguments. We're about to need it in another two places. Stop the duplication and print once into a temporary buffer. Suggested-by: Jakub Sitnicki Acked-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest_harness.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 62ce258b0853..4a2bda6a67ed 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -1107,14 +1108,18 @@ void __run_test(struct __fixture_metadata *f, struct __fixture_variant_metadata *variant, struct __test_metadata *t) { + char test_name[LINE_MAX]; + /* reset test struct */ t->passed = 1; t->skip = 0; t->trigger = 0; memset(t->results->reason, 0, sizeof(t->results->reason)); - ksft_print_msg(" RUN %s%s%s.%s ...\n", - f->name, variant->name[0] ? "." : "", variant->name, t->name); + snprintf(test_name, sizeof(test_name), "%s%s%s.%s", + f->name, variant->name[0] ? "." : "", variant->name, t->name); + + ksft_print_msg(" RUN %s ...\n", test_name); /* Make sure output buffers are flushed before fork */ fflush(stdout); @@ -1135,15 +1140,14 @@ void __run_test(struct __fixture_metadata *f, } else { __wait_for_test(t); } - ksft_print_msg(" %4s %s%s%s.%s\n", t->passed ? "OK" : "FAIL", - f->name, variant->name[0] ? "." : "", variant->name, t->name); + ksft_print_msg(" %4s %s\n", + t->passed ? "OK" : "FAIL", test_name); if (t->skip) ksft_test_result_skip("%s\n", t->results->reason[0] ? t->results->reason : "unknown"); else - ksft_test_result(t->passed, "%s%s%s.%s\n", - f->name, variant->name[0] ? "." : "", variant->name, t->name); + ksft_test_result(t->passed, "%s\n", test_name); } static int test_harness_run(int argc, char **argv) From 69fe8ec4f673b5b35a34718dc39a5131bfc55e36 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:12 -0800 Subject: [PATCH 1691/2255] selftests: kselftest_harness: save full exit code in metadata Instead of tracking passed = 0/1 rename the field to exit_code and invert the values so that they match the KSFT_* exit codes. This will allow us to fold SKIP / XFAIL into the same value. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest_harness.h | 48 +++++++++++-------- tools/testing/selftests/landlock/base_test.c | 2 +- tools/testing/selftests/landlock/fs_test.c | 4 +- tools/testing/selftests/landlock/net_test.c | 4 +- .../testing/selftests/landlock/ptrace_test.c | 7 +-- tools/testing/selftests/net/tls.c | 2 +- tools/testing/selftests/seccomp/seccomp_bpf.c | 9 ++-- 7 files changed, 41 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 4a2bda6a67ed..d90d4a9039ee 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -128,7 +128,7 @@ fprintf(TH_LOG_STREAM, "# SKIP %s\n", \ _metadata->results->reason); \ } \ - _metadata->passed = 1; \ + _metadata->exit_code = KSFT_PASS; \ _metadata->skip = 1; \ _metadata->trigger = 0; \ statement; \ @@ -387,7 +387,7 @@ if (setjmp(_metadata->env) == 0) { \ fixture_name##_setup(_metadata, &self, variant->data); \ /* Let setup failure terminate early. */ \ - if (!_metadata->passed || _metadata->skip) \ + if (!__test_passed(_metadata) || _metadata->skip) \ return; \ _metadata->setup_completed = true; \ /* Use the same _metadata. */ \ @@ -398,7 +398,7 @@ } \ if (child < 0) { \ ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \ - _metadata->passed = 0; \ + _metadata->exit_code = KSFT_FAIL; \ } \ } \ if (child == 0) \ @@ -747,7 +747,7 @@ break; \ } \ } \ - _metadata->passed = 0; \ + _metadata->exit_code = KSFT_FAIL; \ /* Ensure the optional handler is triggered */ \ _metadata->trigger = 1; \ } \ @@ -758,7 +758,7 @@ const char *__seen = (_seen); \ if (!(strcmp(__exp, __seen) _t 0)) { \ __TH_LOG("Expected '%s' %s '%s'.", __exp, #_t, __seen); \ - _metadata->passed = 0; \ + _metadata->exit_code = KSFT_FAIL; \ _metadata->trigger = 1; \ } \ } while (0); OPTIONAL_HANDLER(_assert) @@ -836,7 +836,7 @@ struct __test_metadata { pid_t pid; /* pid of test when being run */ struct __fixture_metadata *fixture; int termsig; - int passed; + int exit_code; int skip; /* did SKIP get used? */ int trigger; /* extra handler after the evaluation */ int timeout; /* seconds to wait for test timeout */ @@ -848,6 +848,12 @@ struct __test_metadata { struct __test_metadata *prev, *next; }; +static inline bool __test_passed(struct __test_metadata *metadata) +{ + return metadata->exit_code != KSFT_FAIL && + metadata->exit_code <= KSFT_SKIP; +} + /* * Since constructors are called in reverse order, reverse the test * list so tests are run in source declaration order. @@ -912,7 +918,7 @@ void __wait_for_test(struct __test_metadata *t) int status; if (sigaction(SIGALRM, &action, &saved_action)) { - t->passed = 0; + t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, "# %s: unable to install SIGALRM handler\n", t->name); @@ -924,7 +930,7 @@ void __wait_for_test(struct __test_metadata *t) waitpid(t->pid, &status, 0); alarm(0); if (sigaction(SIGALRM, &saved_action, NULL)) { - t->passed = 0; + t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, "# %s: unable to uninstall SIGALRM handler\n", t->name); @@ -933,16 +939,16 @@ void __wait_for_test(struct __test_metadata *t) __active_test = NULL; if (t->timed_out) { - t->passed = 0; + t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, "# %s: Test terminated by timeout\n", t->name); } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) == KSFT_SKIP) { /* SKIP */ - t->passed = 1; + t->exit_code = KSFT_PASS; t->skip = 1; } else if (t->termsig != -1) { - t->passed = 0; + t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, "# %s: Test exited normally instead of by signal (code: %d)\n", t->name, @@ -951,24 +957,24 @@ void __wait_for_test(struct __test_metadata *t) switch (WEXITSTATUS(status)) { /* Success */ case KSFT_PASS: - t->passed = 1; + t->exit_code = KSFT_PASS; break; /* Failure */ default: - t->passed = 0; + t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, "# %s: Test failed\n", t->name); } } } else if (WIFSIGNALED(status)) { - t->passed = 0; + t->exit_code = KSFT_FAIL; if (WTERMSIG(status) == SIGABRT) { fprintf(TH_LOG_STREAM, "# %s: Test terminated by assertion\n", t->name); } else if (WTERMSIG(status) == t->termsig) { - t->passed = 1; + t->exit_code = KSFT_PASS; } else { fprintf(TH_LOG_STREAM, "# %s: Test terminated unexpectedly by signal %d\n", @@ -1111,7 +1117,7 @@ void __run_test(struct __fixture_metadata *f, char test_name[LINE_MAX]; /* reset test struct */ - t->passed = 1; + t->exit_code = KSFT_PASS; t->skip = 0; t->trigger = 0; memset(t->results->reason, 0, sizeof(t->results->reason)); @@ -1128,26 +1134,26 @@ void __run_test(struct __fixture_metadata *f, t->pid = fork(); if (t->pid < 0) { ksft_print_msg("ERROR SPAWNING TEST CHILD\n"); - t->passed = 0; + t->exit_code = KSFT_FAIL; } else if (t->pid == 0) { setpgrp(); t->fn(t, variant); if (t->skip) _exit(KSFT_SKIP); - if (t->passed) + if (__test_passed(t)) _exit(KSFT_PASS); _exit(KSFT_FAIL); } else { __wait_for_test(t); } ksft_print_msg(" %4s %s\n", - t->passed ? "OK" : "FAIL", test_name); + __test_passed(t) ? "OK" : "FAIL", test_name); if (t->skip) ksft_test_result_skip("%s\n", t->results->reason[0] ? t->results->reason : "unknown"); else - ksft_test_result(t->passed, "%s\n", test_name); + ksft_test_result(__test_passed(t), "%s\n", test_name); } static int test_harness_run(int argc, char **argv) @@ -1195,7 +1201,7 @@ static int test_harness_run(int argc, char **argv) t->results = results; __run_test(f, v, t); t->results = NULL; - if (t->passed) + if (__test_passed(t)) pass_count++; else ret = 1; diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c index 646f778dfb1e..a6f89aaea77d 100644 --- a/tools/testing/selftests/landlock/base_test.c +++ b/tools/testing/selftests/landlock/base_test.c @@ -307,7 +307,7 @@ TEST(ruleset_fd_transfer) dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC); ASSERT_LE(0, dir_fd); ASSERT_EQ(0, close(dir_fd)); - _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); + _exit(_metadata->exit_code); return; } diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 2d6d9b43d958..98817a14c91b 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -1964,7 +1964,7 @@ static void test_execute(struct __test_metadata *const _metadata, const int err, strerror(errno)); }; ASSERT_EQ(err, errno); - _exit(_metadata->passed ? 2 : 1); + _exit(__test_passed(_metadata) ? 2 : 1); return; } ASSERT_EQ(child, waitpid(child, &status, 0)); @@ -3807,7 +3807,7 @@ TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes) ASSERT_EQ(0, close(socket_fds[0])); - _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); + _exit(_metadata->exit_code); return; } diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 936cfc879f1d..f21cfbbc3638 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -539,7 +539,7 @@ static void test_bind_and_connect(struct __test_metadata *const _metadata, } EXPECT_EQ(0, close(connect_fd)); - _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); + _exit(_metadata->exit_code); return; } @@ -834,7 +834,7 @@ TEST_F(protocol, connect_unspec) } EXPECT_EQ(0, close(connect_fd)); - _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); + _exit(_metadata->exit_code); return; } diff --git a/tools/testing/selftests/landlock/ptrace_test.c b/tools/testing/selftests/landlock/ptrace_test.c index 55e7871631a1..a19db4d0b3bd 100644 --- a/tools/testing/selftests/landlock/ptrace_test.c +++ b/tools/testing/selftests/landlock/ptrace_test.c @@ -314,7 +314,7 @@ TEST_F(hierarchy, trace) ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); if (variant->domain_both) { create_domain(_metadata); - if (!_metadata->passed) + if (!__test_passed(_metadata)) /* Aborts before forking. */ return; } @@ -375,7 +375,7 @@ TEST_F(hierarchy, trace) /* Waits for the parent PTRACE_ATTACH test. */ ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1)); - _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); + _exit(_metadata->exit_code); return; } @@ -430,9 +430,10 @@ TEST_F(hierarchy, trace) /* Signals that the parent PTRACE_ATTACH test is done. */ ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); ASSERT_EQ(child, waitpid(child, &status, 0)); + if (WIFSIGNALED(status) || !WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS) - _metadata->passed = 0; + _metadata->exit_code = KSFT_FAIL; } TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index b95c249f81c2..c6eda21cefb6 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -1927,7 +1927,7 @@ TEST_F(tls_err, poll_partial_rec_async) pfd.events = POLLIN; EXPECT_EQ(poll(&pfd, 1, 20), 1); - exit(!_metadata->passed); + exit(!__test_passed(_metadata)); } } diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 38f651469968..1027e6170186 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -1576,7 +1576,7 @@ void start_tracer(struct __test_metadata *_metadata, int fd, pid_t tracee, ASSERT_EQ(0, ret); } /* Directly report the status of our test harness results. */ - syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); + syscall(__NR_exit, _metadata->exit_code); } /* Common tracer setup/teardown functions. */ @@ -1623,7 +1623,7 @@ void teardown_trace_fixture(struct __test_metadata *_metadata, ASSERT_EQ(0, kill(tracer, SIGUSR1)); ASSERT_EQ(tracer, waitpid(tracer, &status, 0)); if (WEXITSTATUS(status)) - _metadata->passed = 0; + _metadata->exit_code = KSFT_FAIL; } } @@ -3088,8 +3088,7 @@ TEST(syscall_restart) } /* Directly report the status of our test harness results. */ - syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS - : EXIT_FAILURE); + syscall(__NR_exit, _metadata->exit_code); } EXPECT_EQ(0, close(pipefd[0])); @@ -3174,7 +3173,7 @@ TEST(syscall_restart) ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); if (WIFSIGNALED(status) || WEXITSTATUS(status)) - _metadata->passed = 0; + _metadata->exit_code = KSFT_FAIL; } TEST_SIGNAL(filter_flag_log, SIGSYS) From 796a344fa4315f9c1f2258de14c1d20cbbef79a8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:13 -0800 Subject: [PATCH 1692/2255] selftests: kselftest_harness: use exit code to store skip We always use skip in combination with exit_code being 0 (KSFT_PASS). This are basic KSFT / KTAP semantics. Store the right KSFT_* code in exit_code directly. This makes it easier to support tests reporting other extended KSFT_* codes like XFAIL / XPASS. Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest_harness.h | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index d90d4a9039ee..5a48177c8c00 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -128,8 +128,7 @@ fprintf(TH_LOG_STREAM, "# SKIP %s\n", \ _metadata->results->reason); \ } \ - _metadata->exit_code = KSFT_PASS; \ - _metadata->skip = 1; \ + _metadata->exit_code = KSFT_SKIP; \ _metadata->trigger = 0; \ statement; \ } while (0) @@ -387,7 +386,7 @@ if (setjmp(_metadata->env) == 0) { \ fixture_name##_setup(_metadata, &self, variant->data); \ /* Let setup failure terminate early. */ \ - if (!__test_passed(_metadata) || _metadata->skip) \ + if (_metadata->exit_code) \ return; \ _metadata->setup_completed = true; \ /* Use the same _metadata. */ \ @@ -837,7 +836,6 @@ struct __test_metadata { struct __fixture_metadata *fixture; int termsig; int exit_code; - int skip; /* did SKIP get used? */ int trigger; /* extra handler after the evaluation */ int timeout; /* seconds to wait for test timeout */ bool timed_out; /* did this test timeout instead of exiting? */ @@ -944,9 +942,7 @@ void __wait_for_test(struct __test_metadata *t) "# %s: Test terminated by timeout\n", t->name); } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) == KSFT_SKIP) { - /* SKIP */ - t->exit_code = KSFT_PASS; - t->skip = 1; + t->exit_code = WEXITSTATUS(status); } else if (t->termsig != -1) { t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, @@ -1118,7 +1114,6 @@ void __run_test(struct __fixture_metadata *f, /* reset test struct */ t->exit_code = KSFT_PASS; - t->skip = 0; t->trigger = 0; memset(t->results->reason, 0, sizeof(t->results->reason)); @@ -1138,18 +1133,14 @@ void __run_test(struct __fixture_metadata *f, } else if (t->pid == 0) { setpgrp(); t->fn(t, variant); - if (t->skip) - _exit(KSFT_SKIP); - if (__test_passed(t)) - _exit(KSFT_PASS); - _exit(KSFT_FAIL); + _exit(t->exit_code); } else { __wait_for_test(t); } ksft_print_msg(" %4s %s\n", __test_passed(t) ? "OK" : "FAIL", test_name); - if (t->skip) + if (t->exit_code == KSFT_SKIP) ksft_test_result_skip("%s\n", t->results->reason[0] ? t->results->reason : "unknown"); else From fa1a53d83674b3aa089b8661ee9f884c024f6e95 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:14 -0800 Subject: [PATCH 1693/2255] selftests: kselftest: add ksft_test_result_code(), handling all exit codes For generic test harness code it's more useful to deal with exit codes directly, rather than having to switch on them and call the right ksft_test_result_*() helper. Add such function to kselftest.h. Note that "directive" and "diagnostic" are what ktap docs call those parts of the message. Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest.h | 39 +++++++++++++++++++++ tools/testing/selftests/kselftest_harness.h | 9 +++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index a781e6311810..12ad7f8dfe3a 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h @@ -25,6 +25,7 @@ * ksft_test_result_skip(fmt, ...); * ksft_test_result_xfail(fmt, ...); * ksft_test_result_error(fmt, ...); + * ksft_test_result_code(exit_code, test_name, fmt, ...); * * When all tests are finished, clean up and exit the program with one of: * @@ -254,6 +255,44 @@ static inline __printf(1, 2) void ksft_test_result_error(const char *msg, ...) va_end(args); } +static inline __printf(2, 3) +void ksft_test_result_code(int exit_code, const char *msg, ...) +{ + const char *tap_code = "ok"; + const char *directive = ""; + int saved_errno = errno; + va_list args; + + switch (exit_code) { + case KSFT_PASS: + ksft_cnt.ksft_pass++; + break; + case KSFT_XFAIL: + directive = " # XFAIL "; + ksft_cnt.ksft_xfail++; + break; + case KSFT_XPASS: + directive = " # XPASS "; + ksft_cnt.ksft_xpass++; + break; + case KSFT_SKIP: + directive = " # SKIP "; + ksft_cnt.ksft_xskip++; + break; + case KSFT_FAIL: + default: + tap_code = "not ok"; + ksft_cnt.ksft_fail++; + break; + } + + va_start(args, msg); + printf("%s %u%s", tap_code, ksft_test_num(), directive); + errno = saved_errno; + vprintf(msg, args); + va_end(args); +} + static inline int ksft_exit_pass(void) { ksft_print_cnts(); diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 5a48177c8c00..4fb30fcc7774 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -1111,6 +1111,7 @@ void __run_test(struct __fixture_metadata *f, struct __test_metadata *t) { char test_name[LINE_MAX]; + const char *diagnostic; /* reset test struct */ t->exit_code = KSFT_PASS; @@ -1140,9 +1141,13 @@ void __run_test(struct __fixture_metadata *f, ksft_print_msg(" %4s %s\n", __test_passed(t) ? "OK" : "FAIL", test_name); + if (t->results->reason[0]) + diagnostic = t->results->reason; + else + diagnostic = "unknown"; + if (t->exit_code == KSFT_SKIP) - ksft_test_result_skip("%s\n", t->results->reason[0] ? - t->results->reason : "unknown"); + ksft_test_result_code(t->exit_code, "%s\n", diagnostic); else ksft_test_result(__test_passed(t), "%s\n", test_name); } From 732e2035280bf499a4b002677e2a1845f557d403 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:15 -0800 Subject: [PATCH 1694/2255] selftests: kselftest_harness: print test name for SKIP Jakub points out that for parsers it's rather useful to always have the test name on the result line. Currently if we SKIP (or soon XFAIL or XPASS), we will print: ok 17 # SKIP SCTP doesn't support IP_BIND_ADDRESS_NO_PORT ^ no test name Always print the test name. KTAP format seems to allow or even call for it, per: https://docs.kernel.org/dev-tools/ktap.html Suggested-by: Jakub Sitnicki Link: https://lore.kernel.org/all/87jzn6lnou.fsf@cloudflare.com/ Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest.h | 7 ++++--- tools/testing/selftests/kselftest_harness.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index 12ad7f8dfe3a..25e29626566e 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h @@ -255,8 +255,9 @@ static inline __printf(1, 2) void ksft_test_result_error(const char *msg, ...) va_end(args); } -static inline __printf(2, 3) -void ksft_test_result_code(int exit_code, const char *msg, ...) +static inline __printf(3, 4) +void ksft_test_result_code(int exit_code, const char *test_name, + const char *msg, ...) { const char *tap_code = "ok"; const char *directive = ""; @@ -287,7 +288,7 @@ void ksft_test_result_code(int exit_code, const char *msg, ...) } va_start(args, msg); - printf("%s %u%s", tap_code, ksft_test_num(), directive); + printf("%s %u %s%s", tap_code, ksft_test_num(), test_name, directive); errno = saved_errno; vprintf(msg, args); va_end(args); diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 4fb30fcc7774..82377051aa54 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -1147,7 +1147,8 @@ void __run_test(struct __fixture_metadata *f, diagnostic = "unknown"; if (t->exit_code == KSFT_SKIP) - ksft_test_result_code(t->exit_code, "%s\n", diagnostic); + ksft_test_result_code(t->exit_code, test_name, + "%s\n", diagnostic); else ksft_test_result(__test_passed(t), "%s\n", test_name); } From 42ab727eb95fcff83e7a67fcdbf467bbcd53451e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:16 -0800 Subject: [PATCH 1695/2255] selftests: kselftest_harness: separate diagnostic message with # in ksft_test_result_code() According to the spec we should always print a # if we add a diagnostic message. Having the caller pass in the new line as part of diagnostic message makes handling this a bit counter-intuitive, so append the new line in the helper. Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest.h | 5 +++++ tools/testing/selftests/kselftest_harness.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index 25e29626566e..541bf192e30e 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h @@ -287,10 +287,15 @@ void ksft_test_result_code(int exit_code, const char *test_name, break; } + /* Docs seem to call for double space if directive is absent */ + if (!directive[0] && msg[0]) + directive = " # "; + va_start(args, msg); printf("%s %u %s%s", tap_code, ksft_test_num(), test_name, directive); errno = saved_errno; vprintf(msg, args); + printf("\n"); va_end(args); } diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 82377051aa54..5b0592e4b7a4 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -1148,7 +1148,7 @@ void __run_test(struct __fixture_metadata *f, if (t->exit_code == KSFT_SKIP) ksft_test_result_code(t->exit_code, test_name, - "%s\n", diagnostic); + "%s", diagnostic); else ksft_test_result(__test_passed(t), "%s\n", test_name); } From 378193eff3399acb8529d0b553709e8f91d34fe3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:17 -0800 Subject: [PATCH 1696/2255] selftests: kselftest_harness: let PASS / FAIL provide diagnostic Switch to printing KTAP line for PASS / FAIL with ksft_test_result_code(), this gives us the ability to report diagnostic messages. Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest_harness.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 5b0592e4b7a4..b643a577f9e1 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -1143,14 +1143,13 @@ void __run_test(struct __fixture_metadata *f, if (t->results->reason[0]) diagnostic = t->results->reason; + else if (t->exit_code == KSFT_PASS || t->exit_code == KSFT_FAIL) + diagnostic = NULL; else diagnostic = "unknown"; - if (t->exit_code == KSFT_SKIP) - ksft_test_result_code(t->exit_code, test_name, - "%s", diagnostic); - else - ksft_test_result(__test_passed(t), "%s\n", test_name); + ksft_test_result_code(t->exit_code, test_name, + diagnostic ? "%s" : "", diagnostic); } static int test_harness_run(int argc, char **argv) From 2709473c938602c3955b87000009e9bf3cd9bb32 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:18 -0800 Subject: [PATCH 1697/2255] selftests: kselftest_harness: support using xfail Currently some tests report skip for things they expect to fail e.g. when given combination of parameters is known to be unsupported. This is confusing because in an ideal test environment and fully featured kernel no tests should be skipped. Selftest summary line already includes xfail and xpass counters, e.g.: Totals: pass:725 fail:0 xfail:0 xpass:0 skip:0 error:0 but there's no way to use it from within the harness. Add a new per-fixture+variant combination list of test cases we expect to fail. Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/kselftest_harness.h | 49 ++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index b643a577f9e1..634be793ad58 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -803,6 +803,37 @@ struct __fixture_metadata { .prev = &_fixture_global, }; +struct __test_xfail { + struct __fixture_metadata *fixture; + struct __fixture_variant_metadata *variant; + struct __test_metadata *test; + struct __test_xfail *prev, *next; +}; + +/** + * XFAIL_ADD() - mark variant + test case combination as expected to fail + * @fixture_name: name of the fixture + * @variant_name: name of the variant + * @test_name: name of the test case + * + * Mark a combination of variant + test case for a given fixture as expected + * to fail. Tests marked this way will report XPASS / XFAIL return codes, + * instead of PASS / FAIL,and use respective counters. + */ +#define XFAIL_ADD(fixture_name, variant_name, test_name) \ + static struct __test_xfail \ + _##fixture_name##_##variant_name##_##test_name##_xfail = \ + { \ + .fixture = &_##fixture_name##_fixture_object, \ + .variant = &_##fixture_name##_##variant_name##_object, \ + .test = &_##fixture_name##_##test_name##_object, \ + }; \ + static void __attribute__((constructor)) \ + _register_##fixture_name##_##variant_name##_##test_name##_xfail(void) \ + { \ + __register_xfail(&_##fixture_name##_##variant_name##_##test_name##_xfail); \ + } + static struct __fixture_metadata *__fixture_list = &_fixture_global; static int __constructor_order; @@ -817,6 +848,7 @@ static inline void __register_fixture(struct __fixture_metadata *f) struct __fixture_variant_metadata { const char *name; const void *data; + struct __test_xfail *xfails; struct __fixture_variant_metadata *prev, *next; }; @@ -866,6 +898,11 @@ static inline void __register_test(struct __test_metadata *t) __LIST_APPEND(t->fixture->tests, t); } +static inline void __register_xfail(struct __test_xfail *xf) +{ + __LIST_APPEND(xf->variant->xfails, xf); +} + static inline int __bail(int for_realz, struct __test_metadata *t) { /* if this is ASSERT, return immediately. */ @@ -941,7 +978,9 @@ void __wait_for_test(struct __test_metadata *t) fprintf(TH_LOG_STREAM, "# %s: Test terminated by timeout\n", t->name); } else if (WIFEXITED(status)) { - if (WEXITSTATUS(status) == KSFT_SKIP) { + if (WEXITSTATUS(status) == KSFT_SKIP || + WEXITSTATUS(status) == KSFT_XPASS || + WEXITSTATUS(status) == KSFT_XFAIL) { t->exit_code = WEXITSTATUS(status); } else if (t->termsig != -1) { t->exit_code = KSFT_FAIL; @@ -1110,6 +1149,7 @@ void __run_test(struct __fixture_metadata *f, struct __fixture_variant_metadata *variant, struct __test_metadata *t) { + struct __test_xfail *xfail; char test_name[LINE_MAX]; const char *diagnostic; @@ -1141,6 +1181,13 @@ void __run_test(struct __fixture_metadata *f, ksft_print_msg(" %4s %s\n", __test_passed(t) ? "OK" : "FAIL", test_name); + /* Check if we're expecting this test to fail */ + for (xfail = variant->xfails; xfail; xfail = xfail->next) + if (xfail->test == t) + break; + if (xfail) + t->exit_code = __test_passed(t) ? KSFT_XPASS : KSFT_XFAIL; + if (t->results->reason[0]) diagnostic = t->results->reason; else if (t->exit_code == KSFT_PASS || t->exit_code == KSFT_FAIL) From c05bf0e933129dbb71d057949d90531b03462538 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 28 Feb 2024 16:59:19 -0800 Subject: [PATCH 1698/2255] selftests: ip_local_port_range: use XFAIL instead of SKIP SCTP does not support IP_LOCAL_PORT_RANGE and we know it, so use XFAIL instead of SKIP. Reviewed-by: Kees Cook Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/net/ip_local_port_range.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/net/ip_local_port_range.c b/tools/testing/selftests/net/ip_local_port_range.c index 6ebd58869a63..193b82745fd8 100644 --- a/tools/testing/selftests/net/ip_local_port_range.c +++ b/tools/testing/selftests/net/ip_local_port_range.c @@ -365,9 +365,6 @@ TEST_F(ip_local_port_range, late_bind) __u32 range; __u16 port; - if (variant->so_protocol == IPPROTO_SCTP) - SKIP(return, "SCTP doesn't support IP_BIND_ADDRESS_NO_PORT"); - fd = socket(variant->so_domain, variant->so_type, 0); ASSERT_GE(fd, 0) TH_LOG("socket failed"); @@ -414,6 +411,9 @@ TEST_F(ip_local_port_range, late_bind) ASSERT_TRUE(!err) TH_LOG("close failed"); } +XFAIL_ADD(ip_local_port_range, ip4_stcp, late_bind); +XFAIL_ADD(ip_local_port_range, ip6_stcp, late_bind); + TEST_F(ip_local_port_range, get_port_range) { __u16 lo, hi; From f532957d76de89b8ee2545cb6ad5265e1701d0ba Mon Sep 17 00:00:00 2001 From: David Wei Date: Wed, 28 Feb 2024 15:22:49 -0800 Subject: [PATCH 1699/2255] netdevsim: allow two netdevsim ports to be connected Add two netdevsim bus attribute to sysfs: /sys/bus/netdevsim/link_device /sys/bus/netdevsim/unlink_device Writing "A M B N" to link_device will link netdevsim M in netnsid A with netdevsim N in netnsid B. Writing "A M" to unlink_device will unlink netdevsim M in netnsid A from its peer, if any. rtnl_lock is taken to ensure nothing changes during the linking. Signed-off-by: David Wei Reviewed-by: Maciek Machnikowski Signed-off-by: David S. Miller --- drivers/net/netdevsim/bus.c | 145 ++++++++++++++++++++++++++++++ drivers/net/netdevsim/netdev.c | 10 +++ drivers/net/netdevsim/netdevsim.h | 2 + 3 files changed, 157 insertions(+) diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index 0c5aff63d242..64c0cdd31bf8 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -232,9 +232,154 @@ del_device_store(const struct bus_type *bus, const char *buf, size_t count) } static BUS_ATTR_WO(del_device); +static ssize_t link_device_store(const struct bus_type *bus, const char *buf, size_t count) +{ + struct netdevsim *nsim_a, *nsim_b, *peer; + struct net_device *dev_a, *dev_b; + unsigned int ifidx_a, ifidx_b; + int netnsfd_a, netnsfd_b, err; + struct net *ns_a, *ns_b; + + err = sscanf(buf, "%d:%u %d:%u", &netnsfd_a, &ifidx_a, &netnsfd_b, + &ifidx_b); + if (err != 4) { + pr_err("Format for linking two devices is \"netnsfd_a:ifidx_a netnsfd_b:ifidx_b\" (int uint int uint).\n"); + return -EINVAL; + } + + ns_a = get_net_ns_by_fd(netnsfd_a); + if (IS_ERR(ns_a)) { + pr_err("Could not find netns with fd: %d\n", netnsfd_a); + return -EINVAL; + } + + ns_b = get_net_ns_by_fd(netnsfd_b); + if (IS_ERR(ns_b)) { + pr_err("Could not find netns with fd: %d\n", netnsfd_b); + put_net(ns_a); + return -EINVAL; + } + + err = -EINVAL; + rtnl_lock(); + dev_a = __dev_get_by_index(ns_a, ifidx_a); + if (!dev_a) { + pr_err("Could not find device with ifindex %u in netnsfd %d\n", + ifidx_a, netnsfd_a); + goto out_err; + } + + if (!netdev_is_nsim(dev_a)) { + pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n", + ifidx_a, netnsfd_a); + goto out_err; + } + + dev_b = __dev_get_by_index(ns_b, ifidx_b); + if (!dev_b) { + pr_err("Could not find device with ifindex %u in netnsfd %d\n", + ifidx_b, netnsfd_b); + goto out_err; + } + + if (!netdev_is_nsim(dev_b)) { + pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n", + ifidx_b, netnsfd_b); + goto out_err; + } + + if (dev_a == dev_b) { + pr_err("Cannot link a netdevsim to itself\n"); + goto out_err; + } + + err = -EBUSY; + nsim_a = netdev_priv(dev_a); + peer = rtnl_dereference(nsim_a->peer); + if (peer) { + pr_err("Netdevsim %d:%u is already linked\n", netnsfd_a, + ifidx_a); + goto out_err; + } + + nsim_b = netdev_priv(dev_b); + peer = rtnl_dereference(nsim_b->peer); + if (peer) { + pr_err("Netdevsim %d:%u is already linked\n", netnsfd_b, + ifidx_b); + goto out_err; + } + + err = 0; + rcu_assign_pointer(nsim_a->peer, nsim_b); + rcu_assign_pointer(nsim_b->peer, nsim_a); + +out_err: + put_net(ns_b); + put_net(ns_a); + rtnl_unlock(); + + return !err ? count : err; +} +static BUS_ATTR_WO(link_device); + +static ssize_t unlink_device_store(const struct bus_type *bus, const char *buf, size_t count) +{ + struct netdevsim *nsim, *peer; + struct net_device *dev; + unsigned int ifidx; + int netnsfd, err; + struct net *ns; + + err = sscanf(buf, "%u:%u", &netnsfd, &ifidx); + if (err != 2) { + pr_err("Format for unlinking a device is \"netnsfd:ifidx\" (int uint).\n"); + return -EINVAL; + } + + ns = get_net_ns_by_fd(netnsfd); + if (IS_ERR(ns)) { + pr_err("Could not find netns with fd: %d\n", netnsfd); + return -EINVAL; + } + + err = -EINVAL; + rtnl_lock(); + dev = __dev_get_by_index(ns, ifidx); + if (!dev) { + pr_err("Could not find device with ifindex %u in netnsfd %d\n", + ifidx, netnsfd); + goto out_put_netns; + } + + if (!netdev_is_nsim(dev)) { + pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n", + ifidx, netnsfd); + goto out_put_netns; + } + + nsim = netdev_priv(dev); + peer = rtnl_dereference(nsim->peer); + if (!peer) + goto out_put_netns; + + err = 0; + RCU_INIT_POINTER(nsim->peer, NULL); + RCU_INIT_POINTER(peer->peer, NULL); + +out_put_netns: + put_net(ns); + rtnl_unlock(); + + return !err ? count : err; +} +static BUS_ATTR_WO(unlink_device); + static struct attribute *nsim_bus_attrs[] = { &bus_attr_new_device.attr, &bus_attr_del_device.attr, + &bus_attr_link_device.attr, + &bus_attr_unlink_device.attr, NULL }; ATTRIBUTE_GROUPS(nsim_bus); diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 77e8250282a5..9063f4f2971b 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -413,8 +413,13 @@ err_free_netdev: void nsim_destroy(struct netdevsim *ns) { struct net_device *dev = ns->netdev; + struct netdevsim *peer; rtnl_lock(); + peer = rtnl_dereference(ns->peer); + if (peer) + RCU_INIT_POINTER(peer->peer, NULL); + RCU_INIT_POINTER(ns->peer, NULL); unregister_netdevice(dev); if (nsim_dev_port_is_pf(ns->nsim_dev_port)) { nsim_macsec_teardown(ns); @@ -427,6 +432,11 @@ void nsim_destroy(struct netdevsim *ns) free_netdev(dev); } +bool netdev_is_nsim(struct net_device *dev) +{ + return dev->netdev_ops == &nsim_netdev_ops; +} + static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 028c825b86db..c8b45b0d955e 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -125,11 +125,13 @@ struct netdevsim { } udp_ports; struct nsim_ethtool ethtool; + struct netdevsim __rcu *peer; }; struct netdevsim * nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port); void nsim_destroy(struct netdevsim *ns); +bool netdev_is_nsim(struct net_device *dev); void nsim_ethtool_init(struct netdevsim *ns); From 9eb95228a74163e26d338913a5d61e571ea45307 Mon Sep 17 00:00:00 2001 From: David Wei Date: Wed, 28 Feb 2024 15:22:50 -0800 Subject: [PATCH 1700/2255] netdevsim: forward skbs from one connected port to another Forward skbs sent from one netdevsim port to its connected netdevsim port using dev_forward_skb, in a spirit similar to veth. Add a tx_dropped variable to struct netdevsim, tracking the number of skbs that could not be forwarded using dev_forward_skb(). The xmit() function accessing the peer ptr is protected by an RCU read critical section. The rcu_read_lock() is functionally redundant as since v5.0 all softirqs are implicitly RCU read critical sections; but it is useful for human readers. If another CPU is concurrently in nsim_destroy(), then it will first set the peer ptr to NULL. This does not affect any existing readers that dereferenced a non-NULL peer. Then, in unregister_netdevice(), there is a synchronize_rcu() before the netdev is actually unregistered and freed. This ensures that any readers i.e. xmit() that got a non-NULL peer will complete before the netdev is freed. Any readers after the RCU_INIT_POINTER() but before synchronize_rcu() will dereference NULL, making it safe. The codepath to nsim_destroy() and nsim_create() takes both the newly added nsim_dev_list_lock and rtnl_lock. This makes it safe with concurrent calls to linking two netdevsims together. Signed-off-by: David Wei Reviewed-by: Maciek Machnikowski Signed-off-by: David S. Miller --- drivers/net/netdevsim/netdev.c | 27 ++++++++++++++++++++++----- drivers/net/netdevsim/netdevsim.h | 1 + 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 9063f4f2971b..c3f3fda5fdc0 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -29,18 +29,35 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct netdevsim *ns = netdev_priv(dev); + unsigned int len = skb->len; + struct netdevsim *peer_ns; + rcu_read_lock(); if (!nsim_ipsec_tx(ns, skb)) - goto out; + goto out_drop_free; + peer_ns = rcu_dereference(ns->peer); + if (!peer_ns) + goto out_drop_free; + + skb_tx_timestamp(skb); + if (unlikely(dev_forward_skb(peer_ns->netdev, skb) == NET_RX_DROP)) + goto out_drop_cnt; + + rcu_read_unlock(); u64_stats_update_begin(&ns->syncp); ns->tx_packets++; - ns->tx_bytes += skb->len; + ns->tx_bytes += len; u64_stats_update_end(&ns->syncp); + return NETDEV_TX_OK; -out: +out_drop_free: dev_kfree_skb(skb); - +out_drop_cnt: + rcu_read_unlock(); + u64_stats_update_begin(&ns->syncp); + ns->tx_dropped++; + u64_stats_update_end(&ns->syncp); return NETDEV_TX_OK; } @@ -70,6 +87,7 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) start = u64_stats_fetch_begin(&ns->syncp); stats->tx_bytes = ns->tx_bytes; stats->tx_packets = ns->tx_packets; + stats->tx_dropped = ns->tx_dropped; } while (u64_stats_fetch_retry(&ns->syncp, start)); } @@ -302,7 +320,6 @@ static void nsim_setup(struct net_device *dev) eth_hw_addr_random(dev); dev->tx_queue_len = 0; - dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index c8b45b0d955e..553c4b9b4f63 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -98,6 +98,7 @@ struct netdevsim { u64 tx_packets; u64 tx_bytes; + u64 tx_dropped; struct u64_stats_sync syncp; struct nsim_bus_dev *nsim_bus_dev; From 8debcf5832c3e8a6baaea27c75ad8a6ba5077beb Mon Sep 17 00:00:00 2001 From: David Wei Date: Wed, 28 Feb 2024 15:22:51 -0800 Subject: [PATCH 1701/2255] netdevsim: add ndo_get_iflink() implementation Add an implementation for ndo_get_iflink() in netdevsim that shows the ifindex of the linked peer, if any. Signed-off-by: David Wei Reviewed-by: Maciek Machnikowski Signed-off-by: David S. Miller --- drivers/net/netdevsim/netdev.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index c3f3fda5fdc0..8330bc0bcb7e 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -283,6 +283,21 @@ nsim_set_features(struct net_device *dev, netdev_features_t features) return 0; } +static int nsim_get_iflink(const struct net_device *dev) +{ + struct netdevsim *nsim, *peer; + int iflink; + + nsim = netdev_priv(dev); + + rcu_read_lock(); + peer = rcu_dereference(nsim->peer); + iflink = peer ? READ_ONCE(peer->netdev->ifindex) : 0; + rcu_read_unlock(); + + return iflink; +} + static const struct net_device_ops nsim_netdev_ops = { .ndo_start_xmit = nsim_start_xmit, .ndo_set_rx_mode = nsim_set_rx_mode, @@ -300,6 +315,7 @@ static const struct net_device_ops nsim_netdev_ops = { .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, .ndo_setup_tc = nsim_setup_tc, .ndo_set_features = nsim_set_features, + .ndo_get_iflink = nsim_get_iflink, .ndo_bpf = nsim_bpf, }; From dfb429ea4f2db6a946ada94cce8955e87906e6b5 Mon Sep 17 00:00:00 2001 From: David Wei Date: Wed, 28 Feb 2024 15:22:52 -0800 Subject: [PATCH 1702/2255] netdevsim: add selftest for forwarding skb between connected ports Connect two netdevsim ports in different namespaces together, then send packets between them using socat. Signed-off-by: David Wei Reviewed-by: Maciek Machnikowski Signed-off-by: David S. Miller --- .../selftests/drivers/net/netdevsim/Makefile | 1 + .../selftests/drivers/net/netdevsim/peer.sh | 143 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100755 tools/testing/selftests/drivers/net/netdevsim/peer.sh diff --git a/tools/testing/selftests/drivers/net/netdevsim/Makefile b/tools/testing/selftests/drivers/net/netdevsim/Makefile index 7a29a05bea8b..5bace0b7fb57 100644 --- a/tools/testing/selftests/drivers/net/netdevsim/Makefile +++ b/tools/testing/selftests/drivers/net/netdevsim/Makefile @@ -10,6 +10,7 @@ TEST_PROGS = devlink.sh \ fib.sh \ hw_stats_l3.sh \ nexthop.sh \ + peer.sh \ psample.sh \ tc-mq-visibility.sh \ udp_tunnel_nic.sh \ diff --git a/tools/testing/selftests/drivers/net/netdevsim/peer.sh b/tools/testing/selftests/drivers/net/netdevsim/peer.sh new file mode 100755 index 000000000000..aed62d9e6c0a --- /dev/null +++ b/tools/testing/selftests/drivers/net/netdevsim/peer.sh @@ -0,0 +1,143 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only + +source ../../../net/net_helper.sh + +NSIM_DEV_1_ID=$((256 + RANDOM % 256)) +NSIM_DEV_1_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_DEV_1_ID +NSIM_DEV_2_ID=$((512 + RANDOM % 256)) +NSIM_DEV_2_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_DEV_2_ID + +NSIM_DEV_SYS_NEW=/sys/bus/netdevsim/new_device +NSIM_DEV_SYS_DEL=/sys/bus/netdevsim/del_device +NSIM_DEV_SYS_LINK=/sys/bus/netdevsim/link_device +NSIM_DEV_SYS_UNLINK=/sys/bus/netdevsim/unlink_device + +socat_check() +{ + if [ ! -x "$(command -v socat)" ]; then + echo "socat command not found. Skipping test" + return 1 + fi + + return 0 +} + +setup_ns() +{ + set -e + ip netns add nssv + ip netns add nscl + + NSIM_DEV_1_NAME=$(find $NSIM_DEV_1_SYS/net -maxdepth 1 -type d ! \ + -path $NSIM_DEV_1_SYS/net -exec basename {} \;) + NSIM_DEV_2_NAME=$(find $NSIM_DEV_2_SYS/net -maxdepth 1 -type d ! \ + -path $NSIM_DEV_2_SYS/net -exec basename {} \;) + + ip link set $NSIM_DEV_1_NAME netns nssv + ip link set $NSIM_DEV_2_NAME netns nscl + + ip netns exec nssv ip addr add '192.168.1.1/24' dev $NSIM_DEV_1_NAME + ip netns exec nscl ip addr add '192.168.1.2/24' dev $NSIM_DEV_2_NAME + + ip netns exec nssv ip link set dev $NSIM_DEV_1_NAME up + ip netns exec nscl ip link set dev $NSIM_DEV_2_NAME up + set +e +} + +cleanup_ns() +{ + ip netns del nscl + ip netns del nssv +} + +### +### Code start +### + +socat_check || exit 4 + +modprobe netdevsim + +# linking + +echo $NSIM_DEV_1_ID > $NSIM_DEV_SYS_NEW +echo $NSIM_DEV_2_ID > $NSIM_DEV_SYS_NEW +udevadm settle + +setup_ns + +NSIM_DEV_1_FD=$((256 + RANDOM % 256)) +exec {NSIM_DEV_1_FD} $NSIM_DEV_SYS_LINK 2>/dev/null +if [ $? -eq 0 ]; then + echo "linking with non-existent netdevsim should fail" + cleanup_ns + exit 1 +fi + +echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX 2000:$NSIM_DEV_2_IFIDX" > $NSIM_DEV_SYS_LINK 2>/dev/null +if [ $? -eq 0 ]; then + echo "linking with non-existent netnsid should fail" + cleanup_ns + exit 1 +fi + +echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX $NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX" > $NSIM_DEV_SYS_LINK 2>/dev/null +if [ $? -eq 0 ]; then + echo "linking with self should fail" + cleanup_ns + exit 1 +fi + +echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX $NSIM_DEV_2_FD:$NSIM_DEV_2_IFIDX" > $NSIM_DEV_SYS_LINK +if [ $? -ne 0 ]; then + echo "linking netdevsim1 with netdevsim2 should succeed" + cleanup_ns + exit 1 +fi + +# argument error checking + +echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX $NSIM_DEV_2_FD:a" > $NSIM_DEV_SYS_LINK 2>/dev/null +if [ $? -eq 0 ]; then + echo "invalid arg should fail" + cleanup_ns + exit 1 +fi + +# send/recv packets + +tmp_file=$(mktemp) +ip netns exec nssv socat TCP-LISTEN:1234,fork $tmp_file & +pid=$! +res=0 + +wait_local_port_listen nssv 1234 tcp + +echo "HI" | ip netns exec nscl socat STDIN TCP:192.168.1.1:1234 + +count=$(cat $tmp_file | wc -c) +if [[ $count -ne 3 ]]; then + echo "expected 3 bytes, got $count" + res=1 +fi + +echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX" > $NSIM_DEV_SYS_UNLINK + +echo $NSIM_DEV_2_ID > $NSIM_DEV_SYS_DEL + +kill $pid +echo $NSIM_DEV_1_ID > $NSIM_DEV_SYS_DEL + +cleanup_ns + +modprobe -r netdevsim + +exit $res From 8ee60f9c41fb01440e8a8f97127869c9b1978362 Mon Sep 17 00:00:00 2001 From: David Wei Date: Wed, 28 Feb 2024 15:22:53 -0800 Subject: [PATCH 1703/2255] netdevsim: fix rtnetlink.sh selftest I cleared IFF_NOARP flag from netdevsim dev->flags in order to support skb forwarding. This breaks the rtnetlink.sh selftest kci_test_ipsec_offload() test because ipsec does not connect to peers it cannot transmit to. Fix the issue by adding a neigh entry manually. ipsec_offload test now successfully pass. Signed-off-by: David Wei Signed-off-by: David S. Miller --- tools/testing/selftests/net/rtnetlink.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index 874a2952aa8e..bdf6f10d0558 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -801,6 +801,8 @@ kci_test_ipsec_offload() end_test "FAIL: ipsec_offload SA offload missing from list output" fi + # we didn't create a peer, make sure we can Tx + ip neigh add $dstip dev $dev lladdr 00:11:22:33:44:55 # use ping to exercise the Tx path ping -I $dev -c 3 -W 1 -i 0 $dstip >/dev/null From 3cd3e72ccb3aade0e8fe037ef07a44b341ab577c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 11:40:11 +0000 Subject: [PATCH 1704/2255] inet: annotate data-races around ifa->ifa_tstamp and ifa->ifa_cstamp ifa->ifa_tstamp can be read locklessly. Add appropriate READ_ONCE()/WRITE_ONCE() annotations. Do the same for ifa->ifa_cstamp to prepare upcoming changes. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index af741af61830..1316046d5f28 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -713,13 +713,14 @@ static void check_lifetime(struct work_struct *work) rcu_read_lock(); hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) { - unsigned long age; + unsigned long age, tstamp; if (ifa->ifa_flags & IFA_F_PERMANENT) continue; + tstamp = READ_ONCE(ifa->ifa_tstamp); /* We try to batch several events at once. */ - age = (now - ifa->ifa_tstamp + + age = (now - tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && @@ -729,17 +730,17 @@ static void check_lifetime(struct work_struct *work) INFINITY_LIFE_TIME) { continue; } else if (age >= ifa->ifa_preferred_lft) { - if (time_before(ifa->ifa_tstamp + + if (time_before(tstamp + ifa->ifa_valid_lft * HZ, next)) - next = ifa->ifa_tstamp + + next = tstamp + ifa->ifa_valid_lft * HZ; if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) change_needed = true; - } else if (time_before(ifa->ifa_tstamp + + } else if (time_before(tstamp + ifa->ifa_preferred_lft * HZ, next)) { - next = ifa->ifa_tstamp + + next = tstamp + ifa->ifa_preferred_lft * HZ; } } @@ -819,9 +820,9 @@ static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, ifa->ifa_flags |= IFA_F_DEPRECATED; ifa->ifa_preferred_lft = timeout; } - ifa->ifa_tstamp = jiffies; + WRITE_ONCE(ifa->ifa_tstamp, jiffies); if (!ifa->ifa_cstamp) - ifa->ifa_cstamp = ifa->ifa_tstamp; + WRITE_ONCE(ifa->ifa_cstamp, ifa->ifa_tstamp); } static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, @@ -1676,6 +1677,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, { struct ifaddrmsg *ifm; struct nlmsghdr *nlh; + unsigned long tstamp; u32 preferred, valid; nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm), @@ -1694,11 +1696,12 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) goto nla_put_failure; + tstamp = READ_ONCE(ifa->ifa_tstamp); if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { preferred = ifa->ifa_preferred_lft; valid = ifa->ifa_valid_lft; if (preferred != INFINITY_LIFE_TIME) { - long tval = (jiffies - ifa->ifa_tstamp) / HZ; + long tval = (jiffies - tstamp) / HZ; if (preferred > tval) preferred -= tval; @@ -1728,7 +1731,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || (ifa->ifa_rt_priority && nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) || - put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, + put_cacheinfo(skb, READ_ONCE(ifa->ifa_cstamp), tstamp, preferred, valid)) goto nla_put_failure; From a5fcf74d80bec9948701ff0f7529ae96a0c4a41c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 11:40:12 +0000 Subject: [PATCH 1705/2255] inet: annotate data-races around ifa->ifa_valid_lft ifa->ifa_valid_lft can be read locklessly. Add appropriate READ_ONCE()/WRITE_ONCE() annotations. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 1316046d5f28..99f3e7c57d36 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -714,26 +714,26 @@ static void check_lifetime(struct work_struct *work) rcu_read_lock(); hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) { unsigned long age, tstamp; + u32 valid_lft; if (ifa->ifa_flags & IFA_F_PERMANENT) continue; + valid_lft = READ_ONCE(ifa->ifa_valid_lft); tstamp = READ_ONCE(ifa->ifa_tstamp); /* We try to batch several events at once. */ age = (now - tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; - if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && - age >= ifa->ifa_valid_lft) { + if (valid_lft != INFINITY_LIFE_TIME && + age >= valid_lft) { change_needed = true; } else if (ifa->ifa_preferred_lft == INFINITY_LIFE_TIME) { continue; } else if (age >= ifa->ifa_preferred_lft) { - if (time_before(tstamp + - ifa->ifa_valid_lft * HZ, next)) - next = tstamp + - ifa->ifa_valid_lft * HZ; + if (time_before(tstamp + valid_lft * HZ, next)) + next = tstamp + valid_lft * HZ; if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) change_needed = true; @@ -810,7 +810,7 @@ static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, timeout = addrconf_timeout_fixup(valid_lft, HZ); if (addrconf_finite_timeout(timeout)) - ifa->ifa_valid_lft = timeout; + WRITE_ONCE(ifa->ifa_valid_lft, timeout); else ifa->ifa_flags |= IFA_F_PERMANENT; @@ -1699,7 +1699,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, tstamp = READ_ONCE(ifa->ifa_tstamp); if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { preferred = ifa->ifa_preferred_lft; - valid = ifa->ifa_valid_lft; + valid = READ_ONCE(ifa->ifa_valid_lft); if (preferred != INFINITY_LIFE_TIME) { long tval = (jiffies - tstamp) / HZ; From 9f6fa3c4e722cbb9a007c3b85797bebfcdee84e9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 11:40:13 +0000 Subject: [PATCH 1706/2255] inet: annotate data-races around ifa->ifa_preferred_lft ifa->ifa_preferred_lft can be read locklessly. Add appropriate READ_ONCE()/WRITE_ONCE() annotations. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 99f3e7c57d36..368fb56e1f1b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -714,11 +714,13 @@ static void check_lifetime(struct work_struct *work) rcu_read_lock(); hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) { unsigned long age, tstamp; + u32 preferred_lft; u32 valid_lft; if (ifa->ifa_flags & IFA_F_PERMANENT) continue; + preferred_lft = READ_ONCE(ifa->ifa_preferred_lft); valid_lft = READ_ONCE(ifa->ifa_valid_lft); tstamp = READ_ONCE(ifa->ifa_tstamp); /* We try to batch several events at once. */ @@ -728,20 +730,18 @@ static void check_lifetime(struct work_struct *work) if (valid_lft != INFINITY_LIFE_TIME && age >= valid_lft) { change_needed = true; - } else if (ifa->ifa_preferred_lft == + } else if (preferred_lft == INFINITY_LIFE_TIME) { continue; - } else if (age >= ifa->ifa_preferred_lft) { + } else if (age >= preferred_lft) { if (time_before(tstamp + valid_lft * HZ, next)) next = tstamp + valid_lft * HZ; if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) change_needed = true; - } else if (time_before(tstamp + - ifa->ifa_preferred_lft * HZ, + } else if (time_before(tstamp + preferred_lft * HZ, next)) { - next = tstamp + - ifa->ifa_preferred_lft * HZ; + next = tstamp + preferred_lft * HZ; } } rcu_read_unlock(); @@ -818,7 +818,7 @@ static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, if (addrconf_finite_timeout(timeout)) { if (timeout == 0) ifa->ifa_flags |= IFA_F_DEPRECATED; - ifa->ifa_preferred_lft = timeout; + WRITE_ONCE(ifa->ifa_preferred_lft, timeout); } WRITE_ONCE(ifa->ifa_tstamp, jiffies); if (!ifa->ifa_cstamp) @@ -1698,7 +1698,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, tstamp = READ_ONCE(ifa->ifa_tstamp); if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { - preferred = ifa->ifa_preferred_lft; + preferred = READ_ONCE(ifa->ifa_preferred_lft); valid = READ_ONCE(ifa->ifa_valid_lft); if (preferred != INFINITY_LIFE_TIME) { long tval = (jiffies - tstamp) / HZ; From 3ddc2231c8108302a8229d3c5849ee792a63230d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 11:40:14 +0000 Subject: [PATCH 1707/2255] inet: annotate data-races around ifa->ifa_flags ifa->ifa_flags can be read locklessly. Add appropriate READ_ONCE()/WRITE_ONCE() annotations. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 368fb56e1f1b..550b775cbbf3 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -716,8 +716,10 @@ static void check_lifetime(struct work_struct *work) unsigned long age, tstamp; u32 preferred_lft; u32 valid_lft; + u32 flags; - if (ifa->ifa_flags & IFA_F_PERMANENT) + flags = READ_ONCE(ifa->ifa_flags); + if (flags & IFA_F_PERMANENT) continue; preferred_lft = READ_ONCE(ifa->ifa_preferred_lft); @@ -737,7 +739,7 @@ static void check_lifetime(struct work_struct *work) if (time_before(tstamp + valid_lft * HZ, next)) next = tstamp + valid_lft * HZ; - if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) + if (!(flags & IFA_F_DEPRECATED)) change_needed = true; } else if (time_before(tstamp + preferred_lft * HZ, next)) { @@ -805,21 +807,23 @@ static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, __u32 prefered_lft) { unsigned long timeout; + u32 flags; - ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED); + flags = ifa->ifa_flags & ~(IFA_F_PERMANENT | IFA_F_DEPRECATED); timeout = addrconf_timeout_fixup(valid_lft, HZ); if (addrconf_finite_timeout(timeout)) WRITE_ONCE(ifa->ifa_valid_lft, timeout); else - ifa->ifa_flags |= IFA_F_PERMANENT; + flags |= IFA_F_PERMANENT; timeout = addrconf_timeout_fixup(prefered_lft, HZ); if (addrconf_finite_timeout(timeout)) { if (timeout == 0) - ifa->ifa_flags |= IFA_F_DEPRECATED; + flags |= IFA_F_DEPRECATED; WRITE_ONCE(ifa->ifa_preferred_lft, timeout); } + WRITE_ONCE(ifa->ifa_flags, flags); WRITE_ONCE(ifa->ifa_tstamp, jiffies); if (!ifa->ifa_cstamp) WRITE_ONCE(ifa->ifa_cstamp, ifa->ifa_tstamp); @@ -1313,7 +1317,7 @@ static __be32 in_dev_select_addr(const struct in_device *in_dev, const struct in_ifaddr *ifa; in_dev_for_each_ifa_rcu(ifa, in_dev) { - if (ifa->ifa_flags & IFA_F_SECONDARY) + if (READ_ONCE(ifa->ifa_flags) & IFA_F_SECONDARY) continue; if (ifa->ifa_scope != RT_SCOPE_LINK && ifa->ifa_scope <= scope) @@ -1341,7 +1345,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) localnet_scope = RT_SCOPE_LINK; in_dev_for_each_ifa_rcu(ifa, in_dev) { - if (ifa->ifa_flags & IFA_F_SECONDARY) + if (READ_ONCE(ifa->ifa_flags) & IFA_F_SECONDARY) continue; if (min(ifa->ifa_scope, localnet_scope) > scope) continue; @@ -1688,7 +1692,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, ifm = nlmsg_data(nlh); ifm->ifa_family = AF_INET; ifm->ifa_prefixlen = ifa->ifa_prefixlen; - ifm->ifa_flags = ifa->ifa_flags; + ifm->ifa_flags = READ_ONCE(ifa->ifa_flags); ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; @@ -1728,7 +1732,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || (ifa->ifa_proto && nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto)) || - nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || + nla_put_u32(skb, IFA_FLAGS, ifm->ifa_flags) || (ifa->ifa_rt_priority && nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) || put_cacheinfo(skb, READ_ONCE(ifa->ifa_cstamp), tstamp, From 590e92cdc835fcf435d8611f2477fff0e16877c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 11:40:15 +0000 Subject: [PATCH 1708/2255] inet: prepare inet_base_seq() to run without RTNL In the following patch, inet_base_seq() will no longer be called with RTNL held. Add READ_ONCE()/WRITE_ONCE() annotations in dev_base_seq_inc() and inet_base_seq(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 5 +++-- net/ipv4/devinet.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 4868e6734509..fe054cbd41e9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -180,8 +180,9 @@ static DECLARE_RWSEM(devnet_rename_sem); static inline void dev_base_seq_inc(struct net *net) { - while (++net->dev_base_seq == 0) - ; + unsigned int val = net->dev_base_seq + 1; + + WRITE_ONCE(net->dev_base_seq, val ?: 1); } static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 550b775cbbf3..2afe78dfc3c2 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1837,7 +1837,7 @@ done: static u32 inet_base_seq(const struct net *net) { u32 res = atomic_read(&net->ipv4.dev_addr_genid) + - net->dev_base_seq; + READ_ONCE(net->dev_base_seq); /* Must not return 0 (see nl_dump_check_consistent()). * Chose a value far away from 0. From cdb2f80f1c10654efc66c1624f66df2b87eabf06 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 11:40:16 +0000 Subject: [PATCH 1709/2255] inet: use xa_array iterator to implement inet_dump_ifaddr() 1) inet_dump_ifaddr() can can run under RCU protection instead of RTNL. 2) properly return 0 at the end of a dump, avoiding an an extra recvmsg() system call. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 95 ++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 58 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 2afe78dfc3c2..4daa8124f247 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1676,7 +1676,7 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci); } -static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, +static int inet_fill_ifaddr(struct sk_buff *skb, const struct in_ifaddr *ifa, struct inet_fill_args *args) { struct ifaddrmsg *ifm; @@ -1805,15 +1805,15 @@ static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, } static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb, - struct netlink_callback *cb, int s_ip_idx, + struct netlink_callback *cb, int *s_ip_idx, struct inet_fill_args *fillargs) { struct in_ifaddr *ifa; int ip_idx = 0; int err; - in_dev_for_each_ifa_rtnl(ifa, in_dev) { - if (ip_idx < s_ip_idx) { + in_dev_for_each_ifa_rcu(ifa, in_dev) { + if (ip_idx < *s_ip_idx) { ip_idx++; continue; } @@ -1825,9 +1825,9 @@ static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb, ip_idx++; } err = 0; - + ip_idx = 0; done: - cb->args[2] = ip_idx; + *s_ip_idx = ip_idx; return err; } @@ -1859,75 +1859,53 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) }; struct net *net = sock_net(skb->sk); struct net *tgt_net = net; - int h, s_h; - int idx, s_idx; - int s_ip_idx; - struct net_device *dev; + struct { + unsigned long ifindex; + int ip_idx; + } *ctx = (void *)cb->ctx; struct in_device *in_dev; - struct hlist_head *head; + struct net_device *dev; int err = 0; - s_h = cb->args[0]; - s_idx = idx = cb->args[1]; - s_ip_idx = cb->args[2]; - + rcu_read_lock(); if (cb->strict_check) { err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, skb->sk, cb); if (err < 0) - goto put_tgt_net; + goto done; - err = 0; if (fillargs.ifindex) { - dev = __dev_get_by_index(tgt_net, fillargs.ifindex); - if (!dev) { - err = -ENODEV; - goto put_tgt_net; - } - - in_dev = __in_dev_get_rtnl(dev); - if (in_dev) { - err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx, - &fillargs); - } - goto put_tgt_net; - } - } - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &tgt_net->dev_index_head[h]; - rcu_read_lock(); - cb->seq = inet_base_seq(tgt_net); - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - if (h > s_h || idx > s_idx) - s_ip_idx = 0; + err = -ENODEV; + dev = dev_get_by_index_rcu(tgt_net, fillargs.ifindex); + if (!dev) + goto done; in_dev = __in_dev_get_rcu(dev); if (!in_dev) - goto cont; - - err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx, - &fillargs); - if (err < 0) { - rcu_read_unlock(); goto done; - } -cont: - idx++; + err = in_dev_dump_addr(in_dev, skb, cb, &ctx->ip_idx, + &fillargs); + goto done; } - rcu_read_unlock(); } + cb->seq = inet_base_seq(tgt_net); + + for_each_netdev_dump(net, dev, ctx->ifindex) { + in_dev = __in_dev_get_rcu(dev); + if (!in_dev) + continue; + err = in_dev_dump_addr(in_dev, skb, cb, &ctx->ip_idx, + &fillargs); + if (err < 0) + goto done; + } done: - cb->args[0] = h; - cb->args[1] = idx; -put_tgt_net: + if (err < 0 && likely(skb->len)) + err = skb->len; if (fillargs.netnsid >= 0) put_net(tgt_net); - - return skb->len ? : err; + rcu_read_unlock(); + return err; } static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, @@ -2818,7 +2796,8 @@ void __init devinet_init(void) rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0); rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0); - rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0); + rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, + RTNL_FLAG_DUMP_UNLOCKED); rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf, inet_netconf_dump_devconf, RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED); From 4e73e1bc1abf3181d57d6b8f1ab2a9f62a6a1a52 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Fri, 1 Mar 2024 14:23:37 -0800 Subject: [PATCH 1710/2255] bpf, docs: Use IETF format for field definitions in instruction-set.rst In preparation for publication as an IETF RFC, the WG chairs asked me to convert the document to use IETF packet format for field layout, so this patch attempts to make it consistent with other IETF documents. Some fields that are not byte aligned were previously inconsistent in how values were defined. Some were defined as the value of the byte containing the field (like 0x20 for a field holding the high four bits of the byte), and others were defined as the value of the field itself (like 0x2). This PR makes them be consistent in using just the values of the field itself, which is IETF convention. As a result, some of the defines that used BPF_* would no longer match the value in the spec, and so this patch also drops the BPF_* prefix to avoid confusion with the defines that are the full-byte equivalent values. For consistency, BPF_* is then dropped from other fields too. BPF_ is thus the Linux implementation-specific define for as it appears in the BPF ISA specification. The syntax BPF_ADD | BPF_X | BPF_ALU only worked for full-byte values so the convention {ADD, X, ALU} is proposed for referring to field values instead. Also replace the redundant "LSB bits" with "least significant bits". A preview of what the resulting Internet Draft would look like can be seen at: https://htmlpreview.github.io/?https://raw.githubusercontent.com/dthaler/ebp f-docs-1/format/draft-ietf-bpf-isa.html v1->v2: Fix sphinx issue as recommended by David Vernet Signed-off-by: Dave Thaler Acked-by: David Vernet Link: https://lore.kernel.org/r/20240301222337.15931-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/standardization/instruction-set.rst | 515 ++++++++++-------- 1 file changed, 282 insertions(+), 233 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index f3269d6dd5e0..ffcba257e004 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -24,22 +24,22 @@ a type's signedness (`S`) and bit width (`N`), respectively. .. table:: Meaning of signedness notation. ==== ========= - `S` Meaning + S Meaning ==== ========= - `u` unsigned - `s` signed + u unsigned + s signed ==== ========= .. table:: Meaning of bit-width notation. ===== ========= - `N` Bit width + N Bit width ===== ========= - `8` 8 bits - `16` 16 bits - `32` 32 bits - `64` 64 bits - `128` 128 bits + 8 8 bits + 16 16 bits + 32 32 bits + 64 64 bits + 128 128 bits ===== ========= For example, `u32` is a type whose valid values are all the 32-bit unsigned @@ -48,31 +48,31 @@ numbers. Functions --------- -* `htobe16`: Takes an unsigned 16-bit number in host-endian format and +* htobe16: Takes an unsigned 16-bit number in host-endian format and returns the equivalent number as an unsigned 16-bit number in big-endian format. -* `htobe32`: Takes an unsigned 32-bit number in host-endian format and +* htobe32: Takes an unsigned 32-bit number in host-endian format and returns the equivalent number as an unsigned 32-bit number in big-endian format. -* `htobe64`: Takes an unsigned 64-bit number in host-endian format and +* htobe64: Takes an unsigned 64-bit number in host-endian format and returns the equivalent number as an unsigned 64-bit number in big-endian format. -* `htole16`: Takes an unsigned 16-bit number in host-endian format and +* htole16: Takes an unsigned 16-bit number in host-endian format and returns the equivalent number as an unsigned 16-bit number in little-endian format. -* `htole32`: Takes an unsigned 32-bit number in host-endian format and +* htole32: Takes an unsigned 32-bit number in host-endian format and returns the equivalent number as an unsigned 32-bit number in little-endian format. -* `htole64`: Takes an unsigned 64-bit number in host-endian format and +* htole64: Takes an unsigned 64-bit number in host-endian format and returns the equivalent number as an unsigned 64-bit number in little-endian format. -* `bswap16`: Takes an unsigned 16-bit number in either big- or little-endian +* bswap16: Takes an unsigned 16-bit number in either big- or little-endian format and returns the equivalent number with the same bit width but opposite endianness. -* `bswap32`: Takes an unsigned 32-bit number in either big- or little-endian +* bswap32: Takes an unsigned 32-bit number in either big- or little-endian format and returns the equivalent number with the same bit width but opposite endianness. -* `bswap64`: Takes an unsigned 64-bit number in either big- or little-endian +* bswap64: Takes an unsigned 64-bit number in either big- or little-endian format and returns the equivalent number with the same bit width but opposite endianness. @@ -135,34 +135,63 @@ Instruction encoding BPF has two instruction encodings: * the basic instruction encoding, which uses 64 bits to encode an instruction -* the wide instruction encoding, which appends a second 64-bit immediate (i.e., - constant) value after the basic instruction for a total of 128 bits. +* the wide instruction encoding, which appends a second 64 bits + after the basic instruction for a total of 128 bits. -The fields conforming an encoded basic instruction are stored in the -following order:: +Basic instruction encoding +-------------------------- - opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32 // In little-endian BPF. - opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32 // In big-endian BPF. +A basic instruction is encoded as follows:: -**imm** - signed integer immediate value + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | opcode | regs | offset | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | imm | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +**opcode** + operation to perform, encoded as follows:: + + +-+-+-+-+-+-+-+-+ + |specific |class| + +-+-+-+-+-+-+-+-+ + + **specific** + The format of these bits varies by instruction class + + **class** + The instruction class (see `Instruction classes`_) + +**regs** + The source and destination register numbers, encoded as follows + on a little-endian host:: + + +-+-+-+-+-+-+-+-+ + |src_reg|dst_reg| + +-+-+-+-+-+-+-+-+ + + and as follows on a big-endian host:: + + +-+-+-+-+-+-+-+-+ + |dst_reg|src_reg| + +-+-+-+-+-+-+-+-+ + + **src_reg** + the source register number (0-10), except where otherwise specified + (`64-bit immediate instructions`_ reuse this field for other purposes) + + **dst_reg** + destination register number (0-10) **offset** signed integer offset used with pointer arithmetic -**src_reg** - the source register number (0-10), except where otherwise specified - (`64-bit immediate instructions`_ reuse this field for other purposes) +**imm** + signed integer immediate value -**dst_reg** - destination register number (0-10) - -**opcode** - operation to perform - -Note that the contents of multi-byte fields ('imm' and 'offset') are -stored using big-endian byte ordering in big-endian BPF and -little-endian byte ordering in little-endian BPF. +Note that the contents of multi-byte fields ('offset' and 'imm') are +stored using big-endian byte ordering on big-endian hosts and +little-endian byte ordering on little-endian hosts. For example:: @@ -175,66 +204,83 @@ For example:: Note that most instructions do not use all of the fields. Unused fields shall be cleared to zero. -As discussed below in `64-bit immediate instructions`_, a 64-bit immediate -instruction uses two 32-bit immediate values that are constructed as follows. -The 64 bits following the basic instruction contain a pseudo instruction -using the same format but with 'opcode', 'dst_reg', 'src_reg', and 'offset' all -set to zero, and imm containing the high 32 bits of the immediate value. +Wide instruction encoding +-------------------------- + +Some instructions are defined to use the wide instruction encoding, +which uses two 32-bit immediate values. The 64 bits following +the basic instruction format contain a pseudo instruction +with 'opcode', 'dst_reg', 'src_reg', and 'offset' all set to zero. This is depicted in the following figure:: - basic_instruction - .------------------------------. - | | - opcode:8 regs:8 offset:16 imm:32 unused:32 imm:32 - | | - '--------------' - pseudo instruction + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | opcode | regs | offset | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | imm | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | next_imm | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -Here, the imm value of the pseudo instruction is called 'next_imm'. The unused -bytes in the pseudo instruction are reserved and shall be cleared to zero. +**opcode** + operation to perform, encoded as explained above + +**regs** + The source and destination register numbers, encoded as explained above + +**offset** + signed integer offset used with pointer arithmetic + +**imm** + signed integer immediate value + +**reserved** + unused, set to zero + +**next_imm** + second signed integer immediate value Instruction classes ------------------- -The three LSB bits of the 'opcode' field store the instruction class: +The three least significant bits of the 'opcode' field store the instruction class: -========= ===== =============================== =================================== -class value description reference -========= ===== =============================== =================================== -BPF_LD 0x00 non-standard load operations `Load and store instructions`_ -BPF_LDX 0x01 load into register operations `Load and store instructions`_ -BPF_ST 0x02 store from immediate operations `Load and store instructions`_ -BPF_STX 0x03 store from register operations `Load and store instructions`_ -BPF_ALU 0x04 32-bit arithmetic operations `Arithmetic and jump instructions`_ -BPF_JMP 0x05 64-bit jump operations `Arithmetic and jump instructions`_ -BPF_JMP32 0x06 32-bit jump operations `Arithmetic and jump instructions`_ -BPF_ALU64 0x07 64-bit arithmetic operations `Arithmetic and jump instructions`_ -========= ===== =============================== =================================== +===== ===== =============================== =================================== +class value description reference +===== ===== =============================== =================================== +LD 0x0 non-standard load operations `Load and store instructions`_ +LDX 0x1 load into register operations `Load and store instructions`_ +ST 0x2 store from immediate operations `Load and store instructions`_ +STX 0x3 store from register operations `Load and store instructions`_ +ALU 0x4 32-bit arithmetic operations `Arithmetic and jump instructions`_ +JMP 0x5 64-bit jump operations `Arithmetic and jump instructions`_ +JMP32 0x6 32-bit jump operations `Arithmetic and jump instructions`_ +ALU64 0x7 64-bit arithmetic operations `Arithmetic and jump instructions`_ +===== ===== =============================== =================================== Arithmetic and jump instructions ================================ -For arithmetic and jump instructions (``BPF_ALU``, ``BPF_ALU64``, ``BPF_JMP`` and -``BPF_JMP32``), the 8-bit 'opcode' field is divided into three parts: +For arithmetic and jump instructions (``ALU``, ``ALU64``, ``JMP`` and +``JMP32``), the 8-bit 'opcode' field is divided into three parts:: -============== ====== ================= -4 bits (MSB) 1 bit 3 bits (LSB) -============== ====== ================= -code source instruction class -============== ====== ================= + +-+-+-+-+-+-+-+-+ + | code |s|class| + +-+-+-+-+-+-+-+-+ **code** the operation code, whose meaning varies by instruction class -**source** +**s (source)** the source operand location, which unless otherwise specified is one of: ====== ===== ============================================== source value description ====== ===== ============================================== - BPF_K 0x00 use 32-bit 'imm' value as source operand - BPF_X 0x08 use 'src_reg' register value as source operand + K 0 use 32-bit 'imm' value as source operand + X 1 use 'src_reg' register value as source operand ====== ===== ============================================== **instruction class** @@ -243,75 +289,75 @@ code source instruction class Arithmetic instructions ----------------------- -``BPF_ALU`` uses 32-bit wide operands while ``BPF_ALU64`` uses 64-bit wide operands for -otherwise identical operations. ``BPF_ALU64`` instructions belong to the +``ALU`` uses 32-bit wide operands while ``ALU64`` uses 64-bit wide operands for +otherwise identical operations. ``ALU64`` instructions belong to the base64 conformance group unless noted otherwise. The 'code' field encodes the operation as below, where 'src' and 'dst' refer to the values of the source and destination registers, respectively. -========= ===== ======= ========================================================== -code value offset description -========= ===== ======= ========================================================== -BPF_ADD 0x00 0 dst += src -BPF_SUB 0x10 0 dst -= src -BPF_MUL 0x20 0 dst \*= src -BPF_DIV 0x30 0 dst = (src != 0) ? (dst / src) : 0 -BPF_SDIV 0x30 1 dst = (src != 0) ? (dst s/ src) : 0 -BPF_OR 0x40 0 dst \|= src -BPF_AND 0x50 0 dst &= src -BPF_LSH 0x60 0 dst <<= (src & mask) -BPF_RSH 0x70 0 dst >>= (src & mask) -BPF_NEG 0x80 0 dst = -dst -BPF_MOD 0x90 0 dst = (src != 0) ? (dst % src) : dst -BPF_SMOD 0x90 1 dst = (src != 0) ? (dst s% src) : dst -BPF_XOR 0xa0 0 dst ^= src -BPF_MOV 0xb0 0 dst = src -BPF_MOVSX 0xb0 8/16/32 dst = (s8,s16,s32)src -BPF_ARSH 0xc0 0 :term:`sign extending` dst >>= (src & mask) -BPF_END 0xd0 0 byte swap operations (see `Byte swap instructions`_ below) -========= ===== ======= ========================================================== +===== ===== ======= ========================================================== +name code offset description +===== ===== ======= ========================================================== +ADD 0x0 0 dst += src +SUB 0x1 0 dst -= src +MUL 0x2 0 dst \*= src +DIV 0x3 0 dst = (src != 0) ? (dst / src) : 0 +SDIV 0x3 1 dst = (src != 0) ? (dst s/ src) : 0 +OR 0x4 0 dst \|= src +AND 0x5 0 dst &= src +LSH 0x6 0 dst <<= (src & mask) +RSH 0x7 0 dst >>= (src & mask) +NEG 0x8 0 dst = -dst +MOD 0x9 0 dst = (src != 0) ? (dst % src) : dst +SMOD 0x9 1 dst = (src != 0) ? (dst s% src) : dst +XOR 0xa 0 dst ^= src +MOV 0xb 0 dst = src +MOVSX 0xb 8/16/32 dst = (s8,s16,s32)src +ARSH 0xc 0 :term:`sign extending` dst >>= (src & mask) +END 0xd 0 byte swap operations (see `Byte swap instructions`_ below) +===== ===== ======= ========================================================== Underflow and overflow are allowed during arithmetic operations, meaning the 64-bit or 32-bit value will wrap. If BPF program execution would result in division by zero, the destination register is instead set to zero. -If execution would result in modulo by zero, for ``BPF_ALU64`` the value of -the destination register is unchanged whereas for ``BPF_ALU`` the upper +If execution would result in modulo by zero, for ``ALU64`` the value of +the destination register is unchanged whereas for ``ALU`` the upper 32 bits of the destination register are zeroed. -``BPF_ADD | BPF_X | BPF_ALU`` means:: +``{ADD, X, ALU}``, where 'code' = ``ADD``, 'source' = ``X``, and 'class' = ``ALU``, means:: dst = (u32) ((u32) dst + (u32) src) where '(u32)' indicates that the upper 32 bits are zeroed. -``BPF_ADD | BPF_X | BPF_ALU64`` means:: +``{ADD, X, ALU64}`` means:: dst = dst + src -``BPF_XOR | BPF_K | BPF_ALU`` means:: +``{XOR, K, ALU}`` means:: dst = (u32) dst ^ (u32) imm -``BPF_XOR | BPF_K | BPF_ALU64`` means:: +``{XOR, K, ALU64}`` means:: dst = dst ^ imm Note that most instructions have instruction offset of 0. Only three instructions -(``BPF_SDIV``, ``BPF_SMOD``, ``BPF_MOVSX``) have a non-zero offset. +(``SDIV``, ``SMOD``, ``MOVSX``) have a non-zero offset. -Division, multiplication, and modulo operations for ``BPF_ALU`` are part +Division, multiplication, and modulo operations for ``ALU`` are part of the "divmul32" conformance group, and division, multiplication, and -modulo operations for ``BPF_ALU64`` are part of the "divmul64" conformance +modulo operations for ``ALU64`` are part of the "divmul64" conformance group. The division and modulo operations support both unsigned and signed flavors. -For unsigned operations (``BPF_DIV`` and ``BPF_MOD``), for ``BPF_ALU``, -'imm' is interpreted as a 32-bit unsigned value. For ``BPF_ALU64``, +For unsigned operations (``DIV`` and ``MOD``), for ``ALU``, +'imm' is interpreted as a 32-bit unsigned value. For ``ALU64``, 'imm' is first :term:`sign extended` from 32 to 64 bits, and then interpreted as a 64-bit unsigned value. -For signed operations (``BPF_SDIV`` and ``BPF_SMOD``), for ``BPF_ALU``, -'imm' is interpreted as a 32-bit signed value. For ``BPF_ALU64``, 'imm' +For signed operations (``SDIV`` and ``SMOD``), for ``ALU``, +'imm' is interpreted as a 32-bit signed value. For ``ALU64``, 'imm' is first :term:`sign extended` from 32 to 64 bits, and then interpreted as a 64-bit signed value. @@ -323,15 +369,15 @@ etc. This specification requires that signed modulo use truncated division a % n = a - n * trunc(a / n) -The ``BPF_MOVSX`` instruction does a move operation with sign extension. -``BPF_ALU | BPF_MOVSX`` :term:`sign extends` 8-bit and 16-bit operands into 32 +The ``MOVSX`` instruction does a move operation with sign extension. +``{MOVSX, X, ALU}`` :term:`sign extends` 8-bit and 16-bit operands into 32 bit operands, and zeroes the remaining upper 32 bits. -``BPF_ALU64 | BPF_MOVSX`` :term:`sign extends` 8-bit, 16-bit, and 32-bit +``{MOVSX, X, ALU64}`` :term:`sign extends` 8-bit, 16-bit, and 32-bit operands into 64 bit operands. Unlike other arithmetic instructions, -``BPF_MOVSX`` is only defined for register source operands (``BPF_X``). +``MOVSX`` is only defined for register source operands (``X``). -The ``BPF_NEG`` instruction is only defined when the source bit is clear -(``BPF_K``). +The ``NEG`` instruction is only defined when the source bit is clear +(``K``). Shift operations use a mask of 0x3F (63) for 64-bit operations and 0x1F (31) for 32-bit operations. @@ -339,24 +385,24 @@ for 32-bit operations. Byte swap instructions ---------------------- -The byte swap instructions use instruction classes of ``BPF_ALU`` and ``BPF_ALU64`` -and a 4-bit 'code' field of ``BPF_END``. +The byte swap instructions use instruction classes of ``ALU`` and ``ALU64`` +and a 4-bit 'code' field of ``END``. The byte swap instructions operate on the destination register only and do not use a separate source register or immediate value. -For ``BPF_ALU``, the 1-bit source operand field in the opcode is used to +For ``ALU``, the 1-bit source operand field in the opcode is used to select what byte order the operation converts from or to. For -``BPF_ALU64``, the 1-bit source operand field in the opcode is reserved +``ALU64``, the 1-bit source operand field in the opcode is reserved and must be set to 0. -========= ========= ===== ================================================= -class source value description -========= ========= ===== ================================================= -BPF_ALU BPF_TO_LE 0x00 convert between host byte order and little endian -BPF_ALU BPF_TO_BE 0x08 convert between host byte order and big endian -BPF_ALU64 Reserved 0x00 do byte swap unconditionally -========= ========= ===== ================================================= +===== ======== ===== ================================================= +class source value description +===== ======== ===== ================================================= +ALU TO_LE 0 convert between host byte order and little endian +ALU TO_BE 1 convert between host byte order and big endian +ALU64 Reserved 0 do byte swap unconditionally +===== ======== ===== ================================================= The 'imm' field encodes the width of the swap operations. The following widths are supported: 16, 32 and 64. Width 64 operations belong to the base64 @@ -365,19 +411,19 @@ conformance group. Examples: -``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16/32/64 means:: +``{END, TO_LE, ALU}`` with imm = 16/32/64 means:: dst = htole16(dst) dst = htole32(dst) dst = htole64(dst) -``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 16/32/64 means:: +``{END, TO_BE, ALU}`` with imm = 16/32/64 means:: dst = htobe16(dst) dst = htobe32(dst) dst = htobe64(dst) -``BPF_ALU64 | BPF_TO_LE | BPF_END`` with imm = 16/32/64 means:: +``{END, TO_LE, ALU64}`` with imm = 16/32/64 means:: dst = bswap16(dst) dst = bswap32(dst) @@ -386,59 +432,59 @@ Examples: Jump instructions ----------------- -``BPF_JMP32`` uses 32-bit wide operands and indicates the base32 -conformance group, while ``BPF_JMP`` uses 64-bit wide operands for +``JMP32`` uses 32-bit wide operands and indicates the base32 +conformance group, while ``JMP`` uses 64-bit wide operands for otherwise identical operations, and indicates the base64 conformance group unless otherwise specified. The 'code' field encodes the operation as below: -======== ===== ======= =============================== ============================================= +======== ===== ======= =============================== =================================================== code value src_reg description notes -======== ===== ======= =============================== ============================================= -BPF_JA 0x0 0x0 PC += offset BPF_JMP | BPF_K only -BPF_JA 0x0 0x0 PC += imm BPF_JMP32 | BPF_K only -BPF_JEQ 0x1 any PC += offset if dst == src -BPF_JGT 0x2 any PC += offset if dst > src unsigned -BPF_JGE 0x3 any PC += offset if dst >= src unsigned -BPF_JSET 0x4 any PC += offset if dst & src -BPF_JNE 0x5 any PC += offset if dst != src -BPF_JSGT 0x6 any PC += offset if dst > src signed -BPF_JSGE 0x7 any PC += offset if dst >= src signed -BPF_CALL 0x8 0x0 call helper function by address BPF_JMP | BPF_K only, see `Helper functions`_ -BPF_CALL 0x8 0x1 call PC += imm BPF_JMP | BPF_K only, see `Program-local functions`_ -BPF_CALL 0x8 0x2 call helper function by BTF ID BPF_JMP | BPF_K only, see `Helper functions`_ -BPF_EXIT 0x9 0x0 return BPF_JMP | BPF_K only -BPF_JLT 0xa any PC += offset if dst < src unsigned -BPF_JLE 0xb any PC += offset if dst <= src unsigned -BPF_JSLT 0xc any PC += offset if dst < src signed -BPF_JSLE 0xd any PC += offset if dst <= src signed -======== ===== ======= =============================== ============================================= +======== ===== ======= =============================== =================================================== +JA 0x0 0x0 PC += offset {JA, K, JMP} only +JA 0x0 0x0 PC += imm {JA, K, JMP32} only +JEQ 0x1 any PC += offset if dst == src +JGT 0x2 any PC += offset if dst > src unsigned +JGE 0x3 any PC += offset if dst >= src unsigned +JSET 0x4 any PC += offset if dst & src +JNE 0x5 any PC += offset if dst != src +JSGT 0x6 any PC += offset if dst > src signed +JSGE 0x7 any PC += offset if dst >= src signed +CALL 0x8 0x0 call helper function by address {CALL, K, JMP} only, see `Helper functions`_ +CALL 0x8 0x1 call PC += imm {CALL, K, JMP} only, see `Program-local functions`_ +CALL 0x8 0x2 call helper function by BTF ID {CALL, K, JMP} only, see `Helper functions`_ +EXIT 0x9 0x0 return {CALL, K, JMP} only +JLT 0xa any PC += offset if dst < src unsigned +JLE 0xb any PC += offset if dst <= src unsigned +JSLT 0xc any PC += offset if dst < src signed +JSLE 0xd any PC += offset if dst <= src signed +======== ===== ======= =============================== =================================================== -The BPF program needs to store the return value into register R0 before doing a -``BPF_EXIT``. +The BPF program needs to store the return value into register R0 before doing an +``EXIT``. Example: -``BPF_JSGE | BPF_X | BPF_JMP32`` (0x7e) means:: +``{JSGE, X, JMP32}`` means:: if (s32)dst s>= (s32)src goto +offset where 's>=' indicates a signed '>=' comparison. -``BPF_JA | BPF_K | BPF_JMP32`` (0x06) means:: +``{JA, K, JMP32}`` means:: gotol +imm where 'imm' means the branch offset comes from insn 'imm' field. -Note that there are two flavors of ``BPF_JA`` instructions. The -``BPF_JMP`` class permits a 16-bit jump offset specified by the 'offset' -field, whereas the ``BPF_JMP32`` class permits a 32-bit jump offset +Note that there are two flavors of ``JA`` instructions. The +``JMP`` class permits a 16-bit jump offset specified by the 'offset' +field, whereas the ``JMP32`` class permits a 32-bit jump offset specified by the 'imm' field. A > 16-bit conditional jump may be converted to a < 16-bit conditional jump plus a 32-bit unconditional jump. -All ``BPF_CALL`` and ``BPF_JA`` instructions belong to the +All ``CALL`` and ``JA`` instructions belong to the base32 conformance group. Helper functions @@ -459,80 +505,83 @@ Program-local functions ~~~~~~~~~~~~~~~~~~~~~~~ Program-local functions are functions exposed by the same BPF program as the caller, and are referenced by offset from the call instruction, similar to -``BPF_JA``. The offset is encoded in the imm field of the call instruction. -A ``BPF_EXIT`` within the program-local function will return to the caller. +``JA``. The offset is encoded in the imm field of the call instruction. +A ``EXIT`` within the program-local function will return to the caller. Load and store instructions =========================== -For load and store instructions (``BPF_LD``, ``BPF_LDX``, ``BPF_ST``, and ``BPF_STX``), the -8-bit 'opcode' field is divided as: +For load and store instructions (``LD``, ``LDX``, ``ST``, and ``STX``), the +8-bit 'opcode' field is divided as:: -============ ====== ================= -3 bits (MSB) 2 bits 3 bits (LSB) -============ ====== ================= -mode size instruction class -============ ====== ================= + +-+-+-+-+-+-+-+-+ + |mode |sz |class| + +-+-+-+-+-+-+-+-+ -The mode modifier is one of: +**mode** + The mode modifier is one of: - ============= ===== ==================================== ============= - mode modifier value description reference - ============= ===== ==================================== ============= - BPF_IMM 0x00 64-bit immediate instructions `64-bit immediate instructions`_ - BPF_ABS 0x20 legacy BPF packet access (absolute) `Legacy BPF Packet access instructions`_ - BPF_IND 0x40 legacy BPF packet access (indirect) `Legacy BPF Packet access instructions`_ - BPF_MEM 0x60 regular load and store operations `Regular load and store operations`_ - BPF_MEMSX 0x80 sign-extension load operations `Sign-extension load operations`_ - BPF_ATOMIC 0xc0 atomic operations `Atomic operations`_ - ============= ===== ==================================== ============= + ============= ===== ==================================== ============= + mode modifier value description reference + ============= ===== ==================================== ============= + IMM 0 64-bit immediate instructions `64-bit immediate instructions`_ + ABS 1 legacy BPF packet access (absolute) `Legacy BPF Packet access instructions`_ + IND 2 legacy BPF packet access (indirect) `Legacy BPF Packet access instructions`_ + MEM 3 regular load and store operations `Regular load and store operations`_ + MEMSX 4 sign-extension load operations `Sign-extension load operations`_ + ATOMIC 6 atomic operations `Atomic operations`_ + ============= ===== ==================================== ============= -The size modifier is one of: +**sz (size)** + The size modifier is one of: - ============= ===== ===================== - size modifier value description - ============= ===== ===================== - BPF_W 0x00 word (4 bytes) - BPF_H 0x08 half word (2 bytes) - BPF_B 0x10 byte - BPF_DW 0x18 double word (8 bytes) - ============= ===== ===================== + ==== ===== ===================== + size value description + ==== ===== ===================== + W 0 word (4 bytes) + H 1 half word (2 bytes) + B 2 byte + DW 3 double word (8 bytes) + ==== ===== ===================== -Instructions using ``BPF_DW`` belong to the base64 conformance group. + Instructions using ``DW`` belong to the base64 conformance group. + +**class** + The instruction class (see `Instruction classes`_) Regular load and store operations --------------------------------- -The ``BPF_MEM`` mode modifier is used to encode regular load and store +The ``MEM`` mode modifier is used to encode regular load and store instructions that transfer data between a register and memory. -``BPF_MEM | | BPF_STX`` means:: +``{MEM, , STX}`` means:: *(size *) (dst + offset) = src -``BPF_MEM | | BPF_ST`` means:: +``{MEM, , ST}`` means:: *(size *) (dst + offset) = imm -``BPF_MEM | | BPF_LDX`` means:: +``{MEM, , LDX}`` means:: dst = *(unsigned size *) (src + offset) -Where size is one of: ``BPF_B``, ``BPF_H``, ``BPF_W``, or ``BPF_DW`` and -'unsigned size' is one of u8, u16, u32 or u64. +Where '' is one of: ``B``, ``H``, ``W``, or ``DW``, and +'unsigned size' is one of: u8, u16, u32, or u64. Sign-extension load operations ------------------------------ -The ``BPF_MEMSX`` mode modifier is used to encode :term:`sign-extension` load +The ``MEMSX`` mode modifier is used to encode :term:`sign-extension` load instructions that transfer data between a register and memory. -``BPF_MEMSX | | BPF_LDX`` means:: +``{MEMSX, , LDX}`` means:: dst = *(signed size *) (src + offset) -Where size is one of: ``BPF_B``, ``BPF_H`` or ``BPF_W``, and -'signed size' is one of s8, s16 or s32. +Where size is one of: ``B``, ``H``, or ``W``, and +'signed size' is one of: s8, s16, or s32. Atomic operations ----------------- @@ -542,11 +591,11 @@ interrupted or corrupted by other access to the same memory region by other BPF programs or means outside of this specification. All atomic operations supported by BPF are encoded as store operations -that use the ``BPF_ATOMIC`` mode modifier as follows: +that use the ``ATOMIC`` mode modifier as follows: -* ``BPF_ATOMIC | BPF_W | BPF_STX`` for 32-bit operations, which are +* ``{ATOMIC, W, STX}`` for 32-bit operations, which are part of the "atomic32" conformance group. -* ``BPF_ATOMIC | BPF_DW | BPF_STX`` for 64-bit operations, which are +* ``{ATOMIC, DW, STX}`` for 64-bit operations, which are part of the "atomic64" conformance group. * 8-bit and 16-bit wide atomic operations are not supported. @@ -557,18 +606,18 @@ arithmetic operations in the 'imm' field to encode the atomic operation: ======== ===== =========== imm value description ======== ===== =========== -BPF_ADD 0x00 atomic add -BPF_OR 0x40 atomic or -BPF_AND 0x50 atomic and -BPF_XOR 0xa0 atomic xor +ADD 0x00 atomic add +OR 0x40 atomic or +AND 0x50 atomic and +XOR 0xa0 atomic xor ======== ===== =========== -``BPF_ATOMIC | BPF_W | BPF_STX`` with 'imm' = BPF_ADD means:: +``{ATOMIC, W, STX}`` with 'imm' = ADD means:: *(u32 *)(dst + offset) += src -``BPF_ATOMIC | BPF_DW | BPF_STX`` with 'imm' = BPF_ADD means:: +``{ATOMIC, DW, STX}`` with 'imm' = ADD means:: *(u64 *)(dst + offset) += src @@ -578,20 +627,20 @@ two complex atomic operations: =========== ================ =========================== imm value description =========== ================ =========================== -BPF_FETCH 0x01 modifier: return old value -BPF_XCHG 0xe0 | BPF_FETCH atomic exchange -BPF_CMPXCHG 0xf0 | BPF_FETCH atomic compare and exchange +FETCH 0x01 modifier: return old value +XCHG 0xe0 | FETCH atomic exchange +CMPXCHG 0xf0 | FETCH atomic compare and exchange =========== ================ =========================== -The ``BPF_FETCH`` modifier is optional for simple atomic operations, and -always set for the complex atomic operations. If the ``BPF_FETCH`` flag +The ``FETCH`` modifier is optional for simple atomic operations, and +always set for the complex atomic operations. If the ``FETCH`` flag is set, then the operation also overwrites ``src`` with the value that was in memory before it was modified. -The ``BPF_XCHG`` operation atomically exchanges ``src`` with the value +The ``XCHG`` operation atomically exchanges ``src`` with the value addressed by ``dst + offset``. -The ``BPF_CMPXCHG`` operation atomically compares the value addressed by +The ``CMPXCHG`` operation atomically compares the value addressed by ``dst + offset`` with ``R0``. If they match, the value addressed by ``dst + offset`` is replaced with ``src``. In either case, the value that was at ``dst + offset`` before the operation is zero-extended @@ -600,25 +649,25 @@ and loaded back to ``R0``. 64-bit immediate instructions ----------------------------- -Instructions with the ``BPF_IMM`` 'mode' modifier use the wide instruction +Instructions with the ``IMM`` 'mode' modifier use the wide instruction encoding defined in `Instruction encoding`_, and use the 'src_reg' field of the basic instruction to hold an opcode subtype. -The following table defines a set of ``BPF_IMM | BPF_DW | BPF_LD`` instructions +The following table defines a set of ``{IMM, DW, LD}`` instructions with opcode subtypes in the 'src_reg' field, using new terms such as "map" defined further below: -========================= ====== ======= ========================================= =========== ============== -opcode construction opcode src_reg pseudocode imm type dst type -========================= ====== ======= ========================================= =========== ============== -BPF_IMM | BPF_DW | BPF_LD 0x18 0x0 dst = (next_imm << 32) | imm integer integer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x1 dst = map_by_fd(imm) map fd map -BPF_IMM | BPF_DW | BPF_LD 0x18 0x2 dst = map_val(map_by_fd(imm)) + next_imm map fd data pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x3 dst = var_addr(imm) variable id data pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x4 dst = code_addr(imm) integer code pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x5 dst = map_by_idx(imm) map index map -BPF_IMM | BPF_DW | BPF_LD 0x18 0x6 dst = map_val(map_by_idx(imm)) + next_imm map index data pointer -========================= ====== ======= ========================================= =========== ============== +======= ========================================= =========== ============== +src_reg pseudocode imm type dst type +======= ========================================= =========== ============== +0x0 dst = (next_imm << 32) | imm integer integer +0x1 dst = map_by_fd(imm) map fd map +0x2 dst = map_val(map_by_fd(imm)) + next_imm map fd data pointer +0x3 dst = var_addr(imm) variable id data pointer +0x4 dst = code_addr(imm) integer code pointer +0x5 dst = map_by_idx(imm) map index map +0x6 dst = map_val(map_by_idx(imm)) + next_imm map index data pointer +======= ========================================= =========== ============== where @@ -657,8 +706,8 @@ Legacy BPF Packet access instructions BPF previously introduced special instructions for access to packet data that were carried over from classic BPF. These instructions used an instruction -class of BPF_LD, a size modifier of BPF_W, BPF_H, or BPF_B, and a -mode modifier of BPF_ABS or BPF_IND. The 'dst_reg' and 'offset' fields were -set to zero, and 'src_reg' was set to zero for BPF_ABS. However, these +class of ``LD``, a size modifier of ``W``, ``H``, or ``B``, and a +mode modifier of ``ABS`` or ``IND``. The 'dst_reg' and 'offset' fields were +set to zero, and 'src_reg' was set to zero for ``ABS``. However, these instructions are deprecated and should no longer be used. All legacy packet access instructions belong to the "legacy" conformance group. From 8985f2b09b3303b935b9ab4814d801251f0c7c22 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 30 Jan 2024 08:44:40 +0000 Subject: [PATCH 1711/2255] rxrpc: Use rxrpc_txbuf::kvec[0] instead of rxrpc_txbuf::wire Use rxrpc_txbuf::kvec[0] instead of rxrpc_txbuf::wire to gain access to the Rx protocol header. In future, the wire header will be stored in a page frag, not in the rxrpc_txbuf struct making it possible to use MSG_SPLICE_PAGES when sending it. Similarly, access the ack header as being immediately after the wire header when filling out an ACK packet. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/ar-internal.h | 5 +-- net/rxrpc/output.c | 79 ++++++++++++++++++++--------------------- net/rxrpc/txbuf.c | 27 +++++++------- 3 files changed, 56 insertions(+), 55 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index a8795ef0d669..9ea4e7e9d9f7 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -804,6 +804,7 @@ struct rxrpc_txbuf { #define RXRPC_TXBUF_WIRE_FLAGS 0xff /* The wire protocol flags */ #define RXRPC_TXBUF_RESENT 0x100 /* Set if has been resent */ __be16 cksum; /* Checksum to go in header */ + unsigned short ack_rwind; /* ACK receive window */ u8 /*enum rxrpc_propose_ack_trace*/ ack_why; /* If ack, why */ u8 nr_kvec; struct kvec kvec[1]; @@ -812,11 +813,11 @@ struct rxrpc_txbuf { * that data[] aligns correctly for any crypto blocksize. */ u8 pad[64 - sizeof(struct rxrpc_wire_header)]; - struct rxrpc_wire_header wire; /* Network-ready header */ + struct rxrpc_wire_header _wire; /* Network-ready header */ union { u8 data[RXRPC_JUMBO_DATALEN]; /* Data packet */ struct { - struct rxrpc_ackpacket ack; + struct rxrpc_ackpacket _ack; DECLARE_FLEX_ARRAY(u8, acks); }; }; diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index ec9ae9c6c492..5398aa24bb8e 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -77,11 +77,13 @@ static void rxrpc_set_keepalive(struct rxrpc_call *call) /* * Fill out an ACK packet. */ -static void rxrpc_fill_out_ack(struct rxrpc_connection *conn, - struct rxrpc_call *call, +static void rxrpc_fill_out_ack(struct rxrpc_call *call, struct rxrpc_txbuf *txb, - u16 *_rwind) + u8 ack_reason, + rxrpc_serial_t serial) { + struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; + struct rxrpc_ackpacket *ack = (struct rxrpc_ackpacket *)(whdr + 1); struct rxrpc_acktrailer trailer; unsigned int qsize, sack, wrap, to; rxrpc_seq_t window, wtop; @@ -97,15 +99,24 @@ static void rxrpc_fill_out_ack(struct rxrpc_connection *conn, window = call->ackr_window; wtop = call->ackr_wtop; sack = call->ackr_sack_base % RXRPC_SACK_SIZE; - txb->ack.firstPacket = htonl(window); - txb->ack.nAcks = wtop - window; + + whdr->seq = 0; + whdr->type = RXRPC_PACKET_TYPE_ACK; + txb->flags |= RXRPC_SLOW_START_OK; + ack->bufferSpace = 0; + ack->maxSkew = 0; + ack->firstPacket = htonl(window); + ack->previousPacket = htonl(call->rx_highest_seq); + ack->serial = htonl(serial); + ack->reason = ack_reason; + ack->nAcks = wtop - window; if (after(wtop, window)) { wrap = RXRPC_SACK_SIZE - sack; - to = min_t(unsigned int, txb->ack.nAcks, RXRPC_SACK_SIZE); + to = min_t(unsigned int, ack->nAcks, RXRPC_SACK_SIZE); - if (sack + txb->ack.nAcks <= RXRPC_SACK_SIZE) { - memcpy(txb->acks, call->ackr_sack_table + sack, txb->ack.nAcks); + if (sack + ack->nAcks <= RXRPC_SACK_SIZE) { + memcpy(txb->acks, call->ackr_sack_table + sack, ack->nAcks); } else { memcpy(txb->acks, call->ackr_sack_table + sack, wrap); memcpy(txb->acks + wrap, call->ackr_sack_table, @@ -115,16 +126,16 @@ static void rxrpc_fill_out_ack(struct rxrpc_connection *conn, ackp += to; } else if (before(wtop, window)) { pr_warn("ack window backward %x %x", window, wtop); - } else if (txb->ack.reason == RXRPC_ACK_DELAY) { - txb->ack.reason = RXRPC_ACK_IDLE; + } else if (ack->reason == RXRPC_ACK_DELAY) { + ack->reason = RXRPC_ACK_IDLE; } - mtu = conn->peer->if_mtu; - mtu -= conn->peer->hdrsize; + mtu = call->peer->if_mtu; + mtu -= call->peer->hdrsize; jmax = rxrpc_rx_jumbo_max; qsize = (window - 1) - call->rx_consumed; rsize = max_t(int, call->rx_winsize - qsize, 0); - *_rwind = rsize; + txb->ack_rwind = rsize; trailer.maxMTU = htonl(rxrpc_rx_mtu); trailer.ifMTU = htonl(mtu); trailer.rwind = htonl(rsize); @@ -134,8 +145,7 @@ static void rxrpc_fill_out_ack(struct rxrpc_connection *conn, *ackp++ = 0; *ackp++ = 0; memcpy(ackp, &trailer, sizeof(trailer)); - txb->kvec[0].iov_len = sizeof(txb->wire) + - sizeof(txb->ack) + txb->ack.nAcks + 3 + sizeof(trailer); + txb->kvec[0].iov_len += sizeof(*ack) + ack->nAcks + 3 + sizeof(trailer); txb->len = txb->kvec[0].iov_len; } @@ -187,10 +197,11 @@ static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call, */ static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) { + struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; struct rxrpc_connection *conn; + struct rxrpc_ackpacket *ack = (struct rxrpc_ackpacket *)(whdr + 1); struct msghdr msg; int ret, rtt_slot = -1; - u16 rwind; if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) return -ECONNRESET; @@ -203,27 +214,22 @@ static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *tx msg.msg_controllen = 0; msg.msg_flags = 0; - if (txb->ack.reason == RXRPC_ACK_PING) + if (ack->reason == RXRPC_ACK_PING) txb->flags |= RXRPC_REQUEST_ACK; - txb->wire.flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; - - rxrpc_fill_out_ack(conn, call, txb, &rwind); + whdr->flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; txb->serial = rxrpc_get_next_serial(conn); - txb->wire.serial = htonl(txb->serial); + whdr->serial = htonl(txb->serial); trace_rxrpc_tx_ack(call->debug_id, txb->serial, - ntohl(txb->ack.firstPacket), - ntohl(txb->ack.serial), txb->ack.reason, txb->ack.nAcks, - rwind); + ntohl(ack->firstPacket), + ntohl(ack->serial), ack->reason, ack->nAcks, + txb->ack_rwind); - if (txb->ack.reason == RXRPC_ACK_PING) + if (ack->reason == RXRPC_ACK_PING) rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_ping); rxrpc_inc_stat(call->rxnet, stat_tx_ack_send); - /* Grab the highest received seq as late as possible */ - txb->ack.previousPacket = htonl(call->rx_highest_seq); - iov_iter_kvec(&msg.msg_iter, WRITE, txb->kvec, txb->nr_kvec, txb->len); rxrpc_local_dont_fragment(conn->local, false); ret = do_udp_sendmsg(conn->local->socket, &msg, txb->len); @@ -232,7 +238,7 @@ static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *tx trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, rxrpc_tx_point_call_ack); } else { - trace_rxrpc_tx_packet(call->debug_id, &txb->wire, + trace_rxrpc_tx_packet(call->debug_id, whdr, rxrpc_tx_point_call_ack); if (txb->flags & RXRPC_REQUEST_ACK) call->peer->rtt_last_req = ktime_get_real(); @@ -268,18 +274,9 @@ void rxrpc_send_ACK(struct rxrpc_call *call, u8 ack_reason, return; } - txb->ack_why = why; - txb->wire.seq = 0; - txb->wire.type = RXRPC_PACKET_TYPE_ACK; - txb->flags |= RXRPC_SLOW_START_OK; - txb->ack.bufferSpace = 0; - txb->ack.maxSkew = 0; - txb->ack.firstPacket = 0; - txb->ack.previousPacket = 0; - txb->ack.serial = htonl(serial); - txb->ack.reason = ack_reason; - txb->ack.nAcks = 0; + rxrpc_fill_out_ack(call, txb, ack_reason, serial); + txb->ack_why = why; trace_rxrpc_send_ack(call, why, ack_reason, serial); rxrpc_send_ack_packet(call, txb); rxrpc_put_txbuf(txb, rxrpc_txbuf_put_ack_tx); @@ -365,7 +362,7 @@ static void rxrpc_prepare_data_subpacket(struct rxrpc_call *call, struct rxrpc_t if (test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags) && txb->seq == 1) - txb->wire.userStatus = RXRPC_USERSTATUS_SERVICE_UPGRADE; + whdr->userStatus = RXRPC_USERSTATUS_SERVICE_UPGRADE; /* If our RTT cache needs working on, request an ACK. Also request * ACKs if a DATA packet appears to have been lost. diff --git a/net/rxrpc/txbuf.c b/net/rxrpc/txbuf.c index 91e96cda6dc7..2e8c5b15a84f 100644 --- a/net/rxrpc/txbuf.c +++ b/net/rxrpc/txbuf.c @@ -19,10 +19,13 @@ atomic_t rxrpc_nr_txbuf; struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, gfp_t gfp) { + struct rxrpc_wire_header *whdr; struct rxrpc_txbuf *txb; txb = kmalloc(sizeof(*txb), gfp); if (txb) { + whdr = &txb->_wire; + INIT_LIST_HEAD(&txb->call_link); INIT_LIST_HEAD(&txb->tx_link); refcount_set(&txb->ref, 1); @@ -37,18 +40,18 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, txb->serial = 0; txb->cksum = 0; txb->nr_kvec = 1; - txb->kvec[0].iov_base = &txb->wire; - txb->kvec[0].iov_len = sizeof(txb->wire); - txb->wire.epoch = htonl(call->conn->proto.epoch); - txb->wire.cid = htonl(call->cid); - txb->wire.callNumber = htonl(call->call_id); - txb->wire.seq = htonl(txb->seq); - txb->wire.type = packet_type; - txb->wire.flags = 0; - txb->wire.userStatus = 0; - txb->wire.securityIndex = call->security_ix; - txb->wire._rsvd = 0; - txb->wire.serviceId = htons(call->dest_srx.srx_service); + txb->kvec[0].iov_base = whdr; + txb->kvec[0].iov_len = sizeof(*whdr); + whdr->epoch = htonl(call->conn->proto.epoch); + whdr->cid = htonl(call->cid); + whdr->callNumber = htonl(call->call_id); + whdr->seq = htonl(txb->seq); + whdr->type = packet_type; + whdr->flags = 0; + whdr->userStatus = 0; + whdr->securityIndex = call->security_ix; + whdr->_rsvd = 0; + whdr->serviceId = htons(call->dest_srx.srx_service); trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 1, From 0b40cd9b4ecca68d95edd1a2ce688c64db58b095 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Fri, 23 Feb 2024 10:52:17 +0100 Subject: [PATCH 1712/2255] can: kvaser_usb: Add support for Leaf v3 Add support for Kvaser Leaf v3, based on the hydra platform. Signed-off-by: Jimmy Assarsson Link: https://lore.kernel.org/all/20240223095217.43783-1-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/Kconfig | 1 + drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index d1450722cb3c..bd58c636d465 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -100,6 +100,7 @@ config CAN_KVASER_USB - Scania VCI2 (if you have the Kvaser logo on top) - Kvaser BlackBird v2 - Kvaser Leaf Pro HS v2 + - Kvaser Leaf v3 - Kvaser Hybrid CAN/LIN - Kvaser Hybrid 2xCAN/LIN - Kvaser Hybrid Pro CAN/LIN diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c index 71ef4db5c09f..8faf8a462c05 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c @@ -88,6 +88,7 @@ #define USB_USBCAN_PRO_4HS_PRODUCT_ID 0x0114 #define USB_HYBRID_CANLIN_PRODUCT_ID 0x0115 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 0x0116 +#define USB_LEAF_V3_PRODUCT_ID 0x0117 static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = { .quirks = KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP, @@ -235,6 +236,8 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID), .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_V3_PRODUCT_ID), + .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, { } }; MODULE_DEVICE_TABLE(usb, kvaser_usb_table); From 9b221ba452aa752a088f88bc40196e8f927b26f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Joci=C4=87?= Date: Fri, 1 Mar 2024 12:37:08 +0000 Subject: [PATCH 1713/2255] can: kvaser_pciefd: Add support for Kvaser PCIe 8xCAN Add support for new Kvaser pciefd device, PCIe 8xCAN, based on Xilinx FPGA. Signed-off-by: Martin Jocic Link: https://lore.kernel.org/all/2b2c720a788e1904283e354abb320adb5b631d26.camel@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/Kconfig | 1 + drivers/net/can/kvaser_pciefd.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 620766eb6bc1..2e31db55d927 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -169,6 +169,7 @@ config CAN_KVASER_PCIEFD Kvaser Mini PCI Express 1xCAN v3 Kvaser Mini PCI Express 2xCAN v3 Kvaser M.2 PCIe 4xCAN + Kvaser PCIe 8xCAN config CAN_SLCAN tristate "Serial / USB serial CAN Adaptors (slcan)" diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 416f10480b40..f81b598147b3 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -27,7 +27,7 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_BEC_POLL_FREQ (jiffies + msecs_to_jiffies(200)) #define KVASER_PCIEFD_MAX_ERR_REP 256U #define KVASER_PCIEFD_CAN_TX_MAX_COUNT 17U -#define KVASER_PCIEFD_MAX_CAN_CHANNELS 4UL +#define KVASER_PCIEFD_MAX_CAN_CHANNELS 8UL #define KVASER_PCIEFD_DMA_COUNT 2U #define KVASER_PCIEFD_DMA_SIZE (4U * 1024U) @@ -49,6 +49,7 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* Xilinx based devices */ #define KVASER_PCIEFD_M2_4CAN_DEVICE_ID 0x0017 +#define KVASER_PCIEFD_8CAN_DEVICE_ID 0x0019 /* Altera SerDes Enable 64-bit DMA address translation */ #define KVASER_PCIEFD_ALTERA_DMA_64BIT BIT(0) @@ -496,6 +497,10 @@ static struct pci_device_id kvaser_pciefd_id_table[] = { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_M2_4CAN_DEVICE_ID), .driver_data = (kernel_ulong_t)&kvaser_pciefd_xilinx_driver_data, }, + { + PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_8CAN_DEVICE_ID), + .driver_data = (kernel_ulong_t)&kvaser_pciefd_xilinx_driver_data, + }, { 0, }, From ef488e47e060eb6d6b08de12a2a9b40ba345c4d0 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 4 Mar 2024 08:45:30 +0100 Subject: [PATCH 1714/2255] can: gs_usb: gs_cmd_reset(): use cpu_to_le32() to assign mode The structure gs_device_mode dm::mode is a __le32, use cpu_to_le32() to assign GS_CAN_MODE_RESET. As GS_CAN_MODE_RESET is 0x0, this is basically a no-op. Link: https://lore.kernel.org/all/20240304074540.3584842-1-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/gs_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 95b0fdb602c8..65c962f76898 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -385,7 +385,7 @@ static struct gs_tx_context *gs_get_tx_context(struct gs_can *dev, static int gs_cmd_reset(struct gs_can *dev) { struct gs_device_mode dm = { - .mode = GS_CAN_MODE_RESET, + .mode = cpu_to_le32(GS_CAN_MODE_RESET), }; return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_MODE, From 79f7319908fb568f60b7ddbe0cb9c9d2e714ac87 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 4 Mar 2024 08:44:50 +0100 Subject: [PATCH 1715/2255] can: mcp251xfd: __mcp251xfd_get_berr_counter(): use CAN_BUS_OFF_THRESHOLD instead of open coding it Since 3f9c26210cf8 ("can: error: add definitions for the different CAN error thresholds") we have proper defines for the various CAN error thresholds. So make use of it and replace 256 by CAN_BUS_OFF_THRESHOLD. Link: https://lore.kernel.org/all/20240304074503.3584662-1-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index eebf967f4711..1d9057dc44f2 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -837,7 +837,7 @@ static int __mcp251xfd_get_berr_counter(const struct net_device *ndev, return err; if (trec & MCP251XFD_REG_TREC_TXBO) - bec->txerr = 256; + bec->txerr = CAN_BUS_OFF_THRESHOLD; else bec->txerr = FIELD_GET(MCP251XFD_REG_TREC_TEC_MASK, trec); bec->rxerr = FIELD_GET(MCP251XFD_REG_TREC_REC_MASK, trec); From 80bfab79b8351c8d858e6928a091b57c103dce29 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 09:39:07 +0000 Subject: [PATCH 1716/2255] net: adopt skb_network_offset() and similar helpers This is a cleanup patch, making code a bit more concise. 1) Use skb_network_offset(skb) in place of (skb_network_header(skb) - skb->data) 2) Use -skb_network_offset(skb) in place of (skb->data - skb_network_header(skb)) 3) Use skb_transport_offset(skb) in place of (skb_transport_header(skb) - skb->data) 4) Use skb_inner_transport_offset(skb) in place of (skb_inner_transport_header(skb) - skb->data) Signed-off-by: Eric Dumazet Acked-by: Edward Cree # for sfc Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 11 +++++------ drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 4 ++-- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 2 +- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- drivers/net/ethernet/intel/igbvf/netdev.c | 2 +- drivers/net/ethernet/intel/igc/igc_main.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 2 +- drivers/net/ethernet/qlogic/qede/qede_fp.c | 2 +- drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 3 +-- drivers/net/ethernet/sfc/siena/tx_common.c | 5 ++--- drivers/net/ethernet/sfc/tx_common.c | 5 ++--- drivers/net/ethernet/sfc/tx_tso.c | 4 ++-- drivers/net/ethernet/sun/sunvnet_common.c | 4 ++-- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 2 +- drivers/net/wireguard/receive.c | 2 +- kernel/bpf/cgroup.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/xfrm4_input.c | 2 +- net/ipv6/exthdrs.c | 4 ++-- net/ipv6/netfilter/nf_conntrack_reasm.c | 4 ++-- net/ipv6/reassembly.c | 4 ++-- net/ipv6/xfrm6_input.c | 2 +- 24 files changed, 36 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 528441b28c4e..adcee8d9d6d9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3538,7 +3538,7 @@ static u8 bnx2x_set_pbd_csum_enc(struct bnx2x *bp, struct sk_buff *skb, u32 *parsing_data, u32 xmit_type) { *parsing_data |= - ((((u8 *)skb_inner_transport_header(skb) - skb->data) >> 1) << + ((skb_inner_transport_offset(skb) >> 1) << ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) & ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W; @@ -3570,7 +3570,7 @@ static u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, u32 *parsing_data, u32 xmit_type) { *parsing_data |= - ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) << + ((skb_transport_offset(skb) >> 1) << ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) & ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W; @@ -3613,7 +3613,7 @@ static u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, u32 xmit_type) { - u8 hlen = (skb_network_header(skb) - skb->data) >> 1; + u8 hlen = skb_network_offset(skb) >> 1; /* for now NS flag is not used in Linux */ pbd->global_data = @@ -3667,8 +3667,7 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb, u8 outerip_off, outerip_len = 0; /* from outer IP to transport */ - hlen_w = (skb_inner_transport_header(skb) - - skb_network_header(skb)) >> 1; + hlen_w = skb_inner_transport_offset(skb) >> 1; /* transport len */ hlen_w += inner_tcp_hdrlen(skb) >> 1; @@ -3714,7 +3713,7 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb, 0, IPPROTO_TCP, 0)); } - outerip_off = (skb_network_header(skb) - skb->data) >> 1; + outerip_off = (skb_network_offset(skb)) >> 1; *global_data |= outerip_off | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index f1695c889d3a..19668a8d22f7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2473,9 +2473,9 @@ static netdev_features_t hns3_features_check(struct sk_buff *skb, return features; if (skb->encapsulation) - len = skb_inner_transport_header(skb) - skb->data; + len = skb_inner_transport_offset(skb); else - len = skb_transport_header(skb) - skb->data; + len = skb_transport_offset(skb); /* Assume L4 is 60 byte as TCP is the only protocol with a * a flexible value, and it's max len is 60 bytes. diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f12092cdb1f0..a67b13869016 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -13208,7 +13208,7 @@ static netdev_features_t i40e_features_check(struct sk_buff *skb, features &= ~NETIF_F_GSO_MASK; /* MACLEN can support at most 63 words */ - len = skb_network_header(skb) - skb->data; + len = skb_network_offset(skb); if (len & ~(63 * 2)) goto out_err; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 335fd13e86f7..245c458e38ae 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -4423,7 +4423,7 @@ static netdev_features_t iavf_features_check(struct sk_buff *skb, features &= ~NETIF_F_GSO_MASK; /* MACLEN can support at most 63 words */ - len = skb_network_header(skb) - skb->data; + len = skb_network_offset(skb); if (len & ~(63 * 2)) goto out_err; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index cebb44f51d5f..b35556550503 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2538,7 +2538,7 @@ igb_features_check(struct sk_buff *skb, struct net_device *dev, unsigned int network_hdr_len, mac_hdr_len; /* Make certain the headers can be described by a context descriptor */ - mac_hdr_len = skb_network_header(skb) - skb->data; + mac_hdr_len = skb_network_offset(skb); if (unlikely(mac_hdr_len > IGB_MAX_MAC_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index a4d4f00e6a87..b0cf310e6f7b 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -2655,7 +2655,7 @@ igbvf_features_check(struct sk_buff *skb, struct net_device *dev, unsigned int network_hdr_len, mac_hdr_len; /* Make certain the headers can be described by a context descriptor */ - mac_hdr_len = skb_network_header(skb) - skb->data; + mac_hdr_len = skb_network_offset(skb); if (unlikely(mac_hdr_len > IGBVF_MAX_MAC_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 3af52d238f3b..34820f6a78b9 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -5277,7 +5277,7 @@ igc_features_check(struct sk_buff *skb, struct net_device *dev, unsigned int network_hdr_len, mac_hdr_len; /* Make certain the headers can be described by a context descriptor */ - mac_hdr_len = skb_network_header(skb) - skb->data; + mac_hdr_len = skb_network_offset(skb); if (unlikely(mac_hdr_len > IGC_MAX_MAC_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index e23c3614fb10..1e93edc967ed 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -10205,7 +10205,7 @@ ixgbe_features_check(struct sk_buff *skb, struct net_device *dev, unsigned int network_hdr_len, mac_hdr_len; /* Make certain the headers can be described by a context descriptor */ - mac_hdr_len = skb_network_header(skb) - skb->data; + mac_hdr_len = skb_network_offset(skb); if (unlikely(mac_hdr_len > IXGBE_MAX_MAC_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index a44e4bd56142..9c960017a6de 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -4413,7 +4413,7 @@ ixgbevf_features_check(struct sk_buff *skb, struct net_device *dev, unsigned int network_hdr_len, mac_hdr_len; /* Make certain the headers can be described by a context descriptor */ - mac_hdr_len = skb_network_header(skb) - skb->data; + mac_hdr_len = skb_network_offset(skb); if (unlikely(mac_hdr_len > IXGBEVF_MAX_MAC_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index cb1746bc0e0c..847fa62c80df 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -215,7 +215,7 @@ static void qede_set_params_for_ipv6_ext(struct sk_buff *skb, bd2_bits1 |= (1 << ETH_TX_DATA_2ND_BD_IPV6_EXT_SHIFT); - bd2_bits2 |= ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) & + bd2_bits2 |= ((skb_transport_offset(skb) >> 1) & ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_MASK) << ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_SHIFT; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 41894d154013..b9dc0071c5de 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -446,8 +446,7 @@ static int qlcnic_tx_encap_pkt(struct qlcnic_adapter *adapter, encap_descr |= skb_network_offset(skb) << 10; first_desc->encap_descr = cpu_to_le16(encap_descr); - first_desc->tcp_hdr_offset = skb_inner_transport_header(skb) - - skb->data; + first_desc->tcp_hdr_offset = skb_inner_transport_offset(skb); first_desc->ip_hdr_offset = skb_inner_network_offset(skb); qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); diff --git a/drivers/net/ethernet/sfc/siena/tx_common.c b/drivers/net/ethernet/sfc/siena/tx_common.c index a7a9ab304e13..71f9b5ec5ae4 100644 --- a/drivers/net/ethernet/sfc/siena/tx_common.c +++ b/drivers/net/ethernet/sfc/siena/tx_common.c @@ -317,11 +317,10 @@ static int efx_tx_tso_header_length(struct sk_buff *skb) size_t header_len; if (skb->encapsulation) - header_len = skb_inner_transport_header(skb) - - skb->data + + header_len = skb_inner_transport_offset(skb) + (inner_tcp_hdr(skb)->doff << 2u); else - header_len = skb_transport_header(skb) - skb->data + + header_len = skb_transport_offset(skb) + (tcp_hdr(skb)->doff << 2u); return header_len; } diff --git a/drivers/net/ethernet/sfc/tx_common.c b/drivers/net/ethernet/sfc/tx_common.c index 9f2393d34371..2adb132b2f7e 100644 --- a/drivers/net/ethernet/sfc/tx_common.c +++ b/drivers/net/ethernet/sfc/tx_common.c @@ -336,11 +336,10 @@ int efx_tx_tso_header_length(struct sk_buff *skb) size_t header_len; if (skb->encapsulation) - header_len = skb_inner_transport_header(skb) - - skb->data + + header_len = skb_inner_transport_offset(skb) + (inner_tcp_hdr(skb)->doff << 2u); else - header_len = skb_transport_header(skb) - skb->data + + header_len = skb_transport_offset(skb) + (tcp_hdr(skb)->doff << 2u); return header_len; } diff --git a/drivers/net/ethernet/sfc/tx_tso.c b/drivers/net/ethernet/sfc/tx_tso.c index 64a6768f75ea..ddf149db8180 100644 --- a/drivers/net/ethernet/sfc/tx_tso.c +++ b/drivers/net/ethernet/sfc/tx_tso.c @@ -174,8 +174,8 @@ static int tso_start(struct tso_state *st, struct efx_nic *efx, unsigned int header_len, in_len; dma_addr_t dma_addr; - st->ip_off = skb_network_header(skb) - skb->data; - st->tcp_off = skb_transport_header(skb) - skb->data; + st->ip_off = skb_network_offset(skb); + st->tcp_off = skb_transport_offset(skb); header_len = st->tcp_off + (tcp_hdr(skb)->doff << 2u); in_len = skb_headlen(skb) - header_len; st->header_len = header_len; diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c index 3525d5c0d694..351609f4f011 100644 --- a/drivers/net/ethernet/sun/sunvnet_common.c +++ b/drivers/net/ethernet/sun/sunvnet_common.c @@ -1144,9 +1144,9 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies) nskb->protocol = skb->protocol; offset = skb_mac_header(skb) - skb->data; skb_set_mac_header(nskb, offset); - offset = skb_network_header(skb) - skb->data; + offset = skb_network_offset(skb); skb_set_network_header(nskb, offset); - offset = skb_transport_header(skb) - skb->data; + offset = skb_transport_offset(skb); skb_set_transport_header(nskb, offset); offset = 0; diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 7cf02ab6de68..6dff2c85682d 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1257,7 +1257,7 @@ static int wx_tso(struct wx_ring *tx_ring, struct wx_tx_buffer *first, /* compute header lengths */ l4len = enc ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb); - *hdr_len = enc ? (skb_inner_transport_header(skb) - skb->data) : + *hdr_len = enc ? skb_inner_transport_offset(skb) : skb_transport_offset(skb); *hdr_len += l4len; diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c index a176653c8861..df275b4fccb6 100644 --- a/drivers/net/wireguard/receive.c +++ b/drivers/net/wireguard/receive.c @@ -263,7 +263,7 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) * call skb_cow_data, so that there's no chance that data is removed * from the skb, so that later we can extract the original endpoint. */ - offset = skb->data - skb_network_header(skb); + offset = -skb_network_offset(skb); skb_push(skb, offset); num_frags = skb_cow_data(skb, 0, &trailer); offset += sizeof(struct message_data); diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 5a568bbbeaeb..82243cb6c54d 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1358,7 +1358,7 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk, struct sk_buff *skb, enum cgroup_bpf_attach_type atype) { - unsigned int offset = skb->data - skb_network_header(skb); + unsigned int offset = -skb_network_offset(skb); struct sock *save_sk; void *saved_data_end; struct cgroup *cgrp; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 7d2bdfd7e7d7..a82fd102df05 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -310,7 +310,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) } nf_reset_ct(skb); - skb_push(skb, skb->data - skb_network_header(skb)); + skb_push(skb, -skb_network_offset(skb)); raw_rcv_skb(sk, skb); return 0; diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index c54676998eb6..dae35101d189 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -58,7 +58,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) return -iph->protocol; #endif - __skb_push(skb, skb->data - skb_network_header(skb)); + __skb_push(skb, -skb_network_offset(skb)); iph->tot_len = htons(skb->len); ip_send_check(iph); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 26f1e4a5ade0..25a5b394481b 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -804,7 +804,7 @@ looped_back: ip6_route_input(skb); if (skb_dst(skb)->error) { - skb_push(skb, skb->data - skb_network_header(skb)); + skb_push(skb, -skb_network_offset(skb)); dst_input(skb); return -1; } @@ -821,7 +821,7 @@ looped_back: goto looped_back; } - skb_push(skb, skb->data - skb_network_header(skb)); + skb_push(skb, -skb_network_offset(skb)); dst_input(skb); return -1; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index b2dd48911c8d..1a51a44571c3 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -327,9 +327,9 @@ static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb, if (!reasm_data) goto err; - payload_len = ((skb->data - skb_network_header(skb)) - + payload_len = -skb_network_offset(skb) - sizeof(struct ipv6hdr) + fq->q.len - - sizeof(struct frag_hdr)); + sizeof(struct frag_hdr); if (payload_len > IPV6_MAXPLEN) { net_dbg_ratelimited("nf_ct_frag6_reasm: payload len = %d\n", payload_len); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 5ebc47da1000..acb4f119e11f 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -272,9 +272,9 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb, if (!reasm_data) goto out_oom; - payload_len = ((skb->data - skb_network_header(skb)) - + payload_len = -skb_network_offset(skb) - sizeof(struct ipv6hdr) + fq->q.len - - sizeof(struct frag_hdr)); + sizeof(struct frag_hdr); if (payload_len > IPV6_MAXPLEN) goto out_oversize; diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 6e36e5047fba..a17d783dc7c0 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -43,7 +43,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk, int xfrm6_transport_finish(struct sk_buff *skb, int async) { struct xfrm_offload *xo = xfrm_offload(skb); - int nhlen = skb->data - skb_network_header(skb); + int nhlen = -skb_network_offset(skb); skb_network_header(skb)[IP6CB(skb)->nhoff] = XFRM_MODE_SKB_CB(skb)->protocol; From cc15bd10e716fcb472d611f24d76c795acb0f8c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Feb 2024 09:39:08 +0000 Subject: [PATCH 1717/2255] net: adopt skb_network_header_len() more broadly (skb_transport_header(skb) - skb_network_header(skb)) can be replaced by skb_network_header_len(skb) Add a DEBUG_NET_WARN_ON_ONCE() in skb_network_header_len() to catch cases were the transport_header was not set. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3 +-- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 3 +-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- drivers/net/wireless/intel/iwlwifi/queue/tx.c | 2 +- include/linux/skbuff.h | 1 + 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index adcee8d9d6d9..c9b6acd8c892 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3621,8 +3621,7 @@ static u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) << ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT)); - pbd->ip_hlen_w = (skb_transport_header(skb) - - skb_network_header(skb)) >> 1; + pbd->ip_hlen_w = skb_network_header_len(skb) >> 1; hlen += pbd->ip_hlen_w; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index a67b13869016..3fada49b8ae2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -13213,7 +13213,7 @@ static netdev_features_t i40e_features_check(struct sk_buff *skb, goto out_err; /* IPLEN and EIPLEN can support at most 127 dwords */ - len = skb_transport_header(skb) - skb_network_header(skb); + len = skb_network_header_len(skb); if (len & ~(127 * 4)) goto out_err; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 245c458e38ae..aefec6bd3b67 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -4428,7 +4428,7 @@ static netdev_features_t iavf_features_check(struct sk_buff *skb, goto out_err; /* IPLEN and EIPLEN can support at most 127 dwords */ - len = skb_transport_header(skb) - skb_network_header(skb); + len = skb_network_header_len(skb); if (len & ~(127 * 4)) goto out_err; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index e502f4ee9e1f..782ddc8c296b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1015,8 +1015,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG; u8 tid; - snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + - tcp_hdrlen(skb); + snap_ip_tcp = 8 + skb_network_header_len(skb) + tcp_hdrlen(skb); if (!mvmsta->max_amsdu_len || !ieee80211_is_data_qos(hdr->frame_control) || diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 6c2b37e56c78..fa8eba47dc4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1331,7 +1331,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, trans->txqs.tfd.size, &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, 0); - ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); + ip_hdrlen = skb_network_header_len(skb); snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len; amsdu_pad = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index d3bde2d010b7..33973a60d0bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -353,7 +353,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, start_len, 0); - ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); + ip_hdrlen = skb_network_header_len(skb); snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len; amsdu_pad = 0; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1470b74fb6d2..d577e0bee18d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3036,6 +3036,7 @@ static inline int skb_transport_offset(const struct sk_buff *skb) static inline u32 skb_network_header_len(const struct sk_buff *skb) { + DEBUG_NET_WARN_ON_ONCE(!skb_transport_header_was_set(skb)); return skb->transport_header - skb->network_header; } From 6f355bbb5ca3062fceb945f9ec08bc892046ae90 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 29 Feb 2024 09:04:23 -0800 Subject: [PATCH 1718/2255] net: bareudp: Do not allocate stats in the driver With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the bareudp driver and leverage the network core allocation. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/bareudp.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index 4db6122c9b43..27408f0b93d6 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -194,15 +194,10 @@ static int bareudp_init(struct net_device *dev) struct bareudp_dev *bareudp = netdev_priv(dev); int err; - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - err = gro_cells_init(&bareudp->gro_cells, dev); - if (err) { - free_percpu(dev->tstats); + if (err) return err; - } + return 0; } @@ -211,7 +206,6 @@ static void bareudp_uninit(struct net_device *dev) struct bareudp_dev *bareudp = netdev_priv(dev); gro_cells_destroy(&bareudp->gro_cells); - free_percpu(dev->tstats); } static struct socket *bareudp_create_sock(struct net *net, __be16 port) @@ -567,6 +561,7 @@ static void bareudp_setup(struct net_device *dev) netif_keep_dst(dev); dev->priv_flags |= IFF_NO_QUEUE; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; } static int bareudp_validate(struct nlattr *tb[], struct nlattr *data[], From 4ab597d2962195ca4f01a429f9b2ea87ee684be3 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 29 Feb 2024 09:04:24 -0800 Subject: [PATCH 1719/2255] net: bareudp: Remove generic .ndo_get_stats64 Commit 3e2f544dd8a33 ("net: get stats64 if device if driver is configured") moved the callback to dev_get_tstats64() to net core, so, unless the driver is doing some custom stats collection, it does not need to set .ndo_get_stats64. Since this driver is now relying in NETDEV_PCPU_STAT_TSTATS, then, it doesn't need to set the dev_get_tstats64() generic .ndo_get_stats64 function pointer. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/bareudp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index 27408f0b93d6..339db6e4a1d5 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -523,7 +523,6 @@ static const struct net_device_ops bareudp_netdev_ops = { .ndo_open = bareudp_open, .ndo_stop = bareudp_stop, .ndo_start_xmit = bareudp_xmit, - .ndo_get_stats64 = dev_get_tstats64, .ndo_fill_metadata_dst = bareudp_fill_metadata_dst, }; From df620d7fabe984accf6567c846e4188fbd8add4d Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Thu, 29 Feb 2024 18:24:00 +0000 Subject: [PATCH 1720/2255] dt-bindings: leds: pwm-multicolour: re-allow active-low active-low was lifted to the common schema for leds, but it went unnoticed that the leds-multicolour binding had "additionalProperties: false" where the other users had "unevaluatedProperties: false", thereby disallowing active-low for multicolour leds. Explicitly permit it again. Fixes: c94d1783136e ("dt-bindings: net: phy: Make LED active-low property common") Acked-by: Rob Herring Signed-off-by: Conor Dooley Acked-by: Lee Jones Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml b/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml index 5edfbe347341..a31a202afe5c 100644 --- a/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml +++ b/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml @@ -41,6 +41,8 @@ properties: pwm-names: true + active-low: true + color: true required: From 061b9bedbef124ab28682496bdba7f265f13b2f3 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:24 -0800 Subject: [PATCH 1721/2255] ionic: Rework Tx start/stop flow Currently the driver attempts to wake the Tx queue for every descriptor processed. However, this is overkill and can cause thrashing since Tx xmit can be running concurrently on a different CPU than Tx clean. Fix this by refactoring Tx cq servicing into its own function so the Tx wake code can run after processing all Tx descriptors. The driver isn't using the expected memory barriers to make sure the stop/start bits are coherent. Fix this by making sure to use the correct memory barriers. Also, the driver is using the wake API during Tx xmit even though it's already scheduled. Fix this by using the start API during Tx xmit. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_dev.h | 2 + .../net/ethernet/pensando/ionic/ionic_lif.c | 3 +- .../net/ethernet/pensando/ionic/ionic_txrx.c | 89 ++++++++++--------- .../net/ethernet/pensando/ionic/ionic_txrx.h | 1 - 4 files changed, 50 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index bfcfc2d7bcbd..abe64086e8ca 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -19,6 +19,7 @@ #define IONIC_DEF_TXRX_DESC 4096 #define IONIC_RX_FILL_THRESHOLD 16 #define IONIC_RX_FILL_DIV 8 +#define IONIC_TSO_DESCS_NEEDED 44 /* 64K TSO @1500B */ #define IONIC_LIFS_MAX 1024 #define IONIC_WATCHDOG_SECS 5 #define IONIC_ITR_COAL_USEC_DEFAULT 64 @@ -379,6 +380,7 @@ typedef void (*ionic_cq_done_cb)(void *done_arg); unsigned int ionic_cq_service(struct ionic_cq *cq, unsigned int work_to_do, ionic_cq_cb cb, ionic_cq_done_cb done_cb, void *done_arg); +unsigned int ionic_tx_cq_service(struct ionic_cq *cq, unsigned int work_to_do); int ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev, struct ionic_queue *q, unsigned int index, const char *name, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 1496893c28be..4271ebb0ddc0 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1262,8 +1262,7 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget) ionic_rx_service, NULL, NULL); if (lif->hwstamp_txq) - tx_work = ionic_cq_service(&lif->hwstamp_txq->cq, budget, - ionic_tx_service, NULL, NULL); + tx_work = ionic_tx_cq_service(&lif->hwstamp_txq->cq, budget); work_done = max(max(n_work, a_work), max(rx_work, tx_work)); if (work_done < budget && napi_complete_done(napi, work_done)) { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 56a7ad5bff17..dcaa8a4d6ad5 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -5,13 +5,12 @@ #include #include #include +#include #include "ionic.h" #include "ionic_lif.h" #include "ionic_txrx.h" -static int ionic_maybe_stop_tx(struct ionic_queue *q, int ndescs); - static dma_addr_t ionic_tx_map_single(struct ionic_queue *q, void *data, size_t len); @@ -458,7 +457,9 @@ int ionic_xdp_xmit(struct net_device *netdev, int n, txq_trans_cond_update(nq); if (netif_tx_queue_stopped(nq) || - unlikely(ionic_maybe_stop_tx(txq, 1))) { + !netif_txq_maybe_stop(q_to_ndq(txq), + ionic_q_space_avail(txq), + 1, 1)) { __netif_tx_unlock(nq); return -EIO; } @@ -478,7 +479,9 @@ int ionic_xdp_xmit(struct net_device *netdev, int n, ionic_dbell_ring(lif->kern_dbpage, txq->hw_type, txq->dbval | txq->head_idx); - ionic_maybe_stop_tx(txq, 4); + netif_txq_maybe_stop(q_to_ndq(txq), + ionic_q_space_avail(txq), + 4, 4); __netif_tx_unlock(nq); return nxmit; @@ -571,7 +574,9 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, txq_trans_cond_update(nq); if (netif_tx_queue_stopped(nq) || - unlikely(ionic_maybe_stop_tx(txq, 1))) { + !netif_txq_maybe_stop(q_to_ndq(txq), + ionic_q_space_avail(txq), + 1, 1)) { __netif_tx_unlock(nq); goto out_xdp_abort; } @@ -946,8 +951,7 @@ int ionic_tx_napi(struct napi_struct *napi, int budget) lif = cq->bound_q->lif; idev = &lif->ionic->idev; - work_done = ionic_cq_service(cq, budget, - ionic_tx_service, NULL, NULL); + work_done = ionic_tx_cq_service(cq, budget); if (unlikely(!budget)) return budget; @@ -1038,8 +1042,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget) txqcq = lif->txqcqs[qi]; txcq = &lif->txqcqs[qi]->cq; - tx_work_done = ionic_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT, - ionic_tx_service, NULL, NULL); + tx_work_done = ionic_tx_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT); if (unlikely(!budget)) return budget; @@ -1183,7 +1186,6 @@ static void ionic_tx_clean(struct ionic_queue *q, struct ionic_tx_stats *stats = q_to_tx_stats(q); struct ionic_qcq *qcq = q_to_qcq(q); struct sk_buff *skb = cb_arg; - u16 qi; if (desc_info->xdpf) { ionic_xdp_tx_desc_clean(q->partner, desc_info); @@ -1200,8 +1202,6 @@ static void ionic_tx_clean(struct ionic_queue *q, if (!skb) return; - qi = skb_get_queue_mapping(skb); - if (ionic_txq_hwstamp_enabled(q)) { if (cq_info) { struct skb_shared_hwtstamps hwts = {}; @@ -1227,9 +1227,6 @@ static void ionic_tx_clean(struct ionic_queue *q, stats->hwstamp_invalid++; } } - - } else if (unlikely(__netif_subqueue_stopped(q->lif->netdev, qi))) { - netif_wake_subqueue(q->lif->netdev, qi); } desc_info->bytes = skb->len; @@ -1238,7 +1235,7 @@ static void ionic_tx_clean(struct ionic_queue *q, dev_consume_skb_any(skb); } -bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) +static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) { struct ionic_queue *q = cq->bound_q; struct ionic_desc_info *desc_info; @@ -1275,6 +1272,37 @@ bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) return true; } +unsigned int ionic_tx_cq_service(struct ionic_cq *cq, unsigned int work_to_do) +{ + struct ionic_cq_info *cq_info; + unsigned int work_done = 0; + + if (work_to_do == 0) + return 0; + + cq_info = &cq->info[cq->tail_idx]; + while (ionic_tx_service(cq, cq_info)) { + if (cq->tail_idx == cq->num_descs - 1) + cq->done_color = !cq->done_color; + cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1); + cq_info = &cq->info[cq->tail_idx]; + + if (++work_done >= work_to_do) + break; + } + + if (work_done) { + struct ionic_queue *q = cq->bound_q; + + smp_mb(); /* assure sync'd state before stopped check */ + if (unlikely(__netif_subqueue_stopped(q->lif->netdev, q->index)) && + ionic_q_has_space(q, IONIC_TSO_DESCS_NEEDED)) + netif_wake_subqueue(q->lif->netdev, q->index); + } + + return work_done; +} + void ionic_tx_flush(struct ionic_cq *cq) { struct ionic_dev *idev = &cq->lif->ionic->idev; @@ -1724,25 +1752,6 @@ linearize: return ndescs; } -static int ionic_maybe_stop_tx(struct ionic_queue *q, int ndescs) -{ - int stopped = 0; - - if (unlikely(!ionic_q_has_space(q, ndescs))) { - netif_stop_subqueue(q->lif->netdev, q->index); - stopped = 1; - - /* Might race with ionic_tx_clean, check again */ - smp_rmb(); - if (ionic_q_has_space(q, ndescs)) { - netif_wake_subqueue(q->lif->netdev, q->index); - stopped = 0; - } - } - - return stopped; -} - static netdev_tx_t ionic_start_hwstamp_xmit(struct sk_buff *skb, struct net_device *netdev) { @@ -1804,7 +1813,9 @@ netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (ndescs < 0) goto err_out_drop; - if (unlikely(ionic_maybe_stop_tx(q, ndescs))) + if (!netif_txq_maybe_stop(q_to_ndq(q), + ionic_q_space_avail(q), + ndescs, ndescs)) return NETDEV_TX_BUSY; if (skb_is_gso(skb)) @@ -1815,12 +1826,6 @@ netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (err) goto err_out_drop; - /* Stop the queue if there aren't descriptors for the next packet. - * Since our SG lists per descriptor take care of most of the possible - * fragmentation, we don't need to have many descriptors available. - */ - ionic_maybe_stop_tx(q, 4); - return NETDEV_TX_OK; err_out_drop: diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.h b/drivers/net/ethernet/pensando/ionic/ionic_txrx.h index 82fc38e0f573..68228bb8c119 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.h @@ -15,7 +15,6 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget); netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev); bool ionic_rx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info); -bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info); int ionic_xdp_xmit(struct net_device *netdev, int n, struct xdp_frame **xdp, u32 flags); #endif /* _IONIC_TXRX_H_ */ From 4d140402c6e8b58c6ab76f716ae38c558bf5b080 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:25 -0800 Subject: [PATCH 1722/2255] ionic: Change default number of descriptors for Tx and Rx Cut down the number of default Tx and Rx descriptors to save initial memory requirements. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_dev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index abe64086e8ca..516db910e8e8 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -16,7 +16,7 @@ #define IONIC_MAX_TX_DESC 8192 #define IONIC_MAX_RX_DESC 16384 #define IONIC_MIN_TXRX_DESC 64 -#define IONIC_DEF_TXRX_DESC 4096 +#define IONIC_DEF_TXRX_DESC 1024 #define IONIC_RX_FILL_THRESHOLD 16 #define IONIC_RX_FILL_DIV 8 #define IONIC_TSO_DESCS_NEEDED 44 /* 64K TSO @1500B */ From 97085cda1227939f0abe07d25a8107d4182cafbe Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:26 -0800 Subject: [PATCH 1723/2255] ionic: Shorten a Tx hotpath Perf was showing some hot spots in ionic_tx_descs_needed() for TSO traffic. Rework the function to return sooner where possible. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index dcaa8a4d6ad5..2837f2cc0151 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -1669,7 +1669,7 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb) static int ionic_tx_descs_needed(struct ionic_queue *q, struct sk_buff *skb) { - struct ionic_tx_stats *stats = q_to_tx_stats(q); + int nr_frags = skb_shinfo(skb)->nr_frags; bool too_many_frags = false; skb_frag_t *frag; int desc_bufs; @@ -1685,17 +1685,20 @@ static int ionic_tx_descs_needed(struct ionic_queue *q, struct sk_buff *skb) /* Each desc is mss long max, so a descriptor for each gso_seg */ if (skb_is_gso(skb)) { ndescs = skb_shinfo(skb)->gso_segs; + if (!nr_frags) + return ndescs; } else { ndescs = 1; - if (skb_shinfo(skb)->nr_frags > q->max_sg_elems) { + if (!nr_frags) + return ndescs; + + if (unlikely(nr_frags > q->max_sg_elems)) { too_many_frags = true; goto linearize; } - } - /* If non-TSO, or no frags to check, we're done */ - if (!skb_is_gso(skb) || !skb_shinfo(skb)->nr_frags) return ndescs; + } /* We need to scan the skb to be sure that none of the MTU sized * packets in the TSO will require more sgs per descriptor than we @@ -1743,6 +1746,8 @@ static int ionic_tx_descs_needed(struct ionic_queue *q, struct sk_buff *skb) linearize: if (too_many_frags) { + struct ionic_tx_stats *stats = q_to_tx_stats(q); + err = skb_linearize(skb); if (err) return err; From 386e69865311044b576ff536c99c6ee9cc98a228 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:27 -0800 Subject: [PATCH 1724/2255] ionic: Make use napi_consume_skb Make use of napi_consume_skb so that skb recycling can happen by way of the napi_skb_cache. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 2837f2cc0151..3da4fd322690 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -1232,7 +1232,7 @@ static void ionic_tx_clean(struct ionic_queue *q, desc_info->bytes = skb->len; stats->clean++; - dev_consume_skb_any(skb); + napi_consume_skb(skb, 1); } static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) From bc581273fead93ccc918b8c9a5b8a9f60b1ee836 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:28 -0800 Subject: [PATCH 1725/2255] ionic: Clean up BQL logic The driver currently calls netdev_tx_completed_queue() for every Tx completion. However, this API is only meant to be called once per NAPI if any Tx work is done. Make the necessary changes to support calling netdev_tx_completed_queue() only once per NAPI. Also, use the __netdev_tx_sent_queue() API, which supports the xmit_more functionality. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_txrx.c | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 3da4fd322690..1397a0dcf794 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -1235,13 +1235,14 @@ static void ionic_tx_clean(struct ionic_queue *q, napi_consume_skb(skb, 1); } -static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) +static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info, + unsigned int *total_pkts, unsigned int *total_bytes) { struct ionic_queue *q = cq->bound_q; struct ionic_desc_info *desc_info; struct ionic_txq_comp *comp; - int bytes = 0; - int pkts = 0; + unsigned int bytes = 0; + unsigned int pkts = 0; u16 index; comp = cq_info->cq_desc + cq->desc_size - sizeof(*comp); @@ -1266,8 +1267,8 @@ static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) desc_info->cb_arg = NULL; } while (index != le16_to_cpu(comp->comp_index)); - if (pkts && bytes && !ionic_txq_hwstamp_enabled(q)) - netdev_tx_completed_queue(q_to_ndq(q), pkts, bytes); + (*total_pkts) += pkts; + (*total_bytes) += bytes; return true; } @@ -1276,12 +1277,14 @@ unsigned int ionic_tx_cq_service(struct ionic_cq *cq, unsigned int work_to_do) { struct ionic_cq_info *cq_info; unsigned int work_done = 0; + unsigned int bytes = 0; + unsigned int pkts = 0; if (work_to_do == 0) return 0; cq_info = &cq->info[cq->tail_idx]; - while (ionic_tx_service(cq, cq_info)) { + while (ionic_tx_service(cq, cq_info, &pkts, &bytes)) { if (cq->tail_idx == cq->num_descs - 1) cq->done_color = !cq->done_color; cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1); @@ -1294,10 +1297,10 @@ unsigned int ionic_tx_cq_service(struct ionic_cq *cq, unsigned int work_to_do) if (work_done) { struct ionic_queue *q = cq->bound_q; - smp_mb(); /* assure sync'd state before stopped check */ - if (unlikely(__netif_subqueue_stopped(q->lif->netdev, q->index)) && - ionic_q_has_space(q, IONIC_TSO_DESCS_NEEDED)) - netif_wake_subqueue(q->lif->netdev, q->index); + if (!ionic_txq_hwstamp_enabled(q)) + netif_txq_completed_wake(q_to_ndq(q), pkts, bytes, + ionic_q_space_avail(q), + IONIC_TSO_DESCS_NEEDED); } return work_done; @@ -1308,8 +1311,7 @@ void ionic_tx_flush(struct ionic_cq *cq) struct ionic_dev *idev = &cq->lif->ionic->idev; u32 work_done; - work_done = ionic_cq_service(cq, cq->num_descs, - ionic_tx_service, NULL, NULL); + work_done = ionic_tx_cq_service(cq, cq->num_descs); if (work_done) ionic_intr_credits(idev->intr_ctrl, cq->bound_intr->index, work_done, IONIC_INTR_CRED_RESET_COALESCE); @@ -1335,8 +1337,10 @@ void ionic_tx_empty(struct ionic_queue *q) desc_info->cb_arg = NULL; } - if (pkts && bytes && !ionic_txq_hwstamp_enabled(q)) + if (!ionic_txq_hwstamp_enabled(q)) { netdev_tx_completed_queue(q_to_ndq(q), pkts, bytes); + netdev_tx_reset_queue(q_to_ndq(q)); + } } static int ionic_tx_tcp_inner_pseudo_csum(struct sk_buff *skb) @@ -1643,6 +1647,7 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb) { struct ionic_desc_info *desc_info = &q->info[q->head_idx]; struct ionic_tx_stats *stats = q_to_tx_stats(q); + bool ring_dbell = true; if (unlikely(ionic_tx_map_skb(q, skb, desc_info))) return -EIO; @@ -1661,8 +1666,9 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb) stats->bytes += skb->len; if (!ionic_txq_hwstamp_enabled(q)) - netdev_tx_sent_queue(q_to_ndq(q), skb->len); - ionic_txq_post(q, !netdev_xmit_more(), ionic_tx_clean, skb); + ring_dbell = __netdev_tx_sent_queue(q_to_ndq(q), skb->len, + netdev_xmit_more()); + ionic_txq_post(q, ring_dbell, ionic_tx_clean, skb); return 0; } From 138506ab249b7ac7856cb7a5a536a4b61a7a4ae1 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:29 -0800 Subject: [PATCH 1726/2255] ionic: Check stop no restart If there is a lot of transmit traffic the driver can get into a situation that the device is starved due to the doorbell never being rung. This can happen if xmit_more is set constantly and __netdev_tx_sent_queue() keeps returning false. Fix this by checking if the queue needs to be stopped right before calling __netdev_tx_sent_queue(). Use MAX_SKB_FRAGS + 1 as the stop condition because that's the maximum number of frags supported for non-TSO transmit. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 1397a0dcf794..d9e23fc78e6b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -1665,9 +1665,14 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb) stats->pkts++; stats->bytes += skb->len; - if (!ionic_txq_hwstamp_enabled(q)) - ring_dbell = __netdev_tx_sent_queue(q_to_ndq(q), skb->len, + if (!ionic_txq_hwstamp_enabled(q)) { + struct netdev_queue *ndq = q_to_ndq(q); + + if (unlikely(!ionic_q_has_space(q, MAX_SKB_FRAGS + 1))) + netif_tx_stop_queue(ndq); + ring_dbell = __netdev_tx_sent_queue(ndq, skb->len, netdev_xmit_more()); + } ionic_txq_post(q, ring_dbell, ionic_tx_clean, skb); return 0; From 1937b7ab6bd6bd4cee631fa6ea9142bb4dabc898 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:30 -0800 Subject: [PATCH 1727/2255] ionic: Pass local netdev instead of referencing struct Instead of using q->lif->netdev, just pass the netdev when it's locally defined. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_txrx.c | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index d9e23fc78e6b..f217b9875f1b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -99,9 +99,10 @@ bool ionic_rxq_poke_doorbell(struct ionic_queue *q) return true; } -static inline struct netdev_queue *q_to_ndq(struct ionic_queue *q) +static inline struct netdev_queue *q_to_ndq(struct net_device *netdev, + struct ionic_queue *q) { - return netdev_get_tx_queue(q->lif->netdev, q->index); + return netdev_get_tx_queue(netdev, q->index); } static void *ionic_rx_buf_va(struct ionic_buf_info *buf_info) @@ -203,14 +204,14 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q, return true; } -static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, +static struct sk_buff *ionic_rx_frags(struct net_device *netdev, + struct ionic_queue *q, struct ionic_desc_info *desc_info, unsigned int headroom, unsigned int len, unsigned int num_sg_elems, bool synced) { - struct net_device *netdev = q->lif->netdev; struct ionic_buf_info *buf_info; struct ionic_rx_stats *stats; struct device *dev = q->dev; @@ -271,13 +272,13 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, return skb; } -static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, +static struct sk_buff *ionic_rx_copybreak(struct net_device *netdev, + struct ionic_queue *q, struct ionic_desc_info *desc_info, unsigned int headroom, unsigned int len, bool synced) { - struct net_device *netdev = q->lif->netdev; struct ionic_buf_info *buf_info; struct ionic_rx_stats *stats; struct device *dev = q->dev; @@ -308,7 +309,7 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, headroom, len, DMA_FROM_DEVICE); skb_put(skb, len); - skb->protocol = eth_type_trans(skb, q->lif->netdev); + skb->protocol = eth_type_trans(skb, netdev); return skb; } @@ -348,8 +349,7 @@ static void ionic_xdp_tx_desc_clean(struct ionic_queue *q, desc_info->act = 0; } -static int ionic_xdp_post_frame(struct net_device *netdev, - struct ionic_queue *q, struct xdp_frame *frame, +static int ionic_xdp_post_frame(struct ionic_queue *q, struct xdp_frame *frame, enum xdp_action act, struct page *page, int off, bool ring_doorbell) { @@ -457,7 +457,7 @@ int ionic_xdp_xmit(struct net_device *netdev, int n, txq_trans_cond_update(nq); if (netif_tx_queue_stopped(nq) || - !netif_txq_maybe_stop(q_to_ndq(txq), + !netif_txq_maybe_stop(q_to_ndq(netdev, txq), ionic_q_space_avail(txq), 1, 1)) { __netif_tx_unlock(nq); @@ -466,7 +466,7 @@ int ionic_xdp_xmit(struct net_device *netdev, int n, space = min_t(int, n, ionic_q_space_avail(txq)); for (nxmit = 0; nxmit < space ; nxmit++) { - if (ionic_xdp_post_frame(netdev, txq, xdp_frames[nxmit], + if (ionic_xdp_post_frame(txq, xdp_frames[nxmit], XDP_REDIRECT, virt_to_page(xdp_frames[nxmit]->data), 0, false)) { @@ -479,7 +479,7 @@ int ionic_xdp_xmit(struct net_device *netdev, int n, ionic_dbell_ring(lif->kern_dbpage, txq->hw_type, txq->dbval | txq->head_idx); - netif_txq_maybe_stop(q_to_ndq(txq), + netif_txq_maybe_stop(q_to_ndq(netdev, txq), ionic_q_space_avail(txq), 4, 4); __netif_tx_unlock(nq); @@ -574,7 +574,7 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, txq_trans_cond_update(nq); if (netif_tx_queue_stopped(nq) || - !netif_txq_maybe_stop(q_to_ndq(txq), + !netif_txq_maybe_stop(q_to_ndq(netdev, txq), ionic_q_space_avail(txq), 1, 1)) { __netif_tx_unlock(nq); @@ -584,7 +584,7 @@ static bool ionic_run_xdp(struct ionic_rx_stats *stats, dma_unmap_page(rxq->dev, buf_info->dma_addr, IONIC_PAGE_SIZE, DMA_FROM_DEVICE); - err = ionic_xdp_post_frame(netdev, txq, xdpf, XDP_TX, + err = ionic_xdp_post_frame(txq, xdpf, XDP_TX, buf_info->page, buf_info->page_offset, true); @@ -662,9 +662,10 @@ static void ionic_rx_clean(struct ionic_queue *q, headroom = q->xdp_rxq_info ? XDP_PACKET_HEADROOM : 0; if (len <= q->lif->rx_copybreak) - skb = ionic_rx_copybreak(q, desc_info, headroom, len, !!xdp_prog); + skb = ionic_rx_copybreak(netdev, q, desc_info, + headroom, len, !!xdp_prog); else - skb = ionic_rx_frags(q, desc_info, headroom, len, + skb = ionic_rx_frags(netdev, q, desc_info, headroom, len, comp->num_sg_elems, !!xdp_prog); if (unlikely(!skb)) { @@ -1298,7 +1299,8 @@ unsigned int ionic_tx_cq_service(struct ionic_cq *cq, unsigned int work_to_do) struct ionic_queue *q = cq->bound_q; if (!ionic_txq_hwstamp_enabled(q)) - netif_txq_completed_wake(q_to_ndq(q), pkts, bytes, + netif_txq_completed_wake(q_to_ndq(q->lif->netdev, q), + pkts, bytes, ionic_q_space_avail(q), IONIC_TSO_DESCS_NEEDED); } @@ -1338,8 +1340,10 @@ void ionic_tx_empty(struct ionic_queue *q) } if (!ionic_txq_hwstamp_enabled(q)) { - netdev_tx_completed_queue(q_to_ndq(q), pkts, bytes); - netdev_tx_reset_queue(q_to_ndq(q)); + struct netdev_queue *ndq = q_to_ndq(q->lif->netdev, q); + + netdev_tx_completed_queue(ndq, pkts, bytes); + netdev_tx_reset_queue(ndq); } } @@ -1388,7 +1392,7 @@ static int ionic_tx_tcp_pseudo_csum(struct sk_buff *skb) return 0; } -static void ionic_tx_tso_post(struct ionic_queue *q, +static void ionic_tx_tso_post(struct net_device *netdev, struct ionic_queue *q, struct ionic_desc_info *desc_info, struct sk_buff *skb, dma_addr_t addr, u8 nsge, u16 len, @@ -1418,14 +1422,15 @@ static void ionic_tx_tso_post(struct ionic_queue *q, if (start) { skb_tx_timestamp(skb); if (!ionic_txq_hwstamp_enabled(q)) - netdev_tx_sent_queue(q_to_ndq(q), skb->len); + netdev_tx_sent_queue(q_to_ndq(netdev, q), skb->len); ionic_txq_post(q, false, ionic_tx_clean, skb); } else { ionic_txq_post(q, done, NULL, NULL); } } -static int ionic_tx_tso(struct ionic_queue *q, struct sk_buff *skb) +static int ionic_tx_tso(struct net_device *netdev, struct ionic_queue *q, + struct sk_buff *skb) { struct ionic_tx_stats *stats = q_to_tx_stats(q); struct ionic_desc_info *desc_info; @@ -1533,7 +1538,7 @@ static int ionic_tx_tso(struct ionic_queue *q, struct sk_buff *skb) seg_rem = min(tso_rem, mss); done = (tso_rem == 0); /* post descriptor */ - ionic_tx_tso_post(q, desc_info, skb, + ionic_tx_tso_post(netdev, q, desc_info, skb, desc_addr, desc_nsge, desc_len, hdrlen, mss, outer_csum, vlan_tci, has_vlan, start, done); @@ -1643,7 +1648,8 @@ static void ionic_tx_skb_frags(struct ionic_queue *q, struct sk_buff *skb, stats->frags += skb_shinfo(skb)->nr_frags; } -static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb) +static int ionic_tx(struct net_device *netdev, struct ionic_queue *q, + struct sk_buff *skb) { struct ionic_desc_info *desc_info = &q->info[q->head_idx]; struct ionic_tx_stats *stats = q_to_tx_stats(q); @@ -1666,7 +1672,7 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb) stats->bytes += skb->len; if (!ionic_txq_hwstamp_enabled(q)) { - struct netdev_queue *ndq = q_to_ndq(q); + struct netdev_queue *ndq = q_to_ndq(netdev, q); if (unlikely(!ionic_q_has_space(q, MAX_SKB_FRAGS + 1))) netif_tx_stop_queue(ndq); @@ -1789,9 +1795,9 @@ static netdev_tx_t ionic_start_hwstamp_xmit(struct sk_buff *skb, skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP; if (skb_is_gso(skb)) - err = ionic_tx_tso(q, skb); + err = ionic_tx_tso(netdev, q, skb); else - err = ionic_tx(q, skb); + err = ionic_tx(netdev, q, skb); if (err) goto err_out_drop; @@ -1829,15 +1835,15 @@ netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (ndescs < 0) goto err_out_drop; - if (!netif_txq_maybe_stop(q_to_ndq(q), + if (!netif_txq_maybe_stop(q_to_ndq(netdev, q), ionic_q_space_avail(q), ndescs, ndescs)) return NETDEV_TX_BUSY; if (skb_is_gso(skb)) - err = ionic_tx_tso(q, skb); + err = ionic_tx_tso(netdev, q, skb); else - err = ionic_tx(q, skb); + err = ionic_tx(netdev, q, skb); if (err) goto err_out_drop; From 25623ab9cb372b778a211601a1fb5e3bb72c827d Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 29 Feb 2024 11:39:31 -0800 Subject: [PATCH 1728/2255] ionic: reduce the use of netdev To help make sure we're only accessing things we really need to access we can cut down on the q->lif->netdev references by using q->dev which is already in cache. Reviewed-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_txrx.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index f217b9875f1b..ed095696f67a 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -123,7 +123,6 @@ static unsigned int ionic_rx_buf_size(struct ionic_buf_info *buf_info) static int ionic_rx_page_alloc(struct ionic_queue *q, struct ionic_buf_info *buf_info) { - struct net_device *netdev = q->lif->netdev; struct ionic_rx_stats *stats; struct device *dev; struct page *page; @@ -133,14 +132,14 @@ static int ionic_rx_page_alloc(struct ionic_queue *q, if (unlikely(!buf_info)) { net_err_ratelimited("%s: %s invalid buf_info in alloc\n", - netdev->name, q->name); + dev_name(dev), q->name); return -EINVAL; } page = alloc_pages(IONIC_PAGE_GFP_MASK, 0); if (unlikely(!page)) { net_err_ratelimited("%s: %s page alloc failed\n", - netdev->name, q->name); + dev_name(dev), q->name); stats->alloc_err++; return -ENOMEM; } @@ -150,7 +149,7 @@ static int ionic_rx_page_alloc(struct ionic_queue *q, if (unlikely(dma_mapping_error(dev, buf_info->dma_addr))) { __free_pages(page, 0); net_err_ratelimited("%s: %s dma map failed\n", - netdev->name, q->name); + dev_name(dev), q->name); stats->dma_map_err++; return -EIO; } @@ -164,12 +163,11 @@ static int ionic_rx_page_alloc(struct ionic_queue *q, static void ionic_rx_page_free(struct ionic_queue *q, struct ionic_buf_info *buf_info) { - struct net_device *netdev = q->lif->netdev; struct device *dev = q->dev; if (unlikely(!buf_info)) { net_err_ratelimited("%s: %s invalid buf_info in free\n", - netdev->name, q->name); + dev_name(dev), q->name); return; } @@ -228,7 +226,7 @@ static struct sk_buff *ionic_rx_frags(struct net_device *netdev, skb = napi_get_frags(&q_to_qcq(q)->napi); if (unlikely(!skb)) { net_warn_ratelimited("%s: SKB alloc failed on %s!\n", - netdev->name, q->name); + dev_name(dev), q->name); stats->alloc_err++; return NULL; } @@ -291,7 +289,7 @@ static struct sk_buff *ionic_rx_copybreak(struct net_device *netdev, skb = napi_alloc_skb(&q_to_qcq(q)->napi, len); if (unlikely(!skb)) { net_warn_ratelimited("%s: SKB alloc failed on %s!\n", - netdev->name, q->name); + dev_name(dev), q->name); stats->alloc_err++; return NULL; } @@ -1086,7 +1084,7 @@ static dma_addr_t ionic_tx_map_single(struct ionic_queue *q, dma_addr = dma_map_single(dev, data, len, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma_addr)) { net_warn_ratelimited("%s: DMA single map failed on %s!\n", - q->lif->netdev->name, q->name); + dev_name(dev), q->name); stats->dma_map_err++; return 0; } @@ -1104,7 +1102,7 @@ static dma_addr_t ionic_tx_map_frag(struct ionic_queue *q, dma_addr = skb_frag_dma_map(dev, frag, offset, len, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma_addr)) { net_warn_ratelimited("%s: DMA frag map failed on %s!\n", - q->lif->netdev->name, q->name); + dev_name(dev), q->name); stats->dma_map_err++; } return dma_addr; From b889bfe5bd0c278730f92e87a8996aa6ec6d9f09 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:32 -0800 Subject: [PATCH 1729/2255] ionic: change the hwstamp likely check An earlier change moved the hwstamp queue check into a helper function with an unlikely(). However, it makes more sense for the caller to decide if it's likely() or unlikely(), so make the change to support that. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_lif.h | 2 +- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 42006de8069d..b4f8692a3ead 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -327,7 +327,7 @@ static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs) static inline bool ionic_txq_hwstamp_enabled(struct ionic_queue *q) { - return unlikely(q->features & IONIC_TXQ_F_HWSTAMP); + return q->features & IONIC_TXQ_F_HWSTAMP; } void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index ed095696f67a..89a40657c689 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -1201,7 +1201,7 @@ static void ionic_tx_clean(struct ionic_queue *q, if (!skb) return; - if (ionic_txq_hwstamp_enabled(q)) { + if (unlikely(ionic_txq_hwstamp_enabled(q))) { if (cq_info) { struct skb_shared_hwtstamps hwts = {}; __le64 *cq_desc_hwstamp; @@ -1296,7 +1296,7 @@ unsigned int ionic_tx_cq_service(struct ionic_cq *cq, unsigned int work_to_do) if (work_done) { struct ionic_queue *q = cq->bound_q; - if (!ionic_txq_hwstamp_enabled(q)) + if (likely(!ionic_txq_hwstamp_enabled(q))) netif_txq_completed_wake(q_to_ndq(q->lif->netdev, q), pkts, bytes, ionic_q_space_avail(q), @@ -1337,7 +1337,7 @@ void ionic_tx_empty(struct ionic_queue *q) desc_info->cb_arg = NULL; } - if (!ionic_txq_hwstamp_enabled(q)) { + if (likely(!ionic_txq_hwstamp_enabled(q))) { struct netdev_queue *ndq = q_to_ndq(q->lif->netdev, q); netdev_tx_completed_queue(ndq, pkts, bytes); @@ -1419,7 +1419,7 @@ static void ionic_tx_tso_post(struct net_device *netdev, struct ionic_queue *q, if (start) { skb_tx_timestamp(skb); - if (!ionic_txq_hwstamp_enabled(q)) + if (likely(!ionic_txq_hwstamp_enabled(q))) netdev_tx_sent_queue(q_to_ndq(netdev, q), skb->len); ionic_txq_post(q, false, ionic_tx_clean, skb); } else { @@ -1669,7 +1669,7 @@ static int ionic_tx(struct net_device *netdev, struct ionic_queue *q, stats->pkts++; stats->bytes += skb->len; - if (!ionic_txq_hwstamp_enabled(q)) { + if (likely(!ionic_txq_hwstamp_enabled(q))) { struct netdev_queue *ndq = q_to_ndq(netdev, q); if (unlikely(!ionic_q_has_space(q, MAX_SKB_FRAGS + 1))) From 8aacc71399be59bec8fc4b49da64440658f8210f Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:33 -0800 Subject: [PATCH 1730/2255] ionic: Use CQE profile for dim Use the kernel's CQE dim table to align better with the driver's use of completion queues, and use the tx moderation when using Tx interrupts. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 4271ebb0ddc0..33b1691a4ee5 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -52,15 +52,20 @@ static void ionic_xdp_unregister_rxq_info(struct ionic_queue *q); static void ionic_dim_work(struct work_struct *work) { struct dim *dim = container_of(work, struct dim, work); - struct ionic_intr_info *intr; struct dim_cq_moder cur_moder; + struct ionic_intr_info *intr; struct ionic_qcq *qcq; struct ionic_lif *lif; + struct ionic_queue *q; u32 new_coal; - cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix); qcq = container_of(dim, struct ionic_qcq, dim); - lif = qcq->q.lif; + q = &qcq->q; + if (q->type == IONIC_QTYPE_RXQ) + cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix); + else + cur_moder = net_dim_get_tx_moderation(dim->mode, dim->profile_ix); + lif = q->lif; new_coal = ionic_coal_usec_to_hw(lif->ionic, cur_moder.usec); new_coal = new_coal ? new_coal : 1; @@ -685,7 +690,7 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, } INIT_WORK(&new->dim.work, ionic_dim_work); - new->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; + new->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE; *qcq = new; From bc40b88930bfb6d5464f8113a5feb6d72b423ffb Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 29 Feb 2024 11:39:34 -0800 Subject: [PATCH 1731/2255] ionic: Clean RCT ordering issues Clean up complaints from an xmastree.py scan. Signed-off-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_debugfs.c | 2 +- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c index 91327ef670c7..c3ae11a48024 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c @@ -113,8 +113,8 @@ static const struct debugfs_reg32 intr_ctrl_regs[] = { void ionic_debugfs_add_qcq(struct ionic_lif *lif, struct ionic_qcq *qcq) { struct dentry *qcq_dentry, *q_dentry, *cq_dentry; - struct dentry *intr_dentry, *stats_dentry; struct ionic_dev *idev = &lif->ionic->idev; + struct dentry *intr_dentry, *stats_dentry; struct debugfs_regset32 *intr_ctrl_regset; struct ionic_intr_info *intr = &qcq->intr; struct debugfs_blob_wrapper *desc_blob; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 89a40657c689..6d168ad8c84f 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -40,8 +40,8 @@ static inline void ionic_rxq_post(struct ionic_queue *q, bool ring_dbell, bool ionic_txq_poke_doorbell(struct ionic_queue *q) { - unsigned long now, then, dif; struct netdev_queue *netdev_txq; + unsigned long now, then, dif; struct net_device *netdev; netdev = q->lif->netdev; @@ -1776,7 +1776,7 @@ static netdev_tx_t ionic_start_hwstamp_xmit(struct sk_buff *skb, struct net_device *netdev) { struct ionic_lif *lif = netdev_priv(netdev); - struct ionic_queue *q = &lif->hwstamp_txq->q; + struct ionic_queue *q; int err, ndescs; /* Does not stop/start txq, because we post to a separate tx queue @@ -1784,6 +1784,7 @@ static netdev_tx_t ionic_start_hwstamp_xmit(struct sk_buff *skb, * the timestamping queue, it is dropped. */ + q = &lif->hwstamp_txq->q; ndescs = ionic_tx_descs_needed(q, skb); if (unlikely(ndescs < 0)) goto err_out_drop; From 217397da4d522e88c4f3e25701390d36dd8e874a Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 29 Feb 2024 11:39:35 -0800 Subject: [PATCH 1732/2255] ionic: change MODULE_AUTHOR to person name The MODULE_AUTHOR macro is supposed to be a person not a company. Reviewed-by: Brett Creeley Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index 2f479de329fe..29b4d039bbce 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -15,7 +15,7 @@ #include "ionic_debugfs.h" MODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION); -MODULE_AUTHOR("Pensando Systems, Inc"); +MODULE_AUTHOR("Shannon Nelson "); MODULE_LICENSE("GPL"); static const char *ionic_error_to_str(enum ionic_status_code code) From 6752fb18dc5763e9d6efe5aebf03e4fc69e6086b Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 28 Feb 2024 10:03:17 -0800 Subject: [PATCH 1733/2255] net: ip6_tunnel: Leverage core stats allocator With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of in this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the ip6_tunnel driver and leverage the network core allocation instead. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 5fd07581efaf..e9cc315832cb 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -247,7 +247,6 @@ static void ip6_dev_free(struct net_device *dev) gro_cells_destroy(&t->gro_cells); dst_cache_destroy(&t->dst_cache); - free_percpu(dev->tstats); } static int ip6_tnl_create2(struct net_device *dev) @@ -1848,6 +1847,7 @@ static void ip6_tnl_dev_setup(struct net_device *dev) dev->flags |= IFF_NOARP; dev->addr_len = sizeof(struct in6_addr); dev->features |= NETIF_F_LLTX; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; netif_keep_dst(dev); dev->features |= IPXIPX_FEATURES; @@ -1873,13 +1873,10 @@ ip6_tnl_dev_init_gen(struct net_device *dev) t->dev = dev; t->net = dev_net(dev); - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; ret = dst_cache_init(&t->dst_cache, GFP_KERNEL); if (ret) - goto free_stats; + return ret; ret = gro_cells_init(&t->gro_cells, dev); if (ret) @@ -1903,9 +1900,6 @@ ip6_tnl_dev_init_gen(struct net_device *dev) destroy_dst: dst_cache_destroy(&t->dst_cache); -free_stats: - free_percpu(dev->tstats); - dev->tstats = NULL; return ret; } From 0b43cf527d1d6b75597b0f6c40a60a8b67837afe Mon Sep 17 00:00:00 2001 From: Jeroen de Borst Date: Thu, 29 Feb 2024 13:22:34 -0800 Subject: [PATCH 1734/2255] gve: Add header split device option To enable header split via ethtool, we first need to query the device to get the max rx buffer size and header buffer size. Add a device option to get these values and store them in the driver. If the header buffer size received from the device is non-zero, it means header split is supported in the device. Currently the max rx buffer size will only be used when header split is enabled which will set the data_buffer_size_dqo to be the max rx buffer size. Also change the data_buffer_size_dqo from int to u16 since we are modifying it and making it to be consistent with max_rx_buffer_size. Co-developed-by: Ziwei Xiao Signed-off-by: Ziwei Xiao Signed-off-by: Jeroen de Borst Reviewed-by: Praveen Kaligineedi Reviewed-by: Harshitha Ramamurthy Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- drivers/net/ethernet/google/gve/gve.h | 9 +++- drivers/net/ethernet/google/gve/gve_adminq.c | 47 +++++++++++++++++--- drivers/net/ethernet/google/gve/gve_adminq.h | 20 ++++++++- drivers/net/ethernet/google/gve/gve_main.c | 8 +--- drivers/net/ethernet/google/gve/gve_rx_dqo.c | 2 +- 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index fd290f3ad6ec..5305404516fc 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -51,12 +51,16 @@ #define GVE_DEFAULT_RX_BUFFER_SIZE 2048 +#define GVE_MAX_RX_BUFFER_SIZE 4096 + #define GVE_DEFAULT_RX_BUFFER_OFFSET 2048 #define GVE_XDP_ACTIONS 5 #define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182 +#define GVE_DEFAULT_HEADER_BUFFER_SIZE 128 + #define DQO_QPL_DEFAULT_TX_PAGES 512 #define DQO_QPL_DEFAULT_RX_PAGES 2048 @@ -778,13 +782,16 @@ struct gve_priv { struct gve_ptype_lut *ptype_lut_dqo; /* Must be a power of two. */ - int data_buffer_size_dqo; + u16 data_buffer_size_dqo; + u16 max_rx_buffer_size; /* device limit */ enum gve_queue_format queue_format; /* Interrupt coalescing settings */ u32 tx_coalesce_usecs; u32 rx_coalesce_usecs; + + u16 header_buf_size; /* device configured, header-split supported if non-zero */ }; enum gve_service_task_flags_bit { diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index 12fbd723ecc6..e2c27bbb56e6 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -40,7 +40,8 @@ void gve_parse_device_option(struct gve_priv *priv, struct gve_device_option_gqi_qpl **dev_op_gqi_qpl, struct gve_device_option_dqo_rda **dev_op_dqo_rda, struct gve_device_option_jumbo_frames **dev_op_jumbo_frames, - struct gve_device_option_dqo_qpl **dev_op_dqo_qpl) + struct gve_device_option_dqo_qpl **dev_op_dqo_qpl, + struct gve_device_option_buffer_sizes **dev_op_buffer_sizes) { u32 req_feat_mask = be32_to_cpu(option->required_features_mask); u16 option_length = be16_to_cpu(option->option_length); @@ -147,6 +148,23 @@ void gve_parse_device_option(struct gve_priv *priv, } *dev_op_jumbo_frames = (void *)(option + 1); break; + case GVE_DEV_OPT_ID_BUFFER_SIZES: + if (option_length < sizeof(**dev_op_buffer_sizes) || + req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_BUFFER_SIZES) { + dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT, + "Buffer Sizes", + (int)sizeof(**dev_op_buffer_sizes), + GVE_DEV_OPT_REQ_FEAT_MASK_BUFFER_SIZES, + option_length, req_feat_mask); + break; + } + + if (option_length > sizeof(**dev_op_buffer_sizes)) + dev_warn(&priv->pdev->dev, + GVE_DEVICE_OPTION_TOO_BIG_FMT, + "Buffer Sizes"); + *dev_op_buffer_sizes = (void *)(option + 1); + break; default: /* If we don't recognize the option just continue * without doing anything. @@ -164,7 +182,8 @@ gve_process_device_options(struct gve_priv *priv, struct gve_device_option_gqi_qpl **dev_op_gqi_qpl, struct gve_device_option_dqo_rda **dev_op_dqo_rda, struct gve_device_option_jumbo_frames **dev_op_jumbo_frames, - struct gve_device_option_dqo_qpl **dev_op_dqo_qpl) + struct gve_device_option_dqo_qpl **dev_op_dqo_qpl, + struct gve_device_option_buffer_sizes **dev_op_buffer_sizes) { const int num_options = be16_to_cpu(descriptor->num_device_options); struct gve_device_option *dev_opt; @@ -185,7 +204,7 @@ gve_process_device_options(struct gve_priv *priv, gve_parse_device_option(priv, descriptor, dev_opt, dev_op_gqi_rda, dev_op_gqi_qpl, dev_op_dqo_rda, dev_op_jumbo_frames, - dev_op_dqo_qpl); + dev_op_dqo_qpl, dev_op_buffer_sizes); dev_opt = next_opt; } @@ -755,7 +774,9 @@ static void gve_enable_supported_features(struct gve_priv *priv, const struct gve_device_option_jumbo_frames *dev_op_jumbo_frames, const struct gve_device_option_dqo_qpl - *dev_op_dqo_qpl) + *dev_op_dqo_qpl, + const struct gve_device_option_buffer_sizes + *dev_op_buffer_sizes) { /* Before control reaches this point, the page-size-capped max MTU from * the gve_device_descriptor field has already been stored in @@ -779,10 +800,22 @@ static void gve_enable_supported_features(struct gve_priv *priv, if (priv->rx_pages_per_qpl == 0) priv->rx_pages_per_qpl = DQO_QPL_DEFAULT_RX_PAGES; } + + if (dev_op_buffer_sizes && + (supported_features_mask & GVE_SUP_BUFFER_SIZES_MASK)) { + priv->max_rx_buffer_size = + be16_to_cpu(dev_op_buffer_sizes->packet_buffer_size); + priv->header_buf_size = + be16_to_cpu(dev_op_buffer_sizes->header_buffer_size); + dev_info(&priv->pdev->dev, + "BUFFER SIZES device option enabled with max_rx_buffer_size of %u, header_buf_size of %u.\n", + priv->max_rx_buffer_size, priv->header_buf_size); + } } int gve_adminq_describe_device(struct gve_priv *priv) { + struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = NULL; struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL; struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL; struct gve_device_option_gqi_qpl *dev_op_gqi_qpl = NULL; @@ -816,7 +849,8 @@ int gve_adminq_describe_device(struct gve_priv *priv) err = gve_process_device_options(priv, descriptor, &dev_op_gqi_rda, &dev_op_gqi_qpl, &dev_op_dqo_rda, &dev_op_jumbo_frames, - &dev_op_dqo_qpl); + &dev_op_dqo_qpl, + &dev_op_buffer_sizes); if (err) goto free_device_descriptor; @@ -885,7 +919,8 @@ int gve_adminq_describe_device(struct gve_priv *priv) priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues); gve_enable_supported_features(priv, supported_features_mask, - dev_op_jumbo_frames, dev_op_dqo_qpl); + dev_op_jumbo_frames, dev_op_dqo_qpl, + dev_op_buffer_sizes); free_device_descriptor: dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus); diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h index 5865ccdccbd0..5ac972e45ff8 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.h +++ b/drivers/net/ethernet/google/gve/gve_adminq.h @@ -125,6 +125,15 @@ struct gve_device_option_jumbo_frames { static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8); +struct gve_device_option_buffer_sizes { + /* GVE_SUP_BUFFER_SIZES_MASK bit should be set */ + __be32 supported_features_mask; + __be16 packet_buffer_size; + __be16 header_buffer_size; +}; + +static_assert(sizeof(struct gve_device_option_buffer_sizes) == 8); + /* Terminology: * * RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA @@ -140,6 +149,7 @@ enum gve_dev_opt_id { GVE_DEV_OPT_ID_DQO_RDA = 0x4, GVE_DEV_OPT_ID_DQO_QPL = 0x7, GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8, + GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa, }; enum gve_dev_opt_req_feat_mask { @@ -149,10 +159,12 @@ enum gve_dev_opt_req_feat_mask { GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0, GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES = 0x0, GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL = 0x0, + GVE_DEV_OPT_REQ_FEAT_MASK_BUFFER_SIZES = 0x0, }; enum gve_sup_feature_mask { GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2, + GVE_SUP_BUFFER_SIZES_MASK = 1 << 4, }; #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0 @@ -165,6 +177,7 @@ enum gve_driver_capbility { gve_driver_capability_dqo_qpl = 2, /* reserved for future use */ gve_driver_capability_dqo_rda = 3, gve_driver_capability_alt_miss_compl = 4, + gve_driver_capability_flexible_buffer_size = 5, }; #define GVE_CAP1(a) BIT((int)a) @@ -176,7 +189,8 @@ enum gve_driver_capbility { (GVE_CAP1(gve_driver_capability_gqi_qpl) | \ GVE_CAP1(gve_driver_capability_gqi_rda) | \ GVE_CAP1(gve_driver_capability_dqo_rda) | \ - GVE_CAP1(gve_driver_capability_alt_miss_compl)) + GVE_CAP1(gve_driver_capability_alt_miss_compl) | \ + GVE_CAP1(gve_driver_capability_flexible_buffer_size)) #define GVE_DRIVER_CAPABILITY_FLAGS2 0x0 #define GVE_DRIVER_CAPABILITY_FLAGS3 0x0 @@ -260,7 +274,9 @@ struct gve_adminq_create_rx_queue { __be16 packet_buffer_size; __be16 rx_buff_ring_size; u8 enable_rsc; - u8 padding[5]; + u8 padding1; + __be16 header_buffer_size; + u8 padding2[2]; }; static_assert(sizeof(struct gve_adminq_create_rx_queue) == 56); diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index db6d9ae7cd78..02d12aa50885 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -1448,12 +1448,6 @@ static int gve_queues_start(struct gve_priv *priv, if (err) goto reset; - if (!gve_is_gqi(priv)) { - /* Hard code this for now. This may be tuned in the future for - * performance. - */ - priv->data_buffer_size_dqo = GVE_DEFAULT_RX_BUFFER_SIZE; - } err = gve_create_rings(priv); if (err) goto reset; @@ -2511,6 +2505,8 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->service_task_flags = 0x0; priv->state_flags = 0x0; priv->ethtool_flags = 0x0; + priv->data_buffer_size_dqo = GVE_DEFAULT_RX_BUFFER_SIZE; + priv->max_rx_buffer_size = GVE_DEFAULT_RX_BUFFER_SIZE; gve_set_probe_in_progress(priv); priv->gve_wq = alloc_ordered_workqueue("gve", 0); diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index 8e6aeb5b3ed4..c3ce819ee5ab 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -458,7 +458,7 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) static void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx, struct gve_rx_buf_state_dqo *buf_state) { - const int data_buffer_size = priv->data_buffer_size_dqo; + const u16 data_buffer_size = priv->data_buffer_size_dqo; int pagecount; /* Can't reuse if we only fit one buffer per page */ From 5e37d8254e7f551dda62e7590e819d69c7491845 Mon Sep 17 00:00:00 2001 From: Jeroen de Borst Date: Thu, 29 Feb 2024 13:22:35 -0800 Subject: [PATCH 1735/2255] gve: Add header split data path Add header buffers and ethtool support to enable header split via the tcp-data-split flag in ethtool's ringparam config. A coherent dma memory is allocated for the header buffers. There is one header buffer per ring entry by calculating the offset to the header-buffers starting address. The header buffer is always copied directly into the skb and payload is always added as frags. When there is a header buffer overflow or the header length is 0, the driver places the whole unsplit packet in frags. When toggling header split, the driver will call gve_adjust_config to set its queues appropriately. If header split is enabled by the user and the max packet buffer size is no less than 4KB, driver will set the packet buffer size as 4KB to support TCP_ZEROCOPY_RECEIVE. Otherwise the driver will use the default 2KB as the packet buffer size. `ethtool -G tcp-data-split on/off` is the command to toggle header split. `ethtool -g ` will show the status of header split with the field of `tcp-data-split`. Co-developed-by: Ziwei Xiao Signed-off-by: Ziwei Xiao Signed-off-by: Jeroen de Borst Reviewed-by: Praveen Kaligineedi Reviewed-by: Harshitha Ramamurthy Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- drivers/net/ethernet/google/gve/gve.h | 14 +++++ drivers/net/ethernet/google/gve/gve_adminq.c | 3 + drivers/net/ethernet/google/gve/gve_ethtool.c | 26 ++++++++- drivers/net/ethernet/google/gve/gve_main.c | 57 +++++++++++++++++++ drivers/net/ethernet/google/gve/gve_rx_dqo.c | 57 ++++++++++++++++++- drivers/net/ethernet/google/gve/gve_utils.c | 17 ++++-- drivers/net/ethernet/google/gve/gve_utils.h | 3 + 7 files changed, 169 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index 5305404516fc..5f02b87d7fea 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -154,6 +155,11 @@ struct gve_rx_compl_queue_dqo { u32 mask; /* Mask for indices to the size of the ring */ }; +struct gve_header_buf { + u8 *data; + dma_addr_t addr; +}; + /* Stores state for tracking buffers posted to HW */ struct gve_rx_buf_state_dqo { /* The page posted to HW. */ @@ -256,6 +262,9 @@ struct gve_rx_ring { /* track number of used buffers */ u16 used_buf_states_cnt; + + /* Address info of the buffers for header-split */ + struct gve_header_buf hdr_bufs; } dqo; }; @@ -668,6 +677,7 @@ struct gve_rx_alloc_rings_cfg { struct gve_qpl_config *qpl_cfg; u16 ring_size; + u16 packet_buffer_size; bool raw_addressing; bool enable_header_split; @@ -792,6 +802,7 @@ struct gve_priv { u32 rx_coalesce_usecs; u16 header_buf_size; /* device configured, header-split supported if non-zero */ + bool header_split_enabled; /* True if the header split is enabled by the user */ }; enum gve_service_task_flags_bit { @@ -1129,6 +1140,9 @@ void gve_rx_free_rings_gqi(struct gve_priv *priv, struct gve_rx_alloc_rings_cfg *cfg); void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx); void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx); +u16 gve_get_pkt_buf_size(const struct gve_priv *priv, bool enable_hplit); +bool gve_header_split_supported(const struct gve_priv *priv); +int gve_set_hsplit_config(struct gve_priv *priv, u8 tcp_data_split); /* Reset */ void gve_schedule_reset(struct gve_priv *priv); int gve_reset(struct gve_priv *priv, bool attempt_teardown); diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index e2c27bbb56e6..ae12ac38e18b 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -659,6 +659,9 @@ static int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_index) cpu_to_be16(rx_buff_ring_entries); cmd.create_rx_queue.enable_rsc = !!(priv->dev->features & NETIF_F_LRO); + if (priv->header_split_enabled) + cmd.create_rx_queue.header_buffer_size = + cpu_to_be16(priv->header_buf_size); } return gve_adminq_issue_cmd(priv, &cmd); diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c index e5397aa1e48f..13c2901968e0 100644 --- a/drivers/net/ethernet/google/gve/gve_ethtool.c +++ b/drivers/net/ethernet/google/gve/gve_ethtool.c @@ -4,7 +4,6 @@ * Copyright (C) 2015-2021 Google, Inc. */ -#include #include #include "gve.h" #include "gve_adminq.h" @@ -480,6 +479,29 @@ static void gve_get_ringparam(struct net_device *netdev, cmd->tx_max_pending = priv->tx_desc_cnt; cmd->rx_pending = priv->rx_desc_cnt; cmd->tx_pending = priv->tx_desc_cnt; + + if (!gve_header_split_supported(priv)) + kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_UNKNOWN; + else if (priv->header_split_enabled) + kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED; + else + kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED; +} + +static int gve_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *cmd, + struct kernel_ethtool_ringparam *kernel_cmd, + struct netlink_ext_ack *extack) +{ + struct gve_priv *priv = netdev_priv(netdev); + + if (priv->tx_desc_cnt != cmd->tx_pending || + priv->rx_desc_cnt != cmd->rx_pending) { + dev_info(&priv->pdev->dev, "Modify ring size is not supported.\n"); + return -EOPNOTSUPP; + } + + return gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split); } static int gve_user_reset(struct net_device *netdev, u32 *flags) @@ -655,6 +677,7 @@ static int gve_set_coalesce(struct net_device *netdev, const struct ethtool_ops gve_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS, + .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT, .get_drvinfo = gve_get_drvinfo, .get_strings = gve_get_strings, .get_sset_count = gve_get_sset_count, @@ -667,6 +690,7 @@ const struct ethtool_ops gve_ethtool_ops = { .get_coalesce = gve_get_coalesce, .set_coalesce = gve_set_coalesce, .get_ringparam = gve_get_ringparam, + .set_ringparam = gve_set_ringparam, .reset = gve_user_reset, .get_tunable = gve_get_tunable, .set_tunable = gve_set_tunable, diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 02d12aa50885..7b89b66adb53 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -1307,9 +1307,13 @@ static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv, cfg->qcfg = &priv->rx_cfg; cfg->qcfg_tx = &priv->tx_cfg; cfg->raw_addressing = !gve_is_qpl(priv); + cfg->enable_header_split = priv->header_split_enabled; cfg->qpls = priv->qpls; cfg->qpl_cfg = &priv->qpl_cfg; cfg->ring_size = priv->rx_desc_cnt; + cfg->packet_buffer_size = gve_is_gqi(priv) ? + GVE_DEFAULT_RX_BUFFER_SIZE : + priv->data_buffer_size_dqo; cfg->rx = priv->rx; } @@ -1448,6 +1452,9 @@ static int gve_queues_start(struct gve_priv *priv, if (err) goto reset; + priv->header_split_enabled = rx_alloc_cfg->enable_header_split; + priv->data_buffer_size_dqo = rx_alloc_cfg->packet_buffer_size; + err = gve_create_rings(priv); if (err) goto reset; @@ -2059,6 +2066,56 @@ out: priv->tx_timeo_cnt++; } +u16 gve_get_pkt_buf_size(const struct gve_priv *priv, bool enable_hsplit) +{ + if (enable_hsplit && priv->max_rx_buffer_size >= GVE_MAX_RX_BUFFER_SIZE) + return GVE_MAX_RX_BUFFER_SIZE; + else + return GVE_DEFAULT_RX_BUFFER_SIZE; +} + +/* header-split is not supported on non-DQO_RDA yet even if device advertises it */ +bool gve_header_split_supported(const struct gve_priv *priv) +{ + return priv->header_buf_size && priv->queue_format == GVE_DQO_RDA_FORMAT; +} + +int gve_set_hsplit_config(struct gve_priv *priv, u8 tcp_data_split) +{ + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; + bool enable_hdr_split; + int err = 0; + + if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_UNKNOWN) + return 0; + + if (!gve_header_split_supported(priv)) { + dev_err(&priv->pdev->dev, "Header-split not supported\n"); + return -EOPNOTSUPP; + } + + if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED) + enable_hdr_split = true; + else + enable_hdr_split = false; + + if (enable_hdr_split == priv->header_split_enabled) + return 0; + + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + + rx_alloc_cfg.enable_header_split = enable_hdr_split; + rx_alloc_cfg.packet_buffer_size = gve_get_pkt_buf_size(priv, enable_hdr_split); + + if (netif_running(priv->dev)) + err = gve_adjust_config(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + return err; +} + static int gve_set_features(struct net_device *netdev, netdev_features_t features) { diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index c3ce819ee5ab..a12d776d4385 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -199,6 +199,18 @@ static int gve_alloc_page_dqo(struct gve_rx_ring *rx, return 0; } +static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) +{ + struct device *hdev = &priv->pdev->dev; + int buf_count = rx->dqo.bufq.mask + 1; + + if (rx->dqo.hdr_bufs.data) { + dma_free_coherent(hdev, priv->header_buf_size * buf_count, + rx->dqo.hdr_bufs.data, rx->dqo.hdr_bufs.addr); + rx->dqo.hdr_bufs.data = NULL; + } +} + void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx) { int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); @@ -258,9 +270,24 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, struct gve_rx_ring *rx, kvfree(rx->dqo.buf_states); rx->dqo.buf_states = NULL; + gve_rx_free_hdr_bufs(priv, rx); + netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx); } +static int gve_rx_alloc_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) +{ + struct device *hdev = &priv->pdev->dev; + int buf_count = rx->dqo.bufq.mask + 1; + + rx->dqo.hdr_bufs.data = dma_alloc_coherent(hdev, priv->header_buf_size * buf_count, + &rx->dqo.hdr_bufs.addr, GFP_KERNEL); + if (!rx->dqo.hdr_bufs.data) + return -ENOMEM; + + return 0; +} + void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx) { int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); @@ -302,6 +329,11 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, if (!rx->dqo.buf_states) return -ENOMEM; + /* Allocate header buffers for header-split */ + if (cfg->enable_header_split) + if (gve_rx_alloc_hdr_bufs(priv, rx)) + goto err; + /* Set up linked list of buffer IDs */ for (i = 0; i < rx->dqo.num_buf_states - 1; i++) rx->dqo.buf_states[i].next = i + 1; @@ -443,6 +475,10 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) desc->buf_id = cpu_to_le16(buf_state - rx->dqo.buf_states); desc->buf_addr = cpu_to_le64(buf_state->addr + buf_state->page_info.page_offset); + if (rx->dqo.hdr_bufs.data) + desc->header_buf_addr = + cpu_to_le64(rx->dqo.hdr_bufs.addr + + priv->header_buf_size * bufq->tail); bufq->tail = (bufq->tail + 1) & bufq->mask; complq->num_free_slots--; @@ -645,13 +681,16 @@ static int gve_rx_append_frags(struct napi_struct *napi, */ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, const struct gve_rx_compl_desc_dqo *compl_desc, - int queue_idx) + u32 desc_idx, int queue_idx) { const u16 buffer_id = le16_to_cpu(compl_desc->buf_id); + const bool hbo = compl_desc->header_buffer_overflow; const bool eop = compl_desc->end_of_packet != 0; + const bool hsplit = compl_desc->split_header; struct gve_rx_buf_state_dqo *buf_state; struct gve_priv *priv = rx->gve; u16 buf_len; + u16 hdr_len; if (unlikely(buffer_id >= rx->dqo.num_buf_states)) { net_err_ratelimited("%s: Invalid RX buffer_id=%u\n", @@ -672,12 +711,26 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, } buf_len = compl_desc->packet_len; + hdr_len = compl_desc->header_len; /* Page might have not been used for awhile and was likely last written * by a different thread. */ prefetch(buf_state->page_info.page); + /* Copy the header into the skb in the case of header split */ + if (hsplit) { + if (hdr_len && !hbo) { + rx->ctx.skb_head = gve_rx_copy_data(priv->dev, napi, + rx->dqo.hdr_bufs.data + + desc_idx * priv->header_buf_size, + hdr_len); + if (unlikely(!rx->ctx.skb_head)) + goto error; + rx->ctx.skb_tail = rx->ctx.skb_head; + } + } + /* Sync the portion of dma buffer for CPU to read. */ dma_sync_single_range_for_cpu(&priv->pdev->dev, buf_state->addr, buf_state->page_info.page_offset, @@ -820,7 +873,7 @@ int gve_rx_poll_dqo(struct gve_notify_block *block, int budget) /* Do not read data until we own the descriptor */ dma_rmb(); - err = gve_rx_dqo(napi, rx, compl_desc, rx->q_num); + err = gve_rx_dqo(napi, rx, compl_desc, complq->head, rx->q_num); if (err < 0) { gve_rx_free_skb(rx); u64_stats_update_begin(&rx->statss); diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index 535b1796b91d..2349750075a5 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -64,11 +64,9 @@ void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx) rx->ntfy_id = ntfy_idx; } -struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi, - struct gve_rx_slot_page_info *page_info, u16 len) +struct sk_buff *gve_rx_copy_data(struct net_device *dev, struct napi_struct *napi, + u8 *data, u16 len) { - void *va = page_info->page_address + page_info->page_offset + - page_info->pad; struct sk_buff *skb; skb = napi_alloc_skb(napi, len); @@ -76,12 +74,21 @@ struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi, return NULL; __skb_put(skb, len); - skb_copy_to_linear_data_offset(skb, 0, va, len); + skb_copy_to_linear_data_offset(skb, 0, data, len); skb->protocol = eth_type_trans(skb, dev); return skb; } +struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi, + struct gve_rx_slot_page_info *page_info, u16 len) +{ + void *va = page_info->page_address + page_info->page_offset + + page_info->pad; + + return gve_rx_copy_data(dev, napi, va, len); +} + void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info) { page_info->pagecnt_bias--; diff --git a/drivers/net/ethernet/google/gve/gve_utils.h b/drivers/net/ethernet/google/gve/gve_utils.h index 277921a629f7..bf2e9a0adb36 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.h +++ b/drivers/net/ethernet/google/gve/gve_utils.h @@ -19,6 +19,9 @@ bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx); void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx); void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx); +struct sk_buff *gve_rx_copy_data(struct net_device *dev, struct napi_struct *napi, + u8 *data, u16 len); + struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi, struct gve_rx_slot_page_info *page_info, u16 len); From 056a70924a0272718adfa37ffcfc1e1d426a0d7e Mon Sep 17 00:00:00 2001 From: Jeroen de Borst Date: Thu, 29 Feb 2024 13:22:36 -0800 Subject: [PATCH 1736/2255] gve: Add header split ethtool stats To record the stats of header split packets, three stats are added in the driver's ethtool stats. - rx_hsplit_pkt is the split packets count with header split - rx_hsplit_bytes is the received header bytes count with header split - rx_hsplit_unsplit_pkt is the unsplit packet count due to header buffer overflow or zero header length when header split is enabled Currently, it's entering the stats_update critical section more than once per packet. We have plans to avoid that in the future change to let all the stats_update happen in one place at the end of `gve_rx_poll_dqo`. Co-developed-by: Ziwei Xiao Signed-off-by: Ziwei Xiao Signed-off-by: Jeroen de Borst Reviewed-by: Praveen Kaligineedi Reviewed-by: Harshitha Ramamurthy Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- drivers/net/ethernet/google/gve/gve.h | 4 +++ drivers/net/ethernet/google/gve/gve_ethtool.c | 36 +++++++++++++------ drivers/net/ethernet/google/gve/gve_rx_dqo.c | 9 +++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index 5f02b87d7fea..4814c96d5fe7 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -269,15 +269,19 @@ struct gve_rx_ring { }; u64 rbytes; /* free-running bytes received */ + u64 rx_hsplit_bytes; /* free-running header bytes received */ u64 rpackets; /* free-running packets received */ u32 cnt; /* free-running total number of completed packets */ u32 fill_cnt; /* free-running total number of descs and buffs posted */ u32 mask; /* masks the cnt and fill_cnt to the size of the ring */ + u64 rx_hsplit_pkt; /* free-running packets with headers split */ u64 rx_copybreak_pkt; /* free-running count of copybreak packets */ u64 rx_copied_pkt; /* free-running total number of copied packets */ u64 rx_skb_alloc_fail; /* free-running count of skb alloc fails */ u64 rx_buf_alloc_fail; /* free-running count of buffer alloc fails */ u64 rx_desc_err_dropped_pkt; /* free-running count of packets dropped by descriptor error */ + /* free-running count of unsplit packets due to header buffer overflow or hdr_len is 0 */ + u64 rx_hsplit_unsplit_pkt; u64 rx_cont_packet_cnt; /* free-running multi-fragment packets received */ u64 rx_frag_flip_cnt; /* free-running count of rx segments where page_flip was used */ u64 rx_frag_copy_cnt; /* free-running count of rx segments copied */ diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c index 13c2901968e0..9aebfb843d9d 100644 --- a/drivers/net/ethernet/google/gve/gve_ethtool.c +++ b/drivers/net/ethernet/google/gve/gve_ethtool.c @@ -39,17 +39,18 @@ static u32 gve_get_msglevel(struct net_device *netdev) * as declared in enum xdp_action inside file uapi/linux/bpf.h . */ static const char gve_gstrings_main_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", - "rx_dropped", "tx_dropped", "tx_timeouts", + "rx_packets", "rx_hsplit_pkt", "tx_packets", "rx_bytes", + "tx_bytes", "rx_dropped", "tx_dropped", "tx_timeouts", "rx_skb_alloc_fail", "rx_buf_alloc_fail", "rx_desc_err_dropped_pkt", + "rx_hsplit_unsplit_pkt", "interface_up_cnt", "interface_down_cnt", "reset_cnt", "page_alloc_fail", "dma_mapping_error", "stats_report_trigger_cnt", }; static const char gve_gstrings_rx_stats[][ETH_GSTRING_LEN] = { - "rx_posted_desc[%u]", "rx_completed_desc[%u]", "rx_consumed_desc[%u]", "rx_bytes[%u]", - "rx_cont_packet_cnt[%u]", "rx_frag_flip_cnt[%u]", "rx_frag_copy_cnt[%u]", - "rx_frag_alloc_cnt[%u]", + "rx_posted_desc[%u]", "rx_completed_desc[%u]", "rx_consumed_desc[%u]", + "rx_bytes[%u]", "rx_hsplit_bytes[%u]", "rx_cont_packet_cnt[%u]", + "rx_frag_flip_cnt[%u]", "rx_frag_copy_cnt[%u]", "rx_frag_alloc_cnt[%u]", "rx_dropped_pkt[%u]", "rx_copybreak_pkt[%u]", "rx_copied_pkt[%u]", "rx_queue_drop_cnt[%u]", "rx_no_buffers_posted[%u]", "rx_drops_packet_over_mru[%u]", "rx_drops_invalid_checksum[%u]", @@ -153,11 +154,13 @@ static void gve_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { - u64 tmp_rx_pkts, tmp_rx_bytes, tmp_rx_skb_alloc_fail, - tmp_rx_buf_alloc_fail, tmp_rx_desc_err_dropped_pkt, + u64 tmp_rx_pkts, tmp_rx_hsplit_pkt, tmp_rx_bytes, tmp_rx_hsplit_bytes, + tmp_rx_skb_alloc_fail, tmp_rx_buf_alloc_fail, + tmp_rx_desc_err_dropped_pkt, tmp_rx_hsplit_unsplit_pkt, tmp_tx_pkts, tmp_tx_bytes; - u64 rx_buf_alloc_fail, rx_desc_err_dropped_pkt, rx_pkts, - rx_skb_alloc_fail, rx_bytes, tx_pkts, tx_bytes, tx_dropped; + u64 rx_buf_alloc_fail, rx_desc_err_dropped_pkt, rx_hsplit_unsplit_pkt, + rx_pkts, rx_hsplit_pkt, rx_skb_alloc_fail, rx_bytes, tx_pkts, tx_bytes, + tx_dropped; int stats_idx, base_stats_idx, max_stats_idx; struct stats *report_stats; int *rx_qid_to_stats_idx; @@ -184,8 +187,10 @@ gve_get_ethtool_stats(struct net_device *netdev, kfree(rx_qid_to_stats_idx); return; } - for (rx_pkts = 0, rx_bytes = 0, rx_skb_alloc_fail = 0, - rx_buf_alloc_fail = 0, rx_desc_err_dropped_pkt = 0, ring = 0; + for (rx_pkts = 0, rx_bytes = 0, rx_hsplit_pkt = 0, + rx_skb_alloc_fail = 0, rx_buf_alloc_fail = 0, + rx_desc_err_dropped_pkt = 0, rx_hsplit_unsplit_pkt = 0, + ring = 0; ring < priv->rx_cfg.num_queues; ring++) { if (priv->rx) { do { @@ -194,18 +199,23 @@ gve_get_ethtool_stats(struct net_device *netdev, start = u64_stats_fetch_begin(&priv->rx[ring].statss); tmp_rx_pkts = rx->rpackets; + tmp_rx_hsplit_pkt = rx->rx_hsplit_pkt; tmp_rx_bytes = rx->rbytes; tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; tmp_rx_desc_err_dropped_pkt = rx->rx_desc_err_dropped_pkt; + tmp_rx_hsplit_unsplit_pkt = + rx->rx_hsplit_unsplit_pkt; } while (u64_stats_fetch_retry(&priv->rx[ring].statss, start)); rx_pkts += tmp_rx_pkts; + rx_hsplit_pkt += tmp_rx_hsplit_pkt; rx_bytes += tmp_rx_bytes; rx_skb_alloc_fail += tmp_rx_skb_alloc_fail; rx_buf_alloc_fail += tmp_rx_buf_alloc_fail; rx_desc_err_dropped_pkt += tmp_rx_desc_err_dropped_pkt; + rx_hsplit_unsplit_pkt += tmp_rx_hsplit_unsplit_pkt; } } for (tx_pkts = 0, tx_bytes = 0, tx_dropped = 0, ring = 0; @@ -226,6 +236,7 @@ gve_get_ethtool_stats(struct net_device *netdev, i = 0; data[i++] = rx_pkts; + data[i++] = rx_hsplit_pkt; data[i++] = tx_pkts; data[i++] = rx_bytes; data[i++] = tx_bytes; @@ -237,6 +248,7 @@ gve_get_ethtool_stats(struct net_device *netdev, data[i++] = rx_skb_alloc_fail; data[i++] = rx_buf_alloc_fail; data[i++] = rx_desc_err_dropped_pkt; + data[i++] = rx_hsplit_unsplit_pkt; data[i++] = priv->interface_up_cnt; data[i++] = priv->interface_down_cnt; data[i++] = priv->reset_cnt; @@ -276,6 +288,7 @@ gve_get_ethtool_stats(struct net_device *netdev, start = u64_stats_fetch_begin(&priv->rx[ring].statss); tmp_rx_bytes = rx->rbytes; + tmp_rx_hsplit_bytes = rx->rx_hsplit_bytes; tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; tmp_rx_desc_err_dropped_pkt = @@ -283,6 +296,7 @@ gve_get_ethtool_stats(struct net_device *netdev, } while (u64_stats_fetch_retry(&priv->rx[ring].statss, start)); data[i++] = tmp_rx_bytes; + data[i++] = tmp_rx_hsplit_bytes; data[i++] = rx->rx_cont_packet_cnt; data[i++] = rx->rx_frag_flip_cnt; data[i++] = rx->rx_frag_copy_cnt; diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index a12d776d4385..8e8071308aeb 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -720,6 +720,8 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, /* Copy the header into the skb in the case of header split */ if (hsplit) { + int unsplit = 0; + if (hdr_len && !hbo) { rx->ctx.skb_head = gve_rx_copy_data(priv->dev, napi, rx->dqo.hdr_bufs.data + @@ -728,7 +730,14 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, if (unlikely(!rx->ctx.skb_head)) goto error; rx->ctx.skb_tail = rx->ctx.skb_head; + } else { + unsplit = 1; } + u64_stats_update_begin(&rx->statss); + rx->rx_hsplit_pkt++; + rx->rx_hsplit_unsplit_pkt += unsplit; + rx->rx_hsplit_bytes += hdr_len; + u64_stats_update_end(&rx->statss); } /* Sync the portion of dma buffer for CPU to read. */ From c2a22688c931ae965daa15691e902f9cf3069f5f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 29 Feb 2024 23:02:55 -0800 Subject: [PATCH 1737/2255] eth: igc: remove unused embedded struct net_device struct net_device poll_dev in struct igc_q_vector was added in one of the initial commits, but never used. Signed-off-by: Jakub Kicinski Reviewed-by: Eric Dumazet Reviewed-by: Jesse Brandeburg Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igc/igc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index cfa6baccec55..90316dc58630 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -570,7 +570,6 @@ struct igc_q_vector { struct rcu_head rcu; /* to avoid race with update stats on free */ char name[IFNAMSIZ + 9]; - struct net_device poll_dev; /* for dynamic allocation of rings associated with this q_vector */ struct igc_ring ring[] ____cacheline_internodealigned_in_smp; From b8b85d048936bd304c7815fd2bce348a22c2055b Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Fri, 1 Mar 2024 16:33:14 +0530 Subject: [PATCH 1738/2255] Octeontx2-af: Fix an issue in firmware shared data reserved space The last patch which added support to extend the firmware shared data to add channel data information has introduced a bug due to the reserved space not adjusted accordingly. This patch fixes the issue and also adds BUILD_BUG to avoid this regression error. Fixes: 997814491cee ("Octeontx2-af: Fetch MAC channel info from firmware") Signed-off-by: Hariprasad Kelam Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 2 ++ drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index edd12d09dc89..07d4859de53a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -817,6 +817,8 @@ static int rvu_fwdata_init(struct rvu *rvu) err = cgx_get_fwdata_base(&fwdbase); if (err) goto fail; + + BUILD_BUG_ON(offsetof(struct rvu_fwdata, cgx_fw_data) > FWDATA_CGX_LMAC_OFFSET); rvu->fwdata = ioremap_wc(fwdbase, sizeof(struct rvu_fwdata)); if (!rvu->fwdata) goto fail; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index de8eba902276..f390525a6217 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -469,11 +469,12 @@ struct rvu_fwdata { u32 ptp_ext_clk_rate; u32 ptp_ext_tstamp; struct channel_fwdata channel_data; -#define FWDATA_RESERVED_MEM 1014 +#define FWDATA_RESERVED_MEM 958 u64 reserved[FWDATA_RESERVED_MEM]; #define CGX_MAX 9 #define CGX_LMACS_MAX 4 #define CGX_LMACS_USX 8 +#define FWDATA_CGX_LMAC_OFFSET 10536 union { struct cgx_lmac_fwdata_s cgx_fw_data[CGX_MAX][CGX_LMACS_MAX]; From 4f41ce81a919cdaa6ae545f1c76264e719a7be0f Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 1 Mar 2024 05:42:13 -0800 Subject: [PATCH 1739/2255] net: nlmon: Remove init and uninit functions With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the nlmon driver and leverage the network core allocation. Signed-off-by: Breno Leitao Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/nlmon.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index 5e19a6839dea..e026bfc83757 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -17,17 +17,6 @@ static netdev_tx_t nlmon_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int nlmon_dev_init(struct net_device *dev) -{ - dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); - return dev->lstats == NULL ? -ENOMEM : 0; -} - -static void nlmon_dev_uninit(struct net_device *dev) -{ - free_percpu(dev->lstats); -} - struct nlmon { struct netlink_tap nt; }; @@ -72,8 +61,6 @@ static const struct ethtool_ops nlmon_ethtool_ops = { }; static const struct net_device_ops nlmon_ops = { - .ndo_init = nlmon_dev_init, - .ndo_uninit = nlmon_dev_uninit, .ndo_open = nlmon_open, .ndo_stop = nlmon_close, .ndo_start_xmit = nlmon_xmit, @@ -92,6 +79,7 @@ static void nlmon_setup(struct net_device *dev) dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | NETIF_F_LLTX; dev->flags = IFF_NOARP; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_LSTATS; /* That's rather a softlimit here, which, of course, * can be altered. Not a real MTU, but what is to be From 26b5df99bf603d3eb1a0acae239192e7d01c6b0e Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 1 Mar 2024 05:42:14 -0800 Subject: [PATCH 1740/2255] net: nlmon: Simplify nlmon_get_stats64 Do not set rtnl_link_stats64 fields to zero, since they are zeroed before ops->ndo_get_stats64 is called in core dev_get_stats() function. Also, simplify the data collection by removing the temporary variable. Signed-off-by: Breno Leitao Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/nlmon.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index e026bfc83757..e5a0987a263e 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -40,15 +40,7 @@ static int nlmon_close(struct net_device *dev) static void nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { - u64 packets, bytes; - - dev_lstats_read(dev, &packets, &bytes); - - stats->rx_packets = packets; - stats->tx_packets = 0; - - stats->rx_bytes = bytes; - stats->tx_bytes = 0; + dev_lstats_read(dev, &stats->rx_packets, &stats->rx_bytes); } static u32 always_on(struct net_device *dev) From 037db6ea57da7a134a8183dead92d64ef92babee Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 1 Mar 2024 18:43:44 +0100 Subject: [PATCH 1741/2255] mptcp: cleanup writer wake-up After commit 5cf92bbadc58 ("mptcp: re-enable sndbuf autotune"), the MPTCP_NOSPACE bit is redundant: it is always set and cleared together with SOCK_NOSPACE. Let's drop the first and always relay on the latter, dropping a bunch of useless code. Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/protocol.c | 15 +++------------ net/mptcp/protocol.h | 16 ++++++---------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 76c8861a852b..a3d79e9d0694 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1692,15 +1692,6 @@ out: } } -static void mptcp_set_nospace(struct sock *sk) -{ - /* enable autotune */ - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - - /* will be cleared on avail space */ - set_bit(MPTCP_NOSPACE, &mptcp_sk(sk)->flags); -} - static int mptcp_disconnect(struct sock *sk, int flags); static int mptcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, @@ -1874,7 +1865,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) continue; wait_for_memory: - mptcp_set_nospace(sk); + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); __mptcp_push_pending(sk, msg->msg_flags); ret = sk_stream_wait_memory(sk, &timeo); if (ret) @@ -3945,8 +3936,8 @@ static __poll_t mptcp_check_writeable(struct mptcp_sock *msk) if (sk_stream_is_writeable(sk)) return EPOLLOUT | EPOLLWRNORM; - mptcp_set_nospace(sk); - smp_mb__after_atomic(); /* msk->flags is changed by write_space cb */ + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + smp_mb__after_atomic(); /* NOSPACE is changed by mptcp_write_space() */ if (sk_stream_is_writeable(sk)) return EPOLLOUT | EPOLLWRNORM; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index d0a7955b96c4..f0c634e843e6 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -113,10 +113,9 @@ #define MPTCP_RST_TRANSIENT BIT(0) /* MPTCP socket atomic flags */ -#define MPTCP_NOSPACE 1 -#define MPTCP_WORK_RTX 2 -#define MPTCP_FALLBACK_DONE 4 -#define MPTCP_WORK_CLOSE_SUBFLOW 5 +#define MPTCP_WORK_RTX 1 +#define MPTCP_FALLBACK_DONE 2 +#define MPTCP_WORK_CLOSE_SUBFLOW 3 /* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1 @@ -810,12 +809,9 @@ static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk) static inline void mptcp_write_space(struct sock *sk) { - if (sk_stream_is_writeable(sk)) { - /* pairs with memory barrier in mptcp_poll */ - smp_mb(); - if (test_and_clear_bit(MPTCP_NOSPACE, &mptcp_sk(sk)->flags)) - sk_stream_write_space(sk); - } + /* pairs with memory barrier in mptcp_poll */ + smp_mb(); + sk_stream_write_space(sk); } static inline void __mptcp_sync_sndbuf(struct sock *sk) From a74762675f700a5473ebe54a671a0788a5b23cc9 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 1 Mar 2024 18:43:45 +0100 Subject: [PATCH 1742/2255] mptcp: avoid some duplicate code in socket option handling The mptcp_get_int_option() helper is needless open-coded in a couple of places, replace the duplicate code with the helper call. Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/sockopt.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index da37e4541a5d..ac37f6c5e2ed 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -629,13 +629,11 @@ static int mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, sockptr_t optva { struct mptcp_subflow_context *subflow; struct sock *sk = (struct sock *)msk; - int val; + int val, ret; - if (optlen < sizeof(int)) - return -EINVAL; - - if (copy_from_sockptr(&val, optval, sizeof(val))) - return -EFAULT; + ret = mptcp_get_int_option(msk, optval, optlen, &val); + if (ret) + return ret; lock_sock(sk); sockopt_seq_inc(msk); @@ -659,13 +657,11 @@ static int mptcp_setsockopt_sol_tcp_nodelay(struct mptcp_sock *msk, sockptr_t op { struct mptcp_subflow_context *subflow; struct sock *sk = (struct sock *)msk; - int val; + int val, ret; - if (optlen < sizeof(int)) - return -EINVAL; - - if (copy_from_sockptr(&val, optval, sizeof(val))) - return -EFAULT; + ret = mptcp_get_int_option(msk, optval, optlen, &val); + if (ret) + return ret; lock_sock(sk); sockopt_seq_inc(msk); From 29b5e5ef87397963ca38d3eec0d296ad1c979bbc Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 1 Mar 2024 18:43:46 +0100 Subject: [PATCH 1743/2255] mptcp: implement TCP_NOTSENT_LOWAT support Add support for such socket option storing the user-space provided value in a new msk field, and using such data to implement the _mptcp_stream_memory_free() helper, similar to the TCP one. To avoid adding more indirect calls in the fast path, open-code a variant of sk_stream_memory_free() in mptcp_sendmsg() and add direct calls to the mptcp stream memory free helper where possible. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/464 Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/protocol.c | 39 ++++++++++++++++++++++++++++++++++----- net/mptcp/protocol.h | 28 +++++++++++++++++++++++++++- net/mptcp/sockopt.c | 12 ++++++++++++ 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index a3d79e9d0694..99367c40de0d 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1762,6 +1762,30 @@ static int do_copy_data_nocache(struct sock *sk, int copy, return 0; } +/* open-code sk_stream_memory_free() plus sent limit computation to + * avoid indirect calls in fast-path. + * Called under the msk socket lock, so we can avoid a bunch of ONCE + * annotations. + */ +static u32 mptcp_send_limit(const struct sock *sk) +{ + const struct mptcp_sock *msk = mptcp_sk(sk); + u32 limit, not_sent; + + if (sk->sk_wmem_queued >= READ_ONCE(sk->sk_sndbuf)) + return 0; + + limit = mptcp_notsent_lowat(sk); + if (limit == UINT_MAX) + return UINT_MAX; + + not_sent = msk->write_seq - msk->snd_nxt; + if (not_sent >= limit) + return 0; + + return limit - not_sent; +} + static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { struct mptcp_sock *msk = mptcp_sk(sk); @@ -1806,6 +1830,12 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) struct mptcp_data_frag *dfrag; bool dfrag_collapsed; size_t psize, offset; + u32 copy_limit; + + /* ensure fitting the notsent_lowat() constraint */ + copy_limit = mptcp_send_limit(sk); + if (!copy_limit) + goto wait_for_memory; /* reuse tail pfrag, if possible, or carve a new one from the * page allocator @@ -1813,9 +1843,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) dfrag = mptcp_pending_tail(sk); dfrag_collapsed = mptcp_frag_can_collapse_to(msk, pfrag, dfrag); if (!dfrag_collapsed) { - if (!sk_stream_memory_free(sk)) - goto wait_for_memory; - if (!mptcp_page_frag_refill(sk, pfrag)) goto wait_for_memory; @@ -1830,6 +1857,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) offset = dfrag->offset + dfrag->data_len; psize = pfrag->size - offset; psize = min_t(size_t, psize, msg_data_left(msg)); + psize = min_t(size_t, psize, copy_limit); total_ts = psize + frag_truesize; if (!sk_wmem_schedule(sk, total_ts)) @@ -3760,6 +3788,7 @@ static struct proto mptcp_prot = { .unhash = mptcp_unhash, .get_port = mptcp_get_port, .forward_alloc_get = mptcp_forward_alloc_get, + .stream_memory_free = mptcp_stream_memory_free, .sockets_allocated = &mptcp_sockets_allocated, .memory_allocated = &tcp_memory_allocated, @@ -3933,12 +3962,12 @@ static __poll_t mptcp_check_writeable(struct mptcp_sock *msk) { struct sock *sk = (struct sock *)msk; - if (sk_stream_is_writeable(sk)) + if (__mptcp_stream_is_writeable(sk, 1)) return EPOLLOUT | EPOLLWRNORM; set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); smp_mb__after_atomic(); /* NOSPACE is changed by mptcp_write_space() */ - if (sk_stream_is_writeable(sk)) + if (__mptcp_stream_is_writeable(sk, 1)) return EPOLLOUT | EPOLLWRNORM; return 0; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index f0c634e843e6..7cb502260dea 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -307,6 +307,7 @@ struct mptcp_sock { in_accept_queue:1, free_first:1, rcvspace_init:1; + u32 notsent_lowat; struct work_struct work; struct sk_buff *ooo_last_skb; struct rb_root out_of_order_queue; @@ -807,11 +808,36 @@ static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk) READ_ONCE(msk->write_seq) == READ_ONCE(msk->snd_nxt); } +static inline u32 mptcp_notsent_lowat(const struct sock *sk) +{ + struct net *net = sock_net(sk); + u32 val; + + val = READ_ONCE(mptcp_sk(sk)->notsent_lowat); + return val ?: READ_ONCE(net->ipv4.sysctl_tcp_notsent_lowat); +} + +static inline bool mptcp_stream_memory_free(const struct sock *sk, int wake) +{ + const struct mptcp_sock *msk = mptcp_sk(sk); + u32 notsent_bytes; + + notsent_bytes = READ_ONCE(msk->write_seq) - READ_ONCE(msk->snd_nxt); + return (notsent_bytes << wake) < mptcp_notsent_lowat(sk); +} + +static inline bool __mptcp_stream_is_writeable(const struct sock *sk, int wake) +{ + return mptcp_stream_memory_free(sk, wake) && + __sk_stream_is_writeable(sk, wake); +} + static inline void mptcp_write_space(struct sock *sk) { /* pairs with memory barrier in mptcp_poll */ smp_mb(); - sk_stream_write_space(sk); + if (mptcp_stream_memory_free(sk, 1)) + sk_stream_write_space(sk); } static inline void __mptcp_sync_sndbuf(struct sock *sk) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index ac37f6c5e2ed..1b38dac70719 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -812,6 +812,16 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, return 0; case TCP_ULP: return -EOPNOTSUPP; + case TCP_NOTSENT_LOWAT: + ret = mptcp_get_int_option(msk, optval, optlen, &val); + if (ret) + return ret; + + lock_sock(sk); + WRITE_ONCE(msk->notsent_lowat, val); + mptcp_write_space(sk); + release_sock(sk); + return 0; case TCP_CONGESTION: return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen); case TCP_CORK: @@ -1345,6 +1355,8 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, return mptcp_put_int_option(msk, optval, optlen, msk->cork); case TCP_NODELAY: return mptcp_put_int_option(msk, optval, optlen, msk->nodelay); + case TCP_NOTSENT_LOWAT: + return mptcp_put_int_option(msk, optval, optlen, msk->notsent_lowat); } return -EOPNOTSUPP; } From 7f71a337b5152ea0e7bef408d1af53778a919316 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 1 Mar 2024 18:43:47 +0100 Subject: [PATCH 1744/2255] mptcp: cleanup SOL_TCP handling Most TCP-level socket options get an integer from user space, and set the corresponding field under the msk-level socket lock. Reduce the code duplication moving such operations in the common code. Signed-off-by: Paolo Abeni Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/sockopt.c | 75 ++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index 1b38dac70719..dcd1c76d2a3b 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -624,18 +624,11 @@ static int mptcp_setsockopt_sol_tcp_congestion(struct mptcp_sock *msk, sockptr_t return ret; } -static int mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, sockptr_t optval, - unsigned int optlen) +static int __mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, int val) { struct mptcp_subflow_context *subflow; struct sock *sk = (struct sock *)msk; - int val, ret; - ret = mptcp_get_int_option(msk, optval, optlen, &val); - if (ret) - return ret; - - lock_sock(sk); sockopt_seq_inc(msk); msk->cork = !!val; mptcp_for_each_subflow(msk, subflow) { @@ -647,23 +640,15 @@ static int mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, sockptr_t optva } if (!val) mptcp_check_and_set_pending(sk); - release_sock(sk); return 0; } -static int mptcp_setsockopt_sol_tcp_nodelay(struct mptcp_sock *msk, sockptr_t optval, - unsigned int optlen) +static int __mptcp_setsockopt_sol_tcp_nodelay(struct mptcp_sock *msk, int val) { struct mptcp_subflow_context *subflow; struct sock *sk = (struct sock *)msk; - int val, ret; - ret = mptcp_get_int_option(msk, optval, optlen, &val); - if (ret) - return ret; - - lock_sock(sk); sockopt_seq_inc(msk); msk->nodelay = !!val; mptcp_for_each_subflow(msk, subflow) { @@ -675,8 +660,6 @@ static int mptcp_setsockopt_sol_tcp_nodelay(struct mptcp_sock *msk, sockptr_t op } if (val) mptcp_check_and_set_pending(sk); - release_sock(sk); - return 0; } @@ -799,35 +782,10 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, int ret, val; switch (optname) { - case TCP_INQ: - ret = mptcp_get_int_option(msk, optval, optlen, &val); - if (ret) - return ret; - if (val < 0 || val > 1) - return -EINVAL; - - lock_sock(sk); - msk->recvmsg_inq = !!val; - release_sock(sk); - return 0; case TCP_ULP: return -EOPNOTSUPP; - case TCP_NOTSENT_LOWAT: - ret = mptcp_get_int_option(msk, optval, optlen, &val); - if (ret) - return ret; - - lock_sock(sk); - WRITE_ONCE(msk->notsent_lowat, val); - mptcp_write_space(sk); - release_sock(sk); - return 0; case TCP_CONGESTION: return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen); - case TCP_CORK: - return mptcp_setsockopt_sol_tcp_cork(msk, optval, optlen); - case TCP_NODELAY: - return mptcp_setsockopt_sol_tcp_nodelay(msk, optval, optlen); case TCP_DEFER_ACCEPT: /* See tcp.c: TCP_DEFER_ACCEPT does not fail */ mptcp_setsockopt_first_sf_only(msk, SOL_TCP, optname, optval, optlen); @@ -840,7 +798,34 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, optval, optlen); } - return -EOPNOTSUPP; + ret = mptcp_get_int_option(msk, optval, optlen, &val); + if (ret) + return ret; + + lock_sock(sk); + switch (optname) { + case TCP_INQ: + if (val < 0 || val > 1) + ret = -EINVAL; + else + msk->recvmsg_inq = !!val; + break; + case TCP_NOTSENT_LOWAT: + WRITE_ONCE(msk->notsent_lowat, val); + mptcp_write_space(sk); + break; + case TCP_CORK: + ret = __mptcp_setsockopt_sol_tcp_cork(msk, val); + break; + case TCP_NODELAY: + ret = __mptcp_setsockopt_sol_tcp_nodelay(msk, val); + break; + default: + ret = -ENOPROTOOPT; + } + + release_sock(sk); + return ret; } int mptcp_setsockopt(struct sock *sk, int level, int optname, From e87e4371edfc369dcc6abbabc3f276d4e0260513 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Mar 2024 11:02:36 -0600 Subject: [PATCH 1745/2255] net: ipa: change ipa_interrupt_config() prototype Change the return type of ipa_interrupt_config() to be an error code rather than an IPA interrupt structure pointer, and assign the the pointer within that function. Change ipa_interrupt_deconfig() to take the IPA pointer as argument and have it invalidate the ipa->interrupt pointer. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_interrupt.c | 25 +++++++++++++++---------- drivers/net/ipa/ipa_interrupt.h | 10 +++++----- drivers/net/ipa/ipa_main.c | 13 ++++--------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index 4d80bf77a532..e23c9a5942ed 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -236,7 +236,7 @@ void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt) } /* Configure the IPA interrupt framework */ -struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa) +int ipa_interrupt_config(struct ipa *ipa) { struct device *dev = &ipa->pdev->dev; struct ipa_interrupt *interrupt; @@ -246,15 +246,14 @@ struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa) ret = platform_get_irq_byname(ipa->pdev, "ipa"); if (ret <= 0) { - dev_err(dev, "DT error %d getting \"ipa\" IRQ property\n", - ret); - return ERR_PTR(ret ? : -EINVAL); + dev_err(dev, "DT error %d getting \"ipa\" IRQ property\n", ret); + return ret ? : -EINVAL; } irq = ret; interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL); if (!interrupt) - return ERR_PTR(-ENOMEM); + return -ENOMEM; interrupt->ipa = ipa; interrupt->irq = irq; @@ -271,24 +270,30 @@ struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa) ret = dev_pm_set_wake_irq(dev, irq); if (ret) { - dev_err(dev, "error %d registering \"ipa\" IRQ as wakeirq\n", ret); + dev_err(dev, "error %d registering \"ipa\" IRQ as wakeirq\n", + ret); goto err_free_irq; } - return interrupt; + ipa->interrupt = interrupt; + + return 0; err_free_irq: free_irq(interrupt->irq, interrupt); err_kfree: kfree(interrupt); - return ERR_PTR(ret); + return ret; } /* Inverse of ipa_interrupt_config() */ -void ipa_interrupt_deconfig(struct ipa_interrupt *interrupt) +void ipa_interrupt_deconfig(struct ipa *ipa) { - struct device *dev = &interrupt->ipa->pdev->dev; + struct ipa_interrupt *interrupt = ipa->interrupt; + struct device *dev = &ipa->pdev->dev; + + ipa->interrupt = NULL; dev_pm_clear_wake_irq(dev); free_irq(interrupt->irq, interrupt); diff --git a/drivers/net/ipa/ipa_interrupt.h b/drivers/net/ipa/ipa_interrupt.h index 53e1b71685c7..1947654e3e36 100644 --- a/drivers/net/ipa/ipa_interrupt.h +++ b/drivers/net/ipa/ipa_interrupt.h @@ -76,17 +76,17 @@ void ipa_interrupt_irq_enable(struct ipa *ipa); void ipa_interrupt_irq_disable(struct ipa *ipa); /** - * ipa_interrupt_config() - Configure the IPA interrupt framework + * ipa_interrupt_config() - Configure IPA interrupts * @ipa: IPA pointer * - * Return: Pointer to IPA SMP2P info, or a pointer-coded error + * Return: 0 if successful, or a negative error code */ -struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa); +int ipa_interrupt_config(struct ipa *ipa); /** * ipa_interrupt_deconfig() - Inverse of ipa_interrupt_config() - * @interrupt: IPA interrupt structure + * @ipa: IPA pointer */ -void ipa_interrupt_deconfig(struct ipa_interrupt *interrupt); +void ipa_interrupt_deconfig(struct ipa *ipa); #endif /* _IPA_INTERRUPT_H_ */ diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 00475fd7a205..0c6e6719d99e 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -542,12 +542,9 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data) if (ret) goto err_hardware_deconfig; - ipa->interrupt = ipa_interrupt_config(ipa); - if (IS_ERR(ipa->interrupt)) { - ret = PTR_ERR(ipa->interrupt); - ipa->interrupt = NULL; + ret = ipa_interrupt_config(ipa); + if (ret) goto err_mem_deconfig; - } ipa_uc_config(ipa); @@ -572,8 +569,7 @@ err_endpoint_deconfig: ipa_endpoint_deconfig(ipa); err_uc_deconfig: ipa_uc_deconfig(ipa); - ipa_interrupt_deconfig(ipa->interrupt); - ipa->interrupt = NULL; + ipa_interrupt_deconfig(ipa); err_mem_deconfig: ipa_mem_deconfig(ipa); err_hardware_deconfig: @@ -591,8 +587,7 @@ static void ipa_deconfig(struct ipa *ipa) ipa_modem_deconfig(ipa); ipa_endpoint_deconfig(ipa); ipa_uc_deconfig(ipa); - ipa_interrupt_deconfig(ipa->interrupt); - ipa->interrupt = NULL; + ipa_interrupt_deconfig(ipa); ipa_mem_deconfig(ipa); ipa_hardware_deconfig(ipa); } From ad1be80d75827aad9582541ecc9d7953d354634f Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Mar 2024 11:02:37 -0600 Subject: [PATCH 1746/2255] net: ipa: introduce ipa_interrupt_init() Create a new function ipa_interrupt_init() that is called at probe time to allocate and initialize the IPA interrupt data structure. Create ipa_interrupt_exit() as its inverse. This follows the normal IPA driver pattern of *_init() functions doing things that can be done before access to hardware is required. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_interrupt.c | 45 +++++++++++++++++++++++---------- drivers/net/ipa/ipa_interrupt.h | 14 ++++++++++ drivers/net/ipa/ipa_main.c | 28 ++++++++++++++++---- 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index e23c9a5942ed..7399724160a8 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -19,6 +19,7 @@ * time only these three are supported. */ +#include #include #include #include @@ -238,26 +239,15 @@ void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt) /* Configure the IPA interrupt framework */ int ipa_interrupt_config(struct ipa *ipa) { + struct ipa_interrupt *interrupt = ipa->interrupt; struct device *dev = &ipa->pdev->dev; - struct ipa_interrupt *interrupt; + unsigned int irq = interrupt->irq; const struct reg *reg; - unsigned int irq; int ret; - ret = platform_get_irq_byname(ipa->pdev, "ipa"); - if (ret <= 0) { - dev_err(dev, "DT error %d getting \"ipa\" IRQ property\n", ret); - return ret ? : -EINVAL; - } - irq = ret; - - interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL); - if (!interrupt) - return -ENOMEM; interrupt->ipa = ipa; - interrupt->irq = irq; - /* Start with all IPA interrupts disabled */ + /* Disable all IPA interrupt types */ reg = ipa_reg(ipa, IPA_IRQ_EN); iowrite32(0, ipa->reg_virt + reg_offset(reg)); @@ -297,5 +287,32 @@ void ipa_interrupt_deconfig(struct ipa *ipa) dev_pm_clear_wake_irq(dev); free_irq(interrupt->irq, interrupt); +} + +/* Initialize the IPA interrupt structure */ +struct ipa_interrupt *ipa_interrupt_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ipa_interrupt *interrupt; + int irq; + + irq = platform_get_irq_byname(pdev, "ipa"); + if (irq <= 0) { + dev_err(dev, "DT error %d getting \"ipa\" IRQ property\n", irq); + + return ERR_PTR(irq ? : -EINVAL); + } + + interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL); + if (!interrupt) + return ERR_PTR(-ENOMEM); + interrupt->irq = irq; + + return interrupt; +} + +/* Inverse of ipa_interrupt_init() */ +void ipa_interrupt_exit(struct ipa_interrupt *interrupt) +{ kfree(interrupt); } diff --git a/drivers/net/ipa/ipa_interrupt.h b/drivers/net/ipa/ipa_interrupt.h index 1947654e3e36..f3f4f4330a59 100644 --- a/drivers/net/ipa/ipa_interrupt.h +++ b/drivers/net/ipa/ipa_interrupt.h @@ -89,4 +89,18 @@ int ipa_interrupt_config(struct ipa *ipa); */ void ipa_interrupt_deconfig(struct ipa *ipa); +/** + * ipa_interrupt_init() - Initialize the IPA interrupt structure + * @pdev: IPA platform device pointer + * + * Return: Pointer to an IPA interrupt structure, or a pointer-coded error + */ +struct ipa_interrupt *ipa_interrupt_init(struct platform_device *pdev); + +/** + * ipa_interrupt_exit() - Inverse of ipa_interrupt_init() + * @interrupt: IPA interrupt structure + */ +void ipa_interrupt_exit(struct ipa_interrupt *interrupt); + #endif /* _IPA_INTERRUPT_H_ */ diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 0c6e6719d99e..6cf5c1280aa4 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -803,6 +803,7 @@ out_self: static int ipa_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct ipa_interrupt *interrupt; enum ipa_firmware_loader loader; const struct ipa_data *data; struct ipa_power *power; @@ -834,12 +835,21 @@ static int ipa_probe(struct platform_device *pdev) if (loader == IPA_LOADER_DEFER) return -EPROBE_DEFER; - /* The clock and interconnects might not be ready when we're - * probed, so might return -EPROBE_DEFER. + /* The IPA interrupt might not be ready when we're probed, so this + * might return -EPROBE_DEFER. + */ + interrupt = ipa_interrupt_init(pdev); + if (IS_ERR(interrupt)) + return PTR_ERR(interrupt); + + /* The clock and interconnects might not be ready when we're probed, + * so this might return -EPROBE_DEFER. */ power = ipa_power_init(dev, data->power_data); - if (IS_ERR(power)) - return PTR_ERR(power); + if (IS_ERR(power)) { + ret = PTR_ERR(power); + goto err_interrupt_exit; + } /* No more EPROBE_DEFER. Allocate and initialize the IPA structure */ ipa = kzalloc(sizeof(*ipa), GFP_KERNEL); @@ -850,6 +860,7 @@ static int ipa_probe(struct platform_device *pdev) ipa->pdev = pdev; dev_set_drvdata(dev, ipa); + ipa->interrupt = interrupt; ipa->power = power; ipa->version = data->version; ipa->modem_route_count = data->modem_route_count; @@ -934,6 +945,8 @@ err_kfree_ipa: kfree(ipa); err_power_exit: ipa_power_exit(power); +err_interrupt_exit: + ipa_interrupt_exit(interrupt); return ret; } @@ -941,10 +954,14 @@ err_power_exit: static void ipa_remove(struct platform_device *pdev) { struct ipa *ipa = dev_get_drvdata(&pdev->dev); - struct ipa_power *power = ipa->power; struct device *dev = &pdev->dev; + struct ipa_interrupt *interrupt; + struct ipa_power *power; int ret; + power = ipa->power; + interrupt = ipa->interrupt; + /* Prevent the modem from triggering a call to ipa_setup(). This * also ensures a modem-initiated setup that's underway completes. */ @@ -986,6 +1003,7 @@ out_power_put: ipa_reg_exit(ipa); kfree(ipa); ipa_power_exit(power); + ipa_interrupt_exit(interrupt); dev_info(dev, "IPA driver removed"); } From a47956e72a3e724f88c696944d197f7bf8442273 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Mar 2024 11:02:38 -0600 Subject: [PATCH 1747/2255] net: ipa: pass a platform device to ipa_reg_init() Rather than using the platform device pointer field in the IPA pointer, pass a platform device pointer to ipa_reg_init(). Use that pointer throughout that function. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_main.c | 2 +- drivers/net/ipa/ipa_reg.c | 8 ++++---- drivers/net/ipa/ipa_reg.h | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 6cf5c1280aa4..5c9c1b0ef8de 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -866,7 +866,7 @@ static int ipa_probe(struct platform_device *pdev) ipa->modem_route_count = data->modem_route_count; init_completion(&ipa->completion); - ret = ipa_reg_init(ipa); + ret = ipa_reg_init(ipa, pdev); if (ret) goto err_kfree_ipa; diff --git a/drivers/net/ipa/ipa_reg.c b/drivers/net/ipa/ipa_reg.c index 6a3203ae6f1e..98625956e0bb 100644 --- a/drivers/net/ipa/ipa_reg.c +++ b/drivers/net/ipa/ipa_reg.c @@ -4,6 +4,7 @@ * Copyright (C) 2019-2023 Linaro Ltd. */ +#include #include #include "ipa.h" @@ -132,9 +133,9 @@ static const struct regs *ipa_regs(enum ipa_version version) } } -int ipa_reg_init(struct ipa *ipa) +int ipa_reg_init(struct ipa *ipa, struct platform_device *pdev) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = &pdev->dev; const struct regs *regs; struct resource *res; @@ -146,8 +147,7 @@ int ipa_reg_init(struct ipa *ipa) return -EINVAL; /* Setup IPA register memory */ - res = platform_get_resource_byname(ipa->pdev, IORESOURCE_MEM, - "ipa-reg"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ipa-reg"); if (!res) { dev_err(dev, "DT error getting \"ipa-reg\" memory property\n"); return -ENODEV; diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index 2998f115f12c..62c62495b796 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -12,6 +12,8 @@ #include "ipa_version.h" #include "reg.h" +struct platform_device; + struct ipa; /** @@ -643,7 +645,7 @@ extern const struct regs ipa_regs_v5_5; const struct reg *ipa_reg(struct ipa *ipa, enum ipa_reg_id reg_id); -int ipa_reg_init(struct ipa *ipa); +int ipa_reg_init(struct ipa *ipa, struct platform_device *pdev); void ipa_reg_exit(struct ipa *ipa); #endif /* _IPA_REG_H_ */ From 95c54a963b2445096adf5c92c8e30160f2cb1d8d Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Mar 2024 11:02:39 -0600 Subject: [PATCH 1748/2255] net: ipa: pass a platform device to ipa_mem_init() Rather than using the platform device pointer field in the IPA pointer, pass a platform device pointer to ipa_mem_init(). Use that pointer throughout that function. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_main.c | 2 +- drivers/net/ipa/ipa_mem.c | 13 +++++++------ drivers/net/ipa/ipa_mem.h | 5 ++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 5c9c1b0ef8de..17ee075370ce 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -870,7 +870,7 @@ static int ipa_probe(struct platform_device *pdev) if (ret) goto err_kfree_ipa; - ret = ipa_mem_init(ipa, data->mem_data); + ret = ipa_mem_init(ipa, pdev, data->mem_data); if (ret) goto err_reg_exit; diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c index 694960537ecd..d7df7d340221 100644 --- a/drivers/net/ipa/ipa_mem.c +++ b/drivers/net/ipa/ipa_mem.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -75,9 +76,9 @@ ipa_mem_zero_region_add(struct gsi_trans *trans, enum ipa_mem_id mem_id) int ipa_mem_setup(struct ipa *ipa) { dma_addr_t addr = ipa->zero_addr; - const struct reg *reg; const struct ipa_mem *mem; struct gsi_trans *trans; + const struct reg *reg; u32 offset; u16 size; u32 val; @@ -615,9 +616,10 @@ static void ipa_smem_exit(struct ipa *ipa) } /* Perform memory region-related initialization */ -int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data) +int ipa_mem_init(struct ipa *ipa, struct platform_device *pdev, + const struct ipa_mem_data *mem_data) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = &pdev->dev; struct resource *res; int ret; @@ -634,14 +636,13 @@ int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data) if (!ipa_table_mem_valid(ipa, true)) return -EINVAL; - ret = dma_set_mask_and_coherent(&ipa->pdev->dev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret) { dev_err(dev, "error %d setting DMA mask\n", ret); return ret; } - res = platform_get_resource_byname(ipa->pdev, IORESOURCE_MEM, - "ipa-shared"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ipa-shared"); if (!res) { dev_err(dev, "DT error getting \"ipa-shared\" memory property\n"); diff --git a/drivers/net/ipa/ipa_mem.h b/drivers/net/ipa/ipa_mem.h index 868e9c20e8c4..28aad00a151d 100644 --- a/drivers/net/ipa/ipa_mem.h +++ b/drivers/net/ipa/ipa_mem.h @@ -6,6 +6,8 @@ #ifndef _IPA_MEM_H_ #define _IPA_MEM_H_ +struct platform_device; + struct ipa; struct ipa_mem_data; @@ -100,7 +102,8 @@ int ipa_mem_setup(struct ipa *ipa); /* No ipa_mem_teardown() needed */ int ipa_mem_zero_modem(struct ipa *ipa); -int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data); +int ipa_mem_init(struct ipa *ipa, struct platform_device *pdev, + const struct ipa_mem_data *mem_data); void ipa_mem_exit(struct ipa *ipa); #endif /* _IPA_MEM_H_ */ From 59622a8fb45350bf8028c350dd20958fa8a77279 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Mar 2024 11:02:40 -0600 Subject: [PATCH 1749/2255] net: ipa: pass a platform device to ipa_smp2p_irq_init() Rather than using the platform device pointer field in the IPA pointer, pass a platform device pointer to ipa_smp2p_irq_init(). Use that pointer throughout that function (without assuming it's the same as the IPA platform device pointer). Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_smp2p.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c index 5620dc271fac..8c4497dfe5af 100644 --- a/drivers/net/ipa/ipa_smp2p.c +++ b/drivers/net/ipa/ipa_smp2p.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include @@ -179,14 +179,15 @@ out_power_put: } /* Initialize SMP2P interrupts */ -static int ipa_smp2p_irq_init(struct ipa_smp2p *smp2p, const char *name, - irq_handler_t handler) +static int ipa_smp2p_irq_init(struct ipa_smp2p *smp2p, + struct platform_device *pdev, + const char *name, irq_handler_t handler) { - struct device *dev = &smp2p->ipa->pdev->dev; + struct device *dev = &pdev->dev; unsigned int irq; int ret; - ret = platform_get_irq_byname(smp2p->ipa->pdev, name); + ret = platform_get_irq_byname(pdev, name); if (ret <= 0) return ret ? : -EINVAL; irq = ret; @@ -261,7 +262,7 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init) /* We have enough information saved to handle notifications */ ipa->smp2p = smp2p; - ret = ipa_smp2p_irq_init(smp2p, "ipa-clock-query", + ret = ipa_smp2p_irq_init(smp2p, smp2p->ipa->pdev, "ipa-clock-query", ipa_smp2p_modem_clk_query_isr); if (ret < 0) goto err_null_smp2p; @@ -273,7 +274,8 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init) if (modem_init) { /* Result will be non-zero (negative for error) */ - ret = ipa_smp2p_irq_init(smp2p, "ipa-setup-ready", + ret = ipa_smp2p_irq_init(smp2p, smp2p->ipa->pdev, + "ipa-setup-ready", ipa_smp2p_modem_setup_ready_isr); if (ret < 0) goto err_notifier_unregister; From 81d65f3413da3fe8158ac3ead6270035db1c0dde Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Mar 2024 11:02:41 -0600 Subject: [PATCH 1750/2255] net: ipa: pass a platform device to ipa_smp2p_init() Rather than using the platform device pointer field in the IPA pointer, pass a platform device pointer to ipa_smp2p_init(). Use that pointer throughout that function. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_main.c | 2 +- drivers/net/ipa/ipa_smp2p.c | 10 +++++----- drivers/net/ipa/ipa_smp2p.h | 7 +++++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 17ee075370ce..3125aec88e6e 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -888,7 +888,7 @@ static int ipa_probe(struct platform_device *pdev) if (ret) goto err_endpoint_exit; - ret = ipa_smp2p_init(ipa, loader == IPA_LOADER_MODEM); + ret = ipa_smp2p_init(ipa, pdev, loader == IPA_LOADER_MODEM); if (ret) goto err_table_exit; diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c index 8c4497dfe5af..831268551d9a 100644 --- a/drivers/net/ipa/ipa_smp2p.c +++ b/drivers/net/ipa/ipa_smp2p.c @@ -220,10 +220,11 @@ static void ipa_smp2p_power_release(struct ipa *ipa) } /* Initialize the IPA SMP2P subsystem */ -int ipa_smp2p_init(struct ipa *ipa, bool modem_init) +int +ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init) { struct qcom_smem_state *enabled_state; - struct device *dev = &ipa->pdev->dev; + struct device *dev = &pdev->dev; struct qcom_smem_state *valid_state; struct ipa_smp2p *smp2p; u32 enabled_bit; @@ -262,7 +263,7 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init) /* We have enough information saved to handle notifications */ ipa->smp2p = smp2p; - ret = ipa_smp2p_irq_init(smp2p, smp2p->ipa->pdev, "ipa-clock-query", + ret = ipa_smp2p_irq_init(smp2p, pdev, "ipa-clock-query", ipa_smp2p_modem_clk_query_isr); if (ret < 0) goto err_null_smp2p; @@ -274,8 +275,7 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init) if (modem_init) { /* Result will be non-zero (negative for error) */ - ret = ipa_smp2p_irq_init(smp2p, smp2p->ipa->pdev, - "ipa-setup-ready", + ret = ipa_smp2p_irq_init(smp2p, pdev, "ipa-setup-ready", ipa_smp2p_modem_setup_ready_isr); if (ret < 0) goto err_notifier_unregister; diff --git a/drivers/net/ipa/ipa_smp2p.h b/drivers/net/ipa/ipa_smp2p.h index 9b969b03d1a4..2a3d8eefb13b 100644 --- a/drivers/net/ipa/ipa_smp2p.h +++ b/drivers/net/ipa/ipa_smp2p.h @@ -8,17 +8,20 @@ #include +struct platform_device; + struct ipa; /** * ipa_smp2p_init() - Initialize the IPA SMP2P subsystem * @ipa: IPA pointer + * @pdev: Platform device pointer * @modem_init: Whether the modem is responsible for GSI initialization * * Return: 0 if successful, or a negative error code - * */ -int ipa_smp2p_init(struct ipa *ipa, bool modem_init); +int ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, + bool modem_init); /** * ipa_smp2p_exit() - Inverse of ipa_smp2p_init() From 5245f4fd28d126cc13e32e77abc8a8fd287167b0 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 1 Mar 2024 11:02:42 -0600 Subject: [PATCH 1751/2255] net: ipa: don't save the platform device The IPA platform device is now only used as the structure containing the IPA device structure. Replace the platform device pointer with a pointer to the device structure. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa.h | 5 ++--- drivers/net/ipa/ipa_cmd.c | 6 +++--- drivers/net/ipa/ipa_endpoint.c | 29 ++++++++++++++--------------- drivers/net/ipa/ipa_interrupt.c | 7 +++---- drivers/net/ipa/ipa_main.c | 13 ++++++++----- drivers/net/ipa/ipa_mem.c | 24 +++++++++++------------- drivers/net/ipa/ipa_modem.c | 14 +++++++------- drivers/net/ipa/ipa_power.c | 4 ++-- drivers/net/ipa/ipa_qmi.c | 10 +++++----- drivers/net/ipa/ipa_smp2p.c | 13 ++++++------- drivers/net/ipa/ipa_table.c | 18 ++++++++---------- drivers/net/ipa/ipa_uc.c | 9 ++++----- 12 files changed, 73 insertions(+), 79 deletions(-) diff --git a/drivers/net/ipa/ipa.h b/drivers/net/ipa/ipa.h index f3355e040a9e..334cd62cf286 100644 --- a/drivers/net/ipa/ipa.h +++ b/drivers/net/ipa/ipa.h @@ -21,7 +21,6 @@ struct clk; struct icc_path; struct net_device; -struct platform_device; struct ipa_power; struct ipa_smp2p; @@ -31,7 +30,7 @@ struct ipa_interrupt; * struct ipa - IPA information * @gsi: Embedded GSI structure * @version: IPA hardware version - * @pdev: Platform device + * @dev: IPA device pointer * @completion: Used to signal pipeline clear transfer complete * @nb: Notifier block used for remoteproc SSR * @notifier: Remoteproc SSR notifier @@ -79,7 +78,7 @@ struct ipa_interrupt; struct ipa { struct gsi gsi; enum ipa_version version; - struct platform_device *pdev; + struct device *dev; struct completion completion; struct notifier_block nb; void *notifier; diff --git a/drivers/net/ipa/ipa_cmd.c b/drivers/net/ipa/ipa_cmd.c index f1419fbd776c..39219963dbb3 100644 --- a/drivers/net/ipa/ipa_cmd.c +++ b/drivers/net/ipa/ipa_cmd.c @@ -174,7 +174,7 @@ bool ipa_cmd_table_init_valid(struct ipa *ipa, const struct ipa_mem *mem, u32 offset_max = field_max(IP_FLTRT_FLAGS_NHASH_ADDR_FMASK); u32 size_max = field_max(IP_FLTRT_FLAGS_NHASH_SIZE_FMASK); const char *table = route ? "route" : "filter"; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; u32 size; size = route ? ipa->route_count : ipa->filter_count + 1; @@ -204,7 +204,7 @@ bool ipa_cmd_table_init_valid(struct ipa *ipa, const struct ipa_mem *mem, /* Validate the memory region that holds headers */ static bool ipa_cmd_header_init_local_valid(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; const struct ipa_mem *mem; u32 offset_max; u32 size_max; @@ -256,7 +256,7 @@ static bool ipa_cmd_register_write_offset_valid(struct ipa *ipa, const char *name, u32 offset) { struct ipa_cmd_register_write *payload; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; u32 offset_max; u32 bit_count; diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index afa1d56d9095..dd490941615e 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -233,8 +233,8 @@ static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count, const struct ipa_gsi_endpoint_data *data) { const struct ipa_gsi_endpoint_data *other_data; - struct device *dev = &ipa->pdev->dev; enum ipa_endpoint_name other_name; + struct device *dev = ipa->dev; if (ipa_gsi_endpoint_data_empty(data)) return true; @@ -388,7 +388,7 @@ static u32 ipa_endpoint_max(struct ipa *ipa, u32 count, const struct ipa_gsi_endpoint_data *data) { const struct ipa_gsi_endpoint_data *dp = data; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; enum ipa_endpoint_name name; u32 max; @@ -606,7 +606,7 @@ int ipa_endpoint_modem_exception_reset_all(struct ipa *ipa) count = ipa->modem_tx_count + ipa_cmd_pipeline_clear_count(); trans = ipa_cmd_trans_alloc(ipa, count); if (!trans) { - dev_err(&ipa->pdev->dev, + dev_err(ipa->dev, "no transaction to reset modem exception endpoints\n"); return -EBUSY; } @@ -1498,8 +1498,7 @@ ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, const void *data) if (endpoint_id == command_endpoint->endpoint_id) { complete(&ipa->completion); } else { - dev_err(&ipa->pdev->dev, - "unexpected tagged packet from endpoint %u\n", + dev_err(ipa->dev, "unexpected tagged packet from endpoint %u\n", endpoint_id); } @@ -1536,6 +1535,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, void *data = page_address(page) + NET_SKB_PAD; u32 unused = buffer_size - total_len; struct ipa *ipa = endpoint->ipa; + struct device *dev = ipa->dev; u32 resid = total_len; while (resid) { @@ -1544,7 +1544,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, u32 len; if (resid < IPA_STATUS_SIZE) { - dev_err(&endpoint->ipa->pdev->dev, + dev_err(dev, "short message (%u bytes < %zu byte status)\n", resid, IPA_STATUS_SIZE); break; @@ -1666,8 +1666,8 @@ void ipa_endpoint_default_route_clear(struct ipa *ipa) */ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint) { - struct device *dev = &endpoint->ipa->pdev->dev; struct ipa *ipa = endpoint->ipa; + struct device *dev = ipa->dev; struct gsi *gsi = &ipa->gsi; bool suspended = false; dma_addr_t addr; @@ -1769,7 +1769,7 @@ static void ipa_endpoint_reset(struct ipa_endpoint *endpoint) gsi_channel_reset(&ipa->gsi, channel_id, true); if (ret) - dev_err(&ipa->pdev->dev, + dev_err(ipa->dev, "error %d resetting channel %u for endpoint %u\n", ret, endpoint->channel_id, endpoint->endpoint_id); } @@ -1817,7 +1817,7 @@ int ipa_endpoint_enable_one(struct ipa_endpoint *endpoint) ret = gsi_channel_start(gsi, endpoint->channel_id); if (ret) { - dev_err(&ipa->pdev->dev, + dev_err(ipa->dev, "error %d starting %cX channel %u for endpoint %u\n", ret, endpoint->toward_ipa ? 'T' : 'R', endpoint->channel_id, endpoint_id); @@ -1854,14 +1854,13 @@ void ipa_endpoint_disable_one(struct ipa_endpoint *endpoint) /* Note that if stop fails, the channel's state is not well-defined */ ret = gsi_channel_stop(gsi, endpoint->channel_id); if (ret) - dev_err(&ipa->pdev->dev, - "error %d attempting to stop endpoint %u\n", ret, - endpoint_id); + dev_err(ipa->dev, "error %d attempting to stop endpoint %u\n", + ret, endpoint_id); } void ipa_endpoint_suspend_one(struct ipa_endpoint *endpoint) { - struct device *dev = &endpoint->ipa->pdev->dev; + struct device *dev = endpoint->ipa->dev; struct gsi *gsi = &endpoint->ipa->gsi; int ret; @@ -1881,7 +1880,7 @@ void ipa_endpoint_suspend_one(struct ipa_endpoint *endpoint) void ipa_endpoint_resume_one(struct ipa_endpoint *endpoint) { - struct device *dev = &endpoint->ipa->pdev->dev; + struct device *dev = endpoint->ipa->dev; struct gsi *gsi = &endpoint->ipa->gsi; int ret; @@ -1983,7 +1982,7 @@ void ipa_endpoint_deconfig(struct ipa *ipa) int ipa_endpoint_config(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; const struct reg *reg; u32 endpoint_id; u32 hw_limit; diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index 7399724160a8..c3e8784d51d9 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -110,14 +110,13 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id) struct ipa_interrupt *interrupt = dev_id; struct ipa *ipa = interrupt->ipa; u32 enabled = interrupt->enabled; + struct device *dev = ipa->dev; const struct reg *reg; - struct device *dev; u32 pending; u32 offset; u32 mask; int ret; - dev = &ipa->pdev->dev; ret = pm_runtime_get_sync(dev); if (WARN_ON(ret < 0)) goto out_power_put; @@ -240,8 +239,8 @@ void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt) int ipa_interrupt_config(struct ipa *ipa) { struct ipa_interrupt *interrupt = ipa->interrupt; - struct device *dev = &ipa->pdev->dev; unsigned int irq = interrupt->irq; + struct device *dev = ipa->dev; const struct reg *reg; int ret; @@ -281,7 +280,7 @@ err_kfree: void ipa_interrupt_deconfig(struct ipa *ipa) { struct ipa_interrupt *interrupt = ipa->interrupt; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; ipa->interrupt = NULL; diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 3125aec88e6e..57b241417e8c 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -114,7 +113,7 @@ int ipa_setup(struct ipa *ipa) { struct ipa_endpoint *exception_endpoint; struct ipa_endpoint *command_endpoint; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; int ret; ret = gsi_setup(&ipa->gsi); @@ -858,7 +857,7 @@ static int ipa_probe(struct platform_device *pdev) goto err_power_exit; } - ipa->pdev = pdev; + ipa->dev = dev; dev_set_drvdata(dev, ipa); ipa->interrupt = interrupt; ipa->power = power; @@ -953,12 +952,16 @@ err_interrupt_exit: static void ipa_remove(struct platform_device *pdev) { - struct ipa *ipa = dev_get_drvdata(&pdev->dev); - struct device *dev = &pdev->dev; struct ipa_interrupt *interrupt; struct ipa_power *power; + struct device *dev; + struct ipa *ipa; int ret; + ipa = dev_get_drvdata(&pdev->dev); + dev = ipa->dev; + WARN_ON(dev != &pdev->dev); + power = ipa->power; interrupt = ipa->interrupt; diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c index d7df7d340221..709f061ede61 100644 --- a/drivers/net/ipa/ipa_mem.c +++ b/drivers/net/ipa/ipa_mem.c @@ -88,7 +88,7 @@ int ipa_mem_setup(struct ipa *ipa) */ trans = ipa_cmd_trans_alloc(ipa, 4); if (!trans) { - dev_err(&ipa->pdev->dev, "no transaction for memory setup\n"); + dev_err(ipa->dev, "no transaction for memory setup\n"); return -EBUSY; } @@ -218,8 +218,8 @@ static bool ipa_mem_id_required(struct ipa *ipa, enum ipa_mem_id mem_id) static bool ipa_mem_valid_one(struct ipa *ipa, const struct ipa_mem *mem) { - struct device *dev = &ipa->pdev->dev; enum ipa_mem_id mem_id = mem->id; + struct device *dev = ipa->dev; u16 size_multiple; /* Make sure the memory region is valid for this version of IPA */ @@ -255,7 +255,7 @@ static bool ipa_mem_valid_one(struct ipa *ipa, const struct ipa_mem *mem) static bool ipa_mem_valid(struct ipa *ipa, const struct ipa_mem_data *mem_data) { DECLARE_BITMAP(regions, IPA_MEM_COUNT) = { }; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; enum ipa_mem_id mem_id; u32 i; @@ -291,7 +291,7 @@ static bool ipa_mem_valid(struct ipa *ipa, const struct ipa_mem_data *mem_data) /* Do all memory regions fit within the IPA local memory? */ static bool ipa_mem_size_valid(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; u32 limit = ipa->mem_size; u32 i; @@ -318,7 +318,7 @@ static bool ipa_mem_size_valid(struct ipa *ipa) */ int ipa_mem_config(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; const struct ipa_mem *mem; const struct reg *reg; dma_addr_t addr; @@ -394,7 +394,7 @@ err_dma_free: /* Inverse of ipa_mem_config() */ void ipa_mem_deconfig(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; dma_free_coherent(dev, ipa->zero_size, ipa->zero_virt, ipa->zero_addr); ipa->zero_size = 0; @@ -421,8 +421,7 @@ int ipa_mem_zero_modem(struct ipa *ipa) */ trans = ipa_cmd_trans_alloc(ipa, 3); if (!trans) { - dev_err(&ipa->pdev->dev, - "no transaction to zero modem memory\n"); + dev_err(ipa->dev, "no transaction to zero modem memory\n"); return -EBUSY; } @@ -453,7 +452,7 @@ int ipa_mem_zero_modem(struct ipa *ipa) */ static int ipa_imem_init(struct ipa *ipa, unsigned long addr, size_t size) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; struct iommu_domain *domain; unsigned long iova; phys_addr_t phys; @@ -486,13 +485,12 @@ static int ipa_imem_init(struct ipa *ipa, unsigned long addr, size_t size) static void ipa_imem_exit(struct ipa *ipa) { + struct device *dev = ipa->dev; struct iommu_domain *domain; - struct device *dev; if (!ipa->imem_size) return; - dev = &ipa->pdev->dev; domain = iommu_get_domain_for_dev(dev); if (domain) { size_t size; @@ -528,7 +526,7 @@ static void ipa_imem_exit(struct ipa *ipa) */ static int ipa_smem_init(struct ipa *ipa, u32 item, size_t size) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; struct iommu_domain *domain; unsigned long iova; phys_addr_t phys; @@ -595,7 +593,7 @@ static int ipa_smem_init(struct ipa *ipa, u32 item, size_t size) static void ipa_smem_exit(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; struct iommu_domain *domain; domain = iommu_get_domain_for_dev(dev); diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c index 1d1be92fbebc..c27ca3f27f7d 100644 --- a/drivers/net/ipa/ipa_modem.c +++ b/drivers/net/ipa/ipa_modem.c @@ -58,7 +58,7 @@ static int ipa_open(struct net_device *netdev) struct device *dev; int ret; - dev = &ipa->pdev->dev; + dev = ipa->dev; ret = pm_runtime_get_sync(dev); if (ret < 0) goto err_power_put; @@ -94,7 +94,7 @@ static int ipa_stop(struct net_device *netdev) struct device *dev; int ret; - dev = &ipa->pdev->dev; + dev = ipa->dev; ret = pm_runtime_get_sync(dev); if (ret < 0) goto out_power_put; @@ -158,7 +158,7 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev) */ netif_stop_queue(netdev); - dev = &ipa->pdev->dev; + dev = ipa->dev; ret = pm_runtime_get(dev); if (ret < 1) { /* If a resume won't happen, just drop the packet */ @@ -322,7 +322,7 @@ int ipa_modem_start(struct ipa *ipa) goto out_set_state; } - SET_NETDEV_DEV(netdev, &ipa->pdev->dev); + SET_NETDEV_DEV(netdev, ipa->dev); priv = netdev_priv(netdev); priv->ipa = ipa; priv->tx = ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]; @@ -396,7 +396,7 @@ int ipa_modem_stop(struct ipa *ipa) /* Treat a "clean" modem stop the same as a crash */ static void ipa_modem_crashed(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; int ret; /* Prevent the modem from triggering a call to ipa_setup() */ @@ -443,7 +443,7 @@ static int ipa_modem_notify(struct notifier_block *nb, unsigned long action, { struct ipa *ipa = container_of(nb, struct ipa, nb); struct qcom_ssr_notify_data *notify_data = data; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; switch (action) { case QCOM_SSR_BEFORE_POWERUP: @@ -492,7 +492,7 @@ int ipa_modem_config(struct ipa *ipa) void ipa_modem_deconfig(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; int ret; ret = qcom_unregister_ssr_notifier(ipa->notifier, &ipa->nb); diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index 0f635b8356bf..41ca7ef5e20f 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -238,7 +238,7 @@ int ipa_power_setup(struct ipa *ipa) ipa_interrupt_enable(ipa, IPA_IRQ_TX_SUSPEND); - ret = device_init_wakeup(&ipa->pdev->dev, true); + ret = device_init_wakeup(ipa->dev, true); if (ret) ipa_interrupt_disable(ipa, IPA_IRQ_TX_SUSPEND); @@ -247,7 +247,7 @@ int ipa_power_setup(struct ipa *ipa) void ipa_power_teardown(struct ipa *ipa) { - (void)device_init_wakeup(&ipa->pdev->dev, false); + (void)device_init_wakeup(ipa->dev, false); ipa_interrupt_disable(ipa, IPA_IRQ_TX_SUSPEND); } diff --git a/drivers/net/ipa/ipa_qmi.c b/drivers/net/ipa/ipa_qmi.c index f70f0a1d1cda..65c40e207802 100644 --- a/drivers/net/ipa/ipa_qmi.c +++ b/drivers/net/ipa/ipa_qmi.c @@ -96,7 +96,7 @@ static void ipa_server_init_complete(struct ipa_qmi *ipa_qmi) IPA_QMI_INIT_COMPLETE_IND_SZ, ipa_init_complete_ind_ei, &ind); if (ret) - dev_err(&ipa->pdev->dev, + dev_err(ipa->dev, "error %d sending init complete indication\n", ret); else ipa_qmi->indication_sent = true; @@ -148,7 +148,7 @@ static void ipa_qmi_ready(struct ipa_qmi *ipa_qmi) ipa = container_of(ipa_qmi, struct ipa, qmi); ret = ipa_modem_start(ipa); if (ret) - dev_err(&ipa->pdev->dev, "error %d starting modem\n", ret); + dev_err(ipa->dev, "error %d starting modem\n", ret); } /* All QMI clients from the modem node are gone (modem shut down or crashed). */ @@ -199,7 +199,7 @@ static void ipa_server_indication_register(struct qmi_handle *qmi, ipa_qmi->indication_requested = true; ipa_qmi_ready(ipa_qmi); /* We might be ready now */ } else { - dev_err(&ipa->pdev->dev, + dev_err(ipa->dev, "error %d sending register indication response\n", ret); } } @@ -228,7 +228,7 @@ static void ipa_server_driver_init_complete(struct qmi_handle *qmi, ipa_qmi->uc_ready = true; ipa_qmi_ready(ipa_qmi); /* We might be ready now */ } else { - dev_err(&ipa->pdev->dev, + dev_err(ipa->dev, "error %d sending init complete response\n", ret); } } @@ -417,7 +417,7 @@ static void ipa_client_init_driver_work(struct work_struct *work) qmi = &ipa_qmi->client_handle; ipa = container_of(ipa_qmi, struct ipa, qmi); - dev = &ipa->pdev->dev; + dev = ipa->dev; ret = qmi_txn_init(qmi, &txn, NULL, NULL); if (ret < 0) { diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c index 831268551d9a..aeccce9fab72 100644 --- a/drivers/net/ipa/ipa_smp2p.c +++ b/drivers/net/ipa/ipa_smp2p.c @@ -84,15 +84,13 @@ struct ipa_smp2p { */ static void ipa_smp2p_notify(struct ipa_smp2p *smp2p) { - struct device *dev; u32 value; u32 mask; if (smp2p->notified) return; - dev = &smp2p->ipa->pdev->dev; - smp2p->power_on = pm_runtime_get_if_active(dev, true) > 0; + smp2p->power_on = pm_runtime_get_if_active(smp2p->ipa->dev, true) > 0; /* Signal whether the IPA power is enabled */ mask = BIT(smp2p->enabled_bit); @@ -152,15 +150,16 @@ static void ipa_smp2p_panic_notifier_unregister(struct ipa_smp2p *smp2p) static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id) { struct ipa_smp2p *smp2p = dev_id; + struct ipa *ipa = smp2p->ipa; struct device *dev; int ret; /* Ignore any (spurious) interrupts received after the first */ - if (smp2p->ipa->setup_complete) + if (ipa->setup_complete) return IRQ_HANDLED; /* Power needs to be active for setup */ - dev = &smp2p->ipa->pdev->dev; + dev = ipa->dev; ret = pm_runtime_get_sync(dev); if (ret < 0) { dev_err(dev, "error %d getting power for setup\n", ret); @@ -168,7 +167,7 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id) } /* An error here won't cause driver shutdown, so warn if one occurs */ - ret = ipa_setup(smp2p->ipa); + ret = ipa_setup(ipa); WARN(ret != 0, "error %d from ipa_setup()\n", ret); out_power_put: @@ -209,7 +208,7 @@ static void ipa_smp2p_irq_exit(struct ipa_smp2p *smp2p, u32 irq) /* Drop the power reference if it was taken in ipa_smp2p_notify() */ static void ipa_smp2p_power_release(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; if (!ipa->smp2p->power_on) return; diff --git a/drivers/net/ipa/ipa_table.c b/drivers/net/ipa/ipa_table.c index 7b637bb8b41c..a24ac11b8893 100644 --- a/drivers/net/ipa/ipa_table.c +++ b/drivers/net/ipa/ipa_table.c @@ -163,7 +163,7 @@ ipa_table_mem(struct ipa *ipa, bool filter, bool hashed, bool ipv6) bool ipa_filtered_valid(struct ipa *ipa, u64 filtered) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; u32 count; if (!filtered) { @@ -236,8 +236,7 @@ ipa_filter_reset_table(struct ipa *ipa, bool hashed, bool ipv6, bool modem) trans = ipa_cmd_trans_alloc(ipa, hweight64(ep_mask)); if (!trans) { - dev_err(&ipa->pdev->dev, - "no transaction for %s filter reset\n", + dev_err(ipa->dev, "no transaction for %s filter reset\n", modem ? "modem" : "AP"); return -EBUSY; } @@ -298,8 +297,7 @@ static int ipa_route_reset(struct ipa *ipa, bool modem) trans = ipa_cmd_trans_alloc(ipa, hash_support ? 4 : 2); if (!trans) { - dev_err(&ipa->pdev->dev, - "no transaction for %s route reset\n", + dev_err(ipa->dev, "no transaction for %s route reset\n", modem ? "modem" : "AP"); return -EBUSY; } @@ -327,7 +325,7 @@ static int ipa_route_reset(struct ipa *ipa, bool modem) void ipa_table_reset(struct ipa *ipa, bool modem) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; const char *ee_name; int ret; @@ -356,7 +354,7 @@ int ipa_table_hash_flush(struct ipa *ipa) trans = ipa_cmd_trans_alloc(ipa, 1); if (!trans) { - dev_err(&ipa->pdev->dev, "no transaction for hash flush\n"); + dev_err(ipa->dev, "no transaction for hash flush\n"); return -EBUSY; } @@ -469,7 +467,7 @@ int ipa_table_setup(struct ipa *ipa) */ trans = ipa_cmd_trans_alloc(ipa, 8); if (!trans) { - dev_err(&ipa->pdev->dev, "no transaction for table setup\n"); + dev_err(ipa->dev, "no transaction for table setup\n"); return -EBUSY; } @@ -713,7 +711,7 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool filter) */ int ipa_table_init(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; dma_addr_t addr; __le64 le_addr; __le64 *virt; @@ -763,7 +761,7 @@ int ipa_table_init(struct ipa *ipa) void ipa_table_exit(struct ipa *ipa) { u32 count = max_t(u32, 1 + ipa->filter_count, ipa->route_count); - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; size_t size; size = IPA_ZERO_RULE_SIZE + (1 + count) * sizeof(__le64); diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c index 7eaa0b4ebed9..bfd5dc6dab43 100644 --- a/drivers/net/ipa/ipa_uc.c +++ b/drivers/net/ipa/ipa_uc.c @@ -127,7 +127,7 @@ static struct ipa_uc_mem_area *ipa_uc_shared(struct ipa *ipa) static void ipa_uc_event_handler(struct ipa *ipa) { struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa); - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; if (shared->event == IPA_UC_EVENT_ERROR) dev_err(dev, "microcontroller error event\n"); @@ -141,7 +141,7 @@ static void ipa_uc_event_handler(struct ipa *ipa) static void ipa_uc_response_hdlr(struct ipa *ipa) { struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa); - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; /* An INIT_COMPLETED response message is sent to the AP by the * microcontroller when it is operational. Other than this, the AP @@ -191,7 +191,7 @@ void ipa_uc_config(struct ipa *ipa) /* Inverse of ipa_uc_config() */ void ipa_uc_deconfig(struct ipa *ipa) { - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; ipa_interrupt_disable(ipa, IPA_IRQ_UC_1); ipa_interrupt_disable(ipa, IPA_IRQ_UC_0); @@ -208,8 +208,8 @@ void ipa_uc_deconfig(struct ipa *ipa) /* Take a proxy power reference for the microcontroller */ void ipa_uc_power(struct ipa *ipa) { + struct device *dev = ipa->dev; static bool already; - struct device *dev; int ret; if (already) @@ -217,7 +217,6 @@ void ipa_uc_power(struct ipa *ipa) already = true; /* Only do this on first boot */ /* This power reference dropped in ipa_uc_response_hdlr() above */ - dev = &ipa->pdev->dev; ret = pm_runtime_get_sync(dev); if (ret < 0) { pm_runtime_put_noidle(dev); From e38b117d7f3b4a5d810f6d0069ad0f643e503796 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:25 +0100 Subject: [PATCH 1752/2255] mptcp: make pm_remove_addrs_and_subflows static mptcp_pm_remove_addrs_and_subflows() is only used in pm_netlink.c, it's no longer used in pm_userspace.c any more since the commit 8b1c94da1e48 ("mptcp: only send RM_ADDR in nl_cmd_remove"). So this patch changes it to a static function. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm_netlink.c | 4 ++-- net/mptcp/protocol.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index d5a942b9ab29..80c537659922 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -1550,8 +1550,8 @@ void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list) } } -void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk, - struct list_head *rm_list) +static void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk, + struct list_head *rm_list) { struct mptcp_rm_list alist = { .nr = 0 }, slist = { .nr = 0 }; struct mptcp_pm_addr_entry *entry; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 7cb502260dea..5d034e8ca85a 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -981,8 +981,6 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk, int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list); int mptcp_pm_remove_subflow(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list); void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list); -void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk, - struct list_head *rm_list); void mptcp_free_local_addr_list(struct mptcp_sock *msk); From 34ca91e15e69917d2dbb6a76fdf8d28c5c7dc05e Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:26 +0100 Subject: [PATCH 1753/2255] mptcp: export mptcp_genl_family & mptcp_nl_fill_addr This patch exports struct mptcp_genl_family and mptcp_nl_fill_addr() helper to allow them can be used in pm_userspace.c. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm_netlink.c | 9 +++------ net/mptcp/protocol.h | 4 ++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 80c537659922..e8cb887561e0 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -18,9 +18,6 @@ #include "protocol.h" #include "mib.h" -/* forward declaration */ -static struct genl_family mptcp_genl_family; - static int pm_nl_pernet_id; struct mptcp_pm_add_entry { @@ -1636,8 +1633,8 @@ int mptcp_pm_nl_flush_addrs_doit(struct sk_buff *skb, struct genl_info *info) return 0; } -static int mptcp_nl_fill_addr(struct sk_buff *skb, - struct mptcp_pm_addr_entry *entry) +int mptcp_nl_fill_addr(struct sk_buff *skb, + struct mptcp_pm_addr_entry *entry) { struct mptcp_addr_info *addr = &entry->addr; struct nlattr *attr; @@ -2281,7 +2278,7 @@ nla_put_failure: nlmsg_free(skb); } -static struct genl_family mptcp_genl_family __ro_after_init = { +struct genl_family mptcp_genl_family __ro_after_init = { .name = MPTCP_PM_NAME, .version = MPTCP_PM_VER, .netnsok = true, diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 5d034e8ca85a..10117715c57f 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -343,6 +343,8 @@ struct mptcp_sock { #define mptcp_for_each_subflow_safe(__msk, __subflow, __tmp) \ list_for_each_entry_safe(__subflow, __tmp, &((__msk)->conn_list), node) +extern struct genl_family mptcp_genl_family; + static inline void msk_owned_by_me(const struct mptcp_sock *msk) { sock_owned_by_me((const struct sock *)msk); @@ -996,6 +998,8 @@ void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflo const struct mptcp_options_received *mp_opt); void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subflow, struct request_sock *req); +int mptcp_nl_fill_addr(struct sk_buff *skb, + struct mptcp_pm_addr_entry *entry); static inline bool mptcp_pm_should_add_signal(struct mptcp_sock *msk) { From 34e74a5cf3b7d0ab5e54725be19bd27c8b367a63 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:27 +0100 Subject: [PATCH 1754/2255] mptcp: implement mptcp_userspace_pm_dump_addr This patch implements mptcp_userspace_pm_dump_addr() to dump addresses from userspace pm address list. Use mptcp_token_get_sock() to get the msk from the given token, if userspace PM is enabled in it, traverse each address entry in address list, put every entry to userspace using mptcp_pm_nl_put_entry_msg(). Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm_userspace.c | 60 ++++++++++++++++++++++++++++++++++++++++ net/mptcp/protocol.h | 2 ++ 2 files changed, 62 insertions(+) diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index bc97cc30f013..d6b7be3afbe5 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -572,3 +572,63 @@ set_flags_err: sock_put(sk); return ret; } + +int mptcp_userspace_pm_dump_addr(struct sk_buff *msg, + struct netlink_callback *cb) +{ + struct id_bitmap { + DECLARE_BITMAP(map, MPTCP_PM_MAX_ADDR_ID + 1); + } *bitmap; + const struct genl_info *info = genl_info_dump(cb); + struct net *net = sock_net(msg->sk); + struct mptcp_pm_addr_entry *entry; + struct mptcp_sock *msk; + struct nlattr *token; + int ret = -EINVAL; + struct sock *sk; + void *hdr; + + bitmap = (struct id_bitmap *)cb->ctx; + token = info->attrs[MPTCP_PM_ATTR_TOKEN]; + + msk = mptcp_token_get_sock(net, nla_get_u32(token)); + if (!msk) { + NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token"); + return ret; + } + + sk = (struct sock *)msk; + + if (!mptcp_pm_is_userspace(msk)) { + GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected"); + goto out; + } + + lock_sock(sk); + spin_lock_bh(&msk->pm.lock); + list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) { + if (test_bit(entry->addr.id, bitmap->map)) + continue; + + hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, &mptcp_genl_family, + NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR); + if (!hdr) + break; + + if (mptcp_nl_fill_addr(msg, entry) < 0) { + genlmsg_cancel(msg, hdr); + break; + } + + __set_bit(entry->addr.id, bitmap->map); + genlmsg_end(msg, hdr); + } + spin_unlock_bh(&msk->pm.lock); + release_sock(sk); + ret = msg->len; + +out: + sock_put(sk); + return ret; +} diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 10117715c57f..829a492c8d19 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1064,6 +1064,8 @@ bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc); int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc); +int mptcp_userspace_pm_dump_addr(struct sk_buff *msg, + struct netlink_callback *cb); static inline u8 subflow_get_local_id(const struct mptcp_subflow_context *subflow) { From 9e6c88e2f05b05892113fc56fabc652ac1ee7043 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:28 +0100 Subject: [PATCH 1755/2255] mptcp: add token for get-addr in yaml This patch adds token parameter together with addr in get-addr section in mptcp_pm.yaml, then use the following commands to update mptcp_pm_gen.c and mptcp_pm_gen.h: ./tools/net/ynl/ynl-gen-c.py --mode kernel \ --spec Documentation/netlink/specs/mptcp_pm.yaml --source \ -o net/mptcp/mptcp_pm_gen.c ./tools/net/ynl/ynl-gen-c.py --mode kernel \ --spec Documentation/netlink/specs/mptcp_pm.yaml --header \ -o net/mptcp/mptcp_pm_gen.h Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- Documentation/netlink/specs/mptcp_pm.yaml | 3 ++- net/mptcp/mptcp_pm_gen.c | 7 ++++--- net/mptcp/mptcp_pm_gen.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/netlink/specs/mptcp_pm.yaml b/Documentation/netlink/specs/mptcp_pm.yaml index 49f90cfb4698..af525ed29792 100644 --- a/Documentation/netlink/specs/mptcp_pm.yaml +++ b/Documentation/netlink/specs/mptcp_pm.yaml @@ -292,13 +292,14 @@ operations: - name: get-addr doc: Get endpoint information - attribute-set: endpoint + attribute-set: attr dont-validate: [ strict ] flags: [ uns-admin-perm ] do: &get-addr-attrs request: attributes: - addr + - token reply: attributes: - addr diff --git a/net/mptcp/mptcp_pm_gen.c b/net/mptcp/mptcp_pm_gen.c index 670da7822e6c..c30a2a90a192 100644 --- a/net/mptcp/mptcp_pm_gen.c +++ b/net/mptcp/mptcp_pm_gen.c @@ -32,8 +32,9 @@ const struct nla_policy mptcp_pm_del_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1] }; /* MPTCP_PM_CMD_GET_ADDR - do */ -const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1] = { - [MPTCP_PM_ENDPOINT_ADDR] = NLA_POLICY_NESTED(mptcp_pm_address_nl_policy), +const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ATTR_TOKEN + 1] = { + [MPTCP_PM_ATTR_ADDR] = NLA_POLICY_NESTED(mptcp_pm_address_nl_policy), + [MPTCP_PM_ATTR_TOKEN] = { .type = NLA_U32, }, }; /* MPTCP_PM_CMD_FLUSH_ADDRS - do */ @@ -110,7 +111,7 @@ const struct genl_ops mptcp_pm_nl_ops[11] = { .doit = mptcp_pm_nl_get_addr_doit, .dumpit = mptcp_pm_nl_get_addr_dumpit, .policy = mptcp_pm_get_addr_nl_policy, - .maxattr = MPTCP_PM_ENDPOINT_ADDR, + .maxattr = MPTCP_PM_ATTR_TOKEN, .flags = GENL_UNS_ADMIN_PERM, }, { diff --git a/net/mptcp/mptcp_pm_gen.h b/net/mptcp/mptcp_pm_gen.h index ac9fc7225b6a..e24258f6f819 100644 --- a/net/mptcp/mptcp_pm_gen.h +++ b/net/mptcp/mptcp_pm_gen.h @@ -18,7 +18,7 @@ extern const struct nla_policy mptcp_pm_add_addr_nl_policy[MPTCP_PM_ENDPOINT_ADD extern const struct nla_policy mptcp_pm_del_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1]; -extern const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1]; +extern const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ATTR_TOKEN + 1]; extern const struct nla_policy mptcp_pm_flush_addrs_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1]; From 9ae7846c4b6b3c7ccd0c9c96012b92f443295a7d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:29 +0100 Subject: [PATCH 1756/2255] mptcp: dump addrs in userspace pm list This patch renames mptcp_pm_nl_get_addr_dumpit() as a dedicated in-kernel netlink PM dump addrs function mptcp_pm_nl_dump_addr(), and invoke a newly added wrapper mptcp_pm_dump_addr() in mptcp_pm_nl_get_addr_dumpit(). Invoke in-kernel PM dump addrs function mptcp_pm_nl_dump_addr() or userspace PM dump addrs function mptcp_userspace_pm_dump_addr() based on whether the token parameter is passed in or not in the wrapper. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm.c | 9 +++++++++ net/mptcp/pm_netlink.c | 10 ++++++++-- net/mptcp/protocol.h | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 53e0b08b1123..193198cec74a 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -441,6 +441,15 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id return mptcp_pm_nl_get_flags_and_ifindex_by_id(msk, id, flags, ifindex); } +int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb) +{ + const struct genl_info *info = genl_info_dump(cb); + + if (info->attrs[MPTCP_PM_ATTR_TOKEN]) + return mptcp_userspace_pm_dump_addr(msg, cb); + return mptcp_pm_nl_dump_addr(msg, cb); +} + int mptcp_pm_set_flags(struct net *net, struct nlattr *token, struct mptcp_pm_addr_entry *loc, struct mptcp_pm_addr_entry *rem, u8 bkup) diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index e8cb887561e0..5fae35b6b305 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -1722,8 +1722,8 @@ fail: return ret; } -int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg, - struct netlink_callback *cb) +int mptcp_pm_nl_dump_addr(struct sk_buff *msg, + struct netlink_callback *cb) { struct net *net = sock_net(msg->sk); struct mptcp_pm_addr_entry *entry; @@ -1765,6 +1765,12 @@ int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg, return msg->len; } +int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg, + struct netlink_callback *cb) +{ + return mptcp_pm_dump_addr(msg, cb); +} + static int parse_limit(struct genl_info *info, int id, unsigned int *limit) { struct nlattr *attr = info->attrs[id]; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 829a492c8d19..f23ca7645e96 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1064,6 +1064,9 @@ bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc); int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc); +int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb); +int mptcp_pm_nl_dump_addr(struct sk_buff *msg, + struct netlink_callback *cb); int mptcp_userspace_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb); From c19ee3c7e38857b7d266d09129fa509d34716ec3 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:30 +0100 Subject: [PATCH 1757/2255] mptcp: check userspace pm flags Just like MPTCP_PM_ADDR_FLAG_SIGNAL flag is checked in userspace PM announce mptcp_pm_nl_announce_doit(), PM flags should be checked in mptcp_pm_nl_subflow_create_doit() too. If MPTCP_PM_ADDR_FLAG_SUBFLOW flag is not set, there's no flags field in the output of dump_addr. This looks a bit strange: id 10 flags 10.0.3.2 This patch uses mptcp_pm_parse_entry() instead of mptcp_pm_parse_addr() to get the PM flags of the entry and check it. MPTCP_PM_ADDR_FLAG_SIGNAL flag shouldn't be set here, and if MPTCP_PM_ADDR_FLAG_SUBFLOW flag is missing from the netlink attribute, always set this flag. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm_userspace.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index d6b7be3afbe5..3bd13e94b568 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -334,7 +334,6 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR]; struct mptcp_pm_addr_entry local = { 0 }; struct mptcp_addr_info addr_r; - struct mptcp_addr_info addr_l; struct mptcp_sock *msk; int err = -EINVAL; struct sock *sk; @@ -360,25 +359,31 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) goto create_err; } - err = mptcp_pm_parse_addr(laddr, info, &addr_l); + err = mptcp_pm_parse_entry(laddr, info, true, &local); if (err < 0) { NL_SET_ERR_MSG_ATTR(info->extack, laddr, "error parsing local addr"); goto create_err; } + if (local.flags & MPTCP_PM_ADDR_FLAG_SIGNAL) { + GENL_SET_ERR_MSG(info, "invalid addr flags"); + err = -EINVAL; + goto create_err; + } + local.flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW; + err = mptcp_pm_parse_addr(raddr, info, &addr_r); if (err < 0) { NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr"); goto create_err; } - if (!mptcp_pm_addr_families_match(sk, &addr_l, &addr_r)) { + if (!mptcp_pm_addr_families_match(sk, &local.addr, &addr_r)) { GENL_SET_ERR_MSG(info, "families mismatch"); err = -EINVAL; goto create_err; } - local.addr = addr_l; err = mptcp_userspace_pm_append_new_local_addr(msk, &local, false); if (err < 0) { GENL_SET_ERR_MSG(info, "did not match address and id"); @@ -387,7 +392,7 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) lock_sock(sk); - err = __mptcp_subflow_connect(sk, &addr_l, &addr_r); + err = __mptcp_subflow_connect(sk, &local.addr, &addr_r); release_sock(sk); From 9963b77e25c63b3f1fee306a8e83e9e0b45ebad0 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:31 +0100 Subject: [PATCH 1758/2255] selftests: mptcp: add userspace pm subflow flag This patch adds the address flag MPTCP_PM_ADDR_FLAG_SUBFLOW in csf() in pm_nl_ctl.c when subflow is created by a userspace PM. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- tools/testing/selftests/net/mptcp/pm_nl_ctl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c index 49369c4a5f26..e97856323ec3 100644 --- a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c +++ b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c @@ -453,6 +453,7 @@ int csf(int fd, int pm_family, int argc, char *argv[]) char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024]; + u_int32_t flags = MPTCP_PM_ADDR_FLAG_SUBFLOW; const char *params[5]; struct nlmsghdr *nh; struct rtattr *addr; @@ -558,6 +559,13 @@ int csf(int fd, int pm_family, int argc, char *argv[]) off += NLMSG_ALIGN(rta->rta_len); } + /* addr flags */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &flags, 4); + off += NLMSG_ALIGN(rta->rta_len); + addr->rta_len = off - addr_start; } From 950c332125f66d7419a24fc933f05606ae199b40 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:32 +0100 Subject: [PATCH 1759/2255] selftests: mptcp: add token for dump_addr The command dump_addr() of pm_nl_ctl can be used like this in in-kernel PM: pm_nl_ctl dump This patch adds token argument for it to support userspace PM: pm_nl_ctl dump token $token If 'token $token' is passed to dump_addr(), copy it into the kernel netlink. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- tools/testing/selftests/net/mptcp/pm_nl_ctl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c index e97856323ec3..8d7d1b4ed28e 100644 --- a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c +++ b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c @@ -1127,8 +1127,16 @@ int dump_addrs(int fd, int pm_family, int argc, char *argv[]) 1024]; pid_t pid = getpid(); struct nlmsghdr *nh; + u_int32_t token = 0; + struct rtattr *rta; int off = 0; + if (argc != 2 && argc != 4) + syntax(argv); + + if (argc == 4 && !strcmp(argv[2], "token")) + token = strtoul(argv[3], NULL, 10); + memset(data, 0, sizeof(data)); nh = (void *)data; off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, @@ -1138,6 +1146,15 @@ int dump_addrs(int fd, int pm_family, int argc, char *argv[]) nh->nlmsg_pid = pid; nh->nlmsg_len = off; + /* token */ + if (token) { + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + } + print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); return 0; } From 2d0c1d27ea4eced07bd841d1cfccb838b437dfae Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:33 +0100 Subject: [PATCH 1760/2255] selftests: mptcp: add mptcp_lib_check_output helper Extract the main part of check() in pm_netlink.sh into a new helper named mptcp_lib_check_output in mptcp_lib.sh. This helper will be used for userspace dump addresses tests. Co-developed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- .../testing/selftests/net/mptcp/mptcp_lib.sh | 23 +++++++++++++++++++ .../testing/selftests/net/mptcp/pm_netlink.sh | 18 ++++++--------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 108a1e12436c..438f557aac90 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -319,3 +319,26 @@ mptcp_lib_wait_local_port_listen() { sleep 0.1 done } + +mptcp_lib_check_output() { + local err="${1}" + local cmd="${2}" + local expected="${3}" + local cmd_ret=0 + local out + + if ! out=$(${cmd} 2>"${err}"); then + cmd_ret=${?} + fi + + if [ ${cmd_ret} -ne 0 ]; then + mptcp_lib_print_err "[FAIL] command execution '${cmd}' stderr" + cat "${err}" + return 2 + elif [ "${out}" = "${expected}" ]; then + return 0 + else + mptcp_lib_print_err "[FAIL] expected '${expected}' got '${out}'" + return 1 + fi +} diff --git a/tools/testing/selftests/net/mptcp/pm_netlink.sh b/tools/testing/selftests/net/mptcp/pm_netlink.sh index ebfefae71e13..705106d60db5 100755 --- a/tools/testing/selftests/net/mptcp/pm_netlink.sh +++ b/tools/testing/selftests/net/mptcp/pm_netlink.sh @@ -54,21 +54,17 @@ check() local cmd="$1" local expected="$2" local msg="$3" - local out=`$cmd 2>$err` - local cmd_ret=$? + local rc=0 printf "%-50s" "$msg" - if [ $cmd_ret -ne 0 ]; then - echo "[FAIL] command execution '$cmd' stderr " - cat $err - mptcp_lib_result_fail "${msg} # error ${cmd_ret}" + mptcp_lib_check_output "${err}" "${cmd}" "${expected}" || rc=${?} + if [ ${rc} -eq 2 ]; then + mptcp_lib_result_fail "${msg} # error ${rc}" ret=1 - elif [ "$out" = "$expected" ]; then - echo "[ OK ]" + elif [ ${rc} -eq 0 ]; then + mptcp_lib_print_ok "[ OK ]" mptcp_lib_result_pass "${msg}" - else - echo -n "[FAIL] " - echo "expected '$expected' got '$out'" + elif [ ${rc} -eq 1 ]; then mptcp_lib_result_fail "${msg} # different output" ret=1 fi From 38f027fca1b724c6814fff4b8ad16b59c14a3e2a Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:34 +0100 Subject: [PATCH 1761/2255] selftests: mptcp: dump userspace addrs list This patch adds a new helper userspace_pm_dump() to dump addresses for the userspace PM. Use this helper to check whether an ID 0 subflow is listed in the output of dump command after creating an ID 0 subflow in "userspace pm create id 0 subflow" test. Dump userspace PM addresses list in "userspace pm add & remove address" test and in "userspace pm create destroy subflow" test. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- .../testing/selftests/net/mptcp/mptcp_join.sh | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 1267d5708e13..8b6430642706 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -21,6 +21,7 @@ cinfail="" cinsent="" tmpfile="" cout="" +err="" capout="" ns1="" ns2="" @@ -189,6 +190,7 @@ init() { cin=$(mktemp) cinsent=$(mktemp) cout=$(mktemp) + err=$(mktemp) evts_ns1=$(mktemp) evts_ns2=$(mktemp) @@ -204,6 +206,7 @@ cleanup() rm -f "$sin" "$sout" "$cinsent" "$cinfail" rm -f "$tmpfile" rm -rf $evts_ns1 $evts_ns2 + rm -f "$err" cleanup_partial } @@ -3356,6 +3359,50 @@ userspace_pm_rm_sf() wait_rm_sf $1 "${cnt}" } +check_output() +{ + local cmd="$1" + local expected="$2" + local msg="$3" + local rc=0 + + mptcp_lib_check_output "${err}" "${cmd}" "${expected}" || rc=${?} + if [ ${rc} -eq 2 ]; then + fail_test "fail to check output # error ${rc}" + elif [ ${rc} -eq 0 ]; then + print_ok + elif [ ${rc} -eq 1 ]; then + fail_test "fail to check output # different output" + fi +} + +# $1: ns +userspace_pm_dump() +{ + local evts=$evts_ns1 + local tk + + [ "$1" == "$ns2" ] && evts=$evts_ns2 + tk=$(mptcp_lib_evts_get_info token "$evts") + + ip netns exec $1 ./pm_nl_ctl dump token $tk +} + +userspace_pm_chk_dump_addr() +{ + local ns="${1}" + local exp="${2}" + local check="${3}" + + print_check "dump addrs ${check}" + + if mptcp_lib_kallsyms_has "mptcp_userspace_pm_dump_addr$"; then + check_output "userspace_pm_dump ${ns}" "${exp}" + else + print_skip + fi +} + userspace_tests() { # userspace pm type prevents add_addr @@ -3447,10 +3494,16 @@ userspace_tests() chk_mptcp_info subflows 2 subflows 2 chk_subflows_total 3 3 chk_mptcp_info add_addr_signal 2 add_addr_accepted 2 + userspace_pm_chk_dump_addr "${ns1}" \ + $'id 10 flags signal 10.0.2.1\nid 20 flags signal 10.0.3.1' \ + "signal" userspace_pm_rm_addr $ns1 10 userspace_pm_rm_sf $ns1 "::ffff:10.0.2.1" $SUB_ESTABLISHED + userspace_pm_chk_dump_addr "${ns1}" \ + "id 20 flags signal 10.0.3.1" "after rm_addr 10" userspace_pm_rm_addr $ns1 20 userspace_pm_rm_sf $ns1 10.0.3.1 $SUB_ESTABLISHED + userspace_pm_chk_dump_addr "${ns1}" "" "after rm_addr 20" chk_rm_nr 2 2 invert chk_mptcp_info subflows 0 subflows 0 chk_subflows_total 1 1 @@ -3471,8 +3524,14 @@ userspace_tests() chk_join_nr 1 1 1 chk_mptcp_info subflows 1 subflows 1 chk_subflows_total 2 2 + userspace_pm_chk_dump_addr "${ns2}" \ + "id 20 flags subflow 10.0.3.2" \ + "subflow" userspace_pm_rm_addr $ns2 20 userspace_pm_rm_sf $ns2 10.0.3.2 $SUB_ESTABLISHED + userspace_pm_chk_dump_addr "${ns2}" \ + "" \ + "after rm_addr 20" chk_rm_nr 1 1 chk_mptcp_info subflows 0 subflows 0 chk_subflows_total 1 1 @@ -3492,6 +3551,8 @@ userspace_tests() chk_mptcp_info subflows 0 subflows 0 chk_subflows_total 1 1 userspace_pm_add_sf $ns2 10.0.3.2 0 + userspace_pm_chk_dump_addr "${ns2}" \ + "id 0 flags subflow 10.0.3.2" "id 0 subflow" chk_join_nr 1 1 1 chk_mptcp_info subflows 1 subflows 1 chk_subflows_total 2 2 From 06afe09091ee69dc7ab058b4be9917ae59cc81e5 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:35 +0100 Subject: [PATCH 1762/2255] mptcp: add userspace_pm_lookup_addr_by_id helper Corresponding __lookup_addr_by_id() helper in the in-kernel netlink PM, this patch adds a new helper mptcp_userspace_pm_lookup_addr_by_id() to lookup the address entry with the given id on the userspace pm local address list. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm_userspace.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index 3bd13e94b568..20cbcb62cd8c 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -106,19 +106,26 @@ static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk, return -EINVAL; } +static struct mptcp_pm_addr_entry * +mptcp_userspace_pm_lookup_addr_by_id(struct mptcp_sock *msk, unsigned int id) +{ + struct mptcp_pm_addr_entry *entry; + + list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) { + if (entry->addr.id == id) + return entry; + } + return NULL; +} + int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, u8 *flags, int *ifindex) { - struct mptcp_pm_addr_entry *entry, *match = NULL; + struct mptcp_pm_addr_entry *match; spin_lock_bh(&msk->pm.lock); - list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) { - if (id == entry->addr.id) { - match = entry; - break; - } - } + match = mptcp_userspace_pm_lookup_addr_by_id(msk, id); spin_unlock_bh(&msk->pm.lock); if (match) { *flags = match->flags; @@ -261,7 +268,7 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) { struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN]; struct nlattr *id = info->attrs[MPTCP_PM_ATTR_LOC_ID]; - struct mptcp_pm_addr_entry *match = NULL; + struct mptcp_pm_addr_entry *match; struct mptcp_pm_addr_entry *entry; struct mptcp_sock *msk; LIST_HEAD(free_list); @@ -298,13 +305,7 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) lock_sock(sk); - list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) { - if (entry->addr.id == id_val) { - match = entry; - break; - } - } - + match = mptcp_userspace_pm_lookup_addr_by_id(msk, id_val); if (!match) { GENL_SET_ERR_MSG(info, "address with specified id not found"); release_sock(sk); From d32c8fb1c881478e4af8e6ac3c922d35c8ba3ca8 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:36 +0100 Subject: [PATCH 1763/2255] mptcp: implement mptcp_userspace_pm_get_addr This patch implements mptcp_userspace_pm_get_addr() to get an address from userspace pm address list according the given 'token' and 'id'. Use nla_get_u32() to get the u32 value of 'token', then pass it to mptcp_token_get_sock() to get the msk. Pass 'msk' and 'id' to the helper mptcp_userspace_pm_lookup_addr_by_id() to get the address entry. Put this entry to userspace using mptcp_pm_nl_put_entry_info(). Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm_userspace.c | 74 ++++++++++++++++++++++++++++++++++++++++ net/mptcp/protocol.h | 2 ++ 2 files changed, 76 insertions(+) diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index 20cbcb62cd8c..b9809d988693 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -638,3 +638,77 @@ out: sock_put(sk); return ret; } + +int mptcp_userspace_pm_get_addr(struct sk_buff *skb, + struct genl_info *info) +{ + struct nlattr *attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR]; + struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN]; + struct mptcp_pm_addr_entry addr, *entry; + struct net *net = sock_net(skb->sk); + struct mptcp_sock *msk; + struct sk_buff *msg; + int ret = -EINVAL; + struct sock *sk; + void *reply; + + msk = mptcp_token_get_sock(net, nla_get_u32(token)); + if (!msk) { + NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token"); + return ret; + } + + sk = (struct sock *)msk; + + if (!mptcp_pm_is_userspace(msk)) { + GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected"); + goto out; + } + + ret = mptcp_pm_parse_entry(attr, info, false, &addr); + if (ret < 0) + goto out; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto out; + } + + reply = genlmsg_put_reply(msg, info, &mptcp_genl_family, 0, + info->genlhdr->cmd); + if (!reply) { + GENL_SET_ERR_MSG(info, "not enough space in Netlink message"); + ret = -EMSGSIZE; + goto fail; + } + + lock_sock(sk); + spin_lock_bh(&msk->pm.lock); + entry = mptcp_userspace_pm_lookup_addr_by_id(msk, addr.addr.id); + if (!entry) { + GENL_SET_ERR_MSG(info, "address not found"); + ret = -EINVAL; + goto unlock_fail; + } + + ret = mptcp_nl_fill_addr(msg, entry); + if (ret) + goto unlock_fail; + + genlmsg_end(msg, reply); + ret = genlmsg_reply(msg, info); + spin_unlock_bh(&msk->pm.lock); + release_sock(sk); + sock_put(sk); + return ret; + +unlock_fail: + spin_unlock_bh(&msk->pm.lock); + release_sock(sk); +fail: + nlmsg_free(msg); +out: + sock_put(sk); + return ret; +} diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index f23ca7645e96..f848e0203e88 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1069,6 +1069,8 @@ int mptcp_pm_nl_dump_addr(struct sk_buff *msg, struct netlink_callback *cb); int mptcp_userspace_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb); +int mptcp_userspace_pm_get_addr(struct sk_buff *skb, + struct genl_info *info); static inline u8 subflow_get_local_id(const struct mptcp_subflow_context *subflow) { From 564ae6794ec5f050bb6df4446820777e7253f960 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:37 +0100 Subject: [PATCH 1764/2255] mptcp: get addr in userspace pm list This patch renames mptcp_pm_nl_get_addr_doit() as a dedicated in-kernel netlink PM get addr function mptcp_pm_nl_get_addr(). and invoke a new wrapper mptcp_pm_get_addr() in mptcp_pm_nl_get_addr_doit. If a token is gotten in the wrapper, that means a userspace PM is used. So invoke mptcp_userspace_pm_get_addr() to get addr in userspace PM list. Otherwise, invoke mptcp_pm_nl_get_addr(). Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- net/mptcp/pm.c | 7 +++++++ net/mptcp/pm_netlink.c | 7 ++++++- net/mptcp/protocol.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 193198cec74a..b4bdd92a5648 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -441,6 +441,13 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id return mptcp_pm_nl_get_flags_and_ifindex_by_id(msk, id, flags, ifindex); } +int mptcp_pm_get_addr(struct sk_buff *skb, struct genl_info *info) +{ + if (info->attrs[MPTCP_PM_ATTR_TOKEN]) + return mptcp_userspace_pm_get_addr(skb, info); + return mptcp_pm_nl_get_addr(skb, info); +} + int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb) { const struct genl_info *info = genl_info_dump(cb); diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 5fae35b6b305..16f8bd47f4b8 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -1672,7 +1672,7 @@ nla_put_failure: return -EMSGSIZE; } -int mptcp_pm_nl_get_addr_doit(struct sk_buff *skb, struct genl_info *info) +int mptcp_pm_nl_get_addr(struct sk_buff *skb, struct genl_info *info) { struct nlattr *attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR]; struct pm_nl_pernet *pernet = genl_info_pm_nl(info); @@ -1722,6 +1722,11 @@ fail: return ret; } +int mptcp_pm_nl_get_addr_doit(struct sk_buff *skb, struct genl_info *info) +{ + return mptcp_pm_get_addr(skb, info); +} + int mptcp_pm_nl_dump_addr(struct sk_buff *msg, struct netlink_callback *cb) { diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index f848e0203e88..de9f0ff6dd30 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1069,6 +1069,8 @@ int mptcp_pm_nl_dump_addr(struct sk_buff *msg, struct netlink_callback *cb); int mptcp_userspace_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb); +int mptcp_pm_get_addr(struct sk_buff *skb, struct genl_info *info); +int mptcp_pm_nl_get_addr(struct sk_buff *skb, struct genl_info *info); int mptcp_userspace_pm_get_addr(struct sk_buff *skb, struct genl_info *info); From b055671b39363ada7270b815448042aade4d60eb Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:38 +0100 Subject: [PATCH 1765/2255] selftests: mptcp: add token for get_addr The command get_addr() of pm_nl_ctl can be used like this in in-kernel PM: pm_nl_ctl get $id This patch adds token argument for it to support userspace PM: pm_nl_ctl get $id token $token If 'token $token' is passed to get_addr(), copy it into the kernel netlink. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- tools/testing/selftests/net/mptcp/pm_nl_ctl.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c index 8d7d1b4ed28e..7426a2cbd4a0 100644 --- a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c +++ b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c @@ -1087,6 +1087,7 @@ int get_addr(int fd, int pm_family, int argc, char *argv[]) 1024]; struct rtattr *rta, *nest; struct nlmsghdr *nh; + u_int32_t token = 0; int nest_start; u_int8_t id; int off = 0; @@ -1097,10 +1098,12 @@ int get_addr(int fd, int pm_family, int argc, char *argv[]) MPTCP_PM_VER); /* the only argument is the address id */ - if (argc != 3) + if (argc != 3 && argc != 5) syntax(argv); id = atoi(argv[2]); + if (argc == 5 && !strcmp(argv[3], "token")) + token = strtoul(argv[4], NULL, 10); nest_start = off; nest = (void *)(data + off); @@ -1116,6 +1119,15 @@ int get_addr(int fd, int pm_family, int argc, char *argv[]) off += NLMSG_ALIGN(rta->rta_len); nest->rta_len = off - nest_start; + /* token */ + if (token) { + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + } + print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); return 0; } From 4cc5cc7ca052c816e20ed0cbc160299b454cbb75 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Mar 2024 19:18:39 +0100 Subject: [PATCH 1766/2255] selftests: mptcp: userspace pm get addr tests This patch adds a new helper userspace_pm_get_addr() in mptcp_join.sh. In it, parse the token value from the output of 'pm_nl_ctl events', then pass it to pm_nl_ctl get_addr command. Use this helper in userspace pm dump tests. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Signed-off-by: David S. Miller --- .../testing/selftests/net/mptcp/mptcp_join.sh | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 8b6430642706..955ee651dcd5 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -3388,6 +3388,18 @@ userspace_pm_dump() ip netns exec $1 ./pm_nl_ctl dump token $tk } +# $1: ns ; $2: id +userspace_pm_get_addr() +{ + local evts=$evts_ns1 + local tk + + [ "$1" == "$ns2" ] && evts=$evts_ns2 + tk=$(mptcp_lib_evts_get_info token "$evts") + + ip netns exec $1 ./pm_nl_ctl get $2 token $tk +} + userspace_pm_chk_dump_addr() { local ns="${1}" @@ -3403,6 +3415,21 @@ userspace_pm_chk_dump_addr() fi } +userspace_pm_chk_get_addr() +{ + local ns="${1}" + local id="${2}" + local exp="${3}" + + print_check "get id ${id} addr" + + if mptcp_lib_kallsyms_has "mptcp_userspace_pm_get_addr$"; then + check_output "userspace_pm_get_addr ${ns} ${id}" "${exp}" + else + print_skip + fi +} + userspace_tests() { # userspace pm type prevents add_addr @@ -3497,6 +3524,8 @@ userspace_tests() userspace_pm_chk_dump_addr "${ns1}" \ $'id 10 flags signal 10.0.2.1\nid 20 flags signal 10.0.3.1' \ "signal" + userspace_pm_chk_get_addr "${ns1}" "10" "id 10 flags signal 10.0.2.1" + userspace_pm_chk_get_addr "${ns1}" "20" "id 20 flags signal 10.0.3.1" userspace_pm_rm_addr $ns1 10 userspace_pm_rm_sf $ns1 "::ffff:10.0.2.1" $SUB_ESTABLISHED userspace_pm_chk_dump_addr "${ns1}" \ @@ -3527,6 +3556,7 @@ userspace_tests() userspace_pm_chk_dump_addr "${ns2}" \ "id 20 flags subflow 10.0.3.2" \ "subflow" + userspace_pm_chk_get_addr "${ns2}" "20" "id 20 flags subflow 10.0.3.2" userspace_pm_rm_addr $ns2 20 userspace_pm_rm_sf $ns2 10.0.3.2 $SUB_ESTABLISHED userspace_pm_chk_dump_addr "${ns2}" \ From 01ad6b7be1d259cdf638eaed5c1b122d043f82bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Mar 2024 19:36:32 +0100 Subject: [PATCH 1767/2255] wifi: mac80211: always initialize match_auth My previous patch only initialized match_auth when the ifmgd->auth_data exists, but that was wrong, it should always be set. Fix that. Fixes: 310c8387c638 ("wifi: mac80211: clean up connection process") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/3151f5d0-c18f-413d-b34b-b94f095b947c@moroto.mountain Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240301193633.1a3fc370f211.I979dd222b3b5eb5e1437886e5f7c2355eeccb9f7@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5f2e9f5e1779..89c4165f2753 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -8129,10 +8129,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sizeof(ifmgd->s1g_capa_mask)); /* keep some setup (AP STA, channel, ...) if matching */ - if (ifmgd->auth_data) - match_auth = ether_addr_equal(ifmgd->auth_data->ap_addr, - assoc_data->ap_addr) && - ifmgd->auth_data->link_id == req->link_id; + match_auth = ifmgd->auth_data && + ether_addr_equal(ifmgd->auth_data->ap_addr, + assoc_data->ap_addr) && + ifmgd->auth_data->link_id == req->link_id; if (req->ap_mld_addr) { uapsd_supported = true; From 2a705bc314961e9b3eb8561645b7704ff278f032 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Mar 2024 19:36:33 +0100 Subject: [PATCH 1768/2255] wifi: mac80211: check link exists before use If the assoc link doesn't exist yet at this point, we cannot use it yet. This isn't normally the case, but e.g. in case of FT-DS (or just broken userspace) the link might not be set up yet and will only be created later in this function. Check that the link exists. Fixes: 310c8387c638 ("wifi: mac80211: clean up connection process") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/3151f5d0-c18f-413d-b34b-b94f095b947c@moroto.mountain Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240301193633.c886d300e90a.Ie1d5e23b2a033d934d343c37249f6f4dfddcc5fe@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 89c4165f2753..c60d23da91fe 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -8173,7 +8173,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, eth_random_addr(assoc_data->link[i].addr); sband = local->hw.wiphy->bands[link_cbss->channel->band]; - if (match_auth && i == assoc_link_id) + if (match_auth && i == assoc_link_id && link) assoc_data->link[i].conn = link->u.mgd.conn; else assoc_data->link[i].conn = From b73229331ed5dad6479cc3ae9c61d861d5c1f2a2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Mar 2024 17:54:51 +0100 Subject: [PATCH 1769/2255] wifi: mac80211: fix supported rate masking in scan We have an nl80211 attribute to mask supported rates from probe responses in scanning, e.g. for use in P2P, but in the refactoring I stopped applying this mask. Restore it. Fixes: 07095d167749 ("wifi: mac80211: start building elements in SKBs") Link: https://msgid.link/20240301175451.7ad8ab0bd90c.I46b49e4fc27fe60b75d4559c01104e55ed381c37@changeid Signed-off-by: Johannes Berg --- net/mac80211/util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 627bd5a8bda5..f810b83a390a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1216,8 +1216,8 @@ static int ieee80211_put_preq_ies_band(struct sk_buff *skb, if (band == NL80211_BAND_S1GHZ) return ieee80211_put_s1g_cap(skb, &sband->s1g_cap); - err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, 0, - WLAN_EID_SUPP_RATES); + err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, + ~rate_mask, WLAN_EID_SUPP_RATES); if (err) return err; @@ -1238,8 +1238,8 @@ static int ieee80211_put_preq_ies_band(struct sk_buff *skb, *offset = noffset; } - err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, 0, - WLAN_EID_EXT_SUPP_RATES); + err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, + ~rate_mask, WLAN_EID_EXT_SUPP_RATES); if (err) return err; From a8bca3e9371dc5e276af4168be099b2a05554c2a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 12:01:57 +0100 Subject: [PATCH 1770/2255] wifi: mac80211: track capability/opmode NSS separately We're currently tracking rx_nss for each station, and that is meant to be initialized to the capability NSS and later reduced by the operating mode notification NSS. However, we're mixing up capabilities and operating mode NSS in the same variable. This forces us to recalculate the NSS capability on operating mode notification RX, which is a bit strange; due to the previous fix I had to never keep rx_nss as zero, it also means that the capa is never taken into account properly. Fix all this by storing the capability value, that can be recalculated unconditionally whenever needed, and storing the operating mode notification NSS separately, taking it into account when assigning the final rx_nss value. Cc: stable@vger.kernel.org Fixes: dd6c064cfc3f ("wifi: mac80211: set station RX-NSS on reconfig") Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228120157.0e1c41924d1d.I0acaa234e0267227b7e3ef81a59117c8792116bc@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/rate.c | 2 +- net/mac80211/sta_info.h | 6 ++++- net/mac80211/vht.c | 46 ++++++++++++++++++-------------------- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0744113f3535..3aa96898a250 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1867,7 +1867,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, sband->band); } - ieee80211_sta_set_rx_nss(link_sta); + ieee80211_sta_init_nss(link_sta); return ret; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4bec625a84d1..32b5ac8947bd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2153,7 +2153,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta); -void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta); +void ieee80211_sta_init_nss(struct link_sta_info *link_sta); enum ieee80211_sta_rx_bandwidth ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); enum nl80211_chan_width diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 34e03b9522c8..192c5f8b9e08 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -37,7 +37,7 @@ void rate_control_rate_init(struct sta_info *sta) struct ieee80211_supported_band *sband; struct ieee80211_chanctx_conf *chanctx_conf; - ieee80211_sta_set_rx_nss(&sta->deflink); + ieee80211_sta_init_nss(&sta->deflink); if (!ref) return; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f03731a5bbee..a52fb76386d0 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -3,7 +3,7 @@ * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright(c) 2020-2023 Intel Corporation + * Copyright(c) 2020-2024 Intel Corporation */ #ifndef STA_INFO_H @@ -482,6 +482,8 @@ struct ieee80211_fragment_cache { * same for non-MLD STA. This is used as key for searching link STA * @link_id: Link ID uniquely identifying the link STA. This is 0 for non-MLD * and set to the corresponding vif LinkId for MLD STA + * @op_mode_nss: NSS limit as set by operating mode notification, or 0 + * @capa_nss: NSS limit as determined by local and peer capabilities * @link_hash_node: hash node for rhashtable * @sta: Points to the STA info * @gtk: group keys negotiated with this station, if any @@ -518,6 +520,8 @@ struct link_sta_info { u8 addr[ETH_ALEN]; u8 link_id; + u8 op_mode_nss, capa_nss; + struct rhlist_head link_hash_node; struct sta_info *sta; diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 2c475c439ba9..642891cafbaf 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -4,7 +4,7 @@ * * Portions of this file * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * Copyright (C) 2018 - 2023 Intel Corporation + * Copyright (C) 2018 - 2024 Intel Corporation */ #include @@ -541,15 +541,11 @@ ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta) return bw; } -void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta) +void ieee80211_sta_init_nss(struct link_sta_info *link_sta) { u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss; bool support_160; - /* if we received a notification already don't overwrite it */ - if (link_sta->pub->rx_nss) - return; - if (link_sta->pub->eht_cap.has_eht) { int i; const u8 *rx_nss_mcs = (void *)&link_sta->pub->eht_cap.eht_mcs_nss_supp; @@ -627,7 +623,15 @@ void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta) rx_nss = max(vht_rx_nss, ht_rx_nss); rx_nss = max(he_rx_nss, rx_nss); rx_nss = max(eht_rx_nss, rx_nss); - link_sta->pub->rx_nss = max_t(u8, 1, rx_nss); + rx_nss = max_t(u8, 1, rx_nss); + link_sta->capa_nss = rx_nss; + + /* that shouldn't be set yet, but we can handle it anyway */ + if (link_sta->op_mode_nss) + link_sta->pub->rx_nss = + min_t(u8, rx_nss, link_sta->op_mode_nss); + else + link_sta->pub->rx_nss = rx_nss; } u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, @@ -637,7 +641,7 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, enum ieee80211_sta_rx_bandwidth new_bw; struct sta_opmode_info sta_opmode = {}; u32 changed = 0; - u8 nss, cur_nss; + u8 nss; /* ignore - no support for BF yet */ if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF) @@ -647,23 +651,17 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; nss += 1; - if (link_sta->pub->rx_nss != nss) { - cur_nss = link_sta->pub->rx_nss; - /* Reset rx_nss and call ieee80211_sta_set_rx_nss() which - * will set the same to max nss value calculated based on capability. - */ - link_sta->pub->rx_nss = 0; - ieee80211_sta_set_rx_nss(link_sta); - /* Do not allow an nss change to rx_nss greater than max_nss - * negotiated and capped to APs capability during association. - */ - if (nss <= link_sta->pub->rx_nss) { - link_sta->pub->rx_nss = nss; - sta_opmode.rx_nss = nss; - changed |= IEEE80211_RC_NSS_CHANGED; - sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED; + if (link_sta->op_mode_nss != nss) { + if (nss <= link_sta->capa_nss) { + link_sta->op_mode_nss = nss; + + if (nss != link_sta->pub->rx_nss) { + link_sta->pub->rx_nss = nss; + changed |= IEEE80211_RC_NSS_CHANGED; + sta_opmode.rx_nss = link_sta->pub->rx_nss; + sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED; + } } else { - link_sta->pub->rx_nss = cur_nss; pr_warn_ratelimited("Ignoring NSS change in VHT Operating Mode Notification from %pM with invalid nss %d", link_sta->pub->addr, nss); } From 4223675d2b5912060a85e48fd8fee51207e00957 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Feb 2024 17:38:37 +0100 Subject: [PATCH 1771/2255] wifi: iwlwifi: Add missing MODULE_FIRMWARE() for *.pnvm A few models require *.pnvm files while we don't declare them via MODULE_FIRMWARE(). This resulted in the breakage of WiFi on the system that relies on the information from modinfo (e.g. openSUSE installer image). This patch adds those missing MODULE_FIRMWARE() entries for *.pnvm files. type=feature ticket=none Link: https://bugzilla.opensuse.org/show_bug.cgi?id=1207553 Signed-off-by: Takashi Iwai Link: https://msgid.link/20240228163837.4320-1-tiwai@suse.de [move to appropriate files] Signed-off-by: Miri Korenblit Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 6 ++++++ drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 2e530fc928a4..25952d0bea99 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -299,3 +299,9 @@ MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); + +MODULE_FIRMWARE("iwlwifi-so-a0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-so-a0-gf4-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ty-a0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ma-b0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ma-b0-gf4-a0.pnvm"); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 18b1f2cf08cc..072b0a5827d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -176,3 +176,5 @@ MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); + +MODULE_FIRMWARE("iwlwifi-gl-c0-fm-c0.pnvm"); From 9ad7974856926129f190ffbe3beea78460b3b7cc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 26 Feb 2024 20:34:06 +0100 Subject: [PATCH 1772/2255] wifi: cfg80211: check A-MSDU format more carefully If it looks like there's another subframe in the A-MSDU but the header isn't fully there, we can end up reading data out of bounds, only to discard later. Make this a bit more careful and check if the subframe header can even be present. Reported-by: syzbot+d050d437fe47d479d210@syzkaller.appspotmail.com Link: https://msgid.link/20240226203405.a731e2c95e38.I82ce7d8c0cc8970ce29d0a39fdc07f1ffc425be4@changeid Signed-off-by: Johannes Berg --- net/wireless/util.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index 379f742fd741..2bde8a354631 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -791,15 +791,19 @@ ieee80211_amsdu_subframe_length(void *field, u8 mesh_flags, u8 hdr_type) bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr) { - int offset = 0, remaining, subframe_len, padding; + int offset = 0, subframe_len, padding; for (offset = 0; offset < skb->len; offset += subframe_len + padding) { + int remaining = skb->len - offset; struct { __be16 len; u8 mesh_flags; } hdr; u16 len; + if (sizeof(hdr) > remaining) + return false; + if (skb_copy_bits(skb, offset + 2 * ETH_ALEN, &hdr, sizeof(hdr)) < 0) return false; @@ -807,7 +811,6 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr) mesh_hdr); subframe_len = sizeof(struct ethhdr) + len; padding = (4 - subframe_len) & 0x3; - remaining = skb->len - offset; if (subframe_len > remaining) return false; @@ -825,7 +828,7 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, { unsigned int hlen = ALIGN(extra_headroom, 4); struct sk_buff *frame = NULL; - int offset = 0, remaining; + int offset = 0; struct { struct ethhdr eth; uint8_t flags; @@ -839,10 +842,14 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, copy_len = sizeof(hdr); while (!last) { + int remaining = skb->len - offset; unsigned int subframe_len; int len, mesh_len = 0; u8 padding; + if (copy_len > remaining) + goto purge; + skb_copy_bits(skb, offset, &hdr, copy_len); if (iftype == NL80211_IFTYPE_MESH_POINT) mesh_len = __ieee80211_get_mesh_hdrlen(hdr.flags); @@ -852,7 +859,6 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, padding = (4 - subframe_len) & 0x3; /* the last MSDU has no padding */ - remaining = skb->len - offset; if (subframe_len > remaining) goto purge; /* mitigate A-MSDU aggregation injection attacks */ From 1c0d21c4b33a41be9090e73f8225813d72ac88d9 Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Tue, 27 Feb 2024 09:52:50 +0530 Subject: [PATCH 1773/2255] wifi: mac80211: remove only link keys during stopping link AP Currently while stopping a link AP, all keys from the interface were removed. However with MLO there is a requirement to free only the link keys. Add changes to remove keys which are associated with the link AP which is going to be stopped. Signed-off-by: Rameshkumar Sundaram Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240227042251.1511122-2-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3aa96898a250..bc0c1300e404 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1563,6 +1563,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_link_data *link = sdata_dereference(sdata->link[link_id], sdata); struct ieee80211_bss_conf *link_conf = link->conf; + LIST_HEAD(keys); lockdep_assert_wiphy(local->hw.wiphy); @@ -1617,7 +1618,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, link_conf->bssid_indicator = 0; __sta_info_flush(sdata, true, link_id); - ieee80211_free_keys(sdata, true); + + ieee80211_remove_link_keys(link, &keys); + if (!list_empty(&keys)) { + synchronize_net(); + ieee80211_free_key_list(local, &keys); + } link_conf->enable_beacon = false; sdata->beacon_rate_set = false; From 5fcc7c51f9e72d1e62991f8b32be4a5adf44d556 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 27 Feb 2024 09:52:51 +0530 Subject: [PATCH 1774/2255] wifi: mac80211: handle netif carrier up/down with link AP during MLO Currently whenever link AP is started, netif_carrier_up() function is called and whenever it is brought down, netif_carrier_down() function is called. However, with MLO, all the links of the same MLD would use the same netdev. Hence there is no need to indicate for each link up/down. Also, calling it down when only one of the links went down is not desirable. Add changes to call the netif_carrier_up() function only when first link is brought up. Similarly, add changes to call the netif_carrier_down() function only when last link is brought down. In order to check the number of beaconing links in the given interface, introduce a new helper function ieee80211_num_beaconing_links(). Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240227042251.1511122-3-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index bc0c1300e404..734368fd3f97 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1241,6 +1241,30 @@ ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, return 0; } +static u8 ieee80211_num_beaconing_links(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_link_data *link; + u8 link_id, num = 0; + + if (sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_P2P_GO) + return num; + + if (!sdata->vif.valid_links) + return num; + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + continue; + + if (sdata_dereference(link->u.ap.beacon, sdata)) + num++; + } + + return num; +} + static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *params) { @@ -1470,7 +1494,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_SSID); ieee80211_link_info_change_notify(sdata, link, changed); - netif_carrier_on(dev); + if (ieee80211_num_beaconing_links(sdata) <= 1) + netif_carrier_on(dev); + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) netif_carrier_on(vlan->dev); @@ -1592,7 +1618,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, /* turn off carrier for this interface and dependent VLANs */ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) netif_carrier_off(vlan->dev); - netif_carrier_off(dev); + + if (ieee80211_num_beaconing_links(sdata) <= 1) + netif_carrier_off(dev); /* remove beacon and probe response */ sdata->u.ap.active = false; From bf7bc8c5974b78a09f266be3a5a84ed3865f30a6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:40:51 +0100 Subject: [PATCH 1775/2255] wifi: mac80211: don't add VHT capa on links without them When a link doesn't have VHT capability, before the rework we'd have set IEEE80211_CONN_DISABLE_VHT, but now with the linear progression of 'mode', we no longer have that. Add an explicit check for VHT being supported, so we don't add a zeroed VHT capabilities element where it shouldn't be. Fixes: 310c8387c638 ("wifi: mac80211: clean up connection process") Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094207.bfe4283bcde7.Ib70a558bc6bdbcec3d9e663079229dfcc2493682@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c60d23da91fe..a2dca15d9c2e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1319,7 +1319,8 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, offset); if (sband->band != NL80211_BAND_6GHZ && - assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_VHT) { + assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_VHT && + sband->vht_cap.vht_supported) { bool mu_mimo_owner = ieee80211_add_vht_ie(sdata, skb, sband, &assoc_data->link[link_id].ap_vht_cap, From 7d8b02592d528b073805af752458a589862b5eb0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:40:52 +0100 Subject: [PATCH 1776/2255] wifi: mac80211: obtain AP HT/VHT data for assoc request In the association request, we make some parameters depend on the AP's HT/VHT information. This was broken by my code because it no longer filled that information, making it all zero. For HT that meant we wouldn't reduce our capabilities to 20 MHz if needed, and for VHT we lost beamforming capabilities. Fix this. It seems like it may even have been broken for all but the assoc link before. Fixes: 310c8387c638 ("wifi: mac80211: clean up connection process") Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094207.7dc812c2060a.Ibd591f9c214b4e166cf7171db3cf63bda8e3c9fd@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a2dca15d9c2e..2c72d4d0fc25 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -8049,6 +8049,67 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, } } +static int +ieee80211_mgd_get_ap_ht_vht_capa(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_assoc_data *assoc_data, + int link_id) +{ + struct cfg80211_bss *cbss = assoc_data->link[link_id].bss; + enum nl80211_band band = cbss->channel->band; + struct ieee80211_supported_band *sband; + const struct element *elem; + int err; + + /* neither HT nor VHT elements used on 6 GHz */ + if (band == NL80211_BAND_6GHZ) + return 0; + + if (assoc_data->link[link_id].conn.mode < IEEE80211_CONN_MODE_HT) + return 0; + + rcu_read_lock(); + elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_OPERATION); + if (!elem || elem->datalen < sizeof(struct ieee80211_ht_operation)) { + mlme_link_id_dbg(sdata, link_id, "no HT operation on BSS %pM\n", + cbss->bssid); + err = -EINVAL; + goto out_rcu; + } + assoc_data->link[link_id].ap_ht_param = + ((struct ieee80211_ht_operation *)(elem->data))->ht_param; + rcu_read_unlock(); + + if (assoc_data->link[link_id].conn.mode < IEEE80211_CONN_MODE_VHT) + return 0; + + /* some drivers want to support VHT on 2.4 GHz even */ + sband = sdata->local->hw.wiphy->bands[band]; + if (!sband->vht_cap.vht_supported) + return 0; + + rcu_read_lock(); + elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); + /* but even then accept it not being present on the AP */ + if (!elem && band == NL80211_BAND_2GHZ) { + err = 0; + goto out_rcu; + } + if (!elem || elem->datalen < sizeof(struct ieee80211_vht_cap)) { + mlme_link_id_dbg(sdata, link_id, "no VHT capa on BSS %pM\n", + cbss->bssid); + err = -EINVAL; + goto out_rcu; + } + memcpy(&assoc_data->link[link_id].ap_vht_cap, elem->data, + sizeof(struct ieee80211_vht_cap)); + rcu_read_unlock(); + + return 0; +out_rcu: + rcu_read_unlock(); + return err; +} + int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { @@ -8193,6 +8254,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, req->links[i].error = err; goto err_free; } + + err = ieee80211_mgd_get_ap_ht_vht_capa(sdata, + assoc_data, i); + if (err) { + err = -EINVAL; + req->links[i].error = err; + goto err_free; + } } assoc_data->wmm = true; @@ -8228,6 +8297,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, &assoc_data->link[0].conn); uapsd_supported = bss->uapsd_supported; + + err = ieee80211_mgd_get_ap_ht_vht_capa(sdata, assoc_data, 0); + if (err) + goto err_free; } assoc_data->spp_amsdu = req->flags & ASSOC_REQ_SPP_AMSDU; From 0ef05e258b5e15c254534d9dd382ad4c3173dce0 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Fri, 1 Mar 2024 17:22:29 -0800 Subject: [PATCH 1777/2255] bpf, docs: Rename legacy conformance group to packet There could be other legacy conformance groups in the future, so use a more descriptive name. The status of the conformance group in the IANA registry is what designates it as legacy, not the name of the group. Signed-off-by: Dave Thaler Link: https://lore.kernel.org/r/20240302012229.16452-1-dthaler1968@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- Documentation/bpf/standardization/instruction-set.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index ffcba257e004..a5ab00ac0b14 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -127,7 +127,7 @@ This document defines the following conformance groups: * divmul32: includes 32-bit division, multiplication, and modulo instructions. * divmul64: includes divmul32, plus 64-bit division, multiplication, and modulo instructions. -* legacy: deprecated packet access instructions. +* packet: deprecated packet access instructions. Instruction encoding ==================== @@ -710,4 +710,4 @@ class of ``LD``, a size modifier of ``W``, ``H``, or ``B``, and a mode modifier of ``ABS`` or ``IND``. The 'dst_reg' and 'offset' fields were set to zero, and 'src_reg' was set to zero for ``ABS``. However, these instructions are deprecated and should no longer be used. All legacy packet -access instructions belong to the "legacy" conformance group. +access instructions belong to the "packet" conformance group. From b2edc721716f44e2a7e46eb592321960a1227c7b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:42:54 +0100 Subject: [PATCH 1778/2255] wifi: cfg80211: print flags in tracing in hex It's confusing to see decimal, e.g. 20, here. Printing the flags in hex (0x14 == 20) is much clearer. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094254.5f7f4ab2e137.Id5e665104bbc51377b4591289e32f8c1d4711dce@changeid Signed-off-by: Johannes Berg --- net/wireless/trace.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 361331c29116..e039e66ab377 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -818,8 +818,8 @@ DECLARE_EVENT_CLASS(station_add_change, params->link_sta_params.opmode_notif_used; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: %pM" - ", station flags mask: %u, station flags set: %u, " - "station modify mask: %u, listen interval: %d, aid: %u, " + ", station flags mask: 0x%x, station flags set: 0x%x, " + "station modify mask: 0x%x, listen interval: %d, aid: %u, " "plink action: %u, plink state: %u, uapsd queues: %u, vlan:%s", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sta_mac, __entry->sta_flags_mask, __entry->sta_flags_set, @@ -1075,7 +1075,7 @@ TRACE_EVENT(rdev_return_int_mpath_info, ), TP_printk(WIPHY_PR_FMT ", returned %d. mpath info - generation: %d, " "filled: %u, frame qlen: %u, sn: %u, metric: %u, exptime: %u," - " discovery timeout: %u, discovery retries: %u, flags: %u", + " discovery timeout: %u, discovery retries: %u, flags: 0x%x", WIPHY_PR_ARG, __entry->ret, __entry->generation, __entry->filled, __entry->frame_qlen, __entry->sn, __entry->metric, __entry->exptime, __entry->discovery_timeout, @@ -1317,7 +1317,7 @@ TRACE_EVENT(rdev_assoc, req->fils_nonces, 2 * FILS_NONCE_LEN); ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: %pM" - ", previous bssid: %pM, use mfp: %s, flags: %u", + ", previous bssid: %pM, use mfp: %s, flags: 0x%x", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->bssid, __entry->prev_bssid, BOOL_TO_STR(__entry->use_mfp), __entry->flags) @@ -1439,7 +1439,7 @@ TRACE_EVENT(rdev_connect, ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: %pM" ", ssid: %s, auth type: %d, privacy: %s, wpa versions: %u, " - "flags: %u, previous bssid: %pM", + "flags: 0x%x, previous bssid: %pM", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->bssid, __entry->ssid, __entry->auth_type, BOOL_TO_STR(__entry->privacy), __entry->wpa_versions, __entry->flags, __entry->prev_bssid) From 04577bfa99ac8cfb7a43dbbba09584e0b1086cee Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Wed, 28 Feb 2024 09:44:56 +0100 Subject: [PATCH 1779/2255] wifi: mac80211: add link id to ieee80211_gtk_rekey_add() In MLO, we need the link id in the GTK key to be given by the driver after rekeying in wowlan, so add that. Signed-off-by: Shaul Triebitz Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094500.ce1bfc83a680.I43a6f8ab2804ee07116a37d5b9ec601b843464b1@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 12 +++++++----- include/net/mac80211.h | 4 +++- net/mac80211/key.c | 16 ++++++++++++---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 6d5ed79b9fff..ca2c6d0b605e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1976,6 +1976,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, } conf = { .conf.cipher = gtk_cipher, }; + int link_id = vif->active_links ? __ffs(vif->active_links) : -1; BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); @@ -2009,7 +2010,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, memcpy(conf.conf.key, status->gtk[i].key, sizeof(status->gtk[i].key)); - key = ieee80211_gtk_rekey_add(vif, &conf.conf); + key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); if (IS_ERR(key)) return false; @@ -2040,6 +2041,7 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, .conf.keyidx = key_data->id, }; struct ieee80211_key_seq seq; + int link_id = vif->active_links ? __ffs(vif->active_links) : -1; if (!key_data->len) return true; @@ -2065,17 +2067,17 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - key_config = ieee80211_gtk_rekey_add(vif, &conf.conf); + key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); if (IS_ERR(key_config)) return false; ieee80211_set_key_rx_seq(key_config, 0, &seq); if (key_config->keyidx == 4 || key_config->keyidx == 5) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int link_id = vif->active_links ? __ffs(vif->active_links) : 0; - struct iwl_mvm_vif_link_info *mvm_link = - mvmvif->link[link_id]; + struct iwl_mvm_vif_link_info *mvm_link; + link_id = link_id < 0 ? 0 : link_id; + mvm_link = mvmvif->link[link_id]; mvm_link->igtk = key_config; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 56c6ecb2c10a..34d66d0a24b1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5912,6 +5912,7 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf); * ieee80211_gtk_rekey_add - add a GTK key from rekeying during WoWLAN * @vif: the virtual interface to add the key on * @keyconf: new key data + * @link_id: the link id of the key or -1 for non-MLO * * When GTK rekeying was done while the system was suspended, (a) new * key(s) will be available. These will be needed by mac80211 for proper @@ -5939,7 +5940,8 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf); */ struct ieee80211_key_conf * ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf); + struct ieee80211_key_conf *keyconf, + int link_id); /** * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying diff --git a/net/mac80211/key.c b/net/mac80211/key.c index a2cce62c97b7..eecdd2265eaa 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -6,7 +6,7 @@ * Copyright 2007-2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright 2018-2020, 2022-2023 Intel Corporation + * Copyright 2018-2020, 2022-2024 Intel Corporation */ #include @@ -1372,12 +1372,19 @@ EXPORT_SYMBOL_GPL(ieee80211_remove_key); struct ieee80211_key_conf * ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf) + struct ieee80211_key_conf *keyconf, + int link_id) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; struct ieee80211_key *key; int err; + struct ieee80211_link_data *link_data = + link_id < 0 ? &sdata->deflink : + sdata_dereference(sdata->link[link_id], sdata); + + if (WARN_ON(!link_data)) + return ERR_PTR(-EINVAL); if (WARN_ON(!local->wowlan)) return ERR_PTR(-EINVAL); @@ -1394,8 +1401,9 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; - /* FIXME: this function needs to get a link ID */ - err = ieee80211_key_link(key, &sdata->deflink, NULL); + key->conf.link_id = link_id; + + err = ieee80211_key_link(key, link_data, NULL); if (err) return ERR_PTR(err); From ddf82e752f8a3253e03fe4c0a957792701f8b2e6 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 28 Feb 2024 09:47:39 +0100 Subject: [PATCH 1780/2255] wifi: mac80211: Allow beacons to update BSS table regardless of scan When a beacon is received use it to update the BSS table regardless of the scanning state. Do so only when there are active non-monitor interfaces. Also, while at it, in any case accept beacons only with broadcast address. Reviewed-by: Miriam Rachel Korenblit Signed-off-by: Ilan Peer Link: https://msgid.link/20240228094742.e508605f495b.I3ab24ab3543319e31165111b28bcdcc622b5cf02@changeid Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index bca2a259fda6..0429e59ba387 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -257,7 +257,6 @@ static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_sub_if_data *sdata1, *sdata2; struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_bss *bss; struct ieee80211_channel *channel; @@ -281,12 +280,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) if (skb->len < min_hdr_len) return; - sdata1 = rcu_dereference(local->scan_sdata); - sdata2 = rcu_dereference(local->sched_scan_sdata); - - if (likely(!sdata1 && !sdata2)) - return; - if (test_and_clear_bit(SCAN_BEACON_WAIT, &local->scanning)) { /* * we were passive scanning because of radar/no-IR, but @@ -304,10 +297,17 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) return; if (ieee80211_is_probe_resp(mgmt->frame_control)) { + struct ieee80211_sub_if_data *sdata1, *sdata2; struct cfg80211_scan_request *scan_req; struct cfg80211_sched_scan_request *sched_scan_req; u32 scan_req_flags = 0, sched_scan_req_flags = 0; + sdata1 = rcu_dereference(local->scan_sdata); + sdata2 = rcu_dereference(local->sched_scan_sdata); + + if (likely(!sdata1 && !sdata2)) + return; + scan_req = rcu_dereference(local->scan_req); sched_scan_req = rcu_dereference(local->sched_scan_req); @@ -327,8 +327,16 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) sched_scan_req_flags, mgmt->da)) return; + } else { + /* Beacons are expected only with broadcast address */ + if (!is_broadcast_ether_addr(mgmt->da)) + return; } + /* Do not update the BSS table in case of only monitor interfaces */ + if (local->open_count == local->monitors) + return; + bss = ieee80211_bss_info_update(local, rx_status, mgmt, skb->len, channel); From 0e3a22389defd20215657f0442ae109b160f2eee Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 28 Feb 2024 09:47:54 +0100 Subject: [PATCH 1781/2255] wifi: mac80211: Adjust CQM handling for MLO The CQM handling did not consider the MLO case and thus notified a not-existing link with the CQM change. To fix this, propagate the CQM notification to all the active links (handling both the non-MLO and MLO cases). TODO: this currently propagates the same configuration to all links regardless of the band. This might not be the correct approach as different links might need to be configured with different values. Signed-off-by: Ilan Peer Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094753.bf6a3fefe553.Id738810b73e1087e01d5885508b70a3631707627@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 79 +++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 734368fd3f97..b9c1ec2f9cfc 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3290,33 +3290,57 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, return 0; } +static void ieee80211_set_cqm_rssi_link(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, + s32 rssi_thold, u32 rssi_hyst, + s32 rssi_low, s32 rssi_high) +{ + struct ieee80211_bss_conf *conf; + + if (!link || !link->conf) + return; + + conf = link->conf; + + if (rssi_thold && rssi_hyst && + rssi_thold == conf->cqm_rssi_thold && + rssi_hyst == conf->cqm_rssi_hyst) + return; + + conf->cqm_rssi_thold = rssi_thold; + conf->cqm_rssi_hyst = rssi_hyst; + conf->cqm_rssi_low = rssi_low; + conf->cqm_rssi_high = rssi_high; + link->u.mgd.last_cqm_event_signal = 0; + + if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) + return; + + if (sdata->u.mgd.associated && + (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) + ieee80211_link_info_change_notify(sdata, link, BSS_CHANGED_CQM); +} + static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev, s32 rssi_thold, u32 rssi_hyst) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_vif *vif = &sdata->vif; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + int link_id; - if (rssi_thold == bss_conf->cqm_rssi_thold && - rssi_hyst == bss_conf->cqm_rssi_hyst) - return 0; - - if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER && - !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) + if (vif->driver_flags & IEEE80211_VIF_BEACON_FILTER && + !(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) return -EOPNOTSUPP; - bss_conf->cqm_rssi_thold = rssi_thold; - bss_conf->cqm_rssi_hyst = rssi_hyst; - bss_conf->cqm_rssi_low = 0; - bss_conf->cqm_rssi_high = 0; - sdata->deflink.u.mgd.last_cqm_event_signal = 0; + /* For MLD, handle CQM change on all the active links */ + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + struct ieee80211_link_data *link = + sdata_dereference(sdata->link[link_id], sdata); - /* tell the driver upon association, unless already associated */ - if (sdata->u.mgd.associated && - sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_link_info_change_notify(sdata, &sdata->deflink, - BSS_CHANGED_CQM); + ieee80211_set_cqm_rssi_link(sdata, link, rssi_thold, rssi_hyst, + 0, 0); + } return 0; } @@ -3327,22 +3351,19 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_vif *vif = &sdata->vif; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + int link_id; - if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) + if (vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) return -EOPNOTSUPP; - bss_conf->cqm_rssi_low = rssi_low; - bss_conf->cqm_rssi_high = rssi_high; - bss_conf->cqm_rssi_thold = 0; - bss_conf->cqm_rssi_hyst = 0; - sdata->deflink.u.mgd.last_cqm_event_signal = 0; + /* For MLD, handle CQM change on all the active links */ + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + struct ieee80211_link_data *link = + sdata_dereference(sdata->link[link_id], sdata); - /* tell the driver upon association, unless already associated */ - if (sdata->u.mgd.associated && - sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_link_info_change_notify(sdata, &sdata->deflink, - BSS_CHANGED_CQM); + ieee80211_set_cqm_rssi_link(sdata, link, 0, 0, + rssi_low, rssi_high); + } return 0; } From 6810ee918d23f67170f127a848cf30c257adcaff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:09 +0100 Subject: [PATCH 1782/2255] wifi: mac80211: update scratch_pos after defrag The scratch_pos update here was lost after defrag, so any other uses of the scratch buffer might overwrite it. Fixes: a286de1aa38f ("wifi: mac80211: Rename multi_link") Reviewed-by: Benjamin Berg Reviewed-by: Ilan Peer Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094901.9da35f39eeb7.I7127f2918ec4cba416fcbc35eacaea10262c1268@changeid Signed-off-by: Johannes Berg --- net/mac80211/parse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 196a882e4c19..233c761823d3 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -800,6 +800,7 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, elems->ml_basic = (const void *)elems->scratch_pos; elems->ml_basic_len = ml_len; + elems->scratch_pos += ml_len; ieee80211_mle_get_sta_prof(elems, params->link_id); prof = elems->prof; From 0217972f9684b924b2cbd9219e5ed8c53564782b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:10 +0100 Subject: [PATCH 1783/2255] wifi: mac80211: remove unnecessary ML element type check At this point, since it's taken from elems->ml_basic which is stored only if it's of type basic, we don't really need to check again if it's basic. Reviewed-by: Ilan Peer Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094901.ad1d4a09a6eb.Ib96fa75b1a6db21dd4182dcfa11fe9aff78fa3ed@changeid Signed-off-by: Johannes Berg --- net/mac80211/parse.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 233c761823d3..ae0f14bd952a 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -723,10 +723,6 @@ static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, if (!ml || !ml_len) return; - if (le16_get_bits(ml->control, IEEE80211_ML_CONTROL_TYPE) != - IEEE80211_ML_CONTROL_TYPE_BASIC) - return; - for_each_mle_subelement(sub, (u8 *)ml, ml_len) { struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; ssize_t sta_prof_len; From 68f6c6afbcebdc3acdc6084abfe453f4cba6b9dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:11 +0100 Subject: [PATCH 1784/2255] wifi: mac80211: add ieee80211_vif_link_active() helper We sometimes need to check if a link is active, and this is complicated by the fact that active_links has no bits set when the vif isn't (acting as) an MLD. Add a small new helper ieee80211_vif_link_active() to make that a bit easier, and use it in a few places. Reviewed-by: Ilan Peer Reviewed-by: Emmanuel Grumbach Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094901.688760aff5f7.I06892a503f5ecb9563fbd678d35d08daf7a044b0@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 15 +++++++++++++++ net/mac80211/cfg.c | 3 +-- net/mac80211/chan.c | 3 +-- net/mac80211/driver-ops.c | 14 +++++--------- net/mac80211/util.c | 3 +-- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 34d66d0a24b1..6c6d8210d637 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2011,6 +2011,21 @@ static inline bool ieee80211_vif_is_mld(const struct ieee80211_vif *vif) return vif->valid_links != 0; } +/** + * ieee80211_vif_link_active - check if a given link is active + * @vif: the vif + * @link_id: the link ID to check + * Return: %true if the vif is an MLD and the link is active, or if + * the vif is not an MLD and the link ID is 0; %false otherwise. + */ +static inline bool ieee80211_vif_link_active(const struct ieee80211_vif *vif, + unsigned int link_id) +{ + if (!ieee80211_vif_is_mld(vif)) + return link_id == 0; + return vif->active_links & BIT(link_id); +} + #define for_each_vif_active_link(vif, link, link_id) \ for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \ if ((!(vif)->active_links || \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b9c1ec2f9cfc..358593eeb500 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3189,8 +3189,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) return -EINVAL; - if (ieee80211_vif_is_mld(&sdata->vif) && - !(sdata->vif.active_links & BIT(link->link_id))) + if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) return 0; old_req = link->u.mgd.req_smps; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 38acdc458c7c..80e4b9784131 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1701,8 +1701,7 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link, lockdep_assert_wiphy(local->hw.wiphy); - if (sdata->vif.active_links && - !(sdata->vif.active_links & BIT(link->link_id))) { + if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) { ieee80211_link_update_chanreq(link, chanreq); return 0; } diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index 3b7f70073fc3..dce37ba8ebe3 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2015 Intel Deutschland GmbH - * Copyright (C) 2022-2023 Intel Corporation + * Copyright (C) 2022-2024 Intel Corporation */ #include #include "ieee80211_i.h" @@ -214,8 +214,7 @@ int drv_conf_tx(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - if (sdata->vif.active_links && - !(sdata->vif.active_links & BIT(link->link_id))) + if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) return 0; if (params->cw_min == 0 || params->cw_min > params->cw_max) { @@ -315,8 +314,7 @@ int drv_assign_vif_chanctx(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - if (sdata->vif.active_links && - !(sdata->vif.active_links & BIT(link_conf->link_id))) + if (!ieee80211_vif_link_active(&sdata->vif, link_conf->link_id)) return 0; trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx); @@ -343,8 +341,7 @@ void drv_unassign_vif_chanctx(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - if (sdata->vif.active_links && - !(sdata->vif.active_links & BIT(link_conf->link_id))) + if (!ieee80211_vif_link_active(&sdata->vif, link_conf->link_id)) return; trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx); @@ -461,8 +458,7 @@ void drv_link_info_changed(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - if (sdata->vif.active_links && - !(sdata->vif.active_links & BIT(link_id))) + if (!ieee80211_vif_link_active(&sdata->vif, link_id)) return; trace_drv_link_info_changed(local, sdata, info, changed); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f810b83a390a..a237cbcf7b49 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1935,8 +1935,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) { - if (ieee80211_vif_is_mld(&sdata->vif) && - !(sdata->vif.active_links & BIT(link_id))) + if (!ieee80211_vif_link_active(&sdata->vif, link_id)) continue; link = sdata_dereference(sdata->link[link_id], sdata); From 2015d2d6391bf08115566c80fe2964b434cf0681 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:12 +0100 Subject: [PATCH 1785/2255] wifi: mac80211: remove unnecessary ML element checks Given the prior changes to ieee80211_mle_size_ok(), we can now pass NULL to for_each_mle_subelement(), so no longer need to check for that here explicitly. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094901.9e32c4b63875.Ia2ee0aafdc8a48bd21b485cc36a9866f950d781b@changeid Signed-off-by: Johannes Berg --- net/mac80211/parse.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index ae0f14bd952a..d231aaecc219 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -720,9 +720,6 @@ static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, ssize_t ml_len = elems->ml_basic_len; const struct element *sub; - if (!ml || !ml_len) - return; - for_each_mle_subelement(sub, (u8 *)ml, ml_len) { struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; ssize_t sta_prof_len; From 508c423d9444a5eeeebd66fcff19ebe346a05150 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:13 +0100 Subject: [PATCH 1786/2255] wifi: mac80211: simplify multi-link element parsing We shouldn't assign elems->ml_basic{,len} before defragmentation, and we don't need elems->ml_reconf{,len} at all since we don't do defragmentation. Clean that up a bit. This does require always defragmention even when it may not be needed, but that's easier to reason about. Reviewed-by: Ilan Peer Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094902.e0115da4d2a6.I89a80f7387eabef8df3955485d4a583ed024c5b1@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 6 ++---- net/mac80211/mlme.c | 6 ++---- net/mac80211/parse.c | 12 ++++-------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 32b5ac8947bd..26cf24a31583 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1736,7 +1736,6 @@ struct ieee802_11_elems { const struct ieee80211_eht_cap_elem *eht_cap; const struct ieee80211_eht_operation *eht_operation; const struct ieee80211_multi_link_elem *ml_basic; - const struct ieee80211_multi_link_elem *ml_reconf; const struct ieee80211_bandwidth_indication *bandwidth_indication; const struct ieee80211_ttlm_elem *ttlm[IEEE80211_TTLM_MAX_CNT]; @@ -1764,12 +1763,11 @@ struct ieee802_11_elems { /* mult-link element can be de-fragmented and thus u8 is not sufficient */ size_t ml_basic_len; - size_t ml_reconf_len; - /* The basic Multi-Link element in the original IEs */ + /* The basic Multi-Link element in the original elements */ const struct element *ml_basic_elem; - /* The reconfiguration Multi-Link element in the original IEs */ + /* The reconfiguration Multi-Link element in the original elements */ const struct element *ml_reconf_elem; u8 ttlm_num; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2c72d4d0fc25..3be4f4cf12c3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5760,7 +5760,7 @@ static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata, u8 link_id; u32 delay; - if (!ieee80211_vif_is_mld(&sdata->vif) || !elems->ml_reconf) + if (!ieee80211_vif_is_mld(&sdata->vif) || !elems->ml_reconf_elem) return; ml_len = cfg80211_defragment_element(elems->ml_reconf_elem, @@ -5773,9 +5773,7 @@ static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata, if (ml_len < 0) return; - elems->ml_reconf = (const void *)elems->scratch_pos; - elems->ml_reconf_len = ml_len; - ml = elems->ml_reconf; + ml = (const void *)elems->scratch_pos; /* Directly parse the sub elements as the common information doesn't * hold any useful information. diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index d231aaecc219..8bdf6e7efa58 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -129,19 +129,15 @@ ieee80211_parse_extension_element(u32 *crc, switch (le16_get_bits(mle->control, IEEE80211_ML_CONTROL_TYPE)) { case IEEE80211_ML_CONTROL_TYPE_BASIC: - if (elems->ml_basic) { + if (elems->ml_basic_elem) { elems->parse_error |= IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC; break; } elems->ml_basic_elem = (void *)elem; - elems->ml_basic = data; - elems->ml_basic_len = len; break; case IEEE80211_ML_CONTROL_TYPE_RECONF: elems->ml_reconf_elem = (void *)elem; - elems->ml_reconf = data; - elems->ml_reconf_len = len; break; default: break; @@ -776,9 +772,6 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, const struct element *non_inherit = NULL; const u8 *end; - if (params->link_id == -1) - return; - ml_len = cfg80211_defragment_element(elems->ml_basic_elem, elems->ie_start, elems->total_len, @@ -795,6 +788,9 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, elems->ml_basic_len = ml_len; elems->scratch_pos += ml_len; + if (params->link_id == -1) + return; + ieee80211_mle_get_sta_prof(elems, params->link_id); prof = elems->prof; From 4d70e9c5488dd57ff5fcabe4d4ecf3d9dd4555ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:14 +0100 Subject: [PATCH 1787/2255] wifi: mac80211: defragment reconfiguration MLE when parsing Using the scratch buffer (without advancing it) here in the mlme.c code seems somewhat wrong, defragment the reconfig multi-link element already when parsing. This might be a bit more work in certain cases, but makes the whole thing more regular. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094902.92936a3ce216.I4b736ce4fdc199fa1d6b00d00032f448c873a8b4@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/mlme.c | 19 +++---------------- net/mac80211/parse.c | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 26cf24a31583..caee68cc8f14 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1736,6 +1736,7 @@ struct ieee802_11_elems { const struct ieee80211_eht_cap_elem *eht_cap; const struct ieee80211_eht_operation *eht_operation; const struct ieee80211_multi_link_elem *ml_basic; + const struct ieee80211_multi_link_elem *ml_reconf; const struct ieee80211_bandwidth_indication *bandwidth_indication; const struct ieee80211_ttlm_elem *ttlm[IEEE80211_TTLM_MAX_CNT]; @@ -1763,6 +1764,7 @@ struct ieee802_11_elems { /* mult-link element can be de-fragmented and thus u8 is not sufficient */ size_t ml_basic_len; + size_t ml_reconf_len; /* The basic Multi-Link element in the original elements */ const struct element *ml_basic_elem; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3be4f4cf12c3..90e505778db6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5752,33 +5752,20 @@ out: static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems) { - const struct ieee80211_multi_link_elem *ml; const struct element *sub; - ssize_t ml_len; unsigned long removed_links = 0; u16 link_removal_timeout[IEEE80211_MLD_MAX_NUM_LINKS] = {}; u8 link_id; u32 delay; - if (!ieee80211_vif_is_mld(&sdata->vif) || !elems->ml_reconf_elem) + if (!ieee80211_vif_is_mld(&sdata->vif) || !elems->ml_reconf) return; - ml_len = cfg80211_defragment_element(elems->ml_reconf_elem, - elems->ie_start, - elems->total_len, - elems->scratch_pos, - elems->scratch + elems->scratch_len - - elems->scratch_pos, - WLAN_EID_FRAGMENT); - if (ml_len < 0) - return; - - ml = (const void *)elems->scratch_pos; - /* Directly parse the sub elements as the common information doesn't * hold any useful information. */ - for_each_mle_subelement(sub, (u8 *)ml, ml_len) { + for_each_mle_subelement(sub, (const u8 *)elems->ml_reconf, + elems->ml_reconf_len) { struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; u8 *pos = prof->variable; u16 control; diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 8bdf6e7efa58..804323858977 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -819,6 +819,26 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, _ieee802_11_parse_elems_full(&sub, elems, non_inherit); } +static void +ieee80211_mle_defrag_reconf(struct ieee802_11_elems *elems) +{ + ssize_t ml_len; + + ml_len = cfg80211_defragment_element(elems->ml_reconf_elem, + elems->ie_start, + elems->total_len, + elems->scratch_pos, + elems->scratch + + elems->scratch_len - + elems->scratch_pos, + WLAN_EID_FRAGMENT); + if (ml_len < 0) + return; + elems->ml_reconf = (void *)elems->scratch_pos; + elems->ml_reconf_len = ml_len; + elems->scratch_pos += ml_len; +} + struct ieee802_11_elems * ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) { @@ -864,6 +884,8 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) ieee80211_mle_parse_link(elems, params); + ieee80211_mle_defrag_reconf(elems); + if (elems->tim && !elems->parse_error) { const struct ieee80211_tim_ie *tim_ie = elems->tim; From b413c0bd9ccc6bf705b51ae268c3a7ebba1cd11f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:15 +0100 Subject: [PATCH 1788/2255] wifi: mac80211: remove unneeded scratch_len subtraction We're always using "scratch + len - pos", so we don't need to subtract here to calculate the remaining length. Remove the unnecessary subtraction. Reviewed-by: Miriam Rachel Korenblit Reviewed-by: Ilan Peer Link: https://msgid.link/20240228094902.44e07cfa9e63.I7a9758fb9bc6b726aac49804f2f05cd521bc4128@changeid Signed-off-by: Johannes Berg --- net/mac80211/parse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 804323858977..73e52504ed97 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -862,7 +862,6 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) elems, params->bss, nontransmitted_profile); elems->scratch_pos += nontransmitted_profile_len; - elems->scratch_len -= nontransmitted_profile_len; non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, nontransmitted_profile, nontransmitted_profile_len); From 5a21f0eae13515b9a0b6cc66dc5f1903c18afb17 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:48:16 +0100 Subject: [PATCH 1789/2255] wifi: mac80211: hide element parsing internals Rework the data structures to hide element parsing internals from the users. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228094902.19c610b529e2.Ie7ea2dcb6713911590ace6583a4748f32dc37df2@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 14 ----- net/mac80211/parse.c | 118 ++++++++++++++++++++++++------------- net/mac80211/tests/elems.c | 4 +- 3 files changed, 78 insertions(+), 58 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index caee68cc8f14..da320799fbff 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1766,12 +1766,6 @@ struct ieee802_11_elems { size_t ml_basic_len; size_t ml_reconf_len; - /* The basic Multi-Link element in the original elements */ - const struct element *ml_basic_elem; - - /* The reconfiguration Multi-Link element in the original elements */ - const struct element *ml_reconf_elem; - u8 ttlm_num; /* @@ -1784,14 +1778,6 @@ struct ieee802_11_elems { /* whether/which parse error occurred while retrieving these elements */ u8 parse_error; - - /* - * scratch buffer that can be used for various element parsing related - * tasks, e.g., element de-fragmentation etc. - */ - size_t scratch_len; - u8 *scratch_pos; - u8 scratch[] __counted_by(scratch_len); }; static inline struct ieee80211_local *hw_to_local( diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 73e52504ed97..55e5497f8978 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -34,12 +34,32 @@ #include "led.h" #include "wep.h" +struct ieee80211_elems_parse { + /* must be first for kfree to work */ + struct ieee802_11_elems elems; + + /* The basic Multi-Link element in the original elements */ + const struct element *ml_basic_elem; + + /* The reconfiguration Multi-Link element in the original elements */ + const struct element *ml_reconf_elem; + + /* + * scratch buffer that can be used for various element parsing related + * tasks, e.g., element de-fragmentation etc. + */ + size_t scratch_len; + u8 *scratch_pos; + u8 scratch[] __counted_by(scratch_len); +}; + static void ieee80211_parse_extension_element(u32 *crc, const struct element *elem, - struct ieee802_11_elems *elems, + struct ieee80211_elems_parse *elems_parse, struct ieee80211_elems_parse_params *params) { + struct ieee802_11_elems *elems = &elems_parse->elems; const void *data = elem->data + 1; bool calc_crc = false; u8 len; @@ -129,15 +149,15 @@ ieee80211_parse_extension_element(u32 *crc, switch (le16_get_bits(mle->control, IEEE80211_ML_CONTROL_TYPE)) { case IEEE80211_ML_CONTROL_TYPE_BASIC: - if (elems->ml_basic_elem) { + if (elems_parse->ml_basic_elem) { elems->parse_error |= IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC; break; } - elems->ml_basic_elem = (void *)elem; + elems_parse->ml_basic_elem = elem; break; case IEEE80211_ML_CONTROL_TYPE_RECONF: - elems->ml_reconf_elem = (void *)elem; + elems_parse->ml_reconf_elem = elem; break; default: break; @@ -169,9 +189,10 @@ ieee80211_parse_extension_element(u32 *crc, static u32 _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, - struct ieee802_11_elems *elems, + struct ieee80211_elems_parse *elems_parse, const struct element *check_inherit) { + struct ieee802_11_elems *elems = &elems_parse->elems; const struct element *elem; bool calc_crc = params->filter != 0; DECLARE_BITMAP(seen_elems, 256); @@ -586,7 +607,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, case WLAN_EID_EXTENSION: ieee80211_parse_extension_element(calc_crc ? &crc : NULL, - elem, elems, params); + elem, elems_parse, + params); break; case WLAN_EID_S1G_CAPABILITIES: if (params->mode != IEEE80211_CONN_MODE_S1G) @@ -709,9 +731,11 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, return found ? profile_len : 0; } -static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, - u8 link_id) +static void +ieee80211_mle_get_sta_prof(struct ieee80211_elems_parse *elems_parse, + u8 link_id) { + struct ieee802_11_elems *elems = &elems_parse->elems; const struct ieee80211_multi_link_elem *ml = elems->ml_basic; ssize_t ml_len = elems->ml_basic_len; const struct element *sub; @@ -741,26 +765,27 @@ static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, sta_prof_len = cfg80211_defragment_element(sub, (u8 *)ml, ml_len, - elems->scratch_pos, - elems->scratch + - elems->scratch_len - - elems->scratch_pos, + elems_parse->scratch_pos, + elems_parse->scratch + + elems_parse->scratch_len - + elems_parse->scratch_pos, IEEE80211_MLE_SUBELEM_FRAGMENT); if (sta_prof_len < 0) return; - elems->prof = (void *)elems->scratch_pos; + elems->prof = (void *)elems_parse->scratch_pos; elems->sta_prof_len = sta_prof_len; - elems->scratch_pos += sta_prof_len; + elems_parse->scratch_pos += sta_prof_len; return; } } -static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, +static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse, struct ieee80211_elems_parse_params *params) { + struct ieee802_11_elems *elems = &elems_parse->elems; struct ieee80211_mle_per_sta_profile *prof; struct ieee80211_elems_parse_params sub = { .mode = params->mode, @@ -772,26 +797,26 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, const struct element *non_inherit = NULL; const u8 *end; - ml_len = cfg80211_defragment_element(elems->ml_basic_elem, + ml_len = cfg80211_defragment_element(elems_parse->ml_basic_elem, elems->ie_start, elems->total_len, - elems->scratch_pos, - elems->scratch + - elems->scratch_len - - elems->scratch_pos, + elems_parse->scratch_pos, + elems_parse->scratch + + elems_parse->scratch_len - + elems_parse->scratch_pos, WLAN_EID_FRAGMENT); if (ml_len < 0) return; - elems->ml_basic = (const void *)elems->scratch_pos; + elems->ml_basic = (const void *)elems_parse->scratch_pos; elems->ml_basic_len = ml_len; - elems->scratch_pos += ml_len; + elems_parse->scratch_pos += ml_len; if (params->link_id == -1) return; - ieee80211_mle_get_sta_prof(elems, params->link_id); + ieee80211_mle_get_sta_prof(elems_parse, params->link_id); prof = elems->prof; if (!prof) @@ -816,57 +841,66 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, sub.start, sub.len); - _ieee802_11_parse_elems_full(&sub, elems, non_inherit); + _ieee802_11_parse_elems_full(&sub, elems_parse, non_inherit); } static void -ieee80211_mle_defrag_reconf(struct ieee802_11_elems *elems) +ieee80211_mle_defrag_reconf(struct ieee80211_elems_parse *elems_parse) { + struct ieee802_11_elems *elems = &elems_parse->elems; ssize_t ml_len; - ml_len = cfg80211_defragment_element(elems->ml_reconf_elem, + ml_len = cfg80211_defragment_element(elems_parse->ml_reconf_elem, elems->ie_start, elems->total_len, - elems->scratch_pos, - elems->scratch + - elems->scratch_len - - elems->scratch_pos, + elems_parse->scratch_pos, + elems_parse->scratch + + elems_parse->scratch_len - + elems_parse->scratch_pos, WLAN_EID_FRAGMENT); if (ml_len < 0) return; - elems->ml_reconf = (void *)elems->scratch_pos; + elems->ml_reconf = (void *)elems_parse->scratch_pos; elems->ml_reconf_len = ml_len; - elems->scratch_pos += ml_len; + elems_parse->scratch_pos += ml_len; } struct ieee802_11_elems * ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) { + struct ieee80211_elems_parse *elems_parse; struct ieee802_11_elems *elems; const struct element *non_inherit = NULL; u8 *nontransmitted_profile; int nontransmitted_profile_len = 0; size_t scratch_len = 3 * params->len; - elems = kzalloc(struct_size(elems, scratch, scratch_len), GFP_ATOMIC); - if (!elems) + BUILD_BUG_ON(offsetof(typeof(*elems_parse), elems) != 0); + + elems_parse = kzalloc(struct_size(elems_parse, scratch, scratch_len), + GFP_ATOMIC); + if (!elems_parse) return NULL; + + elems_parse->scratch_len = scratch_len; + elems_parse->scratch_pos = elems_parse->scratch; + + elems = &elems_parse->elems; elems->ie_start = params->start; elems->total_len = params->len; - elems->scratch_len = scratch_len; - elems->scratch_pos = elems->scratch; - nontransmitted_profile = elems->scratch_pos; + nontransmitted_profile = elems_parse->scratch_pos; nontransmitted_profile_len = ieee802_11_find_bssid_profile(params->start, params->len, elems, params->bss, nontransmitted_profile); - elems->scratch_pos += nontransmitted_profile_len; + elems_parse->scratch_pos += nontransmitted_profile_len; non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, nontransmitted_profile, nontransmitted_profile_len); - elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit); + elems->crc = _ieee802_11_parse_elems_full(params, elems_parse, + non_inherit); /* Override with nontransmitted profile, if found */ if (nontransmitted_profile_len) { @@ -878,12 +912,12 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) .link_id = params->link_id, }; - _ieee802_11_parse_elems_full(&sub, elems, NULL); + _ieee802_11_parse_elems_full(&sub, elems_parse, NULL); } - ieee80211_mle_parse_link(elems, params); + ieee80211_mle_parse_link(elems_parse, params); - ieee80211_mle_defrag_reconf(elems); + ieee80211_mle_defrag_reconf(elems_parse); if (elems->tim && !elems->parse_error) { const struct ieee80211_tim_ie *tim_ie = elems->tim; diff --git a/net/mac80211/tests/elems.c b/net/mac80211/tests/elems.c index 30fc0acb7ac2..a413ba29f759 100644 --- a/net/mac80211/tests/elems.c +++ b/net/mac80211/tests/elems.c @@ -2,7 +2,7 @@ /* * KUnit tests for element parsing * - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation */ #include #include "../ieee80211_i.h" @@ -69,7 +69,7 @@ static void mle_defrag(struct kunit *test) if (IS_ERR_OR_NULL(parsed)) goto free_skb; - KUNIT_EXPECT_NOT_NULL(test, parsed->ml_basic_elem); + KUNIT_EXPECT_NOT_NULL(test, parsed->ml_basic); KUNIT_EXPECT_EQ(test, parsed->ml_basic_len, 2 /* control */ + From 22667035e5ddb7b68c7d473693b321fb9e20a397 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:41 +0100 Subject: [PATCH 1790/2255] wifi: cfg80211: expose cfg80211_iter_rnr() to drivers In mac80211 we'll need to look at reduced neighbor report entries for channel switch purposes, so export the iteration function to make that simpler. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228095718.0954809964ef.I53e95c017aa71f14e8d1057afbbc75982ddb43df@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 32 ++++++++++++++++++++++++++++++++ net/wireless/scan.c | 20 +++++++------------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f9eada2a26ec..53653d234d39 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6870,6 +6870,38 @@ cfg80211_find_vendor_ie(unsigned int oui, int oui_type, return (const void *)cfg80211_find_vendor_elem(oui, oui_type, ies, len); } +/** + * enum cfg80211_rnr_iter_ret - reduced neighbor report iteration state + * @RNR_ITER_CONTINUE: continue iterating with the next entry + * @RNR_ITER_BREAK: break iteration and return success + * @RNR_ITER_ERROR: break iteration and return error + */ +enum cfg80211_rnr_iter_ret { + RNR_ITER_CONTINUE, + RNR_ITER_BREAK, + RNR_ITER_ERROR, +}; + +/** + * cfg80211_iter_rnr - iterate reduced neighbor report entries + * @elems: the frame elements to iterate RNR elements and then + * their entries in + * @elems_len: length of the elements + * @iter: iteration function, see also &enum cfg80211_rnr_iter_ret + * for the return value + * @iter_data: additional data passed to the iteration function + * Return: %true on success (after successfully iterating all entries + * or if the iteration function returned %RNR_ITER_BREAK), + * %false on error (iteration function returned %RNR_ITER_ERROR + * or elements were malformed.) + */ +bool cfg80211_iter_rnr(const u8 *elems, size_t elems_len, + enum cfg80211_rnr_iter_ret + (*iter)(void *data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len), + void *iter_data); + /** * cfg80211_defragment_element - Defrag the given element data into a buffer * diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7cf36b8d3ae7..9377a43aa5f7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -611,19 +611,12 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, return 0; } -enum cfg80211_rnr_iter_ret { - RNR_ITER_CONTINUE, - RNR_ITER_BREAK, - RNR_ITER_ERROR, -}; - -static bool -cfg80211_iter_rnr(const u8 *elems, size_t elems_len, - enum cfg80211_rnr_iter_ret - (*iter)(void *data, u8 type, - const struct ieee80211_neighbor_ap_info *info, - const u8 *tbtt_info, u8 tbtt_info_len), - void *iter_data) +bool cfg80211_iter_rnr(const u8 *elems, size_t elems_len, + enum cfg80211_rnr_iter_ret + (*iter)(void *data, u8 type, + const struct ieee80211_neighbor_ap_info *info, + const u8 *tbtt_info, u8 tbtt_info_len), + void *iter_data) { const struct element *rnr; const u8 *pos, *end; @@ -675,6 +668,7 @@ cfg80211_iter_rnr(const u8 *elems, size_t elems_len, return true; } +EXPORT_SYMBOL_GPL(cfg80211_iter_rnr); struct colocated_ap_data { const struct element *ssid_elem; From 8ade3356b25ab2522892a21832a709e7ad5f8168 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:42 +0100 Subject: [PATCH 1791/2255] wifi: cfg80211: allow cfg80211_defragment_element() without output If we just want to determine the length of the fragmented data, we basically need the same logic, and really we want it to be _literally_ the same logic, so it cannot be out of sync in any way. Allow calling cfg80211_defragment_element() without an output buffer, where it then just returns the required output size. Also add this to the tests, just to exercise it, using the pre-calculated length to really do the defragmentation, which checks that this is sufficient. Reviewed-by: Miriam Rachel Korenblit Reviewed-by: Benjamin Berg Link: https://msgid.link/20240228095718.6d6565b9e3f2.Ib441903f4b8644ba04b1c766f90580ee6f54fc66@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++-- net/wireless/scan.c | 27 ++++++++++++++++++--------- net/wireless/tests/fragmentation.c | 30 +++++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 53653d234d39..2e2be4fd2bb6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6908,8 +6908,8 @@ bool cfg80211_iter_rnr(const u8 *elems, size_t elems_len, * @elem: the element to defragment * @ies: elements where @elem is contained * @ieslen: length of @ies - * @data: buffer to store element data - * @data_len: length of @data + * @data: buffer to store element data, or %NULL to just determine size + * @data_len: length of @data, or 0 * @frag_id: the element ID of fragments * * Return: length of @data, or -EINVAL on error diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 9377a43aa5f7..5a5dd3ce497f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2504,16 +2504,22 @@ ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies, if (elem->id == WLAN_EID_EXTENSION) { copied = elem->datalen - 1; - if (copied > data_len) - return -ENOSPC; - memmove(data, elem->data + 1, copied); + if (data) { + if (copied > data_len) + return -ENOSPC; + + memmove(data, elem->data + 1, copied); + } } else { copied = elem->datalen; - if (copied > data_len) - return -ENOSPC; - memmove(data, elem->data, copied); + if (data) { + if (copied > data_len) + return -ENOSPC; + + memmove(data, elem->data, copied); + } } /* Fragmented elements must have 255 bytes */ @@ -2532,10 +2538,13 @@ ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies, elem_datalen = elem->datalen; - if (copied + elem_datalen > data_len) - return -ENOSPC; + if (data) { + if (copied + elem_datalen > data_len) + return -ENOSPC; + + memmove(data + copied, elem->data, elem_datalen); + } - memmove(data + copied, elem->data, elem_datalen); copied += elem_datalen; /* Only the last fragment may be short */ diff --git a/net/wireless/tests/fragmentation.c b/net/wireless/tests/fragmentation.c index 49a339ca8880..411fae18cd88 100644 --- a/net/wireless/tests/fragmentation.c +++ b/net/wireless/tests/fragmentation.c @@ -2,7 +2,7 @@ /* * KUnit tests for element fragmentation * - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation */ #include #include @@ -27,7 +27,12 @@ static void defragment_0(struct kunit *test) ret = cfg80211_defragment_element((void *)input, input, sizeof(input), - data, sizeof(input), + NULL, 0, + WLAN_EID_FRAGMENT); + KUNIT_EXPECT_EQ(test, ret, 253); + ret = cfg80211_defragment_element((void *)input, + input, sizeof(input), + data, ret, WLAN_EID_FRAGMENT); KUNIT_EXPECT_EQ(test, ret, 253); KUNIT_EXPECT_MEMEQ(test, data, input + 3, 253); @@ -63,7 +68,12 @@ static void defragment_1(struct kunit *test) ret = cfg80211_defragment_element((void *)input, input, sizeof(input), - data, sizeof(input), + NULL, 0, + WLAN_EID_FRAGMENT); + KUNIT_EXPECT_EQ(test, ret, 254 + 7); + ret = cfg80211_defragment_element((void *)input, + input, sizeof(input), + data, ret, WLAN_EID_FRAGMENT); /* this means the last fragment was not used */ KUNIT_EXPECT_EQ(test, ret, 254 + 7); @@ -106,10 +116,15 @@ static void defragment_2(struct kunit *test) ret = cfg80211_defragment_element((void *)input, input, sizeof(input), - data, sizeof(input), + NULL, 0, WLAN_EID_FRAGMENT); /* this means the last fragment was not used */ KUNIT_EXPECT_EQ(test, ret, 254 + 255 + 1); + ret = cfg80211_defragment_element((void *)input, + input, sizeof(input), + data, ret, + WLAN_EID_FRAGMENT); + KUNIT_EXPECT_EQ(test, ret, 254 + 255 + 1); KUNIT_EXPECT_MEMEQ(test, data, input + 3, 254); KUNIT_EXPECT_MEMEQ(test, data + 254, input + 257 + 2, 255); KUNIT_EXPECT_MEMEQ(test, data + 254 + 255, input + 2 * 257 + 2, 1); @@ -134,7 +149,12 @@ static void defragment_at_end(struct kunit *test) ret = cfg80211_defragment_element((void *)input, input, sizeof(input), - data, sizeof(input), + NULL, 0, + WLAN_EID_FRAGMENT); + KUNIT_EXPECT_EQ(test, ret, 254 + 7); + ret = cfg80211_defragment_element((void *)input, + input, sizeof(input), + data, ret, WLAN_EID_FRAGMENT); KUNIT_EXPECT_EQ(test, ret, 254 + 7); KUNIT_EXPECT_MEMEQ(test, data, input + 3, 254); From 25703adf45f8430ec59effa20920c80139d13cdc Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 2 Mar 2024 14:22:18 +0800 Subject: [PATCH 1792/2255] libbpf: Correct debug message in btf__load_vmlinux_btf In the function btf__load_vmlinux_btf, the debug message incorrectly refers to 'path' instead of 'sysfs_btf_path'. Signed-off-by: Chen Shen Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240302062218.3587-1-peterchenshen@gmail.com --- tools/lib/bpf/btf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index a17b4c9c4213..2d0840ef599a 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -4968,7 +4968,7 @@ struct btf *btf__load_vmlinux_btf(void) pr_warn("failed to read kernel BTF from '%s': %d\n", sysfs_btf_path, err); return libbpf_err_ptr(err); } - pr_debug("loaded kernel BTF from '%s'\n", path); + pr_debug("loaded kernel BTF from '%s'\n", sysfs_btf_path); return btf; } From e6ee3a3713fe38e4ae94318e9cb18b39ec30da4a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:43 +0100 Subject: [PATCH 1793/2255] wifi: mac80211: pass link_id to channel switch ops For CSA to work correctly in multi-link scenarios, pass the link_id to the relevant callbacks. While at it, unify/deduplicate the tracing for them. Reviewed-by: Miriam Rachel Korenblit Reviewed-by: Emmanuel Grumbach Link: https://msgid.link/20240228095718.b7726635c054.I0be5d00af4acb48cfbd23a9dbf067f9aeb66469d@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 6 ++-- net/mac80211/cfg.c | 4 ++- net/mac80211/mlme.c | 4 ++- net/mac80211/trace.h | 82 ++++++++++-------------------------------- 4 files changed, 28 insertions(+), 68 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6c6d8210d637..8ea9fa81e68c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1763,8 +1763,9 @@ struct ieee80211_conf { * @chandef: the new channel to switch to * @count: the number of TBTT's until the channel switch event * @delay: maximum delay between the time the AP transmitted the last beacon in - * current channel and the expected time of the first beacon in the new - * channel, expressed in TU. + * current channel and the expected time of the first beacon in the new + * channel, expressed in TU. + * @link_id: the link ID of the link doing the channel switch, 0 for non-MLO */ struct ieee80211_channel_switch { u64 timestamp; @@ -1772,6 +1773,7 @@ struct ieee80211_channel_switch { bool block_tx; struct cfg80211_chan_def chandef; u8 count; + u8 link_id; u32 delay; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 358593eeb500..4bc0cc2dff83 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3931,7 +3931,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, 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_channel_switch ch_switch = { + .link_id = params->link_id, + }; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; struct ieee80211_bss_conf *link_conf; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 90e505778db6..d1d4480c0352 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2021,7 +2021,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, struct ieee80211_chanctx *chanctx; enum nl80211_band current_band; struct ieee80211_csa_ie csa_ie; - struct ieee80211_channel_switch ch_switch; + struct ieee80211_channel_switch ch_switch = { + .link_id = link->link_id, + }; struct ieee80211_bss *bss; unsigned long timeout; int res; diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 478b32d2520a..8e758b5074bd 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1209,7 +1209,7 @@ DEFINE_EVENT(sta_event, drv_flush_sta, TP_ARGS(local, sdata, sta) ); -TRACE_EVENT(drv_channel_switch, +DECLARE_EVENT_CLASS(chanswitch_evt, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_channel_switch *ch_switch), @@ -1224,6 +1224,7 @@ TRACE_EVENT(drv_channel_switch, __field(u32, device_timestamp) __field(bool, block_tx) __field(u8, count) + __field(u8, link_id) ), TP_fast_assign( @@ -1234,14 +1235,24 @@ TRACE_EVENT(drv_channel_switch, __entry->device_timestamp = ch_switch->device_timestamp; __entry->block_tx = ch_switch->block_tx; __entry->count = ch_switch->count; + __entry->link_id = ch_switch->link_id; ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d", - LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count + LOCAL_PR_FMT VIF_PR_FMT CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu device_ts:%u link_id:%d", + LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count, + __entry->block_tx, __entry->timestamp, + __entry->device_timestamp, __entry->link_id ) ); +DEFINE_EVENT(chanswitch_evt, drv_channel_switch, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_switch *ch_switch), + TP_ARGS(local, sdata, ch_switch) +); + TRACE_EVENT(drv_set_antenna, TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret), @@ -2121,39 +2132,11 @@ TRACE_EVENT(drv_channel_switch_beacon, ) ); -TRACE_EVENT(drv_pre_channel_switch, +DEFINE_EVENT(chanswitch_evt, drv_pre_channel_switch, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_channel_switch *ch_switch), - - TP_ARGS(local, sdata, ch_switch), - - TP_STRUCT__entry( - LOCAL_ENTRY - VIF_ENTRY - CHANDEF_ENTRY - __field(u64, timestamp) - __field(u32, device_timestamp) - __field(bool, block_tx) - __field(u8, count) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - VIF_ASSIGN; - CHANDEF_ASSIGN(&ch_switch->chandef) - __entry->timestamp = ch_switch->timestamp; - __entry->device_timestamp = ch_switch->device_timestamp; - __entry->block_tx = ch_switch->block_tx; - __entry->count = ch_switch->count; - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to " - CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu", - LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count, - __entry->block_tx, __entry->timestamp - ) + TP_ARGS(local, sdata, ch_switch) ); DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch, @@ -2168,40 +2151,11 @@ DEFINE_EVENT(local_sdata_evt, drv_abort_channel_switch, TP_ARGS(local, sdata) ); -TRACE_EVENT(drv_channel_switch_rx_beacon, +DEFINE_EVENT(chanswitch_evt, drv_channel_switch_rx_beacon, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_channel_switch *ch_switch), - - TP_ARGS(local, sdata, ch_switch), - - TP_STRUCT__entry( - LOCAL_ENTRY - VIF_ENTRY - CHANDEF_ENTRY - __field(u64, timestamp) - __field(u32, device_timestamp) - __field(bool, block_tx) - __field(u8, count) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - VIF_ASSIGN; - CHANDEF_ASSIGN(&ch_switch->chandef) - __entry->timestamp = ch_switch->timestamp; - __entry->device_timestamp = ch_switch->device_timestamp; - __entry->block_tx = ch_switch->block_tx; - __entry->count = ch_switch->count; - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT - " received a channel switch beacon to " - CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu", - LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count, - __entry->block_tx, __entry->timestamp - ) + TP_ARGS(local, sdata, ch_switch) ); TRACE_EVENT(drv_get_txpower, From 5ecd5d82b17ee2818548aeb5eb52f3a5b5cae18c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:44 +0100 Subject: [PATCH 1794/2255] wifi: mac80211: pass link conf to abort_channel_switch Pass the link conf to the abort_channel_switch driver method so the driver can handle things correctly. Reviewed-by: Emmanuel Grumbach Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228095718.27f621106ddd.Iadd3d69b722ffe5934779a32a0e4e596a4e33ed4@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 13 +++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 ++- include/net/mac80211.h | 5 +++-- net/mac80211/driver-ops.h | 8 +++++--- net/mac80211/mlme.c | 2 +- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 69f6a96b0cfb..1935630d3def 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1470,7 +1470,8 @@ out_unlock: } void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -5551,8 +5552,16 @@ void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw, if (chsw->count >= mvmvif->csa_count && chsw->block_tx) { if (mvmvif->csa_misbehave) { + struct ieee80211_bss_conf *link_conf; + /* Second time, give up on this AP*/ - iwl_mvm_abort_channel_switch(hw, vif); + + link_conf = wiphy_dereference(hw->wiphy, + vif->link_conf[chsw->link_id]); + if (WARN_ON(!link_conf)) + return; + + iwl_mvm_abort_channel_switch(hw, vif, link_conf); ieee80211_chswitch_done(vif, false, 0); mvmvif->csa_misbehave = false; return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index c85d9e460ad2..63c802712596 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2709,7 +2709,8 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *chsw); void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *chsw); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8ea9fa81e68c..c622450ac012 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4268,7 +4268,7 @@ struct ieee80211_prep_tx_info { * after a channel switch procedure is completed, allowing the * driver to go back to a normal configuration. * @abort_channel_switch: This is an optional callback that is called - * when channel switch procedure was completed, allowing the + * when channel switch procedure was aborted, allowing the * driver to go back to a normal configuration. * @channel_switch_rx_beacon: This is an optional callback that is called * when channel switch procedure is in progress and additional beacon with @@ -4664,7 +4664,8 @@ struct ieee80211_ops { struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); void (*abort_channel_switch)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); void (*channel_switch_rx_beacon)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *ch_switch); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index e20c64edb880..5d078c0a2323 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -2,7 +2,7 @@ /* * Portions of this file * Copyright(c) 2016 Intel Deutschland GmbH -* Copyright (C) 2018 - 2019, 2021 - 2023 Intel Corporation +* Copyright (C) 2018-2019, 2021-2024 Intel Corporation */ #ifndef __MAC80211_DRIVER_OPS @@ -1180,8 +1180,9 @@ drv_post_channel_switch(struct ieee80211_link_data *link) } static inline void -drv_abort_channel_switch(struct ieee80211_sub_if_data *sdata) +drv_abort_channel_switch(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; might_sleep(); @@ -1193,7 +1194,8 @@ drv_abort_channel_switch(struct ieee80211_sub_if_data *sdata) trace_drv_abort_channel_switch(local, sdata); if (local->ops->abort_channel_switch) - local->ops->abort_channel_switch(&local->hw, &sdata->vif); + local->ops->abort_channel_switch(&local->hw, &sdata->vif, + link->conf); } static inline void diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d1d4480c0352..c5c757514179 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2004,7 +2004,7 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_link_data *link) link->csa_block_tx = false; link->conf->csa_active = false; - drv_abort_channel_switch(sdata); + drv_abort_channel_switch(link); } static void From 6f0107d195a812074c6f977d492ffc99ba3ff2bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:45 +0100 Subject: [PATCH 1795/2255] wifi: mac80211: introduce a feature flag for quiet in CSA When doing CSA in multi-link, there really isn't a need to stop transmissions entirely. Add a feature flag for drivers to indicate they can handle quiet in CSA (be it by parsing themselves, or by implementing drv_pre_channel_switch()), to make that possible. Also clean up the csa_block_tx handling: it clearly cannot handle multi-link due to the way queues are stopped, move it to the sdata. Drivers should be doing it themselves for working properly during CSA in MLO anyway. Also rename it to indicate that it reflects TX was blocked at mac80211. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228095719.258439191541.I2469d206e2bf5cb244cfde2b4bbc2ae6d1cd3dd9@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 6 ++++++ net/mac80211/cfg.c | 16 +++++++++------- net/mac80211/debugfs.c | 3 ++- net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/iface.c | 6 +++--- net/mac80211/mlme.c | 35 +++++++++++++++++++++-------------- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c622450ac012..353488ab94a2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2778,6 +2778,11 @@ struct ieee80211_txq { * @IEEE80211_HW_DISALLOW_PUNCTURING: HW requires disabling puncturing in EHT * and connecting with a lower bandwidth instead * + * @IEEE80211_HW_HANDLES_QUIET_CSA: HW/driver handles quieting for CSA, so + * no need to stop queues. This really should be set by a driver that + * implements MLO, so operation can continue on other links when one + * link is switching. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2836,6 +2841,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_DETECTS_COLOR_COLLISION, IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX, IEEE80211_HW_DISALLOW_PUNCTURING, + IEEE80211_HW_HANDLES_QUIET_CSA, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bc0cc2dff83..3a9d2ceec752 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1607,10 +1607,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, /* abort any running channel switch or color change */ link_conf->csa_active = false; link_conf->color_change_active = false; - if (link->csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - link->csa_block_tx = false; + sdata->csa_blocked_tx = false; } ieee80211_free_next_beacon(link); @@ -3649,7 +3649,7 @@ void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_t struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - sdata->deflink.csa_block_tx = block_tx; + sdata->csa_blocked_tx = block_tx; sdata_info(sdata, "channel switch failed, disconnecting\n"); wiphy_work_queue(local->hw.wiphy, &ifmgd->csa_connection_drop_work); } @@ -3735,10 +3735,10 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) ieee80211_link_info_change_notify(sdata, link_data, changed); - if (link_data->csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - link_data->csa_block_tx = false; + sdata->csa_blocked_tx = false; } err = drv_post_channel_switch(link_data); @@ -4014,12 +4014,14 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, } link_data->csa_chanreq = chanreq; - link_data->csa_block_tx = params->block_tx; link_conf->csa_active = true; - if (link_data->csa_block_tx) + if (params->block_tx && + !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA)) { ieee80211_stop_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_blocked_tx = true; + } cfg80211_ch_switch_started_notify(sdata->dev, &link_data->csa_chanreq.oper, 0, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 74be49191e70..2f68e92a7404 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -4,7 +4,7 @@ * * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018 - 2019, 2021-2023 Intel Corporation + * Copyright (C) 2018 - 2019, 2021-2024 Intel Corporation */ #include @@ -498,6 +498,7 @@ static const char *hw_flag_names[] = { FLAG(DETECTS_COLOR_COLLISION), FLAG(MLO_MCAST_MULTI_LINK_TX), FLAG(DISALLOW_PUNCTURING), + FLAG(HANDLES_QUIET_CSA), #undef FLAG }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index da320799fbff..cfd0c03e4bd6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1034,7 +1034,6 @@ struct ieee80211_link_data { struct ieee80211_key __rcu *default_beacon_key; struct wiphy_work csa_finalize_work; - bool csa_block_tx; bool operating_11g_mode; @@ -1093,6 +1092,8 @@ struct ieee80211_sub_if_data { unsigned long state; + bool csa_blocked_tx; + char name[IFNAMSIZ]; struct ieee80211_fragment_cache frags; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b75b83a5142b..395de62d9cb2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -8,7 +8,7 @@ * Copyright 2008, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include #include @@ -544,10 +544,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do sdata->vif.bss_conf.csa_active = false; if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->deflink.u.mgd.csa_waiting_bcn = false; - if (sdata->deflink.csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->deflink.csa_block_tx = false; + sdata->csa_blocked_tx = false; } wiphy_work_cancel(local->hw.wiphy, &sdata->deflink.csa_finalize_work); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c5c757514179..3d5cc3dd9238 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1926,10 +1926,10 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link) WARN_ON(!link->conf->csa_active); - if (link->csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - link->csa_block_tx = false; + sdata->csa_blocked_tx = false; } link->conf->csa_active = false; @@ -1997,11 +1997,12 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_link_data *link) ieee80211_link_unreserve_chanctx(link); - if (link->csa_block_tx) + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_blocked_tx = false; + } - link->csa_block_tx = false; link->conf->csa_active = false; drv_abort_channel_switch(link); @@ -2145,13 +2146,15 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, link->conf->csa_active = true; 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; - if (link->csa_block_tx) + if (csa_ie.mode && + !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA)) { ieee80211_stop_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_blocked_tx = true; + } cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chanreq.oper, link->link_id, csa_ie.count, @@ -2179,7 +2182,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, * reset when the disconnection worker runs. */ link->conf->csa_active = true; - link->csa_block_tx = csa_ie.mode; + sdata->csa_blocked_tx = + csa_ie.mode && !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA); wiphy_work_queue(sdata->local->hw.wiphy, &ifmgd->csa_connection_drop_work); @@ -3233,10 +3237,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; sdata->deflink.u.mgd.csa_ignored_same_chan = false; - if (sdata->deflink.csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->deflink.csa_block_tx = false; + sdata->csa_blocked_tx = false; } /* existing TX TSPEC sessions no longer exist */ @@ -3549,9 +3553,12 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) if (!ifmgd->associated) return; - /* in MLO assume we have a link where we can TX the frame */ - tx = ieee80211_vif_is_mld(&sdata->vif) || - !sdata->deflink.csa_block_tx; + /* + * MLO drivers should have HANDLES_QUIET_CSA, so that csa_blocked_tx + * is always false; if they don't then this may try to transmit the + * frame but queues will be stopped. + */ + tx = !sdata->csa_blocked_tx; if (!ifmgd->driver_disconnect) { unsigned int link_id; @@ -3584,10 +3591,10 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) /* the other links will be destroyed */ sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; - if (sdata->deflink.csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->deflink.csa_block_tx = false; + sdata->csa_blocked_tx = false; } ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx, From f3dee30c6791e22633d9d7e43e48c1dff946cc0b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:46 +0100 Subject: [PATCH 1796/2255] wifi: mac80211: mlme: unify CSA handling Unify all the CSA handling, including handling of a beacon after the CSA, into ieee80211_sta_process_chanswitch(). The CRC of the beacon will change due to changes in the CSA/ECSA elements, so there's really no need to have the 'beacon after CSA' handling before the CRC processing or to change the beacon_crc_valid value here. Reviewed-by: Miriam Rachel Korenblit Link: https://msgid.link/20240228095719.e269c0e02905.I9dc68ff1e84d51349822bc7d3b33b578fcf8e360@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3d5cc3dd9238..2180b1ba0e42 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1934,11 +1934,6 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link) link->conf->csa_active = false; link->u.mgd.csa_waiting_bcn = false; - /* - * If the CSA IE is still present on the beacon after the switch, - * we need to consider it as a new CSA (possibly to self). - */ - link->u.mgd.beacon_crc_valid = false; ret = drv_post_channel_switch(link); if (ret) { @@ -2053,18 +2048,32 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, if (res < 0) goto drop_connection; - if (beacon && link->conf->csa_active && - !link->u.mgd.csa_waiting_bcn) { - if (res) + if (link->conf->csa_active) { + /* already processing - disregard action frames */ + if (!beacon) + return; + + if (link->u.mgd.csa_waiting_bcn) { + ieee80211_chswitch_post_beacon(link); + /* + * If the CSA IE is still present in the beacon after + * the switch, we need to consider it as a new CSA + * (possibly to self) - this happens by not returning + * here so we'll get to the check below. + */ + } else if (res) { ieee80211_sta_abort_chanswitch(link); - else + return; + } else { drv_channel_switch_rx_beacon(sdata, &ch_switch); - return; - } else if (link->conf->csa_active || res) { - /* disregard subsequent announcements if already processing */ - return; + return; + } } + /* nothing to do at all - no active CSA nor a new one */ + if (res) + return; + if (link->conf->chanreq.oper.chan->band != csa_ie.chanreq.oper.chan->band) { sdata_info(sdata, @@ -6293,9 +6302,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, } } - if (link->u.mgd.csa_waiting_bcn) - ieee80211_chswitch_post_beacon(link); - /* * Update beacon timing and dtim count on every beacon appearance. This * will allow the driver to use the most updated values. Do it before From 85977fc0aa489420709779cbc859966db94be68f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:47 +0100 Subject: [PATCH 1797/2255] wifi: mac80211: remove TDLS peers only on affected link If a link does CSA, or if it changes SMPS mode, we need to drop the TDLS peers, but we really should drop them only on the affected link. Fix that. Reviewed-by: Miriam Rachel Korenblit Reviewed-by: Emmanuel Grumbach Link: https://msgid.link/20240228095719.00d1d793f5b8.Ia9971316c6b3922dd371d64ac2198f91ed5ad9d2@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mlme.c | 7 ++++--- net/mac80211/tdls.c | 6 +++++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3a9d2ceec752..f03452dc716d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3242,7 +3242,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, if (err) link->u.mgd.req_smps = old_req; else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found) - ieee80211_teardown_tdls_peers(sdata); + ieee80211_teardown_tdls_peers(link); return err; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cfd0c03e4bd6..b6fead612b66 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2611,7 +2611,7 @@ int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, struct net_device *dev, const u8 *addr); -void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata); +void ieee80211_teardown_tdls_peers(struct ieee80211_link_data *link); void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata, const u8 *peer, u16 reason); void diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2180b1ba0e42..47a2cba8313f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2115,12 +2115,13 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, } /* - * Drop all TDLS peers - either we disconnect or move to a different - * channel from this point on. There's no telling what our peer will do. + * Drop all TDLS peers on the affected link - either we disconnect or + * move to a different channel from this point on. There's no telling + * what our peer will do. * The TDLS WIDER_BW scenario is also problematic, as peers might now * have an incompatible wider chandef. */ - ieee80211_teardown_tdls_peers(sdata); + ieee80211_teardown_tdls_peers(link); conf = rcu_dereference_protected(link->conf->chanctx_conf, lockdep_is_held(&local->hw.wiphy->mtx)); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 42d9c06cbb84..f07b40916485 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -2028,8 +2028,9 @@ ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, } } -void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata) +void ieee80211_teardown_tdls_peers(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct sta_info *sta; u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; @@ -2039,6 +2040,9 @@ void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata) !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) continue; + if (sta->deflink.link_id != link->link_id) + continue; + ieee80211_tdls_oper_request(&sdata->vif, sta->sta.addr, NL80211_TDLS_TEARDOWN, reason, GFP_ATOMIC); From 07fba2277fcedd0948bec657f76ef374d0157d93 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 09:55:48 +0100 Subject: [PATCH 1798/2255] wifi: mac80211: remove TDLS peers on link deactivation If a link is deactivated, we really cannot sustain any TDLS connections on that link any more. With the API now changed, fix this issue and remove TDLS connections. Reviewed-by: Miriam Rachel Korenblit Reviewed-by: Emmanuel Grumbach Link: https://msgid.link/20240228095719.a7dd812c37bf.I3474dbde79e9e7a539d47f6f81f32e6c3e459080@changeid Signed-off-by: Johannes Berg --- net/mac80211/link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/link.c b/net/mac80211/link.c index 87a413374ece..685ec66b4264 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -356,7 +356,7 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata, link = sdata_dereference(sdata->link[link_id], sdata); - /* FIXME: kill TDLS connections on the link */ + ieee80211_teardown_tdls_peers(link); ieee80211_link_release_channel(link); } From 8f79870ec8a9409983ad5981e1b7d599cbf047bd Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 1 Mar 2024 13:45:51 -0800 Subject: [PATCH 1799/2255] selftests/bpf: Extend uprobe/uretprobe triggering benchmarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settle on three "flavors" of uprobe/uretprobe, installed on different kinds of instruction: nop, push, and ret. All three are testing different internal code paths emulating or single-stepping instructions, so are interesting to compare and benchmark separately. To ensure `push rbp` instruction we ensure that uprobe_target_push() is not a leaf function by calling (global __weak) noop function and returning something afterwards (if we don't do that, compiler will just do a tail call optimization). Also, we need to make sure that compiler isn't skipping frame pointer generation, so let's add `-fno-omit-frame-pointers` to Makefile. Just to give an idea of where we currently stand in terms of relative performance of different uprobe/uretprobe cases vs a cheap syscall (getpgid()) baseline, here are results from my local machine: $ benchs/run_bench_uprobes.sh base : 1.561 ± 0.020M/s uprobe-nop : 0.947 ± 0.007M/s uprobe-push : 0.951 ± 0.004M/s uprobe-ret : 0.443 ± 0.007M/s uretprobe-nop : 0.471 ± 0.013M/s uretprobe-push : 0.483 ± 0.004M/s uretprobe-ret : 0.306 ± 0.007M/s Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20240301214551.1686095-1-andrii@kernel.org --- tools/testing/selftests/bpf/Makefile | 2 +- tools/testing/selftests/bpf/bench.c | 20 +-- .../selftests/bpf/benchs/bench_trigger.c | 118 ++++++++++++------ .../selftests/bpf/benchs/run_bench_uprobes.sh | 9 ++ 4 files changed, 103 insertions(+), 46 deletions(-) create mode 100755 tools/testing/selftests/bpf/benchs/run_bench_uprobes.sh diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 84cb5500e8ef..3b9eb40d6343 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -34,7 +34,7 @@ LIBELF_CFLAGS := $(shell $(PKG_CONFIG) libelf --cflags 2>/dev/null) LIBELF_LIBS := $(shell $(PKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf) CFLAGS += -g $(OPT_FLAGS) -rdynamic \ - -Wall -Werror \ + -Wall -Werror -fno-omit-frame-pointer \ $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \ -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \ -I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT) diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index 1724d50ba942..60df99b6ac72 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -499,10 +499,12 @@ extern const struct bench bench_trig_fentry; extern const struct bench bench_trig_fentry_sleep; extern const struct bench bench_trig_fmodret; extern const struct bench bench_trig_uprobe_base; -extern const struct bench bench_trig_uprobe_with_nop; -extern const struct bench bench_trig_uretprobe_with_nop; -extern const struct bench bench_trig_uprobe_without_nop; -extern const struct bench bench_trig_uretprobe_without_nop; +extern const struct bench bench_trig_uprobe_nop; +extern const struct bench bench_trig_uretprobe_nop; +extern const struct bench bench_trig_uprobe_push; +extern const struct bench bench_trig_uretprobe_push; +extern const struct bench bench_trig_uprobe_ret; +extern const struct bench bench_trig_uretprobe_ret; extern const struct bench bench_rb_libbpf; extern const struct bench bench_rb_custom; extern const struct bench bench_pb_libbpf; @@ -541,10 +543,12 @@ static const struct bench *benchs[] = { &bench_trig_fentry_sleep, &bench_trig_fmodret, &bench_trig_uprobe_base, - &bench_trig_uprobe_with_nop, - &bench_trig_uretprobe_with_nop, - &bench_trig_uprobe_without_nop, - &bench_trig_uretprobe_without_nop, + &bench_trig_uprobe_nop, + &bench_trig_uretprobe_nop, + &bench_trig_uprobe_push, + &bench_trig_uretprobe_push, + &bench_trig_uprobe_ret, + &bench_trig_uretprobe_ret, &bench_rb_libbpf, &bench_rb_custom, &bench_pb_libbpf, diff --git a/tools/testing/selftests/bpf/benchs/bench_trigger.c b/tools/testing/selftests/bpf/benchs/bench_trigger.c index dbd362771d6a..064a1ef7a6fb 100644 --- a/tools/testing/selftests/bpf/benchs/bench_trigger.c +++ b/tools/testing/selftests/bpf/benchs/bench_trigger.c @@ -113,12 +113,25 @@ static void trigger_fmodret_setup(void) * GCC doesn't generate stack setup preample for these functions due to them * having no input arguments and doing nothing in the body. */ -__weak void uprobe_target_with_nop(void) +__weak void uprobe_target_nop(void) { asm volatile ("nop"); } -__weak void uprobe_target_without_nop(void) +__weak void opaque_noop_func(void) +{ +} + +__weak int uprobe_target_push(void) +{ + /* overhead of function call is negligible compared to uprobe + * triggering, so this shouldn't affect benchmark results much + */ + opaque_noop_func(); + return 1; +} + +__weak void uprobe_target_ret(void) { asm volatile (""); } @@ -126,27 +139,34 @@ __weak void uprobe_target_without_nop(void) static void *uprobe_base_producer(void *input) { while (true) { - uprobe_target_with_nop(); + uprobe_target_nop(); atomic_inc(&base_hits.value); } return NULL; } -static void *uprobe_producer_with_nop(void *input) +static void *uprobe_producer_nop(void *input) { while (true) - uprobe_target_with_nop(); + uprobe_target_nop(); return NULL; } -static void *uprobe_producer_without_nop(void *input) +static void *uprobe_producer_push(void *input) { while (true) - uprobe_target_without_nop(); + uprobe_target_push(); return NULL; } -static void usetup(bool use_retprobe, bool use_nop) +static void *uprobe_producer_ret(void *input) +{ + while (true) + uprobe_target_ret(); + return NULL; +} + +static void usetup(bool use_retprobe, void *target_addr) { size_t uprobe_offset; struct bpf_link *link; @@ -159,11 +179,7 @@ static void usetup(bool use_retprobe, bool use_nop) exit(1); } - if (use_nop) - uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop); - else - uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop); - + uprobe_offset = get_uprobe_offset(target_addr); link = bpf_program__attach_uprobe(ctx.skel->progs.bench_trigger_uprobe, use_retprobe, -1 /* all PIDs */, @@ -176,24 +192,34 @@ static void usetup(bool use_retprobe, bool use_nop) ctx.skel->links.bench_trigger_uprobe = link; } -static void uprobe_setup_with_nop(void) +static void uprobe_setup_nop(void) { - usetup(false, true); + usetup(false, &uprobe_target_nop); } -static void uretprobe_setup_with_nop(void) +static void uretprobe_setup_nop(void) { - usetup(true, true); + usetup(true, &uprobe_target_nop); } -static void uprobe_setup_without_nop(void) +static void uprobe_setup_push(void) { - usetup(false, false); + usetup(false, &uprobe_target_push); } -static void uretprobe_setup_without_nop(void) +static void uretprobe_setup_push(void) { - usetup(true, false); + usetup(true, &uprobe_target_push); +} + +static void uprobe_setup_ret(void) +{ + usetup(false, &uprobe_target_ret); +} + +static void uretprobe_setup_ret(void) +{ + usetup(true, &uprobe_target_ret); } const struct bench bench_trig_base = { @@ -274,37 +300,55 @@ const struct bench bench_trig_uprobe_base = { .report_final = hits_drops_report_final, }; -const struct bench bench_trig_uprobe_with_nop = { - .name = "trig-uprobe-with-nop", - .setup = uprobe_setup_with_nop, - .producer_thread = uprobe_producer_with_nop, +const struct bench bench_trig_uprobe_nop = { + .name = "trig-uprobe-nop", + .setup = uprobe_setup_nop, + .producer_thread = uprobe_producer_nop, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, }; -const struct bench bench_trig_uretprobe_with_nop = { - .name = "trig-uretprobe-with-nop", - .setup = uretprobe_setup_with_nop, - .producer_thread = uprobe_producer_with_nop, +const struct bench bench_trig_uretprobe_nop = { + .name = "trig-uretprobe-nop", + .setup = uretprobe_setup_nop, + .producer_thread = uprobe_producer_nop, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, }; -const struct bench bench_trig_uprobe_without_nop = { - .name = "trig-uprobe-without-nop", - .setup = uprobe_setup_without_nop, - .producer_thread = uprobe_producer_without_nop, +const struct bench bench_trig_uprobe_push = { + .name = "trig-uprobe-push", + .setup = uprobe_setup_push, + .producer_thread = uprobe_producer_push, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, }; -const struct bench bench_trig_uretprobe_without_nop = { - .name = "trig-uretprobe-without-nop", - .setup = uretprobe_setup_without_nop, - .producer_thread = uprobe_producer_without_nop, +const struct bench bench_trig_uretprobe_push = { + .name = "trig-uretprobe-push", + .setup = uretprobe_setup_push, + .producer_thread = uprobe_producer_push, + .measure = trigger_measure, + .report_progress = hits_drops_report_progress, + .report_final = hits_drops_report_final, +}; + +const struct bench bench_trig_uprobe_ret = { + .name = "trig-uprobe-ret", + .setup = uprobe_setup_ret, + .producer_thread = uprobe_producer_ret, + .measure = trigger_measure, + .report_progress = hits_drops_report_progress, + .report_final = hits_drops_report_final, +}; + +const struct bench bench_trig_uretprobe_ret = { + .name = "trig-uretprobe-ret", + .setup = uretprobe_setup_ret, + .producer_thread = uprobe_producer_ret, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/run_bench_uprobes.sh b/tools/testing/selftests/bpf/benchs/run_bench_uprobes.sh new file mode 100755 index 000000000000..9bdcc74e03a4 --- /dev/null +++ b/tools/testing/selftests/bpf/benchs/run_bench_uprobes.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -eufo pipefail + +for i in base {uprobe,uretprobe}-{nop,push,ret} +do + summary=$(sudo ./bench -w2 -d5 -a trig-$i | tail -n1 | cut -d'(' -f1 | cut -d' ' -f3-) + printf "%-15s: %s\n" $i "$summary" +done From 01031fd473059bf69bb6edc6d51d4bd58ad92e50 Mon Sep 17 00:00:00 2001 From: Song Yoong Siang Date: Sun, 3 Mar 2024 16:32:24 +0800 Subject: [PATCH 1800/2255] selftests/bpf: xdp_hw_metadata reduce sleep interval In current ping-pong design, xdp_hw_metadata will wait until the packet transmission completely done, then only start to receive the next packet. The current sleep interval is 10ms, which is unnecessary large. Typically, a NIC does not need such a long time to transmit a packet. Furthermore, during this 10ms sleep time, the app is unable to receive incoming packets. Therefore, this commit reduce sleep interval to 10us, so that xdp_hw_metadata is able to support periodic packets with shorter interval. 10us * 500 = 5ms should be enough for packet transmission and status retrieval. Signed-off-by: Song Yoong Siang Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20240303083225.1184165-2-yoong.siang.song@intel.com --- tools/testing/selftests/bpf/xdp_hw_metadata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c index 878d68db0325..bdf5d8180067 100644 --- a/tools/testing/selftests/bpf/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c @@ -480,7 +480,7 @@ peek: for (int j = 0; j < 500; j++) { if (complete_tx(xsk, clock_id)) break; - usleep(10*1000); + usleep(10); } } } From 5dc283fa5cf72011248b00e1036b17876e4f5a40 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:31 -0800 Subject: [PATCH 1801/2255] idpf: add idpf_virtchnl.h idpf.h is quite heavy. We can reduce the burden a fair bit by introducing an idpf_virtchnl.h file. This mostly just moves function declarations but there are many of them. This also makes an attempt to group those declarations in a way that makes some sense instead of mishmashed. Suggested-by: Alexander Lobakin Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 50 ------------- drivers/net/ethernet/intel/idpf/idpf_dev.c | 1 + drivers/net/ethernet/intel/idpf/idpf_lib.c | 1 + drivers/net/ethernet/intel/idpf/idpf_main.c | 1 + drivers/net/ethernet/intel/idpf/idpf_txrx.c | 1 + drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 1 + .../net/ethernet/intel/idpf/idpf_virtchnl.c | 1 + .../net/ethernet/intel/idpf/idpf_virtchnl.h | 71 +++++++++++++++++++ 8 files changed, 77 insertions(+), 50 deletions(-) create mode 100644 drivers/net/ethernet/intel/idpf/idpf_virtchnl.h diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 0acc125decb3..b2f1bc63c3b6 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -903,68 +903,18 @@ void idpf_mbx_task(struct work_struct *work); void idpf_vc_event_task(struct work_struct *work); void idpf_dev_ops_init(struct idpf_adapter *adapter); void idpf_vf_dev_ops_init(struct idpf_adapter *adapter); -int idpf_vport_adjust_qs(struct idpf_vport *vport); -int idpf_init_dflt_mbx(struct idpf_adapter *adapter); -void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter); -int idpf_vc_core_init(struct idpf_adapter *adapter); -void idpf_vc_core_deinit(struct idpf_adapter *adapter); int idpf_intr_req(struct idpf_adapter *adapter); void idpf_intr_rel(struct idpf_adapter *adapter); -int idpf_get_reg_intr_vecs(struct idpf_vport *vport, - struct idpf_vec_regs *reg_vals); u16 idpf_get_max_tx_hdr_size(struct idpf_adapter *adapter); -int idpf_send_delete_queues_msg(struct idpf_vport *vport); -int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, - u16 num_complq, u16 num_rx_q, u16 num_rx_bufq); int idpf_initiate_soft_reset(struct idpf_vport *vport, enum idpf_vport_reset_cause reset_cause); -int idpf_send_enable_vport_msg(struct idpf_vport *vport); -int idpf_send_disable_vport_msg(struct idpf_vport *vport); -int idpf_send_destroy_vport_msg(struct idpf_vport *vport); -int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport); -int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport); -int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get); -int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get); -int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter); -int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors); void idpf_deinit_task(struct idpf_adapter *adapter); int idpf_req_rel_vector_indexes(struct idpf_adapter *adapter, u16 *q_vector_idxs, struct idpf_vector_info *vec_info); -int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport); -int idpf_send_get_stats_msg(struct idpf_vport *vport); -int idpf_get_vec_ids(struct idpf_adapter *adapter, - u16 *vecids, int num_vecids, - struct virtchnl2_vector_chunks *chunks); -int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, - void *msg, int msg_size); -int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op, - u16 msg_size, u8 *msg); void idpf_set_ethtool_ops(struct net_device *netdev); -int idpf_vport_alloc_max_qs(struct idpf_adapter *adapter, - struct idpf_vport_max_q *max_q); -void idpf_vport_dealloc_max_qs(struct idpf_adapter *adapter, - struct idpf_vport_max_q *max_q); -int idpf_add_del_mac_filters(struct idpf_vport *vport, - struct idpf_netdev_priv *np, - bool add, bool async); -int idpf_set_promiscuous(struct idpf_adapter *adapter, - struct idpf_vport_user_config_data *config_data, - u32 vport_id); -int idpf_send_disable_queues_msg(struct idpf_vport *vport); -void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q); -u32 idpf_get_vport_id(struct idpf_vport *vport); -int idpf_vport_queue_ids_init(struct idpf_vport *vport); -int idpf_queue_reg_init(struct idpf_vport *vport); -int idpf_send_config_queues_msg(struct idpf_vport *vport); -int idpf_send_enable_queues_msg(struct idpf_vport *vport); -int idpf_send_create_vport_msg(struct idpf_adapter *adapter, - struct idpf_vport_max_q *max_q); -int idpf_check_supported_desc_ids(struct idpf_vport *vport); void idpf_vport_intr_write_itr(struct idpf_q_vector *q_vector, u16 itr, bool tx); -int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map); -int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs); int idpf_sriov_configure(struct pci_dev *pdev, int num_vfs); u8 idpf_vport_get_hsplit(const struct idpf_vport *vport); diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c index 34ad1ac46b78..3df9935685e9 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_dev.c +++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c @@ -3,6 +3,7 @@ #include "idpf.h" #include "idpf_lan_pf_regs.h" +#include "idpf_virtchnl.h" #define IDPF_PF_ITR_IDX_SPACING 0x4 diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 58179bd733ff..1832f800a370 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -2,6 +2,7 @@ /* Copyright (C) 2023 Intel Corporation */ #include "idpf.h" +#include "idpf_virtchnl.h" static const struct net_device_ops idpf_netdev_ops_splitq; static const struct net_device_ops idpf_netdev_ops_singleq; diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c index e1febc74cefd..92e73fdd7bbe 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_main.c +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c @@ -3,6 +3,7 @@ #include "idpf.h" #include "idpf_devids.h" +#include "idpf_virtchnl.h" #define DRV_SUMMARY "Intel(R) Infrastructure Data Path Function Linux Driver" diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 2f8ad79ae3f0..6dd7a66bb897 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -2,6 +2,7 @@ /* Copyright (C) 2023 Intel Corporation */ #include "idpf.h" +#include "idpf_virtchnl.h" /** * idpf_buf_lifo_push - push a buffer pointer onto stack diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c index 8ade4e3a9fe1..be40dd68358e 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c @@ -3,6 +3,7 @@ #include "idpf.h" #include "idpf_lan_vf_regs.h" +#include "idpf_virtchnl.h" #define IDPF_VF_ITR_IDX_SPACING 0x40 diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index d0cdd63b3d5b..6217a05389cd 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -2,6 +2,7 @@ /* Copyright (C) 2023 Intel Corporation */ #include "idpf.h" +#include "idpf_virtchnl.h" /** * idpf_recv_event_msg - Receive virtchnl event message diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h new file mode 100644 index 000000000000..78aff791f3a9 --- /dev/null +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2024 Intel Corporation */ + +#ifndef _IDPF_VIRTCHNL_H_ +#define _IDPF_VIRTCHNL_H_ + +struct idpf_adapter; +struct idpf_netdev_priv; +struct idpf_vec_regs; +struct idpf_vport; +struct idpf_vport_max_q; +struct idpf_vport_user_config_data; + +int idpf_init_dflt_mbx(struct idpf_adapter *adapter); +void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter); +int idpf_vc_core_init(struct idpf_adapter *adapter); +void idpf_vc_core_deinit(struct idpf_adapter *adapter); + +int idpf_get_reg_intr_vecs(struct idpf_vport *vport, + struct idpf_vec_regs *reg_vals); +int idpf_queue_reg_init(struct idpf_vport *vport); +int idpf_vport_queue_ids_init(struct idpf_vport *vport); + +int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, + void *msg, int msg_size); +int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op, + u16 msg_size, u8 *msg); + +void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q); +u32 idpf_get_vport_id(struct idpf_vport *vport); +int idpf_send_create_vport_msg(struct idpf_adapter *adapter, + struct idpf_vport_max_q *max_q); +int idpf_send_destroy_vport_msg(struct idpf_vport *vport); +int idpf_send_enable_vport_msg(struct idpf_vport *vport); +int idpf_send_disable_vport_msg(struct idpf_vport *vport); + +int idpf_vport_adjust_qs(struct idpf_vport *vport); +int idpf_vport_alloc_max_qs(struct idpf_adapter *adapter, + struct idpf_vport_max_q *max_q); +void idpf_vport_dealloc_max_qs(struct idpf_adapter *adapter, + struct idpf_vport_max_q *max_q); +int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, + u16 num_complq, u16 num_rx_q, u16 num_rx_bufq); +int idpf_send_delete_queues_msg(struct idpf_vport *vport); +int idpf_send_enable_queues_msg(struct idpf_vport *vport); +int idpf_send_disable_queues_msg(struct idpf_vport *vport); +int idpf_send_config_queues_msg(struct idpf_vport *vport); + +int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport); +int idpf_get_vec_ids(struct idpf_adapter *adapter, + u16 *vecids, int num_vecids, + struct virtchnl2_vector_chunks *chunks); +int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors); +int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter); +int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map); + +int idpf_add_del_mac_filters(struct idpf_vport *vport, + struct idpf_netdev_priv *np, + bool add, bool async); +int idpf_set_promiscuous(struct idpf_adapter *adapter, + struct idpf_vport_user_config_data *config_data, + u32 vport_id); +int idpf_check_supported_desc_ids(struct idpf_vport *vport); +int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport); +int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport); +int idpf_send_get_stats_msg(struct idpf_vport *vport); +int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs); +int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get); +int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get); + +#endif /* _IDPF_VIRTCHNL_H_ */ From 34c21fa894a1af6166f4284c81d1dc21efed8f38 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:32 -0800 Subject: [PATCH 1802/2255] idpf: implement virtchnl transaction manager This starts refactoring how virtchnl messages are handled by adding a transaction manager (idpf_vc_xn_manager). There are two primary motivations here which are to enable handling of multiple messages at once and to make it more robust in general. As it is right now, the driver may only have one pending message at a time and there's no guarantee that the response we receive was actually intended for the message we sent prior. This works by utilizing a "cookie" field of the message descriptor. It is arbitrary what data we put in the cookie and the response is required to have the same cookie the original message was sent with. Then using a "transaction" abstraction that uses the completion API to pair responses to the message it belongs to. The cookie works such that the first half is the index to the transaction in our array, and the second half is a "salt" that gets incremented every message. This enables quick lookups into the array and also ensuring we have the correct message. The salt is necessary because after, for example, a message times out and we deem the response was lost for some reason, we could theoretically reuse the same index but using a different salt ensures that when we do actually get a response it's not the old message that timed out previously finally coming in. Since the number of transactions allocated is U8_MAX and the salt is 8 bits, we can never have a conflict because we can't roll over the salt without using more transactions than we have available. This starts by only converting the VIRTCHNL2_OP_VERSION message to use this new transaction API. Follow up patches will convert all virtchnl messages to use the API. Tested-by: Alexander Lobakin Reviewed-by: Przemek Kitszel Reviewed-by: Igor Bagnucki Co-developed-by: Joshua Hay Signed-off-by: Joshua Hay Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 6 +- .../ethernet/intel/idpf/idpf_controlq_api.h | 5 + drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 + drivers/net/ethernet/intel/idpf/idpf_main.c | 3 + drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 2 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 614 ++++++++++++++++-- .../net/ethernet/intel/idpf/idpf_virtchnl.h | 2 +- 7 files changed, 561 insertions(+), 73 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index b2f1bc63c3b6..c3b08d4593b0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -66,14 +66,12 @@ struct idpf_mac_filter { /** * enum idpf_state - State machine to handle bring up - * @__IDPF_STARTUP: Start the state machine * @__IDPF_VER_CHECK: Negotiate virtchnl version * @__IDPF_GET_CAPS: Negotiate capabilities * @__IDPF_INIT_SW: Init based on given capabilities * @__IDPF_STATE_LAST: Must be last, used to determine size */ enum idpf_state { - __IDPF_STARTUP, __IDPF_VER_CHECK, __IDPF_GET_CAPS, __IDPF_INIT_SW, @@ -560,6 +558,8 @@ struct idpf_vport_config { DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS); }; +struct idpf_vc_xn_manager; + /** * struct idpf_adapter - Device data struct generated on probe * @pdev: PCI device struct given on probe @@ -604,6 +604,7 @@ struct idpf_vport_config { * @vchnl_wq: Wait queue for virtchnl messages * @vc_state: Virtchnl message state * @vc_msg: Virtchnl message buffer + * @vcxn_mngr: Virtchnl transaction manager * @dev_ops: See idpf_dev_ops * @num_vfs: Number of allocated VFs through sysfs. PF does not directly talk * to VFs but is used to initialize them @@ -663,6 +664,7 @@ struct idpf_adapter { wait_queue_head_t vchnl_wq; DECLARE_BITMAP(vc_state, IDPF_VC_NBITS); char vc_msg[IDPF_CTLQ_MAX_BUF_LEN]; + struct idpf_vc_xn_manager *vcxn_mngr; struct idpf_dev_ops dev_ops; int num_vfs; bool crc_enable; diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h index 8dee098bbfb0..e8e046ef2f0d 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h +++ b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h @@ -69,6 +69,11 @@ struct idpf_ctlq_msg { u8 context[IDPF_INDIRECT_CTX_SIZE]; struct idpf_dma_mem *payload; } indirect; + struct { + u32 rsvd; + u16 data; + u16 flags; + } sw_cookie; } ctx; }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 1832f800a370..96c0b6d38799 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1824,6 +1824,8 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter) goto unlock_mutex; } + queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0); + /* Initialize the state machine, also allocate memory and request * resources */ diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c index 92e73fdd7bbe..c9b6ef3166aa 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_main.c +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c @@ -31,6 +31,7 @@ static void idpf_remove(struct pci_dev *pdev) idpf_sriov_configure(pdev, 0); idpf_vc_core_deinit(adapter); + /* Be a good citizen and leave the device clean on exit */ adapter->dev_ops.reg_ops.trigger_reset(adapter, IDPF_HR_FUNC_RESET); idpf_deinit_dflt_mbx(adapter); @@ -67,6 +68,8 @@ destroy_wqs: adapter->vport_config = NULL; kfree(adapter->netdevs); adapter->netdevs = NULL; + kfree(adapter->vcxn_mngr); + adapter->vcxn_mngr = NULL; mutex_destroy(&adapter->vport_ctrl_lock); mutex_destroy(&adapter->vector_lock); diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c index be40dd68358e..629cb5cb7c9f 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c @@ -138,7 +138,7 @@ static void idpf_vf_trigger_reset(struct idpf_adapter *adapter, /* Do not send VIRTCHNL2_OP_RESET_VF message on driver unload */ if (trig_cause == IDPF_HR_FUNC_RESET && !test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) - idpf_send_mb_msg(adapter, VIRTCHNL2_OP_RESET_VF, 0, NULL); + idpf_send_mb_msg(adapter, VIRTCHNL2_OP_RESET_VF, 0, NULL, 0); } /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 6217a05389cd..95ca10f644b2 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -4,6 +4,102 @@ #include "idpf.h" #include "idpf_virtchnl.h" +#define IDPF_VC_XN_MIN_TIMEOUT_MSEC 2000 +#define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC (60 * 1000) +#define IDPF_VC_XN_IDX_M GENMASK(7, 0) +#define IDPF_VC_XN_SALT_M GENMASK(15, 8) +#define IDPF_VC_XN_RING_LEN U8_MAX + +/** + * enum idpf_vc_xn_state - Virtchnl transaction status + * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used + * @IDPF_VC_XN_WAITING: expecting a reply, not yet received + * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, + * buffer updated + * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there + * was an error, buffer not updated + * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down + * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the + * return context; a callback may be provided to handle + * return + */ +enum idpf_vc_xn_state { + IDPF_VC_XN_IDLE = 1, + IDPF_VC_XN_WAITING, + IDPF_VC_XN_COMPLETED_SUCCESS, + IDPF_VC_XN_COMPLETED_FAILED, + IDPF_VC_XN_SHUTDOWN, + IDPF_VC_XN_ASYNC, +}; + +struct idpf_vc_xn; +/* Callback for asynchronous messages */ +typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *, + const struct idpf_ctlq_msg *); + +/** + * struct idpf_vc_xn - Data structure representing virtchnl transactions + * @completed: virtchnl event loop uses that to signal when a reply is + * available, uses kernel completion API + * @state: virtchnl event loop stores the data below, protected by the + * completion's lock. + * @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be + * truncated on its way to the receiver thread according to + * reply_buf.iov_len. + * @reply: Reference to the buffer(s) where the reply data should be written + * to. May be 0-length (then NULL address permitted) if the reply data + * should be ignored. + * @async_handler: if sent asynchronously, a callback can be provided to handle + * the reply when it's received + * @vc_op: corresponding opcode sent with this transaction + * @idx: index used as retrieval on reply receive, used for cookie + * @salt: changed every message to make unique, used for cookie + */ +struct idpf_vc_xn { + struct completion completed; + enum idpf_vc_xn_state state; + size_t reply_sz; + struct kvec reply; + async_vc_cb async_handler; + u32 vc_op; + u8 idx; + u8 salt; +}; + +/** + * struct idpf_vc_xn_params - Parameters for executing transaction + * @send_buf: kvec for send buffer + * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length + * @timeout_ms: timeout to wait for reply + * @async: send message asynchronously, will not wait on completion + * @async_handler: If sent asynchronously, optional callback handler. The user + * must be careful when using async handlers as the memory for + * the recv_buf _cannot_ be on stack if this is async. + * @vc_op: virtchnl op to send + */ +struct idpf_vc_xn_params { + struct kvec send_buf; + struct kvec recv_buf; + int timeout_ms; + bool async; + async_vc_cb async_handler; + u32 vc_op; +}; + +/** + * struct idpf_vc_xn_manager - Manager for tracking transactions + * @ring: backing and lookup for transactions + * @free_xn_bm: bitmap for free transactions + * @xn_bm_lock: make bitmap access synchronous where necessary + * @salt: used to make cookie unique every message + */ +struct idpf_vc_xn_manager { + struct idpf_vc_xn ring[IDPF_VC_XN_RING_LEN]; + DECLARE_BITMAP(free_xn_bm, IDPF_VC_XN_RING_LEN); + spinlock_t xn_bm_lock; + u8 salt; +}; + /** * idpf_recv_event_msg - Receive virtchnl event message * @vport: virtual port structure @@ -94,13 +190,14 @@ err_kfree: * @op: virtchnl opcode * @msg_size: size of the payload * @msg: pointer to buffer holding the payload + * @cookie: unique SW generated cookie per message * * Will prepare the control queue message and initiates the send api * * Returns 0 on success, negative on failure */ int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op, - u16 msg_size, u8 *msg) + u16 msg_size, u8 *msg, u16 cookie) { struct idpf_ctlq_msg *ctlq_msg; struct idpf_dma_mem *dma_mem; @@ -140,8 +237,12 @@ int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op, err = -ENOMEM; goto dma_alloc_error; } - memcpy(dma_mem->va, msg, msg_size); + + /* It's possible we're just sending an opcode but no buffer */ + if (msg && msg_size) + memcpy(dma_mem->va, msg, msg_size); ctlq_msg->ctx.indirect.payload = dma_mem; + ctlq_msg->ctx.sw_cookie.data = cookie; err = idpf_ctlq_send(&adapter->hw, adapter->hw.asq, 1, ctlq_msg); if (err) @@ -362,6 +463,378 @@ static void idpf_recv_vchnl_op(struct idpf_adapter *adapter, } } +/* API for virtchnl "transaction" support ("xn" for short). + * + * We are reusing the completion lock to serialize the accesses to the + * transaction state for simplicity, but it could be its own separate synchro + * as well. For now, this API is only used from within a workqueue context; + * raw_spin_lock() is enough. + */ +/** + * idpf_vc_xn_lock - Request exclusive access to vc transaction + * @xn: struct idpf_vc_xn* to access + */ +#define idpf_vc_xn_lock(xn) \ + raw_spin_lock(&(xn)->completed.wait.lock) + +/** + * idpf_vc_xn_unlock - Release exclusive access to vc transaction + * @xn: struct idpf_vc_xn* to access + */ +#define idpf_vc_xn_unlock(xn) \ + raw_spin_unlock(&(xn)->completed.wait.lock) + +/** + * idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and + * reset the transaction state. + * @xn: struct idpf_vc_xn to update + */ +static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn) +{ + xn->reply.iov_base = NULL; + xn->reply.iov_len = 0; + + if (xn->state != IDPF_VC_XN_SHUTDOWN) + xn->state = IDPF_VC_XN_IDLE; +} + +/** + * idpf_vc_xn_init - Initialize virtchnl transaction object + * @vcxn_mngr: pointer to vc transaction manager struct + */ +static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr) +{ + int i; + + spin_lock_init(&vcxn_mngr->xn_bm_lock); + + for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) { + struct idpf_vc_xn *xn = &vcxn_mngr->ring[i]; + + xn->state = IDPF_VC_XN_IDLE; + xn->idx = i; + idpf_vc_xn_release_bufs(xn); + init_completion(&xn->completed); + } + + bitmap_fill(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN); +} + +/** + * idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object + * @vcxn_mngr: pointer to vc transaction manager struct + * + * All waiting threads will be woken-up and their transaction aborted. Further + * operations on that object will fail. + */ +static void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr) +{ + int i; + + spin_lock_bh(&vcxn_mngr->xn_bm_lock); + bitmap_zero(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN); + spin_unlock_bh(&vcxn_mngr->xn_bm_lock); + + for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) { + struct idpf_vc_xn *xn = &vcxn_mngr->ring[i]; + + idpf_vc_xn_lock(xn); + xn->state = IDPF_VC_XN_SHUTDOWN; + idpf_vc_xn_release_bufs(xn); + idpf_vc_xn_unlock(xn); + complete_all(&xn->completed); + } +} + +/** + * idpf_vc_xn_pop_free - Pop a free transaction from free list + * @vcxn_mngr: transaction manager to pop from + * + * Returns NULL if no free transactions + */ +static +struct idpf_vc_xn *idpf_vc_xn_pop_free(struct idpf_vc_xn_manager *vcxn_mngr) +{ + struct idpf_vc_xn *xn = NULL; + unsigned long free_idx; + + spin_lock_bh(&vcxn_mngr->xn_bm_lock); + free_idx = find_first_bit(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN); + if (free_idx == IDPF_VC_XN_RING_LEN) + goto do_unlock; + + clear_bit(free_idx, vcxn_mngr->free_xn_bm); + xn = &vcxn_mngr->ring[free_idx]; + xn->salt = vcxn_mngr->salt++; + +do_unlock: + spin_unlock_bh(&vcxn_mngr->xn_bm_lock); + + return xn; +} + +/** + * idpf_vc_xn_push_free - Push a free transaction to free list + * @vcxn_mngr: transaction manager to push to + * @xn: transaction to push + */ +static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr, + struct idpf_vc_xn *xn) +{ + idpf_vc_xn_release_bufs(xn); + set_bit(xn->idx, vcxn_mngr->free_xn_bm); +} + +/** + * idpf_vc_xn_exec - Perform a send/recv virtchnl transaction + * @adapter: driver specific private structure with vcxn_mngr + * @params: parameters for this particular transaction including + * -vc_op: virtchannel operation to send + * -send_buf: kvec iov for send buf and len + * -recv_buf: kvec iov for recv buf and len (ignored if NULL) + * -timeout_ms: timeout waiting for a reply (milliseconds) + * -async: don't wait for message reply, will lose caller context + * -async_handler: callback to handle async replies + * + * @returns >= 0 for success, the size of the initial reply (may or may not be + * >= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). < 0 for + * error. + */ +static ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter, + const struct idpf_vc_xn_params *params) +{ + const struct kvec *send_buf = ¶ms->send_buf; + struct idpf_vc_xn *xn; + ssize_t retval; + u16 cookie; + + xn = idpf_vc_xn_pop_free(adapter->vcxn_mngr); + /* no free transactions available */ + if (!xn) + return -ENOSPC; + + idpf_vc_xn_lock(xn); + if (xn->state == IDPF_VC_XN_SHUTDOWN) { + retval = -ENXIO; + goto only_unlock; + } else if (xn->state != IDPF_VC_XN_IDLE) { + /* We're just going to clobber this transaction even though + * it's not IDLE. If we don't reuse it we could theoretically + * eventually leak all the free transactions and not be able to + * send any messages. At least this way we make an attempt to + * remain functional even though something really bad is + * happening that's corrupting what was supposed to be free + * transactions. + */ + WARN_ONCE(1, "There should only be idle transactions in free list (idx %d op %d)\n", + xn->idx, xn->vc_op); + } + + xn->reply = params->recv_buf; + xn->reply_sz = 0; + xn->state = params->async ? IDPF_VC_XN_ASYNC : IDPF_VC_XN_WAITING; + xn->vc_op = params->vc_op; + xn->async_handler = params->async_handler; + idpf_vc_xn_unlock(xn); + + if (!params->async) + reinit_completion(&xn->completed); + cookie = FIELD_PREP(IDPF_VC_XN_SALT_M, xn->salt) | + FIELD_PREP(IDPF_VC_XN_IDX_M, xn->idx); + + retval = idpf_send_mb_msg(adapter, params->vc_op, + send_buf->iov_len, send_buf->iov_base, + cookie); + if (retval) { + idpf_vc_xn_lock(xn); + goto release_and_unlock; + } + + if (params->async) + return 0; + + wait_for_completion_timeout(&xn->completed, + msecs_to_jiffies(params->timeout_ms)); + + /* No need to check the return value; we check the final state of the + * transaction below. It's possible the transaction actually gets more + * timeout than specified if we get preempted here but after + * wait_for_completion_timeout returns. This should be non-issue + * however. + */ + idpf_vc_xn_lock(xn); + switch (xn->state) { + case IDPF_VC_XN_SHUTDOWN: + retval = -ENXIO; + goto only_unlock; + case IDPF_VC_XN_WAITING: + dev_notice_ratelimited(&adapter->pdev->dev, "Transaction timed-out (op %d, %dms)\n", + params->vc_op, params->timeout_ms); + retval = -ETIME; + break; + case IDPF_VC_XN_COMPLETED_SUCCESS: + retval = xn->reply_sz; + break; + case IDPF_VC_XN_COMPLETED_FAILED: + dev_notice_ratelimited(&adapter->pdev->dev, "Transaction failed (op %d)\n", + params->vc_op); + retval = -EIO; + break; + default: + /* Invalid state. */ + WARN_ON_ONCE(1); + retval = -EIO; + break; + } + +release_and_unlock: + idpf_vc_xn_push_free(adapter->vcxn_mngr, xn); + /* If we receive a VC reply after here, it will be dropped. */ +only_unlock: + idpf_vc_xn_unlock(xn); + + return retval; +} + +/** + * idpf_vc_xn_forward_async - Handle async reply receives + * @adapter: private data struct + * @xn: transaction to handle + * @ctlq_msg: corresponding ctlq_msg + * + * For async sends we're going to lose the caller's context so, if an + * async_handler was provided, it can deal with the reply, otherwise we'll just + * check and report if there is an error. + */ +static int +idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn, + const struct idpf_ctlq_msg *ctlq_msg) +{ + int err = 0; + + if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) { + dev_err_ratelimited(&adapter->pdev->dev, "Async message opcode does not match transaction opcode (msg: %d) (xn: %d)\n", + ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op); + xn->reply_sz = 0; + err = -EINVAL; + goto release_bufs; + } + + if (xn->async_handler) { + err = xn->async_handler(adapter, xn, ctlq_msg); + goto release_bufs; + } + + if (ctlq_msg->cookie.mbx.chnl_retval) { + xn->reply_sz = 0; + dev_err_ratelimited(&adapter->pdev->dev, "Async message failure (op %d)\n", + ctlq_msg->cookie.mbx.chnl_opcode); + err = -EINVAL; + } + +release_bufs: + idpf_vc_xn_push_free(adapter->vcxn_mngr, xn); + + return err; +} + +/** + * idpf_vc_xn_forward_reply - copy a reply back to receiving thread + * @adapter: driver specific private structure with vcxn_mngr + * @ctlq_msg: controlq message to send back to receiving thread + */ +static int +idpf_vc_xn_forward_reply(struct idpf_adapter *adapter, + const struct idpf_ctlq_msg *ctlq_msg) +{ + const void *payload = NULL; + size_t payload_size = 0; + struct idpf_vc_xn *xn; + u16 msg_info; + int err = 0; + u16 xn_idx; + u16 salt; + + msg_info = ctlq_msg->ctx.sw_cookie.data; + xn_idx = FIELD_GET(IDPF_VC_XN_IDX_M, msg_info); + if (xn_idx >= ARRAY_SIZE(adapter->vcxn_mngr->ring)) { + dev_err_ratelimited(&adapter->pdev->dev, "Out of bounds cookie received: %02x\n", + xn_idx); + return -EINVAL; + } + xn = &adapter->vcxn_mngr->ring[xn_idx]; + salt = FIELD_GET(IDPF_VC_XN_SALT_M, msg_info); + if (xn->salt != salt) { + dev_err_ratelimited(&adapter->pdev->dev, "Transaction salt does not match (%02x != %02x)\n", + xn->salt, salt); + return -EINVAL; + } + + idpf_vc_xn_lock(xn); + switch (xn->state) { + case IDPF_VC_XN_WAITING: + /* success */ + break; + case IDPF_VC_XN_IDLE: + dev_err_ratelimited(&adapter->pdev->dev, "Unexpected or belated VC reply (op %d)\n", + ctlq_msg->cookie.mbx.chnl_opcode); + err = -EINVAL; + goto out_unlock; + case IDPF_VC_XN_SHUTDOWN: + /* ENXIO is a bit special here as the recv msg loop uses that + * know if it should stop trying to clean the ring if we lost + * the virtchnl. We need to stop playing with registers and + * yield. + */ + err = -ENXIO; + goto out_unlock; + case IDPF_VC_XN_ASYNC: + err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg); + idpf_vc_xn_unlock(xn); + return err; + default: + dev_err_ratelimited(&adapter->pdev->dev, "Overwriting VC reply (op %d)\n", + ctlq_msg->cookie.mbx.chnl_opcode); + err = -EBUSY; + goto out_unlock; + } + + if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) { + dev_err_ratelimited(&adapter->pdev->dev, "Message opcode does not match transaction opcode (msg: %d) (xn: %d)\n", + ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op); + xn->reply_sz = 0; + xn->state = IDPF_VC_XN_COMPLETED_FAILED; + err = -EINVAL; + goto out_unlock; + } + + if (ctlq_msg->cookie.mbx.chnl_retval) { + xn->reply_sz = 0; + xn->state = IDPF_VC_XN_COMPLETED_FAILED; + err = -EINVAL; + goto out_unlock; + } + + if (ctlq_msg->data_len) { + payload = ctlq_msg->ctx.indirect.payload->va; + payload_size = ctlq_msg->ctx.indirect.payload->size; + } + + xn->reply_sz = payload_size; + xn->state = IDPF_VC_XN_COMPLETED_SUCCESS; + + if (xn->reply.iov_base && xn->reply.iov_len && payload_size) + memcpy(xn->reply.iov_base, payload, + min_t(size_t, xn->reply.iov_len, payload_size)); + +out_unlock: + idpf_vc_xn_unlock(xn); + /* we _cannot_ hold lock while calling complete */ + complete(&xn->completed); + + return err; +} + /** * idpf_recv_mb_msg - Receive message over mailbox * @adapter: Driver specific private structure @@ -430,6 +903,8 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, */ switch (ctlq_msg.cookie.mbx.chnl_opcode) { case VIRTCHNL2_OP_VERSION: + err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); + break; case VIRTCHNL2_OP_GET_CAPS: if (ctlq_msg.cookie.mbx.chnl_retval) { dev_err(&adapter->pdev->dev, "Failure initializing, vc op: %u retval: %u\n", @@ -786,7 +1261,11 @@ static int idpf_wait_for_marker_event(struct idpf_vport *vport) */ static int idpf_send_ver_msg(struct idpf_adapter *adapter) { + struct idpf_vc_xn_params xn_params = {}; struct virtchnl2_version_info vvi; + ssize_t reply_sz; + u32 major, minor; + int err = 0; if (adapter->virt_ver_maj) { vvi.major = cpu_to_le32(adapter->virt_ver_maj); @@ -796,43 +1275,29 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter) vvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR); } - return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_VERSION, sizeof(vvi), - (u8 *)&vvi); -} + xn_params.vc_op = VIRTCHNL2_OP_VERSION; + xn_params.send_buf.iov_base = &vvi; + xn_params.send_buf.iov_len = sizeof(vvi); + xn_params.recv_buf = xn_params.send_buf; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; -/** - * idpf_recv_ver_msg - Receive virtchnl version message - * @adapter: Driver specific private structure - * - * Receive virtchnl version message. Returns 0 on success, -EAGAIN if we need - * to send version message again, otherwise negative on failure. - */ -static int idpf_recv_ver_msg(struct idpf_adapter *adapter) -{ - struct virtchnl2_version_info vvi; - u32 major, minor; - int err; - - err = idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_VERSION, &vvi, - sizeof(vvi)); - if (err) - return err; + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; + if (reply_sz < sizeof(vvi)) + return -EIO; major = le32_to_cpu(vvi.major); minor = le32_to_cpu(vvi.minor); if (major > IDPF_VIRTCHNL_VERSION_MAJOR) { - dev_warn(&adapter->pdev->dev, - "Virtchnl major version (%d) greater than supported\n", - major); - + dev_warn(&adapter->pdev->dev, "Virtchnl major version greater than supported\n"); return -EINVAL; } if (major == IDPF_VIRTCHNL_VERSION_MAJOR && minor > IDPF_VIRTCHNL_VERSION_MINOR) - dev_warn(&adapter->pdev->dev, - "Virtchnl minor version (%d) didn't match\n", minor); + dev_warn(&adapter->pdev->dev, "Virtchnl minor version didn't match\n"); /* If we have a mismatch, resend version to update receiver on what * version we will use. @@ -915,7 +1380,7 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter) VIRTCHNL2_CAP_LOOPBACK); return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, sizeof(caps), - (u8 *)&caps); + (u8 *)&caps, 0); } /** @@ -1290,7 +1755,7 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter, mutex_lock(&adapter->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CREATE_VPORT, buf_size, - (u8 *)vport_msg); + (u8 *)vport_msg, 0); if (err) goto rel_lock; @@ -1376,7 +1841,7 @@ int idpf_send_destroy_vport_msg(struct idpf_vport *vport) mutex_lock(&vport->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DESTROY_VPORT, - sizeof(v_id), (u8 *)&v_id); + sizeof(v_id), (u8 *)&v_id, 0); if (err) goto rel_lock; @@ -1407,7 +1872,7 @@ int idpf_send_enable_vport_msg(struct idpf_vport *vport) mutex_lock(&vport->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ENABLE_VPORT, - sizeof(v_id), (u8 *)&v_id); + sizeof(v_id), (u8 *)&v_id, 0); if (err) goto rel_lock; @@ -1438,7 +1903,7 @@ int idpf_send_disable_vport_msg(struct idpf_vport *vport) mutex_lock(&vport->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DISABLE_VPORT, - sizeof(v_id), (u8 *)&v_id); + sizeof(v_id), (u8 *)&v_id, 0); if (err) goto rel_lock; @@ -1557,7 +2022,7 @@ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport) err = idpf_send_mb_msg(vport->adapter, VIRTCHNL2_OP_CONFIG_TX_QUEUES, - buf_sz, (u8 *)ctq); + buf_sz, (u8 *)ctq, 0); if (err) goto mbx_error; @@ -1709,7 +2174,7 @@ common_qi_fields: err = idpf_send_mb_msg(vport->adapter, VIRTCHNL2_OP_CONFIG_RX_QUEUES, - buf_sz, (u8 *)crq); + buf_sz, (u8 *)crq, 0); if (err) goto mbx_error; @@ -1876,7 +2341,7 @@ send_msg: qcs = &eq->chunks; memcpy(qcs->chunks, &qc[k], chunk_sz * num_chunks); - err = idpf_send_mb_msg(adapter, vc_op, buf_sz, (u8 *)eq); + err = idpf_send_mb_msg(adapter, vc_op, buf_sz, (u8 *)eq, 0); if (err) goto mbx_error; @@ -2020,7 +2485,7 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) if (map) { err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_MAP_QUEUE_VECTOR, - buf_sz, (u8 *)vqvm); + buf_sz, (u8 *)vqvm, 0); if (!err) err = idpf_wait_for_event(adapter, vport, IDPF_VC_MAP_IRQ, @@ -2028,7 +2493,7 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) } else { err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR, - buf_sz, (u8 *)vqvm); + buf_sz, (u8 *)vqvm, 0); if (!err) err = idpf_min_wait_for_event(adapter, vport, @@ -2158,7 +2623,7 @@ int idpf_send_delete_queues_msg(struct idpf_vport *vport) mutex_lock(&vport->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEL_QUEUES, - buf_size, (u8 *)eq); + buf_size, (u8 *)eq, 0); if (err) goto rel_lock; @@ -2222,7 +2687,7 @@ int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, mutex_lock(&((struct idpf_vport *)vport)->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ADD_QUEUES, - sizeof(struct virtchnl2_add_queues), (u8 *)&aq); + sizeof(struct virtchnl2_add_queues), (u8 *)&aq, 0); if (err) goto rel_lock; @@ -2281,7 +2746,7 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors) mutex_lock(&adapter->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ALLOC_VECTORS, - sizeof(ac), (u8 *)&ac); + sizeof(ac), (u8 *)&ac, 0); if (err) goto rel_lock; @@ -2337,7 +2802,7 @@ int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter) mutex_lock(&adapter->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEALLOC_VECTORS, buf_size, - (u8 *)vcs); + (u8 *)vcs, 0); if (err) goto rel_lock; @@ -2383,7 +2848,7 @@ int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs) mutex_lock(&adapter->vc_buf_lock); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_SRIOV_VFS, - sizeof(svi), (u8 *)&svi); + sizeof(svi), (u8 *)&svi, 0); if (err) goto rel_lock; @@ -2421,7 +2886,7 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport) err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_STATS, sizeof(struct virtchnl2_vport_stats), - (u8 *)&stats_msg); + (u8 *)&stats_msg, 0); if (err) goto rel_lock; @@ -2490,7 +2955,7 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]); err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_LUT, - buf_size, (u8 *)rl); + buf_size, (u8 *)rl, 0); if (err) goto free_mem; @@ -2501,7 +2966,7 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) } err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_LUT, - buf_size, (u8 *)rl); + buf_size, (u8 *)rl, 0); if (err) goto free_mem; @@ -2560,7 +3025,7 @@ int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get) if (get) { err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_KEY, - buf_size, (u8 *)rk); + buf_size, (u8 *)rk, 0); if (err) goto error; @@ -2592,7 +3057,7 @@ int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get) rk->key_flex[i] = rss_data->rss_key[i]; err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_KEY, - buf_size, (u8 *)rk); + buf_size, (u8 *)rk, 0); if (err) goto error; @@ -2689,7 +3154,7 @@ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport) err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_PTYPE_INFO, sizeof(struct virtchnl2_get_ptype_info), - (u8 *)&get_ptype_info); + (u8 *)&get_ptype_info, 0); if (err) goto vc_buf_unlock; @@ -2883,7 +3348,7 @@ int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport) mutex_lock(&vport->vc_buf_lock); err = idpf_send_mb_msg(vport->adapter, VIRTCHNL2_OP_LOOPBACK, - sizeof(loopback), (u8 *)&loopback); + sizeof(loopback), (u8 *)&loopback, 0); if (err) goto rel_lock; @@ -2959,7 +3424,7 @@ int idpf_init_dflt_mbx(struct idpf_adapter *adapter) return -ENOENT; } - adapter->state = __IDPF_STARTUP; + adapter->state = __IDPF_VER_CHECK; return 0; } @@ -3056,27 +3521,35 @@ int idpf_vc_core_init(struct idpf_adapter *adapter) u16 num_max_vports; int err = 0; + if (!adapter->vcxn_mngr) { + adapter->vcxn_mngr = kzalloc(sizeof(*adapter->vcxn_mngr), GFP_KERNEL); + if (!adapter->vcxn_mngr) { + err = -ENOMEM; + goto init_failed; + } + } + idpf_vc_xn_init(adapter->vcxn_mngr); + while (adapter->state != __IDPF_INIT_SW) { switch (adapter->state) { - case __IDPF_STARTUP: - if (idpf_send_ver_msg(adapter)) - goto init_failed; - adapter->state = __IDPF_VER_CHECK; - goto restart; case __IDPF_VER_CHECK: - err = idpf_recv_ver_msg(adapter); - if (err == -EIO) { - return err; - } else if (err == -EAGAIN) { - adapter->state = __IDPF_STARTUP; + err = idpf_send_ver_msg(adapter); + switch (err) { + case 0: + /* success, move state machine forward */ + adapter->state = __IDPF_GET_CAPS; + err = idpf_send_get_caps_msg(adapter); + if (err) + goto init_failed; + fallthrough; + case -EAGAIN: goto restart; - } else if (err) { + default: + /* Something bad happened, try again but only a + * few times. + */ goto init_failed; } - if (idpf_send_get_caps_msg(adapter)) - goto init_failed; - adapter->state = __IDPF_GET_CAPS; - goto restart; case __IDPF_GET_CAPS: if (idpf_recv_get_caps_msg(adapter)) goto init_failed; @@ -3169,7 +3642,9 @@ init_failed: * register writes might not have taken effect. Retry to initialize * the mailbox again */ - adapter->state = __IDPF_STARTUP; + adapter->state = __IDPF_VER_CHECK; + if (adapter->vcxn_mngr) + idpf_vc_xn_shutdown(adapter->vcxn_mngr); idpf_deinit_dflt_mbx(adapter); set_bit(IDPF_HR_DRV_LOAD, adapter->flags); queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task, @@ -3187,6 +3662,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter) { int i; + idpf_vc_xn_shutdown(adapter->vcxn_mngr); idpf_deinit_task(adapter); idpf_intr_rel(adapter); /* Set all bits as we dont know on which vc_state the vhnl_wq is @@ -3740,7 +4216,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, if (async) set_bit(mac_flag, vport_config->flags); - err = idpf_send_mb_msg(adapter, vop, buf_size, (u8 *)ma_list); + err = idpf_send_mb_msg(adapter, vop, buf_size, (u8 *)ma_list, 0); if (err) goto mbx_error; @@ -3795,7 +4271,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter, err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE, sizeof(struct virtchnl2_promisc_info), - (u8 *)&vpi); + (u8 *)&vpi, 0); return err; } diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h index 78aff791f3a9..f008c793e486 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h @@ -24,7 +24,7 @@ int idpf_vport_queue_ids_init(struct idpf_vport *vport); int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, void *msg, int msg_size); int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op, - u16 msg_size, u8 *msg); + u16 msg_size, u8 *msg, u16 cookie); void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q); u32 idpf_get_vport_id(struct idpf_vport *vport); From 8c49e68f542f6a3bf800103ead26df61ceaa18c3 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:33 -0800 Subject: [PATCH 1803/2255] idpf: refactor vport virtchnl messages This reworks the way vport related virtchnl messages work to take advantage of the added transaction API. It is fairly mechanical as, to use the transaction API, the function just needs to fill out an appropriate idpf_vc_xn_params struct to pass to idpf_vc_xn_exec which will take care of the actual send and recv. Tested-by: Alexander Lobakin Reviewed-by: Przemek Kitszel Reviewed-by: Igor Bagnucki Co-developed-by: Joshua Hay Signed-off-by: Joshua Hay Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 185 +++++++----------- 1 file changed, 69 insertions(+), 116 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 95ca10f644b2..2dab7122615f 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -858,7 +858,6 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, while (1) { struct idpf_vport_config *vport_config; - int payload_size = 0; /* Try to get one message */ num_q_msg = 1; @@ -895,47 +894,17 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, if (err) goto post_buffs; - if (ctlq_msg.data_len) - payload_size = ctlq_msg.ctx.indirect.payload->size; - /* All conditions are met. Either a message requested is * received or we received a message to be processed */ switch (ctlq_msg.cookie.mbx.chnl_opcode) { case VIRTCHNL2_OP_VERSION: - err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); - break; case VIRTCHNL2_OP_GET_CAPS: - if (ctlq_msg.cookie.mbx.chnl_retval) { - dev_err(&adapter->pdev->dev, "Failure initializing, vc op: %u retval: %u\n", - ctlq_msg.cookie.mbx.chnl_opcode, - ctlq_msg.cookie.mbx.chnl_retval); - err = -EBADMSG; - } else if (msg) { - memcpy(msg, ctlq_msg.ctx.indirect.payload->va, - min_t(int, payload_size, msg_size)); - } - work_done = true; - break; case VIRTCHNL2_OP_CREATE_VPORT: - idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg, - IDPF_VC_CREATE_VPORT, - IDPF_VC_CREATE_VPORT_ERR); - break; case VIRTCHNL2_OP_ENABLE_VPORT: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_ENA_VPORT, - IDPF_VC_ENA_VPORT_ERR); - break; case VIRTCHNL2_OP_DISABLE_VPORT: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_DIS_VPORT, - IDPF_VC_DIS_VPORT_ERR); - break; case VIRTCHNL2_OP_DESTROY_VPORT: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_DESTROY_VPORT, - IDPF_VC_DESTROY_VPORT_ERR); + err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); break; case VIRTCHNL2_OP_CONFIG_TX_QUEUES: idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, @@ -1322,7 +1291,9 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter) */ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter) { - struct virtchnl2_get_capabilities caps = { }; + struct virtchnl2_get_capabilities caps = {}; + struct idpf_vc_xn_params xn_params = {}; + ssize_t reply_sz; caps.csum_caps = cpu_to_le32(VIRTCHNL2_CAP_TX_CSUM_L3_IPV4 | @@ -1379,21 +1350,20 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter) VIRTCHNL2_CAP_PROMISC | VIRTCHNL2_CAP_LOOPBACK); - return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, sizeof(caps), - (u8 *)&caps, 0); -} + xn_params.vc_op = VIRTCHNL2_OP_GET_CAPS; + xn_params.send_buf.iov_base = ∩︀ + xn_params.send_buf.iov_len = sizeof(caps); + xn_params.recv_buf.iov_base = &adapter->caps; + xn_params.recv_buf.iov_len = sizeof(adapter->caps); + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; -/** - * idpf_recv_get_caps_msg - Receive virtchnl get capabilities message - * @adapter: Driver specific private structure - * - * Receive virtchnl get capabilities message. Returns 0 on success, negative on - * failure. - */ -static int idpf_recv_get_caps_msg(struct idpf_adapter *adapter) -{ - return idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, &adapter->caps, - sizeof(struct virtchnl2_get_capabilities)); + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; + if (reply_sz < sizeof(adapter->caps)) + return -EIO; + + return 0; } /** @@ -1720,8 +1690,10 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter, struct idpf_vport_max_q *max_q) { struct virtchnl2_create_vport *vport_msg; + struct idpf_vc_xn_params xn_params = {}; u16 idx = adapter->next_vport; int err, buf_size; + ssize_t reply_sz; buf_size = sizeof(struct virtchnl2_create_vport); if (!adapter->vport_params_reqd[idx]) { @@ -1752,35 +1724,38 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter, return err; } - mutex_lock(&adapter->vc_buf_lock); - - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CREATE_VPORT, buf_size, - (u8 *)vport_msg, 0); - if (err) - goto rel_lock; - - err = idpf_wait_for_event(adapter, NULL, IDPF_VC_CREATE_VPORT, - IDPF_VC_CREATE_VPORT_ERR); - if (err) { - dev_err(&adapter->pdev->dev, "Failed to receive create vport message"); - - goto rel_lock; - } - if (!adapter->vport_params_recvd[idx]) { adapter->vport_params_recvd[idx] = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL); if (!adapter->vport_params_recvd[idx]) { err = -ENOMEM; - goto rel_lock; + goto free_vport_params; } } - vport_msg = adapter->vport_params_recvd[idx]; - memcpy(vport_msg, adapter->vc_msg, IDPF_CTLQ_MAX_BUF_LEN); + xn_params.vc_op = VIRTCHNL2_OP_CREATE_VPORT; + xn_params.send_buf.iov_base = vport_msg; + xn_params.send_buf.iov_len = buf_size; + xn_params.recv_buf.iov_base = adapter->vport_params_recvd[idx]; + xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); + if (reply_sz < 0) { + err = reply_sz; + goto free_vport_params; + } + if (reply_sz < IDPF_CTLQ_MAX_BUF_LEN) { + err = -EIO; + goto free_vport_params; + } -rel_lock: - mutex_unlock(&adapter->vc_buf_lock); + return 0; + +free_vport_params: + kfree(adapter->vport_params_recvd[idx]); + adapter->vport_params_recvd[idx] = NULL; + kfree(adapter->vport_params_reqd[idx]); + adapter->vport_params_reqd[idx] = NULL; return err; } @@ -1832,26 +1807,19 @@ int idpf_check_supported_desc_ids(struct idpf_vport *vport) */ int idpf_send_destroy_vport_msg(struct idpf_vport *vport) { - struct idpf_adapter *adapter = vport->adapter; + struct idpf_vc_xn_params xn_params = {}; struct virtchnl2_vport v_id; - int err; + ssize_t reply_sz; v_id.vport_id = cpu_to_le32(vport->vport_id); - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_DESTROY_VPORT; + xn_params.send_buf.iov_base = &v_id; + xn_params.send_buf.iov_len = sizeof(v_id); + xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DESTROY_VPORT, - sizeof(v_id), (u8 *)&v_id, 0); - if (err) - goto rel_lock; - - err = idpf_min_wait_for_event(adapter, vport, IDPF_VC_DESTROY_VPORT, - IDPF_VC_DESTROY_VPORT_ERR); - -rel_lock: - mutex_unlock(&vport->vc_buf_lock); - - return err; + return reply_sz < 0 ? reply_sz : 0; } /** @@ -1863,26 +1831,19 @@ rel_lock: */ int idpf_send_enable_vport_msg(struct idpf_vport *vport) { - struct idpf_adapter *adapter = vport->adapter; + struct idpf_vc_xn_params xn_params = {}; struct virtchnl2_vport v_id; - int err; + ssize_t reply_sz; v_id.vport_id = cpu_to_le32(vport->vport_id); - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_ENABLE_VPORT; + xn_params.send_buf.iov_base = &v_id; + xn_params.send_buf.iov_len = sizeof(v_id); + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ENABLE_VPORT, - sizeof(v_id), (u8 *)&v_id, 0); - if (err) - goto rel_lock; - - err = idpf_wait_for_event(adapter, vport, IDPF_VC_ENA_VPORT, - IDPF_VC_ENA_VPORT_ERR); - -rel_lock: - mutex_unlock(&vport->vc_buf_lock); - - return err; + return reply_sz < 0 ? reply_sz : 0; } /** @@ -1894,26 +1855,19 @@ rel_lock: */ int idpf_send_disable_vport_msg(struct idpf_vport *vport) { - struct idpf_adapter *adapter = vport->adapter; + struct idpf_vc_xn_params xn_params = {}; struct virtchnl2_vport v_id; - int err; + ssize_t reply_sz; v_id.vport_id = cpu_to_le32(vport->vport_id); - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_DISABLE_VPORT; + xn_params.send_buf.iov_base = &v_id; + xn_params.send_buf.iov_len = sizeof(v_id); + xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DISABLE_VPORT, - sizeof(v_id), (u8 *)&v_id, 0); - if (err) - goto rel_lock; - - err = idpf_min_wait_for_event(adapter, vport, IDPF_VC_DIS_VPORT, - IDPF_VC_DIS_VPORT_ERR); - -rel_lock: - mutex_unlock(&vport->vc_buf_lock); - - return err; + return reply_sz < 0 ? reply_sz : 0; } /** @@ -3538,9 +3492,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter) case 0: /* success, move state machine forward */ adapter->state = __IDPF_GET_CAPS; - err = idpf_send_get_caps_msg(adapter); - if (err) - goto init_failed; fallthrough; case -EAGAIN: goto restart; @@ -3551,13 +3502,15 @@ int idpf_vc_core_init(struct idpf_adapter *adapter) goto init_failed; } case __IDPF_GET_CAPS: - if (idpf_recv_get_caps_msg(adapter)) + err = idpf_send_get_caps_msg(adapter); + if (err) goto init_failed; adapter->state = __IDPF_INIT_SW; break; default: dev_err(&adapter->pdev->dev, "Device is in bad state: %d\n", adapter->state); + err = -EINVAL; goto init_failed; } break; From 52361a06d3f2995f6cdbe35792ed1514067871d6 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:34 -0800 Subject: [PATCH 1804/2255] idpf: refactor queue related virtchnl messages This reworks queue specific virtchnl messages to use the added transaction API. It is fairly mechanical and generally makes the functions using it more simple. Functions using transaction API no longer need to take the vc_buf_lock since it's not using it anymore. After filling out an idpf_vc_xn_params struct, idpf_vc_xn_exec takes care of the send and recv handling. This also converts those functions where appropriate to use auto-variables instead of manually calling kfree. This greatly simplifies the memory alloc paths and makes them less prone memory leaks. Tested-by: Alexander Lobakin Reviewed-by: Przemek Kitszel Reviewed-by: Igor Bagnucki Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 2 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 393 ++++++------------ 2 files changed, 136 insertions(+), 259 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index c3b08d4593b0..ed5474c1565a 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -553,7 +553,7 @@ struct idpf_vector_lifo { struct idpf_vport_config { struct idpf_vport_user_config_data user_config; struct idpf_vport_max_q max_q; - void *req_qs_chunks; + struct virtchnl2_add_queues *req_qs_chunks; spinlock_t mac_filter_list_lock; DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS); }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 2dab7122615f..1d1b421c33a3 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -904,47 +904,15 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, case VIRTCHNL2_OP_ENABLE_VPORT: case VIRTCHNL2_OP_DISABLE_VPORT: case VIRTCHNL2_OP_DESTROY_VPORT: - err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); - break; case VIRTCHNL2_OP_CONFIG_TX_QUEUES: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_CONFIG_TXQ, - IDPF_VC_CONFIG_TXQ_ERR); - break; case VIRTCHNL2_OP_CONFIG_RX_QUEUES: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_CONFIG_RXQ, - IDPF_VC_CONFIG_RXQ_ERR); - break; case VIRTCHNL2_OP_ENABLE_QUEUES: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_ENA_QUEUES, - IDPF_VC_ENA_QUEUES_ERR); - break; case VIRTCHNL2_OP_DISABLE_QUEUES: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_DIS_QUEUES, - IDPF_VC_DIS_QUEUES_ERR); - break; case VIRTCHNL2_OP_ADD_QUEUES: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_ADD_QUEUES, - IDPF_VC_ADD_QUEUES_ERR); - break; case VIRTCHNL2_OP_DEL_QUEUES: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_DEL_QUEUES, - IDPF_VC_DEL_QUEUES_ERR); - break; case VIRTCHNL2_OP_MAP_QUEUE_VECTOR: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_MAP_IRQ, - IDPF_VC_MAP_IRQ_ERR); - break; case VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_UNMAP_IRQ, - IDPF_VC_UNMAP_IRQ_ERR); + err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); break; case VIRTCHNL2_OP_GET_STATS: idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, @@ -1879,11 +1847,13 @@ int idpf_send_disable_vport_msg(struct idpf_vport *vport) */ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport) { - struct virtchnl2_config_tx_queues *ctq; + struct virtchnl2_config_tx_queues *ctq __free(kfree) = NULL; + struct virtchnl2_txq_info *qi __free(kfree) = NULL; + struct idpf_vc_xn_params xn_params = {}; u32 config_sz, chunk_sz, buf_sz; int totqs, num_msgs, num_chunks; - struct virtchnl2_txq_info *qi; - int err = 0, i, k = 0; + ssize_t reply_sz; + int i, k = 0; totqs = vport->num_txq + vport->num_complq; qi = kcalloc(totqs, sizeof(struct virtchnl2_txq_info), GFP_KERNEL); @@ -1944,10 +1914,8 @@ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport) } /* Make sure accounting agrees */ - if (k != totqs) { - err = -EINVAL; - goto error; - } + if (k != totqs) + return -EINVAL; /* Chunk up the queue contexts into multiple messages to avoid * sending a control queue message buffer that is too large @@ -1961,12 +1929,11 @@ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport) buf_sz = struct_size(ctq, qinfo, num_chunks); ctq = kzalloc(buf_sz, GFP_KERNEL); - if (!ctq) { - err = -ENOMEM; - goto error; - } + if (!ctq) + return -ENOMEM; - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_CONFIG_TX_QUEUES; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; for (i = 0, k = 0; i < num_msgs; i++) { memset(ctq, 0, buf_sz); @@ -1974,17 +1941,11 @@ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport) ctq->num_qinfo = cpu_to_le16(num_chunks); memcpy(ctq->qinfo, &qi[k], chunk_sz * num_chunks); - err = idpf_send_mb_msg(vport->adapter, - VIRTCHNL2_OP_CONFIG_TX_QUEUES, - buf_sz, (u8 *)ctq, 0); - if (err) - goto mbx_error; - - err = idpf_wait_for_event(vport->adapter, vport, - IDPF_VC_CONFIG_TXQ, - IDPF_VC_CONFIG_TXQ_ERR); - if (err) - goto mbx_error; + xn_params.send_buf.iov_base = ctq; + xn_params.send_buf.iov_len = buf_sz; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; k += num_chunks; totqs -= num_chunks; @@ -1993,13 +1954,7 @@ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport) buf_sz = struct_size(ctq, qinfo, num_chunks); } -mbx_error: - mutex_unlock(&vport->vc_buf_lock); - kfree(ctq); -error: - kfree(qi); - - return err; + return 0; } /** @@ -2011,11 +1966,13 @@ error: */ static int idpf_send_config_rx_queues_msg(struct idpf_vport *vport) { - struct virtchnl2_config_rx_queues *crq; + struct virtchnl2_config_rx_queues *crq __free(kfree) = NULL; + struct virtchnl2_rxq_info *qi __free(kfree) = NULL; + struct idpf_vc_xn_params xn_params = {}; u32 config_sz, chunk_sz, buf_sz; int totqs, num_msgs, num_chunks; - struct virtchnl2_rxq_info *qi; - int err = 0, i, k = 0; + ssize_t reply_sz; + int i, k = 0; totqs = vport->num_rxq + vport->num_bufq; qi = kcalloc(totqs, sizeof(struct virtchnl2_rxq_info), GFP_KERNEL); @@ -2096,10 +2053,8 @@ common_qi_fields: } /* Make sure accounting agrees */ - if (k != totqs) { - err = -EINVAL; - goto error; - } + if (k != totqs) + return -EINVAL; /* Chunk up the queue contexts into multiple messages to avoid * sending a control queue message buffer that is too large @@ -2113,12 +2068,11 @@ common_qi_fields: buf_sz = struct_size(crq, qinfo, num_chunks); crq = kzalloc(buf_sz, GFP_KERNEL); - if (!crq) { - err = -ENOMEM; - goto error; - } + if (!crq) + return -ENOMEM; - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_CONFIG_RX_QUEUES; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; for (i = 0, k = 0; i < num_msgs; i++) { memset(crq, 0, buf_sz); @@ -2126,17 +2080,11 @@ common_qi_fields: crq->num_qinfo = cpu_to_le16(num_chunks); memcpy(crq->qinfo, &qi[k], chunk_sz * num_chunks); - err = idpf_send_mb_msg(vport->adapter, - VIRTCHNL2_OP_CONFIG_RX_QUEUES, - buf_sz, (u8 *)crq, 0); - if (err) - goto mbx_error; - - err = idpf_wait_for_event(vport->adapter, vport, - IDPF_VC_CONFIG_RXQ, - IDPF_VC_CONFIG_RXQ_ERR); - if (err) - goto mbx_error; + xn_params.send_buf.iov_base = crq; + xn_params.send_buf.iov_len = buf_sz; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; k += num_chunks; totqs -= num_chunks; @@ -2145,42 +2093,28 @@ common_qi_fields: buf_sz = struct_size(crq, qinfo, num_chunks); } -mbx_error: - mutex_unlock(&vport->vc_buf_lock); - kfree(crq); -error: - kfree(qi); - - return err; + return 0; } /** * idpf_send_ena_dis_queues_msg - Send virtchnl enable or disable * queues message * @vport: virtual port data structure - * @vc_op: virtchnl op code to send + * @ena: if true enable, false disable * * Send enable or disable queues virtchnl message. Returns 0 on success, * negative on failure. */ -static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, u32 vc_op) +static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, bool ena) { + struct virtchnl2_del_ena_dis_queues *eq __free(kfree) = NULL; + struct virtchnl2_queue_chunk *qc __free(kfree) = NULL; u32 num_msgs, num_chunks, num_txq, num_rxq, num_q; - struct idpf_adapter *adapter = vport->adapter; - struct virtchnl2_del_ena_dis_queues *eq; + struct idpf_vc_xn_params xn_params = {}; struct virtchnl2_queue_chunks *qcs; - struct virtchnl2_queue_chunk *qc; u32 config_sz, chunk_sz, buf_sz; - int i, j, k = 0, err = 0; - - /* validate virtchnl op */ - switch (vc_op) { - case VIRTCHNL2_OP_ENABLE_QUEUES: - case VIRTCHNL2_OP_DISABLE_QUEUES: - break; - default: - return -EINVAL; - } + ssize_t reply_sz; + int i, j, k = 0; num_txq = vport->num_txq + vport->num_complq; num_rxq = vport->num_rxq + vport->num_bufq; @@ -2199,10 +2133,8 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, u32 vc_op) qc[k].num_queues = cpu_to_le32(IDPF_NUMQ_PER_CHUNK); } } - if (vport->num_txq != k) { - err = -EINVAL; - goto error; - } + if (vport->num_txq != k) + return -EINVAL; if (!idpf_is_queue_model_split(vport->txq_model)) goto setup_rx; @@ -2214,10 +2146,8 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, u32 vc_op) qc[k].start_queue_id = cpu_to_le32(tx_qgrp->complq->q_id); qc[k].num_queues = cpu_to_le32(IDPF_NUMQ_PER_CHUNK); } - if (vport->num_complq != (k - vport->num_txq)) { - err = -EINVAL; - goto error; - } + if (vport->num_complq != (k - vport->num_txq)) + return -EINVAL; setup_rx: for (i = 0; i < vport->num_rxq_grp; i++) { @@ -2243,10 +2173,8 @@ setup_rx: qc[k].num_queues = cpu_to_le32(IDPF_NUMQ_PER_CHUNK); } } - if (vport->num_rxq != k - (vport->num_txq + vport->num_complq)) { - err = -EINVAL; - goto error; - } + if (vport->num_rxq != k - (vport->num_txq + vport->num_complq)) + return -EINVAL; if (!idpf_is_queue_model_split(vport->rxq_model)) goto send_msg; @@ -2265,10 +2193,8 @@ setup_rx: } if (vport->num_bufq != k - (vport->num_txq + vport->num_complq + - vport->num_rxq)) { - err = -EINVAL; - goto error; - } + vport->num_rxq)) + return -EINVAL; send_msg: /* Chunk up the queue info into multiple messages */ @@ -2281,12 +2207,16 @@ send_msg: buf_sz = struct_size(eq, chunks.chunks, num_chunks); eq = kzalloc(buf_sz, GFP_KERNEL); - if (!eq) { - err = -ENOMEM; - goto error; - } + if (!eq) + return -ENOMEM; - mutex_lock(&vport->vc_buf_lock); + if (ena) { + xn_params.vc_op = VIRTCHNL2_OP_ENABLE_QUEUES; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + } else { + xn_params.vc_op = VIRTCHNL2_OP_DISABLE_QUEUES; + xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC; + } for (i = 0, k = 0; i < num_msgs; i++) { memset(eq, 0, buf_sz); @@ -2295,20 +2225,11 @@ send_msg: qcs = &eq->chunks; memcpy(qcs->chunks, &qc[k], chunk_sz * num_chunks); - err = idpf_send_mb_msg(adapter, vc_op, buf_sz, (u8 *)eq, 0); - if (err) - goto mbx_error; - - if (vc_op == VIRTCHNL2_OP_ENABLE_QUEUES) - err = idpf_wait_for_event(adapter, vport, - IDPF_VC_ENA_QUEUES, - IDPF_VC_ENA_QUEUES_ERR); - else - err = idpf_min_wait_for_event(adapter, vport, - IDPF_VC_DIS_QUEUES, - IDPF_VC_DIS_QUEUES_ERR); - if (err) - goto mbx_error; + xn_params.send_buf.iov_base = eq; + xn_params.send_buf.iov_len = buf_sz; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; k += num_chunks; num_q -= num_chunks; @@ -2317,13 +2238,7 @@ send_msg: buf_sz = struct_size(eq, chunks.chunks, num_chunks); } -mbx_error: - mutex_unlock(&vport->vc_buf_lock); - kfree(eq); -error: - kfree(qc); - - return err; + return 0; } /** @@ -2337,12 +2252,13 @@ error: */ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) { - struct idpf_adapter *adapter = vport->adapter; - struct virtchnl2_queue_vector_maps *vqvm; - struct virtchnl2_queue_vector *vqv; + struct virtchnl2_queue_vector_maps *vqvm __free(kfree) = NULL; + struct virtchnl2_queue_vector *vqv __free(kfree) = NULL; + struct idpf_vc_xn_params xn_params = {}; u32 config_sz, chunk_sz, buf_sz; u32 num_msgs, num_chunks, num_q; - int i, j, k = 0, err = 0; + ssize_t reply_sz; + int i, j, k = 0; num_q = vport->num_txq + vport->num_rxq; @@ -2372,10 +2288,8 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) } } - if (vport->num_txq != k) { - err = -EINVAL; - goto error; - } + if (vport->num_txq != k) + return -EINVAL; for (i = 0; i < vport->num_rxq_grp; i++) { struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i]; @@ -2402,15 +2316,11 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) } if (idpf_is_queue_model_split(vport->txq_model)) { - if (vport->num_rxq != k - vport->num_complq) { - err = -EINVAL; - goto error; - } + if (vport->num_rxq != k - vport->num_complq) + return -EINVAL; } else { - if (vport->num_rxq != k - vport->num_txq) { - err = -EINVAL; - goto error; - } + if (vport->num_rxq != k - vport->num_txq) + return -EINVAL; } /* Chunk up the vector info into multiple messages */ @@ -2423,39 +2333,28 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) buf_sz = struct_size(vqvm, qv_maps, num_chunks); vqvm = kzalloc(buf_sz, GFP_KERNEL); - if (!vqvm) { - err = -ENOMEM; - goto error; - } + if (!vqvm) + return -ENOMEM; - mutex_lock(&vport->vc_buf_lock); + if (map) { + xn_params.vc_op = VIRTCHNL2_OP_MAP_QUEUE_VECTOR; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + } else { + xn_params.vc_op = VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR; + xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC; + } for (i = 0, k = 0; i < num_msgs; i++) { memset(vqvm, 0, buf_sz); + xn_params.send_buf.iov_base = vqvm; + xn_params.send_buf.iov_len = buf_sz; vqvm->vport_id = cpu_to_le32(vport->vport_id); vqvm->num_qv_maps = cpu_to_le16(num_chunks); memcpy(vqvm->qv_maps, &vqv[k], chunk_sz * num_chunks); - if (map) { - err = idpf_send_mb_msg(adapter, - VIRTCHNL2_OP_MAP_QUEUE_VECTOR, - buf_sz, (u8 *)vqvm, 0); - if (!err) - err = idpf_wait_for_event(adapter, vport, - IDPF_VC_MAP_IRQ, - IDPF_VC_MAP_IRQ_ERR); - } else { - err = idpf_send_mb_msg(adapter, - VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR, - buf_sz, (u8 *)vqvm, 0); - if (!err) - err = - idpf_min_wait_for_event(adapter, vport, - IDPF_VC_UNMAP_IRQ, - IDPF_VC_UNMAP_IRQ_ERR); - } - if (err) - goto mbx_error; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; k += num_chunks; num_q -= num_chunks; @@ -2464,13 +2363,7 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) buf_sz = struct_size(vqvm, qv_maps, num_chunks); } -mbx_error: - mutex_unlock(&vport->vc_buf_lock); - kfree(vqvm); -error: - kfree(vqv); - - return err; + return 0; } /** @@ -2482,7 +2375,7 @@ error: */ int idpf_send_enable_queues_msg(struct idpf_vport *vport) { - return idpf_send_ena_dis_queues_msg(vport, VIRTCHNL2_OP_ENABLE_QUEUES); + return idpf_send_ena_dis_queues_msg(vport, true); } /** @@ -2496,7 +2389,7 @@ int idpf_send_disable_queues_msg(struct idpf_vport *vport) { int err, i; - err = idpf_send_ena_dis_queues_msg(vport, VIRTCHNL2_OP_DISABLE_QUEUES); + err = idpf_send_ena_dis_queues_msg(vport, false); if (err) return err; @@ -2542,22 +2435,21 @@ static void idpf_convert_reg_to_queue_chunks(struct virtchnl2_queue_chunk *dchun */ int idpf_send_delete_queues_msg(struct idpf_vport *vport) { - struct idpf_adapter *adapter = vport->adapter; + struct virtchnl2_del_ena_dis_queues *eq __free(kfree) = NULL; struct virtchnl2_create_vport *vport_params; struct virtchnl2_queue_reg_chunks *chunks; - struct virtchnl2_del_ena_dis_queues *eq; + struct idpf_vc_xn_params xn_params = {}; struct idpf_vport_config *vport_config; u16 vport_idx = vport->idx; - int buf_size, err; + ssize_t reply_sz; u16 num_chunks; + int buf_size; - vport_config = adapter->vport_config[vport_idx]; + vport_config = vport->adapter->vport_config[vport_idx]; if (vport_config->req_qs_chunks) { - struct virtchnl2_add_queues *vc_aq = - (struct virtchnl2_add_queues *)vport_config->req_qs_chunks; - chunks = &vc_aq->chunks; + chunks = &vport_config->req_qs_chunks->chunks; } else { - vport_params = adapter->vport_params_recvd[vport_idx]; + vport_params = vport->adapter->vport_params_recvd[vport_idx]; chunks = &vport_params->chunks; } @@ -2574,21 +2466,13 @@ int idpf_send_delete_queues_msg(struct idpf_vport *vport) idpf_convert_reg_to_queue_chunks(eq->chunks.chunks, chunks->chunks, num_chunks); - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_DEL_QUEUES; + xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC; + xn_params.send_buf.iov_base = eq; + xn_params.send_buf.iov_len = buf_size; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEL_QUEUES, - buf_size, (u8 *)eq, 0); - if (err) - goto rel_lock; - - err = idpf_min_wait_for_event(adapter, vport, IDPF_VC_DEL_QUEUES, - IDPF_VC_DEL_QUEUES_ERR); - -rel_lock: - mutex_unlock(&vport->vc_buf_lock); - kfree(eq); - - return err; + return reply_sz < 0 ? reply_sz : 0; } /** @@ -2623,14 +2507,21 @@ int idpf_send_config_queues_msg(struct idpf_vport *vport) int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, u16 num_complq, u16 num_rx_q, u16 num_rx_bufq) { - struct idpf_adapter *adapter = vport->adapter; + struct virtchnl2_add_queues *vc_msg __free(kfree) = NULL; + struct idpf_vc_xn_params xn_params = {}; struct idpf_vport_config *vport_config; - struct virtchnl2_add_queues aq = { }; - struct virtchnl2_add_queues *vc_msg; + struct virtchnl2_add_queues aq = {}; u16 vport_idx = vport->idx; - int size, err; + ssize_t reply_sz; + int size; - vport_config = adapter->vport_config[vport_idx]; + vc_msg = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL); + if (!vc_msg) + return -ENOMEM; + + vport_config = vport->adapter->vport_config[vport_idx]; + kfree(vport_config->req_qs_chunks); + vport_config->req_qs_chunks = NULL; aq.vport_id = cpu_to_le32(vport->vport_id); aq.num_tx_q = cpu_to_le16(num_tx_q); @@ -2638,47 +2529,33 @@ int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, aq.num_rx_q = cpu_to_le16(num_rx_q); aq.num_rx_bufq = cpu_to_le16(num_rx_bufq); - mutex_lock(&((struct idpf_vport *)vport)->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_ADD_QUEUES; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + xn_params.send_buf.iov_base = &aq; + xn_params.send_buf.iov_len = sizeof(aq); + xn_params.recv_buf.iov_base = vc_msg; + xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ADD_QUEUES, - sizeof(struct virtchnl2_add_queues), (u8 *)&aq, 0); - if (err) - goto rel_lock; - - /* We want vport to be const to prevent incidental code changes making - * changes to the vport config. We're making a special exception here - * to discard const to use the virtchnl. - */ - err = idpf_wait_for_event(adapter, (struct idpf_vport *)vport, - IDPF_VC_ADD_QUEUES, IDPF_VC_ADD_QUEUES_ERR); - if (err) - goto rel_lock; - - kfree(vport_config->req_qs_chunks); - vport_config->req_qs_chunks = NULL; - - vc_msg = (struct virtchnl2_add_queues *)vport->vc_msg; /* compare vc_msg num queues with vport num queues */ if (le16_to_cpu(vc_msg->num_tx_q) != num_tx_q || le16_to_cpu(vc_msg->num_rx_q) != num_rx_q || le16_to_cpu(vc_msg->num_tx_complq) != num_complq || - le16_to_cpu(vc_msg->num_rx_bufq) != num_rx_bufq) { - err = -EINVAL; - goto rel_lock; - } + le16_to_cpu(vc_msg->num_rx_bufq) != num_rx_bufq) + return -EINVAL; size = struct_size(vc_msg, chunks.chunks, le16_to_cpu(vc_msg->chunks.num_chunks)); + if (reply_sz < size) + return -EIO; + vport_config->req_qs_chunks = kmemdup(vc_msg, size, GFP_KERNEL); - if (!vport_config->req_qs_chunks) { - err = -ENOMEM; - goto rel_lock; - } + if (!vport_config->req_qs_chunks) + return -ENOMEM; -rel_lock: - mutex_unlock(&((struct idpf_vport *)vport)->vc_buf_lock); - - return err; + return 0; } /** From 43b67308df98ac58055c6a3126427a76d7802e1a Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:35 -0800 Subject: [PATCH 1805/2255] idpf: refactor remaining virtchnl messages This takes care of RSS/SRIOV/MAC and other misc virtchnl messages. This again is mostly mechanical. In absence of an async_handler for MAC filters, this will simply generically report any errors from idpf_vc_xn_forward_async. This maintains the existing behavior. Follow up patch will add an async handler for MAC filters to remove bad filters from our list. While we're here we can also make the code much nicer by converting some variables to auto-variables where appropriate. This makes it cleaner and less prone to memory leaking. There's still a bit more cleanup we can do here to remove stuff that's not being used anymore now; follow-up patches will take care of loose ends. Tested-by: Alexander Lobakin Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 894 ++++++------------ 1 file changed, 298 insertions(+), 596 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 1d1b421c33a3..0f14860efa28 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -100,6 +100,64 @@ struct idpf_vc_xn_manager { u8 salt; }; +/** + * idpf_vid_to_vport - Translate vport id to vport pointer + * @adapter: private data struct + * @v_id: vport id to translate + * + * Returns vport matching v_id, NULL if not found. + */ +static +struct idpf_vport *idpf_vid_to_vport(struct idpf_adapter *adapter, u32 v_id) +{ + u16 num_max_vports = idpf_get_max_vports(adapter); + int i; + + for (i = 0; i < num_max_vports; i++) + if (adapter->vport_ids[i] == v_id) + return adapter->vports[i]; + + return NULL; +} + +/** + * idpf_handle_event_link - Handle link event message + * @adapter: private data struct + * @v2e: virtchnl event message + */ +static void idpf_handle_event_link(struct idpf_adapter *adapter, + const struct virtchnl2_event *v2e) +{ + struct idpf_netdev_priv *np; + struct idpf_vport *vport; + + vport = idpf_vid_to_vport(adapter, le32_to_cpu(v2e->vport_id)); + if (!vport) { + dev_err_ratelimited(&adapter->pdev->dev, "Failed to find vport_id %d for link event\n", + v2e->vport_id); + return; + } + np = netdev_priv(vport->netdev); + + vport->link_speed_mbps = le32_to_cpu(v2e->link_speed); + + if (vport->link_up == v2e->link_status) + return; + + vport->link_up = v2e->link_status; + + if (np->state != __IDPF_VPORT_UP) + return; + + if (vport->link_up) { + netif_tx_start_all_queues(vport->netdev); + netif_carrier_on(vport->netdev); + } else { + netif_tx_stop_all_queues(vport->netdev); + netif_carrier_off(vport->netdev); + } +} + /** * idpf_recv_event_msg - Receive virtchnl event message * @vport: virtual port structure @@ -110,33 +168,24 @@ struct idpf_vc_xn_manager { static void idpf_recv_event_msg(struct idpf_vport *vport, struct idpf_ctlq_msg *ctlq_msg) { - struct idpf_netdev_priv *np = netdev_priv(vport->netdev); + int payload_size = ctlq_msg->ctx.indirect.payload->size; struct virtchnl2_event *v2e; - bool link_status; u32 event; + if (payload_size < sizeof(*v2e)) { + dev_err_ratelimited(&vport->adapter->pdev->dev, "Failed to receive valid payload for event msg (op %d len %d)\n", + ctlq_msg->cookie.mbx.chnl_opcode, + payload_size); + return; + } + v2e = (struct virtchnl2_event *)ctlq_msg->ctx.indirect.payload->va; event = le32_to_cpu(v2e->event); switch (event) { case VIRTCHNL2_EVENT_LINK_CHANGE: - vport->link_speed_mbps = le32_to_cpu(v2e->link_speed); - link_status = v2e->link_status; - - if (vport->link_up == link_status) - break; - - vport->link_up = link_status; - if (np->state == __IDPF_VPORT_UP) { - if (vport->link_up) { - netif_carrier_on(vport->netdev); - netif_tx_start_all_queues(vport->netdev); - } else { - netif_tx_stop_all_queues(vport->netdev); - netif_carrier_off(vport->netdev); - } - } - break; + idpf_handle_event_link(vport->adapter, v2e); + return; default: dev_err(&vport->adapter->pdev->dev, "Unknown event %d from PF\n", event); @@ -380,89 +429,6 @@ free_vc_msg: return err; } -/** - * idpf_copy_data_to_vc_buf - Copy the virtchnl response data into the buffer. - * @adapter: driver specific private structure - * @vport: virtual port structure - * @ctlq_msg: msg to copy from - * @err_enum: err bit to set on error - * - * Copies the payload from ctlq_msg into virtchnl buffer. Returns 0 on success, - * negative on failure. - */ -static int idpf_copy_data_to_vc_buf(struct idpf_adapter *adapter, - struct idpf_vport *vport, - struct idpf_ctlq_msg *ctlq_msg, - enum idpf_vport_vc_state err_enum) -{ - if (ctlq_msg->cookie.mbx.chnl_retval) { - if (vport) - set_bit(err_enum, vport->vc_state); - else - set_bit(err_enum, adapter->vc_state); - - return -EINVAL; - } - - if (vport) - memcpy(vport->vc_msg, ctlq_msg->ctx.indirect.payload->va, - min_t(int, ctlq_msg->ctx.indirect.payload->size, - IDPF_CTLQ_MAX_BUF_LEN)); - else - memcpy(adapter->vc_msg, ctlq_msg->ctx.indirect.payload->va, - min_t(int, ctlq_msg->ctx.indirect.payload->size, - IDPF_CTLQ_MAX_BUF_LEN)); - - return 0; -} - -/** - * idpf_recv_vchnl_op - helper function with common logic when handling the - * reception of VIRTCHNL OPs. - * @adapter: driver specific private structure - * @vport: virtual port structure - * @ctlq_msg: msg to copy from - * @state: state bit used on timeout check - * @err_state: err bit to set on error - */ -static void idpf_recv_vchnl_op(struct idpf_adapter *adapter, - struct idpf_vport *vport, - struct idpf_ctlq_msg *ctlq_msg, - enum idpf_vport_vc_state state, - enum idpf_vport_vc_state err_state) -{ - wait_queue_head_t *vchnl_wq; - int err; - - if (vport) - vchnl_wq = &vport->vchnl_wq; - else - vchnl_wq = &adapter->vchnl_wq; - - err = idpf_copy_data_to_vc_buf(adapter, vport, ctlq_msg, err_state); - if (wq_has_sleeper(vchnl_wq)) { - if (vport) - set_bit(state, vport->vc_state); - else - set_bit(state, adapter->vc_state); - - wake_up(vchnl_wq); - } else { - if (!err) { - dev_warn(&adapter->pdev->dev, "opcode %d received without waiting thread\n", - ctlq_msg->cookie.mbx.chnl_opcode); - } else { - /* Clear the errors since there is no sleeper to pass - * them on - */ - if (vport) - clear_bit(err_state, vport->vc_state); - else - clear_bit(err_state, adapter->vc_state); - } - } -} - /* API for virtchnl "transaction" support ("xn" for short). * * We are reusing the completion lock to serialize the accesses to the @@ -857,8 +823,6 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, int err; while (1) { - struct idpf_vport_config *vport_config; - /* Try to get one message */ num_q_msg = 1; dma_mem = NULL; @@ -912,112 +876,20 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, case VIRTCHNL2_OP_DEL_QUEUES: case VIRTCHNL2_OP_MAP_QUEUE_VECTOR: case VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR: - err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); - break; case VIRTCHNL2_OP_GET_STATS: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_GET_STATS, - IDPF_VC_GET_STATS_ERR); - break; case VIRTCHNL2_OP_GET_RSS_LUT: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_GET_RSS_LUT, - IDPF_VC_GET_RSS_LUT_ERR); - break; case VIRTCHNL2_OP_SET_RSS_LUT: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_SET_RSS_LUT, - IDPF_VC_SET_RSS_LUT_ERR); - break; case VIRTCHNL2_OP_GET_RSS_KEY: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_GET_RSS_KEY, - IDPF_VC_GET_RSS_KEY_ERR); - break; case VIRTCHNL2_OP_SET_RSS_KEY: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_SET_RSS_KEY, - IDPF_VC_SET_RSS_KEY_ERR); - break; case VIRTCHNL2_OP_SET_SRIOV_VFS: - idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg, - IDPF_VC_SET_SRIOV_VFS, - IDPF_VC_SET_SRIOV_VFS_ERR); - break; case VIRTCHNL2_OP_ALLOC_VECTORS: - idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg, - IDPF_VC_ALLOC_VECTORS, - IDPF_VC_ALLOC_VECTORS_ERR); - break; case VIRTCHNL2_OP_DEALLOC_VECTORS: - idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg, - IDPF_VC_DEALLOC_VECTORS, - IDPF_VC_DEALLOC_VECTORS_ERR); - break; case VIRTCHNL2_OP_GET_PTYPE_INFO: - idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg, - IDPF_VC_GET_PTYPE_INFO, - IDPF_VC_GET_PTYPE_INFO_ERR); - break; case VIRTCHNL2_OP_LOOPBACK: - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_LOOPBACK_STATE, - IDPF_VC_LOOPBACK_STATE_ERR); - break; case VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE: - /* This message can only be sent asynchronously. As - * such we'll have lost the context in which it was - * called and thus can only really report if it looks - * like an error occurred. Don't bother setting ERR bit - * or waking chnl_wq since no work queue will be waiting - * to read the message. - */ - if (ctlq_msg.cookie.mbx.chnl_retval) { - dev_err(&adapter->pdev->dev, "Failed to set promiscuous mode: %d\n", - ctlq_msg.cookie.mbx.chnl_retval); - } - break; case VIRTCHNL2_OP_ADD_MAC_ADDR: - vport_config = adapter->vport_config[vport->idx]; - if (test_and_clear_bit(IDPF_VPORT_ADD_MAC_REQ, - vport_config->flags)) { - /* Message was sent asynchronously. We don't - * normally print errors here, instead - * prefer to handle errors in the function - * calling wait_for_event. However, if - * asynchronous, the context in which the - * message was sent is lost. We can't really do - * anything about at it this point, but we - * should at a minimum indicate that it looks - * like something went wrong. Also don't bother - * setting ERR bit or waking vchnl_wq since no - * one will be waiting to read the async - * message. - */ - if (ctlq_msg.cookie.mbx.chnl_retval) - dev_err(&adapter->pdev->dev, "Failed to add MAC address: %d\n", - ctlq_msg.cookie.mbx.chnl_retval); - break; - } - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_ADD_MAC_ADDR, - IDPF_VC_ADD_MAC_ADDR_ERR); - break; case VIRTCHNL2_OP_DEL_MAC_ADDR: - vport_config = adapter->vport_config[vport->idx]; - if (test_and_clear_bit(IDPF_VPORT_DEL_MAC_REQ, - vport_config->flags)) { - /* Message was sent asynchronously like the - * VIRTCHNL2_OP_ADD_MAC_ADDR - */ - if (ctlq_msg.cookie.mbx.chnl_retval) - dev_err(&adapter->pdev->dev, "Failed to delete MAC address: %d\n", - ctlq_msg.cookie.mbx.chnl_retval); - break; - } - idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, - IDPF_VC_DEL_MAC_ADDR, - IDPF_VC_DEL_MAC_ADDR_ERR); + err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); break; case VIRTCHNL2_OP_EVENT: idpf_recv_event_msg(vport, &ctlq_msg); @@ -1050,116 +922,6 @@ post_buffs: return err; } -/** - * __idpf_wait_for_event - wrapper function for wait on virtchannel response - * @adapter: Driver private data structure - * @vport: virtual port structure - * @state: check on state upon timeout - * @err_check: check if this specific error bit is set - * @timeout: Max time to wait - * - * Checks if state is set upon expiry of timeout. Returns 0 on success, - * negative on failure. - */ -static int __idpf_wait_for_event(struct idpf_adapter *adapter, - struct idpf_vport *vport, - enum idpf_vport_vc_state state, - enum idpf_vport_vc_state err_check, - int timeout) -{ - int time_to_wait, num_waits; - wait_queue_head_t *vchnl_wq; - unsigned long *vc_state; - - time_to_wait = ((timeout <= IDPF_MAX_WAIT) ? timeout : IDPF_MAX_WAIT); - num_waits = ((timeout <= IDPF_MAX_WAIT) ? 1 : timeout / IDPF_MAX_WAIT); - - if (vport) { - vchnl_wq = &vport->vchnl_wq; - vc_state = vport->vc_state; - } else { - vchnl_wq = &adapter->vchnl_wq; - vc_state = adapter->vc_state; - } - - while (num_waits) { - int event; - - /* If we are here and a reset is detected do not wait but - * return. Reset timing is out of drivers control. So - * while we are cleaning resources as part of reset if the - * underlying HW mailbox is gone, wait on mailbox messages - * is not meaningful - */ - if (idpf_is_reset_detected(adapter)) - return 0; - - event = wait_event_timeout(*vchnl_wq, - test_and_clear_bit(state, vc_state), - msecs_to_jiffies(time_to_wait)); - if (event) { - if (test_and_clear_bit(err_check, vc_state)) { - dev_err(&adapter->pdev->dev, "VC response error %s\n", - idpf_vport_vc_state_str[err_check]); - - return -EINVAL; - } - - return 0; - } - num_waits--; - } - - /* Timeout occurred */ - dev_err(&adapter->pdev->dev, "VC timeout, state = %s\n", - idpf_vport_vc_state_str[state]); - - return -ETIMEDOUT; -} - -/** - * idpf_min_wait_for_event - wait for virtchannel response - * @adapter: Driver private data structure - * @vport: virtual port structure - * @state: check on state upon timeout - * @err_check: check if this specific error bit is set - * - * Returns 0 on success, negative on failure. - */ -static int idpf_min_wait_for_event(struct idpf_adapter *adapter, - struct idpf_vport *vport, - enum idpf_vport_vc_state state, - enum idpf_vport_vc_state err_check) -{ - return __idpf_wait_for_event(adapter, vport, state, err_check, - IDPF_WAIT_FOR_EVENT_TIMEO_MIN); -} - -/** - * idpf_wait_for_event - wait for virtchannel response - * @adapter: Driver private data structure - * @vport: virtual port structure - * @state: check on state upon timeout after 500ms - * @err_check: check if this specific error bit is set - * - * Returns 0 on success, negative on failure. - */ -static int idpf_wait_for_event(struct idpf_adapter *adapter, - struct idpf_vport *vport, - enum idpf_vport_vc_state state, - enum idpf_vport_vc_state err_check) -{ - /* Increasing the timeout in __IDPF_INIT_SW flow to consider large - * number of VF's mailbox message responses. When a message is received - * on mailbox, this thread is woken up by the idpf_recv_mb_msg before - * the timeout expires. Only in the error case i.e. if no message is - * received on mailbox, we wait for the complete timeout which is - * less likely to happen. - */ - return __idpf_wait_for_event(adapter, vport, state, err_check, - IDPF_WAIT_FOR_EVENT_TIMEO); -} - /** * idpf_wait_for_marker_event - wait for software marker response * @vport: virtual port data structure @@ -2567,53 +2329,49 @@ int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, */ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors) { - struct virtchnl2_alloc_vectors *alloc_vec, *rcvd_vec; - struct virtchnl2_alloc_vectors ac = { }; + struct virtchnl2_alloc_vectors *rcvd_vec __free(kfree) = NULL; + struct idpf_vc_xn_params xn_params = {}; + struct virtchnl2_alloc_vectors ac = {}; + ssize_t reply_sz; u16 num_vchunks; - int size, err; + int size; ac.num_vectors = cpu_to_le16(num_vectors); - mutex_lock(&adapter->vc_buf_lock); + rcvd_vec = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL); + if (!rcvd_vec) + return -ENOMEM; - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ALLOC_VECTORS, - sizeof(ac), (u8 *)&ac, 0); - if (err) - goto rel_lock; + xn_params.vc_op = VIRTCHNL2_OP_ALLOC_VECTORS; + xn_params.send_buf.iov_base = ∾ + xn_params.send_buf.iov_len = sizeof(ac); + xn_params.recv_buf.iov_base = rcvd_vec; + xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; - err = idpf_wait_for_event(adapter, NULL, IDPF_VC_ALLOC_VECTORS, - IDPF_VC_ALLOC_VECTORS_ERR); - if (err) - goto rel_lock; - - rcvd_vec = (struct virtchnl2_alloc_vectors *)adapter->vc_msg; num_vchunks = le16_to_cpu(rcvd_vec->vchunks.num_vchunks); - size = struct_size(rcvd_vec, vchunks.vchunks, num_vchunks); - if (size > sizeof(adapter->vc_msg)) { - err = -EINVAL; - goto rel_lock; - } + if (reply_sz < size) + return -EIO; + + if (size > IDPF_CTLQ_MAX_BUF_LEN) + return -EINVAL; kfree(adapter->req_vec_chunks); - adapter->req_vec_chunks = NULL; - adapter->req_vec_chunks = kmemdup(adapter->vc_msg, size, GFP_KERNEL); - if (!adapter->req_vec_chunks) { - err = -ENOMEM; - goto rel_lock; - } + adapter->req_vec_chunks = kmemdup(rcvd_vec, size, GFP_KERNEL); + if (!adapter->req_vec_chunks) + return -ENOMEM; - alloc_vec = adapter->req_vec_chunks; - if (le16_to_cpu(alloc_vec->num_vectors) < num_vectors) { + if (le16_to_cpu(adapter->req_vec_chunks->num_vectors) < num_vectors) { kfree(adapter->req_vec_chunks); adapter->req_vec_chunks = NULL; - err = -EINVAL; + return -EINVAL; } -rel_lock: - mutex_unlock(&adapter->vc_buf_lock); - - return err; + return 0; } /** @@ -2626,29 +2384,24 @@ int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter) { struct virtchnl2_alloc_vectors *ac = adapter->req_vec_chunks; struct virtchnl2_vector_chunks *vcs = &ac->vchunks; - int buf_size, err; + struct idpf_vc_xn_params xn_params = {}; + ssize_t reply_sz; + int buf_size; buf_size = struct_size(vcs, vchunks, le16_to_cpu(vcs->num_vchunks)); - mutex_lock(&adapter->vc_buf_lock); - - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEALLOC_VECTORS, buf_size, - (u8 *)vcs, 0); - if (err) - goto rel_lock; - - err = idpf_min_wait_for_event(adapter, NULL, IDPF_VC_DEALLOC_VECTORS, - IDPF_VC_DEALLOC_VECTORS_ERR); - if (err) - goto rel_lock; + xn_params.vc_op = VIRTCHNL2_OP_DEALLOC_VECTORS; + xn_params.send_buf.iov_base = vcs; + xn_params.send_buf.iov_len = buf_size; + xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC; + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; kfree(adapter->req_vec_chunks); adapter->req_vec_chunks = NULL; -rel_lock: - mutex_unlock(&adapter->vc_buf_lock); - - return err; + return 0; } /** @@ -2671,25 +2424,18 @@ static int idpf_get_max_vfs(struct idpf_adapter *adapter) */ int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs) { - struct virtchnl2_sriov_vfs_info svi = { }; - int err; + struct virtchnl2_sriov_vfs_info svi = {}; + struct idpf_vc_xn_params xn_params = {}; + ssize_t reply_sz; svi.num_vfs = cpu_to_le16(num_vfs); + xn_params.vc_op = VIRTCHNL2_OP_SET_SRIOV_VFS; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + xn_params.send_buf.iov_base = &svi; + xn_params.send_buf.iov_len = sizeof(svi); + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); - mutex_lock(&adapter->vc_buf_lock); - - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_SRIOV_VFS, - sizeof(svi), (u8 *)&svi, 0); - if (err) - goto rel_lock; - - err = idpf_wait_for_event(adapter, NULL, IDPF_VC_SET_SRIOV_VFS, - IDPF_VC_SET_SRIOV_VFS_ERR); - -rel_lock: - mutex_unlock(&adapter->vc_buf_lock); - - return err; + return reply_sz < 0 ? reply_sz : 0; } /** @@ -2702,10 +2448,10 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport) { struct idpf_netdev_priv *np = netdev_priv(vport->netdev); struct rtnl_link_stats64 *netstats = &np->netstats; - struct idpf_adapter *adapter = vport->adapter; - struct virtchnl2_vport_stats stats_msg = { }; - struct virtchnl2_vport_stats *stats; - int err; + struct virtchnl2_vport_stats stats_msg = {}; + struct idpf_vc_xn_params xn_params = {}; + ssize_t reply_sz; + /* Don't send get_stats message if the link is down */ if (np->state <= __IDPF_VPORT_DOWN) @@ -2713,46 +2459,38 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport) stats_msg.vport_id = cpu_to_le32(vport->vport_id); - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_GET_STATS; + xn_params.send_buf.iov_base = &stats_msg; + xn_params.send_buf.iov_len = sizeof(stats_msg); + xn_params.recv_buf = xn_params.send_buf; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_STATS, - sizeof(struct virtchnl2_vport_stats), - (u8 *)&stats_msg, 0); - if (err) - goto rel_lock; - - err = idpf_wait_for_event(adapter, vport, IDPF_VC_GET_STATS, - IDPF_VC_GET_STATS_ERR); - if (err) - goto rel_lock; - - stats = (struct virtchnl2_vport_stats *)vport->vc_msg; + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; + if (reply_sz < sizeof(stats_msg)) + return -EIO; spin_lock_bh(&np->stats_lock); - netstats->rx_packets = le64_to_cpu(stats->rx_unicast) + - le64_to_cpu(stats->rx_multicast) + - le64_to_cpu(stats->rx_broadcast); - netstats->rx_bytes = le64_to_cpu(stats->rx_bytes); - netstats->rx_dropped = le64_to_cpu(stats->rx_discards); - netstats->rx_over_errors = le64_to_cpu(stats->rx_overflow_drop); - netstats->rx_length_errors = le64_to_cpu(stats->rx_invalid_frame_length); + netstats->rx_packets = le64_to_cpu(stats_msg.rx_unicast) + + le64_to_cpu(stats_msg.rx_multicast) + + le64_to_cpu(stats_msg.rx_broadcast); + netstats->tx_packets = le64_to_cpu(stats_msg.tx_unicast) + + le64_to_cpu(stats_msg.tx_multicast) + + le64_to_cpu(stats_msg.tx_broadcast); + netstats->rx_bytes = le64_to_cpu(stats_msg.rx_bytes); + netstats->tx_bytes = le64_to_cpu(stats_msg.tx_bytes); + netstats->rx_errors = le64_to_cpu(stats_msg.rx_errors); + netstats->tx_errors = le64_to_cpu(stats_msg.tx_errors); + netstats->rx_dropped = le64_to_cpu(stats_msg.rx_discards); + netstats->tx_dropped = le64_to_cpu(stats_msg.tx_discards); - netstats->tx_packets = le64_to_cpu(stats->tx_unicast) + - le64_to_cpu(stats->tx_multicast) + - le64_to_cpu(stats->tx_broadcast); - netstats->tx_bytes = le64_to_cpu(stats->tx_bytes); - netstats->tx_errors = le64_to_cpu(stats->tx_errors); - netstats->tx_dropped = le64_to_cpu(stats->tx_discards); - - vport->port_stats.vport_stats = *stats; + vport->port_stats.vport_stats = stats_msg; spin_unlock_bh(&np->stats_lock); -rel_lock: - mutex_unlock(&vport->vc_buf_lock); - - return err; + return 0; } /** @@ -2764,70 +2502,70 @@ rel_lock: */ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) { - struct idpf_adapter *adapter = vport->adapter; - struct virtchnl2_rss_lut *recv_rl; + struct virtchnl2_rss_lut *recv_rl __free(kfree) = NULL; + struct virtchnl2_rss_lut *rl __free(kfree) = NULL; + struct idpf_vc_xn_params xn_params = {}; struct idpf_rss_data *rss_data; - struct virtchnl2_rss_lut *rl; int buf_size, lut_buf_size; - int i, err; + ssize_t reply_sz; + int i; - rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; + rss_data = + &vport->adapter->vport_config[vport->idx]->user_config.rss_data; buf_size = struct_size(rl, lut, rss_data->rss_lut_size); rl = kzalloc(buf_size, GFP_KERNEL); if (!rl) return -ENOMEM; rl->vport_id = cpu_to_le32(vport->vport_id); - mutex_lock(&vport->vc_buf_lock); - if (!get) { + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + xn_params.send_buf.iov_base = rl; + xn_params.send_buf.iov_len = buf_size; + + if (get) { + recv_rl = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL); + if (!recv_rl) + return -ENOMEM; + xn_params.vc_op = VIRTCHNL2_OP_GET_RSS_LUT; + xn_params.recv_buf.iov_base = recv_rl; + xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN; + } else { rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size); for (i = 0; i < rss_data->rss_lut_size; i++) rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]); - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_LUT, - buf_size, (u8 *)rl, 0); - if (err) - goto free_mem; - - err = idpf_wait_for_event(adapter, vport, IDPF_VC_SET_RSS_LUT, - IDPF_VC_SET_RSS_LUT_ERR); - - goto free_mem; + xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT; } + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; + if (!get) + return 0; + if (reply_sz < sizeof(struct virtchnl2_rss_lut)) + return -EIO; - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_LUT, - buf_size, (u8 *)rl, 0); - if (err) - goto free_mem; + lut_buf_size = le16_to_cpu(recv_rl->lut_entries) * sizeof(u32); + if (reply_sz < lut_buf_size) + return -EIO; - err = idpf_wait_for_event(adapter, vport, IDPF_VC_GET_RSS_LUT, - IDPF_VC_GET_RSS_LUT_ERR); - if (err) - goto free_mem; - - recv_rl = (struct virtchnl2_rss_lut *)vport->vc_msg; + /* size didn't change, we can reuse existing lut buf */ if (rss_data->rss_lut_size == le16_to_cpu(recv_rl->lut_entries)) goto do_memcpy; rss_data->rss_lut_size = le16_to_cpu(recv_rl->lut_entries); kfree(rss_data->rss_lut); - lut_buf_size = rss_data->rss_lut_size * sizeof(u32); rss_data->rss_lut = kzalloc(lut_buf_size, GFP_KERNEL); if (!rss_data->rss_lut) { rss_data->rss_lut_size = 0; - err = -ENOMEM; - goto free_mem; + return -ENOMEM; } do_memcpy: - memcpy(rss_data->rss_lut, vport->vc_msg, rss_data->rss_lut_size); -free_mem: - mutex_unlock(&vport->vc_buf_lock); - kfree(rl); + memcpy(rss_data->rss_lut, recv_rl->lut, rss_data->rss_lut_size); - return err; + return 0; } /** @@ -2839,68 +2577,70 @@ free_mem: */ int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get) { - struct idpf_adapter *adapter = vport->adapter; - struct virtchnl2_rss_key *recv_rk; + struct virtchnl2_rss_key *recv_rk __free(kfree) = NULL; + struct virtchnl2_rss_key *rk __free(kfree) = NULL; + struct idpf_vc_xn_params xn_params = {}; struct idpf_rss_data *rss_data; - struct virtchnl2_rss_key *rk; - int i, buf_size, err; + ssize_t reply_sz; + int i, buf_size; + u16 key_size; - rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; + rss_data = + &vport->adapter->vport_config[vport->idx]->user_config.rss_data; buf_size = struct_size(rk, key_flex, rss_data->rss_key_size); rk = kzalloc(buf_size, GFP_KERNEL); if (!rk) return -ENOMEM; rk->vport_id = cpu_to_le32(vport->vport_id); - mutex_lock(&vport->vc_buf_lock); - + xn_params.send_buf.iov_base = rk; + xn_params.send_buf.iov_len = buf_size; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; if (get) { - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_KEY, - buf_size, (u8 *)rk, 0); - if (err) - goto error; + recv_rk = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL); + if (!recv_rk) + return -ENOMEM; - err = idpf_wait_for_event(adapter, vport, IDPF_VC_GET_RSS_KEY, - IDPF_VC_GET_RSS_KEY_ERR); - if (err) - goto error; - - recv_rk = (struct virtchnl2_rss_key *)vport->vc_msg; - if (rss_data->rss_key_size != - le16_to_cpu(recv_rk->key_len)) { - rss_data->rss_key_size = - min_t(u16, NETDEV_RSS_KEY_LEN, - le16_to_cpu(recv_rk->key_len)); - kfree(rss_data->rss_key); - rss_data->rss_key = kzalloc(rss_data->rss_key_size, - GFP_KERNEL); - if (!rss_data->rss_key) { - rss_data->rss_key_size = 0; - err = -ENOMEM; - goto error; - } - } - memcpy(rss_data->rss_key, recv_rk->key_flex, - rss_data->rss_key_size); + xn_params.vc_op = VIRTCHNL2_OP_GET_RSS_KEY; + xn_params.recv_buf.iov_base = recv_rk; + xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN; } else { rk->key_len = cpu_to_le16(rss_data->rss_key_size); for (i = 0; i < rss_data->rss_key_size; i++) rk->key_flex[i] = rss_data->rss_key[i]; - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_KEY, - buf_size, (u8 *)rk, 0); - if (err) - goto error; - - err = idpf_wait_for_event(adapter, vport, IDPF_VC_SET_RSS_KEY, - IDPF_VC_SET_RSS_KEY_ERR); + xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_KEY; } -error: - mutex_unlock(&vport->vc_buf_lock); - kfree(rk); + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; + if (!get) + return 0; + if (reply_sz < sizeof(struct virtchnl2_rss_key)) + return -EIO; - return err; + key_size = min_t(u16, NETDEV_RSS_KEY_LEN, + le16_to_cpu(recv_rk->key_len)); + if (reply_sz < key_size) + return -EIO; + + /* key len didn't change, reuse existing buf */ + if (rss_data->rss_key_size == key_size) + goto do_memcpy; + + rss_data->rss_key_size = key_size; + kfree(rss_data->rss_key); + rss_data->rss_key = kzalloc(key_size, GFP_KERNEL); + if (!rss_data->rss_key) { + rss_data->rss_key_size = 0; + return -ENOMEM; + } + +do_memcpy: + memcpy(rss_data->rss_key, recv_rk->key_flex, rss_data->rss_key_size); + + return 0; } /** @@ -2952,13 +2692,15 @@ static void idpf_fill_ptype_lookup(struct idpf_rx_ptype_decoded *ptype, */ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport) { + struct virtchnl2_get_ptype_info *get_ptype_info __free(kfree) = NULL; + struct virtchnl2_get_ptype_info *ptype_info __free(kfree) = NULL; struct idpf_rx_ptype_decoded *ptype_lkup = vport->rx_ptype_lkup; - struct virtchnl2_get_ptype_info get_ptype_info; int max_ptype, ptypes_recvd = 0, ptype_offset; struct idpf_adapter *adapter = vport->adapter; - struct virtchnl2_get_ptype_info *ptype_info; + struct idpf_vc_xn_params xn_params = {}; u16 next_ptype_id = 0; - int err = 0, i, j, k; + ssize_t reply_sz; + int i, j, k; if (idpf_is_queue_model_split(vport->rxq_model)) max_ptype = IDPF_RX_MAX_PTYPE; @@ -2967,43 +2709,44 @@ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport) memset(vport->rx_ptype_lkup, 0, sizeof(vport->rx_ptype_lkup)); + get_ptype_info = kzalloc(sizeof(*get_ptype_info), GFP_KERNEL); + if (!get_ptype_info) + return -ENOMEM; + ptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL); if (!ptype_info) return -ENOMEM; - mutex_lock(&adapter->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_GET_PTYPE_INFO; + xn_params.send_buf.iov_base = get_ptype_info; + xn_params.send_buf.iov_len = sizeof(*get_ptype_info); + xn_params.recv_buf.iov_base = ptype_info; + xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; while (next_ptype_id < max_ptype) { - get_ptype_info.start_ptype_id = cpu_to_le16(next_ptype_id); + get_ptype_info->start_ptype_id = cpu_to_le16(next_ptype_id); if ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) > max_ptype) - get_ptype_info.num_ptypes = + get_ptype_info->num_ptypes = cpu_to_le16(max_ptype - next_ptype_id); else - get_ptype_info.num_ptypes = + get_ptype_info->num_ptypes = cpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF); - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_PTYPE_INFO, - sizeof(struct virtchnl2_get_ptype_info), - (u8 *)&get_ptype_info, 0); - if (err) - goto vc_buf_unlock; + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; - err = idpf_wait_for_event(adapter, NULL, IDPF_VC_GET_PTYPE_INFO, - IDPF_VC_GET_PTYPE_INFO_ERR); - if (err) - goto vc_buf_unlock; - - memcpy(ptype_info, adapter->vc_msg, IDPF_CTLQ_MAX_BUF_LEN); + if (reply_sz < IDPF_CTLQ_MAX_BUF_LEN) + return -EIO; ptypes_recvd += le16_to_cpu(ptype_info->num_ptypes); - if (ptypes_recvd > max_ptype) { - err = -EINVAL; - goto vc_buf_unlock; - } + if (ptypes_recvd > max_ptype) + return -EINVAL; - next_ptype_id = le16_to_cpu(get_ptype_info.start_ptype_id) + - le16_to_cpu(get_ptype_info.num_ptypes); + next_ptype_id = le16_to_cpu(get_ptype_info->start_ptype_id) + + le16_to_cpu(get_ptype_info->num_ptypes); ptype_offset = IDPF_RX_PTYPE_HDR_SZ; @@ -3016,17 +2759,13 @@ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport) ((u8 *)ptype_info + ptype_offset); ptype_offset += IDPF_GET_PTYPE_SIZE(ptype); - if (ptype_offset > IDPF_CTLQ_MAX_BUF_LEN) { - err = -EINVAL; - goto vc_buf_unlock; - } + if (ptype_offset > IDPF_CTLQ_MAX_BUF_LEN) + return -EINVAL; /* 0xFFFF indicates end of ptypes */ if (le16_to_cpu(ptype->ptype_id_10) == - IDPF_INVALID_PTYPE_ID) { - err = 0; - goto vc_buf_unlock; - } + IDPF_INVALID_PTYPE_ID) + return 0; if (idpf_is_queue_model_split(vport->rxq_model)) k = le16_to_cpu(ptype->ptype_id_10); @@ -3154,11 +2893,7 @@ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport) } } -vc_buf_unlock: - mutex_unlock(&adapter->vc_buf_lock); - kfree(ptype_info); - - return err; + return 0; } /** @@ -3170,27 +2905,20 @@ vc_buf_unlock: */ int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport) { + struct idpf_vc_xn_params xn_params = {}; struct virtchnl2_loopback loopback; - int err; + ssize_t reply_sz; loopback.vport_id = cpu_to_le32(vport->vport_id); loopback.enable = idpf_is_feature_ena(vport, NETIF_F_LOOPBACK); - mutex_lock(&vport->vc_buf_lock); + xn_params.vc_op = VIRTCHNL2_OP_LOOPBACK; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + xn_params.send_buf.iov_base = &loopback; + xn_params.send_buf.iov_len = sizeof(loopback); + reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params); - err = idpf_send_mb_msg(vport->adapter, VIRTCHNL2_OP_LOOPBACK, - sizeof(loopback), (u8 *)&loopback, 0); - if (err) - goto rel_lock; - - err = idpf_wait_for_event(vport->adapter, vport, - IDPF_VC_LOOPBACK_STATE, - IDPF_VC_LOOPBACK_STATE_ERR); - -rel_lock: - mutex_unlock(&vport->vc_buf_lock); - - return err; + return reply_sz < 0 ? reply_sz : 0; } /** @@ -3941,17 +3669,20 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, struct idpf_netdev_priv *np, bool add, bool async) { - struct virtchnl2_mac_addr_list *ma_list = NULL; + struct virtchnl2_mac_addr_list *ma_list __free(kfree) = NULL; + struct virtchnl2_mac_addr *mac_addr __free(kfree) = NULL; struct idpf_adapter *adapter = np->adapter; + struct idpf_vc_xn_params xn_params = {}; struct idpf_vport_config *vport_config; - enum idpf_vport_config_flags mac_flag; - struct pci_dev *pdev = adapter->pdev; - enum idpf_vport_vc_state vc, vc_err; - struct virtchnl2_mac_addr *mac_addr; - struct idpf_mac_filter *f, *tmp; u32 num_msgs, total_filters = 0; - int i = 0, k, err = 0; - u32 vop; + struct idpf_mac_filter *f; + ssize_t reply_sz; + int i = 0, k; + + xn_params.vc_op = add ? VIRTCHNL2_OP_ADD_MAC_ADDR : + VIRTCHNL2_OP_DEL_MAC_ADDR; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + xn_params.async = async; vport_config = adapter->vport_config[np->vport_idx]; spin_lock_bh(&vport_config->mac_filter_list_lock); @@ -3975,13 +3706,13 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, mac_addr = kcalloc(total_filters, sizeof(struct virtchnl2_mac_addr), GFP_ATOMIC); if (!mac_addr) { - err = -ENOMEM; spin_unlock_bh(&vport_config->mac_filter_list_lock); - goto error; + + return -ENOMEM; } - list_for_each_entry_safe(f, tmp, &vport_config->user_config.mac_filter_list, - list) { + list_for_each_entry(f, &vport_config->user_config.mac_filter_list, + list) { if (add && f->add) { ether_addr_copy(mac_addr[i].addr, f->macaddr); i++; @@ -4000,26 +3731,11 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, spin_unlock_bh(&vport_config->mac_filter_list_lock); - if (add) { - vop = VIRTCHNL2_OP_ADD_MAC_ADDR; - vc = IDPF_VC_ADD_MAC_ADDR; - vc_err = IDPF_VC_ADD_MAC_ADDR_ERR; - mac_flag = IDPF_VPORT_ADD_MAC_REQ; - } else { - vop = VIRTCHNL2_OP_DEL_MAC_ADDR; - vc = IDPF_VC_DEL_MAC_ADDR; - vc_err = IDPF_VC_DEL_MAC_ADDR_ERR; - mac_flag = IDPF_VPORT_DEL_MAC_REQ; - } - /* Chunk up the filters into multiple messages to avoid * sending a control queue message buffer that is too large */ num_msgs = DIV_ROUND_UP(total_filters, IDPF_NUM_FILTERS_PER_MSG); - if (!async) - mutex_lock(&vport->vc_buf_lock); - for (i = 0, k = 0; i < num_msgs; i++) { u32 entries_size, buf_size, num_entries; @@ -4031,10 +3747,8 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, if (!ma_list || num_entries != IDPF_NUM_FILTERS_PER_MSG) { kfree(ma_list); ma_list = kzalloc(buf_size, GFP_ATOMIC); - if (!ma_list) { - err = -ENOMEM; - goto list_prep_error; - } + if (!ma_list) + return -ENOMEM; } else { memset(ma_list, 0, buf_size); } @@ -4043,34 +3757,17 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, ma_list->num_mac_addr = cpu_to_le16(num_entries); memcpy(ma_list->mac_addr_list, &mac_addr[k], entries_size); - if (async) - set_bit(mac_flag, vport_config->flags); - - err = idpf_send_mb_msg(adapter, vop, buf_size, (u8 *)ma_list, 0); - if (err) - goto mbx_error; - - if (!async) { - err = idpf_wait_for_event(adapter, vport, vc, vc_err); - if (err) - goto mbx_error; - } + xn_params.send_buf.iov_base = ma_list; + xn_params.send_buf.iov_len = buf_size; + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); + if (reply_sz < 0) + return reply_sz; k += num_entries; total_filters -= num_entries; } -mbx_error: - if (!async) - mutex_unlock(&vport->vc_buf_lock); - kfree(ma_list); -list_prep_error: - kfree(mac_addr); -error: - if (err) - dev_err(&pdev->dev, "Failed to add or del mac filters %d", err); - - return err; + return 0; } /** @@ -4087,9 +3784,10 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter, struct idpf_vport_user_config_data *config_data, u32 vport_id) { + struct idpf_vc_xn_params xn_params = {}; struct virtchnl2_promisc_info vpi; + ssize_t reply_sz; u16 flags = 0; - int err; if (test_bit(__IDPF_PROMISC_UC, config_data->user_flags)) flags |= VIRTCHNL2_UNICAST_PROMISC; @@ -4099,9 +3797,13 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter, vpi.vport_id = cpu_to_le32(vport_id); vpi.flags = cpu_to_le16(flags); - err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE, - sizeof(struct virtchnl2_promisc_info), - (u8 *)&vpi, 0); + xn_params.vc_op = VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE; + xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; + xn_params.send_buf.iov_base = &vpi; + xn_params.send_buf.iov_len = sizeof(vpi); + /* setting promiscuous is only ever done asynchronously */ + xn_params.async = true; + reply_sz = idpf_vc_xn_exec(adapter, &xn_params); - return err; + return reply_sz < 0 ? reply_sz : 0; } From 41252855df77a9bef119489b66671e317efb5a7e Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:36 -0800 Subject: [PATCH 1806/2255] idpf: add async_handler for MAC filter messages There are situations where the driver needs to add a MAC filter but we're explicitly not allowed to sleep so we can wait for a virtchnl message to complete. This adds an async_handler for asynchronously sent messages for MAC filters so that we can better handle if there's an error of some kind. If success we don't need to do anything else, but if we failed to program the new filter we really should remove it from our list of MAC filters. If we don't remove bad filters, what I expect to happen is after a reset of some kind we try to program the MAC filter again and it fails again. This is clearly wrong and I would expect to be confusing for the user. It could also be the failure is for a delete MAC filter message but those filters get deleted regardless. Not much we can do about a delete failure. Tested-by: Alexander Lobakin Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 0f14860efa28..d1107507a98c 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -3656,6 +3656,75 @@ u32 idpf_get_vport_id(struct idpf_vport *vport) return le32_to_cpu(vport_msg->vport_id); } +/** + * idpf_mac_filter_async_handler - Async callback for mac filters + * @adapter: private data struct + * @xn: transaction for message + * @ctlq_msg: received message + * + * In some scenarios driver can't sleep and wait for a reply (e.g.: stack is + * holding rtnl_lock) when adding a new mac filter. It puts us in a difficult + * situation to deal with errors returned on the reply. The best we can + * ultimately do is remove it from our list of mac filters and report the + * error. + */ +static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter, + struct idpf_vc_xn *xn, + const struct idpf_ctlq_msg *ctlq_msg) +{ + struct virtchnl2_mac_addr_list *ma_list; + struct idpf_vport_config *vport_config; + struct virtchnl2_mac_addr *mac_addr; + struct idpf_mac_filter *f, *tmp; + struct list_head *ma_list_head; + struct idpf_vport *vport; + u16 num_entries; + int i; + + /* if success we're done, we're only here if something bad happened */ + if (!ctlq_msg->cookie.mbx.chnl_retval) + return 0; + + /* make sure at least struct is there */ + if (xn->reply_sz < sizeof(*ma_list)) + goto invalid_payload; + + ma_list = ctlq_msg->ctx.indirect.payload->va; + mac_addr = ma_list->mac_addr_list; + num_entries = le16_to_cpu(ma_list->num_mac_addr); + /* we should have received a buffer at least this big */ + if (xn->reply_sz < struct_size(ma_list, mac_addr_list, num_entries)) + goto invalid_payload; + + vport = idpf_vid_to_vport(adapter, le32_to_cpu(ma_list->vport_id)); + if (!vport) + goto invalid_payload; + + vport_config = adapter->vport_config[le32_to_cpu(ma_list->vport_id)]; + ma_list_head = &vport_config->user_config.mac_filter_list; + + /* We can't do much to reconcile bad filters at this point, however we + * should at least remove them from our list one way or the other so we + * have some idea what good filters we have. + */ + spin_lock_bh(&vport_config->mac_filter_list_lock); + list_for_each_entry_safe(f, tmp, ma_list_head, list) + for (i = 0; i < num_entries; i++) + if (ether_addr_equal(mac_addr[i].addr, f->macaddr)) + list_del(&f->list); + spin_unlock_bh(&vport_config->mac_filter_list_lock); + dev_err_ratelimited(&adapter->pdev->dev, "Received error sending MAC filter request (op %d)\n", + xn->vc_op); + + return 0; + +invalid_payload: + dev_err_ratelimited(&adapter->pdev->dev, "Received invalid MAC filter payload (op %d) (len %zd)\n", + xn->vc_op, xn->reply_sz); + + return -EINVAL; +} + /** * idpf_add_del_mac_filters - Add/del mac filters * @vport: Virtual port data structure @@ -3683,6 +3752,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, VIRTCHNL2_OP_DEL_MAC_ADDR; xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC; xn_params.async = async; + xn_params.async_handler = idpf_mac_filter_async_handler; vport_config = adapter->vport_config[np->vport_idx]; spin_lock_bh(&vport_config->mac_filter_list_lock); From e54232da12388a45ba4c30de4f6eab4bbc71994f Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:37 -0800 Subject: [PATCH 1807/2255] idpf: refactor idpf_recv_mb_msg Now that all the messages are using the transaction API, we can rework idpf_recv_mb_msg quite a lot to simplify it. Due to this, we remove idpf_find_vport as no longer used and alter idpf_recv_event_msg slightly. Tested-by: Alexander Lobakin Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 254 +++--------------- .../net/ethernet/intel/idpf/idpf_virtchnl.h | 3 +- 3 files changed, 37 insertions(+), 222 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 96c0b6d38799..4c6c7b9db762 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1254,7 +1254,7 @@ void idpf_mbx_task(struct work_struct *work) queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, msecs_to_jiffies(300)); - idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_UNKNOWN, NULL, 0); + idpf_recv_mb_msg(adapter); } /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index d1107507a98c..cf8aff26c3a9 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -160,12 +160,12 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter, /** * idpf_recv_event_msg - Receive virtchnl event message - * @vport: virtual port structure + * @adapter: Driver specific private structure * @ctlq_msg: message to copy from * * Receive virtchnl event message */ -static void idpf_recv_event_msg(struct idpf_vport *vport, +static void idpf_recv_event_msg(struct idpf_adapter *adapter, struct idpf_ctlq_msg *ctlq_msg) { int payload_size = ctlq_msg->ctx.indirect.payload->size; @@ -173,7 +173,7 @@ static void idpf_recv_event_msg(struct idpf_vport *vport, u32 event; if (payload_size < sizeof(*v2e)) { - dev_err_ratelimited(&vport->adapter->pdev->dev, "Failed to receive valid payload for event msg (op %d len %d)\n", + dev_err_ratelimited(&adapter->pdev->dev, "Failed to receive valid payload for event msg (op %d len %d)\n", ctlq_msg->cookie.mbx.chnl_opcode, payload_size); return; @@ -184,10 +184,10 @@ static void idpf_recv_event_msg(struct idpf_vport *vport, switch (event) { case VIRTCHNL2_EVENT_LINK_CHANGE: - idpf_handle_event_link(vport->adapter, v2e); + idpf_handle_event_link(adapter, v2e); return; default: - dev_err(&vport->adapter->pdev->dev, + dev_err(&adapter->pdev->dev, "Unknown event %d from PF\n", event); break; } @@ -310,125 +310,6 @@ dma_mem_error: return err; } -/** - * idpf_find_vport - Find vport pointer from control queue message - * @adapter: driver specific private structure - * @vport: address of vport pointer to copy the vport from adapters vport list - * @ctlq_msg: control queue message - * - * Return 0 on success, error value on failure. Also this function does check - * for the opcodes which expect to receive payload and return error value if - * it is not the case. - */ -static int idpf_find_vport(struct idpf_adapter *adapter, - struct idpf_vport **vport, - struct idpf_ctlq_msg *ctlq_msg) -{ - bool no_op = false, vid_found = false; - int i, err = 0; - char *vc_msg; - u32 v_id; - - vc_msg = kcalloc(IDPF_CTLQ_MAX_BUF_LEN, sizeof(char), GFP_KERNEL); - if (!vc_msg) - return -ENOMEM; - - if (ctlq_msg->data_len) { - size_t payload_size = ctlq_msg->ctx.indirect.payload->size; - - if (!payload_size) { - dev_err(&adapter->pdev->dev, "Failed to receive payload buffer\n"); - kfree(vc_msg); - - return -EINVAL; - } - - memcpy(vc_msg, ctlq_msg->ctx.indirect.payload->va, - min_t(size_t, payload_size, IDPF_CTLQ_MAX_BUF_LEN)); - } - - switch (ctlq_msg->cookie.mbx.chnl_opcode) { - case VIRTCHNL2_OP_VERSION: - case VIRTCHNL2_OP_GET_CAPS: - case VIRTCHNL2_OP_CREATE_VPORT: - case VIRTCHNL2_OP_SET_SRIOV_VFS: - case VIRTCHNL2_OP_ALLOC_VECTORS: - case VIRTCHNL2_OP_DEALLOC_VECTORS: - case VIRTCHNL2_OP_GET_PTYPE_INFO: - goto free_vc_msg; - case VIRTCHNL2_OP_ENABLE_VPORT: - case VIRTCHNL2_OP_DISABLE_VPORT: - case VIRTCHNL2_OP_DESTROY_VPORT: - v_id = le32_to_cpu(((struct virtchnl2_vport *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_CONFIG_TX_QUEUES: - v_id = le32_to_cpu(((struct virtchnl2_config_tx_queues *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_CONFIG_RX_QUEUES: - v_id = le32_to_cpu(((struct virtchnl2_config_rx_queues *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_ENABLE_QUEUES: - case VIRTCHNL2_OP_DISABLE_QUEUES: - case VIRTCHNL2_OP_DEL_QUEUES: - v_id = le32_to_cpu(((struct virtchnl2_del_ena_dis_queues *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_ADD_QUEUES: - v_id = le32_to_cpu(((struct virtchnl2_add_queues *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_MAP_QUEUE_VECTOR: - case VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR: - v_id = le32_to_cpu(((struct virtchnl2_queue_vector_maps *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_GET_STATS: - v_id = le32_to_cpu(((struct virtchnl2_vport_stats *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_GET_RSS_LUT: - case VIRTCHNL2_OP_SET_RSS_LUT: - v_id = le32_to_cpu(((struct virtchnl2_rss_lut *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_GET_RSS_KEY: - case VIRTCHNL2_OP_SET_RSS_KEY: - v_id = le32_to_cpu(((struct virtchnl2_rss_key *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_EVENT: - v_id = le32_to_cpu(((struct virtchnl2_event *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_LOOPBACK: - v_id = le32_to_cpu(((struct virtchnl2_loopback *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE: - v_id = le32_to_cpu(((struct virtchnl2_promisc_info *)vc_msg)->vport_id); - break; - case VIRTCHNL2_OP_ADD_MAC_ADDR: - case VIRTCHNL2_OP_DEL_MAC_ADDR: - v_id = le32_to_cpu(((struct virtchnl2_mac_addr_list *)vc_msg)->vport_id); - break; - default: - no_op = true; - break; - } - - if (no_op) - goto free_vc_msg; - - for (i = 0; i < idpf_get_max_vports(adapter); i++) { - if (adapter->vport_ids[i] == v_id) { - vid_found = true; - break; - } - } - - if (vid_found) - *vport = adapter->vports[i]; - else - err = -EINVAL; - -free_vc_msg: - kfree(vc_msg); - - return err; -} - /* API for virtchnl "transaction" support ("xn" for short). * * We are reusing the completion lock to serialize the accesses to the @@ -804,118 +685,53 @@ out_unlock: /** * idpf_recv_mb_msg - Receive message over mailbox * @adapter: Driver specific private structure - * @op: virtchannel operation code - * @msg: Received message holding buffer - * @msg_size: message size * * Will receive control queue message and posts the receive buffer. Returns 0 * on success and negative on failure. */ -int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, - void *msg, int msg_size) +int idpf_recv_mb_msg(struct idpf_adapter *adapter) { - struct idpf_vport *vport = NULL; struct idpf_ctlq_msg ctlq_msg; struct idpf_dma_mem *dma_mem; - bool work_done = false; - int num_retry = 2000; - u16 num_q_msg; - int err; + int post_err, err; + u16 num_recv; while (1) { - /* Try to get one message */ - num_q_msg = 1; - dma_mem = NULL; - err = idpf_ctlq_recv(adapter->hw.arq, &num_q_msg, &ctlq_msg); - /* If no message then decide if we have to retry based on - * opcode + /* This will get <= num_recv messages and output how many + * actually received on num_recv. */ - if (err || !num_q_msg) { - /* Increasing num_retry to consider the delayed - * responses because of large number of VF's mailbox - * messages. If the mailbox message is received from - * the other side, we come out of the sleep cycle - * immediately else we wait for more time. - */ - if (!op || !num_retry--) - break; - if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) { - err = -EIO; - break; - } - msleep(20); - continue; - } - - /* If we are here a message is received. Check if we are looking - * for a specific message based on opcode. If it is different - * ignore and post buffers - */ - if (op && ctlq_msg.cookie.mbx.chnl_opcode != op) - goto post_buffs; - - err = idpf_find_vport(adapter, &vport, &ctlq_msg); - if (err) - goto post_buffs; - - /* All conditions are met. Either a message requested is - * received or we received a message to be processed - */ - switch (ctlq_msg.cookie.mbx.chnl_opcode) { - case VIRTCHNL2_OP_VERSION: - case VIRTCHNL2_OP_GET_CAPS: - case VIRTCHNL2_OP_CREATE_VPORT: - case VIRTCHNL2_OP_ENABLE_VPORT: - case VIRTCHNL2_OP_DISABLE_VPORT: - case VIRTCHNL2_OP_DESTROY_VPORT: - case VIRTCHNL2_OP_CONFIG_TX_QUEUES: - case VIRTCHNL2_OP_CONFIG_RX_QUEUES: - case VIRTCHNL2_OP_ENABLE_QUEUES: - case VIRTCHNL2_OP_DISABLE_QUEUES: - case VIRTCHNL2_OP_ADD_QUEUES: - case VIRTCHNL2_OP_DEL_QUEUES: - case VIRTCHNL2_OP_MAP_QUEUE_VECTOR: - case VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR: - case VIRTCHNL2_OP_GET_STATS: - case VIRTCHNL2_OP_GET_RSS_LUT: - case VIRTCHNL2_OP_SET_RSS_LUT: - case VIRTCHNL2_OP_GET_RSS_KEY: - case VIRTCHNL2_OP_SET_RSS_KEY: - case VIRTCHNL2_OP_SET_SRIOV_VFS: - case VIRTCHNL2_OP_ALLOC_VECTORS: - case VIRTCHNL2_OP_DEALLOC_VECTORS: - case VIRTCHNL2_OP_GET_PTYPE_INFO: - case VIRTCHNL2_OP_LOOPBACK: - case VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE: - case VIRTCHNL2_OP_ADD_MAC_ADDR: - case VIRTCHNL2_OP_DEL_MAC_ADDR: - err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); + num_recv = 1; + err = idpf_ctlq_recv(adapter->hw.arq, &num_recv, &ctlq_msg); + if (err || !num_recv) break; - case VIRTCHNL2_OP_EVENT: - idpf_recv_event_msg(vport, &ctlq_msg); - break; - default: - dev_warn(&adapter->pdev->dev, - "Unhandled virtchnl response %d\n", - ctlq_msg.cookie.mbx.chnl_opcode); - break; - } -post_buffs: - if (ctlq_msg.data_len) + if (ctlq_msg.data_len) { dma_mem = ctlq_msg.ctx.indirect.payload; + } else { + dma_mem = NULL; + num_recv = 0; + } + + if (ctlq_msg.cookie.mbx.chnl_opcode == VIRTCHNL2_OP_EVENT) + idpf_recv_event_msg(adapter, &ctlq_msg); else - num_q_msg = 0; + err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg); + + post_err = idpf_ctlq_post_rx_buffs(&adapter->hw, + adapter->hw.arq, + &num_recv, &dma_mem); - err = idpf_ctlq_post_rx_buffs(&adapter->hw, adapter->hw.arq, - &num_q_msg, &dma_mem); /* If post failed clear the only buffer we supplied */ - if (err && dma_mem) - dma_free_coherent(&adapter->pdev->dev, dma_mem->size, - dma_mem->va, dma_mem->pa); + if (post_err) { + if (dma_mem) + dmam_free_coherent(&adapter->pdev->dev, + dma_mem->size, dma_mem->va, + dma_mem->pa); + break; + } - /* Applies only if we are looking for a specific opcode */ - if (work_done) + /* virtchnl trying to shutdown, stop cleaning */ + if (err == -ENXIO) break; } diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h index f008c793e486..83da5d8da56b 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h @@ -21,8 +21,7 @@ int idpf_get_reg_intr_vecs(struct idpf_vport *vport, int idpf_queue_reg_init(struct idpf_vport *vport); int idpf_vport_queue_ids_init(struct idpf_vport *vport); -int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, - void *msg, int msg_size); +int idpf_recv_mb_msg(struct idpf_adapter *adapter); int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op, u16 msg_size, u8 *msg, u16 cookie); From bcbedf253e918bcba8df999d300c3336e96fabff Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:38 -0800 Subject: [PATCH 1808/2255] idpf: cleanup virtchnl cruft We can now remove a bunch of gross code we don't need anymore like the vc state bits and vc_buf_lock since everything is using transaction API now. Tested-by: Alexander Lobakin Reviewed-by: Przemek Kitszel Reviewed-by: Igor Bagnucki Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 88 +------------------ drivers/net/ethernet/intel/idpf/idpf_lib.c | 25 +----- drivers/net/ethernet/intel/idpf/idpf_main.c | 2 - .../net/ethernet/intel/idpf/idpf_virtchnl.c | 13 --- 4 files changed, 3 insertions(+), 125 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index ed5474c1565a..5ed08be1dbc0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -37,8 +37,6 @@ struct idpf_vport_max_q; #define IDPF_MB_MAX_ERR 20 #define IDPF_NUM_CHUNKS_PER_MSG(struct_sz, chunk_sz) \ ((IDPF_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz)) -#define IDPF_WAIT_FOR_EVENT_TIMEO_MIN 2000 -#define IDPF_WAIT_FOR_EVENT_TIMEO 60000 #define IDPF_MAX_WAIT 500 @@ -207,71 +205,6 @@ struct idpf_dev_ops { struct idpf_reg_ops reg_ops; }; -/* These macros allow us to generate an enum and a matching char * array of - * stringified enums that are always in sync. Checkpatch issues a bogus warning - * about this being a complex macro; but it's wrong, these are never used as a - * statement and instead only used to define the enum and array. - */ -#define IDPF_FOREACH_VPORT_VC_STATE(STATE) \ - STATE(IDPF_VC_CREATE_VPORT) \ - STATE(IDPF_VC_CREATE_VPORT_ERR) \ - STATE(IDPF_VC_ENA_VPORT) \ - STATE(IDPF_VC_ENA_VPORT_ERR) \ - STATE(IDPF_VC_DIS_VPORT) \ - STATE(IDPF_VC_DIS_VPORT_ERR) \ - STATE(IDPF_VC_DESTROY_VPORT) \ - STATE(IDPF_VC_DESTROY_VPORT_ERR) \ - STATE(IDPF_VC_CONFIG_TXQ) \ - STATE(IDPF_VC_CONFIG_TXQ_ERR) \ - STATE(IDPF_VC_CONFIG_RXQ) \ - STATE(IDPF_VC_CONFIG_RXQ_ERR) \ - STATE(IDPF_VC_ENA_QUEUES) \ - STATE(IDPF_VC_ENA_QUEUES_ERR) \ - STATE(IDPF_VC_DIS_QUEUES) \ - STATE(IDPF_VC_DIS_QUEUES_ERR) \ - STATE(IDPF_VC_MAP_IRQ) \ - STATE(IDPF_VC_MAP_IRQ_ERR) \ - STATE(IDPF_VC_UNMAP_IRQ) \ - STATE(IDPF_VC_UNMAP_IRQ_ERR) \ - STATE(IDPF_VC_ADD_QUEUES) \ - STATE(IDPF_VC_ADD_QUEUES_ERR) \ - STATE(IDPF_VC_DEL_QUEUES) \ - STATE(IDPF_VC_DEL_QUEUES_ERR) \ - STATE(IDPF_VC_ALLOC_VECTORS) \ - STATE(IDPF_VC_ALLOC_VECTORS_ERR) \ - STATE(IDPF_VC_DEALLOC_VECTORS) \ - STATE(IDPF_VC_DEALLOC_VECTORS_ERR) \ - STATE(IDPF_VC_SET_SRIOV_VFS) \ - STATE(IDPF_VC_SET_SRIOV_VFS_ERR) \ - STATE(IDPF_VC_GET_RSS_LUT) \ - STATE(IDPF_VC_GET_RSS_LUT_ERR) \ - STATE(IDPF_VC_SET_RSS_LUT) \ - STATE(IDPF_VC_SET_RSS_LUT_ERR) \ - STATE(IDPF_VC_GET_RSS_KEY) \ - STATE(IDPF_VC_GET_RSS_KEY_ERR) \ - STATE(IDPF_VC_SET_RSS_KEY) \ - STATE(IDPF_VC_SET_RSS_KEY_ERR) \ - STATE(IDPF_VC_GET_STATS) \ - STATE(IDPF_VC_GET_STATS_ERR) \ - STATE(IDPF_VC_ADD_MAC_ADDR) \ - STATE(IDPF_VC_ADD_MAC_ADDR_ERR) \ - STATE(IDPF_VC_DEL_MAC_ADDR) \ - STATE(IDPF_VC_DEL_MAC_ADDR_ERR) \ - STATE(IDPF_VC_GET_PTYPE_INFO) \ - STATE(IDPF_VC_GET_PTYPE_INFO_ERR) \ - STATE(IDPF_VC_LOOPBACK_STATE) \ - STATE(IDPF_VC_LOOPBACK_STATE_ERR) \ - STATE(IDPF_VC_NBITS) - -#define IDPF_GEN_ENUM(ENUM) ENUM, -#define IDPF_GEN_STRING(STRING) #STRING, - -enum idpf_vport_vc_state { - IDPF_FOREACH_VPORT_VC_STATE(IDPF_GEN_ENUM) -}; - -extern const char * const idpf_vport_vc_state_str[]; - /** * enum idpf_vport_reset_cause - Vport soft reset causes * @IDPF_SR_Q_CHANGE: Soft reset queue change @@ -356,11 +289,7 @@ struct idpf_port_stats { * @port_stats: per port csum, header split, and other offload stats * @link_up: True if link is up * @link_speed_mbps: Link speed in mbps - * @vc_msg: Virtchnl message buffer - * @vc_state: Virtchnl message state - * @vchnl_wq: Wait queue for virtchnl messages * @sw_marker_wq: workqueue for marker packets - * @vc_buf_lock: Lock to protect virtchnl buffer */ struct idpf_vport { u16 num_txq; @@ -406,12 +335,7 @@ struct idpf_vport { bool link_up; u32 link_speed_mbps; - char vc_msg[IDPF_CTLQ_MAX_BUF_LEN]; - DECLARE_BITMAP(vc_state, IDPF_VC_NBITS); - - wait_queue_head_t vchnl_wq; wait_queue_head_t sw_marker_wq; - struct mutex vc_buf_lock; }; /** @@ -474,15 +398,11 @@ struct idpf_vport_user_config_data { * enum idpf_vport_config_flags - Vport config flags * @IDPF_VPORT_REG_NETDEV: Register netdev * @IDPF_VPORT_UP_REQUESTED: Set if interface up is requested on core reset - * @IDPF_VPORT_ADD_MAC_REQ: Asynchronous add ether address in flight - * @IDPF_VPORT_DEL_MAC_REQ: Asynchronous delete ether address in flight * @IDPF_VPORT_CONFIG_FLAGS_NBITS: Must be last */ enum idpf_vport_config_flags { IDPF_VPORT_REG_NETDEV, IDPF_VPORT_UP_REQUESTED, - IDPF_VPORT_ADD_MAC_REQ, - IDPF_VPORT_DEL_MAC_REQ, IDPF_VPORT_CONFIG_FLAGS_NBITS, }; @@ -601,9 +521,6 @@ struct idpf_vc_xn_manager; * @stats_task: Periodic statistics retrieval task * @stats_wq: Workqueue for statistics task * @caps: Negotiated capabilities with device - * @vchnl_wq: Wait queue for virtchnl messages - * @vc_state: Virtchnl message state - * @vc_msg: Virtchnl message buffer * @vcxn_mngr: Virtchnl transaction manager * @dev_ops: See idpf_dev_ops * @num_vfs: Number of allocated VFs through sysfs. PF does not directly talk @@ -660,11 +577,8 @@ struct idpf_adapter { struct delayed_work stats_task; struct workqueue_struct *stats_wq; struct virtchnl2_get_capabilities caps; - - wait_queue_head_t vchnl_wq; - DECLARE_BITMAP(vc_state, IDPF_VC_NBITS); - char vc_msg[IDPF_CTLQ_MAX_BUF_LEN]; struct idpf_vc_xn_manager *vcxn_mngr; + struct idpf_dev_ops dev_ops; int num_vfs; bool crc_enable; diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 4c6c7b9db762..0714d7dcab10 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -7,10 +7,6 @@ static const struct net_device_ops idpf_netdev_ops_splitq; static const struct net_device_ops idpf_netdev_ops_singleq; -const char * const idpf_vport_vc_state_str[] = { - IDPF_FOREACH_VPORT_VC_STATE(IDPF_GEN_STRING) -}; - /** * idpf_init_vector_stack - Fill the MSIX vector stack with vector index * @adapter: private data struct @@ -976,7 +972,6 @@ static void idpf_vport_rel(struct idpf_vport *vport) struct idpf_rss_data *rss_data; struct idpf_vport_max_q max_q; u16 idx = vport->idx; - int i; vport_config = adapter->vport_config[vport->idx]; idpf_deinit_rss(vport); @@ -986,20 +981,6 @@ static void idpf_vport_rel(struct idpf_vport *vport) idpf_send_destroy_vport_msg(vport); - /* Set all bits as we dont know on which vc_state the vport vhnl_wq - * is waiting on and wakeup the virtchnl workqueue even if it is - * waiting for the response as we are going down - */ - for (i = 0; i < IDPF_VC_NBITS; i++) - set_bit(i, vport->vc_state); - wake_up(&vport->vchnl_wq); - - mutex_destroy(&vport->vc_buf_lock); - - /* Clear all the bits */ - for (i = 0; i < IDPF_VC_NBITS; i++) - clear_bit(i, vport->vc_state); - /* Release all max queues allocated to the adapter's pool */ max_q.max_rxq = vport_config->max_q.max_rxq; max_q.max_txq = vport_config->max_q.max_txq; @@ -1544,9 +1525,7 @@ void idpf_init_task(struct work_struct *work) vport_config = adapter->vport_config[index]; init_waitqueue_head(&vport->sw_marker_wq); - init_waitqueue_head(&vport->vchnl_wq); - mutex_init(&vport->vc_buf_lock); spin_lock_init(&vport_config->mac_filter_list_lock); INIT_LIST_HEAD(&vport_config->user_config.mac_filter_list); @@ -1905,7 +1884,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, * mess with. Nothing below should use those variables from new_vport * and should instead always refer to them in vport if they need to. */ - memcpy(new_vport, vport, offsetof(struct idpf_vport, vc_state)); + memcpy(new_vport, vport, offsetof(struct idpf_vport, link_speed_mbps)); /* Adjust resource parameters prior to reallocating resources */ switch (reset_cause) { @@ -1954,7 +1933,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, /* Same comment as above regarding avoiding copying the wait_queues and * mutexes applies here. We do not want to mess with those if possible. */ - memcpy(vport, new_vport, offsetof(struct idpf_vport, vc_state)); + memcpy(vport, new_vport, offsetof(struct idpf_vport, link_speed_mbps)); /* Since idpf_vport_queues_alloc was called with new_port, the queue * back pointers are currently pointing to the local new_vport. Reset diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c index c9b6ef3166aa..f784eea044bd 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_main.c +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c @@ -233,8 +233,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mutex_init(&adapter->queue_lock); mutex_init(&adapter->vc_buf_lock); - init_waitqueue_head(&adapter->vchnl_wq); - INIT_DELAYED_WORK(&adapter->init_task, idpf_init_task); INIT_DELAYED_WORK(&adapter->serv_task, idpf_service_task); INIT_DELAYED_WORK(&adapter->mbx_task, idpf_mbx_task); diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index cf8aff26c3a9..e89e2bad460d 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -3034,28 +3034,15 @@ init_failed: */ void idpf_vc_core_deinit(struct idpf_adapter *adapter) { - int i; - idpf_vc_xn_shutdown(adapter->vcxn_mngr); idpf_deinit_task(adapter); idpf_intr_rel(adapter); - /* Set all bits as we dont know on which vc_state the vhnl_wq is - * waiting on and wakeup the virtchnl workqueue even if it is waiting - * for the response as we are going down - */ - for (i = 0; i < IDPF_VC_NBITS; i++) - set_bit(i, adapter->vc_state); - wake_up(&adapter->vchnl_wq); cancel_delayed_work_sync(&adapter->serv_task); cancel_delayed_work_sync(&adapter->mbx_task); idpf_vport_params_buf_rel(adapter); - /* Clear all the bits */ - for (i = 0; i < IDPF_VC_NBITS; i++) - clear_bit(i, adapter->vc_state); - kfree(adapter->vports); adapter->vports = NULL; } From 14696ed173af247a2d80b779c2f0cb08c94dfb4d Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:39 -0800 Subject: [PATCH 1809/2255] idpf: prevent deinit uninitialized virtchnl core In idpf_remove we need to tear down the virtchnl core with idpf_vc_core_deinit so we can free up resources and leave things in a good state. However, in the case where we failed to establish VC communications we may not have ever actually successfully initialized the virtchnl core. This fixes it by setting a bit once we successfully init the virtchnl core. Then, in deinit, we'll check for it before going on further, otherwise we just return. Also clear the bit at the end of deinit so we know it's gone now. Tested-by: Alexander Lobakin Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 2 ++ drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 5ed08be1dbc0..e7a036538246 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -83,6 +83,7 @@ enum idpf_state { * @IDPF_HR_RESET_IN_PROG: Reset in progress * @IDPF_REMOVE_IN_PROG: Driver remove in progress * @IDPF_MB_INTR_MODE: Mailbox in interrupt mode + * @IDPF_VC_CORE_INIT: virtchnl core has been init * @IDPF_FLAGS_NBITS: Must be last */ enum idpf_flags { @@ -91,6 +92,7 @@ enum idpf_flags { IDPF_HR_RESET_IN_PROG, IDPF_REMOVE_IN_PROG, IDPF_MB_INTR_MODE, + IDPF_VC_CORE_INIT, IDPF_FLAGS_NBITS, }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index e89e2bad460d..a602ff8d74e0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -2990,7 +2990,9 @@ restart: queue_delayed_work(adapter->init_wq, &adapter->init_task, msecs_to_jiffies(5 * (adapter->pdev->devfn & 0x07))); - goto no_err; + set_bit(IDPF_VC_CORE_INIT, adapter->flags); + + return 0; err_intr_req: cancel_delayed_work_sync(&adapter->serv_task); @@ -2999,7 +3001,6 @@ err_intr_req: err_netdev_alloc: kfree(adapter->vports); adapter->vports = NULL; -no_err: return err; init_failed: @@ -3034,6 +3035,9 @@ init_failed: */ void idpf_vc_core_deinit(struct idpf_adapter *adapter) { + if (!test_bit(IDPF_VC_CORE_INIT, adapter->flags)) + return; + idpf_vc_xn_shutdown(adapter->vcxn_mngr); idpf_deinit_task(adapter); idpf_intr_rel(adapter); @@ -3045,6 +3049,8 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter) kfree(adapter->vports); adapter->vports = NULL; + + clear_bit(IDPF_VC_CORE_INIT, adapter->flags); } /** From 4f5126a075c415044d36e9e6948a8a3a43e97ad0 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:40 -0800 Subject: [PATCH 1810/2255] idpf: fix minor controlq issues While we're here improving virtchnl we can include two minor fixes for the lower level ctrlq flow. This adds a memory barrier to idpf_post_rx_buffs before we update tail on the controlq. We should make sure our writes have had a chance to finish before we tell HW it can touch them. This also removes some defensive programming in idpf_ctrlq_recv. The caller should not be using a num_q_msg value of zero or more than the ring size and it's their responsibility to call functions sanely. Tested-by: Alexander Lobakin Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_controlq.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.c b/drivers/net/ethernet/intel/idpf/idpf_controlq.c index c7f43d2fcd13..4849590a5591 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_controlq.c +++ b/drivers/net/ethernet/intel/idpf/idpf_controlq.c @@ -516,6 +516,8 @@ post_buffs_out: /* Wrap to end of end ring since current ntp is 0 */ cq->next_to_post = cq->ring_size - 1; + dma_wmb(); + wr32(hw, cq->reg.tail, cq->next_to_post); } @@ -546,11 +548,6 @@ int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg, int err = 0; u16 i; - if (*num_q_msg == 0) - return 0; - else if (*num_q_msg > cq->ring_size) - return -EBADR; - /* take the lock before we start messing with the ring */ mutex_lock(&cq->cq_lock); From 6009e63c57c9cee216c5f8d415a2f88353abc0a4 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Thu, 22 Feb 2024 11:04:41 -0800 Subject: [PATCH 1811/2255] idpf: remove dealloc vector msg err in idpf_intr_rel This error message is at best not really helpful and at worst misleading. If we're here in idpf_intr_rel we're likely trying to do remove or reset. If we're in reset, this message will fail because we lose the virtchnl on reset and HW is going to clean up those resources regardless in that case. If we're in remove and we get an error here, we're going to reset the device at the end of remove anyway so not a big deal. Just remove this message it's not useful. Tested-by: Alexander Lobakin Signed-off-by: Alan Brady Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 0714d7dcab10..5d3532c27d57 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -79,19 +79,12 @@ static void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter) */ void idpf_intr_rel(struct idpf_adapter *adapter) { - int err; - if (!adapter->msix_entries) return; idpf_mb_intr_rel_irq(adapter); pci_free_irq_vectors(adapter->pdev); - - err = idpf_send_dealloc_vectors_msg(adapter); - if (err) - dev_err(&adapter->pdev->dev, - "Failed to deallocate vectors: %d\n", err); - + idpf_send_dealloc_vectors_msg(adapter); idpf_deinit_vector_stack(adapter); kfree(adapter->msix_entries); adapter->msix_entries = NULL; From 73e4f9e615d7b99f39663d4722dc73e8fa5db5f9 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Sat, 24 Feb 2024 14:34:16 -0800 Subject: [PATCH 1812/2255] bpf, net: validate struct_ops when updating value. Perform all validations when updating values of struct_ops maps. Doing validation in st_ops->reg() and st_ops->update() is not necessary anymore. However, tcp_register_congestion_control() has been called in various places. It still needs to do validations. Cc: netdev@vger.kernel.org Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240224223418.526631-2-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/bpf_struct_ops.c | 11 ++++++----- net/ipv4/tcp_cong.c | 6 +----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index a6019087b467..07e554c191d1 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -672,13 +672,14 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, *(unsigned long *)(udata + moff) = prog->aux->id; } + if (st_ops->validate) { + err = st_ops->validate(kdata); + if (err) + goto reset_unlock; + } + if (st_map->map.map_flags & BPF_F_LINK) { err = 0; - if (st_ops->validate) { - err = st_ops->validate(kdata); - if (err) - goto reset_unlock; - } arch_protect_bpf_trampoline(st_map->image, PAGE_SIZE); /* Let bpf_link handle registration & unregistration. * diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 1b34050a7538..28ffcfbeef14 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -146,11 +146,7 @@ EXPORT_SYMBOL_GPL(tcp_unregister_congestion_control); int tcp_update_congestion_control(struct tcp_congestion_ops *ca, struct tcp_congestion_ops *old_ca) { struct tcp_congestion_ops *existing; - int ret; - - ret = tcp_validate_congestion_control(ca); - if (ret) - return ret; + int ret = 0; ca->key = jhash(ca->name, sizeof(ca->name), strlen(ca->name)); From a21605993dd5dfd15edfa7f06705ede17b519026 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 16 Feb 2024 14:06:35 -0800 Subject: [PATCH 1813/2255] ice: pass VSI pointer into ice_vc_isvalid_q_id The ice_vc_isvalid_q_id() function takes a VSI index and a queue ID. It looks up the VSI from its index, and then validates that the queue number is valid for that VSI. The VSI ID passed is typically a VSI index from the VF. This VSI number is validated by the PF to ensure that it matches the VSI associated with the VF already. In every flow where ice_vc_isvalid_q_id() is called, the PF driver already has a pointer to the VSI associated with the VF. This pointer is obtained using ice_get_vf_vsi(), rather than looking up the VSI using the index sent by the VF. Since we already know which VSI to operate on, we can modify ice_vc_isvalid_q_id() to take a VSI pointer instead of a VSI index. Pass the VSI we found from ice_get_vf_vsi() instead of re-doing the lookup. This removes some unnecessary computation and scanning of the VSI list. It also removes the last place where the driver directly used the VSI number from the VF. This will pave the way for refactoring to communicate relative VSI numbers to the VF instead of absolute numbers from the PF space. Signed-off-by: Jacob Keller Reviewed-by: Przemek Kitszel Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_virtchnl.c | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index c925813ec9ca..3dd4e5af0b6a 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -562,17 +562,15 @@ bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id) /** * ice_vc_isvalid_q_id - * @vf: pointer to the VF info - * @vsi_id: VSI ID + * @vsi: VSI to check queue ID against * @qid: VSI relative queue ID * * check for the valid queue ID */ -static bool ice_vc_isvalid_q_id(struct ice_vf *vf, u16 vsi_id, u8 qid) +static bool ice_vc_isvalid_q_id(struct ice_vsi *vsi, u8 qid) { - struct ice_vsi *vsi = ice_find_vsi(vf->pf, vsi_id); /* allocated Tx and Rx queues should be always equal for VF VSI */ - return (vsi && (qid < vsi->alloc_txq)); + return qid < vsi->alloc_txq; } /** @@ -1330,7 +1328,7 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) */ q_map = vqs->rx_queues; for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { - if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } @@ -1352,7 +1350,7 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) q_map = vqs->tx_queues; for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { - if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } @@ -1457,7 +1455,7 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) q_map = vqs->tx_queues; for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { - if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } @@ -1483,7 +1481,7 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF); } else if (q_map) { for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { - if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } @@ -1539,7 +1537,7 @@ ice_cfg_interrupt(struct ice_vf *vf, struct ice_vsi *vsi, u16 vector_id, for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { vsi_q_id = vsi_q_id_idx; - if (!ice_vc_isvalid_q_id(vf, vsi->vsi_num, vsi_q_id)) + if (!ice_vc_isvalid_q_id(vsi, vsi_q_id)) return VIRTCHNL_STATUS_ERR_PARAM; q_vector->num_ring_rx++; @@ -1553,7 +1551,7 @@ ice_cfg_interrupt(struct ice_vf *vf, struct ice_vsi *vsi, u16 vector_id, for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { vsi_q_id = vsi_q_id_idx; - if (!ice_vc_isvalid_q_id(vf, vsi->vsi_num, vsi_q_id)) + if (!ice_vc_isvalid_q_id(vsi, vsi_q_id)) return VIRTCHNL_STATUS_ERR_PARAM; q_vector->num_ring_tx++; @@ -1710,7 +1708,7 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) qpi->txq.headwb_enabled || !ice_vc_isvalid_ring_len(qpi->txq.ring_len) || !ice_vc_isvalid_ring_len(qpi->rxq.ring_len) || - !ice_vc_isvalid_q_id(vf, qci->vsi_id, qpi->txq.queue_id)) { + !ice_vc_isvalid_q_id(vsi, qpi->txq.queue_id)) { goto error_param; } From 363f689600dd010703ce6391bcfc729a97d21840 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 16 Feb 2024 14:06:36 -0800 Subject: [PATCH 1814/2255] ice: remove unnecessary duplicate checks for VF VSI ID The ice_vc_fdir_param_check() function validates that the VSI ID of the virtchnl flow director command matches the VSI number of the VF. This is already checked by the call to ice_vc_isvalid_vsi_id() immediately following this. This check is unnecessary since ice_vc_isvalid_vsi_id() already confirms this by checking that the VSI ID can locate the VSI associated with the VF structure. Furthermore, a following change is going to refactor the ice driver to report VSI IDs using a relative index for each VF instead of reporting the PF VSI number. This additional check would break that logic since it enforces that the VSI ID matches the VSI number. Since this check duplicates the logic in ice_vc_isvalid_vsi_id() and gets in the way of refactoring that logic, remove it. Signed-off-by: Jacob Keller Reviewed-by: Przemek Kitszel Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c index f001553e1a1a..8e4ff3af86c6 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c @@ -94,9 +94,6 @@ ice_vc_fdir_param_check(struct ice_vf *vf, u16 vsi_id) if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF)) return -EINVAL; - if (vsi_id != vf->lan_vsi_num) - return -EINVAL; - if (!ice_vc_isvalid_vsi_id(vf, vsi_id)) return -EINVAL; From 11fbb1bfb5bc8c98b2d7db9da332b5e568f4aaab Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 16 Feb 2024 14:06:37 -0800 Subject: [PATCH 1815/2255] ice: use relative VSI index for VFs instead of PF VSI number When initializing over virtchnl, the PF is required to pass a VSI ID to the VF as part of its capabilities exchange. The VF driver reports this value back to the PF in a variety of commands. The PF driver validates that this value matches the value it sent to the VF. Some hardware families such as the E700 series could use this value when reading RSS registers or communicating directly with firmware over the Admin Queue. However, E800 series hardware does not support any of these interfaces and the VF's only use for this value is to report it back to the PF. Thus, there is no requirement that this value be an actual VSI ID value of any kind. The PF driver already does not trust that the VF sends it a real VSI ID. The VSI structure is always looked up from the VF structure. The PF does validate that the VSI ID provided matches a VSI associated with the VF, but otherwise does not use the VSI ID for any purpose. Instead of reporting the VSI number relative to the PF space, report a fixed value of 1. When communicating with the VF over virtchnl, validate that the VSI number is returned appropriately. This avoids leaking information about the firmware of the PF state. Currently the ice driver only supplies a VF with a single VSI. However, it appears that virtchnl has some support for allowing multiple VSIs. I did not attempt to implement this. However, space is left open to allow further relative indexes if additional VSIs are provided in future feature development. For this reason, keep the ice_vc_isvalid_vsi_id function in place to allow extending it for multiple VSIs in the future. This change will also simplify handling of live migration in a future series. Since we no longer will provide a real VSI number to the VF, there will be no need to keep track of this number when migrating to a new host. Signed-off-by: Jacob Keller Reviewed-by: Przemek Kitszel Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_virtchnl.c | 9 ++------- drivers/net/ethernet/intel/ice/ice_virtchnl.h | 9 +++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index 3dd4e5af0b6a..6b88b9bfb51e 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -506,7 +506,7 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) vfres->rss_lut_size = ICE_LUT_VSI_SIZE; vfres->max_mtu = ice_vc_get_max_frame_size(vf); - vfres->vsi_res[0].vsi_id = vf->lan_vsi_num; + vfres->vsi_res[0].vsi_id = ICE_VF_VSI_ID; vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV; vfres->vsi_res[0].num_queue_pairs = vsi->num_txq; ether_addr_copy(vfres->vsi_res[0].default_mac_addr, @@ -552,12 +552,7 @@ static void ice_vc_reset_vf_msg(struct ice_vf *vf) */ bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id) { - struct ice_pf *pf = vf->pf; - struct ice_vsi *vsi; - - vsi = ice_find_vsi(pf, vsi_id); - - return (vsi && (vsi->vf == vf)); + return vsi_id == ICE_VF_VSI_ID; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.h b/drivers/net/ethernet/intel/ice/ice_virtchnl.h index 60dfbe05980a..3a4115869153 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.h @@ -19,6 +19,15 @@ #define ICE_MAX_MACADDR_PER_VF 18 #define ICE_FLEX_DESC_RXDID_MAX_NUM 64 +/* VFs only get a single VSI. For ice hardware, the VF does not need to know + * its VSI index. However, the virtchnl interface requires a VSI number, + * mainly due to legacy hardware. + * + * Since the VF doesn't need this information, report a static value to the VF + * instead of leaking any information about the PF or hardware setup. + */ +#define ICE_VF_VSI_ID 1 + struct ice_virtchnl_ops { int (*get_ver_msg)(struct ice_vf *vf, u8 *msg); int (*get_vf_res_msg)(struct ice_vf *vf, u8 *msg); From 1cf94cbfc61bac89cddeb075fbc100ebd3aea81b Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 16 Feb 2024 14:06:38 -0800 Subject: [PATCH 1816/2255] ice: remove vf->lan_vsi_num field The lan_vsi_num field of the VF structure is no longer used for any purpose. Remove it. Signed-off-by: Jacob Keller Reviewed-by: Przemek Kitszel Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_sriov.c | 1 - drivers/net/ethernet/intel/ice/ice_vf_lib.c | 10 +--------- drivers/net/ethernet/intel/ice/ice_vf_lib.h | 5 ----- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index a94a1c48c3de..a2f8dbe3cb82 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -240,7 +240,6 @@ static struct ice_vsi *ice_vf_vsi_setup(struct ice_vf *vf) } vf->lan_vsi_idx = vsi->idx; - vf->lan_vsi_num = vsi->vsi_num; return vsi; } diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 2ffdae9a82df..21d26e19338a 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -280,12 +280,6 @@ int ice_vf_reconfig_vsi(struct ice_vf *vf) return err; } - /* Update the lan_vsi_num field since it might have been changed. The - * PF lan_vsi_idx number remains the same so we don't need to change - * that. - */ - vf->lan_vsi_num = vsi->vsi_num; - return 0; } @@ -315,7 +309,6 @@ static int ice_vf_rebuild_vsi(struct ice_vf *vf) * vf->lan_vsi_idx */ vsi->vsi_num = ice_get_hw_vsi_num(&pf->hw, vsi->idx); - vf->lan_vsi_num = vsi->vsi_num; return 0; } @@ -1315,13 +1308,12 @@ int ice_vf_init_host_cfg(struct ice_vf *vf, struct ice_vsi *vsi) } /** - * ice_vf_invalidate_vsi - invalidate vsi_idx/vsi_num to remove VSI access + * ice_vf_invalidate_vsi - invalidate vsi_idx to remove VSI access * @vf: VF to remove access to VSI for */ void ice_vf_invalidate_vsi(struct ice_vf *vf) { vf->lan_vsi_idx = ICE_NO_VSI; - vf->lan_vsi_num = ICE_NO_VSI; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h index 0cc9034065c5..fec16919ec19 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h @@ -109,11 +109,6 @@ struct ice_vf { u8 spoofchk:1; u8 link_forced:1; u8 link_up:1; /* only valid if VF link is forced */ - /* VSI indices - actual VSI pointers are maintained in the PF structure - * When assigned, these will be non-zero, because VSI 0 is always - * the main LAN VSI for the PF. - */ - u16 lan_vsi_num; /* ID as used by firmware */ unsigned int min_tx_rate; /* Minimum Tx bandwidth limit in Mbps */ unsigned int max_tx_rate; /* Maximum Tx bandwidth limit in Mbps */ DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */ From 1260b45dbe2dbc415f3bc1e841c6c098083bcfb8 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 26 Feb 2024 16:14:54 -0800 Subject: [PATCH 1817/2255] ice: rename ice_write_* functions to ice_pack_ctx_* In ice_common.c there are 4 functions used for converting the unpacked software Tx and Rx context structure data into the packed format used by hardware. These functions have extremely generic names: * ice_write_byte * ice_write_word * ice_write_dword * ice_write_qword When I saw these function names my first thought was "write what? to where?". Understanding what these functions do requires looking at the implementation details. The functions take bits from an unpacked structure and copy them into the packed layout used by hardware. As part of live migration, we will want functions which perform the inverse operation of reading bits from the packed layout and copying them into the unpacked format. Naming these as "ice_read_byte", etc would be very confusing since they appear to write data. In preparation for adding this new inverse operation, rename the existing functions to use the prefix "ice_pack_ctx_". This makes it clear that they perform the bit packing while copying from the unpacked software context structure to the packed hardware context. The inverse operations can then neatly be named ice_unpack_ctx_*, clearly indicating they perform the bit unpacking while copying from the packed hardware context to the unpacked software context structure. Signed-off-by: Jacob Keller Reviewed-by: Przemek Kitszel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 56 ++++++++++----------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 9266f25a9978..3622079cb506 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -4362,13 +4362,13 @@ ice_aq_add_rdma_qsets(struct ice_hw *hw, u8 num_qset_grps, /* End of FW Admin Queue command wrappers */ /** - * ice_write_byte - write a byte to a packed context structure - * @src_ctx: the context structure to read from - * @dest_ctx: the context to be written to - * @ce_info: a description of the struct to be filled + * ice_pack_ctx_byte - write a byte to a packed context structure + * @src_ctx: unpacked source context structure + * @dest_ctx: packed destination context data + * @ce_info: context element description */ -static void -ice_write_byte(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) +static void ice_pack_ctx_byte(u8 *src_ctx, u8 *dest_ctx, + const struct ice_ctx_ele *ce_info) { u8 src_byte, dest_byte, mask; u8 *from, *dest; @@ -4401,13 +4401,13 @@ ice_write_byte(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) } /** - * ice_write_word - write a word to a packed context structure - * @src_ctx: the context structure to read from - * @dest_ctx: the context to be written to - * @ce_info: a description of the struct to be filled + * ice_pack_ctx_word - write a word to a packed context structure + * @src_ctx: unpacked source context structure + * @dest_ctx: packed destination context data + * @ce_info: context element description */ -static void -ice_write_word(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) +static void ice_pack_ctx_word(u8 *src_ctx, u8 *dest_ctx, + const struct ice_ctx_ele *ce_info) { u16 src_word, mask; __le16 dest_word; @@ -4444,13 +4444,13 @@ ice_write_word(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) } /** - * ice_write_dword - write a dword to a packed context structure - * @src_ctx: the context structure to read from - * @dest_ctx: the context to be written to - * @ce_info: a description of the struct to be filled + * ice_pack_ctx_dword - write a dword to a packed context structure + * @src_ctx: unpacked source context structure + * @dest_ctx: packed destination context data + * @ce_info: context element description */ -static void -ice_write_dword(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) +static void ice_pack_ctx_dword(u8 *src_ctx, u8 *dest_ctx, + const struct ice_ctx_ele *ce_info) { u32 src_dword, mask; __le32 dest_dword; @@ -4495,13 +4495,13 @@ ice_write_dword(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) } /** - * ice_write_qword - write a qword to a packed context structure - * @src_ctx: the context structure to read from - * @dest_ctx: the context to be written to - * @ce_info: a description of the struct to be filled + * ice_pack_ctx_qword - write a qword to a packed context structure + * @src_ctx: unpacked source context structure + * @dest_ctx: packed destination context data + * @ce_info: context element description */ -static void -ice_write_qword(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) +static void ice_pack_ctx_qword(u8 *src_ctx, u8 *dest_ctx, + const struct ice_ctx_ele *ce_info) { u64 src_qword, mask; __le64 dest_qword; @@ -4570,16 +4570,16 @@ ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx, } switch (ce_info[f].size_of) { case sizeof(u8): - ice_write_byte(src_ctx, dest_ctx, &ce_info[f]); + ice_pack_ctx_byte(src_ctx, dest_ctx, &ce_info[f]); break; case sizeof(u16): - ice_write_word(src_ctx, dest_ctx, &ce_info[f]); + ice_pack_ctx_word(src_ctx, dest_ctx, &ce_info[f]); break; case sizeof(u32): - ice_write_dword(src_ctx, dest_ctx, &ce_info[f]); + ice_pack_ctx_dword(src_ctx, dest_ctx, &ce_info[f]); break; case sizeof(u64): - ice_write_qword(src_ctx, dest_ctx, &ce_info[f]); + ice_pack_ctx_qword(src_ctx, dest_ctx, &ce_info[f]); break; default: return -EINVAL; From a45d1bf516c097bb7ae4983d3128ebf139be952c Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 26 Feb 2024 16:14:55 -0800 Subject: [PATCH 1818/2255] ice: use GENMASK instead of BIT(n) - 1 in pack functions The functions used to pack the Tx and Rx context into the hardware format rely on using BIT() and then subtracting 1 to get a bitmask. These functions even have a comment about how x86 machines can't use this method for certain widths because the SHL instructions will not work properly. The Linux kernel already provides the GENMASK macro for generating a suitable bitmask. Further, GENMASK is capable of generating the mask including the shift_width. Since width is the total field width, take care to subtract one to get the final bit position. Since we now include the shifted bits as part of the mask, shift the source value first before applying the mask. Signed-off-by: Jacob Keller Reviewed-by: Przemek Kitszel Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 44 ++++----------------- 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 3622079cb506..e9e4a8ef7904 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -4379,14 +4379,11 @@ static void ice_pack_ctx_byte(u8 *src_ctx, u8 *dest_ctx, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - mask = (u8)(BIT(ce_info->width) - 1); + mask = GENMASK(ce_info->width - 1 + shift_width, shift_width); src_byte = *from; - src_byte &= mask; - - /* shift to correct alignment */ - mask <<= shift_width; src_byte <<= shift_width; + src_byte &= mask; /* get the current bits from the target bit string */ dest = dest_ctx + (ce_info->lsb / 8); @@ -4419,17 +4416,14 @@ static void ice_pack_ctx_word(u8 *src_ctx, u8 *dest_ctx, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - mask = BIT(ce_info->width) - 1; + mask = GENMASK(ce_info->width - 1 + shift_width, shift_width); /* don't swizzle the bits until after the mask because the mask bits * will be in a different bit position on big endian machines */ src_word = *(u16 *)from; - src_word &= mask; - - /* shift to correct alignment */ - mask <<= shift_width; src_word <<= shift_width; + src_word &= mask; /* get the current bits from the target bit string */ dest = dest_ctx + (ce_info->lsb / 8); @@ -4462,25 +4456,14 @@ static void ice_pack_ctx_dword(u8 *src_ctx, u8 *dest_ctx, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - - /* if the field width is exactly 32 on an x86 machine, then the shift - * operation will not work because the SHL instructions count is masked - * to 5 bits so the shift will do nothing - */ - if (ce_info->width < 32) - mask = BIT(ce_info->width) - 1; - else - mask = (u32)~0; + mask = GENMASK(ce_info->width - 1 + shift_width, shift_width); /* don't swizzle the bits until after the mask because the mask bits * will be in a different bit position on big endian machines */ src_dword = *(u32 *)from; - src_dword &= mask; - - /* shift to correct alignment */ - mask <<= shift_width; src_dword <<= shift_width; + src_dword &= mask; /* get the current bits from the target bit string */ dest = dest_ctx + (ce_info->lsb / 8); @@ -4513,25 +4496,14 @@ static void ice_pack_ctx_qword(u8 *src_ctx, u8 *dest_ctx, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - - /* if the field width is exactly 64 on an x86 machine, then the shift - * operation will not work because the SHL instructions count is masked - * to 6 bits so the shift will do nothing - */ - if (ce_info->width < 64) - mask = BIT_ULL(ce_info->width) - 1; - else - mask = (u64)~0; + mask = GENMASK_ULL(ce_info->width - 1 + shift_width, shift_width); /* don't swizzle the bits until after the mask because the mask bits * will be in a different bit position on big endian machines */ src_qword = *(u64 *)from; - src_qword &= mask; - - /* shift to correct alignment */ - mask <<= shift_width; src_qword <<= shift_width; + src_qword &= mask; /* get the current bits from the target bit string */ dest = dest_ctx + (ce_info->lsb / 8); From 979c2c049fbea107ce9f8d31f3ba9dba83ddb0a2 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 26 Feb 2024 16:14:56 -0800 Subject: [PATCH 1819/2255] ice: cleanup line splitting for context set functions The indentation for ice_set_ctx and ice_write_rxq_ctx breaks the function name after the return type. This style of breaking is used a lot throughout the ice driver, even in cases where its not actually helpful for readability. We no longer prefer this style of line splitting in the driver, and new code is avoiding it. Normally, I would leave this alone unless the actual function contents or description needed updating. However, a future change is going to add inverse functions for converting packed context to unpacked context structures. To keep this code uniform with the existing set functions, fix up the style to the modern format of keeping the type on the same line. Signed-off-by: Jacob Keller Reviewed-by: Przemek Kitszel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 12 +++++------- drivers/net/ethernet/intel/ice/ice_common.h | 10 ++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index e9e4a8ef7904..7d9315ffae57 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1399,9 +1399,8 @@ static const struct ice_ctx_ele ice_rlan_ctx_info[] = { * it to HW register space and enables the hardware to prefetch descriptors * instead of only fetching them on demand */ -int -ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, - u32 rxq_index) +int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, + u32 rxq_index) { u8 ctx_buf[ICE_RXQ_CTX_SZ] = { 0 }; @@ -4522,11 +4521,10 @@ static void ice_pack_ctx_qword(u8 *src_ctx, u8 *dest_ctx, * @hw: pointer to the hardware structure * @src_ctx: pointer to a generic non-packed context structure * @dest_ctx: pointer to memory for the packed structure - * @ce_info: a description of the structure to be transformed + * @ce_info: List of Rx context elements */ -int -ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx, - const struct ice_ctx_ele *ce_info) +int ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx, + const struct ice_ctx_ele *ce_info) { int f; diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 32fd10de620c..ffb22c7ce28b 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -53,9 +53,8 @@ int ice_get_caps(struct ice_hw *hw); void ice_set_safe_mode_caps(struct ice_hw *hw); -int -ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, - u32 rxq_index); +int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, + u32 rxq_index); int ice_aq_get_rss_lut(struct ice_hw *hw, struct ice_aq_get_set_rss_lut_params *get_params); @@ -72,9 +71,8 @@ bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq); int ice_aq_q_shutdown(struct ice_hw *hw, bool unloading); void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode); extern const struct ice_ctx_ele ice_tlan_ctx_info[]; -int -ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx, - const struct ice_ctx_ele *ce_info); +int ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx, + const struct ice_ctx_ele *ce_info); extern struct mutex ice_global_cfg_lock_sw; From d5926e01e3739542bb047b77f850d7f641eaa7bc Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Fri, 23 Feb 2024 17:06:27 +0100 Subject: [PATCH 1820/2255] ice: do not disable Tx queues twice in ice_down() ice_down() clears QINT_TQCTL_CAUSE_ENA_M bit twice, which is not necessary. First clearing happens in ice_vsi_dis_irq() and second in ice_vsi_stop_tx_ring() - remove the first one. While at it, make ice_vsi_dis_irq() static as ice_down() is the only current caller of it. Signed-off-by: Maciej Fijalkowski Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 55 ----------------------- drivers/net/ethernet/intel/ice/ice_lib.h | 2 - drivers/net/ethernet/intel/ice/ice_main.c | 44 ++++++++++++++++++ 3 files changed, 44 insertions(+), 57 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 59e8a2572985..48e4c33a3550 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2719,61 +2719,6 @@ void ice_dis_vsi(struct ice_vsi *vsi, bool locked) } } -/** - * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI - * @vsi: the VSI being un-configured - */ -void ice_vsi_dis_irq(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - u32 val; - int i; - - /* disable interrupt causation from each queue */ - if (vsi->tx_rings) { - ice_for_each_txq(vsi, i) { - if (vsi->tx_rings[i]) { - u16 reg; - - reg = vsi->tx_rings[i]->reg_idx; - val = rd32(hw, QINT_TQCTL(reg)); - val &= ~QINT_TQCTL_CAUSE_ENA_M; - wr32(hw, QINT_TQCTL(reg), val); - } - } - } - - if (vsi->rx_rings) { - ice_for_each_rxq(vsi, i) { - if (vsi->rx_rings[i]) { - u16 reg; - - reg = vsi->rx_rings[i]->reg_idx; - val = rd32(hw, QINT_RQCTL(reg)); - val &= ~QINT_RQCTL_CAUSE_ENA_M; - wr32(hw, QINT_RQCTL(reg), val); - } - } - } - - /* disable each interrupt */ - ice_for_each_q_vector(vsi, i) { - if (!vsi->q_vectors[i]) - continue; - wr32(hw, GLINT_DYN_CTL(vsi->q_vectors[i]->reg_idx), 0); - } - - ice_flush(hw); - - /* don't call synchronize_irq() for VF's from the host */ - if (vsi->type == ICE_VSI_VF) - return; - - ice_for_each_q_vector(vsi, i) - synchronize_irq(vsi->q_vectors[i]->irq.virq); -} - /** * __ice_queue_set_napi - Set the napi instance for the queue * @dev: device to which NAPI and queue belong diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index b5a1ed7cc4b1..9cd23afe5f15 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -110,8 +110,6 @@ void ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio, bool ena_ts); -void ice_vsi_dis_irq(struct ice_vsi *vsi); - void ice_vsi_free_irq(struct ice_vsi *vsi); void ice_vsi_free_rx_rings(struct ice_vsi *vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 8f73ba77e835..062b4ea8e2c3 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -7001,6 +7001,50 @@ static void ice_napi_disable_all(struct ice_vsi *vsi) } } +/** + * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI + * @vsi: the VSI being un-configured + */ +static void ice_vsi_dis_irq(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + u32 val; + int i; + + /* disable interrupt causation from each Rx queue; Tx queues are + * handled in ice_vsi_stop_tx_ring() + */ + if (vsi->rx_rings) { + ice_for_each_rxq(vsi, i) { + if (vsi->rx_rings[i]) { + u16 reg; + + reg = vsi->rx_rings[i]->reg_idx; + val = rd32(hw, QINT_RQCTL(reg)); + val &= ~QINT_RQCTL_CAUSE_ENA_M; + wr32(hw, QINT_RQCTL(reg), val); + } + } + } + + /* disable each interrupt */ + ice_for_each_q_vector(vsi, i) { + if (!vsi->q_vectors[i]) + continue; + wr32(hw, GLINT_DYN_CTL(vsi->q_vectors[i]->reg_idx), 0); + } + + ice_flush(hw); + + /* don't call synchronize_irq() for VF's from the host */ + if (vsi->type == ICE_VSI_VF) + return; + + ice_for_each_q_vector(vsi, i) + synchronize_irq(vsi->q_vectors[i]->irq.virq); +} + /** * ice_down - Shutdown the connection * @vsi: The VSI being stopped From 90f821d72e112d5e4e4214a3704935283cc53375 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Fri, 23 Feb 2024 17:06:28 +0100 Subject: [PATCH 1821/2255] ice: avoid unnecessary devm_ usage 1. pcaps are free'd right after AQ routines are done, no need for devm_'s 2. a test frame for loopback test in ethtool -t is destroyed at the end of the test so we don't need devm_ here either. Signed-off-by: Maciej Fijalkowski Reviewed-by: Przemek Kitszel Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 34 +++++++------------- drivers/net/ethernet/intel/ice/ice_ethtool.c | 10 ++---- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 7d9315ffae57..4d8111aeb0ff 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1002,9 +1002,9 @@ static void ice_get_itr_intrl_gran(struct ice_hw *hw) */ int ice_init_hw(struct ice_hw *hw) { - struct ice_aqc_get_phy_caps_data *pcaps; + struct ice_aqc_get_phy_caps_data *pcaps __free(kfree); + void *mac_buf __free(kfree); u16 mac_buf_len; - void *mac_buf; int status; /* Set MAC type based on DeviceID */ @@ -1082,7 +1082,7 @@ int ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_sched; - pcaps = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*pcaps), GFP_KERNEL); + pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); if (!pcaps) { status = -ENOMEM; goto err_unroll_sched; @@ -1092,7 +1092,6 @@ int ice_init_hw(struct ice_hw *hw) status = ice_aq_get_phy_caps(hw->port_info, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, pcaps, NULL); - devm_kfree(ice_hw_to_dev(hw), pcaps); if (status) dev_warn(ice_hw_to_dev(hw), "Get PHY capabilities failed status = %d, continuing anyway\n", status); @@ -1119,18 +1118,15 @@ int ice_init_hw(struct ice_hw *hw) /* Get MAC information */ /* A single port can report up to two (LAN and WoL) addresses */ - mac_buf = devm_kcalloc(ice_hw_to_dev(hw), 2, - sizeof(struct ice_aqc_manage_mac_read_resp), - GFP_KERNEL); - mac_buf_len = 2 * sizeof(struct ice_aqc_manage_mac_read_resp); - + mac_buf = kcalloc(2, sizeof(struct ice_aqc_manage_mac_read_resp), + GFP_KERNEL); if (!mac_buf) { status = -ENOMEM; goto err_unroll_fltr_mgmt_struct; } + mac_buf_len = 2 * sizeof(struct ice_aqc_manage_mac_read_resp); status = ice_aq_manage_mac_read(hw, mac_buf, mac_buf_len, NULL); - devm_kfree(ice_hw_to_dev(hw), mac_buf); if (status) goto err_unroll_fltr_mgmt_struct; @@ -3276,19 +3272,14 @@ int ice_update_link_info(struct ice_port_info *pi) return status; if (li->link_info & ICE_AQ_MEDIA_AVAILABLE) { - struct ice_aqc_get_phy_caps_data *pcaps; - struct ice_hw *hw; + struct ice_aqc_get_phy_caps_data *pcaps __free(kfree); - hw = pi->hw; - pcaps = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*pcaps), - GFP_KERNEL); + pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); if (!pcaps) return -ENOMEM; status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, pcaps, NULL); - - devm_kfree(ice_hw_to_dev(hw), pcaps); } return status; @@ -3429,8 +3420,8 @@ ice_cfg_phy_fc(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg, int ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) { + struct ice_aqc_get_phy_caps_data *pcaps __free(kfree); struct ice_aqc_set_phy_cfg_data cfg = { 0 }; - struct ice_aqc_get_phy_caps_data *pcaps; struct ice_hw *hw; int status; @@ -3440,7 +3431,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) *aq_failures = 0; hw = pi->hw; - pcaps = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*pcaps), GFP_KERNEL); + pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); if (!pcaps) return -ENOMEM; @@ -3492,7 +3483,6 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) } out: - devm_kfree(ice_hw_to_dev(hw), pcaps); return status; } @@ -3571,7 +3561,7 @@ int ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec) { - struct ice_aqc_get_phy_caps_data *pcaps; + struct ice_aqc_get_phy_caps_data *pcaps __free(kfree); struct ice_hw *hw; int status; @@ -3640,8 +3630,6 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg, } out: - kfree(pcaps); - return status; } diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 3cc364a4d682..bb912155676e 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -802,7 +802,7 @@ static int ice_lbtest_create_frame(struct ice_pf *pf, u8 **ret_data, u16 size) if (!pf) return -EINVAL; - data = devm_kzalloc(ice_pf_to_dev(pf), size, GFP_KERNEL); + data = kzalloc(size, GFP_KERNEL); if (!data) return -ENOMEM; @@ -945,11 +945,9 @@ static u64 ice_loopback_test(struct net_device *netdev) int num_frames, valid_frames; struct ice_tx_ring *tx_ring; struct ice_rx_ring *rx_ring; - struct device *dev; - u8 *tx_frame; + u8 *tx_frame __free(kfree); int i; - dev = ice_pf_to_dev(pf); netdev_info(netdev, "loopback test\n"); test_vsi = ice_lb_vsi_setup(pf, pf->hw.port_info); @@ -994,7 +992,7 @@ static u64 ice_loopback_test(struct net_device *netdev) for (i = 0; i < num_frames; i++) { if (ice_diag_send(tx_ring, tx_frame, ICE_LB_FRAME_SIZE)) { ret = 8; - goto lbtest_free_frame; + goto remove_mac_filters; } } @@ -1004,8 +1002,6 @@ static u64 ice_loopback_test(struct net_device *netdev) else if (valid_frames != num_frames) ret = 10; -lbtest_free_frame: - devm_kfree(dev, tx_frame); remove_mac_filters: if (ice_fltr_remove_mac(test_vsi, broadcast, ICE_FWD_TO_VSI)) netdev_err(netdev, "Could not remove MAC filter for the test VSI\n"); From 187e2af05abe6bf80581490239c449456627d17a Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Sat, 24 Feb 2024 14:34:17 -0800 Subject: [PATCH 1822/2255] bpf: struct_ops supports more than one page for trampolines. The BPF struct_ops previously only allowed one page of trampolines. Each function pointer of a struct_ops is implemented by a struct_ops bpf program. Each struct_ops bpf program requires a trampoline. The following selftest patch shows each page can hold a little more than 20 trampolines. While one page is more than enough for the tcp-cc usecase, the sched_ext use case shows that one page is not always enough and hits the one page limit. This patch overcomes the one page limit by allocating another page when needed and it is limited to a total of MAX_IMAGE_PAGES (8) pages which is more than enough for reasonable usages. The variable st_map->image has been changed to st_map->image_pages, and its type has been changed to an array of pointers to pages. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240224223418.526631-3-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- include/linux/bpf.h | 4 +- kernel/bpf/bpf_struct_ops.c | 130 ++++++++++++++++++++++----------- net/bpf/bpf_dummy_struct_ops.c | 12 +-- 3 files changed, 96 insertions(+), 50 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 814dc913a968..785660810e6a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1763,7 +1763,9 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, struct bpf_tramp_link *link, const struct btf_func_model *model, void *stub_func, - void *image, void *image_end); + void **image, u32 *image_off, + bool allow_alloc); +void bpf_struct_ops_image_free(void *image); static inline bool bpf_try_module_get(const void *data, struct module *owner) { if (owner == BPF_MODULE_OWNER) diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 07e554c191d1..43356faaa057 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -18,6 +18,8 @@ struct bpf_struct_ops_value { char data[] ____cacheline_aligned_in_smp; }; +#define MAX_TRAMP_IMAGE_PAGES 8 + struct bpf_struct_ops_map { struct bpf_map map; struct rcu_head rcu; @@ -30,12 +32,11 @@ struct bpf_struct_ops_map { */ struct bpf_link **links; u32 links_cnt; - /* image is a page that has all the trampolines + u32 image_pages_cnt; + /* image_pages is an array of pages that has all the trampolines * that stores the func args before calling the bpf_prog. - * A PAGE_SIZE "image" is enough to store all trampoline for - * "links[]". */ - void *image; + void *image_pages[MAX_TRAMP_IMAGE_PAGES]; /* The owner moduler's btf. */ struct btf *btf; /* uvalue->data stores the kernel struct @@ -116,6 +117,31 @@ static bool is_valid_value_type(struct btf *btf, s32 value_id, return true; } +static void *bpf_struct_ops_image_alloc(void) +{ + void *image; + int err; + + err = bpf_jit_charge_modmem(PAGE_SIZE); + if (err) + return ERR_PTR(err); + image = arch_alloc_bpf_trampoline(PAGE_SIZE); + if (!image) { + bpf_jit_uncharge_modmem(PAGE_SIZE); + return ERR_PTR(-ENOMEM); + } + + return image; +} + +void bpf_struct_ops_image_free(void *image) +{ + if (image) { + arch_free_bpf_trampoline(image, PAGE_SIZE); + bpf_jit_uncharge_modmem(PAGE_SIZE); + } +} + #define MAYBE_NULL_SUFFIX "__nullable" #define MAX_STUB_NAME 128 @@ -461,6 +487,15 @@ static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map) } } +static void bpf_struct_ops_map_free_image(struct bpf_struct_ops_map *st_map) +{ + int i; + + for (i = 0; i < st_map->image_pages_cnt; i++) + bpf_struct_ops_image_free(st_map->image_pages[i]); + st_map->image_pages_cnt = 0; +} + static int check_zero_holes(const struct btf *btf, const struct btf_type *t, void *data) { const struct btf_member *member; @@ -506,9 +541,12 @@ const struct bpf_link_ops bpf_struct_ops_link_lops = { int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, struct bpf_tramp_link *link, const struct btf_func_model *model, - void *stub_func, void *image, void *image_end) + void *stub_func, + void **_image, u32 *_image_off, + bool allow_alloc) { - u32 flags = BPF_TRAMP_F_INDIRECT; + u32 image_off = *_image_off, flags = BPF_TRAMP_F_INDIRECT; + void *image = *_image; int size; tlinks[BPF_TRAMP_FENTRY].links[0] = link; @@ -518,12 +556,32 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, flags |= BPF_TRAMP_F_RET_FENTRY_RET; size = arch_bpf_trampoline_size(model, flags, tlinks, NULL); - if (size < 0) - return size; - if (size > (unsigned long)image_end - (unsigned long)image) - return -E2BIG; - return arch_prepare_bpf_trampoline(NULL, image, image_end, + if (size <= 0) + return size ? : -EFAULT; + + /* Allocate image buffer if necessary */ + if (!image || size > PAGE_SIZE - image_off) { + if (!allow_alloc) + return -E2BIG; + + image = bpf_struct_ops_image_alloc(); + if (IS_ERR(image)) + return PTR_ERR(image); + image_off = 0; + } + + size = arch_prepare_bpf_trampoline(NULL, image + image_off, + image + PAGE_SIZE, model, flags, tlinks, stub_func); + if (size <= 0) { + if (image != *_image) + bpf_struct_ops_image_free(image); + return size ? : -EFAULT; + } + + *_image = image; + *_image_off = image_off + size; + return 0; } static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, @@ -539,8 +597,8 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, struct bpf_tramp_links *tlinks; void *udata, *kdata; int prog_fd, err; - void *image, *image_end; - u32 i; + u32 i, trampoline_start, image_off = 0; + void *cur_image = NULL, *image = NULL; if (flags) return -EINVAL; @@ -578,8 +636,6 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, udata = &uvalue->data; kdata = &kvalue->data; - image = st_map->image; - image_end = st_map->image + PAGE_SIZE; module_type = btf_type_by_id(btf_vmlinux, st_ops_ids[IDX_MODULE_ID]); for_each_member(i, t, member) { @@ -658,15 +714,24 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, &bpf_struct_ops_link_lops, prog); st_map->links[i] = &link->link; + trampoline_start = image_off; err = bpf_struct_ops_prepare_trampoline(tlinks, link, - &st_ops->func_models[i], - *(void **)(st_ops->cfi_stubs + moff), - image, image_end); + &st_ops->func_models[i], + *(void **)(st_ops->cfi_stubs + moff), + &image, &image_off, + st_map->image_pages_cnt < MAX_TRAMP_IMAGE_PAGES); + if (err) + goto reset_unlock; + + if (cur_image != image) { + st_map->image_pages[st_map->image_pages_cnt++] = image; + cur_image = image; + trampoline_start = 0; + } if (err < 0) goto reset_unlock; - *(void **)(kdata + moff) = image + cfi_get_offset(); - image += err; + *(void **)(kdata + moff) = image + trampoline_start + cfi_get_offset(); /* put prog_id to udata */ *(unsigned long *)(udata + moff) = prog->aux->id; @@ -677,10 +742,11 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, if (err) goto reset_unlock; } + for (i = 0; i < st_map->image_pages_cnt; i++) + arch_protect_bpf_trampoline(st_map->image_pages[i], PAGE_SIZE); if (st_map->map.map_flags & BPF_F_LINK) { err = 0; - arch_protect_bpf_trampoline(st_map->image, PAGE_SIZE); /* Let bpf_link handle registration & unregistration. * * Pair with smp_load_acquire() during lookup_elem(). @@ -689,7 +755,6 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, goto unlock; } - arch_protect_bpf_trampoline(st_map->image, PAGE_SIZE); err = st_ops->reg(kdata); if (likely(!err)) { /* This refcnt increment on the map here after @@ -712,9 +777,9 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, * there was a race in registering the struct_ops (under the same name) to * a sub-system through different struct_ops's maps. */ - arch_unprotect_bpf_trampoline(st_map->image, PAGE_SIZE); reset_unlock: + bpf_struct_ops_map_free_image(st_map); bpf_struct_ops_map_put_progs(st_map); memset(uvalue, 0, map->value_size); memset(kvalue, 0, map->value_size); @@ -781,10 +846,7 @@ static void __bpf_struct_ops_map_free(struct bpf_map *map) if (st_map->links) bpf_struct_ops_map_put_progs(st_map); bpf_map_area_free(st_map->links); - if (st_map->image) { - arch_free_bpf_trampoline(st_map->image, PAGE_SIZE); - bpf_jit_uncharge_modmem(PAGE_SIZE); - } + bpf_struct_ops_map_free_image(st_map); bpf_map_area_free(st_map->uvalue); bpf_map_area_free(st_map); } @@ -894,20 +956,6 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) st_map->st_ops_desc = st_ops_desc; map = &st_map->map; - ret = bpf_jit_charge_modmem(PAGE_SIZE); - if (ret) - goto errout_free; - - st_map->image = arch_alloc_bpf_trampoline(PAGE_SIZE); - if (!st_map->image) { - /* __bpf_struct_ops_map_free() uses st_map->image as flag - * for "charged or not". In this case, we need to unchange - * here. - */ - bpf_jit_uncharge_modmem(PAGE_SIZE); - ret = -ENOMEM; - goto errout_free; - } st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE); st_map->links_cnt = btf_type_vlen(t); st_map->links = diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c index 02de71719aed..1b5f812e6972 100644 --- a/net/bpf/bpf_dummy_struct_ops.c +++ b/net/bpf/bpf_dummy_struct_ops.c @@ -91,6 +91,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, struct bpf_tramp_link *link = NULL; void *image = NULL; unsigned int op_idx; + u32 image_off = 0; int prog_ret; s32 type_id; int err; @@ -114,12 +115,6 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, goto out; } - image = arch_alloc_bpf_trampoline(PAGE_SIZE); - if (!image) { - err = -ENOMEM; - goto out; - } - link = kzalloc(sizeof(*link), GFP_USER); if (!link) { err = -ENOMEM; @@ -133,7 +128,8 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, err = bpf_struct_ops_prepare_trampoline(tlinks, link, &st_ops->func_models[op_idx], &dummy_ops_test_ret_function, - image, image + PAGE_SIZE); + &image, &image_off, + true); if (err < 0) goto out; @@ -147,7 +143,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, err = -EFAULT; out: kfree(args); - arch_free_bpf_trampoline(image, PAGE_SIZE); + bpf_struct_ops_image_free(image); if (link) bpf_link_put(&link->link); kfree(tlinks); From 93bc28d859e57f1a654d3b63600d14c85c5630a4 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Sat, 24 Feb 2024 14:34:18 -0800 Subject: [PATCH 1823/2255] selftests/bpf: Test struct_ops maps with a large number of struct_ops program. Create and load a struct_ops map with a large number of struct_ops programs to generate trampolines taking a size over multiple pages. The map includes 40 programs. Their trampolines takes 6.6k+, more than 1.5 pages, on x86. Signed-off-by: Kui-Feng Lee Link: https://lore.kernel.org/r/20240224223418.526631-4-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau --- .../selftests/bpf/bpf_testmod/bpf_testmod.h | 44 ++++++++ .../prog_tests/test_struct_ops_multi_pages.c | 30 ++++++ .../bpf/progs/struct_ops_multi_pages.c | 102 ++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_multi_pages.c create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_multi_pages.c diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h index 971458acfac3..622d24e29d35 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h @@ -43,6 +43,50 @@ struct bpf_testmod_ops { int b; } unsupported; int data; + + /* The following pointers are used to test the maps having multiple + * pages of trampolines. + */ + int (*tramp_1)(int value); + int (*tramp_2)(int value); + int (*tramp_3)(int value); + int (*tramp_4)(int value); + int (*tramp_5)(int value); + int (*tramp_6)(int value); + int (*tramp_7)(int value); + int (*tramp_8)(int value); + int (*tramp_9)(int value); + int (*tramp_10)(int value); + int (*tramp_11)(int value); + int (*tramp_12)(int value); + int (*tramp_13)(int value); + int (*tramp_14)(int value); + int (*tramp_15)(int value); + int (*tramp_16)(int value); + int (*tramp_17)(int value); + int (*tramp_18)(int value); + int (*tramp_19)(int value); + int (*tramp_20)(int value); + int (*tramp_21)(int value); + int (*tramp_22)(int value); + int (*tramp_23)(int value); + int (*tramp_24)(int value); + int (*tramp_25)(int value); + int (*tramp_26)(int value); + int (*tramp_27)(int value); + int (*tramp_28)(int value); + int (*tramp_29)(int value); + int (*tramp_30)(int value); + int (*tramp_31)(int value); + int (*tramp_32)(int value); + int (*tramp_33)(int value); + int (*tramp_34)(int value); + int (*tramp_35)(int value); + int (*tramp_36)(int value); + int (*tramp_37)(int value); + int (*tramp_38)(int value); + int (*tramp_39)(int value); + int (*tramp_40)(int value); }; #endif /* _BPF_TESTMOD_H */ diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_multi_pages.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_multi_pages.c new file mode 100644 index 000000000000..645d32b5160c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_multi_pages.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include + +#include "struct_ops_multi_pages.skel.h" + +static void do_struct_ops_multi_pages(void) +{ + struct struct_ops_multi_pages *skel; + struct bpf_link *link; + + /* The size of all trampolines of skel->maps.multi_pages should be + * over 1 page (at least for x86). + */ + skel = struct_ops_multi_pages__open_and_load(); + if (!ASSERT_OK_PTR(skel, "struct_ops_multi_pages_open_and_load")) + return; + + link = bpf_map__attach_struct_ops(skel->maps.multi_pages); + ASSERT_OK_PTR(link, "attach_multi_pages"); + + bpf_link__destroy(link); + struct_ops_multi_pages__destroy(skel); +} + +void test_struct_ops_multi_pages(void) +{ + if (test__start_subtest("multi_pages")) + do_struct_ops_multi_pages(); +} diff --git a/tools/testing/selftests/bpf/progs/struct_ops_multi_pages.c b/tools/testing/selftests/bpf/progs/struct_ops_multi_pages.c new file mode 100644 index 000000000000..9efcc6e4d356 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/struct_ops_multi_pages.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include +#include "../bpf_testmod/bpf_testmod.h" + +char _license[] SEC("license") = "GPL"; + +#define TRAMP(x) \ + SEC("struct_ops/tramp_" #x) \ + int BPF_PROG(tramp_ ## x, int a) \ + { \ + return a; \ + } + +TRAMP(1) +TRAMP(2) +TRAMP(3) +TRAMP(4) +TRAMP(5) +TRAMP(6) +TRAMP(7) +TRAMP(8) +TRAMP(9) +TRAMP(10) +TRAMP(11) +TRAMP(12) +TRAMP(13) +TRAMP(14) +TRAMP(15) +TRAMP(16) +TRAMP(17) +TRAMP(18) +TRAMP(19) +TRAMP(20) +TRAMP(21) +TRAMP(22) +TRAMP(23) +TRAMP(24) +TRAMP(25) +TRAMP(26) +TRAMP(27) +TRAMP(28) +TRAMP(29) +TRAMP(30) +TRAMP(31) +TRAMP(32) +TRAMP(33) +TRAMP(34) +TRAMP(35) +TRAMP(36) +TRAMP(37) +TRAMP(38) +TRAMP(39) +TRAMP(40) + +#define F_TRAMP(x) .tramp_ ## x = (void *)tramp_ ## x + +SEC(".struct_ops.link") +struct bpf_testmod_ops multi_pages = { + F_TRAMP(1), + F_TRAMP(2), + F_TRAMP(3), + F_TRAMP(4), + F_TRAMP(5), + F_TRAMP(6), + F_TRAMP(7), + F_TRAMP(8), + F_TRAMP(9), + F_TRAMP(10), + F_TRAMP(11), + F_TRAMP(12), + F_TRAMP(13), + F_TRAMP(14), + F_TRAMP(15), + F_TRAMP(16), + F_TRAMP(17), + F_TRAMP(18), + F_TRAMP(19), + F_TRAMP(20), + F_TRAMP(21), + F_TRAMP(22), + F_TRAMP(23), + F_TRAMP(24), + F_TRAMP(25), + F_TRAMP(26), + F_TRAMP(27), + F_TRAMP(28), + F_TRAMP(29), + F_TRAMP(30), + F_TRAMP(31), + F_TRAMP(32), + F_TRAMP(33), + F_TRAMP(34), + F_TRAMP(35), + F_TRAMP(36), + F_TRAMP(37), + F_TRAMP(38), + F_TRAMP(39), + F_TRAMP(40), +}; From fb0f02308126736c015afc0cac3c0e8712443299 Mon Sep 17 00:00:00 2001 From: Prabhav Kumar Vaish Date: Wed, 28 Feb 2024 17:37:01 +0530 Subject: [PATCH 1824/2255] selftests: net: Correct couple of spelling mistakes Changes : - "excercise" is corrected to "exercise" in drivers/net/mlxsw/spectrum-2/tc_flower.sh - "mutliple" is corrected to "multiple" in drivers/net/netdevsim/ethtool-fec.sh Signed-off-by: Prabhav Kumar Vaish Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240228120701.422264-1-pvkumar5749404@gmail.com Signed-off-by: Jakub Kicinski --- .../testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh | 2 +- tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh index 616d3581419c..31252bc8775e 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh @@ -869,7 +869,7 @@ bloom_simple_test() bloom_complex_test() { # Bloom filter index computation is affected from region ID, eRP - # ID and from the region key size. In order to excercise those parts + # ID and from the region key size. In order to exercise those parts # of the Bloom filter code, use a series of regions, each with a # different key size and send packet that should hit all of them. local index diff --git a/tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh b/tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh index 7d7829f57550..6c52ce1b0450 100755 --- a/tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh +++ b/tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh @@ -49,7 +49,7 @@ for o in llrs rs; do Active FEC encoding: ${o^^}" done -# Test mutliple bits +# Test multiple bits $ETHTOOL --set-fec $NSIM_NETDEV encoding rs llrs check $? s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) From dcfaf1f758ee74cf059acf6e33faf83f988fad4a Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Thu, 29 Feb 2024 11:38:25 -0300 Subject: [PATCH 1825/2255] selftests/tc-testing: require an up to date iproute2 for blockcast tests Add the dependsOn test check for all the mirred blockcast tests. It will prevent the issue reported by LKFT which happens when an older iproute2 is used to run the current tdc. Tests are skipped if the dependsOn check fails. Reported-by: Linux Kernel Functional Testing Signed-off-by: Pedro Tammela Link: https://lore.kernel.org/r/20240229143825.1373550-1-pctammela@mojatatu.com Signed-off-by: Jakub Kicinski --- .../selftests/tc-testing/tc-tests/actions/mirred.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json index 795cf1ce8af0..b73bd255ea36 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json @@ -657,6 +657,7 @@ "actions", "mirred" ], + "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", "plugins": { "requires": "nsPlugin" }, @@ -711,6 +712,7 @@ "actions", "mirred" ], + "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", "plugins": { "requires": "nsPlugin" }, @@ -765,6 +767,7 @@ "actions", "mirred" ], + "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", "plugins": { "requires": "nsPlugin" }, @@ -819,6 +822,7 @@ "actions", "mirred" ], + "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", "plugins": { "requires": "nsPlugin" }, @@ -873,6 +877,7 @@ "actions", "mirred" ], + "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", "plugins": { "requires": "nsPlugin" }, @@ -937,6 +942,7 @@ "actions", "mirred" ], + "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", "plugins": { "requires": "nsPlugin" }, @@ -995,6 +1001,7 @@ "actions", "mirred" ], + "dependsOn": "$TC actions add action mirred help 2>&1 | grep -q blockid", "plugins": { "requires": "nsPlugin" }, From 345a6e2631c1267221b684e110bba03e4c26ece0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 1 Mar 2024 17:19:45 +0000 Subject: [PATCH 1826/2255] tcp: align tcp_sock_write_rx group Stephen Rothwell and kernel test robot reported that some arches (parisc, hexagon) and/or compilers would not like blamed commit. Lets make sure tcp_sock_write_rx group does not start with a hole. While we are at it, correct tcp_sock_write_tx CACHELINE_ASSERT_GROUP_SIZE() since after the blamed commit, we went to 105 bytes. Fixes: 99123622050f ("tcp: remove some holes in struct tcp_sock") Reported-by: Stephen Rothwell Reported-by: kernel test robot Link: https://lore.kernel.org/netdev/20240301121108.5d39e4f9@canb.auug.org.au/ Closes: https://lore.kernel.org/oe-kbuild-all/202403011451.csPYOS3C-lkp@intel.com/ Signed-off-by: Eric Dumazet Reviewed-by: Simon Horman Tested-by: Simon Horman # build-tested Link: https://lore.kernel.org/r/20240301171945.2958176-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/linux/tcp.h | 2 +- net/ipv4/tcp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 988a30ef6bfe..55399ee2a57e 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -304,7 +304,7 @@ struct tcp_sock { __cacheline_group_end(tcp_sock_write_txrx); /* RX read-write hotpath cache lines */ - __cacheline_group_begin(tcp_sock_write_rx); + __cacheline_group_begin(tcp_sock_write_rx) __aligned(8); u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived * sum(delta(rcv_nxt)), or how many bytes diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c82dc42f57c6..7e1b848398d0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -4651,7 +4651,7 @@ static void __init tcp_struct_check(void) CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tsorted_sent_queue); CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, highest_sack); CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, ecn_flags); - CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_tx, 113); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_tx, 105); /* TXRX read-write hotpath cache lines */ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, pred_flags); From aa9870f5c7ef44c904d35618b6717b9ef7810760 Mon Sep 17 00:00:00 2001 From: Jon Maxwell Date: Fri, 1 Mar 2024 10:48:02 -0800 Subject: [PATCH 1827/2255] intel: make module parameters readable in sys filesystem Linux users sometimes need an easy way to check current values of module parameters. For example the module may be manually reloaded with different parameters. Make these visible and readable in the /sys filesystem to allow that. But don't make the "debug" module parameter visible as debugging is enabled via ethtool msglvl. Signed-off-by: Jon Maxwell Reviewed-by: Jacob Keller Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20240301184806.2634508-2-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/e100.c | 4 ++-- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index 01f0f12035ca..3fcb8daaa243 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -171,8 +171,8 @@ static int debug = 3; static int eeprom_bad_csum_allow = 0; static int use_io = 0; module_param(debug, int, 0); -module_param(eeprom_bad_csum_allow, int, 0); -module_param(use_io, int, 0); +module_param(eeprom_bad_csum_allow, int, 0444); +module_param(use_io, int, 0444); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums"); MODULE_PARM_DESC(use_io, "Force use of i/o access mode"); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index b35556550503..518298bbdadc 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -202,7 +202,7 @@ static struct notifier_block dca_notifier = { #endif #ifdef CONFIG_PCI_IOV static unsigned int max_vfs; -module_param(max_vfs, uint, 0); +module_param(max_vfs, uint, 0444); MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate per physical function"); #endif /* CONFIG_PCI_IOV */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 1e93edc967ed..595098a4c488 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -153,7 +153,7 @@ MODULE_PARM_DESC(max_vfs, #endif /* CONFIG_PCI_IOV */ static bool allow_unsupported_sfp; -module_param(allow_unsupported_sfp, bool, 0); +module_param(allow_unsupported_sfp, bool, 0444); MODULE_PARM_DESC(allow_unsupported_sfp, "Allow unsupported and untested SFP+ modules on 82599-based adapters"); From 1b43e0d20f2d007ec4c124b0deaa848ff8d61f4a Mon Sep 17 00:00:00 2001 From: Ernesto Castellotti Date: Fri, 1 Mar 2024 10:48:03 -0800 Subject: [PATCH 1828/2255] ixgbe: Add 1000BASE-BX support Added support for 1000BASE-BX, i.e. Gigabit Ethernet over single strand of single-mode fiber. The initialization of a 1000BASE-BX SFP is the same as 1000BASE-SX/LX with the only difference that the Bit Rate Nominal Value must be checked to make sure it is a Gigabit Ethernet transceiver, as described by the SFF-8472 specification. This was tested with the FS.com SFP-GE-BX 1310/1490nm 10km transceiver: $ ethtool -m eth4 Identifier : 0x03 (SFP) Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID) Connector : 0x07 (LC) Transceiver codes : 0x00 0x00 0x00 0x40 0x00 0x00 0x00 0x00 0x00 Transceiver type : Ethernet: BASE-BX10 Encoding : 0x01 (8B/10B) BR, Nominal : 1300MBd Rate identifier : 0x00 (unspecified) Length (SMF,km) : 10km Length (SMF) : 10000m Length (50um) : 0m Length (62.5um) : 0m Length (Copper) : 0m Length (OM3) : 0m Laser wavelength : 1310nm Vendor name : FS Vendor OUI : 64:9d:99 Vendor PN : SFP-GE-BX Vendor rev : Option values : 0x20 0x0a Option : RX_LOS implemented Option : TX_FAULT implemented Option : Power level 3 requirement BR margin, max : 0% BR margin, min : 0% Vendor SN : S2202359108 Date code : 220307 Optical diagnostics support : Yes Laser bias current : 17.650 mA Laser output power : 0.2132 mW / -6.71 dBm Receiver signal average optical power : 0.2740 mW / -5.62 dBm Module temperature : 47.30 degrees C / 117.13 degrees F Module voltage : 3.2576 V Alarm/warning flags implemented : Yes Laser bias current high alarm : Off Laser bias current low alarm : Off Laser bias current high warning : Off Laser bias current low warning : Off Laser output power high alarm : Off Laser output power low alarm : Off Laser output power high warning : Off Laser output power low warning : Off Module temperature high alarm : Off Module temperature low alarm : Off Module temperature high warning : Off Module temperature low warning : Off Module voltage high alarm : Off Module voltage low alarm : Off Module voltage high warning : Off Module voltage low warning : Off Laser rx power high alarm : Off Laser rx power low alarm : Off Laser rx power high warning : Off Laser rx power low warning : Off Laser bias current high alarm threshold : 110.000 mA Laser bias current low alarm threshold : 1.000 mA Laser bias current high warning threshold : 100.000 mA Laser bias current low warning threshold : 1.000 mA Laser output power high alarm threshold : 0.7079 mW / -1.50 dBm Laser output power low alarm threshold : 0.0891 mW / -10.50 dBm Laser output power high warning threshold : 0.6310 mW / -2.00 dBm Laser output power low warning threshold : 0.1000 mW / -10.00 dBm Module temperature high alarm threshold : 90.00 degrees C / 194.00 degrees F Module temperature low alarm threshold : -45.00 degrees C / -49.00 degrees F Module temperature high warning threshold : 85.00 degrees C / 185.00 degrees F Module temperature low warning threshold : -40.00 degrees C / -40.00 degrees F Module voltage high alarm threshold : 3.7950 V Module voltage low alarm threshold : 2.8050 V Module voltage high warning threshold : 3.4650 V Module voltage low warning threshold : 3.1350 V Laser rx power high alarm threshold : 0.7079 mW / -1.50 dBm Laser rx power low alarm threshold : 0.0028 mW / -25.53 dBm Laser rx power high warning threshold : 0.6310 mW / -2.00 dBm Laser rx power low warning threshold : 0.0032 mW / -24.95 dBm Signed-off-by: Ernesto Castellotti Reviewed-by: Przemek Kitszel Tested-by: Sunitha Mekala (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20240301184806.2634508-3-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/intel/ixgbe/ixgbe_82599.c | 4 ++- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 32 ++++++++++++++++--- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h | 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 3 ++ 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index e0c300fe5cee..cdaf087b4e85 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -334,7 +334,9 @@ static int ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) { + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1) { *speed = IXGBE_LINK_SPEED_1GB_FULL; *autoneg = true; return 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 633bac1543dd..6e6e6f1847b6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -349,6 +349,8 @@ static int ixgbe_get_link_ksettings(struct net_device *netdev, case ixgbe_sfp_type_1g_sx_core1: case ixgbe_sfp_type_1g_lx_core0: case ixgbe_sfp_type_1g_lx_core1: + case ixgbe_sfp_type_1g_bx_core0: + case ixgbe_sfp_type_1g_bx_core1: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 75e9453331ed..07eaa3c3f4d3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -1532,6 +1532,7 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; struct ixgbe_adapter *adapter = hw->back; u8 oui_bytes[3] = {0, 0, 0}; + u8 bitrate_nominal = 0; u8 comp_codes_10g = 0; u8 comp_codes_1g = 0; u16 enforce_sfp = 0; @@ -1576,7 +1577,12 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_CABLE_TECHNOLOGY, &cable_tech); + if (status) + goto err_read_i2c_eeprom; + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_BITRATE_NOMINAL, + &bitrate_nominal); if (status) goto err_read_i2c_eeprom; @@ -1659,6 +1665,18 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) else hw->phy.sfp_type = ixgbe_sfp_type_1g_lx_core1; + /* Support only Ethernet 1000BASE-BX10, checking the Bit Rate + * Nominal Value as per SFF-8472 by convention 1.25 Gb/s should + * be rounded up to 0Dh (13 in units of 100 MBd) for 1000BASE-BX + */ + } else if ((comp_codes_1g & IXGBE_SFF_BASEBX10_CAPABLE) && + (bitrate_nominal == 0xD)) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_1g_bx_core0; + else + hw->phy.sfp_type = + ixgbe_sfp_type_1g_bx_core1; } else { hw->phy.sfp_type = ixgbe_sfp_type_unknown; } @@ -1747,7 +1765,9 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) { hw->phy.type = ixgbe_phy_sfp_unsupported; return -EOPNOTSUPP; } @@ -1763,7 +1783,9 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) { /* Make sure we're a supported PHY type */ if (hw->phy.type == ixgbe_phy_sfp_intel) return 0; @@ -1999,12 +2021,14 @@ int ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 || sfp_type == ixgbe_sfp_type_1g_lx_core0 || sfp_type == ixgbe_sfp_type_1g_cu_core0 || - sfp_type == ixgbe_sfp_type_1g_sx_core0) + sfp_type == ixgbe_sfp_type_1g_sx_core0 || + sfp_type == ixgbe_sfp_type_1g_bx_core0) sfp_type = ixgbe_sfp_type_srlr_core0; else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 || sfp_type == ixgbe_sfp_type_1g_lx_core1 || sfp_type == ixgbe_sfp_type_1g_cu_core1 || - sfp_type == ixgbe_sfp_type_1g_sx_core1) + sfp_type == ixgbe_sfp_type_1g_sx_core1 || + sfp_type == ixgbe_sfp_type_1g_bx_core1) sfp_type = ixgbe_sfp_type_srlr_core1; /* Read offset to PHY init contents */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index beedcb7bec0d..14aa2ca51f70 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -17,6 +17,7 @@ #define IXGBE_SFF_1GBE_COMP_CODES 0x6 #define IXGBE_SFF_10GBE_COMP_CODES 0x3 #define IXGBE_SFF_CABLE_TECHNOLOGY 0x8 +#define IXGBE_SFF_BITRATE_NOMINAL 0xC #define IXGBE_SFF_CABLE_SPEC_COMP 0x3C #define IXGBE_SFF_SFF_8472_SWAP 0x5C #define IXGBE_SFF_SFF_8472_COMP 0x5E @@ -39,6 +40,7 @@ #define IXGBE_SFF_1GBASESX_CAPABLE 0x1 #define IXGBE_SFF_1GBASELX_CAPABLE 0x2 #define IXGBE_SFF_1GBASET_CAPABLE 0x8 +#define IXGBE_SFF_BASEBX10_CAPABLE 0x64 #define IXGBE_SFF_10GBASESR_CAPABLE 0x10 #define IXGBE_SFF_10GBASELR_CAPABLE 0x20 #define IXGBE_SFF_SOFT_RS_SELECT_MASK 0x8 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index d44c58130be2..ed440dd0c4f9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3210,6 +3210,9 @@ enum ixgbe_sfp_type { ixgbe_sfp_type_1g_sx_core1 = 12, ixgbe_sfp_type_1g_lx_core0 = 13, ixgbe_sfp_type_1g_lx_core1 = 14, + ixgbe_sfp_type_1g_bx_core0 = 15, + ixgbe_sfp_type_1g_bx_core1 = 16, + ixgbe_sfp_type_not_present = 0xFFFE, ixgbe_sfp_type_unknown = 0xFFFF }; From 30654f0eec65c428863f2312cfe0b7f26ae0fab4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 1 Mar 2024 10:48:04 -0800 Subject: [PATCH 1829/2255] igc: fix LEDS_CLASS dependency When IGC is built-in but LEDS_CLASS is a loadable module, there is a link failure: x86_64-linux-ld: drivers/net/ethernet/intel/igc/igc_leds.o: in function `igc_led_setup': igc_leds.c:(.text+0x75c): undefined reference to `devm_led_classdev_register_ext' Add another dependency that prevents this combination. Fixes: ea578703b03d ("igc: Add support for LEDs on i225/i226") Signed-off-by: Arnd Bergmann Reviewed-by: Kurt Kanzenbach Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20240301184806.2634508-4-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 767358b60507..639fbb12bd35 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -372,6 +372,7 @@ config IGC config IGC_LEDS def_bool LEDS_TRIGGER_NETDEV depends on IGC && LEDS_CLASS + depends on LEDS_CLASS=y || IGC=m help Optional support for controlling the NIC LED's with the netdev LED trigger. From 662200e324daebe6859c1f0f3ea1538b0561425a Mon Sep 17 00:00:00 2001 From: Vitaly Lifshits Date: Fri, 1 Mar 2024 10:48:05 -0800 Subject: [PATCH 1830/2255] e1000e: Minor flow correction in e1000_shutdown function Add curly braces to avoid entering to an if statement where it is not always required in e1000_shutdown function. This improves code readability and might prevent non-deterministic behaviour in the future. Signed-off-by: Vitaly Lifshits Tested-by: Naama Meir Signed-off-by: Tony Nguyen Link: https://lore.kernel.org/r/20240301184806.2634508-5-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/e1000e/netdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index af5d9d97a0d6..cc8c531ec3df 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6688,14 +6688,14 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) if (adapter->hw.phy.type == e1000_phy_igp_3) { e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); } else if (hw->mac.type >= e1000_pch_lpt) { - if (wufc && !(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC))) + if (wufc && !(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC))) { /* ULP does not support wake from unicast, multicast * or broadcast. */ retval = e1000_enable_ulp_lpt_lp(hw, !runtime); - - if (retval) - return retval; + if (retval) + return retval; + } } /* Ensure that the appropriate bits are set in LPI_CTRL From b4a2496c17ed645f8d51061047c9c249b58c74ba Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Fri, 1 Mar 2024 17:29:55 +0800 Subject: [PATCH 1831/2255] net: txgbe: fix GPIO interrupt blocking The register of GPIO interrupt status is masked before MAC IRQ is enabled. This is because of hardware deficiency. So manually clear the interrupt status before using them. Otherwise, GPIO interrupts will never be reported again. There is a workaround for clearing interrupts to set GPIO EOI in txgbe_up_complete(). Fixes: aefd013624a1 ("net: txgbe: use irq_domain for interrupt controller") Signed-off-by: Jiawen Wu Link: https://lore.kernel.org/r/20240301092956.18544-1-jiawenwu@trustnetic.com Signed-off-by: Paolo Abeni --- .../net/ethernet/wangxun/txgbe/txgbe_main.c | 1 + .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 27 +++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_phy.h | 1 + 3 files changed, 29 insertions(+) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index e67a21294158..bd4624d14ca0 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -81,6 +81,7 @@ static void txgbe_up_complete(struct wx *wx) { struct net_device *netdev = wx->netdev; + txgbe_reinit_gpio_intr(wx); wx_control_hw(wx, true); wx_configure_vectors(wx); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index bae0a8ee7014..c112f79b026e 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -489,6 +489,33 @@ irqreturn_t txgbe_gpio_irq_handler(int irq, void *data) return IRQ_HANDLED; } +void txgbe_reinit_gpio_intr(struct wx *wx) +{ + struct txgbe *txgbe = wx->priv; + irq_hw_number_t hwirq; + unsigned long gpioirq; + struct gpio_chip *gc; + unsigned long flags; + + /* for gpio interrupt pending before irq enable */ + gpioirq = rd32(wx, WX_GPIO_INTSTATUS); + + gc = txgbe->gpio; + for_each_set_bit(hwirq, &gpioirq, gc->ngpio) { + int gpio = irq_find_mapping(gc->irq.domain, hwirq); + struct irq_data *d = irq_get_irq_data(gpio); + u32 irq_type = irq_get_trigger_type(gpio); + + txgbe_gpio_irq_ack(d); + + if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + txgbe_toggle_trigger(gc, hwirq); + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); + } + } +} + static int txgbe_gpio_init(struct txgbe *txgbe) { struct gpio_irq_chip *girq; diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h index 9855d44076cb..8a026d804fe2 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h @@ -5,6 +5,7 @@ #define _TXGBE_PHY_H_ irqreturn_t txgbe_gpio_irq_handler(int irq, void *data); +void txgbe_reinit_gpio_intr(struct wx *wx); irqreturn_t txgbe_link_irq_handler(int irq, void *data); int txgbe_init_phy(struct txgbe *txgbe); void txgbe_remove_phy(struct txgbe *txgbe); From 0e71862a20d58b6e8d4c39de1d72c8919c4dccd1 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Fri, 1 Mar 2024 17:29:56 +0800 Subject: [PATCH 1832/2255] net: txgbe: fix to clear interrupt status after handling IRQ GPIO EOI is not set to clear interrupt status after handling the interrupt. It should be done in irq_chip->irq_ack, but this function is not called in handle_nested_irq(). So executing function txgbe_gpio_irq_ack() manually in txgbe_gpio_irq_handler(). Fixes: aefd013624a1 ("net: txgbe: use irq_domain for interrupt controller") Signed-off-by: Jiawen Wu Link: https://lore.kernel.org/r/20240301092956.18544-2-jiawenwu@trustnetic.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index c112f79b026e..93295916b1d2 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -475,8 +475,10 @@ irqreturn_t txgbe_gpio_irq_handler(int irq, void *data) gc = txgbe->gpio; for_each_set_bit(hwirq, &gpioirq, gc->ngpio) { int gpio = irq_find_mapping(gc->irq.domain, hwirq); + struct irq_data *d = irq_get_irq_data(gpio); u32 irq_type = irq_get_trigger_type(gpio); + txgbe_gpio_irq_ack(d); handle_nested_irq(gpio); if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { From 411c5f36805c02c7c412f1ad6bfa4459a1148011 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Wed, 28 Feb 2024 17:30:08 +0800 Subject: [PATCH 1833/2255] mm/page_alloc: modify page_frag_alloc_align() to accept align as an argument napi_alloc_frag_align() and netdev_alloc_frag_align() accept align as an argument, and they are thin wrappers around the __napi_alloc_frag_align() and __netdev_alloc_frag_align() APIs doing the alignment checking and align mask conversion, in order to call page_frag_alloc_align() directly. The intention here is to keep the alignment checking and the alignmask conversion in in-line wrapper to avoid those kind of operations during execution time since it can usually be handled during compile time. We are going to use page_frag_alloc_align() in vhost_net.c, it need the same kind of alignment checking and alignmask conversion, so split up page_frag_alloc_align into an inline wrapper doing the above operation, and add __page_frag_alloc_align() which is passed with the align mask the original function expected as suggested by Alexander. Signed-off-by: Yunsheng Lin CC: Alexander Duyck Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- include/linux/gfp.h | 15 +++++++++++---- mm/page_alloc.c | 8 ++++---- net/core/skbuff.c | 9 ++++++--- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index de292a007138..28aea17fa59b 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -312,14 +312,21 @@ extern void free_pages(unsigned long addr, unsigned int order); struct page_frag_cache; extern void __page_frag_cache_drain(struct page *page, unsigned int count); -extern void *page_frag_alloc_align(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask, - unsigned int align_mask); +void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, + gfp_t gfp_mask, unsigned int align_mask); + +static inline void *page_frag_alloc_align(struct page_frag_cache *nc, + unsigned int fragsz, gfp_t gfp_mask, + unsigned int align) +{ + WARN_ON_ONCE(!is_power_of_2(align)); + return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align); +} static inline void *page_frag_alloc(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask) { - return page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u); + return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u); } extern void page_frag_free(void *addr); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 150d4f23b010..c0f7e67c4250 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4708,9 +4708,9 @@ void __page_frag_cache_drain(struct page *page, unsigned int count) } EXPORT_SYMBOL(__page_frag_cache_drain); -void *page_frag_alloc_align(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask, - unsigned int align_mask) +void *__page_frag_alloc_align(struct page_frag_cache *nc, + unsigned int fragsz, gfp_t gfp_mask, + unsigned int align_mask) { unsigned int size = PAGE_SIZE; struct page *page; @@ -4779,7 +4779,7 @@ refill: return nc->va + offset; } -EXPORT_SYMBOL(page_frag_alloc_align); +EXPORT_SYMBOL(__page_frag_alloc_align); /* * Frees a page fragment allocated out of either a compound or order 0 page. diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1f918e602bc4..43d7fc150acc 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -315,7 +315,8 @@ void *__napi_alloc_frag_align(unsigned int fragsz, unsigned int align_mask) fragsz = SKB_DATA_ALIGN(fragsz); - return page_frag_alloc_align(&nc->page, fragsz, GFP_ATOMIC, align_mask); + return __page_frag_alloc_align(&nc->page, fragsz, GFP_ATOMIC, + align_mask); } EXPORT_SYMBOL(__napi_alloc_frag_align); @@ -327,13 +328,15 @@ void *__netdev_alloc_frag_align(unsigned int fragsz, unsigned int align_mask) if (in_hardirq() || irqs_disabled()) { struct page_frag_cache *nc = this_cpu_ptr(&netdev_alloc_cache); - data = page_frag_alloc_align(nc, fragsz, GFP_ATOMIC, align_mask); + data = __page_frag_alloc_align(nc, fragsz, GFP_ATOMIC, + align_mask); } else { struct napi_alloc_cache *nc; local_bh_disable(); nc = this_cpu_ptr(&napi_alloc_cache); - data = page_frag_alloc_align(&nc->page, fragsz, GFP_ATOMIC, align_mask); + data = __page_frag_alloc_align(&nc->page, fragsz, GFP_ATOMIC, + align_mask); local_bh_enable(); } return data; From 4bc0d63a23957262b01b5848bd5e1739e98bbf36 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Wed, 28 Feb 2024 17:30:09 +0800 Subject: [PATCH 1834/2255] page_frag: unify gfp bits for order 3 page allocation Currently there seems to be three page frag implementations which all try to allocate order 3 page, if that fails, it then fail back to allocate order 0 page, and each of them all allow order 3 page allocation to fail under certain condition by using specific gfp bits. The gfp bits for order 3 page allocation are different between different implementation, __GFP_NOMEMALLOC is or'd to forbid access to emergency reserves memory for __page_frag_cache_refill(), but it is not or'd in other implementions, __GFP_DIRECT_RECLAIM is masked off to avoid direct reclaim in vhost_net_page_frag_refill(), but it is not masked off in __page_frag_cache_refill(). This patch unifies the gfp bits used between different implementions by or'ing __GFP_NOMEMALLOC and masking off __GFP_DIRECT_RECLAIM for order 3 page allocation to avoid possible pressure for mm. Leave the gfp unifying for page frag implementation in sock.c for now as suggested by Paolo Abeni. Signed-off-by: Yunsheng Lin Reviewed-by: Alexander Duyck CC: Alexander Duyck Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- drivers/vhost/net.c | 2 +- mm/page_alloc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index f2ed7167c848..e574e21cc0ca 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -670,7 +670,7 @@ static bool vhost_net_page_frag_refill(struct vhost_net *net, unsigned int sz, /* Avoid direct reclaim but allow kswapd to wake */ pfrag->page = alloc_pages((gfp & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP | __GFP_NOWARN | - __GFP_NORETRY, + __GFP_NORETRY | __GFP_NOMEMALLOC, SKB_FRAG_PAGE_ORDER); if (likely(pfrag->page)) { pfrag->size = PAGE_SIZE << SKB_FRAG_PAGE_ORDER; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c0f7e67c4250..636145c29f70 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4685,8 +4685,8 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, gfp_t gfp = gfp_mask; #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY | - __GFP_NOMEMALLOC; + gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP | + __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC; page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, PAGE_FRAG_CACHE_MAX_ORDER); nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE; From a0727489ac22d6fbd2e390d38a51193bba61da83 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Wed, 28 Feb 2024 17:30:10 +0800 Subject: [PATCH 1835/2255] net: introduce page_frag_cache_drain() When draining a page_frag_cache, most user are doing the similar steps, so introduce an API to avoid code duplication. Signed-off-by: Yunsheng Lin Acked-by: Jason Wang Reviewed-by: Alexander Duyck Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- drivers/net/ethernet/google/gve/gve_main.c | 11 ++--------- drivers/net/ethernet/mediatek/mtk_wed_wo.c | 17 ++--------------- drivers/nvme/host/tcp.c | 7 +------ drivers/nvme/target/tcp.c | 4 +--- include/linux/gfp.h | 1 + mm/page_alloc.c | 10 ++++++++++ 6 files changed, 17 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 7b89b66adb53..166bd827a6d7 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -1276,17 +1276,10 @@ static void gve_unreg_xdp_info(struct gve_priv *priv) static void gve_drain_page_cache(struct gve_priv *priv) { - struct page_frag_cache *nc; int i; - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - nc = &priv->rx[i].page_cache; - if (nc->va) { - __page_frag_cache_drain(virt_to_page(nc->va), - nc->pagecnt_bias); - nc->va = NULL; - } - } + for (i = 0; i < priv->rx_cfg.num_queues; i++) + page_frag_cache_drain(&priv->rx[i].page_cache); } static void gve_qpls_get_curr_alloc_cfg(struct gve_priv *priv, diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c index d58b07e7e123..7063c78bd35f 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c @@ -286,7 +286,6 @@ mtk_wed_wo_queue_free(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) static void mtk_wed_wo_queue_tx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) { - struct page *page; int i; for (i = 0; i < q->n_desc; i++) { @@ -301,19 +300,12 @@ mtk_wed_wo_queue_tx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) entry->buf = NULL; } - if (!q->cache.va) - return; - - page = virt_to_page(q->cache.va); - __page_frag_cache_drain(page, q->cache.pagecnt_bias); - memset(&q->cache, 0, sizeof(q->cache)); + page_frag_cache_drain(&q->cache); } static void mtk_wed_wo_queue_rx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) { - struct page *page; - for (;;) { void *buf = mtk_wed_wo_dequeue(wo, q, NULL, true); @@ -323,12 +315,7 @@ mtk_wed_wo_queue_rx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) skb_free_frag(buf); } - if (!q->cache.va) - return; - - page = virt_to_page(q->cache.va); - __page_frag_cache_drain(page, q->cache.pagecnt_bias); - memset(&q->cache, 0, sizeof(q->cache)); + page_frag_cache_drain(&q->cache); } static void diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index a6d596e05602..3692b56cb58d 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1344,7 +1344,6 @@ static int nvme_tcp_alloc_async_req(struct nvme_tcp_ctrl *ctrl) static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) { - struct page *page; struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); struct nvme_tcp_queue *queue = &ctrl->queues[qid]; unsigned int noreclaim_flag; @@ -1355,11 +1354,7 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) if (queue->hdr_digest || queue->data_digest) nvme_tcp_free_crypto(queue); - if (queue->pf_cache.va) { - page = virt_to_head_page(queue->pf_cache.va); - __page_frag_cache_drain(page, queue->pf_cache.pagecnt_bias); - queue->pf_cache.va = NULL; - } + page_frag_cache_drain(&queue->pf_cache); noreclaim_flag = memalloc_noreclaim_save(); /* ->sock will be released by fput() */ diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index c8655fc5aa5b..2aa5762e9f50 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -1591,7 +1591,6 @@ static void nvmet_tcp_free_cmd_data_in_buffers(struct nvmet_tcp_queue *queue) static void nvmet_tcp_release_queue_work(struct work_struct *w) { - struct page *page; struct nvmet_tcp_queue *queue = container_of(w, struct nvmet_tcp_queue, release_work); @@ -1615,8 +1614,7 @@ static void nvmet_tcp_release_queue_work(struct work_struct *w) if (queue->hdr_digest || queue->data_digest) nvmet_tcp_free_crypto(queue); ida_free(&nvmet_tcp_queue_ida, queue->idx); - page = virt_to_head_page(queue->pf_cache.va); - __page_frag_cache_drain(page, queue->pf_cache.pagecnt_bias); + page_frag_cache_drain(&queue->pf_cache); kfree(queue); } diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 28aea17fa59b..6cef1c241180 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -311,6 +311,7 @@ extern void __free_pages(struct page *page, unsigned int order); extern void free_pages(unsigned long addr, unsigned int order); struct page_frag_cache; +void page_frag_cache_drain(struct page_frag_cache *nc); extern void __page_frag_cache_drain(struct page *page, unsigned int count); void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask, unsigned int align_mask); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 636145c29f70..06aa1ebbd21c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4699,6 +4699,16 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, return page; } +void page_frag_cache_drain(struct page_frag_cache *nc) +{ + if (!nc->va) + return; + + __page_frag_cache_drain(virt_to_head_page(nc->va), nc->pagecnt_bias); + nc->va = NULL; +} +EXPORT_SYMBOL(page_frag_cache_drain); + void __page_frag_cache_drain(struct page *page, unsigned int count) { VM_BUG_ON_PAGE(page_ref_count(page) == 0, page); From 4051bd8129ac6c1faf447264aa7a8f91feb778b8 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Wed, 28 Feb 2024 17:30:11 +0800 Subject: [PATCH 1836/2255] vhost/net: remove vhost_net_page_frag_refill() The page frag in vhost_net_page_frag_refill() uses the 'struct page_frag' from skb_page_frag_refill(), but it's implementation is similar to page_frag_alloc_align() now. This patch removes vhost_net_page_frag_refill() by using 'struct page_frag_cache' instead of 'struct page_frag', and allocating frag using page_frag_alloc_align(). The added benefit is that not only unifying the page frag implementation a little, but also having about 0.5% performance boost testing by using the vhost_net_test introduced in the last patch. Signed-off-by: Yunsheng Lin Acked-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- drivers/vhost/net.c | 91 ++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 64 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index e574e21cc0ca..4b2fcb228a0a 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -141,10 +141,8 @@ struct vhost_net { unsigned tx_zcopy_err; /* Flush in progress. Protected by tx vq lock. */ bool tx_flush; - /* Private page frag */ - struct page_frag page_frag; - /* Refcount bias of page frag */ - int refcnt_bias; + /* Private page frag cache */ + struct page_frag_cache pf_cache; }; static unsigned vhost_net_zcopy_mask __read_mostly; @@ -655,41 +653,6 @@ static bool tx_can_batch(struct vhost_virtqueue *vq, size_t total_len) !vhost_vq_avail_empty(vq->dev, vq); } -static bool vhost_net_page_frag_refill(struct vhost_net *net, unsigned int sz, - struct page_frag *pfrag, gfp_t gfp) -{ - if (pfrag->page) { - if (pfrag->offset + sz <= pfrag->size) - return true; - __page_frag_cache_drain(pfrag->page, net->refcnt_bias); - } - - pfrag->offset = 0; - net->refcnt_bias = 0; - if (SKB_FRAG_PAGE_ORDER) { - /* Avoid direct reclaim but allow kswapd to wake */ - pfrag->page = alloc_pages((gfp & ~__GFP_DIRECT_RECLAIM) | - __GFP_COMP | __GFP_NOWARN | - __GFP_NORETRY | __GFP_NOMEMALLOC, - SKB_FRAG_PAGE_ORDER); - if (likely(pfrag->page)) { - pfrag->size = PAGE_SIZE << SKB_FRAG_PAGE_ORDER; - goto done; - } - } - pfrag->page = alloc_page(gfp); - if (likely(pfrag->page)) { - pfrag->size = PAGE_SIZE; - goto done; - } - return false; - -done: - net->refcnt_bias = USHRT_MAX; - page_ref_add(pfrag->page, USHRT_MAX - 1); - return true; -} - #define VHOST_NET_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD) static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, @@ -699,7 +662,6 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, struct vhost_net *net = container_of(vq->dev, struct vhost_net, dev); struct socket *sock = vhost_vq_get_backend(vq); - struct page_frag *alloc_frag = &net->page_frag; struct virtio_net_hdr *gso; struct xdp_buff *xdp = &nvq->xdp[nvq->batched_xdp]; struct tun_xdp_hdr *hdr; @@ -710,6 +672,7 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, int sock_hlen = nvq->sock_hlen; void *buf; int copied; + int ret; if (unlikely(len < nvq->sock_hlen)) return -EFAULT; @@ -719,18 +682,17 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, return -ENOSPC; buflen += SKB_DATA_ALIGN(len + pad); - alloc_frag->offset = ALIGN((u64)alloc_frag->offset, SMP_CACHE_BYTES); - if (unlikely(!vhost_net_page_frag_refill(net, buflen, - alloc_frag, GFP_KERNEL))) + buf = page_frag_alloc_align(&net->pf_cache, buflen, GFP_KERNEL, + SMP_CACHE_BYTES); + if (unlikely(!buf)) return -ENOMEM; - buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset; - copied = copy_page_from_iter(alloc_frag->page, - alloc_frag->offset + - offsetof(struct tun_xdp_hdr, gso), - sock_hlen, from); - if (copied != sock_hlen) - return -EFAULT; + copied = copy_from_iter(buf + offsetof(struct tun_xdp_hdr, gso), + sock_hlen, from); + if (copied != sock_hlen) { + ret = -EFAULT; + goto err; + } hdr = buf; gso = &hdr->gso; @@ -743,27 +705,30 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, vhost16_to_cpu(vq, gso->csum_start) + vhost16_to_cpu(vq, gso->csum_offset) + 2); - if (vhost16_to_cpu(vq, gso->hdr_len) > len) - return -EINVAL; + if (vhost16_to_cpu(vq, gso->hdr_len) > len) { + ret = -EINVAL; + goto err; + } } len -= sock_hlen; - copied = copy_page_from_iter(alloc_frag->page, - alloc_frag->offset + pad, - len, from); - if (copied != len) - return -EFAULT; + copied = copy_from_iter(buf + pad, len, from); + if (copied != len) { + ret = -EFAULT; + goto err; + } xdp_init_buff(xdp, buflen, NULL); xdp_prepare_buff(xdp, buf, pad, len, true); hdr->buflen = buflen; - --net->refcnt_bias; - alloc_frag->offset += buflen; - ++nvq->batched_xdp; return 0; + +err: + page_frag_free(buf); + return ret; } static void handle_tx_copy(struct vhost_net *net, struct socket *sock) @@ -1353,8 +1318,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) vqs[VHOST_NET_VQ_RX]); f->private_data = n; - n->page_frag.page = NULL; - n->refcnt_bias = 0; + n->pf_cache.va = NULL; return 0; } @@ -1422,8 +1386,7 @@ static int vhost_net_release(struct inode *inode, struct file *f) kfree(n->vqs[VHOST_NET_VQ_RX].rxq.queue); kfree(n->vqs[VHOST_NET_VQ_TX].xdp); kfree(n->dev.vqs); - if (n->page_frag.page) - __page_frag_cache_drain(n->page_frag.page, n->refcnt_bias); + page_frag_cache_drain(&n->pf_cache); kvfree(n); return 0; } From c5d3705cfd938f6ddd8fa2ff74689cc9b52c00ca Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Wed, 28 Feb 2024 17:30:12 +0800 Subject: [PATCH 1837/2255] tools: virtio: introduce vhost_net_test introduce vhost_net_test for both vhost_net tx and rx basing on virtio_test to test vhost_net changing in the kernel. Steps for vhost_net tx testing: 1. Prepare a out buf. 2. Kick the vhost_net to do tx processing. 3. Do the receiving in the tun side. 4. verify the data received by tun is correct. Steps for vhost_net rx testing: 1. Prepare a in buf. 2. Do the sending in the tun side. 3. Kick the vhost_net to do rx processing. 4. verify the data received by vhost_net is correct. Signed-off-by: Yunsheng Lin Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- tools/virtio/.gitignore | 1 + tools/virtio/Makefile | 8 +- tools/virtio/linux/virtio_config.h | 4 + tools/virtio/vhost_net_test.c | 532 +++++++++++++++++++++++++++++ 4 files changed, 542 insertions(+), 3 deletions(-) create mode 100644 tools/virtio/vhost_net_test.c diff --git a/tools/virtio/.gitignore b/tools/virtio/.gitignore index 9934d48d9a55..7e47b281c442 100644 --- a/tools/virtio/.gitignore +++ b/tools/virtio/.gitignore @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only *.d virtio_test +vhost_net_test vringh_test virtio-trace/trace-agent diff --git a/tools/virtio/Makefile b/tools/virtio/Makefile index d128925980e0..e25e99c1c3b7 100644 --- a/tools/virtio/Makefile +++ b/tools/virtio/Makefile @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 all: test mod -test: virtio_test vringh_test +test: virtio_test vringh_test vhost_net_test virtio_test: virtio_ring.o virtio_test.o vringh_test: vringh_test.o vringh.o virtio_ring.o +vhost_net_test: virtio_ring.o vhost_net_test.o try-run = $(shell set -e; \ if ($(1)) >/dev/null 2>&1; \ @@ -49,6 +50,7 @@ oot-clean: OOT_BUILD+=clean .PHONY: all test mod clean vhost oot oot-clean oot-build clean: - ${RM} *.o vringh_test virtio_test vhost_test/*.o vhost_test/.*.cmd \ - vhost_test/Module.symvers vhost_test/modules.order *.d + ${RM} *.o vringh_test virtio_test vhost_net_test vhost_test/*.o \ + vhost_test/.*.cmd vhost_test/Module.symvers \ + vhost_test/modules.order *.d -include *.d diff --git a/tools/virtio/linux/virtio_config.h b/tools/virtio/linux/virtio_config.h index 2a8a70e2a950..42a564f22f2d 100644 --- a/tools/virtio/linux/virtio_config.h +++ b/tools/virtio/linux/virtio_config.h @@ -1,4 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_VIRTIO_CONFIG_H +#define LINUX_VIRTIO_CONFIG_H #include #include #include @@ -95,3 +97,5 @@ static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) { return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); } + +#endif diff --git a/tools/virtio/vhost_net_test.c b/tools/virtio/vhost_net_test.c new file mode 100644 index 000000000000..389d99a6d7c7 --- /dev/null +++ b/tools/virtio/vhost_net_test.c @@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HDR_LEN sizeof(struct virtio_net_hdr_mrg_rxbuf) +#define TEST_BUF_LEN 256 +#define TEST_PTYPE ETH_P_LOOPBACK +#define DESC_NUM 256 + +/* Used by implementation of kmalloc() in tools/virtio/linux/kernel.h */ +void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end; + +struct vq_info { + int kick; + int call; + int idx; + long started; + long completed; + struct pollfd fds; + void *ring; + /* copy used for control */ + struct vring vring; + struct virtqueue *vq; +}; + +struct vdev_info { + struct virtio_device vdev; + int control; + struct vq_info vqs[2]; + int nvqs; + void *buf; + size_t buf_size; + char *test_buf; + char *res_buf; + struct vhost_memory *mem; + int sock; + int ifindex; + unsigned char mac[ETHER_ADDR_LEN]; +}; + +static int tun_alloc(struct vdev_info *dev, char *tun_name) +{ + struct ifreq ifr; + int len = HDR_LEN; + int fd, e; + + fd = open("/dev/net/tun", O_RDWR); + if (fd < 0) { + perror("Cannot open /dev/net/tun"); + return fd; + } + + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; + strncpy(ifr.ifr_name, tun_name, IFNAMSIZ); + + e = ioctl(fd, TUNSETIFF, &ifr); + if (e < 0) { + perror("ioctl[TUNSETIFF]"); + close(fd); + return e; + } + + e = ioctl(fd, TUNSETVNETHDRSZ, &len); + if (e < 0) { + perror("ioctl[TUNSETVNETHDRSZ]"); + close(fd); + return e; + } + + e = ioctl(fd, SIOCGIFHWADDR, &ifr); + if (e < 0) { + perror("ioctl[SIOCGIFHWADDR]"); + close(fd); + return e; + } + + memcpy(dev->mac, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); + return fd; +} + +static void vdev_create_socket(struct vdev_info *dev, char *tun_name) +{ + struct ifreq ifr; + + dev->sock = socket(AF_PACKET, SOCK_RAW, htons(TEST_PTYPE)); + assert(dev->sock != -1); + + strncpy(ifr.ifr_name, tun_name, IFNAMSIZ); + assert(ioctl(dev->sock, SIOCGIFINDEX, &ifr) >= 0); + + dev->ifindex = ifr.ifr_ifindex; + + /* Set the flags that bring the device up */ + assert(ioctl(dev->sock, SIOCGIFFLAGS, &ifr) >= 0); + ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); + assert(ioctl(dev->sock, SIOCSIFFLAGS, &ifr) >= 0); +} + +static void vdev_send_packet(struct vdev_info *dev) +{ + char *sendbuf = dev->test_buf + HDR_LEN; + struct sockaddr_ll saddrll = {0}; + int sockfd = dev->sock; + int ret; + + saddrll.sll_family = PF_PACKET; + saddrll.sll_ifindex = dev->ifindex; + saddrll.sll_halen = ETH_ALEN; + saddrll.sll_protocol = htons(TEST_PTYPE); + + ret = sendto(sockfd, sendbuf, TEST_BUF_LEN, 0, + (struct sockaddr *)&saddrll, + sizeof(struct sockaddr_ll)); + assert(ret >= 0); +} + +static bool vq_notify(struct virtqueue *vq) +{ + struct vq_info *info = vq->priv; + unsigned long long v = 1; + int r; + + r = write(info->kick, &v, sizeof(v)); + assert(r == sizeof(v)); + + return true; +} + +static void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info) +{ + struct vhost_vring_addr addr = { + .index = info->idx, + .desc_user_addr = (uint64_t)(unsigned long)info->vring.desc, + .avail_user_addr = (uint64_t)(unsigned long)info->vring.avail, + .used_user_addr = (uint64_t)(unsigned long)info->vring.used, + }; + struct vhost_vring_state state = { .index = info->idx }; + struct vhost_vring_file file = { .index = info->idx }; + int r; + + state.num = info->vring.num; + r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state); + assert(r >= 0); + + state.num = 0; + r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state); + assert(r >= 0); + + r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr); + assert(r >= 0); + + file.fd = info->kick; + r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file); + assert(r >= 0); +} + +static void vq_reset(struct vq_info *info, int num, struct virtio_device *vdev) +{ + if (info->vq) + vring_del_virtqueue(info->vq); + + memset(info->ring, 0, vring_size(num, 4096)); + vring_init(&info->vring, num, info->ring, 4096); + info->vq = vring_new_virtqueue(info->idx, num, 4096, vdev, true, false, + info->ring, vq_notify, NULL, "test"); + assert(info->vq); + info->vq->priv = info; +} + +static void vq_info_add(struct vdev_info *dev, int idx, int num, int fd) +{ + struct vhost_vring_file backend = { .index = idx, .fd = fd }; + struct vq_info *info = &dev->vqs[idx]; + int r; + + info->idx = idx; + info->kick = eventfd(0, EFD_NONBLOCK); + r = posix_memalign(&info->ring, 4096, vring_size(num, 4096)); + assert(r >= 0); + vq_reset(info, num, &dev->vdev); + vhost_vq_setup(dev, info); + + r = ioctl(dev->control, VHOST_NET_SET_BACKEND, &backend); + assert(!r); +} + +static void vdev_info_init(struct vdev_info *dev, unsigned long long features) +{ + struct ether_header *eh; + int i, r; + + dev->vdev.features = features; + INIT_LIST_HEAD(&dev->vdev.vqs); + spin_lock_init(&dev->vdev.vqs_list_lock); + + dev->buf_size = (HDR_LEN + TEST_BUF_LEN) * 2; + dev->buf = malloc(dev->buf_size); + assert(dev->buf); + dev->test_buf = dev->buf; + dev->res_buf = dev->test_buf + HDR_LEN + TEST_BUF_LEN; + + memset(dev->test_buf, 0, HDR_LEN + TEST_BUF_LEN); + eh = (struct ether_header *)(dev->test_buf + HDR_LEN); + eh->ether_type = htons(TEST_PTYPE); + memcpy(eh->ether_dhost, dev->mac, ETHER_ADDR_LEN); + memcpy(eh->ether_shost, dev->mac, ETHER_ADDR_LEN); + + for (i = sizeof(*eh); i < TEST_BUF_LEN; i++) + dev->test_buf[i + HDR_LEN] = (char)i; + + dev->control = open("/dev/vhost-net", O_RDWR); + assert(dev->control >= 0); + + r = ioctl(dev->control, VHOST_SET_OWNER, NULL); + assert(r >= 0); + + dev->mem = malloc(offsetof(struct vhost_memory, regions) + + sizeof(dev->mem->regions[0])); + assert(dev->mem); + memset(dev->mem, 0, offsetof(struct vhost_memory, regions) + + sizeof(dev->mem->regions[0])); + dev->mem->nregions = 1; + dev->mem->regions[0].guest_phys_addr = (long)dev->buf; + dev->mem->regions[0].userspace_addr = (long)dev->buf; + dev->mem->regions[0].memory_size = dev->buf_size; + + r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem); + assert(r >= 0); + + r = ioctl(dev->control, VHOST_SET_FEATURES, &features); + assert(r >= 0); + + dev->nvqs = 2; +} + +static void wait_for_interrupt(struct vq_info *vq) +{ + unsigned long long val; + + poll(&vq->fds, 1, 100); + + if (vq->fds.revents & POLLIN) + read(vq->fds.fd, &val, sizeof(val)); +} + +static void verify_res_buf(char *res_buf) +{ + int i; + + for (i = ETHER_HDR_LEN; i < TEST_BUF_LEN; i++) + assert(res_buf[i] == (char)i); +} + +static void run_tx_test(struct vdev_info *dev, struct vq_info *vq, + bool delayed, int bufs) +{ + long long spurious = 0; + struct scatterlist sl; + unsigned int len; + int r; + + for (;;) { + long started_before = vq->started; + long completed_before = vq->completed; + + virtqueue_disable_cb(vq->vq); + do { + while (vq->started < bufs && + (vq->started - vq->completed) < 1) { + sg_init_one(&sl, dev->test_buf, HDR_LEN + TEST_BUF_LEN); + r = virtqueue_add_outbuf(vq->vq, &sl, 1, + dev->test_buf + vq->started, + GFP_ATOMIC); + if (unlikely(r != 0)) + break; + + ++vq->started; + + if (unlikely(!virtqueue_kick(vq->vq))) { + r = -1; + break; + } + } + + if (vq->started >= bufs) + r = -1; + + /* Flush out completed bufs if any */ + while (virtqueue_get_buf(vq->vq, &len)) { + int n; + + n = recvfrom(dev->sock, dev->res_buf, TEST_BUF_LEN, 0, NULL, NULL); + assert(n == TEST_BUF_LEN); + verify_res_buf(dev->res_buf); + + ++vq->completed; + r = 0; + } + } while (r == 0); + + if (vq->completed == completed_before && vq->started == started_before) + ++spurious; + + assert(vq->completed <= bufs); + assert(vq->started <= bufs); + if (vq->completed == bufs) + break; + + if (delayed) { + if (virtqueue_enable_cb_delayed(vq->vq)) + wait_for_interrupt(vq); + } else { + if (virtqueue_enable_cb(vq->vq)) + wait_for_interrupt(vq); + } + } + printf("TX spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n", + spurious, vq->started, vq->completed); +} + +static void run_rx_test(struct vdev_info *dev, struct vq_info *vq, + bool delayed, int bufs) +{ + long long spurious = 0; + struct scatterlist sl; + unsigned int len; + int r; + + for (;;) { + long started_before = vq->started; + long completed_before = vq->completed; + + do { + while (vq->started < bufs && + (vq->started - vq->completed) < 1) { + sg_init_one(&sl, dev->res_buf, HDR_LEN + TEST_BUF_LEN); + + r = virtqueue_add_inbuf(vq->vq, &sl, 1, + dev->res_buf + vq->started, + GFP_ATOMIC); + if (unlikely(r != 0)) + break; + + ++vq->started; + + vdev_send_packet(dev); + + if (unlikely(!virtqueue_kick(vq->vq))) { + r = -1; + break; + } + } + + if (vq->started >= bufs) + r = -1; + + /* Flush out completed bufs if any */ + while (virtqueue_get_buf(vq->vq, &len)) { + struct ether_header *eh; + + eh = (struct ether_header *)(dev->res_buf + HDR_LEN); + + /* tun netdev is up and running, only handle the + * TEST_PTYPE packet. + */ + if (eh->ether_type == htons(TEST_PTYPE)) { + assert(len == TEST_BUF_LEN + HDR_LEN); + verify_res_buf(dev->res_buf + HDR_LEN); + } + + ++vq->completed; + r = 0; + } + } while (r == 0); + + if (vq->completed == completed_before && vq->started == started_before) + ++spurious; + + assert(vq->completed <= bufs); + assert(vq->started <= bufs); + if (vq->completed == bufs) + break; + } + + printf("RX spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n", + spurious, vq->started, vq->completed); +} + +static const char optstring[] = "h"; +static const struct option longopts[] = { + { + .name = "help", + .val = 'h', + }, + { + .name = "event-idx", + .val = 'E', + }, + { + .name = "no-event-idx", + .val = 'e', + }, + { + .name = "indirect", + .val = 'I', + }, + { + .name = "no-indirect", + .val = 'i', + }, + { + .name = "virtio-1", + .val = '1', + }, + { + .name = "no-virtio-1", + .val = '0', + }, + { + .name = "delayed-interrupt", + .val = 'D', + }, + { + .name = "no-delayed-interrupt", + .val = 'd', + }, + { + .name = "buf-num", + .val = 'n', + .has_arg = required_argument, + }, + { + .name = "batch", + .val = 'b', + .has_arg = required_argument, + }, + { + } +}; + +static void help(int status) +{ + fprintf(stderr, "Usage: vhost_net_test [--help]" + " [--no-indirect]" + " [--no-event-idx]" + " [--no-virtio-1]" + " [--delayed-interrupt]" + " [--buf-num]" + "\n"); + + exit(status); +} + +int main(int argc, char **argv) +{ + unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | + (1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1); + char tun_name[IFNAMSIZ]; + long nbufs = 0x100000; + struct vdev_info dev; + bool delayed = false; + int o, fd; + + for (;;) { + o = getopt_long(argc, argv, optstring, longopts, NULL); + switch (o) { + case -1: + goto done; + case '?': + help(2); + case 'e': + features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX); + break; + case 'h': + help(0); + case 'i': + features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC); + break; + case '0': + features &= ~(1ULL << VIRTIO_F_VERSION_1); + break; + case 'D': + delayed = true; + break; + case 'n': + nbufs = strtol(optarg, NULL, 10); + assert(nbufs > 0); + break; + default: + assert(0); + break; + } + } + +done: + memset(&dev, 0, sizeof(dev)); + snprintf(tun_name, IFNAMSIZ, "tun_%d", getpid()); + + fd = tun_alloc(&dev, tun_name); + assert(fd >= 0); + + vdev_info_init(&dev, features); + vq_info_add(&dev, 0, DESC_NUM, fd); + vq_info_add(&dev, 1, DESC_NUM, fd); + vdev_create_socket(&dev, tun_name); + + run_rx_test(&dev, &dev.vqs[0], delayed, nbufs); + run_tx_test(&dev, &dev.vqs[1], delayed, nbufs); + + return 0; +} From 6ebe414b48cf43abb5abc17321dd4343a5a0d5ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:42:57 +0200 Subject: [PATCH 1838/2255] net: dsa: mt7530: remove .mac_port_config for MT7988 and make it optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the switch on the MT7988 SoC, the mac_port_config member for ID_MT7988 in mt753x_table is not needed as the interfaces of all MACs are already handled on mt7988_mac_port_get_caps(). Therefore, remove the mac_port_config member from ID_MT7988 in mt753x_table. Before calling priv->info->mac_port_config(), if there's no mac_port_config member in mt753x_table, exit mt753x_mac_config() successfully. Remove calling priv->info->mac_port_config() from the sanity check as the sanity check requires a pointer to a mac_port_config function to be non-NULL. This will fail for MT7988 as mac_port_config won't be a member of its info table. Co-developed-by: Daniel Golle Signed-off-by: Daniel Golle Signed-off-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Reviewed-by: Russell King (Oracle) Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 03d966fa67b2..94d4b2c87799 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2655,17 +2655,6 @@ static bool mt753x_is_mac_port(u32 port) return (port == 5 || port == 6); } -static int -mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode, - phy_interface_t interface) -{ - if (dsa_is_cpu_port(ds, port) && - interface == PHY_INTERFACE_MODE_INTERNAL) - return 0; - - return -EINVAL; -} - static int mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) @@ -2706,6 +2695,9 @@ mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode, { struct mt7530_priv *priv = ds->priv; + if (!priv->info->mac_port_config) + return 0; + return priv->info->mac_port_config(ds, port, mode, state->interface); } @@ -3169,7 +3161,6 @@ const struct mt753x_info mt753x_table[] = { .phy_write_c45 = mt7531_ind_c45_phy_write, .cpu_port_config = mt7988_cpu_port_config, .mac_port_get_caps = mt7988_mac_port_get_caps, - .mac_port_config = mt7988_mac_config, }, }; EXPORT_SYMBOL_GPL(mt753x_table); @@ -3197,8 +3188,7 @@ mt7530_probe_common(struct mt7530_priv *priv) * properly. */ if (!priv->info->sw_setup || !priv->info->phy_read_c22 || - !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps || - !priv->info->mac_port_config) + !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps) return -EINVAL; priv->id = priv->info->id; From 804cd5f7059e2ca1e26cbd945b648bcba2d33766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:42:58 +0200 Subject: [PATCH 1839/2255] net: dsa: mt7530: set interrupt register only for MT7530 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting this register related to interrupts is only needed for the MT7530 switch. Make an exclusive check to ensure this. Signed-off-by: Arınç ÜNAL Acked-by: Daniel Golle Tested-by: Daniel Golle Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 94d4b2c87799..5cfd303b773f 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2055,7 +2055,7 @@ mt7530_setup_irq(struct mt7530_priv *priv) } /* This register must be set for MT7530 to properly fire interrupts */ - if (priv->id != ID_MT7531) + if (priv->id == ID_MT7530 || priv->id == ID_MT7621) mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL); ret = request_threaded_irq(priv->irq, NULL, mt7530_irq_thread_fn, From a565f98d7d25ce5125956fc61c47526c8041e531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:42:59 +0200 Subject: [PATCH 1840/2255] net: dsa: mt7530: do not use SW_PHY_RST to reset MT7531 switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the document MT7531 Reference Manual for Development Board v1.0, the SW_PHY_RST bit on the SYS_CTRL register doesn't exist for MT7531. This is likely why forcing link down on all ports is necessary for MT7531. Therefore, do not set SW_PHY_RST on mt7531_setup(). Signed-off-by: Arınç ÜNAL Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 5cfd303b773f..296711fd5c43 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2451,14 +2451,12 @@ mt7531_setup(struct dsa_switch *ds) val = mt7530_read(priv, MT7531_TOP_SIG_SR); priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN); - /* all MACs must be forced link-down before sw reset */ + /* Force link down on all ports before internal reset */ for (i = 0; i < MT7530_NUM_PORTS; i++) mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK); /* Reset the switch through internal reset */ - mt7530_write(priv, MT7530_SYS_CTRL, - SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | - SYS_CTRL_REG_RST); + mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_SW_RST | SYS_CTRL_REG_RST); if (!priv->p5_sgmii) { mt7531_pll_setup(priv); From adf4ae24ba42473a742f55274c0211ed9dea44af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:43:00 +0200 Subject: [PATCH 1841/2255] net: dsa: mt7530: get rid of useless error returns on phylink code path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove error returns on the cases where they are already handled with the function the mac_port_get_caps member in mt753x_table points to. mt7531_mac_config() is also called from mt7531_cpu_port_config() outside of phylink but the port and interface modes are already handled there. Change the functions and the mac_port_config function pointer to void now that there're no error returns anymore. Remove mt753x_is_mac_port() that used to help the said error returns. On mt7531_mac_config(), switch to if statements to simplify the code. Remove internal phy cases from mt753x_phylink_mac_config(), there is no need to check the interface mode as that's already handled with the function the mac_port_get_caps member in mt753x_table points to. Acked-by: Daniel Golle Tested-by: Daniel Golle Signed-off-by: Arınç ÜNAL Reviewed-by: Russell King (Oracle) Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 81 ++++++++-------------------------------- drivers/net/dsa/mt7530.h | 6 +-- 2 files changed, 19 insertions(+), 68 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 296711fd5c43..c069bf273733 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2587,7 +2587,7 @@ static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, } } -static int +static void mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) { @@ -2597,22 +2597,14 @@ mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode, mt7530_setup_port5(priv->ds, interface); else if (port == 6) mt7530_setup_port6(priv->ds, interface); - - return 0; } -static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port, - phy_interface_t interface, - struct phy_device *phydev) +static void mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port, + phy_interface_t interface, + struct phy_device *phydev) { u32 val; - if (priv->p5_sgmii) { - dev_err(priv->dev, "RGMII mode is not available for port %d\n", - port); - return -EINVAL; - } - val = mt7530_read(priv, MT7531_CLKGEN_CTRL); val |= GP_CLK_EN; val &= ~GP_MODE_MASK; @@ -2640,20 +2632,14 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port, case PHY_INTERFACE_MODE_RGMII_ID: break; default: - return -EINVAL; + break; } } + mt7530_write(priv, MT7531_CLKGEN_CTRL, val); - - return 0; } -static bool mt753x_is_mac_port(u32 port) -{ - return (port == 5 || port == 6); -} - -static int +static void mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) { @@ -2661,42 +2647,21 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, struct phy_device *phydev; struct dsa_port *dp; - if (!mt753x_is_mac_port(port)) { - dev_err(priv->dev, "port %d is not a MAC port\n", port); - return -EINVAL; - } - - switch (interface) { - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: + if (phy_interface_mode_is_rgmii(interface)) { dp = dsa_to_port(ds, port); phydev = dp->user->phydev; - return mt7531_rgmii_setup(priv, port, interface, phydev); - case PHY_INTERFACE_MODE_SGMII: - case PHY_INTERFACE_MODE_NA: - case PHY_INTERFACE_MODE_1000BASEX: - case PHY_INTERFACE_MODE_2500BASEX: - /* handled in SGMII PCS driver */ - return 0; - default: - return -EINVAL; + mt7531_rgmii_setup(priv, port, interface, phydev); } - - return -EINVAL; } -static int +static void mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) { struct mt7530_priv *priv = ds->priv; - if (!priv->info->mac_port_config) - return 0; - - return priv->info->mac_port_config(ds, port, mode, state->interface); + if (priv->info->mac_port_config) + priv->info->mac_port_config(ds, port, mode, state->interface); } static struct phylink_pcs * @@ -2725,17 +2690,11 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, u32 mcr_cur, mcr_new; switch (port) { - case 0 ... 4: - if (state->interface != PHY_INTERFACE_MODE_GMII && - state->interface != PHY_INTERFACE_MODE_INTERNAL) - goto unsupported; - break; case 5: if (priv->p5_interface == state->interface) break; - if (mt753x_mac_config(ds, port, mode, state) < 0) - goto unsupported; + mt753x_mac_config(ds, port, mode, state); if (priv->p5_intf_sel != P5_DISABLED) priv->p5_interface = state->interface; @@ -2744,16 +2703,10 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, if (priv->p6_interface == state->interface) break; - if (mt753x_mac_config(ds, port, mode, state) < 0) - goto unsupported; + mt753x_mac_config(ds, port, mode, state); priv->p6_interface = state->interface; break; - default: -unsupported: - dev_err(ds->dev, "%s: unsupported %s port: %i\n", - __func__, phy_modes(state->interface), port); - return; } mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); @@ -2836,7 +2789,6 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port) struct mt7530_priv *priv = ds->priv; phy_interface_t interface; int speed; - int ret; switch (port) { case 5: @@ -2861,9 +2813,8 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port) else speed = SPEED_1000; - ret = mt7531_mac_config(ds, port, MLO_AN_FIXED, interface); - if (ret) - return ret; + mt7531_mac_config(ds, port, MLO_AN_FIXED, interface); + mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPU_PORT_SETTING(priv->id)); mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL, diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 26a6d2160c08..b1665de7f640 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -730,9 +730,9 @@ struct mt753x_info { void (*mac_port_validate)(struct dsa_switch *ds, int port, phy_interface_t interface, unsigned long *supported); - int (*mac_port_config)(struct dsa_switch *ds, int port, - unsigned int mode, - phy_interface_t interface); + void (*mac_port_config)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface); }; /* struct mt7530_priv - This is the main data structure for holding the state From 22fa10170af5963e921b73159348bef807f58e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:43:01 +0200 Subject: [PATCH 1842/2255] net: dsa: mt7530: get rid of priv->info->cpu_port_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit priv->info->cpu_port_config() is used for MT7531 and the switch on the MT7988 SoC. It sets up the ports described as a CPU port earlier than the phylink code path would do. This function is useless as: - Configuring the MACs can be done from the phylink_mac_config code path instead. - All the link configuration it does on the CPU ports are later undone with the port_enable, phylink_mac_config, and then phylink_mac_link_up code path [1]. priv->p5_interface and priv->p6_interface were being used to prevent configuring the MACs from the phylink_mac_config code path. Remove them now that they hold no purpose. Remove priv->info->cpu_port_config(). On mt753x_phylink_mac_config, switch to if statements to simplify the code. Remove the overwriting of the speed and duplex interfaces for certain interface modes. Phylink already provides the speed and duplex variables with proper values. Phylink already sets the max speed of TRGMII to SPEED_1000. Add SPEED_2500 for PHY_INTERFACE_MODE_2500BASEX to where the speed and EEE bits are set instead. On the switch on the MT7988 SoC, PHY_INTERFACE_MODE_INTERNAL is being used to describe the interface mode of the 10G MAC, which is of port 6. On mt7988_cpu_port_config() PMCR_FORCE_SPEED_1000 was set via the PMCR_CPU_PORT_SETTING() mask. Add SPEED_10000 case to where the speed bits are set to cover this. No need to add it to where the EEE bits are set as the "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open Version) v0.1" document shows that these bits don't exist on the MT7530_PMCR_P(6) register. Remove the definition of PMCR_CPU_PORT_SETTING() now that it holds no purpose. Change mt753x_cpu_port_enable() to void now that there're no error cases left. Link: https://lore.kernel.org/netdev/ZHy2jQLesdYFMQtO@shell.armlinux.org.uk/ [1] Suggested-by: Russell King (Oracle) Signed-off-by: Arınç ÜNAL Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 114 +++------------------------------------ drivers/net/dsa/mt7530.h | 11 ---- 2 files changed, 7 insertions(+), 118 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index c069bf273733..80b65f064310 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -966,18 +966,10 @@ mt753x_trap_frames(struct mt7530_priv *priv) MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY)); } -static int +static void mt753x_cpu_port_enable(struct dsa_switch *ds, int port) { struct mt7530_priv *priv = ds->priv; - int ret; - - /* Setup max capability of CPU port at first */ - if (priv->info->cpu_port_config) { - ret = priv->info->cpu_port_config(ds, port); - if (ret) - return ret; - } /* Enable Mediatek header mode on the cpu port */ mt7530_write(priv, MT7530_PVC_P(port), @@ -1003,8 +995,6 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port) /* Set to fallback mode for independent VLAN learning */ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, MT7530_PORT_FALLBACK_MODE); - - return 0; } static int @@ -2261,8 +2251,6 @@ mt7530_setup(struct dsa_switch *ds) val |= MHWTRAP_MANUAL; mt7530_write(priv, MT7530_MHWTRAP, val); - priv->p6_interface = PHY_INTERFACE_MODE_NA; - mt753x_trap_frames(priv); /* Enable and reset MIB counters */ @@ -2277,9 +2265,7 @@ mt7530_setup(struct dsa_switch *ds) mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); if (dsa_is_cpu_port(ds, i)) { - ret = mt753x_cpu_port_enable(ds, i); - if (ret) - return ret; + mt753x_cpu_port_enable(ds, i); } else { mt7530_port_disable(ds, i); @@ -2383,9 +2369,7 @@ mt7531_setup_common(struct dsa_switch *ds) mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR); if (dsa_is_cpu_port(ds, i)) { - ret = mt753x_cpu_port_enable(ds, i); - if (ret) - return ret; + mt753x_cpu_port_enable(ds, i); } else { mt7530_port_disable(ds, i); @@ -2474,10 +2458,6 @@ mt7531_setup(struct dsa_switch *ds) mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK, MT7531_GPIO0_INTERRUPT); - /* Let phylink decide the interface later. */ - priv->p5_interface = PHY_INTERFACE_MODE_NA; - priv->p6_interface = PHY_INTERFACE_MODE_NA; - /* Enable PHY core PLL, since phy_device has not yet been created * provided for phy_[read,write]_mmd_indirect is called, we provide * our own mt7531_ind_mmd_phy_[read,write] to complete this @@ -2689,26 +2669,9 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, struct mt7530_priv *priv = ds->priv; u32 mcr_cur, mcr_new; - switch (port) { - case 5: - if (priv->p5_interface == state->interface) - break; - + if (port == 5 || port == 6) mt753x_mac_config(ds, port, mode, state); - if (priv->p5_intf_sel != P5_DISABLED) - priv->p5_interface = state->interface; - break; - case 6: - if (priv->p6_interface == state->interface) - break; - - mt753x_mac_config(ds, port, mode, state); - - priv->p6_interface = state->interface; - break; - } - mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); mcr_new = mcr_cur; mcr_new &= ~PMCR_LINK_SETTINGS_MASK; @@ -2744,17 +2707,10 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK; - /* MT753x MAC works in 1G full duplex mode for all up-clocked - * variants. - */ - if (interface == PHY_INTERFACE_MODE_TRGMII || - (phy_interface_mode_is_8023z(interface))) { - speed = SPEED_1000; - duplex = DUPLEX_FULL; - } - switch (speed) { case SPEED_1000: + case SPEED_2500: + case SPEED_10000: mcr |= PMCR_FORCE_SPEED_1000; break; case SPEED_100: @@ -2772,6 +2728,7 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) { switch (speed) { case SPEED_1000: + case SPEED_2500: mcr |= PMCR_FORCE_EEE1G; break; case SPEED_100: @@ -2783,61 +2740,6 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, mt7530_set(priv, MT7530_PMCR_P(port), mcr); } -static int -mt7531_cpu_port_config(struct dsa_switch *ds, int port) -{ - struct mt7530_priv *priv = ds->priv; - phy_interface_t interface; - int speed; - - switch (port) { - case 5: - if (!priv->p5_sgmii) - interface = PHY_INTERFACE_MODE_RGMII; - else - interface = PHY_INTERFACE_MODE_2500BASEX; - - priv->p5_interface = interface; - break; - case 6: - interface = PHY_INTERFACE_MODE_2500BASEX; - - priv->p6_interface = interface; - break; - default: - return -EINVAL; - } - - if (interface == PHY_INTERFACE_MODE_2500BASEX) - speed = SPEED_2500; - else - speed = SPEED_1000; - - mt7531_mac_config(ds, port, MLO_AN_FIXED, interface); - - mt7530_write(priv, MT7530_PMCR_P(port), - PMCR_CPU_PORT_SETTING(priv->id)); - mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL, - speed, DUPLEX_FULL, true, true); - - return 0; -} - -static int -mt7988_cpu_port_config(struct dsa_switch *ds, int port) -{ - struct mt7530_priv *priv = ds->priv; - - mt7530_write(priv, MT7530_PMCR_P(port), - PMCR_CPU_PORT_SETTING(priv->id)); - - mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, - PHY_INTERFACE_MODE_INTERNAL, NULL, - SPEED_10000, DUPLEX_FULL, true, true); - - return 0; -} - static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { @@ -3096,7 +2998,6 @@ const struct mt753x_info mt753x_table[] = { .phy_write_c22 = mt7531_ind_c22_phy_write, .phy_read_c45 = mt7531_ind_c45_phy_read, .phy_write_c45 = mt7531_ind_c45_phy_write, - .cpu_port_config = mt7531_cpu_port_config, .mac_port_get_caps = mt7531_mac_port_get_caps, .mac_port_config = mt7531_mac_config, }, @@ -3108,7 +3009,6 @@ const struct mt753x_info mt753x_table[] = { .phy_write_c22 = mt7531_ind_c22_phy_write, .phy_read_c45 = mt7531_ind_c45_phy_read, .phy_write_c45 = mt7531_ind_c45_phy_write, - .cpu_port_config = mt7988_cpu_port_config, .mac_port_get_caps = mt7988_mac_port_get_caps, }, }; diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index b1665de7f640..8a8144868eaa 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -311,13 +311,6 @@ enum mt7530_vlan_port_acc_frm { PMCR_TX_FC_EN | PMCR_RX_FC_EN | \ PMCR_FORCE_FDX | PMCR_FORCE_LNK | \ PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100) -#define PMCR_CPU_PORT_SETTING(id) (PMCR_FORCE_MODE_ID((id)) | \ - PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ - PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \ - PMCR_TX_EN | PMCR_RX_EN | \ - PMCR_TX_FC_EN | PMCR_RX_FC_EN | \ - PMCR_FORCE_SPEED_1000 | \ - PMCR_FORCE_FDX | PMCR_FORCE_LNK) #define MT7530_PMEEECR_P(x) (0x3004 + (x) * 0x100) #define WAKEUP_TIME_1000(x) (((x) & 0xFF) << 24) @@ -724,7 +717,6 @@ struct mt753x_info { int regnum); int (*phy_write_c45)(struct mt7530_priv *priv, int port, int devad, int regnum, u16 val); - int (*cpu_port_config)(struct dsa_switch *ds, int port); void (*mac_port_get_caps)(struct dsa_switch *ds, int port, struct phylink_config *config); void (*mac_port_validate)(struct dsa_switch *ds, int port, @@ -750,7 +742,6 @@ struct mt753x_info { * @ports: Holding the state among ports * @reg_mutex: The lock for protecting among process accessing * registers - * @p6_interface Holding the current port 6 interface * @p5_intf_sel: Holding the current port 5 interface select * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch * has got SGMII @@ -772,8 +763,6 @@ struct mt7530_priv { const struct mt753x_info *info; unsigned int id; bool mcm; - phy_interface_t p6_interface; - phy_interface_t p5_interface; enum p5_interface_select p5_intf_sel; bool p5_sgmii; u8 mirror_rx; From 1192ed898c970a1e6bd5f0e0d92c60214228e62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:43:02 +0200 Subject: [PATCH 1843/2255] net: dsa: mt7530: get rid of mt753x_mac_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for a separate function to call priv->info->mac_port_config(). Call it from mt753x_phylink_mac_config() instead and remove mt753x_mac_config(). Signed-off-by: Arınç ÜNAL Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 80b65f064310..e353c03dd1db 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2634,16 +2634,6 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, } } -static void -mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode, - const struct phylink_link_state *state) -{ - struct mt7530_priv *priv = ds->priv; - - if (priv->info->mac_port_config) - priv->info->mac_port_config(ds, port, mode, state->interface); -} - static struct phylink_pcs * mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port, phy_interface_t interface) @@ -2669,8 +2659,8 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, struct mt7530_priv *priv = ds->priv; u32 mcr_cur, mcr_new; - if (port == 5 || port == 6) - mt753x_mac_config(ds, port, mode, state); + if ((port == 5 || port == 6) && priv->info->mac_port_config) + priv->info->mac_port_config(ds, port, mode, state->interface); mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); mcr_new = mcr_cur; From 3a87131e3d72281285d4df7db2d7d3299b1edb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:43:03 +0200 Subject: [PATCH 1844/2255] net: dsa: mt7530: put initialising PCS devices code back to original order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit fae463084032 ("net: dsa: mt753x: fix pcs conversion regression") fixes regression caused by cpu_port_config manually calling phylink operations. cpu_port_config was deemed useless and was removed. Therefore, put initialising PCS devices code back to its original order. Signed-off-by: Arınç ÜNAL Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index e353c03dd1db..5c8ad41ce8cd 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2812,17 +2812,9 @@ static int mt753x_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; - int i, ret; + int ret = priv->info->sw_setup(ds); + int i; - /* Initialise the PCS devices */ - for (i = 0; i < priv->ds->num_ports; i++) { - priv->pcs[i].pcs.ops = priv->info->pcs_ops; - priv->pcs[i].pcs.neg_mode = true; - priv->pcs[i].priv = priv; - priv->pcs[i].port = i; - } - - ret = priv->info->sw_setup(ds); if (ret) return ret; @@ -2834,6 +2826,14 @@ mt753x_setup(struct dsa_switch *ds) if (ret && priv->irq) mt7530_free_irq_common(priv); + /* Initialise the PCS devices */ + for (i = 0; i < priv->ds->num_ports; i++) { + priv->pcs[i].pcs.ops = priv->info->pcs_ops; + priv->pcs[i].pcs.neg_mode = true; + priv->pcs[i].priv = priv; + priv->pcs[i].port = i; + } + if (priv->create_sgmii) { ret = priv->create_sgmii(priv); if (ret && priv->irq) From 6324230b3b675397a5bcabf9bf7b0bd0a7f2ae0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:43:04 +0200 Subject: [PATCH 1845/2255] net: dsa: mt7530: sort link settings ops and force link down on all ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit port_enable and port_disable clears the link settings. Move that to mt7530_setup() and mt7531_setup_common() which set up the switches. This way, the link settings are cleared on all ports at setup, and then only once with phylink_mac_link_down() when a link goes down. Enable force mode at setup to apply the force part of the link settings. This ensures that disabled ports will have their link down. Suggested-by: Vladimir Oltean Signed-off-by: Arınç ÜNAL Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 5c8ad41ce8cd..91d927bb49f7 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1018,7 +1018,6 @@ mt7530_port_enable(struct dsa_switch *ds, int port, priv->ports[port].enable = true; mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, priv->ports[port].pm); - mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); mutex_unlock(&priv->reg_mutex); @@ -1038,7 +1037,6 @@ mt7530_port_disable(struct dsa_switch *ds, int port) priv->ports[port].enable = false; mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, PCR_MATRIX_CLR); - mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); mutex_unlock(&priv->reg_mutex); } @@ -2257,6 +2255,12 @@ mt7530_setup(struct dsa_switch *ds) mt7530_mib_reset(ds); for (i = 0; i < MT7530_NUM_PORTS; i++) { + /* Clear link settings and enable force mode to force link down + * on all ports until they're enabled later. + */ + mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK | + PMCR_FORCE_MODE, PMCR_FORCE_MODE); + /* Disable forwarding by default on all ports */ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, PCR_MATRIX_CLR); @@ -2359,6 +2363,12 @@ mt7531_setup_common(struct dsa_switch *ds) UNU_FFP_MASK); for (i = 0; i < MT7530_NUM_PORTS; i++) { + /* Clear link settings and enable force mode to force link down + * on all ports until they're enabled later. + */ + mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK | + MT7531_FORCE_MODE, MT7531_FORCE_MODE); + /* Disable forwarding by default on all ports */ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, PCR_MATRIX_CLR); From b04097c7a7450f7ae172b4a049e8876a85e859be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Fri, 1 Mar 2024 12:43:05 +0200 Subject: [PATCH 1846/2255] net: dsa: mt7530: simplify link operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "MT7621 Giga Switch Programming Guide v0.3", "MT7531 Reference Manual for Development Board v1.0", and "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open Version) v0.1" documents show that these bits are enabled at reset: PMCR_IFG_XMIT(1) (not part of PMCR_LINK_SETTINGS_MASK) PMCR_MAC_MODE (not part of PMCR_LINK_SETTINGS_MASK) PMCR_TX_EN PMCR_RX_EN PMCR_BACKOFF_EN (not part of PMCR_LINK_SETTINGS_MASK) PMCR_BACKPR_EN (not part of PMCR_LINK_SETTINGS_MASK) PMCR_TX_FC_EN PMCR_RX_FC_EN These bits also don't exist on the MT7530_PMCR_P(6) register of the switch on the MT7988 SoC: PMCR_IFG_XMIT() PMCR_MAC_MODE PMCR_BACKOFF_EN PMCR_BACKPR_EN Remove the setting of the bits not part of PMCR_LINK_SETTINGS_MASK on phylink_mac_config as they're already set. The bit for setting the port on force mode is already done on mt7530_setup() and mt7531_setup_common(). So get rid of PMCR_FORCE_MODE_ID() which helped determine which bit to use for the switch model. Signed-off-by: Arınç ÜNAL Signed-off-by: Paolo Abeni --- drivers/net/dsa/mt7530.c | 12 +----------- drivers/net/dsa/mt7530.h | 2 -- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 91d927bb49f7..1ae11b180d54 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2667,23 +2667,13 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) { struct mt7530_priv *priv = ds->priv; - u32 mcr_cur, mcr_new; if ((port == 5 || port == 6) && priv->info->mac_port_config) priv->info->mac_port_config(ds, port, mode, state->interface); - mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); - mcr_new = mcr_cur; - mcr_new &= ~PMCR_LINK_SETTINGS_MASK; - mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN | - PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id); - /* Are we connected to external phy */ if (port == 5 && dsa_is_user_port(ds, 5)) - mcr_new |= PMCR_EXT_PHY; - - if (mcr_new != mcr_cur) - mt7530_write(priv, MT7530_PMCR_P(port), mcr_new); + mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY); } static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 8a8144868eaa..a71166e0a7fc 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -304,8 +304,6 @@ enum mt7530_vlan_port_acc_frm { MT7531_FORCE_DPX | \ MT7531_FORCE_RX_FC | \ MT7531_FORCE_TX_FC) -#define PMCR_FORCE_MODE_ID(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ - MT7531_FORCE_MODE : PMCR_FORCE_MODE) #define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \ PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \ PMCR_TX_FC_EN | PMCR_RX_FC_EN | \ From 93e16ea025d234d0ed01d9dc9c819257a2159bb6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 1 Mar 2024 19:37:37 +0000 Subject: [PATCH 1847/2255] net: gro: rename skb_gro_header_hard() skb_gro_header_hard() is renamed to skb_gro_may_pull() to match the convention used by common helpers like pskb_may_pull(). This means the condition is inverted: if (skb_gro_header_hard(skb, hlen)) slow_path(); becomes: if (!skb_gro_may_pull(skb, hlen)) slow_path(); Signed-off-by: Eric Dumazet Acked-by: Paolo Abeni Signed-off-by: Paolo Abeni --- drivers/net/geneve.c | 2 +- include/net/gro.h | 7 ++++--- net/core/gro.c | 2 +- net/ipv4/fou_core.c | 2 +- net/ipv4/gre_offload.c | 2 +- net/ipv4/tcp_offload.c | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 6f3f9b446b1d..e25e0a31126c 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -508,7 +508,7 @@ static struct sk_buff *geneve_gro_receive(struct sock *sk, gh_len = geneve_hlen(gh); hlen = off_gnv + gh_len; - if (skb_gro_header_hard(skb, hlen)) { + if (!skb_gro_may_pull(skb, hlen)) { gh = skb_gro_header_slow(skb, hlen, off_gnv); if (unlikely(!gh)) goto out; diff --git a/include/net/gro.h b/include/net/gro.h index b435f0ddbf64..ffc2c96d263b 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -145,9 +145,10 @@ static inline void *skb_gro_header_fast(struct sk_buff *skb, return NAPI_GRO_CB(skb)->frag0 + offset; } -static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen) +static inline bool skb_gro_may_pull(const struct sk_buff *skb, + unsigned int hlen) { - return NAPI_GRO_CB(skb)->frag0_len < hlen; + return hlen <= NAPI_GRO_CB(skb)->frag0_len; } static inline void skb_gro_frag0_invalidate(struct sk_buff *skb) @@ -172,7 +173,7 @@ static inline void *skb_gro_header(struct sk_buff *skb, void *ptr; ptr = skb_gro_header_fast(skb, offset); - if (skb_gro_header_hard(skb, hlen)) + if (!skb_gro_may_pull(skb, hlen)) ptr = skb_gro_header_slow(skb, hlen, offset); return ptr; } diff --git a/net/core/gro.c b/net/core/gro.c index 0759277dc14e..927ccf681490 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -700,7 +700,7 @@ static struct sk_buff *napi_frags_skb(struct napi_struct *napi) skb_reset_mac_header(skb); skb_gro_reset_offset(skb, hlen); - if (unlikely(skb_gro_header_hard(skb, hlen))) { + if (unlikely(!skb_gro_may_pull(skb, hlen))) { eth = skb_gro_header_slow(skb, hlen, 0); if (unlikely(!eth)) { net_warn_ratelimited("%s: dropping impossible skb from %s\n", diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c index 0c41076e31ed..a8494f796dca 100644 --- a/net/ipv4/fou_core.c +++ b/net/ipv4/fou_core.c @@ -351,7 +351,7 @@ static struct sk_buff *gue_gro_receive(struct sock *sk, optlen = guehdr->hlen << 2; len += optlen; - if (skb_gro_header_hard(skb, len)) { + if (!skb_gro_may_pull(skb, len)) { guehdr = skb_gro_header_slow(skb, len, off); if (unlikely(!guehdr)) goto out; diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 311e70bfce40..5028c72d494a 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -174,7 +174,7 @@ static struct sk_buff *gre_gro_receive(struct list_head *head, grehlen += GRE_HEADER_SECTION; hlen = off + grehlen; - if (skb_gro_header_hard(skb, hlen)) { + if (!skb_gro_may_pull(skb, hlen)) { greh = skb_gro_header_slow(skb, hlen, off); if (unlikely(!greh)) goto out; diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 8311c38267b5..875456efc92d 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -204,7 +204,7 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb) goto out; hlen = off + thlen; - if (skb_gro_header_hard(skb, hlen)) { + if (!skb_gro_may_pull(skb, hlen)) { th = skb_gro_header_slow(skb, hlen, off); if (unlikely(!th)) goto out; From bd56a29c7a4ebcd3ca69505a2e676449e60965f3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 1 Mar 2024 19:37:38 +0000 Subject: [PATCH 1848/2255] net: gro: change skb_gro_network_header() Change skb_gro_network_header() to accept a const sk_buff and to no longer check if frag0 is NULL or not. This allows to remove skb_gro_frag0_invalidate() which is seen in profiles when header-split is enabled. sk_buff parameter is constified for skb_gro_header_fast(), inet_gro_compute_pseudo() and ip6_gro_compute_pseudo(). Signed-off-by: Eric Dumazet Acked-by: Paolo Abeni Signed-off-by: Paolo Abeni --- include/net/gro.h | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/include/net/gro.h b/include/net/gro.h index ffc2c96d263b..3c3666e46b30 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -139,7 +139,7 @@ static inline void skb_gro_pull(struct sk_buff *skb, unsigned int len) NAPI_GRO_CB(skb)->data_offset += len; } -static inline void *skb_gro_header_fast(struct sk_buff *skb, +static inline void *skb_gro_header_fast(const struct sk_buff *skb, unsigned int offset) { return NAPI_GRO_CB(skb)->frag0 + offset; @@ -151,24 +151,17 @@ static inline bool skb_gro_may_pull(const struct sk_buff *skb, return hlen <= NAPI_GRO_CB(skb)->frag0_len; } -static inline void skb_gro_frag0_invalidate(struct sk_buff *skb) -{ - NAPI_GRO_CB(skb)->frag0 = NULL; - NAPI_GRO_CB(skb)->frag0_len = 0; -} - static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen, unsigned int offset) { if (!pskb_may_pull(skb, hlen)) return NULL; - skb_gro_frag0_invalidate(skb); return skb->data + offset; } -static inline void *skb_gro_header(struct sk_buff *skb, - unsigned int hlen, unsigned int offset) +static inline void *skb_gro_header(struct sk_buff *skb, unsigned int hlen, + unsigned int offset) { void *ptr; @@ -178,13 +171,16 @@ static inline void *skb_gro_header(struct sk_buff *skb, return ptr; } -static inline void *skb_gro_network_header(struct sk_buff *skb) +static inline void *skb_gro_network_header(const struct sk_buff *skb) { - return (NAPI_GRO_CB(skb)->frag0 ?: skb->data) + - skb_network_offset(skb); + if (skb_gro_may_pull(skb, skb_gro_offset(skb))) + return skb_gro_header_fast(skb, skb_network_offset(skb)); + + return skb_network_header(skb); } -static inline __wsum inet_gro_compute_pseudo(struct sk_buff *skb, int proto) +static inline __wsum inet_gro_compute_pseudo(const struct sk_buff *skb, + int proto) { const struct iphdr *iph = skb_gro_network_header(skb); @@ -422,7 +418,8 @@ static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb) return uh; } -static inline __wsum ip6_gro_compute_pseudo(struct sk_buff *skb, int proto) +static inline __wsum ip6_gro_compute_pseudo(const struct sk_buff *skb, + int proto) { const struct ipv6hdr *iph = skb_gro_network_header(skb); From c7583e9f768eeb82f2531c8372584ba89cfade8b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 1 Mar 2024 19:37:39 +0000 Subject: [PATCH 1849/2255] net: gro: enable fast path for more cases Currently the so-called GRO fast path is only enabled for napi_frags_skb() callers. After the prior patch, we no longer have to clear frag0 whenever we pulled bytes to skb->head. We therefore can initialize frag0 to skb->data so that GRO fast path can be used in the following additional cases: - Drivers using header split (populating skb->data with headers, and having payload in one or more page fragments). - Drivers not using any page frag (entire packet is in skb->data) Add a likely() in skb_gro_may_pull() to help the compiler to generate better code if possible. Signed-off-by: Eric Dumazet Acked-by: Paolo Abeni Signed-off-by: Paolo Abeni --- include/net/gro.h | 2 +- net/core/gro.c | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/net/gro.h b/include/net/gro.h index 3c3666e46b30..2b58671a6549 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -148,7 +148,7 @@ static inline void *skb_gro_header_fast(const struct sk_buff *skb, static inline bool skb_gro_may_pull(const struct sk_buff *skb, unsigned int hlen) { - return hlen <= NAPI_GRO_CB(skb)->frag0_len; + return likely(hlen <= NAPI_GRO_CB(skb)->frag0_len); } static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen, diff --git a/net/core/gro.c b/net/core/gro.c index 927ccf681490..6a0edbd826a1 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -369,15 +369,21 @@ static void gro_list_prepare(const struct list_head *head, static inline void skb_gro_reset_offset(struct sk_buff *skb, u32 nhoff) { - const struct skb_shared_info *pinfo = skb_shinfo(skb); - const skb_frag_t *frag0 = &pinfo->frags[0]; + const struct skb_shared_info *pinfo; + const skb_frag_t *frag0; + unsigned int headlen; NAPI_GRO_CB(skb)->data_offset = 0; - NAPI_GRO_CB(skb)->frag0 = NULL; - NAPI_GRO_CB(skb)->frag0_len = 0; + headlen = skb_headlen(skb); + NAPI_GRO_CB(skb)->frag0 = skb->data; + NAPI_GRO_CB(skb)->frag0_len = headlen; + if (headlen) + return; - if (!skb_headlen(skb) && pinfo->nr_frags && - !PageHighMem(skb_frag_page(frag0)) && + pinfo = skb_shinfo(skb); + frag0 = &pinfo->frags[0]; + + if (pinfo->nr_frags && !PageHighMem(skb_frag_page(frag0)) && (!NET_IP_ALIGN || !((skb_frag_off(frag0) + nhoff) & 3))) { NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int, @@ -710,7 +716,10 @@ static struct sk_buff *napi_frags_skb(struct napi_struct *napi) } } else { eth = (const struct ethhdr *)skb->data; - gro_pull_from_frag0(skb, hlen); + + if (NAPI_GRO_CB(skb)->frag0 != skb->data) + gro_pull_from_frag0(skb, hlen); + NAPI_GRO_CB(skb)->frag0 += hlen; NAPI_GRO_CB(skb)->frag0_len -= hlen; } From 8f78010b701d8fdc290063f29fefc09aaaca4085 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 1 Mar 2024 19:37:40 +0000 Subject: [PATCH 1850/2255] tcp: gro: micro optimizations in tcp[4]_gro_complete() In tcp_gro_complete() : Moving the skb->inner_transport_header setting allows the compiler to reuse the previously loaded value of skb->transport_header. Caching skb_shinfo() avoids duplications as well. In tcp4_gro_complete(), doing a single change on skb_shinfo(skb)->gso_type also generates better code. Signed-off-by: Eric Dumazet Acked-by: Paolo Abeni Signed-off-by: Paolo Abeni --- net/ipv4/tcp_offload.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 875456efc92d..b955ab3b236d 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -299,18 +299,20 @@ out: void tcp_gro_complete(struct sk_buff *skb) { struct tcphdr *th = tcp_hdr(skb); + struct skb_shared_info *shinfo; + + if (skb->encapsulation) + skb->inner_transport_header = skb->transport_header; skb->csum_start = (unsigned char *)th - skb->head; skb->csum_offset = offsetof(struct tcphdr, check); skb->ip_summed = CHECKSUM_PARTIAL; - skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count; + shinfo = skb_shinfo(skb); + shinfo->gso_segs = NAPI_GRO_CB(skb)->count; if (th->cwr) - skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; - - if (skb->encapsulation) - skb->inner_transport_header = skb->transport_header; + shinfo->gso_type |= SKB_GSO_TCP_ECN; } EXPORT_SYMBOL(tcp_gro_complete); @@ -335,10 +337,9 @@ INDIRECT_CALLABLE_SCOPE int tcp4_gro_complete(struct sk_buff *skb, int thoff) th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr, iph->daddr, 0); - skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4; - if (NAPI_GRO_CB(skb)->is_atomic) - skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_FIXEDID; + skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4 | + (NAPI_GRO_CB(skb)->is_atomic * SKB_GSO_TCP_FIXEDID); tcp_gro_complete(skb); return 0; From 885c36e59f46375c138de18ff1692f18eff67b7f Mon Sep 17 00:00:00 2001 From: Abhishek Chauhan Date: Fri, 1 Mar 2024 12:13:48 -0800 Subject: [PATCH 1851/2255] net: Re-use and set mono_delivery_time bit for userspace tstamp packets Bridge driver today has no support to forward the userspace timestamp packets and ends up resetting the timestamp. ETF qdisc checks the packet coming from userspace and encounters to be 0 thereby dropping time sensitive packets. These changes will allow userspace timestamps packets to be forwarded from the bridge to NIC drivers. Setting the same bit (mono_delivery_time) to avoid dropping of userspace tstamp packets in the forwarding path. Existing functionality of mono_delivery_time remains unaltered here, instead just extended with userspace tstamp support for bridge forwarding path. Signed-off-by: Abhishek Chauhan Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20240301201348.2815102-1-quic_abchauha@quicinc.com Signed-off-by: Paolo Abeni --- include/linux/skbuff.h | 6 +++--- net/ipv4/ip_output.c | 1 + net/ipv4/raw.c | 1 + net/ipv6/ip6_output.c | 2 +- net/ipv6/raw.c | 2 +- net/packet/af_packet.c | 4 +++- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d577e0bee18d..3013355b63f5 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -822,9 +822,9 @@ typedef unsigned char *sk_buff_data_t; * @decrypted: Decrypted SKB * @slow_gro: state present at GRO time, slower prepare step required * @mono_delivery_time: When set, skb->tstamp has the - * delivery_time in mono clock base (i.e. EDT). Otherwise, the - * skb->tstamp has the (rcv) timestamp at ingress and - * delivery_time at egress. + * delivery_time in mono clock base (i.e., EDT) or a clock base chosen + * by SO_TXTIME. If zero, skb->tstamp has the (rcv) timestamp at + * ingress. * @napi_id: id of the NAPI struct this skb came from * @sender_cpu: (aka @napi_id) source CPU in XPS * @alloc_cpu: CPU which did the skb allocation. diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 1fe794967211..33f93dc730a3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1458,6 +1458,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk, skb->priority = (cork->tos != -1) ? cork->priority: READ_ONCE(sk->sk_priority); skb->mark = cork->mark; skb->tstamp = cork->transmit_time; + skb->mono_delivery_time = !!skb->tstamp; /* * Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec * on dst refcount diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index a82fd102df05..494a6284bd7e 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -353,6 +353,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->priority = READ_ONCE(sk->sk_priority); skb->mark = sockc->mark; skb->tstamp = sockc->transmit_time; + skb->mono_delivery_time = !!skb->tstamp; skb_dst_set(skb, &rt->dst); *rtp = NULL; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index b9dd3a66e423..02eeca5492cd 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1925,7 +1925,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk, skb->priority = READ_ONCE(sk->sk_priority); skb->mark = cork->base.mark; skb->tstamp = cork->base.transmit_time; - + skb->mono_delivery_time = !!skb->tstamp; ip6_cork_steal_dst(skb, cork); IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); if (proto == IPPROTO_ICMPV6) { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 76e6eb3b643d..779274055abf 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -615,7 +615,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, skb->priority = READ_ONCE(sk->sk_priority); skb->mark = sockc->mark; skb->tstamp = sockc->transmit_time; - + skb->mono_delivery_time = !!skb->tstamp; skb_put(skb, length); skb_reset_network_header(skb); iph = ipv6_hdr(skb); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c9bbc2686690..0db31ca4982d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2057,7 +2057,7 @@ retry: skb->priority = READ_ONCE(sk->sk_priority); skb->mark = READ_ONCE(sk->sk_mark); skb->tstamp = sockc.transmit_time; - + skb->mono_delivery_time = !!skb->tstamp; skb_setup_tx_timestamp(skb, sockc.tsflags); if (unlikely(extra_len == 4)) @@ -2586,6 +2586,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, skb->priority = READ_ONCE(po->sk.sk_priority); skb->mark = READ_ONCE(po->sk.sk_mark); skb->tstamp = sockc->transmit_time; + skb->mono_delivery_time = !!skb->tstamp; skb_setup_tx_timestamp(skb, sockc->tsflags); skb_zcopy_set_nouarg(skb, ph.raw); @@ -3064,6 +3065,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) skb->priority = READ_ONCE(sk->sk_priority); skb->mark = sockc.mark; skb->tstamp = sockc.transmit_time; + skb->mono_delivery_time = !!skb->tstamp; if (unlikely(extra_len == 4)) skb->no_fcs = 1; From 00af2aa93b76b1bade471ad0d0525d4d29ca5cc0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 2 Mar 2024 10:07:44 +0000 Subject: [PATCH 1852/2255] net/smc: reduce rtnl pressure in smc_pnet_create_pnetids_list() Many syzbot reports show extreme rtnl pressure, and many of them hint that smc acquires rtnl in netns creation for no good reason [1] This patch returns early from smc_pnet_net_init() if there is no netdevice yet. I am not even sure why smc_pnet_create_pnetids_list() even exists, because smc_pnet_netdev_event() is also calling smc_pnet_add_base_pnetid() when handling NETDEV_UP event. [1] extract of typical syzbot reports 2 locks held by syz-executor.3/12252: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.4/12253: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.1/12257: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.2/12261: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.0/12265: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.3/12268: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.4/12271: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.1/12274: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 2 locks held by syz-executor.2/12280: #0: ffffffff8f369610 (pernet_ops_rwsem){++++}-{3:3}, at: copy_net_ns+0x4c7/0x7b0 net/core/net_namespace.c:491 #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_create_pnetids_list net/smc/smc_pnet.c:809 [inline] #1: ffffffff8f375b88 (rtnl_mutex){+.+.}-{3:3}, at: smc_pnet_net_init+0x10a/0x1e0 net/smc/smc_pnet.c:878 Signed-off-by: Eric Dumazet Cc: Wenjia Zhang Cc: Jan Karcher Cc: "D. Wythe" Cc: Tony Lu Cc: Wen Gu Reviewed-by: Wenjia Zhang Link: https://lore.kernel.org/r/20240302100744.3868021-1-edumazet@google.com Signed-off-by: Paolo Abeni --- net/smc/smc_pnet.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 9f2c58c5a86b..2adb92b8c469 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c @@ -806,6 +806,16 @@ static void smc_pnet_create_pnetids_list(struct net *net) u8 ndev_pnetid[SMC_MAX_PNETID_LEN]; struct net_device *dev; + /* Newly created netns do not have devices. + * Do not even acquire rtnl. + */ + if (list_empty(&net->dev_base_head)) + return; + + /* Note: This might not be needed, because smc_pnet_netdev_event() + * is also calling smc_pnet_add_base_pnetid() when handling + * NETDEV_UP event. + */ rtnl_lock(); for_each_netdev(net, dev) smc_pnet_add_base_pnetid(net, dev, ndev_pnetid); From 7b2d64f93319e0d03c1b68ecfdccd5d168cb5c31 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 4 Mar 2024 11:56:07 +0200 Subject: [PATCH 1853/2255] selftests: forwarding: Remove IPv6 L3 multipath hash tests The multipath tests currently test both the L3 and L4 multipath hash policies for IPv6, but only the L4 policy for IPv4. The reason is mostly historic: When the initial multipath test was added (router_multipath.sh) the IPv6 L4 policy did not exist and was later added to the test. The other multipath tests copied this pattern although there is little value in testing both policies. Align the IPv4 and IPv6 tests and only test the L4 policy. On my system, this reduces the run time of router_multipath.sh by 89% because of the repeated ping6 invocations to randomize the flow label. Signed-off-by: Ido Schimmel Link: https://lore.kernel.org/r/20240304095612.462900-2-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/forwarding/gre_multipath_nh.sh | 37 ------------------ .../net/forwarding/gre_multipath_nh_res.sh | 38 ------------------ .../net/forwarding/router_mpath_nh.sh | 35 +---------------- .../net/forwarding/router_multipath.sh | 39 +------------------ 4 files changed, 2 insertions(+), 147 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh b/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh index d03aa2cab9fd..62281898e7a4 100755 --- a/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh +++ b/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh @@ -64,7 +64,6 @@ ALL_TESTS=" ping_ipv6 multipath_ipv4 multipath_ipv6 - multipath_ipv6_l4 " NUM_NETIFS=6 @@ -264,34 +263,6 @@ multipath6_test() local weight1=$1; shift local weight2=$1; shift - sysctl_set net.ipv6.fib_multipath_hash_policy 0 - ip nexthop replace id 103 group 101,$weight1/102,$weight2 - - local t0_111=$(tc_rule_stats_get $ul2 111 ingress) - local t0_222=$(tc_rule_stats_get $ul2 222 ingress) - - # Generate 16384 echo requests, each with a random flow label. - for ((i=0; i < 16384; ++i)); do - ip vrf exec v$h1 $PING6 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null - done - - local t1_111=$(tc_rule_stats_get $ul2 111 ingress) - local t1_222=$(tc_rule_stats_get $ul2 222 ingress) - - local d111=$((t1_111 - t0_111)) - local d222=$((t1_222 - t0_222)) - multipath_eval "$what" $weight1 $weight2 $d111 $d222 - - ip nexthop replace id 103 group 101/102 - sysctl_restore net.ipv6.fib_multipath_hash_policy -} - -multipath6_l4_test() -{ - local what=$1; shift - local weight1=$1; shift - local weight2=$1; shift - sysctl_set net.ipv6.fib_multipath_hash_policy 1 ip nexthop replace id 103 group 101,$weight1/102,$weight2 @@ -339,14 +310,6 @@ multipath_ipv6() multipath6_test "Weighted MP 11:45" 11 45 } -multipath_ipv6_l4() -{ - log_info "Running IPv6 L4 hash multipath tests" - multipath6_l4_test "ECMP" 1 1 - multipath6_l4_test "Weighted MP 2:1" 2 1 - multipath6_l4_test "Weighted MP 11:45" 11 45 -} - trap cleanup EXIT setup_prepare diff --git a/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh b/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh index 088b65e64d66..2085111bcd67 100755 --- a/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh +++ b/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh @@ -64,7 +64,6 @@ ALL_TESTS=" ping_ipv6 multipath_ipv4 multipath_ipv6 - multipath_ipv6_l4 " NUM_NETIFS=6 @@ -267,35 +266,6 @@ multipath6_test() local weight1=$1; shift local weight2=$1; shift - sysctl_set net.ipv6.fib_multipath_hash_policy 0 - ip nexthop replace id 103 group 101,$weight1/102,$weight2 \ - type resilient - - local t0_111=$(tc_rule_stats_get $ul2 111 ingress) - local t0_222=$(tc_rule_stats_get $ul2 222 ingress) - - # Generate 16384 echo requests, each with a random flow label. - for ((i=0; i < 16384; ++i)); do - ip vrf exec v$h1 $PING6 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null - done - - local t1_111=$(tc_rule_stats_get $ul2 111 ingress) - local t1_222=$(tc_rule_stats_get $ul2 222 ingress) - - local d111=$((t1_111 - t0_111)) - local d222=$((t1_222 - t0_222)) - multipath_eval "$what" $weight1 $weight2 $d111 $d222 - - ip nexthop replace id 103 group 101/102 type resilient - sysctl_restore net.ipv6.fib_multipath_hash_policy -} - -multipath6_l4_test() -{ - local what=$1; shift - local weight1=$1; shift - local weight2=$1; shift - sysctl_set net.ipv6.fib_multipath_hash_policy 1 ip nexthop replace id 103 group 101,$weight1/102,$weight2 \ type resilient @@ -344,14 +314,6 @@ multipath_ipv6() multipath6_test "Weighted MP 11:45" 11 45 } -multipath_ipv6_l4() -{ - log_info "Running IPv6 L4 hash multipath tests" - multipath6_l4_test "ECMP" 1 1 - multipath6_l4_test "Weighted MP 2:1" 2 1 - multipath6_l4_test "Weighted MP 11:45" 11 45 -} - trap cleanup EXIT setup_prepare diff --git a/tools/testing/selftests/net/forwarding/router_mpath_nh.sh b/tools/testing/selftests/net/forwarding/router_mpath_nh.sh index a0d612e04990..2ef469ff3bc4 100755 --- a/tools/testing/selftests/net/forwarding/router_mpath_nh.sh +++ b/tools/testing/selftests/net/forwarding/router_mpath_nh.sh @@ -218,7 +218,7 @@ multipath4_test() sysctl_restore net.ipv4.fib_multipath_hash_policy } -multipath6_l4_test() +multipath6_test() { local desc="$1" local weight_rp12=$2 @@ -251,34 +251,6 @@ multipath6_l4_test() sysctl_restore net.ipv6.fib_multipath_hash_policy } -multipath6_test() -{ - local desc="$1" - local weight_rp12=$2 - local weight_rp13=$3 - local t0_rp12 t0_rp13 t1_rp12 t1_rp13 - local packets_rp12 packets_rp13 - - ip nexthop replace id 106 group 104,$weight_rp12/105,$weight_rp13 - - t0_rp12=$(link_stats_tx_packets_get $rp12) - t0_rp13=$(link_stats_tx_packets_get $rp13) - - # Generate 16384 echo requests, each with a random flow label. - for _ in $(seq 1 16384); do - ip vrf exec vrf-h1 $PING6 2001:db8:2::2 -F 0 -c 1 -q >/dev/null 2>&1 - done - - t1_rp12=$(link_stats_tx_packets_get $rp12) - t1_rp13=$(link_stats_tx_packets_get $rp13) - - let "packets_rp12 = $t1_rp12 - $t0_rp12" - let "packets_rp13 = $t1_rp13 - $t0_rp13" - multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 - - ip nexthop replace id 106 group 104/105 -} - multipath_test() { log_info "Running IPv4 multipath tests" @@ -301,11 +273,6 @@ multipath_test() multipath6_test "ECMP" 1 1 multipath6_test "Weighted MP 2:1" 2 1 multipath6_test "Weighted MP 11:45" 11 45 - - log_info "Running IPv6 L4 hash multipath tests" - multipath6_l4_test "ECMP" 1 1 - multipath6_l4_test "Weighted MP 2:1" 2 1 - multipath6_l4_test "Weighted MP 11:45" 11 45 } ping_ipv4_blackhole() diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 464821c587a5..a4eceeb5c06e 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -195,7 +195,7 @@ multipath4_test() sysctl_restore net.ipv4.fib_multipath_hash_policy } -multipath6_l4_test() +multipath6_test() { local desc="$1" local weight_rp12=$2 @@ -232,38 +232,6 @@ multipath6_l4_test() sysctl_restore net.ipv6.fib_multipath_hash_policy } -multipath6_test() -{ - local desc="$1" - local weight_rp12=$2 - local weight_rp13=$3 - local t0_rp12 t0_rp13 t1_rp12 t1_rp13 - local packets_rp12 packets_rp13 - - ip route replace 2001:db8:2::/64 vrf vrf-r1 \ - nexthop via fe80:2::22 dev $rp12 weight $weight_rp12 \ - nexthop via fe80:3::23 dev $rp13 weight $weight_rp13 - - t0_rp12=$(link_stats_tx_packets_get $rp12) - t0_rp13=$(link_stats_tx_packets_get $rp13) - - # Generate 16384 echo requests, each with a random flow label. - for _ in $(seq 1 16384); do - ip vrf exec vrf-h1 $PING6 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null - done - - t1_rp12=$(link_stats_tx_packets_get $rp12) - t1_rp13=$(link_stats_tx_packets_get $rp13) - - let "packets_rp12 = $t1_rp12 - $t0_rp12" - let "packets_rp13 = $t1_rp13 - $t0_rp13" - multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 - - ip route replace 2001:db8:2::/64 vrf vrf-r1 \ - nexthop via fe80:2::22 dev $rp12 \ - nexthop via fe80:3::23 dev $rp13 -} - multipath_test() { log_info "Running IPv4 multipath tests" @@ -275,11 +243,6 @@ multipath_test() multipath6_test "ECMP" 1 1 multipath6_test "Weighted MP 2:1" 2 1 multipath6_test "Weighted MP 11:45" 11 45 - - log_info "Running IPv6 L4 hash multipath tests" - multipath6_l4_test "ECMP" 1 1 - multipath6_l4_test "Weighted MP 2:1" 2 1 - multipath6_l4_test "Weighted MP 11:45" 11 45 } setup_prepare() From 748d27447daa3f2bdf519f2a97647ff69fd1b70b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 4 Mar 2024 11:56:08 +0200 Subject: [PATCH 1854/2255] selftests: forwarding: Parametrize mausezahn delay The various multipath tests use mausezahn to generate different flows and check how they are distributed between the available nexthops. The tool is currently invoked with an hard coded transmission delay of 1 ms. This is unnecessary when the tests are run with veth pairs and needlessly prolongs the tests. Parametrize this delay and default it to 0 us. It can be overridden using the forwarding.config file. On my system, this reduces the run time of router_multipath.sh by 93%. Signed-off-by: Ido Schimmel Link: https://lore.kernel.org/r/20240304095612.462900-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/forwarding/custom_multipath_hash.sh | 16 ++++++++-------- .../net/forwarding/forwarding.config.sample | 2 ++ .../net/forwarding/gre_custom_multipath_hash.sh | 16 ++++++++-------- .../net/forwarding/gre_inner_v4_multipath.sh | 2 +- .../net/forwarding/gre_inner_v6_multipath.sh | 2 +- .../selftests/net/forwarding/gre_multipath.sh | 2 +- .../selftests/net/forwarding/gre_multipath_nh.sh | 4 ++-- .../net/forwarding/gre_multipath_nh_res.sh | 4 ++-- .../forwarding/ip6gre_custom_multipath_hash.sh | 16 ++++++++-------- .../net/forwarding/ip6gre_inner_v4_multipath.sh | 2 +- .../net/forwarding/ip6gre_inner_v6_multipath.sh | 2 +- .../selftests/net/forwarding/ip6gre_lib.sh | 4 ++-- tools/testing/selftests/net/forwarding/lib.sh | 1 + .../selftests/net/forwarding/router_mpath_nh.sh | 4 ++-- .../net/forwarding/router_mpath_nh_res.sh | 4 ++-- .../selftests/net/forwarding/router_multipath.sh | 4 ++-- 16 files changed, 44 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/custom_multipath_hash.sh b/tools/testing/selftests/net/forwarding/custom_multipath_hash.sh index 56eb83d1a3bd..1783c10215e5 100755 --- a/tools/testing/selftests/net/forwarding/custom_multipath_hash.sh +++ b/tools/testing/selftests/net/forwarding/custom_multipath_hash.sh @@ -183,42 +183,42 @@ send_src_ipv4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A "198.51.100.2-198.51.100.253" -B 203.0.113.2 \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_dst_ipv4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B "203.0.113.2-203.0.113.253" \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_src_udp4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B 203.0.113.2 \ - -d 1msec -t udp "sp=0-32768,dp=30000" + -d $MZ_DELAY -t udp "sp=0-32768,dp=30000" } send_dst_udp4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B 203.0.113.2 \ - -d 1msec -t udp "sp=20000,dp=0-32768" + -d $MZ_DELAY -t udp "sp=20000,dp=0-32768" } send_src_ipv6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A "2001:db8:1::2-2001:db8:1::fd" -B 2001:db8:4::2 \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_dst_ipv6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B "2001:db8:4::2-2001:db8:4::fd" \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_flowlabel() @@ -234,14 +234,14 @@ send_src_udp6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B 2001:db8:4::2 \ - -d 1msec -t udp "sp=0-32768,dp=30000" + -d $MZ_DELAY -t udp "sp=0-32768,dp=30000" } send_dst_udp6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B 2001:db8:4::2 \ - -d 1msec -t udp "sp=20000,dp=0-32768" + -d $MZ_DELAY -t udp "sp=20000,dp=0-32768" } custom_hash_test() diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample index 4a546509de90..1fc4f0242fc5 100644 --- a/tools/testing/selftests/net/forwarding/forwarding.config.sample +++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample @@ -28,6 +28,8 @@ PING=ping PING6=ping6 # Packet generator. Some distributions use 'mz'. MZ=mausezahn +# mausezahn delay between transmissions in microseconds. +MZ_DELAY=0 # Time to wait after interfaces participating in the test are all UP WAIT_TIME=5 # Whether to pause on failure or not. diff --git a/tools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh b/tools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh index 0446db9c6f74..9788bd0f6e8b 100755 --- a/tools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh +++ b/tools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh @@ -278,42 +278,42 @@ send_src_ipv4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A "198.51.100.2-198.51.100.253" -B 203.0.113.2 \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_dst_ipv4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B "203.0.113.2-203.0.113.253" \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_src_udp4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B 203.0.113.2 \ - -d 1msec -t udp "sp=0-32768,dp=30000" + -d $MZ_DELAY -t udp "sp=0-32768,dp=30000" } send_dst_udp4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B 203.0.113.2 \ - -d 1msec -t udp "sp=20000,dp=0-32768" + -d $MZ_DELAY -t udp "sp=20000,dp=0-32768" } send_src_ipv6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A "2001:db8:1::2-2001:db8:1::fd" -B 2001:db8:2::2 \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_dst_ipv6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B "2001:db8:2::2-2001:db8:2::fd" \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_flowlabel() @@ -329,14 +329,14 @@ send_src_udp6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=0-32768,dp=30000" + -d $MZ_DELAY -t udp "sp=0-32768,dp=30000" } send_dst_udp6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=20000,dp=0-32768" + -d $MZ_DELAY -t udp "sp=20000,dp=0-32768" } custom_hash_test() diff --git a/tools/testing/selftests/net/forwarding/gre_inner_v4_multipath.sh b/tools/testing/selftests/net/forwarding/gre_inner_v4_multipath.sh index e4009f658003..efca6114a3ce 100755 --- a/tools/testing/selftests/net/forwarding/gre_inner_v4_multipath.sh +++ b/tools/testing/selftests/net/forwarding/gre_inner_v4_multipath.sh @@ -267,7 +267,7 @@ multipath4_test() ip vrf exec v$h1 \ $MZ $h1 -q -p 64 -A "192.0.3.2-192.0.3.62" -B "192.0.4.2-192.0.4.62" \ - -d 1msec -c 50 -t udp "sp=1024,dp=1024" + -d $MZ_DELAY -c 50 -t udp "sp=1024,dp=1024" sleep 1 local t1_111=$(tc_rule_stats_get $ul32 111 ingress) diff --git a/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh b/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh index e449475c4d3e..e5e911ce1562 100755 --- a/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh +++ b/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh @@ -268,7 +268,7 @@ multipath6_test() ip vrf exec v$h1 \ $MZ $h1 -6 -q -p 64 -A "2001:db8:1::2-2001:db8:1::1e" \ -B "2001:db8:2::2-2001:db8:2::1e" \ - -d 1msec -c 50 -t udp "sp=1024,dp=1024" + -d $MZ_DELAY -c 50 -t udp "sp=1024,dp=1024" sleep 1 local t1_111=$(tc_rule_stats_get $ul32 111 ingress) diff --git a/tools/testing/selftests/net/forwarding/gre_multipath.sh b/tools/testing/selftests/net/forwarding/gre_multipath.sh index a8d8e8b3dc81..57531c1d884d 100755 --- a/tools/testing/selftests/net/forwarding/gre_multipath.sh +++ b/tools/testing/selftests/net/forwarding/gre_multipath.sh @@ -220,7 +220,7 @@ multipath4_test() ip vrf exec v$h1 \ $MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" local t1_111=$(tc_rule_stats_get $ul2 111 ingress) local t1_222=$(tc_rule_stats_get $ul2 222 ingress) diff --git a/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh b/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh index 62281898e7a4..7d5b2b9cc133 100755 --- a/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh +++ b/tools/testing/selftests/net/forwarding/gre_multipath_nh.sh @@ -244,7 +244,7 @@ multipath4_test() ip vrf exec v$h1 \ $MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" local t1_111=$(tc_rule_stats_get $ul2 111 ingress) local t1_222=$(tc_rule_stats_get $ul2 222 ingress) @@ -271,7 +271,7 @@ multipath6_test() ip vrf exec v$h1 \ $MZ $h1 -6 -q -p 64 -A 2001:db8:1::1 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" local t1_111=$(tc_rule_stats_get $ul2 111 ingress) local t1_222=$(tc_rule_stats_get $ul2 222 ingress) diff --git a/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh b/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh index 2085111bcd67..370f9925302d 100755 --- a/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh +++ b/tools/testing/selftests/net/forwarding/gre_multipath_nh_res.sh @@ -247,7 +247,7 @@ multipath4_test() ip vrf exec v$h1 \ $MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" local t1_111=$(tc_rule_stats_get $ul2 111 ingress) local t1_222=$(tc_rule_stats_get $ul2 222 ingress) @@ -275,7 +275,7 @@ multipath6_test() ip vrf exec v$h1 \ $MZ $h1 -6 -q -p 64 -A 2001:db8:1::1 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" local t1_111=$(tc_rule_stats_get $ul2 111 ingress) local t1_222=$(tc_rule_stats_get $ul2 222 ingress) diff --git a/tools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh b/tools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh index d40183b4eccc..2ab9eaaa5532 100755 --- a/tools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh +++ b/tools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh @@ -280,42 +280,42 @@ send_src_ipv4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A "198.51.100.2-198.51.100.253" -B 203.0.113.2 \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_dst_ipv4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B "203.0.113.2-203.0.113.253" \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_src_udp4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B 203.0.113.2 \ - -d 1msec -t udp "sp=0-32768,dp=30000" + -d $MZ_DELAY -t udp "sp=0-32768,dp=30000" } send_dst_udp4() { ip vrf exec v$h1 $MZ $h1 -q -p 64 \ -A 198.51.100.2 -B 203.0.113.2 \ - -d 1msec -t udp "sp=20000,dp=0-32768" + -d $MZ_DELAY -t udp "sp=20000,dp=0-32768" } send_src_ipv6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A "2001:db8:1::2-2001:db8:1::fd" -B 2001:db8:2::2 \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_dst_ipv6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B "2001:db8:2::2-2001:db8:2::fd" \ - -d 1msec -c 50 -t udp "sp=20000,dp=30000" + -d $MZ_DELAY -c 50 -t udp "sp=20000,dp=30000" } send_flowlabel() @@ -331,14 +331,14 @@ send_src_udp6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=0-32768,dp=30000" + -d $MZ_DELAY -t udp "sp=0-32768,dp=30000" } send_dst_udp6() { ip vrf exec v$h1 $MZ -6 $h1 -q -p 64 \ -A 2001:db8:1::2 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=20000,dp=0-32768" + -d $MZ_DELAY -t udp "sp=20000,dp=0-32768" } custom_hash_test() diff --git a/tools/testing/selftests/net/forwarding/ip6gre_inner_v4_multipath.sh b/tools/testing/selftests/net/forwarding/ip6gre_inner_v4_multipath.sh index a257979d3fc5..32d1461f37b7 100755 --- a/tools/testing/selftests/net/forwarding/ip6gre_inner_v4_multipath.sh +++ b/tools/testing/selftests/net/forwarding/ip6gre_inner_v4_multipath.sh @@ -266,7 +266,7 @@ multipath4_test() ip vrf exec v$h1 \ $MZ $h1 -q -p 64 -A "192.0.3.2-192.0.3.62" -B "192.0.4.2-192.0.4.62" \ - -d 1msec -c 50 -t udp "sp=1024,dp=1024" + -d $MZ_DELAY -c 50 -t udp "sp=1024,dp=1024" sleep 1 local t1_111=$(tc_rule_stats_get $ul32 111 ingress) diff --git a/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh b/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh index d208f5243ade..eb4e50df5337 100755 --- a/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh +++ b/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh @@ -267,7 +267,7 @@ multipath6_test() ip vrf exec v$h1 \ $MZ $h1 -6 -q -p 64 -A "2001:db8:1::2-2001:db8:1::1e" \ -B "2001:db8:2::2-2001:db8:2::1e" \ - -d 1msec -c 50 -t udp "sp=1024,dp=1024" + -d $MZ_DELAY -c 50 -t udp "sp=1024,dp=1024" sleep 1 local t1_111=$(tc_rule_stats_get $ul32 111 ingress) diff --git a/tools/testing/selftests/net/forwarding/ip6gre_lib.sh b/tools/testing/selftests/net/forwarding/ip6gre_lib.sh index 58a3597037b1..24f4ab328bd2 100644 --- a/tools/testing/selftests/net/forwarding/ip6gre_lib.sh +++ b/tools/testing/selftests/net/forwarding/ip6gre_lib.sh @@ -356,7 +356,7 @@ test_traffic_ip4ip6() flower $TC_FLAG dst_ip 203.0.113.1 action pass $MZ $h1 -c 1000 -p 64 -a $h1mac -b $ol1mac -A 198.51.100.1 \ - -B 203.0.113.1 -t ip -q -d 1msec + -B 203.0.113.1 -t ip -q -d $MZ_DELAY # Check ports after encap and after decap. tc_check_at_least_x_packets "dev $ul1 egress" 101 1000 @@ -389,7 +389,7 @@ test_traffic_ip6ip6() flower $TC_FLAG dst_ip 2001:db8:2::1 action pass $MZ -6 $h1 -c 1000 -p 64 -a $h1mac -b $ol1mac -A 2001:db8:1::1 \ - -B 2001:db8:2::1 -t ip -q -d 1msec + -B 2001:db8:2::1 -t ip -q -d $MZ_DELAY # Check ports after encap and after decap. tc_check_at_least_x_packets "dev $ul1 egress" 101 1000 diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index db3688f52888..d1bf39eaf2b3 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -8,6 +8,7 @@ PING=${PING:=ping} PING6=${PING6:=ping6} MZ=${MZ:=mausezahn} +MZ_DELAY=${MZ_DELAY:=0} ARPING=${ARPING:=arping} TEAMD=${TEAMD:=teamd} WAIT_TIME=${WAIT_TIME:=5} diff --git a/tools/testing/selftests/net/forwarding/router_mpath_nh.sh b/tools/testing/selftests/net/forwarding/router_mpath_nh.sh index 2ef469ff3bc4..982e0d098ea9 100755 --- a/tools/testing/selftests/net/forwarding/router_mpath_nh.sh +++ b/tools/testing/selftests/net/forwarding/router_mpath_nh.sh @@ -204,7 +204,7 @@ multipath4_test() t0_rp13=$(link_stats_tx_packets_get $rp13) ip vrf exec vrf-h1 $MZ $h1 -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" t1_rp12=$(link_stats_tx_packets_get $rp12) t1_rp13=$(link_stats_tx_packets_get $rp13) @@ -237,7 +237,7 @@ multipath6_test() t0_rp13=$(link_stats_tx_packets_get $rp13) $MZ $h1 -6 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" t1_rp12=$(link_stats_tx_packets_get $rp12) t1_rp13=$(link_stats_tx_packets_get $rp13) diff --git a/tools/testing/selftests/net/forwarding/router_mpath_nh_res.sh b/tools/testing/selftests/net/forwarding/router_mpath_nh_res.sh index cb08ffe2356a..a60ff54723b7 100755 --- a/tools/testing/selftests/net/forwarding/router_mpath_nh_res.sh +++ b/tools/testing/selftests/net/forwarding/router_mpath_nh_res.sh @@ -205,7 +205,7 @@ multipath4_test() t0_rp13=$(link_stats_tx_packets_get $rp13) ip vrf exec vrf-h1 $MZ $h1 -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" t1_rp12=$(link_stats_tx_packets_get $rp12) t1_rp13=$(link_stats_tx_packets_get $rp13) @@ -235,7 +235,7 @@ multipath6_l4_test() t0_rp13=$(link_stats_tx_packets_get $rp13) $MZ $h1 -6 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" t1_rp12=$(link_stats_tx_packets_get $rp12) t1_rp13=$(link_stats_tx_packets_get $rp13) diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index a4eceeb5c06e..e2be354167a1 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -179,7 +179,7 @@ multipath4_test() t0_rp13=$(link_stats_tx_packets_get $rp13) ip vrf exec vrf-h1 $MZ $h1 -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" t1_rp12=$(link_stats_tx_packets_get $rp12) t1_rp13=$(link_stats_tx_packets_get $rp13) @@ -216,7 +216,7 @@ multipath6_test() t0_rp13=$(link_stats_tx_packets_get $rp13) $MZ $h1 -6 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \ - -d 1msec -t udp "sp=1024,dp=0-32768" + -d $MZ_DELAY -t udp "sp=1024,dp=0-32768" t1_rp12=$(link_stats_tx_packets_get $rp12) t1_rp13=$(link_stats_tx_packets_get $rp13) From 4aca9eae6f7bfea30467fce6b1062f1bf5f21e9b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 4 Mar 2024 11:56:09 +0200 Subject: [PATCH 1855/2255] selftests: forwarding: Make tc-police pass on debug kernels The test configures a policer with a rate of 80Mbps and expects to measure a rate close to it. This is a too high rate for debug kernels, causing the test to fail [1]. Fix by reducing the rate to 10Mbps. [1] # ./tc_police.sh TEST: police on rx [FAIL] Expected rate 76.2Mbps, got 29.6Mbps, which is -61% off. Required accuracy is +-10%. TEST: police on tx [FAIL] Expected rate 76.2Mbps, got 30.4Mbps, which is -60% off. Required accuracy is +-10%. Signed-off-by: Ido Schimmel Link: https://lore.kernel.org/r/20240304095612.462900-4-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../selftests/net/forwarding/tc_police.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/tc_police.sh b/tools/testing/selftests/net/forwarding/tc_police.sh index 0a51eef21b9e..5103f64a71d6 100755 --- a/tools/testing/selftests/net/forwarding/tc_police.sh +++ b/tools/testing/selftests/net/forwarding/tc_police.sh @@ -140,7 +140,7 @@ police_common_test() sleep 10 local t1=$(tc_rule_stats_get $h2 1 ingress .bytes) - local er=$((80 * 1000 * 1000)) + local er=$((10 * 1000 * 1000)) local nr=$(rate $t0 $t1 10) local nr_pct=$((100 * (nr - er) / er)) ((-10 <= nr_pct && nr_pct <= 10)) @@ -157,7 +157,7 @@ police_rx_test() # Rule to police traffic destined to $h2 on ingress of $rp1 tc filter add dev $rp1 ingress protocol ip pref 1 handle 101 flower \ dst_ip 198.51.100.1 ip_proto udp dst_port 54321 \ - action police rate 80mbit burst 16k conform-exceed drop/ok + action police rate 10mbit burst 16k conform-exceed drop/ok police_common_test "police on rx" @@ -169,7 +169,7 @@ police_tx_test() # Rule to police traffic destined to $h2 on egress of $rp2 tc filter add dev $rp2 egress protocol ip pref 1 handle 101 flower \ dst_ip 198.51.100.1 ip_proto udp dst_port 54321 \ - action police rate 80mbit burst 16k conform-exceed drop/ok + action police rate 10mbit burst 16k conform-exceed drop/ok police_common_test "police on tx" @@ -190,7 +190,7 @@ police_shared_common_test() sleep 10 local t1=$(tc_rule_stats_get $h2 1 ingress .bytes) - local er=$((80 * 1000 * 1000)) + local er=$((10 * 1000 * 1000)) local nr=$(rate $t0 $t1 10) local nr_pct=$((100 * (nr - er) / er)) ((-10 <= nr_pct && nr_pct <= 10)) @@ -211,7 +211,7 @@ police_shared_test() # Rule to police traffic destined to $h2 on ingress of $rp1 tc filter add dev $rp1 ingress protocol ip pref 1 handle 101 flower \ dst_ip 198.51.100.1 ip_proto udp dst_port 54321 \ - action police rate 80mbit burst 16k conform-exceed drop/ok \ + action police rate 10mbit burst 16k conform-exceed drop/ok \ index 10 # Rule to police a different flow destined to $h2 on egress of $rp2 @@ -250,7 +250,7 @@ police_mirror_common_test() # Rule to police traffic destined to $h2 and mirror to $h3 tc filter add dev $pol_if $dir protocol ip pref 1 handle 101 flower \ dst_ip 198.51.100.1 ip_proto udp dst_port 54321 \ - action police rate 80mbit burst 16k conform-exceed drop/pipe \ + action police rate 10mbit burst 16k conform-exceed drop/pipe \ action mirred egress mirror dev $rp3 mausezahn $h1 -a own -b $(mac_get $rp1) -A 192.0.2.1 -B 198.51.100.1 \ @@ -260,7 +260,7 @@ police_mirror_common_test() sleep 10 local t1=$(tc_rule_stats_get $h2 1 ingress .bytes) - local er=$((80 * 1000 * 1000)) + local er=$((10 * 1000 * 1000)) local nr=$(rate $t0 $t1 10) local nr_pct=$((100 * (nr - er) / er)) ((-10 <= nr_pct && nr_pct <= 10)) @@ -270,7 +270,7 @@ police_mirror_common_test() sleep 10 local t1=$(tc_rule_stats_get $h3 1 ingress .bytes) - local er=$((80 * 1000 * 1000)) + local er=$((10 * 1000 * 1000)) local nr=$(rate $t0 $t1 10) local nr_pct=$((100 * (nr - er) / er)) ((-10 <= nr_pct && nr_pct <= 10)) From dfbab74044be66852ebb9d4b2cbef2f082e82531 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 4 Mar 2024 11:56:10 +0200 Subject: [PATCH 1856/2255] selftests: forwarding: Make vxlan-bridge-1q pass on debug kernels The ageing time used by the test is too short for debug kernels and results in entries being aged out prematurely [1]. Fix by increasing the ageing time. [1] # ./vxlan_bridge_1q.sh [...] INFO: learning vlan 10 TEST: VXLAN: flood before learning [ OK ] TEST: VXLAN: show learned FDB entry [ OK ] TEST: VXLAN: learned FDB entry [FAIL] swp4: Expected to capture 0 packets, got 10. RTNETLINK answers: No such file or directory TEST: VXLAN: deletion of learned FDB entry [ OK ] TEST: VXLAN: Ageing of learned FDB entry [FAIL] swp4: Expected to capture 0 packets, got 10. TEST: VXLAN: learning toggling on bridge port [ OK ] [...] Signed-off-by: Ido Schimmel Link: https://lore.kernel.org/r/20240304095612.462900-5-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../selftests/net/forwarding/vxlan_bridge_1q.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1q.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1q.sh index a596bbf3ed6a..fb9a34cb50c6 100755 --- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1q.sh +++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1q.sh @@ -750,7 +750,7 @@ __test_learning() expects[0]=0; expects[$idx1]=10; expects[$idx2]=0 vxlan_flood_test $mac $dst $vid "${expects[@]}" - sleep 20 + sleep 60 bridge fdb show brport $vx | grep $mac | grep -q self check_fail $? @@ -796,11 +796,11 @@ test_learning() local dst=192.0.2.100 local vid=10 - # Enable learning on the VxLAN devices and set ageing time to 10 seconds - ip link set dev br1 type bridge ageing_time 1000 - ip link set dev vx10 type vxlan ageing 10 + # Enable learning on the VxLAN devices and set ageing time to 30 seconds + ip link set dev br1 type bridge ageing_time 3000 + ip link set dev vx10 type vxlan ageing 30 ip link set dev vx10 type vxlan learning - ip link set dev vx20 type vxlan ageing 10 + ip link set dev vx20 type vxlan ageing 30 ip link set dev vx20 type vxlan learning reapply_config From f0008b04977a741b2fb9c5e220120f82a0e50aa8 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 4 Mar 2024 11:56:11 +0200 Subject: [PATCH 1857/2255] selftests: forwarding: Make VXLAN ECN encap tests more robust These tests sometimes fail on the netdev CI because the expected number of packets is larger than expected [1]. Make the tests more robust by specifically matching on VXLAN encapsulated packets and allowing up to five stray packets instead of just two. [1] [...] # TEST: VXLAN: ECN encap: 0x00->0x00 [FAIL] # v1: Expected to capture 10 packets, got 13. # TEST: VXLAN: ECN encap: 0x01->0x01 [ OK ] # TEST: VXLAN: ECN encap: 0x02->0x02 [ OK ] # TEST: VXLAN: ECN encap: 0x03->0x02 [ OK ] [...] Signed-off-by: Ido Schimmel Link: https://lore.kernel.org/r/20240304095612.462900-6-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh | 4 ++-- .../testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh index eb307ca37bfa..6f0a2e452ba1 100755 --- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh +++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh @@ -495,7 +495,7 @@ vxlan_ping_test() local delta=$((t1 - t0)) # Tolerate a couple stray extra packets. - ((expect <= delta && delta <= expect + 2)) + ((expect <= delta && delta <= expect + 5)) check_err $? "$capture_dev: Expected to capture $expect packets, got $delta." } @@ -532,7 +532,7 @@ __test_ecn_encap() RET=0 tc filter add dev v1 egress pref 77 prot ip \ - flower ip_tos $tos action pass + flower ip_tos $tos ip_proto udp dst_port $VXPORT action pass sleep 1 vxlan_ping_test $h1 192.0.2.3 "-Q $q" v1 egress 77 10 tc filter del dev v1 egress pref 77 prot ip diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh index ac97f07e5ce8..a0bb4524e1e9 100755 --- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh +++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh @@ -616,7 +616,7 @@ vxlan_ping_test() local delta=$((t1 - t0)) # Tolerate a couple stray extra packets. - ((expect <= delta && delta <= expect + 2)) + ((expect <= delta && delta <= expect + 5)) check_err $? "$capture_dev: Expected to capture $expect packets, got $delta." } @@ -653,7 +653,7 @@ __test_ecn_encap() RET=0 tc filter add dev v1 egress pref 77 protocol ipv6 \ - flower ip_tos $tos action pass + flower ip_tos $tos ip_proto udp dst_port $VXPORT action pass sleep 1 vxlan_ping_test $h1 2001:db8:1::3 "-Q $q" v1 egress 77 10 tc filter del dev v1 egress pref 77 protocol ipv6 From 35df2ce896dc098554152db063aff1b52e09457a Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 4 Mar 2024 11:56:12 +0200 Subject: [PATCH 1858/2255] selftests: forwarding: Make {, ip6}gre-inner-v6-multipath tests more robust These tests generate various IPv6 flows, encapsulate them in GRE packets and check that the encapsulated packets are distributed between the available nexthops according to the configured weights. Unlike the corresponding IPv4 tests, these tests sometimes fail in the netdev CI because of large discrepancies between the expected and measured ratios [1]. This can be explained by the fact that the IPv4 tests generate about 3,600 different flows whereas the IPv6 tests only generate about 784 different flows (potentially by mistake). Fix by aligning the IPv6 tests to the IPv4 ones and increase the number of generated flows. [1] [...] # TEST: ping [ OK ] # INFO: Running IPv6 over GRE over IPv4 multipath tests # TEST: ECMP [FAIL] # Too large discrepancy between expected and measured ratios # INFO: Expected ratio 1.00 Measured ratio 1.18 [...] Signed-off-by: Ido Schimmel Link: https://lore.kernel.org/r/20240304095612.462900-7-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../selftests/net/forwarding/gre_inner_v6_multipath.sh | 4 ++-- .../selftests/net/forwarding/ip6gre_inner_v6_multipath.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh b/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh index e5e911ce1562..a71ad39fc0c3 100755 --- a/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh +++ b/tools/testing/selftests/net/forwarding/gre_inner_v6_multipath.sh @@ -266,8 +266,8 @@ multipath6_test() local t0_222=$(tc_rule_stats_get $ul32 222 ingress) ip vrf exec v$h1 \ - $MZ $h1 -6 -q -p 64 -A "2001:db8:1::2-2001:db8:1::1e" \ - -B "2001:db8:2::2-2001:db8:2::1e" \ + $MZ $h1 -6 -q -p 64 -A "2001:db8:1::2-2001:db8:1::3e" \ + -B "2001:db8:2::2-2001:db8:2::3e" \ -d $MZ_DELAY -c 50 -t udp "sp=1024,dp=1024" sleep 1 diff --git a/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh b/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh index eb4e50df5337..e1a4b50505f5 100755 --- a/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh +++ b/tools/testing/selftests/net/forwarding/ip6gre_inner_v6_multipath.sh @@ -265,8 +265,8 @@ multipath6_test() local t0_222=$(tc_rule_stats_get $ul32 222 ingress) ip vrf exec v$h1 \ - $MZ $h1 -6 -q -p 64 -A "2001:db8:1::2-2001:db8:1::1e" \ - -B "2001:db8:2::2-2001:db8:2::1e" \ + $MZ $h1 -6 -q -p 64 -A "2001:db8:1::2-2001:db8:1::3e" \ + -B "2001:db8:2::2-2001:db8:2::3e" \ -d $MZ_DELAY -c 50 -t udp "sp=1024,dp=1024" sleep 1 From b8a62478f3b143592d1241de1a7f5f8629ad0f49 Mon Sep 17 00:00:00 2001 From: Nick Morrow Date: Tue, 27 Feb 2024 02:34:40 +0000 Subject: [PATCH 1859/2255] wifi: rtw88: Add missing VID/PIDs for 8811CU and 8821CU Add VID/PIDs that are known to be missing for this driver. Removed /* 8811CU */ and /* 8821CU */ as they are redundant since the file is specific to those chips. Removed /* TOTOLINK A650UA v3 */ as the manufacturer. It has a REALTEK VID so it may not be specific to this adapter. Verified and tested. Cc: stable@vger.kernel.org Signed-off-by: Nick Morrow Signed-off-by: Larry Finger Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/4ume7mjw63u7.XlMUvUuacW2ErhOCdqlLkw2@1EHFQ.trk.elasticemail.com --- .../net/wireless/realtek/rtw88/rtw8821cu.c | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c index 7a5cbdc31ef7..e2c7d9f87683 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c @@ -9,24 +9,36 @@ #include "usb.h" static const struct usb_device_id rtw_8821cu_id_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82b, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb820, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc821, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc820, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82a, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82b, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc811, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */ - { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8811, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2006, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* TOTOLINK A650UA v3 */ + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8731, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8811, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb820, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc80c, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc811, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc820, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc821, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82a, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82c, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331d, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* D-Link */ + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xc811, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */ + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd811, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */ {}, }; MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table); From 41a7acb7dde8395f52a707bbba7712a898dfafb0 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Fri, 1 Mar 2024 00:32:45 +0200 Subject: [PATCH 1860/2255] wifi: rtw88: 8821cu: Fix firmware upload fail RTL8822CU, RTL8822BU, and RTL8821CU need an extra register write after reading and writing certain addresses. Without this, the firmware upload fails approximately more than 50% of the time. Tested with RTL8811CU (Tenda U9 V2.0) which is the same as RTL8821CU but without Bluetooth. Fixes: a82dfd33d123 ("wifi: rtw88: Add common USB chip support") Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/f12ed39d-28e8-4b8b-8d22-447bcf295afc@gmail.com --- drivers/net/wireless/realtek/rtw88/usb.c | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index e6ab1ac6d709..a0188511099a 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -33,6 +33,36 @@ static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb, rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data); } +static void rtw_usb_reg_sec(struct rtw_dev *rtwdev, u32 addr, __le32 *data) +{ + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); + struct usb_device *udev = rtwusb->udev; + bool reg_on_section = false; + u16 t_reg = 0x4e0; + u8 t_len = 1; + int status; + + /* There are three sections: + * 1. on (0x00~0xFF; 0x1000~0x10FF): this section is always powered on + * 2. off (< 0xFE00, excluding "on" section): this section could be + * powered off + * 3. local (>= 0xFE00): usb specific registers section + */ + if (addr <= 0xff || (addr >= 0x1000 && addr <= 0x10ff)) + reg_on_section = true; + + if (!reg_on_section) + return; + + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, + t_reg, 0, data, t_len, 500); + + if (status != t_len && status != -ENODEV) + rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n", + __func__, t_reg, t_len, status); +} + static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) { struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); @@ -58,6 +88,11 @@ static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) rtw_err(rtwdev, "read register 0x%x failed with %d\n", addr, ret); + if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || + rtwdev->chip->id == RTW_CHIP_TYPE_8822B || + rtwdev->chip->id == RTW_CHIP_TYPE_8821C) + rtw_usb_reg_sec(rtwdev, addr, data); + return le32_to_cpu(*data); } @@ -102,6 +137,11 @@ static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len) if (ret < 0 && ret != -ENODEV && count++ < 4) rtw_err(rtwdev, "write register 0x%x failed with %d\n", addr, ret); + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || + rtwdev->chip->id == RTW_CHIP_TYPE_8822B || + rtwdev->chip->id == RTW_CHIP_TYPE_8821C) + rtw_usb_reg_sec(rtwdev, addr, data); } static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) From 605d7c0b05eecb985273b1647070497142c470d3 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Fri, 1 Mar 2024 00:34:13 +0200 Subject: [PATCH 1861/2255] wifi: rtw88: 8821cu: Fix connection failure Clear bit 8 of REG_SYS_STATUS1 after MAC power on. Without this, some RTL8821CU and RTL8811CU cannot connect to any network: Feb 19 13:33:11 ideapad2 kernel: wlp3s0f3u2: send auth to 90:55:de:__:__:__ (try 1/3) Feb 19 13:33:13 ideapad2 kernel: wlp3s0f3u2: send auth to 90:55:de:__:__:__ (try 2/3) Feb 19 13:33:14 ideapad2 kernel: wlp3s0f3u2: send auth to 90:55:de:__:__:__ (try 3/3) Feb 19 13:33:15 ideapad2 kernel: wlp3s0f3u2: authentication with 90:55:de:__:__:__ timed out The RTL8822CU and RTL8822BU out-of-tree drivers do this as well, so do it for all three types of chips. Tested with RTL8811CU (Tenda U9 V2.0). Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/aeeefad9-27c8-4506-a510-ef9a9a8731a4@gmail.com --- drivers/net/wireless/realtek/rtw88/mac.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 298663b03580..0c1c1ff31085 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -309,6 +309,13 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq; ret = rtw_pwr_seq_parser(rtwdev, pwr_seq); + if (pwr_on && rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB) { + if (chip->id == RTW_CHIP_TYPE_8822C || + chip->id == RTW_CHIP_TYPE_8822B || + chip->id == RTW_CHIP_TYPE_8821C) + rtw_write8_clr(rtwdev, REG_SYS_STATUS1 + 1, BIT(0)); + } + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) rtw_write32(rtwdev, REG_SDIO_HIMR, imr); From e1dfa21427baeb813f9a2f9ceab6b7d32c3ca425 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Fri, 1 Mar 2024 00:35:09 +0200 Subject: [PATCH 1862/2255] wifi: rtw88: 8821c: Fix beacon loss and disconnect Tenda U9 V2.0, which contains RTL8811CU, is practically unusable because of frequent disconnections: Feb 23 14:46:45 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-BEACON-LOSS Feb 23 14:46:46 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-DISCONNECTED bssid=90:55:de:__:__:__ reason=4 locally_generated=1 Feb 23 14:46:52 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-CONNECTED - Connection to 90:55:de:__:__:__ completed [id=0 id_str=] Feb 23 14:46:54 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-BEACON-LOSS Feb 23 14:46:55 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-DISCONNECTED bssid=90:55:de:__:__:__ reason=4 locally_generated=1 Feb 23 14:47:01 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-CONNECTED - Connection to 90:55:de:__:__:__ completed [id=0 id_str=] Feb 23 14:47:04 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-BEACON-LOSS Feb 23 14:47:05 ideapad2 wpa_supplicant[427]: wlp3s0f3u2: CTRL-EVENT-DISCONNECTED bssid=90:55:de:__:__:__ reason=4 locally_generated=1 This is caused by a mistake in the chip initialisation. This version of the chip requires loading an extra AGC table right after the main one, but the extra table is being loaded at the wrong time, in rtw_chip_board_info_setup(). Move the extra AGC table loading to the right place, in rtw_phy_load_tables(). The rtw_chip_board_info_setup() can only do "software" things, and rtw_phy_load_tables() can really do IO. Fixes: 5d6651fe8583 ("rtw88: 8821c: support RFE type2 wifi NIC") Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/276c31d8-b9a8-4e54-a3ac-09b74657aff7@gmail.com --- drivers/net/wireless/realtek/rtw88/main.c | 2 -- drivers/net/wireless/realtek/rtw88/phy.c | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 6d22628129d0..ffba6b88f392 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -2032,8 +2032,6 @@ static int rtw_chip_board_info_setup(struct rtw_dev *rtwdev) rtw_phy_setup_phy_cond(rtwdev, hal->pkg_type); rtw_phy_init_tx_power(rtwdev); - if (rfe_def->agc_btg_tbl) - rtw_load_table(rtwdev, rfe_def->agc_btg_tbl); rtw_load_table(rtwdev, rfe_def->phy_pg_tbl); rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl); rtw_phy_tx_power_by_rate_config(hal); diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 128e75a81bf3..37ef80c9091d 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -1761,12 +1761,15 @@ static void rtw_load_rfk_table(struct rtw_dev *rtwdev) void rtw_phy_load_tables(struct rtw_dev *rtwdev) { + const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); const struct rtw_chip_info *chip = rtwdev->chip; u8 rf_path; rtw_load_table(rtwdev, chip->mac_tbl); rtw_load_table(rtwdev, chip->bb_tbl); rtw_load_table(rtwdev, chip->agc_tbl); + if (rfe_def->agc_btg_tbl) + rtw_load_table(rtwdev, rfe_def->agc_btg_tbl); rtw_load_rfk_table(rtwdev); for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) { From c238adbc578eeb70cbc8fdd1bef3666b0f585b13 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Fri, 1 Mar 2024 00:35:58 +0200 Subject: [PATCH 1863/2255] wifi: rtw88: 8821c: Fix false alarm count total_fa_cnt is supposed to include cck_fa_cnt and ofdm_fa_cnt, not just ofdm_fa_cnt. Fixes: 960361238b86 ("rtw88: 8821c: add false alarm statistics") Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/f3cb6d17-e4e4-44a7-9c9b-72aed994b5c9@gmail.com --- drivers/net/wireless/realtek/rtw88/rtw8821c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index 429bb420b056..fe5d8e188350 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -773,9 +773,9 @@ static void rtw8821c_false_alarm_statistics(struct rtw_dev *rtwdev) dm_info->cck_fa_cnt = cck_fa_cnt; dm_info->ofdm_fa_cnt = ofdm_fa_cnt; + dm_info->total_fa_cnt = ofdm_fa_cnt; if (cck_enable) dm_info->total_fa_cnt += cck_fa_cnt; - dm_info->total_fa_cnt = ofdm_fa_cnt; crc32_cnt = rtw_read32(rtwdev, REG_CRC_CCK); dm_info->cck_ok_cnt = FIELD_GET(GENMASK(15, 0), crc32_cnt); From 7979061313c81729b90accc8772635cfed9ba26d Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 27 Feb 2024 14:15:52 +0200 Subject: [PATCH 1864/2255] wifi: rtlwifi: Remove rtl_intf_ops.read_efuse_byte PCI drivers and USB drivers can both use the same function, read_efuse_byte(), and they can call it directly. rtl8192de was the only user. Tested only with the upcoming rtl8192du driver. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/4e2c968d-f25c-4a40-be97-4fdcbdde69cf@gmail.com --- drivers/net/wireless/realtek/rtlwifi/pci.c | 1 - drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c | 6 ++---- drivers/net/wireless/realtek/rtlwifi/wifi.h | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index d059cfe5a2a9..11709b6c83f1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -2374,7 +2374,6 @@ EXPORT_SYMBOL(rtl_pci_resume); #endif /* CONFIG_PM_SLEEP */ const struct rtl_intf_ops rtl_pci_ops = { - .read_efuse_byte = read_efuse_byte, .adapter_start = rtl_pci_start, .adapter_stop = rtl_pci_stop, .check_buddy_priv = rtl_pci_check_buddy_priv, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c index 743ac6871bf4..4ba42f6be3f2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c @@ -1669,10 +1669,8 @@ static void _rtl92de_efuse_update_chip_version(struct ieee80211_hw *hw) u8 cutvalue[2]; u16 chipvalue; - rtlpriv->intf_ops->read_efuse_byte(hw, EEPROME_CHIP_VERSION_H, - &cutvalue[1]); - rtlpriv->intf_ops->read_efuse_byte(hw, EEPROME_CHIP_VERSION_L, - &cutvalue[0]); + read_efuse_byte(hw, EEPROME_CHIP_VERSION_H, &cutvalue[1]); + read_efuse_byte(hw, EEPROME_CHIP_VERSION_L, &cutvalue[0]); chipvalue = (cutvalue[1] << 8) | cutvalue[0]; switch (chipvalue) { case 0xAA55: diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index f388d13e2ba8..9fabf597cfd6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2289,7 +2289,6 @@ struct rtl_hal_ops { struct rtl_intf_ops { /*com */ - void (*read_efuse_byte)(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); int (*adapter_start)(struct ieee80211_hw *hw); void (*adapter_stop)(struct ieee80211_hw *hw); bool (*check_buddy_priv)(struct ieee80211_hw *hw, From f6e36d9e1c6353b74f1511ea18aa7c6fddd6e697 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 28 Feb 2024 11:10:32 +0100 Subject: [PATCH 1865/2255] wifi: wlcore: sdio: Rate limit wl12xx_sdio_raw_{read,write}() failures warns When these failures happen, the warning and call trace is printed which is excessive. Instead, just print the error but rate limited to prevent warns to unnecessarily pollute the kernel log buffer and make the serial console practically unusable. For example, on an AM625 BeaglePlay board where accessing a SDIO WiFi chip fails with an -110 (ETIMEDOUT) error: $ dmesg | grep "sdio write\|read failed (-110)" | wc -l 39 Signed-off-by: Javier Martinez Canillas Reviewed-by: Breno Leitao Signed-off-by: Kalle Valo Link: https://msgid.link/20240228101042.728881-1-javierm@redhat.com --- drivers/net/wireless/ti/wlcore/sdio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 966edb39ad9e..92fb5b8dcdae 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -74,8 +74,8 @@ static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr, sdio_release_host(func); - if (WARN_ON(ret)) - dev_err(child->parent, "sdio read failed (%d)\n", ret); + if (ret) + dev_err_ratelimited(child->parent, "sdio read failed (%d)\n", ret); if (unlikely(dump)) { printk(KERN_DEBUG "wlcore_sdio: READ from 0x%04x\n", addr); @@ -119,8 +119,8 @@ static int __must_check wl12xx_sdio_raw_write(struct device *child, int addr, sdio_release_host(func); - if (WARN_ON(ret)) - dev_err(child->parent, "sdio write failed (%d)\n", ret); + if (ret) + dev_err_ratelimited(child->parent, "sdio write failed (%d)\n", ret); return ret; } From 81e060584f1deb7f89df5c0b7897a96409cf6c2a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Feb 2024 12:11:56 +0100 Subject: [PATCH 1866/2255] wifi: cw1200: restore endian swapping The code here looks well thought-out, so it seems likely that the byte-swaps are actually needed, due to SPI bus and device behaviour. Restore the byte-swapping, in a way that doesn't result in sparse warnings. Fixes: 7ceade653429 ("wifi: cw1200: fix __le16 sparse warnings") Signed-off-by: Johannes Berg Signed-off-by: Kalle Valo Link: https://msgid.link/20240228121156.62f820aa6dfb.Ia63314e4d0ed1ee76f100846d68f0722abf6b793@changeid --- drivers/net/wireless/st/cw1200/cw1200_spi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index fb3aafcafe18..4f346fb977a9 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -81,6 +81,9 @@ 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 = (__force u16)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 */ @@ -143,6 +146,9 @@ 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 = (__force u16)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 */ From 0cb01e0edf7829fa67b4d4c4e90003a61e182f60 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 29 Feb 2024 15:45:07 +0800 Subject: [PATCH 1867/2255] wifi: rtw89: mac: add coexistence helpers {cfg/get}_plt When hardware grant BT initially but transition to grant WiFi, the PLT (polluted) bit is set to assist coexistence mechanism to debug if grant signal is expected. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 8 +++- drivers/net/wireless/realtek/rtw89/mac.h | 22 ++++++++++- drivers/net/wireless/realtek/rtw89/mac_be.c | 41 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 14 +++++++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 908245ac46bd..288383ee6d1e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5615,7 +5615,8 @@ int rtw89_mac_cfg_gnt_v1(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_mac_cfg_gnt_v1); -int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) +static +int rtw89_mac_cfg_plt_ax(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) { u32 reg; u16 val; @@ -5711,7 +5712,7 @@ bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev) return !!val; } -u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band) +static u16 rtw89_mac_get_plt_cnt_ax(struct rtw89_dev *rtwdev, u8 band) { u32 reg; u16 cnt; @@ -6340,6 +6341,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .parse_phycap_map = rtw89_parse_phycap_map_ax, .cnv_efuse_state = rtw89_cnv_efuse_state_ax, + .cfg_plt = rtw89_mac_cfg_plt_ax, + .get_plt_cnt = rtw89_mac_get_plt_cnt_ax, + .get_txpwr_cr = rtw89_mac_get_txpwr_cr_ax, .write_xtal_si = rtw89_mac_write_xtal_si_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index db95509fad2f..721a57150378 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -958,6 +958,9 @@ struct rtw89_mac_gen_def { int (*parse_phycap_map)(struct rtw89_dev *rtwdev); int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle); + int (*cfg_plt)(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt); + u16 (*get_plt_cnt)(struct rtw89_dev *rtwdev, u8 band); + bool (*get_txpwr_cr)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr); @@ -1185,8 +1188,23 @@ int rtw89_mac_cfg_gnt(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); int rtw89_mac_cfg_gnt_v1(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); -int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt); -u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band); + +static inline +int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + return mac->cfg_plt(rtwdev, plt); +} + +static inline +u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + return mac->get_plt_cnt(rtwdev, band); +} + void rtw89_mac_cfg_sb(struct rtw89_dev *rtwdev, u32 val); u32 rtw89_mac_get_sb(struct rtw89_dev *rtwdev); bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 320e88229971..c68fef0f55f1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1797,6 +1797,44 @@ static int trx_init_be(struct rtw89_dev *rtwdev) return 0; } +static +int rtw89_mac_cfg_plt_be(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) +{ + u32 reg; + u16 val; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, plt->band, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_BT_PLT, plt->band); + val = (plt->tx & RTW89_MAC_AX_PLT_LTE_RX ? B_BE_TX_PLT_GNT_LTE_RX : 0) | + (plt->tx & RTW89_MAC_AX_PLT_GNT_BT_TX ? B_BE_TX_PLT_GNT_BT_TX : 0) | + (plt->tx & RTW89_MAC_AX_PLT_GNT_BT_RX ? B_BE_TX_PLT_GNT_BT_RX : 0) | + (plt->tx & RTW89_MAC_AX_PLT_GNT_WL ? B_BE_TX_PLT_GNT_WL : 0) | + (plt->rx & RTW89_MAC_AX_PLT_LTE_RX ? B_BE_RX_PLT_GNT_LTE_RX : 0) | + (plt->rx & RTW89_MAC_AX_PLT_GNT_BT_TX ? B_BE_RX_PLT_GNT_BT_TX : 0) | + (plt->rx & RTW89_MAC_AX_PLT_GNT_BT_RX ? B_BE_RX_PLT_GNT_BT_RX : 0) | + (plt->rx & RTW89_MAC_AX_PLT_GNT_WL ? B_BE_RX_PLT_GNT_WL : 0) | + B_BE_PLT_EN; + rtw89_write16(rtwdev, reg, val); + + return 0; +} + +static u16 rtw89_mac_get_plt_cnt_be(struct rtw89_dev *rtwdev, u8 band) +{ + u32 reg; + u16 cnt; + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_BT_PLT, band); + cnt = rtw89_read32_mask(rtwdev, reg, B_BE_BT_PLT_PKT_CNT_MASK); + rtw89_write16_set(rtwdev, reg, B_BE_BT_PLT_RST); + + return cnt; +} + static int rtw89_set_hw_sch_tx_en_v2(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en, u32 tx_en_mask) { @@ -2439,6 +2477,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .parse_phycap_map = rtw89_parse_phycap_map_be, .cnv_efuse_state = rtw89_cnv_efuse_state_be, + .cfg_plt = rtw89_mac_cfg_plt_be, + .get_plt_cnt = rtw89_mac_get_plt_cnt_be, + .get_txpwr_cr = rtw89_mac_get_txpwr_cr_be, .write_xtal_si = rtw89_mac_write_xtal_si_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 37ccd8ffa87a..c2751391044a 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -6457,6 +6457,20 @@ #define B_BE_PORT_DROP_4_0_MASK GENMASK(20, 16) #define B_BE_MBSSID_DROP_15_0_MASK GENMASK(15, 0) +#define R_BE_BT_PLT 0x1087C +#define R_BE_BT_PLT_C1 0x1487C +#define B_BE_BT_PLT_PKT_CNT_MASK GENMASK(31, 16) +#define B_BE_BT_PLT_RST BIT(9) +#define B_BE_PLT_EN BIT(8) +#define B_BE_RX_PLT_GNT_LTE_RX BIT(7) +#define B_BE_RX_PLT_GNT_BT_RX BIT(6) +#define B_BE_RX_PLT_GNT_BT_TX BIT(5) +#define B_BE_RX_PLT_GNT_WL BIT(4) +#define B_BE_TX_PLT_GNT_LTE_RX BIT(3) +#define B_BE_TX_PLT_GNT_BT_RX BIT(2) +#define B_BE_TX_PLT_GNT_BT_TX BIT(1) +#define B_BE_TX_PLT_GNT_WL BIT(0) + #define R_BE_PTCL_BSS_COLOR_0 0x108A0 #define R_BE_PTCL_BSS_COLOR_0_C1 0x148A0 #define B_BE_BSS_COLOB_BE_PORT_3_MASK GENMASK(29, 24) From d569f8545c7d01dfae4b2704b8b1bf9f9c10059c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 29 Feb 2024 15:45:08 +0800 Subject: [PATCH 1868/2255] wifi: rtw89: 8922a: add coexistence helpers of SW grant Under some circumstances, coexistence mechanism want to keep grant BT or WiFi, such as inquiry and WiFi is connecting, to ensure BT or WiFi can transmit or receive data in that period. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 6 ++ drivers/net/wireless/realtek/rtw89/mac.h | 3 + drivers/net/wireless/realtek/rtw89/mac_be.c | 76 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 28 +++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 + 5 files changed, 115 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index d62d23015c48..2bf1e4e95c0f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1151,9 +1151,15 @@ struct rtw89_mac_ax_gnt { u8 gnt_wl; } __packed; +struct rtw89_mac_ax_wl_act { + u8 wlan_act_en; + u8 wlan_act; +}; + #define RTW89_MAC_AX_COEX_GNT_NR 2 struct rtw89_mac_ax_coex_gnt { struct rtw89_mac_ax_gnt band[RTW89_MAC_AX_COEX_GNT_NR]; + struct rtw89_mac_ax_wl_act bt[RTW89_MAC_AX_COEX_GNT_NR]; }; enum rtw89_btc_ncnt { diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 721a57150378..c55b7e4918eb 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1188,6 +1188,8 @@ int rtw89_mac_cfg_gnt(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); int rtw89_mac_cfg_gnt_v1(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); +int rtw89_mac_cfg_gnt_v2(struct rtw89_dev *rtwdev, + const struct rtw89_mac_ax_coex_gnt *gnt_cfg); static inline int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) @@ -1210,6 +1212,7 @@ u32 rtw89_mac_get_sb(struct rtw89_dev *rtwdev); bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev); int rtw89_mac_cfg_ctrl_path(struct rtw89_dev *rtwdev, bool wl); int rtw89_mac_cfg_ctrl_path_v1(struct rtw89_dev *rtwdev, bool wl); +int rtw89_mac_cfg_ctrl_path_v2(struct rtw89_dev *rtwdev, bool wl); void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter); void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index c68fef0f55f1..7ca94b70a9cb 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1797,6 +1797,82 @@ static int trx_init_be(struct rtw89_dev *rtwdev) return 0; } +int rtw89_mac_cfg_gnt_v2(struct rtw89_dev *rtwdev, + const struct rtw89_mac_ax_coex_gnt *gnt_cfg) +{ + u32 val = 0; + + if (gnt_cfg->band[0].gnt_bt) + val |= B_BE_GNT_BT_BB0_VAL | B_BE_GNT_BT_RX_BB0_VAL | + B_BE_GNT_BT_TX_BB0_VAL; + + if (gnt_cfg->band[0].gnt_bt_sw_en) + val |= B_BE_GNT_BT_BB0_SWCTRL | B_BE_GNT_BT_RX_BB0_SWCTRL | + B_BE_GNT_BT_TX_BB0_SWCTRL; + + if (gnt_cfg->band[0].gnt_wl) + val |= B_BE_GNT_WL_BB0_VAL | B_BE_GNT_WL_RX_VAL | + B_BE_GNT_WL_TX_VAL | B_BE_GNT_WL_BB_PWR_VAL; + + if (gnt_cfg->band[0].gnt_wl_sw_en) + val |= B_BE_GNT_WL_BB0_SWCTRL | B_BE_GNT_WL_RX_SWCTRL | + B_BE_GNT_WL_TX_SWCTRL | B_BE_GNT_WL_BB_PWR_SWCTRL; + + if (gnt_cfg->band[1].gnt_bt) + val |= B_BE_GNT_BT_BB1_VAL | B_BE_GNT_BT_RX_BB1_VAL | + B_BE_GNT_BT_TX_BB1_VAL; + + if (gnt_cfg->band[1].gnt_bt_sw_en) + val |= B_BE_GNT_BT_BB1_SWCTRL | B_BE_GNT_BT_RX_BB1_SWCTRL | + B_BE_GNT_BT_TX_BB1_SWCTRL; + + if (gnt_cfg->band[1].gnt_wl) + val |= B_BE_GNT_WL_BB1_VAL | B_BE_GNT_WL_RX_VAL | + B_BE_GNT_WL_TX_VAL | B_BE_GNT_WL_BB_PWR_VAL; + + if (gnt_cfg->band[1].gnt_wl_sw_en) + val |= B_BE_GNT_WL_BB1_SWCTRL | B_BE_GNT_WL_RX_SWCTRL | + B_BE_GNT_WL_TX_SWCTRL | B_BE_GNT_WL_BB_PWR_SWCTRL; + + if (gnt_cfg->bt[0].wlan_act_en) + val |= B_BE_WL_ACT_SWCTRL; + if (gnt_cfg->bt[0].wlan_act) + val |= B_BE_WL_ACT_VAL; + if (gnt_cfg->bt[1].wlan_act_en) + val |= B_BE_WL_ACT2_SWCTRL; + if (gnt_cfg->bt[1].wlan_act) + val |= B_BE_WL_ACT2_VAL; + + rtw89_write32(rtwdev, R_BE_GNT_SW_CTRL, val); + + return 0; +} +EXPORT_SYMBOL(rtw89_mac_cfg_gnt_v2); + +int rtw89_mac_cfg_ctrl_path_v2(struct rtw89_dev *rtwdev, bool wl) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_mac_ax_gnt *g = dm->gnt.band; + struct rtw89_mac_ax_wl_act *gbt = dm->gnt.bt; + int i; + + if (wl) + return 0; + + for (i = 0; i < RTW89_PHY_MAX; i++) { + g[i].gnt_bt_sw_en = 1; + g[i].gnt_bt = 1; + g[i].gnt_wl_sw_en = 1; + g[i].gnt_wl = 0; + gbt[i].wlan_act = 1; + gbt[i].wlan_act_en = 0; + } + + return rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); +} +EXPORT_SYMBOL(rtw89_mac_cfg_ctrl_path_v2); + static int rtw89_mac_cfg_plt_be(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index c2751391044a..a7f7703a2556 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5932,6 +5932,34 @@ #define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2) #define B_BE_R_MACID_ACQ_CHK_EN BIT(0) +#define R_BE_GNT_SW_CTRL 0x0E348 +#define B_BE_WL_ACT2_VAL BIT(25) +#define B_BE_WL_ACT2_SWCTRL BIT(24) +#define B_BE_WL_ACT_VAL BIT(23) +#define B_BE_WL_ACT_SWCTRL BIT(22) +#define B_BE_GNT_BT_RX_BB1_VAL BIT(21) +#define B_BE_GNT_BT_RX_BB1_SWCTRL BIT(20) +#define B_BE_GNT_BT_TX_BB1_VAL BIT(19) +#define B_BE_GNT_BT_TX_BB1_SWCTRL BIT(18) +#define B_BE_GNT_BT_RX_BB0_VAL BIT(17) +#define B_BE_GNT_BT_RX_BB0_SWCTRL BIT(16) +#define B_BE_GNT_BT_TX_BB0_VAL BIT(15) +#define B_BE_GNT_BT_TX_BB0_SWCTRL BIT(14) +#define B_BE_GNT_WL_RX_VAL BIT(13) +#define B_BE_GNT_WL_RX_SWCTRL BIT(12) +#define B_BE_GNT_WL_TX_VAL BIT(11) +#define B_BE_GNT_WL_TX_SWCTRL BIT(10) +#define B_BE_GNT_BT_BB1_VAL BIT(9) +#define B_BE_GNT_BT_BB1_SWCTRL BIT(8) +#define B_BE_GNT_WL_BB1_VAL BIT(7) +#define B_BE_GNT_WL_BB1_SWCTRL BIT(6) +#define B_BE_GNT_BT_BB0_VAL BIT(5) +#define B_BE_GNT_BT_BB0_SWCTRL BIT(4) +#define B_BE_GNT_WL_BB0_VAL BIT(3) +#define B_BE_GNT_WL_BB0_SWCTRL BIT(2) +#define B_BE_GNT_WL_BB_PWR_VAL BIT(1) +#define B_BE_GNT_WL_BB_PWR_SWCTRL BIT(0) + #define R_BE_PWR_MACID_PATH_BASE 0x0E500 #define R_BE_PWR_MACID_LMT_BASE 0x0ED00 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 823f0d840df9..0e99ecea32a3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2246,6 +2246,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, + .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path_v2, + .mac_cfg_gnt = rtw89_mac_cfg_gnt_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, From 652c9642eda662b337b2408f81a2b4966c3e6d82 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Thu, 29 Feb 2024 15:45:09 +0800 Subject: [PATCH 1869/2255] wifi: rtw89: coex: add init_info H2C command format version 7 To avoid using bit fields for H2C command, rearrange the structure. And also patch the corresponding code for the using of this structure. No logic changes for existing chips. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 158 ++++++++++++------ drivers/net/wireless/realtek/rtw89/coex.h | 18 ++ drivers/net/wireless/realtek/rtw89/core.h | 67 +++++++- drivers/net/wireless/realtek/rtw89/fw.c | 42 ++++- drivers/net/wireless/realtek/rtw89/fw.h | 6 + drivers/net/wireless/realtek/rtw89/reg.h | 7 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 142 ++++++++++------ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 64 ++++--- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 64 ++++--- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 64 ++++--- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 110 ++++++++++++ 11 files changed, 582 insertions(+), 160 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index f37afb4cbb63..3ce4ce144b9e 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -129,67 +129,74 @@ static const u32 cxtbl[] = { static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { /* firmware version must be in decreasing order for each chip */ + {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), + .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, + .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, + .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, + .fwlrole = 2, .frptmap = 7, .fcxctrl = 7, .fcxinit = 7, + .info_buf = 1800, .max_role_num = 6, + }, {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, - .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, + .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1800, .max_role_num = 6, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, - .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, - .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, + .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, - .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, + .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, - .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, + .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1800, .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, - .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1800, .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, - .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, + .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, - .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, - .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, + .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .info_buf = 1024, .max_role_num = 5, }, @@ -198,7 +205,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, - .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, + .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .info_buf = 1024, .max_role_num = 5, }, }; @@ -777,22 +784,27 @@ static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val) { struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; - struct rtw89_btc_module *md = &btc->mdinfo; + union rtw89_btc_module_info *md = &btc->mdinfo; union rtw89_btc_fbtc_mreg_val *pmreg; u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1; u32 reg_val; - u8 idx; + u8 idx, switch_type; - if (md->ant.btg_pos == RF_PATH_A) + if (ver->fcxinit == 7) + switch_type = md->md_v7.switch_type; + else + switch_type = md->md.switch_type; + + if (btc->btg_pos == RF_PATH_A) pre_agc_addr = R_BTC_BB_PRE_AGC_S0; switch (type) { case BTC_CSTATUS_TXDIV_POS: - if (md->switch_type == BTC_SWITCH_INTERNAL) + if (switch_type == BTC_SWITCH_INTERNAL) *val = BTC_ANT_DIV_MAIN; break; case BTC_CSTATUS_RXDIV_POS: - if (md->switch_type == BTC_SWITCH_INTERNAL) + if (switch_type == BTC_SWITCH_INTERNAL) *val = BTC_ANT_DIV_MAIN; break; case BTC_CSTATUS_BB_GNT_MUX: @@ -2083,7 +2095,10 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) switch (type) { case CXDRVINFO_INIT: - rtw89_fw_h2c_cxdrv_init(rtwdev); + if (ver->fcxinit == 7) + rtw89_fw_h2c_cxdrv_init_v7(rtwdev); + else + rtw89_fw_h2c_cxdrv_init(rtwdev); break; case CXDRVINFO_ROLE: if (ver->fwlrole == 0) @@ -2333,7 +2348,7 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev) } /* decide trx_para_level */ - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { /* fix LNA2 + TIA gain not change by GNT_BT */ if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) || dm->bt_only == 1) @@ -2560,8 +2575,16 @@ static bool _check_freerun(struct rtw89_dev *rtwdev) struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; struct rtw89_btc_bt_hid_desc *hid = &bt_linfo->hid_desc; + union rtw89_btc_module_info *md = &btc->mdinfo; + const struct rtw89_btc_ver *ver = btc->ver; + u8 isolation; - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + if (ver->fcxinit == 7) + isolation = md->md_v7.ant.isolation; + else + isolation = md->md.ant.isolation; + + if (btc->ant_type == BTC_ANT_SHARED) { btc->dm.trx_para_level = 0; return false; } @@ -2584,7 +2607,7 @@ static bool _check_freerun(struct rtw89_dev *rtwdev) } /* TODO get isolation by BT psd */ - if (btc->mdinfo.ant.isolation >= BTC_FREERUN_ANTISO_MIN) { + if (isolation >= BTC_FREERUN_ANTISO_MIN) { btc->dm.trx_para_level = 5; return true; } @@ -2712,7 +2735,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type) u8 type; u32 tbl_w1, tbl_b1, tbl_b4; - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { if (btc->cx.wl.status.map._4way) tbl_w1 = cxtbl[1]; else @@ -3028,7 +3051,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) type = FIELD_GET(BTC_CXP_MASK, policy_type); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { if (btc->cx.wl.status.map._4way) tbl_w1 = cxtbl[1]; else if (hid->exist && hid->type == BTC_HID_218) @@ -3615,7 +3638,7 @@ static void _action_bt_idle(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ + if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */ switch (btc->cx.state_map) { case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/ case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */ @@ -3654,7 +3677,7 @@ static void _action_bt_hfp(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { if (btc->cx.wl.status.map._4way) { _set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_BT_HFP); } else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { @@ -3679,7 +3702,7 @@ static void _action_bt_hid(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ + if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */ if (wl->status.map._4way) { policy_type = BTC_CXP_OFF_WL; } else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { @@ -3947,7 +3970,7 @@ static void _action_wl_other(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) + if (btc->ant_type == BTC_ANT_SHARED) _set_policy(rtwdev, BTC_CXP_OFFB_BWB0, BTC_ACT_WL_OTHER); else _set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OTHER); @@ -4083,7 +4106,7 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) else if (ver->fwlrole == 2 && wl_rinfo->dbcc_en && wl_rinfo->dbcc_2g_phy != RTW89_PHY_1) is_preagc = BTC_PREAGC_DISABLE; - else if (btc->mdinfo.ant.type == BTC_ANT_SHARED) + else if (btc->ant_type == BTC_ANT_SHARED) is_preagc = BTC_PREAGC_DISABLE; else is_preagc = BTC_PREAGC_ENABLE; @@ -4402,7 +4425,7 @@ static void _action_wl_scan(struct rtw89_dev *rtwdev) if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) { _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) + if (btc->ant_type == BTC_ANT_SHARED) _set_policy(rtwdev, BTC_CXP_OFFE_DEF, BTC_RSN_NTFY_SCAN_START); else @@ -4430,7 +4453,7 @@ static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { if (btc->cx.bt.link_info.profile_cnt.now == 0) _set_policy(rtwdev, BTC_CXP_OFFE_DEF2, BTC_ACT_WL_25G_MCC); @@ -4447,7 +4470,7 @@ static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ + if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */ if (btc->cx.bt.link_info.profile_cnt.now == 0) _set_policy(rtwdev, BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_MCC); @@ -4465,7 +4488,7 @@ static void _action_wl_2g_scc(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ + if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */ if (btc->cx.bt.link_info.profile_cnt.now == 0) _set_policy(rtwdev, BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_SCC); @@ -4487,7 +4510,7 @@ static void _action_wl_2g_scc_v1(struct rtw89_dev *rtwdev) u16 policy_type = BTC_CXP_OFF_BT; u32 dur; - if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED) { + if (btc->ant_type == BTC_ANT_DEDICATED) { policy_type = BTC_CXP_OFF_EQ0; } else { /* shared-antenna */ @@ -4549,7 +4572,7 @@ static void _action_wl_2g_scc_v2(struct rtw89_dev *rtwdev) u16 policy_type = BTC_CXP_OFF_BT; u32 dur; - if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED) { + if (btc->ant_type == BTC_ANT_DEDICATED) { policy_type = BTC_CXP_OFF_EQ0; } else { /* shared-antenna */ @@ -4607,7 +4630,7 @@ static void _action_wl_2g_ap(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { if (btc->cx.bt.link_info.profile_cnt.now == 0) _set_policy(rtwdev, BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_AP); @@ -4624,7 +4647,7 @@ static void _action_wl_2g_go(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ + if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */ if (btc->cx.bt.link_info.profile_cnt.now == 0) _set_policy(rtwdev, BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_GO); @@ -4642,7 +4665,7 @@ static void _action_wl_2g_gc(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ + if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */ _action_by_bt(rtwdev); } else {/* dedicated-antenna */ _set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GC); @@ -4655,7 +4678,7 @@ static void _action_wl_2g_nan(struct rtw89_dev *rtwdev) _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); - if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */ + if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */ if (btc->cx.bt.link_info.profile_cnt.now == 0) _set_policy(rtwdev, BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_NAN); @@ -5560,16 +5583,26 @@ static void _set_init_info(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &btc->cx.wl; - dm->init_info.wl_only = (u8)dm->wl_only; - dm->init_info.bt_only = (u8)dm->bt_only; - dm->init_info.wl_init_ok = (u8)wl->status.map.init_ok; - dm->init_info.dbcc_en = rtwdev->dbcc_en; - dm->init_info.cx_other = btc->cx.other.type; - dm->init_info.wl_guard_ch = chip->afh_guard_ch; - dm->init_info.module = btc->mdinfo; + if (ver->fcxinit == 7) { + dm->init_info.init_v7.wl_only = (u8)dm->wl_only; + dm->init_info.init_v7.bt_only = (u8)dm->bt_only; + dm->init_info.init_v7.wl_init_ok = (u8)wl->status.map.init_ok; + dm->init_info.init_v7.cx_other = btc->cx.other.type; + dm->init_info.init_v7.wl_guard_ch = chip->afh_guard_ch; + dm->init_info.init_v7.module = btc->mdinfo.md_v7; + } else { + dm->init_info.init.wl_only = (u8)dm->wl_only; + dm->init_info.init.bt_only = (u8)dm->bt_only; + dm->init_info.init.wl_init_ok = (u8)wl->status.map.init_ok; + dm->init_info.init.dbcc_en = rtwdev->dbcc_en; + dm->init_info.init.cx_other = btc->cx.other.type; + dm->init_info.init.wl_guard_ch = chip->afh_guard_ch; + dm->init_info.init.module = btc->mdinfo.md; + } } void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode) @@ -6298,7 +6331,7 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) if (BTC_RSSI_LOW(link_info->rssi_state[i])) rssi_map |= BIT(i); - if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED && + if (btc->ant_type == BTC_ANT_DEDICATED && BTC_RSSI_CHANGE(link_info->rssi_state[i])) is_sta_change = true; } @@ -6489,13 +6522,16 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m) { + union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_btc_ver *ver = rtwdev->btc.ver; struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_wl_info *wl = &btc->cx.wl; u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0; + u8 cv, rfe, iso, ant_num, ant_single_pos; if (!(dm->coex_info_map & BTC_COEX_INFO_CX)) return; @@ -6545,11 +6581,24 @@ static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m) ver_main, ver_sub, ver_hotfix, id_branch, bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM"); + if (ver->fcxinit == 7) { + cv = md->md_v7.kt_ver; + rfe = md->md_v7.rfe_type; + iso = md->md_v7.ant.isolation; + ant_num = md->md_v7.ant.num; + ant_single_pos = md->md_v7.ant.single_pos; + } else { + cv = md->md.cv; + rfe = md->md.rfe_type; + iso = md->md.ant.isolation; + ant_num = md->md.ant.num; + ant_single_pos = md->md.ant.single_pos; + } + seq_printf(m, " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s", - "[hw_info]", btc->mdinfo.cv, btc->mdinfo.rfe_type, - btc->mdinfo.ant.isolation, btc->mdinfo.ant.num, - (btc->mdinfo.ant.num > 1 ? "" : (btc->mdinfo.ant.single_pos ? - "1Ant_Pos:S1, " : "1Ant_Pos:S0, "))); + "[hw_info]", cv, rfe, iso, ant_num, + ant_num > 1 ? "" : + ant_single_pos ? "1Ant_Pos:S1, " : "1Ant_Pos:S0, "); seq_printf(m, "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n", btc->cx.other.type, rtwdev->dbcc_en, hal->tx_nss, @@ -6722,20 +6771,26 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; struct rtw89_btc_wl_info *wl = &cx->wl; - struct rtw89_btc_module *module = &btc->mdinfo; struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; + union rtw89_btc_module_info *md = &btc->mdinfo; u8 *afh = bt_linfo->afh_map; u8 *afh_le = bt_linfo->afh_map_le; + u8 bt_pos; if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT)) return; + if (ver->fcxinit == 7) + bt_pos = md->md_v7.bt_pos; + else + bt_pos = md->md.bt_pos; + seq_puts(m, "========== [BT Status] ==========\n"); seq_printf(m, " %-15s : enable:%s, btg:%s%s, connect:%s, ", "[status]", bt->enable.now ? "Y" : "N", bt->btg_type ? "Y" : "N", - (bt->enable.now && (bt->btg_type != module->bt_pos) ? + (bt->enable.now && (bt->btg_type != bt_pos) ? "(efuse-mismatch!!)" : ""), (bt_linfo->status.map.connect ? "Y" : "N")); @@ -7123,7 +7178,6 @@ static void _show_dm_step(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; @@ -7137,7 +7191,7 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) seq_printf(m, " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%s, init_mode:%s, run_cnt:%d\n", "[status]", - module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated", + btc->ant_type == BTC_ANT_SHARED ? "shared" : "dedicated", steps_to_str(dm->run_reason), steps_to_str(dm->run_action | BTC_ACT_EXT_BIT), id_to_ant(FIELD_GET(GENMASK(7, 0), dm->set_ant_path)), diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index 08121fd899e6..dd9707b4a6d4 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -153,6 +153,10 @@ enum btc_lps_state { #define BTC_REG_NOTFOUND 0xff +#define R_BTC_ZB_COEX_TBL_0 0xE328 +#define R_BTC_ZB_COEX_TBL_1 0xE32c +#define R_BTC_ZB_BREAK_TBL 0xE350 + enum btc_ant_div_pos { BTC_ANT_DIV_MAIN = 0, BTC_ANT_DIV_AUX = 1, @@ -181,6 +185,20 @@ enum btc_btgctrl_type { BTC_BTGCTRL_BB_GNT_NOTFOUND, }; +enum btc_wa_type { + BTC_WA_5G_HI_CH_RX = BIT(0), + BTC_WA_NULL_AP = BIT(1), + BTC_WA_HFP_ZB = BIT(2), /* HFP PTA req bit4 define issue */ +}; + +enum btc_3cx_type { + BTC_3CX_NONE = 0, + BTC_3CX_BT2 = BIT(0), + BTC_3CX_ZB = BIT(1), + BTC_3CX_LTE = BIT(2), + BTC_3CX_MAX, +}; + void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev); void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev); void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2bf1e4e95c0f..4ecca3e51697 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1277,6 +1277,18 @@ struct rtw89_btc_ant_info { u8 stream_cnt: 4; }; +struct rtw89_btc_ant_info_v7 { + u8 type; /* shared, dedicated(non-shared) */ + u8 num; /* antenna count */ + u8 isolation; + u8 single_pos;/* wifi 1ss-1ant at 0:S0 or 1:S1 */ + + u8 diversity; /* only for wifi use 1-antenna */ + u8 btg_pos; /* btg-circuit at 0:S0/1:S1/others:all */ + u8 stream_cnt; /* spatial_stream count */ + u8 rsvd; +} __packed; + enum rtw89_tfc_dir { RTW89_TFC_UL, RTW89_TFC_DL, @@ -1671,6 +1683,16 @@ struct rtw89_btc_dm_emap { u32 wl_e2g_hang: 1; u32 wl_ver_mismatch: 1; u32 bt_ver_mismatch: 1; + u32 rfe_type0: 1; + u32 h2c_buffer_over: 1; + u32 bt_tx_hang: 1; /* for SNR too low bug, BT has no Tx req*/ + u32 wl_no_sta_ntfy: 1; + + u32 h2c_bmap_mismatch: 1; + u32 c2h_bmap_mismatch: 1; + u32 h2c_struct_invalid: 1; + u32 c2h_struct_invalid: 1; + u32 h2c_c2h_buffer_mismatch: 1; }; union rtw89_btc_dm_error_map { @@ -1736,6 +1758,25 @@ struct rtw89_btc_module { u8 kt_ver_adie; }; +struct rtw89_btc_module_v7 { + u8 rfe_type; + u8 kt_ver; + u8 bt_solo; + u8 bt_pos; /* wl-end view: get from efuse, must compare bt.btg_type*/ + + u8 switch_type; /* WL/BT switch type: 0: internal, 1: external */ + u8 wa_type; /* WA type: 0:none, 1: 51B 5G_Hi-Ch_Rx */ + u8 kt_ver_adie; + u8 rsvd; + + struct rtw89_btc_ant_info_v7 ant; +} __packed; + +union rtw89_btc_module_info { + struct rtw89_btc_module md; + struct rtw89_btc_module_v7 md_v7; +}; + #define RTW89_BTC_DM_MAXSTEP 30 #define RTW89_BTC_DM_CNT_MAX (RTW89_BTC_DM_MAXSTEP * 8) @@ -1758,6 +1799,25 @@ struct rtw89_btc_init_info { u16 rsvd; }; +struct rtw89_btc_init_info_v7 { + u8 wl_guard_ch; + u8 wl_only; + u8 wl_init_ok; + u8 rsvd3; + + u8 cx_other; + u8 bt_only; + u8 pta_mode; + u8 pta_direction; + + struct rtw89_btc_module_v7 module; +} __packed; + +union rtw89_btc_init_info_u { + struct rtw89_btc_init_info init; + struct rtw89_btc_init_info_v7 init_v7; +}; + struct rtw89_btc_wl_tx_limit_para { u16 enable; u32 tx_time; /* unit: us */ @@ -2496,7 +2556,7 @@ struct rtw89_btc_dm { struct rtw89_btc_fbtc_tdma tdma; struct rtw89_btc_fbtc_tdma tdma_now; struct rtw89_mac_ax_coex_gnt gnt; - struct rtw89_btc_init_info init_info; /* pass to wl_fw if offload */ + union rtw89_btc_init_info_u init_info; /* pass to wl_fw if offload */ struct rtw89_btc_rf_trx_para rf_trx_para; struct rtw89_btc_wl_tx_limit_para wl_tx_limit; struct rtw89_btc_dm_step dm_step; @@ -2717,6 +2777,7 @@ struct rtw89_btc_ver { u8 fwlrole; u8 frptmap; u8 fcxctrl; + u8 fcxinit; u16 info_buf; u8 max_role_num; @@ -2730,7 +2791,7 @@ struct rtw89_btc { struct rtw89_btc_cx cx; struct rtw89_btc_dm dm; struct rtw89_btc_ctrl ctrl; - struct rtw89_btc_module mdinfo; + union rtw89_btc_module_info mdinfo; struct rtw89_btc_btf_fwinfo fwinfo; struct rtw89_btc_dbg dbg; @@ -2742,6 +2803,8 @@ struct rtw89_btc { u32 bt_req_len; u8 policy[RTW89_BTC_POLICY_MAXLEN]; + u8 ant_type; + u8 btg_pos; u16 policy_len; u16 policy_type; bool bt_req_en; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index f654ad4c2546..b56ecd410907 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3757,7 +3757,7 @@ int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; - struct rtw89_btc_init_info *init_info = &dm->init_info; + struct rtw89_btc_init_info *init_info = &dm->init_info.init; struct rtw89_btc_module *module = &init_info->module; struct rtw89_btc_ant_info *ant = &module->ant; struct rtw89_h2c_cxinit *h2c; @@ -3820,6 +3820,46 @@ fail: return ret; } +int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_init_info_v7 *init_info = &dm->init_info.init_v7; + struct rtw89_h2c_cxinit_v7 *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 cxdrv_init_v7\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cxinit_v7 *)skb->data; + + h2c->hdr.type = CXDRVINFO_INIT; + h2c->hdr.len = len - H2C_LEN_CXDRVHDR; + h2c->init = *init_info; + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_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 PORT_DATA_OFFSET 4 #define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12 #define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \ diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 9c5464dcc081..3533b84717d2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2400,6 +2400,11 @@ struct rtw89_h2c_cxinit { #define RTW89_H2C_CXINIT_INFO_CX_OTHER BIT(3) #define RTW89_H2C_CXINIT_INFO_BT_ONLY BIT(4) +struct rtw89_h2c_cxinit_v7 { + struct rtw89_h2c_cxhdr hdr; + struct rtw89_btc_init_info_v7 init; +} __packed; + static inline void RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(void *cmd, u8 val) { u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0)); @@ -4532,6 +4537,7 @@ int rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi); int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index a7f7703a2556..12568eec32ab 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3510,8 +3510,13 @@ #define B_AX_PTA_EDCCA_EN BIT(0) #define R_BTC_COEX_WL_REQ 0xDA24 +#define R_BTC_COEX_WL_REQ_BE 0xE324 +#define B_BTC_TX_NULL_HI BIT(23) #define B_BTC_TX_BCN_HI BIT(22) +#define B_BTC_TX_TRI_HI BIT(17) #define B_BTC_RSP_ACK_HI BIT(10) +#define B_BTC_PRI_MASK_TX_TIME GENMASK(4, 3) +#define B_BTC_PRI_MASK_RX_TIME_V1 GENMASK(2, 1) #define R_BTC_BREAK_TABLE 0xDA2C #define BTC_BREAK_PARAM 0xf0ffffff @@ -5932,6 +5937,8 @@ #define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2) #define B_BE_R_MACID_ACQ_CHK_EN BIT(0) +#define R_BE_BT_BREAK_TABLE 0x0E344 + #define R_BE_GNT_SW_CTRL 0x0E348 #define B_BE_WL_ACT2_VAL BIT(25) #define B_BE_WL_ACT2_SWCTRL BIT(24) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 83db0a686ee2..d1f9cb427f55 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -1921,41 +1921,81 @@ static u8 rtw8851b_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev) { - struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; + const struct rtw89_btc_ver *ver = rtwdev->btc.ver; + union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; - module->rfe_type = rtwdev->efuse.rfe_type; - module->cv = rtwdev->hal.cv; - module->bt_solo = 0; - module->switch_type = BTC_SWITCH_INTERNAL; - module->ant.isolation = 10; - module->kt_ver_adie = rtwdev->hal.acv; + if (ver->fcxinit == 7) { + md->md_v7.rfe_type = rtwdev->efuse.rfe_type; + md->md_v7.kt_ver = rtwdev->hal.cv; + md->md_v7.bt_solo = 0; + md->md_v7.switch_type = BTC_SWITCH_INTERNAL; + md->md_v7.ant.isolation = 10; + md->md_v7.kt_ver_adie = rtwdev->hal.acv; - if (module->rfe_type == 0) - return; + if (md->md_v7.rfe_type == 0) + return; - /* rfe_type 3*n+1: 1-Ant(shared), - * 3*n+2: 2-Ant+Div(non-shared), - * 3*n+3: 2-Ant+no-Div(non-shared) - */ - module->ant.num = (module->rfe_type % 3 == 1) ? 1 : 2; - /* WL-1ss at S0, btg at s0 (On 1 WL RF) */ - module->ant.single_pos = RF_PATH_A; - module->ant.btg_pos = RF_PATH_A; - module->ant.stream_cnt = 1; + /* rfe_type 3*n+1: 1-Ant(shared), + * 3*n+2: 2-Ant+Div(non-shared), + * 3*n+3: 2-Ant+no-Div(non-shared) + */ + md->md_v7.ant.num = (md->md_v7.rfe_type % 3 == 1) ? 1 : 2; + /* WL-1ss at S0, btg at s0 (On 1 WL RF) */ + md->md_v7.ant.single_pos = RF_PATH_A; + md->md_v7.ant.btg_pos = RF_PATH_A; + md->md_v7.ant.stream_cnt = 1; - if (module->ant.num == 1) { - module->ant.type = BTC_ANT_SHARED; - module->bt_pos = BTC_BT_BTG; - module->wa_type = 1; - module->ant.diversity = 0; - } else { /* ant.num == 2 */ - module->ant.type = BTC_ANT_DEDICATED; - module->bt_pos = BTC_BT_ALONE; - module->switch_type = BTC_SWITCH_EXTERNAL; - module->wa_type = 0; - if (module->rfe_type % 3 == 2) - module->ant.diversity = 1; + if (md->md_v7.ant.num == 1) { + md->md_v7.ant.type = BTC_ANT_SHARED; + md->md_v7.bt_pos = BTC_BT_BTG; + md->md_v7.wa_type = 1; + md->md_v7.ant.diversity = 0; + } else { /* ant.num == 2 */ + md->md_v7.ant.type = BTC_ANT_DEDICATED; + md->md_v7.bt_pos = BTC_BT_ALONE; + md->md_v7.switch_type = BTC_SWITCH_EXTERNAL; + md->md_v7.wa_type = 0; + if (md->md_v7.rfe_type % 3 == 2) + md->md_v7.ant.diversity = 1; + } + rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos; + rtwdev->btc.ant_type = md->md_v7.ant.type; + } else { + md->md.rfe_type = rtwdev->efuse.rfe_type; + md->md.cv = rtwdev->hal.cv; + md->md.bt_solo = 0; + md->md.switch_type = BTC_SWITCH_INTERNAL; + md->md.ant.isolation = 10; + md->md.kt_ver_adie = rtwdev->hal.acv; + + if (md->md.rfe_type == 0) + return; + + /* rfe_type 3*n+1: 1-Ant(shared), + * 3*n+2: 2-Ant+Div(non-shared), + * 3*n+3: 2-Ant+no-Div(non-shared) + */ + md->md.ant.num = (md->md.rfe_type % 3 == 1) ? 1 : 2; + /* WL-1ss at S0, btg at s0 (On 1 WL RF) */ + md->md.ant.single_pos = RF_PATH_A; + md->md.ant.btg_pos = RF_PATH_A; + md->md.ant.stream_cnt = 1; + + if (md->md.ant.num == 1) { + md->md.ant.type = BTC_ANT_SHARED; + md->md.bt_pos = BTC_BT_BTG; + md->md.wa_type = 1; + md->md.ant.diversity = 0; + } else { /* ant.num == 2 */ + md->md.ant.type = BTC_ANT_DEDICATED; + md->md.bt_pos = BTC_BT_ALONE; + md->md.switch_type = BTC_SWITCH_EXTERNAL; + md->md.wa_type = 0; + if (md->md.rfe_type % 3 == 2) + md->md.ant.diversity = 1; + } + rtwdev->btc.btg_pos = md->md.ant.btg_pos; + rtwdev->btc.ant_type = md->md.ant.type; } } @@ -1965,7 +2005,7 @@ void rtw8851b_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) if (group > BTC_BT_SS_GROUP) group--; /* Tx-group=1, Rx-group=2 */ - if (rtwdev->btc.mdinfo.ant.type == BTC_ANT_SHARED) /* 1-Ant */ + if (rtwdev->btc.ant_type == BTC_ANT_SHARED) /* 1-Ant */ group += 3; rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, group); @@ -1980,9 +2020,9 @@ static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev) }; const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; - struct rtw89_btc_ant_info *ant = &module->ant; - u8 path, path_min, path_max; + union rtw89_btc_module_info *md = &btc->mdinfo; + const struct rtw89_btc_ver *ver = btc->ver; + u8 path, path_min, path_max, str_cnt, ant_sing_pos; /* PTA init */ rtw89_mac_coex_init(rtwdev, &coex_params); @@ -1991,9 +2031,17 @@ static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev) chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true); chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true); + if (ver->fcxinit == 7) { + str_cnt = md->md_v7.ant.stream_cnt; + ant_sing_pos = md->md_v7.ant.single_pos; + } else { + str_cnt = md->md.ant.stream_cnt; + ant_sing_pos = md->md.ant.single_pos; + } + /* for 1-Ant && 1-ss case: only 1-path */ - if (ant->stream_cnt == 1) { - path_min = ant->single_pos; + if (str_cnt == 1) { + path_min = ant_sing_pos; path_max = path_min; } else { path_min = RF_PATH_A; @@ -2016,7 +2064,7 @@ static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev) /* if GNT_WL = 0 && BT = Tx_group --> * Shared-Ant && BTG-path:WL mask(0x55f), others:WL THRU(0x5ff) */ - if (ant->type == BTC_ANT_SHARED && ant->btg_pos == path) + if (btc->ant_type == BTC_ANT_SHARED && btc->btg_pos == path) rtw8851b_set_trx_mask(rtwdev, path, BTC_BT_TX_GROUP, 0x55f); else rtw8851b_set_trx_mask(rtwdev, path, BTC_BT_TX_GROUP, 0x5ff); @@ -2148,19 +2196,18 @@ void rtw8851b_btc_update_bt_cnt(struct rtw89_dev *rtwdev) static void rtw8851b_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state) { struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_ant_info *ant = &btc->mdinfo.ant; - rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWE, RFREG_MASK, 0x80000); - rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWA, RFREG_MASK, 0x1); - rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWD1, RFREG_MASK, 0x110); + rtw89_write_rf(rtwdev, btc->btg_pos, RR_LUTWE, RFREG_MASK, 0x80000); + rtw89_write_rf(rtwdev, btc->btg_pos, RR_LUTWA, RFREG_MASK, 0x1); + rtw89_write_rf(rtwdev, btc->btg_pos, RR_LUTWD1, RFREG_MASK, 0x110); /* set WL standby = Rx for GNT_BT_Tx = 1->0 settle issue */ if (state) - rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWD0, RFREG_MASK, 0x179c); + rtw89_write_rf(rtwdev, btc->btg_pos, RR_LUTWD0, RFREG_MASK, 0x179c); else - rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWD0, RFREG_MASK, 0x208); + rtw89_write_rf(rtwdev, btc->btg_pos, RR_LUTWD0, RFREG_MASK, 0x208); - rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWE, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, btc->btg_pos, RR_LUTWE, RFREG_MASK, 0x0); } #define LNA2_51B_MA 0x700 @@ -2175,7 +2222,6 @@ static void rtw8851b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) * level=1 Fix LNA2=5: TIA 1/0= (LNA2,TIAN6) = (5,0)/(5,1) = 18dB/12dB */ struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_ant_info *ant = &btc->mdinfo.ant; const struct rtw89_reg2_def *rf; u32 n, i, val; @@ -2203,10 +2249,10 @@ static void rtw8851b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) for (i = 0; i < n; i++, rf++) { val = rf->data; /* bit[10] = 1 if non-shared-ant for 8851b */ - if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED) + if (btc->ant_type == BTC_ANT_DEDICATED) val |= 0x4; - rtw89_write_rf(rtwdev, ant->btg_pos, rf->addr, LNA2_51B_MA, val); + rtw89_write_rf(rtwdev, btc->btg_pos, rf->addr, LNA2_51B_MA, val); } } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 8e808ded5d52..ade8604bacb8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -1665,28 +1665,55 @@ static u8 rtw8852a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p static void rtw8852a_btc_set_rfe(struct rtw89_dev *rtwdev) { - struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; + const struct rtw89_btc_ver *ver = rtwdev->btc.ver; + union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; - module->rfe_type = rtwdev->efuse.rfe_type; - module->cv = rtwdev->hal.cv; - module->bt_solo = 0; - module->switch_type = BTC_SWITCH_INTERNAL; + if (ver->fcxinit == 7) { + md->md_v7.rfe_type = rtwdev->efuse.rfe_type; + md->md_v7.kt_ver = rtwdev->hal.cv; + md->md_v7.bt_solo = 0; + md->md_v7.switch_type = BTC_SWITCH_INTERNAL; - if (module->rfe_type > 0) - module->ant.num = (module->rfe_type % 2 ? 2 : 3); - else - module->ant.num = 2; + if (md->md_v7.rfe_type > 0) + md->md_v7.ant.num = (md->md_v7.rfe_type % 2 ? 2 : 3); + else + md->md_v7.ant.num = 2; - module->ant.diversity = 0; - module->ant.isolation = 10; + md->md_v7.ant.diversity = 0; + md->md_v7.ant.isolation = 10; - if (module->ant.num == 3) { - module->ant.type = BTC_ANT_DEDICATED; - module->bt_pos = BTC_BT_ALONE; + if (md->md_v7.ant.num == 3) { + md->md_v7.ant.type = BTC_ANT_DEDICATED; + md->md_v7.bt_pos = BTC_BT_ALONE; + } else { + md->md_v7.ant.type = BTC_ANT_SHARED; + md->md_v7.bt_pos = BTC_BT_BTG; + } + rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos; + rtwdev->btc.ant_type = md->md_v7.ant.type; } else { - module->ant.type = BTC_ANT_SHARED; - module->bt_pos = BTC_BT_BTG; + md->md.rfe_type = rtwdev->efuse.rfe_type; + md->md.cv = rtwdev->hal.cv; + md->md.bt_solo = 0; + md->md.switch_type = BTC_SWITCH_INTERNAL; + + if (md->md.rfe_type > 0) + md->md.ant.num = (md->md.rfe_type % 2 ? 2 : 3); + else + md->md.ant.num = 2; + + md->md.ant.diversity = 0; + md->md.ant.isolation = 10; + + if (md->md.ant.num == 3) { + md->md.ant.type = BTC_ANT_DEDICATED; + md->md.bt_pos = BTC_BT_ALONE; + } else { + md->md.ant.type = BTC_ANT_SHARED; + md->md.bt_pos = BTC_BT_BTG; + } + rtwdev->btc.btg_pos = md->md.ant.btg_pos; + rtwdev->btc.ant_type = md->md.ant.type; } } @@ -1717,7 +1744,6 @@ static void rtw8852a_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, static void rtw8852a_btc_init_cfg(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_mac_ax_coex coex_params = { .pta_mode = RTW89_MAC_AX_COEX_RTK_MODE, @@ -1736,7 +1762,7 @@ static void rtw8852a_btc_init_cfg(struct rtw89_dev *rtwdev) rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, 0xfffff, 0x0); /* set WL Tx thru in TRX mask table if GNT_WL = 0 && BT_S1 = ss group */ - if (module->ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { rtw8852a_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5ff); rtw8852a_set_trx_mask(rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 19454766f3de..5b8c3460e35a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2125,28 +2125,55 @@ static u8 rtw8852b_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p static void rtw8852b_btc_set_rfe(struct rtw89_dev *rtwdev) { - struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; + const struct rtw89_btc_ver *ver = rtwdev->btc.ver; + union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; - module->rfe_type = rtwdev->efuse.rfe_type; - module->cv = rtwdev->hal.cv; - module->bt_solo = 0; - module->switch_type = BTC_SWITCH_INTERNAL; + if (ver->fcxinit == 7) { + md->md_v7.rfe_type = rtwdev->efuse.rfe_type; + md->md_v7.kt_ver = rtwdev->hal.cv; + md->md_v7.bt_solo = 0; + md->md_v7.switch_type = BTC_SWITCH_INTERNAL; - if (module->rfe_type > 0) - module->ant.num = module->rfe_type % 2 ? 2 : 3; - else - module->ant.num = 2; + if (md->md_v7.rfe_type > 0) + md->md_v7.ant.num = (md->md_v7.rfe_type % 2 ? 2 : 3); + else + md->md_v7.ant.num = 2; - module->ant.diversity = 0; - module->ant.isolation = 10; + md->md_v7.ant.diversity = 0; + md->md_v7.ant.isolation = 10; - if (module->ant.num == 3) { - module->ant.type = BTC_ANT_DEDICATED; - module->bt_pos = BTC_BT_ALONE; + if (md->md_v7.ant.num == 3) { + md->md_v7.ant.type = BTC_ANT_DEDICATED; + md->md_v7.bt_pos = BTC_BT_ALONE; + } else { + md->md_v7.ant.type = BTC_ANT_SHARED; + md->md_v7.bt_pos = BTC_BT_BTG; + } + rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos; + rtwdev->btc.ant_type = md->md_v7.ant.type; } else { - module->ant.type = BTC_ANT_SHARED; - module->bt_pos = BTC_BT_BTG; + md->md.rfe_type = rtwdev->efuse.rfe_type; + md->md.cv = rtwdev->hal.cv; + md->md.bt_solo = 0; + md->md.switch_type = BTC_SWITCH_INTERNAL; + + if (md->md.rfe_type > 0) + md->md.ant.num = (md->md.rfe_type % 2 ? 2 : 3); + else + md->md.ant.num = 2; + + md->md.ant.diversity = 0; + md->md.ant.isolation = 10; + + if (md->md.ant.num == 3) { + md->md.ant.type = BTC_ANT_DEDICATED; + md->md.bt_pos = BTC_BT_ALONE; + } else { + md->md.ant.type = BTC_ANT_SHARED; + md->md.bt_pos = BTC_BT_BTG; + } + rtwdev->btc.btg_pos = md->md.ant.btg_pos; + rtwdev->btc.ant_type = md->md.ant.type; } } @@ -2162,7 +2189,6 @@ void rtw8852b_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) static void rtw8852b_btc_init_cfg(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_mac_ax_coex coex_params = { .pta_mode = RTW89_MAC_AX_COEX_RTK_MODE, @@ -2181,7 +2207,7 @@ static void rtw8852b_btc_init_cfg(struct rtw89_dev *rtwdev) rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, RFREG_MASK, 0x0); /* set WL Tx thru in TRX mask table if GNT_WL = 0 && BT_S1 = ss group */ - if (module->ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5ff); rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_SS_GROUP, 0x5ff); /* set path-A(S0) Tx/Rx no-mask if GNT_WL=0 && BT_S1=tx group */ diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index ca8547fbd70e..84ee7483acda 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2365,28 +2365,55 @@ static u8 rtw8852c_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p static void rtw8852c_btc_set_rfe(struct rtw89_dev *rtwdev) { - struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; + const struct rtw89_btc_ver *ver = rtwdev->btc.ver; + union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; - module->rfe_type = rtwdev->efuse.rfe_type; - module->cv = rtwdev->hal.cv; - module->bt_solo = 0; - module->switch_type = BTC_SWITCH_INTERNAL; + if (ver->fcxinit == 7) { + md->md_v7.rfe_type = rtwdev->efuse.rfe_type; + md->md_v7.kt_ver = rtwdev->hal.cv; + md->md_v7.bt_solo = 0; + md->md_v7.switch_type = BTC_SWITCH_INTERNAL; - if (module->rfe_type > 0) - module->ant.num = (module->rfe_type % 2 ? 2 : 3); - else - module->ant.num = 2; + if (md->md_v7.rfe_type > 0) + md->md_v7.ant.num = (md->md_v7.rfe_type % 2 ? 2 : 3); + else + md->md_v7.ant.num = 2; - module->ant.diversity = 0; - module->ant.isolation = 10; + md->md_v7.ant.diversity = 0; + md->md_v7.ant.isolation = 10; - if (module->ant.num == 3) { - module->ant.type = BTC_ANT_DEDICATED; - module->bt_pos = BTC_BT_ALONE; + if (md->md_v7.ant.num == 3) { + md->md_v7.ant.type = BTC_ANT_DEDICATED; + md->md_v7.bt_pos = BTC_BT_ALONE; + } else { + md->md_v7.ant.type = BTC_ANT_SHARED; + md->md_v7.bt_pos = BTC_BT_BTG; + } + rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos; + rtwdev->btc.ant_type = md->md_v7.ant.type; } else { - module->ant.type = BTC_ANT_SHARED; - module->bt_pos = BTC_BT_BTG; + md->md.rfe_type = rtwdev->efuse.rfe_type; + md->md.cv = rtwdev->hal.cv; + md->md.bt_solo = 0; + md->md.switch_type = BTC_SWITCH_INTERNAL; + + if (md->md.rfe_type > 0) + md->md.ant.num = (md->md.rfe_type % 2 ? 2 : 3); + else + md->md.ant.num = 2; + + md->md.ant.diversity = 0; + md->md.ant.isolation = 10; + + if (md->md.ant.num == 3) { + md->md.ant.type = BTC_ANT_DEDICATED; + md->md.bt_pos = BTC_BT_ALONE; + } else { + md->md.ant.type = BTC_ANT_SHARED; + md->md.bt_pos = BTC_BT_BTG; + } + rtwdev->btc.btg_pos = md->md.ant.btg_pos; + rtwdev->btc.ant_type = md->md.ant.type; } } @@ -2449,7 +2476,6 @@ void rtw8852c_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_module *module = &btc->mdinfo; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_mac_ax_coex coex_params = { .pta_mode = RTW89_MAC_AX_COEX_RTK_MODE, @@ -2468,7 +2494,7 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev) rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, RFREG_MASK, 0x0); /* set WL Tx thru in TRX mask table if GNT_WL = 0 && BT_S1 = ss group */ - if (module->ant.type == BTC_ANT_SHARED) { + if (btc->ant_type == BTC_ANT_SHARED) { rtw8852c_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5ff); rtw8852c_set_trx_mask(rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 0e99ecea32a3..ca7babf62f8a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2150,6 +2150,113 @@ static u8 rtw8922a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p return clamp_t(int, th, 0, U8_MAX); } +static void rtw8922a_btc_set_rfe(struct rtw89_dev *rtwdev) +{ + union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; + struct rtw89_btc_module_v7 *module = &md->md_v7; + + module->rfe_type = rtwdev->efuse.rfe_type; + module->kt_ver = rtwdev->hal.cv; + module->bt_solo = 0; + module->switch_type = BTC_SWITCH_INTERNAL; + module->wa_type = 0; + + module->ant.type = BTC_ANT_SHARED; + module->ant.num = 2; + module->ant.isolation = 10; + module->ant.diversity = 0; + module->ant.single_pos = RF_PATH_A; + module->ant.btg_pos = RF_PATH_B; + + if (module->kt_ver <= 1) + module->wa_type |= BTC_WA_HFP_ZB; + + rtwdev->btc.cx.other.type = BTC_3CX_NONE; + + if (module->rfe_type == 0) { + rtwdev->btc.dm.error.map.rfe_type0 = true; + return; + } + + module->ant.num = (module->rfe_type % 2) ? 2 : 3; + + if (module->kt_ver == 0) + module->ant.num = 2; + + if (module->ant.num == 3) { + module->ant.type = BTC_ANT_DEDICATED; + module->bt_pos = BTC_BT_ALONE; + } else { + module->ant.type = BTC_ANT_SHARED; + module->bt_pos = BTC_BT_BTG; + } + rtwdev->btc.btg_pos = module->ant.btg_pos; + rtwdev->btc.ant_type = module->ant.type; +} + +static +void rtw8922a_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) +{ + rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, group); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, val); +} + +static void rtw8922a_btc_init_cfg(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ant_info_v7 *ant = &btc->mdinfo.md_v7.ant; + u32 wl_pri, path_min, path_max; + u8 path; + + /* for 1-Ant && 1-ss case: only 1-path */ + if (ant->num == 1) { + path_min = ant->single_pos; + path_max = path_min; + } else { + path_min = RF_PATH_A; + path_max = RF_PATH_B; + } + + path = path_min; + + for (path = path_min; path <= path_max; path++) { + /* set DEBUG_LUT_RFMODE_MASK = 1 to start trx-mask-setup */ + rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, BIT(17)); + + /* if GNT_WL=0 && BT=SS_group --> WL Tx/Rx = THRU */ + rtw8922a_set_trx_mask(rtwdev, path, BTC_BT_SS_GROUP, 0x5ff); + + /* if GNT_WL=0 && BT=Rx_group --> WL-Rx = THRU + WL-Tx = MASK */ + rtw8922a_set_trx_mask(rtwdev, path, BTC_BT_RX_GROUP, 0x5df); + + /* if GNT_WL = 0 && BT = Tx_group --> + * Shared-Ant && BTG-path:WL mask(0x55f), others:WL THRU(0x5ff) + */ + if (btc->ant_type == BTC_ANT_SHARED && btc->btg_pos == path) + rtw8922a_set_trx_mask(rtwdev, path, BTC_BT_TX_GROUP, 0x5ff); + else + rtw8922a_set_trx_mask(rtwdev, path, BTC_BT_TX_GROUP, 0x5ff); + + rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0); + } + + /* set WL PTA Hi-Pri: Ack-Tx, beacon-tx, Trig-frame-Tx, Null-Tx*/ + wl_pri = B_BTC_RSP_ACK_HI | B_BTC_TX_BCN_HI | B_BTC_TX_TRI_HI | + B_BTC_TX_NULL_HI; + rtw89_write32(rtwdev, R_BTC_COEX_WL_REQ_BE, wl_pri); + + /* set PTA break table */ + rtw89_write32(rtwdev, R_BE_BT_BREAK_TABLE, BTC_BREAK_PARAM); + + /* ZB coex table init for HFP PTA req-cmd bit-4 define issue COEX-900*/ + rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_0, 0xda5a5a5a); + + rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_1, 0xda5a5a5a); + + rtw89_write32(rtwdev, R_BTC_ZB_BREAK_TBL, 0xf0ffffff); + btc->cx.wl.status.map.init_ok = true; +} + static void rtw8922a_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status) @@ -2257,6 +2364,9 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, + + .btc_set_rfe = rtw8922a_btc_set_rfe, + .btc_init_cfg = rtw8922a_btc_init_cfg, }; const struct rtw89_chip_info rtw8922a_chip_info = { From 9d27596fdac596bb66b0909c809afb266a7af5c2 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Thu, 29 Feb 2024 15:45:10 +0800 Subject: [PATCH 1870/2255] wifi: rtw89: coex: add BTC ctrl_info version 7 and related logic Change structure member from bit field to normal variable to reduce unnecessary translation. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 90 ++++++++++++++++------ drivers/net/wireless/realtek/rtw89/core.h | 15 +++- drivers/net/wireless/realtek/rtw89/debug.c | 9 ++- drivers/net/wireless/realtek/rtw89/fw.c | 44 ++++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 15 +++- 5 files changed, 142 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 3ce4ce144b9e..ee658d3bea78 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -718,6 +718,7 @@ static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; @@ -735,7 +736,9 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) if (type & BTC_RESET_CTRL) { memset(&btc->ctrl, 0, sizeof(btc->ctrl)); - btc->ctrl.trace_step = FCXDEF_STEP; + btc->manual_ctrl = false; + if (ver->fcxctrl != 7) + btc->ctrl.ctrl.trace_step = FCXDEF_STEP; } /* Init Coex variables that are not zero */ @@ -1129,7 +1132,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, void *rpt_content = NULL, *pfinfo = NULL; u8 rpt_type = 0; u16 wl_slot_set = 0, wl_slot_real = 0; - u32 trace_step = btc->ctrl.trace_step, rpt_len = 0, diff_t = 0; + u32 trace_step = 0, rpt_len = 0, diff_t = 0; u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr; u8 i, val = 0; @@ -1219,6 +1222,9 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, break; case BTC_RPT_TYPE_STEP: pcinfo = &pfwinfo->rpt_fbtc_step.cinfo; + if (ver->fcxctrl != 7) + trace_step = btc->ctrl.ctrl.trace_step; + if (ver->fcxstep == 2) { pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) * @@ -2109,7 +2115,10 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) rtw89_fw_h2c_cxdrv_role_v2(rtwdev); break; case CXDRVINFO_CTRL: - rtw89_fw_h2c_cxdrv_ctrl(rtwdev); + if (ver->fcxctrl == 7) + rtw89_fw_h2c_cxdrv_ctrl_v7(rtwdev); + else + rtw89_fw_h2c_cxdrv_ctrl(rtwdev); break; case CXDRVINFO_TRX: dm->trx_info.tx_power = u32_get_bits(rf_para.wl_tx_power, @@ -2450,7 +2459,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) u8 en = 0, i, ch = 0, bw = 0; u8 mode, connect_cnt; - if (btc->ctrl.manual || wl->status.map.scan) + if (btc->manual_ctrl || wl->status.map.scan) return; if (ver->fwlrole == 0) { @@ -4014,7 +4023,7 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) u32 is_btg; u8 i, val; - if (btc->ctrl.manual) + if (btc->manual_ctrl) return; if (ver->fwlrole == 0) @@ -4086,7 +4095,7 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) struct rtw89_btc_dm *dm = &btc->dm; u8 is_preagc, val; - if (btc->ctrl.manual) + if (btc->manual_ctrl) return; if (wl_rinfo->link_mode == BTC_WLINK_25G_MCC) @@ -4210,13 +4219,12 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2; struct rtw89_txtime_data data = {.rtwdev = rtwdev}; - u8 mode; - u8 tx_retry; + u8 mode, igno_bt, tx_retry; u32 tx_time; u16 enable; bool reenable = false; - if (btc->ctrl.manual) + if (btc->manual_ctrl) return; if (ver->fwlrole == 0) @@ -4228,7 +4236,12 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) else return; - if (btc->dm.freerun || btc->ctrl.igno_bt || b->profile_cnt.now == 0 || + if (ver->fcxctrl == 7) + igno_bt = btc->ctrl.ctrl_v7.igno_bt; + else + igno_bt = btc->ctrl.ctrl.igno_bt; + + if (btc->dm.freerun || igno_bt || b->profile_cnt.now == 0 || mode == BTC_WLINK_5G || mode == BTC_WLINK_NOLINK) { enable = 0; tx_time = BTC_MAX_TX_TIME_DEF; @@ -5374,7 +5387,7 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2; - u8 mode; + u8 mode, igno_bt, always_freerun; lockdep_assert_held(&rtwdev->mutex); @@ -5391,20 +5404,28 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) else return; + if (ver->fcxctrl == 7) { + igno_bt = btc->ctrl.ctrl_v7.igno_bt; + always_freerun = btc->ctrl.ctrl_v7.always_freerun; + } else { + igno_bt = btc->ctrl.ctrl.igno_bt; + always_freerun = btc->ctrl.ctrl.always_freerun; + } + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reason=%d, mode=%d\n", __func__, reason, mode); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): wl_only=%d, bt_only=%d\n", __func__, dm->wl_only, dm->bt_only); /* Be careful to change the following function sequence!! */ - if (btc->ctrl.manual) { + if (btc->manual_ctrl) { rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): return for Manual CTRL!!\n", __func__); return; } - if (btc->ctrl.igno_bt && + if (igno_bt && (reason == BTC_RSN_UPDATE_BT_INFO || reason == BTC_RSN_UPDATE_BT_SCBD)) { rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -5441,24 +5462,24 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) dm->freerun = false; dm->cnt_dm[BTC_DCNT_RUN]++; dm->fddt_train = BTC_FDDT_DISABLE; - btc->ctrl.igno_bt = false; bt->scan_rx_low_pri = false; + igno_bt = false; - if (btc->ctrl.always_freerun) { + if (always_freerun) { _action_freerun(rtwdev); - btc->ctrl.igno_bt = true; + igno_bt = true; goto exit; } if (dm->wl_only) { _action_wl_only(rtwdev); - btc->ctrl.igno_bt = true; + igno_bt = true; goto exit; } if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) { _action_wl_off(rtwdev, mode); - btc->ctrl.igno_bt = true; + igno_bt = true; goto exit; } @@ -5548,6 +5569,10 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) exit: rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__); + if (ver->fcxctrl == 7) + btc->ctrl.ctrl_v7.igno_bt = igno_bt; + else + btc->ctrl.ctrl.igno_bt = igno_bt; _action_common(rtwdev); } @@ -5611,11 +5636,15 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode) struct rtw89_btc_dm *dm = &rtwdev->btc.dm; struct rtw89_btc_wl_info *wl = &btc->cx.wl; const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_btc_ver *ver = btc->ver; _reset_btc_var(rtwdev, BTC_RESET_ALL); btc->dm.run_reason = BTC_RSN_NONE; btc->dm.run_action = BTC_ACT_NONE; - btc->ctrl.igno_bt = true; + if (ver->fcxctrl == 7) + btc->ctrl.ctrl_v7.igno_bt = true; + else + btc->ctrl.ctrl.igno_bt = true; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): mode=%d\n", __func__, mode); @@ -7178,15 +7207,17 @@ static void _show_dm_step(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; + u8 igno_bt; if (!(dm->coex_info_map & BTC_COEX_INFO_DM)) return; seq_printf(m, "========== [Mechanism Status %s] ==========\n", - (btc->ctrl.manual ? "(Manual)" : "(Auto)")); + (btc->manual_ctrl ? "(Manual)" : "(Auto)")); seq_printf(m, " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%s, init_mode:%s, run_cnt:%d\n", @@ -7200,8 +7231,13 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) _show_dm_step(rtwdev, m); + if (ver->fcxctrl == 7) + igno_bt = btc->ctrl.ctrl_v7.igno_bt; + else + igno_bt = btc->ctrl.ctrl.igno_bt; + seq_printf(m, " %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ", - "[dm_flag]", dm->wl_only, dm->bt_only, btc->ctrl.igno_bt, + "[dm_flag]", dm->wl_only, dm->bt_only, igno_bt, dm->freerun, btc->lps, dm->wl_mimo_ps); seq_printf(m, "leak_ap:%d, fw_offload:%s%s\n", dm->leak_ap, @@ -7942,10 +7978,11 @@ static void _show_fbtc_step_v2(struct rtw89_dev *rtwdev, struct seq_file *m) struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; struct rtw89_btc_fbtc_steps_v2 *pstep = NULL; + const struct rtw89_btc_ver *ver = btc->ver; u8 type, val, cnt = 0, state = 0; bool outloop = false; u16 i, diff_t, n_start = 0, n_stop = 0; - u16 pos_old, pos_new; + u16 pos_old, pos_new, trace_step; pcinfo = &pfwinfo->rpt_fbtc_step.cinfo; if (!pcinfo->valid) @@ -7962,11 +7999,16 @@ static void _show_fbtc_step_v2(struct rtw89_dev *rtwdev, struct seq_file *m) do { switch (state) { case 0: + if (ver->fcxctrl == 7 || ver->fcxctrl == 1) + trace_step = 50; + else + trace_step = btc->ctrl.ctrl.trace_step; + n_start = pos_old; if (pos_new >= pos_old) n_stop = pos_new; else - n_stop = btc->ctrl.trace_step - 1; + n_stop = trace_step - 1; state = 1; break; @@ -8796,7 +8838,7 @@ void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m) seq_printf(m, "WL FW / BT FW %d.%d.%d.%d / NA\n", fw_suit->major_ver, fw_suit->minor_ver, fw_suit->sub_ver, fw_suit->sub_idex); - seq_printf(m, "manual %d\n", btc->ctrl.manual); + seq_printf(m, "manual %d\n", btc->manual_ctrl); seq_puts(m, "=========================================\n"); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 4ecca3e51697..91a8f62dc70a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -2605,6 +2605,18 @@ struct rtw89_btc_ctrl { u32 rsvd: 12; }; +struct rtw89_btc_ctrl_v7 { + u8 manual; + u8 igno_bt; + u8 always_freerun; + u8 rsvd; +} __packed; + +union rtw89_btc_ctrl_list { + struct rtw89_btc_ctrl ctrl; + struct rtw89_btc_ctrl_v7 ctrl_v7; +}; + struct rtw89_btc_dbg { /* cmd "rb" */ bool rb_done; @@ -2790,7 +2802,7 @@ struct rtw89_btc { struct rtw89_btc_cx cx; struct rtw89_btc_dm dm; - struct rtw89_btc_ctrl ctrl; + union rtw89_btc_ctrl_list ctrl; union rtw89_btc_module_info mdinfo; struct rtw89_btc_btf_fwinfo fwinfo; struct rtw89_btc_dbg dbg; @@ -2810,6 +2822,7 @@ struct rtw89_btc { bool bt_req_en; bool update_policy_force; bool lps; + bool manual_ctrl; }; enum rtw89_btc_hmsg { diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 44829a148185..affffc4092ba 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3427,14 +3427,17 @@ static ssize_t rtw89_debug_priv_btc_manual_set(struct file *filp, struct rtw89_debugfs_priv *debugfs_priv = filp->private_data; struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; struct rtw89_btc *btc = &rtwdev->btc; - bool btc_manual; + const struct rtw89_btc_ver *ver = btc->ver; int ret; - ret = kstrtobool_from_user(user_buf, count, &btc_manual); + ret = kstrtobool_from_user(user_buf, count, &btc->manual_ctrl); if (ret) return ret; - btc->ctrl.manual = btc_manual; + if (ver->fcxctrl == 7) + btc->ctrl.ctrl_v7.manual = btc->manual_ctrl; + else + btc->ctrl.ctrl.manual = btc->manual_ctrl; return count; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index b56ecd410907..4c607c8b4d15 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3839,7 +3839,8 @@ int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev) h2c = (struct rtw89_h2c_cxinit_v7 *)skb->data; h2c->hdr.type = CXDRVINFO_INIT; - h2c->hdr.len = len - H2C_LEN_CXDRVHDR; + h2c->hdr.ver = btc->ver->fcxinit; + h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7; h2c->init = *init_info; rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -4124,7 +4125,7 @@ int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; - struct rtw89_btc_ctrl *ctrl = &btc->ctrl; + struct rtw89_btc_ctrl *ctrl = &btc->ctrl.ctrl; struct sk_buff *skb; u8 *cmd; int ret; @@ -4164,6 +4165,45 @@ fail: return ret; } +int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ctrl_v7 *ctrl = &btc->ctrl.ctrl_v7; + struct rtw89_h2c_cxctrl_v7 *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 cxdrv_ctrl\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cxctrl_v7 *)skb->data; + + h2c->hdr.type = CXDRVINFO_INIT; + h2c->hdr.ver = btc->ver->fcxctrl; + h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7; + h2c->ctrl = *ctrl; + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_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_LEN_CXDRVINFO_TRX (28 + H2C_LEN_CXDRVHDR) int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 3533b84717d2..51087fa3bc0d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2366,7 +2366,19 @@ struct rtw89_h2c_cxhdr { u8 len; } __packed; +struct rtw89_h2c_cxhdr_v7 { + u8 type; + u8 ver; + u8 len; +} __packed; + +struct rtw89_h2c_cxctrl_v7 { + struct rtw89_h2c_cxhdr_v7 hdr; + struct rtw89_btc_ctrl_v7 ctrl; +} __packed; + #define H2C_LEN_CXDRVHDR sizeof(struct rtw89_h2c_cxhdr) +#define H2C_LEN_CXDRVHDR_V7 sizeof(struct rtw89_h2c_cxhdr_v7) struct rtw89_h2c_cxinit { struct rtw89_h2c_cxhdr hdr; @@ -2401,7 +2413,7 @@ struct rtw89_h2c_cxinit { #define RTW89_H2C_CXINIT_INFO_BT_ONLY BIT(4) struct rtw89_h2c_cxinit_v7 { - struct rtw89_h2c_cxhdr hdr; + struct rtw89_h2c_cxhdr_v7 hdr; struct rtw89_btc_init_info_v7 init; } __packed; @@ -4542,6 +4554,7 @@ int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id); From 6ee10fcd284df946139fffe540e022aa13866b5f Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Thu, 29 Feb 2024 15:45:11 +0800 Subject: [PATCH 1871/2255] wifi: rtw89: coex: Reorder H2C command index to align with firmware Wi-Fi firmware need some driver information to do decision or do some real-time control. Driver will update these information by H2C command. The chip 8922a H2C command index is different from before chips/branch, so need to assign the correct index to let firmware parsing. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 53 ++++++++++++++--------- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 36 +++++++-------- drivers/net/wireless/realtek/rtw89/fw.h | 30 ++++++++----- 4 files changed, 72 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index ee658d3bea78..c270d0c26c00 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -134,70 +134,70 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 2, .frptmap = 7, .fcxctrl = 7, .fcxinit = 7, - .info_buf = 1800, .max_role_num = 6, + .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6, }, {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1800, .max_role_num = 6, + .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1280, .max_role_num = 5, + .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1280, .max_role_num = 5, + .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1280, .max_role_num = 5, + .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1800, .max_role_num = 6, + .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1800, .max_role_num = 6, + .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1280, .max_role_num = 5, + .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .info_buf = 1280, .max_role_num = 5, + .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, - .info_buf = 1024, .max_role_num = 5, + .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5, }, /* keep it to be the last as default entry */ @@ -206,7 +206,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, - .info_buf = 1024, .max_role_num = 5, + .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5, }, }; @@ -2102,25 +2102,31 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) switch (type) { case CXDRVINFO_INIT: if (ver->fcxinit == 7) - rtw89_fw_h2c_cxdrv_init_v7(rtwdev); + rtw89_fw_h2c_cxdrv_init_v7(rtwdev, type); else - rtw89_fw_h2c_cxdrv_init(rtwdev); + rtw89_fw_h2c_cxdrv_init(rtwdev, type); break; case CXDRVINFO_ROLE: if (ver->fwlrole == 0) - rtw89_fw_h2c_cxdrv_role(rtwdev); + rtw89_fw_h2c_cxdrv_role(rtwdev, type); else if (ver->fwlrole == 1) - rtw89_fw_h2c_cxdrv_role_v1(rtwdev); + rtw89_fw_h2c_cxdrv_role_v1(rtwdev, type); else if (ver->fwlrole == 2) - rtw89_fw_h2c_cxdrv_role_v2(rtwdev); + rtw89_fw_h2c_cxdrv_role_v2(rtwdev, type); break; case CXDRVINFO_CTRL: + if (ver->drvinfo_type == 1) + type = 2; + if (ver->fcxctrl == 7) - rtw89_fw_h2c_cxdrv_ctrl_v7(rtwdev); + rtw89_fw_h2c_cxdrv_ctrl_v7(rtwdev, type); else - rtw89_fw_h2c_cxdrv_ctrl(rtwdev); + rtw89_fw_h2c_cxdrv_ctrl(rtwdev, type); break; case CXDRVINFO_TRX: + if (ver->drvinfo_type == 1) + type = 3; + dm->trx_info.tx_power = u32_get_bits(rf_para.wl_tx_power, RTW89_BTC_WL_DEF_TX_PWR); dm->trx_info.rx_gain = u32_get_bits(rf_para.wl_rx_gain, @@ -2131,11 +2137,18 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) RTW89_BTC_WL_DEF_TX_PWR); dm->trx_info.cn = wl->cn_report; dm->trx_info.nhm = wl->nhm.pwr; - rtw89_fw_h2c_cxdrv_trx(rtwdev); + rtw89_fw_h2c_cxdrv_trx(rtwdev, type); break; case CXDRVINFO_RFK: - rtw89_fw_h2c_cxdrv_rfk(rtwdev); + if (ver->drvinfo_type == 1) + return; + + rtw89_fw_h2c_cxdrv_rfk(rtwdev, type); break; + case CXDRVINFO_TXPWR: + case CXDRVINFO_FDDT: + case CXDRVINFO_MLO: + case CXDRVINFO_OSI: default: break; } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 91a8f62dc70a..7957b7b9e4c7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -2791,6 +2791,7 @@ struct rtw89_btc_ver { u8 fcxctrl; u8 fcxinit; + u8 drvinfo_type; u16 info_buf; u8 max_role_num; }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4c607c8b4d15..185cd339c085 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3753,7 +3753,7 @@ fail: return ret; } -int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; @@ -3773,7 +3773,7 @@ int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev) skb_put(skb, len); h2c = (struct rtw89_h2c_cxinit *)skb->data; - h2c->hdr.type = CXDRVINFO_INIT; + h2c->hdr.type = type; h2c->hdr.len = len - H2C_LEN_CXDRVHDR; h2c->ant_type = ant->type; @@ -3820,7 +3820,7 @@ fail: return ret; } -int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; @@ -3838,7 +3838,7 @@ int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev) skb_put(skb, len); h2c = (struct rtw89_h2c_cxinit_v7 *)skb->data; - h2c->hdr.type = CXDRVINFO_INIT; + h2c->hdr.type = type; h2c->hdr.ver = btc->ver->fcxinit; h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7; h2c->init = *init_info; @@ -3866,7 +3866,7 @@ fail: #define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \ (4 + 12 * (max_role_num) + H2C_LEN_CXDRVHDR) -int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; @@ -3891,7 +3891,7 @@ int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) skb_put(skb, len); cmd = skb->data; - RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type); RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); @@ -3947,7 +3947,7 @@ fail: #define H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(max_role_num) \ (4 + 16 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR) -int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; @@ -3971,7 +3971,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) skb_put(skb, len); cmd = skb->data; - RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type); RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); @@ -4037,7 +4037,7 @@ fail: #define H2C_LEN_CXDRVINFO_ROLE_SIZE_V2(max_role_num) \ (4 + 8 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR) -int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; @@ -4061,7 +4061,7 @@ int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev) skb_put(skb, len); cmd = skb->data; - RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type); RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); @@ -4121,7 +4121,7 @@ fail: } #define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR) -int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; @@ -4138,7 +4138,7 @@ int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) skb_put(skb, H2C_LEN_CXDRVINFO_CTRL); cmd = skb->data; - RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_CTRL); + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type); RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_CTRL - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, ctrl->manual); @@ -4165,7 +4165,7 @@ fail: return ret; } -int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_ctrl_v7 *ctrl = &btc->ctrl.ctrl_v7; @@ -4182,7 +4182,7 @@ int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev) skb_put(skb, len); h2c = (struct rtw89_h2c_cxctrl_v7 *)skb->data; - h2c->hdr.type = CXDRVINFO_INIT; + h2c->hdr.type = type; h2c->hdr.ver = btc->ver->fcxctrl; h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7; h2c->ctrl = *ctrl; @@ -4205,7 +4205,7 @@ fail: } #define H2C_LEN_CXDRVINFO_TRX (28 + H2C_LEN_CXDRVHDR) -int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_trx_info *trx = &btc->dm.trx_info; @@ -4221,7 +4221,7 @@ int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev) skb_put(skb, H2C_LEN_CXDRVINFO_TRX); cmd = skb->data; - RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_TRX); + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type); RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_TRX - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXTRX_TXLV(cmd, trx->tx_lvl); @@ -4261,7 +4261,7 @@ fail: } #define H2C_LEN_CXDRVINFO_RFK (4 + H2C_LEN_CXDRVHDR) -int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev) +int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; @@ -4278,7 +4278,7 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev) skb_put(skb, H2C_LEN_CXDRVINFO_RFK); cmd = skb->data; - RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_RFK); + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type); RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_RFK - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXRFK_STATE(cmd, rfk_info->state); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 51087fa3bc0d..6993451a6ef9 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -2324,9 +2324,15 @@ enum rtw89_btc_btf_set { SET_BT_IGNORE_WLAN_ACT, SET_BT_TX_PWR, SET_BT_LNA_CONSTRAIN, - SET_BT_GOLDEN_RX_RANGE, + SET_BT_QUERY_DEV_LIST, + SET_BT_QUERY_DEV_INFO, SET_BT_PSD_REPORT, SET_H2C_TEST, + SET_IOFLD_RF, + SET_IOFLD_BB, + SET_IOFLD_MAC, + SET_IOFLD_SCBD, + SET_H2C_MACRO, SET_MAX1, }; @@ -2340,6 +2346,10 @@ enum rtw89_btc_cxdrvinfo { CXDRVINFO_CTRL, CXDRVINFO_SCAN, CXDRVINFO_TRX, /* WL traffic to WL fw */ + CXDRVINFO_TXPWR, + CXDRVINFO_FDDT, + CXDRVINFO_MLO, + CXDRVINFO_OSI, CXDRVINFO_MAX, }; @@ -4548,15 +4558,15 @@ int rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi); -int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id); int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, struct sk_buff *skb_ofld); From eae888cfb73483ccf8175da9bbc8cc2e313c7083 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Thu, 29 Feb 2024 15:45:12 +0800 Subject: [PATCH 1872/2255] wifi: rtw89: coex: add return value to ensure H2C command is success or not Add return value to H2C function, and only record down the value while H2C command success, this can help us to check the real time status. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 52 ++++++++++++++--------- drivers/net/wireless/realtek/rtw89/coex.h | 2 + 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index c270d0c26c00..c74b1b6be2d3 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -683,20 +683,25 @@ static void _run_coex(struct rtw89_dev *rtwdev, static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state); static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update); -static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, - void *param, u16 len) +static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, + void *param, u16 len) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &cx->wl; + struct rtw89_btc_dm *dm = &btc->dm; int ret; - if (!wl->status.map.init_ok) { + if (len > BTC_H2C_MAXLEN || len == 0) { + btc->fwinfo.cnt_h2c_fail++; + dm->error.map.h2c_buffer_over = true; + return -EINVAL; + } else if (!wl->status.map.init_ok) { rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): return by btc not init!!\n", __func__); pfwinfo->cnt_h2c_fail++; - return; + return -EINVAL; } else if ((wl->status.map.rf_off_pre == BTC_LPS_RF_OFF && wl->status.map.rf_off == BTC_LPS_RF_OFF) || (wl->status.map.lps_pre == BTC_LPS_RF_OFF && @@ -704,15 +709,17 @@ static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): return by wl off!!\n", __func__); pfwinfo->cnt_h2c_fail++; - return; + return -EINVAL; } - pfwinfo->cnt_h2c++; - ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len, false, true); - if (ret != 0) + if (ret) pfwinfo->cnt_h2c_fail++; + else + pfwinfo->cnt_h2c++; + + return ret; } static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) @@ -1938,6 +1945,7 @@ static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev, struct rtw89_btc_btf_fwinfo *fwinfo = &btc->fwinfo; struct rtw89_btc_btf_set_report r = {0}; u32 val, bit_map; + int ret; if ((wl_smap->rf_off || wl_smap->lps != BTC_LPS_OFF) && rpt_state != 0) return; @@ -1956,13 +1964,13 @@ static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev, if (val == fwinfo->rpt_en_map) return; - fwinfo->rpt_en_map = val; - r.fver = BTF_SET_REPORT_VER; r.enable = cpu_to_le32(val); r.para = cpu_to_le32(rpt_state); - _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r, sizeof(r)); + ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r, sizeof(r)); + if (!ret) + fwinfo->rpt_en_map = val; } static void rtw89_btc_fw_set_slots(struct rtw89_dev *rtwdev, u8 num, @@ -2050,6 +2058,7 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type, { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; + int ret; dm->run_action = action; @@ -2078,11 +2087,12 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type, if (btc->lps == 1) rtw89_set_coex_ctrl_lps(rtwdev, btc->lps); - _send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY, - btc->policy, btc->policy_len); - - memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now)); - memcpy(&dm->slot_now, &dm->slot, sizeof(dm->slot_now)); + ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY, + btc->policy, btc->policy_len); + if (!ret) { + memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now)); + memcpy(&dm->slot_now, &dm->slot, sizeof(dm->slot_now)); + } if (btc->update_policy_force) btc->update_policy_force = false; @@ -2298,20 +2308,22 @@ static void _set_bt_tx_power(struct rtw89_dev *rtwdev, u8 level) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_bt_info *bt = &btc->cx.bt; + int ret; u8 buf; if (bt->rf_para.tx_pwr_freerun == level) return; - bt->rf_para.tx_pwr_freerun = level; - btc->dm.rf_trx_para.bt_tx_power = level; - rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): level = %d\n", __func__, level); buf = (s8)(-level); - _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_TX_PWR, &buf, 1); + ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_TX_PWR, &buf, 1); + if (!ret) { + bt->rf_para.tx_pwr_freerun = level; + btc->dm.rf_trx_para.bt_tx_power = level; + } } #define BTC_BT_RX_NORMAL_LVL 7 diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index dd9707b4a6d4..13303830684e 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -7,6 +7,8 @@ #include "core.h" +#define BTC_H2C_MAXLEN 2020 + enum btc_mode { BTC_MODE_NORMAL, BTC_MODE_WL, From bb90a32c3c7d3475dc751b2c0208bd10838d4e31 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Thu, 29 Feb 2024 15:45:13 +0800 Subject: [PATCH 1873/2255] wifi: rtw89: coex: When Bluetooth not available don't set power/gain If Bluetooth is working, it will update their info regularly. And the code will increase the counters while the info updating. Use this counter to judge is Bluetooth working or not. Don't need to set Bluetooth power or gain when it is not working. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index c74b1b6be2d3..6a1f9a555ce7 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -2311,6 +2311,9 @@ static void _set_bt_tx_power(struct rtw89_dev *rtwdev, u8 level) int ret; u8 buf; + if (btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE] == 0) + return; + if (bt->rf_para.tx_pwr_freerun == level) return; @@ -2333,6 +2336,9 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level) struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_bt_info *bt = &btc->cx.bt; + if (btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE] == 0) + return; + if ((bt->rf_para.rx_gain_freerun == level || level > BTC_BT_RX_NORMAL_LVL) && (!rtwdev->chip->scbd || bt->lna_constrain == level)) From 2422c2158fb51b7ba94e0a8b4ac280c88e0c73a6 Mon Sep 17 00:00:00 2001 From: Ching-Te Ku Date: Thu, 29 Feb 2024 15:45:14 +0800 Subject: [PATCH 1874/2255] wifi: rtw89: coex: Add coexistence policy to decrease WiFi packet CRC-ERR The 2 Bluetooth profiles (Hands free profile & Human interface device) have high duty transmission, it will affect the traffic of WiFi packet frequently. And once the WiFi traffic down to B/G mode, it will need a better success rate to recover the transmission rate. Add new policy option to solve the above situation. Signed-off-by: Ching-Te Ku Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240229074514.219276-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 44 +++++++++++++++++++---- drivers/net/wireless/realtek/rtw89/core.h | 1 + 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 6a1f9a555ce7..d9b66d43f32e 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -358,17 +358,26 @@ enum btc_cx_poicy_type { /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */ BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5, + /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */ + BTC_CXP_OFF_EQ4 = (BTC_CXP_OFF << 8) | 6, + + /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */ + BTC_CXP_OFF_EQ5 = (BTC_CXP_OFF << 8) | 7, + /* TDMA off + pri: BT_Hi > WL > BT_Lo */ - BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 6, + BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 8, /* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */ - BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 7, + BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 9, /* TDMA off + pri: WL_Hi-Tx > BT, BT_Hi > other-WL > BT_Lo */ - BTC_CXP_OFF_BWB2 = (BTC_CXP_OFF << 8) | 8, + BTC_CXP_OFF_BWB2 = (BTC_CXP_OFF << 8) | 10, /* TDMA off + pri: WL_Hi-Tx = BT */ - BTC_CXP_OFF_BWB3 = (BTC_CXP_OFF << 8) | 9, + BTC_CXP_OFF_BWB3 = (BTC_CXP_OFF << 8) | 11, + + /* TDMA off + pri: WL > BT, Block-BT*/ + BTC_CXP_OFF_WL2 = (BTC_CXP_OFF << 8) | 12, /* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo*/ BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0, @@ -3086,6 +3095,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1; struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt.link_info.hid_desc; struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt.link_info.hfp_desc; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; u8 type, null_role; u32 tbl_w1, tbl_b1, tbl_b4; @@ -3111,9 +3121,16 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) tbl_b4 = cxtbl[2]; } } else { - tbl_w1 = cxtbl[16]; tbl_b1 = cxtbl[17]; tbl_b4 = cxtbl[17]; + + if (wl->bg_mode) + tbl_w1 = cxtbl[8]; + else if ((wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) && + hid->exist) + tbl_w1 = cxtbl[19]; + else + tbl_w1 = cxtbl[16]; } btc->bt_req_en = false; @@ -3727,7 +3744,12 @@ static void _action_bt_hfp(struct rtw89_dev *rtwdev) _set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP); } } else { - _set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP); + if (wl->bg_mode) + _set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP); + else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) + _set_policy(rtwdev, BTC_CXP_OFF_EQ5, BTC_ACT_BT_HFP); + else + _set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP); } } @@ -3760,7 +3782,12 @@ static void _action_bt_hid(struct rtw89_dev *rtwdev) policy_type = BTC_CXP_OFF_BWB1; } } else { /* dedicated-antenna */ - policy_type = BTC_CXP_OFF_EQ3; + if (wl->bg_mode) + policy_type = BTC_CXP_OFF_BWB1; + else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) + policy_type = BTC_CXP_OFF_EQ4; + else + policy_type = BTC_CXP_OFF_EQ3; } _set_policy(rtwdev, policy_type, BTC_ACT_BT_HID); @@ -7049,10 +7076,13 @@ static const char *steps_to_str(u16 step) CASE_BTC_POLICY_STR(OFF_EQ1); CASE_BTC_POLICY_STR(OFF_EQ2); CASE_BTC_POLICY_STR(OFF_EQ3); + CASE_BTC_POLICY_STR(OFF_EQ4); + CASE_BTC_POLICY_STR(OFF_EQ5); CASE_BTC_POLICY_STR(OFF_BWB0); CASE_BTC_POLICY_STR(OFF_BWB1); CASE_BTC_POLICY_STR(OFF_BWB2); CASE_BTC_POLICY_STR(OFF_BWB3); + CASE_BTC_POLICY_STR(OFF_WL2); CASE_BTC_POLICY_STR(OFFB_BWB0); CASE_BTC_POLICY_STR(OFFE_DEF); CASE_BTC_POLICY_STR(OFFE_DEF2); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7957b7b9e4c7..cbebfbf1d64a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1741,6 +1741,7 @@ struct rtw89_btc_wl_info { u8 cn_report; u8 coex_mode; + bool bg_mode; bool scbd_change; u32 scbd; }; From b4152222e04cb8afeeca239c90e3fcaf4c553b42 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Thu, 29 Feb 2024 18:31:53 +0800 Subject: [PATCH 1875/2255] wifi: brcm80211: handle pmk_op allocation failure The kzalloc() in brcmf_pmksa_v3_op() will return null if the physical memory has run out. As a result, if we dereference the null value, the null pointer dereference bug will happen. Return -ENOMEM from brcmf_pmksa_v3_op() if kzalloc() fails for pmk_op. Fixes: a96202acaea4 ("wifi: brcmfmac: cfg80211: Add support for PMKID_V3 operations") Acked-by: Arend van Spriel Signed-off-by: Duoming Zhou Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://msgid.link/20240229103153.18533-1-duoming@zju.edu.cn --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 54ff59a8c35c..b99aa66dc5a9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -4308,6 +4308,9 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa, int ret; pmk_op = kzalloc(sizeof(*pmk_op), GFP_KERNEL); + if (!pmk_op) + return -ENOMEM; + pmk_op->version = cpu_to_le16(BRCMF_PMKSA_VER_3); if (!pmksa) { From 6ec8faa36564ccf627a8c24b67d9000a459e2312 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 2 Mar 2024 08:58:22 +0800 Subject: [PATCH 1876/2255] wifi: rtw89: wow: update WoWLAN reason register for different chips The WoWLAN reason register is used for driver to get the wakeup reason for reporting to cfg80211, and it is different from chips. So put it into chip information. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240302005828.13666-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + 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/wow.c | 9 +-------- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index cbebfbf1d64a..fb590f51f4f1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3954,6 +3954,7 @@ struct rtw89_chip_info { const u32 *c2h_regs; struct rtw89_reg_def c2h_counter_reg; const struct rtw89_page_regs *page_regs; + u32 wow_reason_reg; bool cfo_src_fd; bool cfo_hw_comp; const struct rtw89_reg_def *dcfo_comp; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index d1f9cb427f55..51d3e61eaa1d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2506,6 +2506,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8851b_c2h_regs, .page_regs = &rtw8851b_page_regs, + .wow_reason_reg = R_AX_C2HREG_DATA3 + 3, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = &rtw8851b_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index ade8604bacb8..2deadec715cf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2223,6 +2223,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .c2h_regs = rtw8852a_c2h_regs, .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .page_regs = &rtw8852a_page_regs, + .wow_reason_reg = R_AX_C2HREG_DATA3 + 3, .cfo_src_fd = false, .cfo_hw_comp = false, .dcfo_comp = &rtw8852a_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 5b8c3460e35a..d025c4135e1c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2657,6 +2657,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8852b_c2h_regs, .page_regs = &rtw8852b_page_regs, + .wow_reason_reg = R_AX_C2HREG_DATA3 + 3, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = &rtw8852b_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 84ee7483acda..17e6164855fa 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2997,6 +2997,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8852c_c2h_regs, .page_regs = &rtw8852c_page_regs, + .wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3, .cfo_src_fd = false, .cfo_hw_comp = false, .dcfo_comp = &rtw8852c_dcfo_comp, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index ca7babf62f8a..367459bd1345 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2453,6 +2453,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .c2h_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, .c2h_regs = rtw8922a_c2h_regs, .page_regs = &rtw8922a_page_regs, + .wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 4c17936795b6..a3d93503717b 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -85,21 +85,14 @@ static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) { - enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + u32 wow_reason_reg = rtwdev->chip->wow_reason_reg; struct cfg80211_wowlan_nd_info nd_info; struct cfg80211_wowlan_wakeup wakeup = { .pattern_idx = -1, }; - u32 wow_reason_reg; u8 reason; - if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) - wow_reason_reg = R_AX_C2HREG_DATA3 + 3; - else - wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3; - reason = rtw89_read8(rtwdev, wow_reason_reg); - switch (reason) { case RTW89_WOW_RSN_RX_DEAUTH: wakeup.disconnect = true; From a0f0046533cf2ef15546e1a9cd393a6b8ef3d483 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 2 Mar 2024 08:58:23 +0800 Subject: [PATCH 1877/2255] wifi: rtw89: wow: update WoWLAN status register for different generation The statue register is for driver to check if WoWLAN mode works or stops successfully. It 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/20240302005828.13666-3-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/reg.h | 6 ++++++ drivers/net/wireless/realtek/rtw89/wow.c | 3 ++- 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 288383ee6d1e..67adb005f121 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6308,6 +6308,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .addr = R_AX_RXTRIG_TEST_USER_2, .mask = B_AX_RXTRIG_RU26_DIS, }, + .wow_ctrl = {.addr = R_AX_WOW_CTRL, .mask = B_AX_WOW_WOWEN,}, .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 c55b7e4918eb..3e9a65125054 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 { struct rtw89_reg_def muedca_ctrl; struct rtw89_reg_def bfee_ctrl; struct rtw89_reg_def narrow_bw_ru_dis; + struct rtw89_reg_def wow_ctrl; 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 7ca94b70a9cb..1d03197529ce 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2520,6 +2520,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .addr = R_BE_RXTRIG_TEST_USER_2, .mask = B_BE_RXTRIG_RU26_DIS, }, + .wow_ctrl = {.addr = R_BE_WOW_CTRL, .mask = B_BE_WOW_WOWEN,}, .check_mac_en = rtw89_mac_check_mac_en_be, .sys_init = sys_init_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 12568eec32ab..3a8117b666bf 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5540,6 +5540,12 @@ #define B_BE_CUT_AMSDU_CHKLEN_L_TH_MASK GENMASK(23, 16) #define B_BE_CUT_AMSDU_CHKLEN_H_TH_MASK GENMASK(15, 0) +#define R_BE_WOW_CTRL 0x9CB8 +#define B_BE_WOW_HCI BIT(5) +#define B_BE_WOW_DROP BIT(2) +#define B_BE_WOW_WOWEN BIT(1) +#define B_BE_WOW_FORCE_WAKEUP BIT(0) + #define R_BE_RX_HDRTRNS 0x9CC0 #define B_BE_RX_MGN_MLD_ADDR_EN BIT(6) #define B_BE_HDR_INFO_MASK GENMASK(5, 4) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index a3d93503717b..852f8a7794be 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -463,13 +463,14 @@ static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) static int rtw89_wow_check_fw_status(struct rtw89_dev *rtwdev, bool wow_enable) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u8 polling; int ret; ret = read_poll_timeout_atomic(rtw89_read8_mask, polling, wow_enable == !!polling, 50, 50000, false, rtwdev, - R_AX_WOW_CTRL, B_AX_WOW_WOWEN); + mac->wow_ctrl.addr, mac->wow_ctrl.mask); if (ret) rtw89_err(rtwdev, "failed to check wow status %s\n", wow_enable ? "enabled" : "disabled"); From 1bf6fa8ac6d5e7ef86ea3dd533b52f5bc8472b3a Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 2 Mar 2024 08:58:24 +0800 Subject: [PATCH 1878/2255] wifi: rtw89: update DMA function with different generation The register of control and polling function for TX/RX DMA is different from different generation, so update them. Also rename polling_dma function to polling_dma_idle to avoid misunderstanding. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240302005828.13666-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 8 +++--- drivers/net/wireless/realtek/rtw89/pci.c | 29 ++++++++++++--------- drivers/net/wireless/realtek/rtw89/pci.h | 27 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/pci_be.c | 24 ++++++++++++----- drivers/net/wireless/realtek/rtw89/wow.c | 4 +-- 5 files changed, 68 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index fb590f51f4f1..2e854c9af709 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3202,7 +3202,7 @@ struct rtw89_hci_ops { void (*ctrl_txdma_ch)(struct rtw89_dev *rtwdev, bool enable); void (*ctrl_txdma_fw_ch)(struct rtw89_dev *rtwdev, bool enable); void (*ctrl_trxhci)(struct rtw89_dev *rtwdev, bool enable); - int (*poll_txdma_ch)(struct rtw89_dev *rtwdev); + int (*poll_txdma_ch_idle)(struct rtw89_dev *rtwdev); void (*clr_idx_all)(struct rtw89_dev *rtwdev); void (*clear)(struct rtw89_dev *rtwdev, struct pci_dev *pdev); void (*disable_intr)(struct rtw89_dev *rtwdev); @@ -5253,12 +5253,12 @@ static inline void rtw89_hci_ctrl_trxhci(struct rtw89_dev *rtwdev, bool enable) rtwdev->hci.ops->ctrl_trxhci(rtwdev, enable); } -static inline int rtw89_hci_poll_txdma_ch(struct rtw89_dev *rtwdev) +static inline int rtw89_hci_poll_txdma_ch_idle(struct rtw89_dev *rtwdev) { int ret = 0; - if (rtwdev->hci.ops->poll_txdma_ch) - ret = rtwdev->hci.ops->poll_txdma_ch(rtwdev); + if (rtwdev->hci.ops->poll_txdma_ch_idle) + ret = rtwdev->hci.ops->poll_txdma_ch_idle(rtwdev); return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index d4c8799d6f2e..19001130ad94 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -218,7 +218,7 @@ int rtw89_pci_sync_skb_for_device_and_validate_rx_info(struct rtw89_dev *rtwdev, return ret; } -static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable) +static void rtw89_pci_ctrl_txdma_ch_ax(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_pci_info *info = rtwdev->pci_info; const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1; @@ -235,7 +235,7 @@ static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable) } } -static void rtw89_pci_ctrl_txdma_fw_ch_pcie(struct rtw89_dev *rtwdev, bool enable) +static void rtw89_pci_ctrl_txdma_fw_ch_ax(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_pci_info *info = rtwdev->pci_info; const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1; @@ -2524,7 +2524,7 @@ static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev) B_AX_CLR_RXQ_IDX | B_AX_CLR_RPQ_IDX); } -static int rtw89_poll_txdma_ch_idle_pcie(struct rtw89_dev *rtwdev) +static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; u32 ret, check, dma_busy; @@ -2551,7 +2551,7 @@ static int rtw89_poll_txdma_ch_idle_pcie(struct rtw89_dev *rtwdev) return 0; } -static int rtw89_poll_rxdma_ch_idle_pcie(struct rtw89_dev *rtwdev) +static int rtw89_pci_poll_rxdma_ch_idle_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; u32 ret, check, dma_busy; @@ -2571,13 +2571,13 @@ static int rtw89_pci_poll_dma_all_idle(struct rtw89_dev *rtwdev) { u32 ret; - ret = rtw89_poll_txdma_ch_idle_pcie(rtwdev); + ret = rtw89_pci_poll_txdma_ch_idle_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "txdma ch busy\n"); return ret; } - ret = rtw89_poll_rxdma_ch_idle_pcie(rtwdev); + ret = rtw89_pci_poll_rxdma_ch_idle_ax(rtwdev); if (ret) { rtw89_err(rtwdev, "rxdma ch busy\n"); return ret; @@ -2756,8 +2756,8 @@ static int rtw89_pci_ops_mac_pre_init_ax(struct rtw89_dev *rtwdev) } /* disable all channels except to FW CMD channel to download firmware */ - rtw89_pci_ctrl_txdma_ch_pcie(rtwdev, false); - rtw89_pci_ctrl_txdma_fw_ch_pcie(rtwdev, true); + rtw89_pci_ctrl_txdma_ch_ax(rtwdev, false); + rtw89_pci_ctrl_txdma_fw_ch_ax(rtwdev, true); /* start DMA activities */ rtw89_pci_ctrl_dma_all(rtwdev, true); @@ -2870,7 +2870,7 @@ static int rtw89_pci_ops_mac_post_init_ax(struct rtw89_dev *rtwdev) } /* enable DMA for all queues */ - rtw89_pci_ctrl_txdma_ch_pcie(rtwdev, true); + rtw89_pci_ctrl_txdma_ch_ax(rtwdev, true); /* Release PCI IO */ rtw89_write32_clr(rtwdev, info->dma_stop1.addr, @@ -4093,6 +4093,10 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_ax, .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_ax, + .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_ax, + .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_ax, + .poll_txdma_ch_idle = rtw89_pci_poll_txdma_ch_idle_ax, + .aspm_set = rtw89_pci_aspm_set_ax, .clkreq_set = rtw89_pci_clkreq_set_ax, .l1ss_set = rtw89_pci_l1ss_set_ax, @@ -4130,10 +4134,11 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .recovery_start = rtw89_pci_ops_recovery_start, .recovery_complete = rtw89_pci_ops_recovery_complete, - .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_pcie, - .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_pcie, + .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch, + .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch, .ctrl_trxhci = rtw89_pci_ctrl_dma_trx, - .poll_txdma_ch = rtw89_poll_txdma_ch_idle_pcie, + .poll_txdma_ch_idle = rtw89_pci_poll_txdma_ch_idle, + .clr_idx_all = rtw89_pci_clr_idx_all, .clear = rtw89_pci_clear_resource, .disable_intr = rtw89_pci_disable_intr_lock, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index c1954cb12030..4a817dd9822e 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1243,6 +1243,10 @@ struct rtw89_pci_gen_def { int (*lv1rst_stop_dma)(struct rtw89_dev *rtwdev); int (*lv1rst_start_dma)(struct rtw89_dev *rtwdev); + void (*ctrl_txdma_ch)(struct rtw89_dev *rtwdev, bool enable); + void (*ctrl_txdma_fw_ch)(struct rtw89_dev *rtwdev, bool enable); + int (*poll_txdma_ch_idle)(struct rtw89_dev *rtwdev); + void (*aspm_set)(struct rtw89_dev *rtwdev, bool enable); void (*clkreq_set)(struct rtw89_dev *rtwdev, bool enable); void (*l1ss_set)(struct rtw89_dev *rtwdev, bool enable); @@ -1709,4 +1713,27 @@ static inline int rtw89_pci_reset_bdram(struct rtw89_dev *rtwdev) return gen_def->rst_bdram(rtwdev); } +static inline void rtw89_pci_ctrl_txdma_ch(struct rtw89_dev *rtwdev, bool enable) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->ctrl_txdma_ch(rtwdev, enable); +} + +static inline void rtw89_pci_ctrl_txdma_fw_ch(struct rtw89_dev *rtwdev, bool enable) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->ctrl_txdma_fw_ch(rtwdev, enable); +} + +static inline int rtw89_pci_poll_txdma_ch_idle(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + return gen_def->poll_txdma_ch_idle(rtwdev); +} #endif diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 0276d5d05925..1a3f02c687f7 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -317,8 +317,7 @@ static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); } -static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool all_en, - bool h2c_en) +static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool enable) { u32 mask_all; u32 val; @@ -331,12 +330,19 @@ static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool all_en, val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1); val |= B_BE_STOP_CH13 | B_BE_STOP_CH14; - if (all_en) + if (enable) val &= ~mask_all; else val |= mask_all; - if (h2c_en) + rtw89_write32(rtwdev, R_BE_HAXI_DMA_STOP1, val); +} + +static void rtw89_pci_ctrl_txdma_fw_ch_be(struct rtw89_dev *rtwdev, bool enable) +{ + u32 val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1); + + if (enable) val &= ~B_BE_STOP_CH12; else val |= B_BE_STOP_CH12; @@ -375,7 +381,8 @@ static int rtw89_pci_ops_mac_pre_init_be(struct rtw89_dev *rtwdev) rtw89_pci_pcie_setting_be(rtwdev); rtw89_pci_ser_setting_be(rtwdev); - rtw89_pci_ctrl_txdma_ch_be(rtwdev, false, true); + rtw89_pci_ctrl_txdma_ch_be(rtwdev, false); + rtw89_pci_ctrl_txdma_fw_ch_be(rtwdev, true); rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_ENABLE, MAC_AX_PCIE_ENABLE, MAC_AX_PCIE_ENABLE); @@ -485,7 +492,8 @@ static int rtw89_pci_ops_mac_post_init_be(struct rtw89_dev *rtwdev) rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_IGNORE, MAC_AX_PCIE_IGNORE, MAC_AX_PCIE_ENABLE); rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, true); - rtw89_pci_ctrl_txdma_ch_be(rtwdev, true, true); + rtw89_pci_ctrl_txdma_ch_be(rtwdev, true); + rtw89_pci_ctrl_txdma_fw_ch_be(rtwdev, true); rtw89_pci_configure_mit_be(rtwdev); return 0; @@ -559,6 +567,10 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_be, .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_be, + .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_be, + .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_be, + .poll_txdma_ch_idle = rtw89_pci_poll_txdma_ch_idle_be, + .aspm_set = rtw89_pci_aspm_set_be, .clkreq_set = rtw89_pci_clkreq_set_be, .l1ss_set = rtw89_pci_l1ss_set_be, diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 852f8a7794be..286c59931fca 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -560,7 +560,7 @@ static int rtw89_wow_enable_trx_pre(struct rtw89_dev *rtwdev) rtw89_mac_ptk_drop_by_band_and_wait(rtwdev, RTW89_MAC_0); - ret = rtw89_hci_poll_txdma_ch(rtwdev); + ret = rtw89_hci_poll_txdma_ch_idle(rtwdev); if (ret) { rtw89_err(rtwdev, "txdma ch busy\n"); return ret; @@ -583,7 +583,7 @@ static int rtw89_wow_enable_trx_post(struct rtw89_dev *rtwdev) rtw89_hci_disable_intr(rtwdev); rtw89_hci_ctrl_trxhci(rtwdev, false); - ret = rtw89_hci_poll_txdma_ch(rtwdev); + ret = rtw89_hci_poll_txdma_ch_idle(rtwdev); if (ret) { rtw89_err(rtwdev, "failed to poll txdma ch idle pcie\n"); return ret; From fff821286f7b3f15fd0b9228c03668e6b5778e05 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 2 Mar 2024 08:58:25 +0800 Subject: [PATCH 1879/2255] wifi: rtw89: wow: update config mac function with different generation The registers to configure mac function for WoWLAN mode that are different from different generation, so update them. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240302005828.13666-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.h | 9 +++- drivers/net/wireless/realtek/rtw89/mac.c | 37 ++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 8 ++++ drivers/net/wireless/realtek/rtw89/mac_be.c | 48 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 16 +++++++ drivers/net/wireless/realtek/rtw89/wow.c | 28 +----------- 6 files changed, 117 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 6993451a6ef9..44311f65b4fa 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -64,6 +64,8 @@ struct rtw89_h2creg_sch_tx_en { #define RTW89_H2CREG_SCH_TX_EN_W1_MASK GENMASK(15, 0) #define RTW89_H2CREG_SCH_TX_EN_W1_BAND BIT(16) +#define RTW89_H2CREG_WOW_CPUIO_RX_CTRL_EN GENMASK(23, 16) + #define RTW89_H2CREG_MAX 4 #define RTW89_C2HREG_MAX 4 #define RTW89_C2HREG_HDR_LEN 2 @@ -95,7 +97,9 @@ enum rtw89_mac_h2c_type { RTW89_FWCMD_H2CREG_FUNC_FWERR, RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE, RTW89_FWCMD_H2CREG_FUNC_GETPKT_INFORM, - RTW89_FWCMD_H2CREG_FUNC_SCH_TX_EN + RTW89_FWCMD_H2CREG_FUNC_SCH_TX_EN, + RTW89_FWCMD_H2CREG_FUNC_WOW_TRX_STOP = 0x6, + RTW89_FWCMD_H2CREG_FUNC_WOW_CPUIO_RX_CTRL = 0xA, }; enum rtw89_mac_c2h_type { @@ -104,7 +108,8 @@ enum rtw89_mac_c2h_type { RTW89_FWCMD_C2HREG_FUNC_ERR_MSG, RTW89_FWCMD_C2HREG_FUNC_PHY_CAP, RTW89_FWCMD_C2HREG_FUNC_TX_PAUSE_RPT, - RTW89_FWCMD_C2HREG_FUNC_NULL = 0xFF + RTW89_FWCMD_C2HREG_FUNC_WOW_CPUIO_RX_ACK = 0xA, + RTW89_FWCMD_C2HREG_FUNC_NULL = 0xFF, }; enum rtw89_fw_c2h_category { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 67adb005f121..06a4b7ab0200 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6266,6 +6266,41 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, return ret; } +static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + int ret; + + if (enable_wow) { + ret = rtw89_mac_resize_ple_rx_quota(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); + return ret; + } + + rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); + rtw89_write32_clr(rtwdev, mac->rx_fltr, B_AX_SNIFFER_MODE); + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); + rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0); + rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0); + rtw89_write32(rtwdev, R_AX_TF_FWD, 0); + rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); + } else { + ret = rtw89_mac_resize_ple_rx_quota(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); + return ret; + } + + rtw89_write32_clr(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); + rtw89_write32(rtwdev, R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD); + rtw89_write32(rtwdev, R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD); + } + + return 0; +} + static u8 rtw89_fw_get_rdy_ax(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type) { u8 val = rtw89_read8(rtwdev, R_AX_WCPU_FW_CTRL); @@ -6357,5 +6392,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .add_chan_list = rtw89_hw_scan_add_chan_list, .scan_offload = rtw89_fw_h2c_scan_offload, + + .wow_config_mac = rtw89_wow_config_mac_ax, }; 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 3e9a65125054..6fb457153a11 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -169,6 +169,12 @@ enum rtw89_mac_ax_l0_to_l1_event { MAC_AX_L0_TO_L1_EVENT_MAX = 15, }; +enum rtw89_mac_wow_fw_status { + WOWLAN_NOT_READY = 0x00, + WOWLAN_SLEEP_READY = 0x01, + WOWLAN_RESUME_READY = 0x02, +}; + #define RTW89_PORT_OFFSET_TU_TO_32US(shift_tu) ((shift_tu) * 1024 / 32) enum rtw89_mac_dbg_port_sel { @@ -980,6 +986,8 @@ struct rtw89_mac_gen_def { int (*scan_offload)(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, struct rtw89_vif *rtwvif); + + int (*wow_config_mac)(struct rtw89_dev *rtwdev, bool enable_wow); }; 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 1d03197529ce..f16467377eab 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2307,6 +2307,52 @@ static void rtw89_mac_dump_qta_lost_be(struct rtw89_dev *rtwdev) dump_err_status_dispatcher_be(rtwdev); } +static int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable) +{ + struct rtw89_mac_h2c_info h2c_info = {}; + struct rtw89_mac_c2h_info c2h_info = {}; + u32 ret; + + h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_WOW_CPUIO_RX_CTRL; + h2c_info.content_len = sizeof(h2c_info.u.hdr); + h2c_info.u.hdr.w0 = u32_encode_bits(wow_enable, RTW89_H2CREG_WOW_CPUIO_RX_CTRL_EN); + + ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, &c2h_info); + if (ret) + return ret; + + if (c2h_info.id != RTW89_FWCMD_C2HREG_FUNC_WOW_CPUIO_RX_ACK) + ret = -EINVAL; + + return ret; +} + +static int rtw89_wow_config_mac_be(struct rtw89_dev *rtwdev, bool enable_wow) +{ + if (enable_wow) { + rtw89_write32_set(rtwdev, R_BE_RX_STOP, B_BE_HOST_RX_STOP); + rtw89_write32_clr(rtwdev, R_BE_RX_FLTR_OPT, B_BE_SNIFFER_MODE); + rtw89_mac_cpu_io_rx(rtwdev, enable_wow); + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); + rtw89_write32(rtwdev, R_BE_FWD_ERR, 0); + rtw89_write32(rtwdev, R_BE_FWD_ACTN0, 0); + rtw89_write32(rtwdev, R_BE_FWD_ACTN1, 0); + rtw89_write32(rtwdev, R_BE_FWD_ACTN2, 0); + rtw89_write32(rtwdev, R_BE_FWD_TF0, 0); + rtw89_write32(rtwdev, R_BE_FWD_TF1, 0); + rtw89_write32(rtwdev, R_BE_FWD_ERR, 0); + rtw89_write32(rtwdev, R_BE_HW_PPDU_STATUS, 0); + rtw89_write8(rtwdev, R_BE_DBG_WOW_READY, WOWLAN_NOT_READY); + } else { + rtw89_mac_cpu_io_rx(rtwdev, enable_wow); + rtw89_write32_clr(rtwdev, R_BE_RX_STOP, B_BE_HOST_RX_STOP); + rtw89_write32_set(rtwdev, R_BE_RX_FLTR_OPT, R_BE_RX_FLTR_OPT); + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); + } + + return 0; +} + static void rtw89_mac_dump_cmac_err_status_be(struct rtw89_dev *rtwdev, u8 band) { @@ -2569,5 +2615,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .add_chan_list = rtw89_hw_scan_add_chan_list_be, .scan_offload = rtw89_fw_h2c_scan_offload_be, + + .wow_config_mac = rtw89_wow_config_mac_be, }; EXPORT_SYMBOL(rtw89_mac_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 3a8117b666bf..088d39202ca2 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4456,6 +4456,9 @@ #define B_BE_HCI_RXDMA_EN BIT(1) #define B_BE_HCI_TXDMA_EN BIT(0) +#define R_BE_DBG_WOW_READY 0x815E +#define B_BE_DBG_WOW_READY GENMASK(7, 0) + #define R_BE_DMAC_FUNC_EN 0x8400 #define B_BE_DMAC_CRPRT BIT(31) #define B_BE_MAC_FUNC_EN BIT(30) @@ -5009,6 +5012,12 @@ B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \ B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN) +#define R_BE_RX_STOP 0x8914 +#define B_BE_CPU_RX_STOP BIT(17) +#define B_BE_HOST_RX_STOP BIT(16) +#define B_BE_CPU_RX_CH_STOP_MSK GENMASK(15, 8) +#define B_BE_HOST_RX_CH_STOP_MSK GENMASK(5, 0) + #define R_BE_DISP_FWD_WLAN_0 0x8938 #define B_BE_FWD_WLAN_CPU_TYPE_13_MASK GENMASK(31, 30) #define B_BE_FWD_WLAN_CPU_TYPE_12_MASK GENMASK(29, 28) @@ -5524,6 +5533,13 @@ #define B_BE_DROP_NONDMA_PPDU BIT(2) #define B_BE_APPEND_FCS BIT(0) +#define R_BE_FWD_ERR 0x9C10 +#define R_BE_FWD_ACTN0 0x9C14 +#define R_BE_FWD_ACTN1 0x9C18 +#define R_BE_FWD_ACTN2 0x9C1C +#define R_BE_FWD_TF0 0x9C20 +#define R_BE_FWD_TF1 0x9C24 + #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) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 286c59931fca..689a4e94387a 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -41,34 +41,8 @@ static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev) static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; - int ret; - if (enable_wow) { - ret = rtw89_mac_resize_ple_rx_quota(rtwdev, true); - if (ret) { - rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); - return ret; - } - rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); - rtw89_write32_clr(rtwdev, mac->rx_fltr, B_AX_SNIFFER_MODE); - rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); - rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0); - rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0); - rtw89_write32(rtwdev, R_AX_TF_FWD, 0); - rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); - } else { - ret = rtw89_mac_resize_ple_rx_quota(rtwdev, false); - if (ret) { - rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); - return ret; - } - rtw89_write32_clr(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); - rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); - rtw89_write32(rtwdev, R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD); - rtw89_write32(rtwdev, R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD); - } - - return 0; + return mac->wow_config_mac(rtwdev, enable_wow); } static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) From 60b3f2898a80e7ca38d8bf6ed6bfc707e2282d6f Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 2 Mar 2024 08:58:26 +0800 Subject: [PATCH 1880/2255] wifi: rtw89: update suspend/resume for different generation The setting during suspend or resume is different between different 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/20240302005828.13666-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.h | 3 ++ drivers/net/wireless/realtek/rtw89/pci_be.c | 40 +++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 13 ++++++ .../net/wireless/realtek/rtw89/rtw8922ae.c | 2 +- 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 4a817dd9822e..a63b6b7c9bfa 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -942,6 +942,8 @@ #define B_BE_SER_L1SUB_IMR BIT(1) #define B_BE_SER_PMU_IMR BIT(0) +#define R_BE_REG_PL1_ISR 0x34B4 + #define R_BE_RX_APPEND_MODE 0x8920 #define B_BE_APPEND_OFFSET_MASK GENMASK(23, 16) #define B_BE_APPEND_LEN_MASK GENMASK(15, 0) @@ -1558,6 +1560,7 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) } extern const struct dev_pm_ops rtw89_pm_ops; +extern const struct dev_pm_ops rtw89_pm_ops_be; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be; diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 1a3f02c687f7..7cc328222965 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -550,6 +550,46 @@ static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) return 0; } +static int __maybe_unused rtw89_pci_suspend_be(struct device *dev) +{ + struct ieee80211_hw *hw = dev_get_drvdata(dev); + struct rtw89_dev *rtwdev = hw->priv; + + rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6); + rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_R_DIS_PRST); + rtw89_write32_clr(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6); + rtw89_write32_set(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_FRZ_REG_RST); + rtw89_write32_clr(rtwdev, R_BE_REG_PL1_MASK, B_BE_SER_PM_MASTER_IMR); + return 0; +} + +static int __maybe_unused rtw89_pci_resume_be(struct device *dev) +{ + struct ieee80211_hw *hw = dev_get_drvdata(dev); + struct rtw89_dev *rtwdev = hw->priv; + u32 polling; + int ret; + + rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6); + rtw89_write32_clr(rtwdev, R_BE_RSV_CTRL, B_BE_R_DIS_PRST); + rtw89_write32_clr(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6); + rtw89_write32_clr(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_FRZ_REG_RST); + rtw89_write32_clr(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + + ret = read_poll_timeout_atomic(rtw89_read32, polling, !polling, 1, 1000, + false, rtwdev, R_BE_REG_PL1_ISR); + if (ret) + rtw89_warn(rtwdev, "[ERR] PCIE SER clear polling fail\n"); + + rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + rtw89_write32_set(rtwdev, R_BE_REG_PL1_MASK, B_BE_SER_PM_MASTER_IMR); + + return 0; +} + +SIMPLE_DEV_PM_OPS(rtw89_pm_ops_be, rtw89_pci_suspend_be, rtw89_pci_resume_be); +EXPORT_SYMBOL(rtw89_pm_ops_be); + const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .isr_rdu = B_BE_RDU_CH1_INT | B_BE_RDU_CH0_INT, .isr_halt_c2h = B_BE_HALT_C2H_INT, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 088d39202ca2..72e448e91b6f 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3764,6 +3764,19 @@ #define B_BE_SYM_PADPDN_WL_RFC1_1P3 BIT(6) #define B_BE_SYM_PADPDN_WL_RFC0_1P3 BIT(5) +#define R_BE_RSV_CTRL 0x001C +#define B_BE_HR_BE_DBG GENMASK(23, 12) +#define B_BE_R_SYM_DIS_PCIE_FLR BIT(9) +#define B_BE_R_EN_HRST_PWRON BIT(8) +#define B_BE_LOCK_ALL_EN BIT(7) +#define B_BE_R_DIS_PRST BIT(6) +#define B_BE_WLOCK_1C_BIT6 BIT(5) +#define B_BE_WLOCK_40 BIT(4) +#define B_BE_WLOCK_08 BIT(3) +#define B_BE_WLOCK_04 BIT(2) +#define B_BE_WLOCK_00 BIT(1) +#define B_BE_WLOCK_ALL BIT(0) + #define R_BE_AFE_LDO_CTRL 0x0020 #define B_BE_FORCE_MACBBBT_PWR_ON BIT(31) #define B_BE_R_SYM_WLPOFF_P4_PC_EN BIT(28) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 9f46fb166105..4981b657bd7b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -80,7 +80,7 @@ static struct pci_driver rtw89_8922ae_driver = { .id_table = rtw89_8922ae_id_table, .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, - .driver.pm = &rtw89_pm_ops, + .driver.pm = &rtw89_pm_ops_be, }; module_pci_driver(rtw89_8922ae_driver); From d12d3df874975e8879d77c289812bbb96e5ae1a9 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 2 Mar 2024 08:58:27 +0800 Subject: [PATCH 1881/2255] wifi: rtw89: wow: set security engine options for 802.11ax chips only The security engine is set for management frames by default for 802.11be chips, so no need to set it in WoWLAN flow. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240302005828.13666-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 06a4b7ab0200..aa5b396b5d2b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -2025,6 +2025,9 @@ void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool enable) { u32 msk32 = B_AX_UC_MGNT_DEC | B_AX_BMC_MGNT_DEC; + if (rtwdev->chip->chip_gen != RTW89_CHIP_AX) + return; + if (enable) rtw89_write32_set(rtwdev, R_AX_SEC_ENG_CTRL, msk32); else From 4dc38e39758df9669914d2aa9bbdb488caaaf64c Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Sat, 2 Mar 2024 08:58:28 +0800 Subject: [PATCH 1882/2255] wifi: rtw89: wow: move release offload packet earlier for WoWLAN mode Now WoWLAN firmware will disable PCIE DMA after driver call cfg_wake function, and it will lead to release offload packet fail because driver can't receive completion notification from firmware. We move release offload packet earlier to avoid this error. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240302005828.13666-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/wow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 689a4e94387a..ccad026defb5 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -667,14 +667,14 @@ static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) goto out; } + rtw89_fw_release_general_pkt_list(rtwdev, true); + ret = rtw89_wow_cfg_wake(rtwdev, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable config wake\n"); goto out; } - rtw89_fw_release_general_pkt_list(rtwdev, true); - ret = rtw89_wow_check_fw_status(rtwdev, false); if (ret) { rtw89_err(rtwdev, "wow: failed to check disable fw ready\n"); From e9097f8e1e768a359f2484329191ece2922330ec Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Mon, 4 Mar 2024 10:15:47 +0100 Subject: [PATCH 1883/2255] net: phy: micrel: lan8814 led errata Lan8814 phy led behavior is not correct. It was noticed that the led still remains ON when the cable is unplugged while there was traffic passing at that time. The fix consists in clearing bit 10 of register 0x38, in this way the led behaviour is correct and gets OFF when there is no link. Reviewed-by: Wojciech Drewek Signed-off-by: Horatiu Vultur Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240304091548.1386022-2-horatiu.vultur@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/micrel.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 9b6973581989..88cc03982bb7 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -114,6 +114,9 @@ #define LAN8814_INTR_CTRL_REG_POLARITY BIT(1) #define LAN8814_INTR_CTRL_REG_INTR_ENABLE BIT(0) +#define LAN8814_EEE_STATE 0x38 +#define LAN8814_EEE_STATE_MASK2P5P BIT(10) + /* Represents 1ppm adjustment in 2^32 format with * each nsec contains 4 clock cycles. * The value is calculated as following: (1/1000000)/((2^-32)/4) @@ -3288,6 +3291,19 @@ static int lan8814_release_coma_mode(struct phy_device *phydev) return 0; } +static void lan8814_clear_2psp_bit(struct phy_device *phydev) +{ + u16 val; + + /* It was noticed that when traffic is passing through the PHY and the + * cable is removed then the LED was still one even though there is no + * link + */ + val = lanphy_read_page_reg(phydev, 2, LAN8814_EEE_STATE); + val &= ~LAN8814_EEE_STATE_MASK2P5P; + lanphy_write_page_reg(phydev, 2, LAN8814_EEE_STATE, val); +} + static int lan8814_probe(struct phy_device *phydev) { const struct kszphy_type *type = phydev->drv->driver_data; @@ -3324,6 +3340,9 @@ static int lan8814_probe(struct phy_device *phydev) lan8814_ptp_init(phydev); + /* Errata workarounds */ + lan8814_clear_2psp_bit(phydev); + return 0; } From ad080db4483b46576ccaa68136a1e7918faa8a18 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Mon, 4 Mar 2024 10:15:48 +0100 Subject: [PATCH 1884/2255] net: phy: micrel: lan8814 cable improvement errata When the length of the cable is more than 100m and the lan8814 is configured to run in 1000Base-T Slave then the register of the device needs to be optimized. Workaround this by setting the measure time to a value of 0xb. This value can be set regardless of the configuration. This issue is described in 'LAN8814 Silicon Errata and Data Sheet Clarification' and according to that, this will not be corrected in a future silicon revision. Reviewed-by: Wojciech Drewek Signed-off-by: Horatiu Vultur Reviewed-by: Andrew Lunn Acked-by: Arun Ramadoss Link: https://lore.kernel.org/r/20240304091548.1386022-3-horatiu.vultur@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/micrel.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 88cc03982bb7..8b8634600c51 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -117,6 +117,10 @@ #define LAN8814_EEE_STATE 0x38 #define LAN8814_EEE_STATE_MASK2P5P BIT(10) +#define LAN8814_PD_CONTROLS 0x9d +#define LAN8814_PD_CONTROLS_PD_MEAS_TIME_MASK GENMASK(3, 0) +#define LAN8814_PD_CONTROLS_PD_MEAS_TIME_VAL 0xb + /* Represents 1ppm adjustment in 2^32 format with * each nsec contains 4 clock cycles. * The value is calculated as following: (1/1000000)/((2^-32)/4) @@ -3304,6 +3308,20 @@ static void lan8814_clear_2psp_bit(struct phy_device *phydev) lanphy_write_page_reg(phydev, 2, LAN8814_EEE_STATE, val); } +static void lan8814_update_meas_time(struct phy_device *phydev) +{ + u16 val; + + /* By setting the measure time to a value of 0xb this will allow cables + * longer than 100m to be used. This configuration can be used + * regardless of the mode of operation of the PHY + */ + val = lanphy_read_page_reg(phydev, 1, LAN8814_PD_CONTROLS); + val &= ~LAN8814_PD_CONTROLS_PD_MEAS_TIME_MASK; + val |= LAN8814_PD_CONTROLS_PD_MEAS_TIME_VAL; + lanphy_write_page_reg(phydev, 1, LAN8814_PD_CONTROLS, val); +} + static int lan8814_probe(struct phy_device *phydev) { const struct kszphy_type *type = phydev->drv->driver_data; @@ -3342,6 +3360,7 @@ static int lan8814_probe(struct phy_device *phydev) /* Errata workarounds */ lan8814_clear_2psp_bit(phydev); + lan8814_update_meas_time(phydev); return 0; } From b6e3c115efb5bec0542508a9120b99960073870f Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 2 Mar 2024 14:05:57 -0300 Subject: [PATCH 1885/2255] net: hns: make hnae_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the hnae_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240302-class_cleanup-net-next-v1-1-8fa378595b93@marliere.net Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns/hnae.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.c b/drivers/net/ethernet/hisilicon/hns/hnae.c index 8a1027ad340d..d4293f76d69d 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.c +++ b/drivers/net/ethernet/hisilicon/hns/hnae.c @@ -12,7 +12,9 @@ #define cls_to_ae_dev(dev) container_of(dev, struct hnae_ae_dev, cls_dev) -static struct class *hnae_class; +static const struct class hnae_class = { + .name = "hnae", +}; static void hnae_list_add(spinlock_t *lock, struct list_head *node, struct list_head *head) @@ -111,7 +113,7 @@ static struct hnae_ae_dev *find_ae(const struct fwnode_handle *fwnode) WARN_ON(!fwnode); - dev = class_find_device(hnae_class, NULL, fwnode, __ae_match); + dev = class_find_device(&hnae_class, NULL, fwnode, __ae_match); return dev ? cls_to_ae_dev(dev) : NULL; } @@ -415,7 +417,7 @@ int hnae_ae_register(struct hnae_ae_dev *hdev, struct module *owner) hdev->owner = owner; hdev->id = (int)atomic_inc_return(&id); hdev->cls_dev.parent = hdev->dev; - hdev->cls_dev.class = hnae_class; + hdev->cls_dev.class = &hnae_class; hdev->cls_dev.release = hnae_release; (void)dev_set_name(&hdev->cls_dev, "hnae%d", hdev->id); ret = device_register(&hdev->cls_dev); @@ -448,13 +450,12 @@ EXPORT_SYMBOL(hnae_ae_unregister); static int __init hnae_init(void) { - hnae_class = class_create("hnae"); - return PTR_ERR_OR_ZERO(hnae_class); + return class_register(&hnae_class); } static void __exit hnae_exit(void) { - class_destroy(hnae_class); + class_unregister(&hnae_class); } subsys_initcall(hnae_init); From 63767a76318c4e2b8321b9eed728ba18020aaccf Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 2 Mar 2024 14:05:58 -0300 Subject: [PATCH 1886/2255] net: wan: framer: make framer_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the framer_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Acked-by: Herve Codina Link: https://lore.kernel.org/r/20240302-class_cleanup-net-next-v1-2-8fa378595b93@marliere.net Signed-off-by: Jakub Kicinski --- drivers/net/wan/framer/framer-core.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/wan/framer/framer-core.c b/drivers/net/wan/framer/framer-core.c index 33b358b99f70..f547c22e26ac 100644 --- a/drivers/net/wan/framer/framer-core.c +++ b/drivers/net/wan/framer/framer-core.c @@ -18,7 +18,12 @@ #include #include -static struct class *framer_class; +static void framer_release(struct device *dev); +static const struct class framer_class = { + .name = "framer", + .dev_release = framer_release, +}; + static DEFINE_MUTEX(framer_provider_mutex); static LIST_HEAD(framer_provider_list); static DEFINE_IDA(framer_ida); @@ -627,7 +632,7 @@ struct framer *framer_create(struct device *dev, struct device_node *node, INIT_DELAYED_WORK(&framer->polling_work, framer_polling_work); BLOCKING_INIT_NOTIFIER_HEAD(&framer->notifier_list); - framer->dev.class = framer_class; + framer->dev.class = &framer_class; framer->dev.parent = dev; framer->dev.of_node = node ? node : dev->of_node; framer->id = id; @@ -741,7 +746,7 @@ struct framer *framer_provider_simple_of_xlate(struct device *dev, struct class_dev_iter iter; struct framer *framer; - class_dev_iter_init(&iter, framer_class, NULL, NULL); + class_dev_iter_init(&iter, &framer_class, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) { framer = dev_to_framer(dev); if (args->np != framer->dev.of_node) @@ -870,14 +875,6 @@ static void framer_release(struct device *dev) static int __init framer_core_init(void) { - framer_class = class_create("framer"); - if (IS_ERR(framer_class)) { - pr_err("failed to create framer class (%pe)\n", framer_class); - return PTR_ERR(framer_class); - } - - framer_class->dev_release = framer_release; - - return 0; + return class_register(&framer_class); } device_initcall(framer_core_init); From 2ad2018aa3572a82079b423f61680353bed2af60 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 2 Mar 2024 14:05:59 -0300 Subject: [PATCH 1887/2255] net: ppp: make ppp_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the ppp_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240302-class_cleanup-net-next-v1-3-8fa378595b93@marliere.net Signed-off-by: Jakub Kicinski --- drivers/net/ppp/ppp_generic.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index db1d11ae817b..fe380fe196e7 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -295,7 +295,9 @@ static void ppp_setup(struct net_device *dev); static const struct net_device_ops ppp_netdev_ops; -static struct class *ppp_class; +static const struct class ppp_class = { + .name = "ppp", +}; /* per net-namespace data */ static inline struct ppp_net *ppp_pernet(struct net *net) @@ -1394,11 +1396,9 @@ static int __init ppp_init(void) goto out_net; } - ppp_class = class_create("ppp"); - if (IS_ERR(ppp_class)) { - err = PTR_ERR(ppp_class); + err = class_register(&ppp_class); + if (err) goto out_chrdev; - } err = rtnl_link_register(&ppp_link_ops); if (err) { @@ -1407,12 +1407,12 @@ static int __init ppp_init(void) } /* not a big deal if we fail here :-) */ - device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); + device_create(&ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); return 0; out_class: - class_destroy(ppp_class); + class_unregister(&ppp_class); out_chrdev: unregister_chrdev(PPP_MAJOR, "ppp"); out_net: @@ -3549,8 +3549,8 @@ static void __exit ppp_cleanup(void) pr_err("PPP: removing module but units remain!\n"); rtnl_link_unregister(&ppp_link_ops); unregister_chrdev(PPP_MAJOR, "ppp"); - device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); - class_destroy(ppp_class); + device_destroy(&ppp_class, MKDEV(PPP_MAJOR, 0)); + class_unregister(&ppp_class); unregister_pernet_device(&ppp_net_ops); } From d9567f212b15c2bb2220ca59b3103c752765dded Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 2 Mar 2024 14:06:00 -0300 Subject: [PATCH 1888/2255] net: wwan: hwsim: make wwan_hwsim_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the wwan_hwsim_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Acked-by: Sergey Ryazanov Link: https://lore.kernel.org/r/20240302-class_cleanup-net-next-v1-4-8fa378595b93@marliere.net Signed-off-by: Jakub Kicinski --- drivers/net/wwan/wwan_hwsim.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wwan/wwan_hwsim.c b/drivers/net/wwan/wwan_hwsim.c index ff3dd24ddb33..b02befd1b6fb 100644 --- a/drivers/net/wwan/wwan_hwsim.c +++ b/drivers/net/wwan/wwan_hwsim.c @@ -25,7 +25,9 @@ static int wwan_hwsim_devsnum = 2; module_param_named(devices, wwan_hwsim_devsnum, int, 0444); MODULE_PARM_DESC(devices, "Number of simulated devices"); -static struct class *wwan_hwsim_class; +static const struct class wwan_hwsim_class = { + .name = "wwan_hwsim", +}; static struct dentry *wwan_hwsim_debugfs_topdir; static struct dentry *wwan_hwsim_debugfs_devcreate; @@ -277,7 +279,7 @@ static struct wwan_hwsim_dev *wwan_hwsim_dev_new(void) spin_unlock(&wwan_hwsim_devs_lock); dev->dev.release = wwan_hwsim_dev_release; - dev->dev.class = wwan_hwsim_class; + dev->dev.class = &wwan_hwsim_class; dev_set_name(&dev->dev, "hwsim%u", dev->id); spin_lock_init(&dev->ports_lock); @@ -511,11 +513,9 @@ static int __init wwan_hwsim_init(void) if (!wwan_wq) return -ENOMEM; - wwan_hwsim_class = class_create("wwan_hwsim"); - if (IS_ERR(wwan_hwsim_class)) { - err = PTR_ERR(wwan_hwsim_class); + err = class_register(&wwan_hwsim_class); + if (err) goto err_wq_destroy; - } wwan_hwsim_debugfs_topdir = debugfs_create_dir("wwan_hwsim", NULL); wwan_hwsim_debugfs_devcreate = @@ -534,7 +534,7 @@ err_clean_devs: wwan_hwsim_free_devs(); flush_workqueue(wwan_wq); /* Wait deletion works completion */ debugfs_remove(wwan_hwsim_debugfs_topdir); - class_destroy(wwan_hwsim_class); + class_unregister(&wwan_hwsim_class); err_wq_destroy: destroy_workqueue(wwan_wq); @@ -547,7 +547,7 @@ static void __exit wwan_hwsim_exit(void) wwan_hwsim_free_devs(); flush_workqueue(wwan_wq); /* Wait deletion works completion */ debugfs_remove(wwan_hwsim_debugfs_topdir); - class_destroy(wwan_hwsim_class); + class_unregister(&wwan_hwsim_class); destroy_workqueue(wwan_wq); } From 070bef83f03ea9d91a8011f18113f8967e3df5bf Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 2 Mar 2024 14:06:01 -0300 Subject: [PATCH 1889/2255] net: wwan: core: make wwan_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the wwan_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Acked-by: Sergey Ryazanov Link: https://lore.kernel.org/r/20240302-class_cleanup-net-next-v1-5-8fa378595b93@marliere.net Signed-off-by: Jakub Kicinski --- drivers/net/wwan/wwan_core.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index b0030f3ed0f0..17431f1b1a0c 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -26,7 +26,9 @@ static DEFINE_MUTEX(wwan_register_lock); /* WWAN device create|remove lock */ static DEFINE_IDA(minors); /* minors for WWAN port chardevs */ static DEFINE_IDA(wwan_dev_ids); /* for unique WWAN device IDs */ -static struct class *wwan_class; +static const struct class wwan_class = { + .name = "wwan", +}; static int wwan_major; static struct dentry *wwan_debugfs_dir; @@ -130,7 +132,7 @@ static struct wwan_device *wwan_dev_get_by_parent(struct device *parent) { struct device *dev; - dev = class_find_device(wwan_class, NULL, parent, wwan_dev_parent_match); + dev = class_find_device(&wwan_class, NULL, parent, wwan_dev_parent_match); if (!dev) return ERR_PTR(-ENODEV); @@ -147,7 +149,7 @@ static struct wwan_device *wwan_dev_get_by_name(const char *name) { struct device *dev; - dev = class_find_device(wwan_class, NULL, name, wwan_dev_name_match); + dev = class_find_device(&wwan_class, NULL, name, wwan_dev_name_match); if (!dev) return ERR_PTR(-ENODEV); @@ -183,7 +185,7 @@ static struct wwan_device *wwan_dev_get_by_debugfs(struct dentry *dir) { struct device *dev; - dev = class_find_device(wwan_class, NULL, dir, wwan_dev_debugfs_match); + dev = class_find_device(&wwan_class, NULL, dir, wwan_dev_debugfs_match); if (!dev) return ERR_PTR(-ENODEV); @@ -239,7 +241,7 @@ static struct wwan_device *wwan_create_dev(struct device *parent) } wwandev->dev.parent = parent; - wwandev->dev.class = wwan_class; + wwandev->dev.class = &wwan_class; wwandev->dev.type = &wwan_dev_type; wwandev->id = id; dev_set_name(&wwandev->dev, "wwan%d", wwandev->id); @@ -265,7 +267,7 @@ done_unlock: static int is_wwan_child(struct device *dev, void *data) { - return dev->class == wwan_class; + return dev->class == &wwan_class; } static void wwan_remove_dev(struct wwan_device *wwandev) @@ -375,7 +377,7 @@ static struct wwan_port *wwan_port_get_by_minor(unsigned int minor) { struct device *dev; - dev = class_find_device(wwan_class, NULL, &minor, wwan_port_minor_match); + dev = class_find_device(&wwan_class, NULL, &minor, wwan_port_minor_match); if (!dev) return ERR_PTR(-ENODEV); @@ -405,7 +407,7 @@ static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt) return -ENOMEM; /* Collect ids of same name format ports */ - class_dev_iter_init(&iter, wwan_class, NULL, &wwan_port_dev_type); + class_dev_iter_init(&iter, &wwan_class, NULL, &wwan_port_dev_type); while ((dev = class_dev_iter_next(&iter))) { if (dev->parent != &wwandev->dev) continue; @@ -477,7 +479,7 @@ struct wwan_port *wwan_create_port(struct device *parent, mutex_init(&port->data_lock); port->dev.parent = &wwandev->dev; - port->dev.class = wwan_class; + port->dev.class = &wwan_class; port->dev.type = &wwan_port_dev_type; port->dev.devt = MKDEV(wwan_major, minor); dev_set_drvdata(&port->dev, drvdata); @@ -1212,11 +1214,9 @@ static int __init wwan_init(void) if (err) return err; - wwan_class = class_create("wwan"); - if (IS_ERR(wwan_class)) { - err = PTR_ERR(wwan_class); + err = class_register(&wwan_class); + if (err) goto unregister; - } /* chrdev used for wwan ports */ wwan_major = __register_chrdev(0, 0, WWAN_MAX_MINORS, "wwan_port", @@ -1233,7 +1233,7 @@ static int __init wwan_init(void) return 0; destroy: - class_destroy(wwan_class); + class_unregister(&wwan_class); unregister: rtnl_link_unregister(&wwan_rtnl_link_ops); return err; @@ -1244,7 +1244,7 @@ static void __exit wwan_exit(void) debugfs_remove_recursive(wwan_debugfs_dir); __unregister_chrdev(wwan_major, 0, WWAN_MAX_MINORS, "wwan_port"); rtnl_link_unregister(&wwan_rtnl_link_ops); - class_destroy(wwan_class); + class_unregister(&wwan_class); } module_init(wwan_init); From e5560011692981bc8bfeae7fc0673c65a02badba Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 2 Mar 2024 14:06:02 -0300 Subject: [PATCH 1890/2255] nfc: core: make nfc_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the nfc_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240302-class_cleanup-net-next-v1-6-8fa378595b93@marliere.net Signed-off-by: Jakub Kicinski --- include/net/nfc/nfc.h | 2 +- net/nfc/core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 5dee575fbe86..3d07abacf08b 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -196,7 +196,7 @@ struct nfc_dev { }; #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev) -extern struct class nfc_class; +extern const struct class nfc_class; struct nfc_dev *nfc_allocate_device(const struct nfc_ops *ops, u32 supported_protocols, diff --git a/net/nfc/core.c b/net/nfc/core.c index eb2c0959e5b6..e58dc6405054 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -1015,7 +1015,7 @@ static void nfc_check_pres_timeout(struct timer_list *t) schedule_work(&dev->check_pres_work); } -struct class nfc_class = { +const struct class nfc_class = { .name = "nfc", .dev_release = nfc_release, }; From 60d06425e04558be21634a719b5c60c9bd862c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Mar 2024 10:13:25 +0100 Subject: [PATCH 1891/2255] ptp: fc3: 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: Simon Horman Link: https://lore.kernel.org/r/20240304091325.717546-2-u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/ptp/ptp_fc3.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ptp/ptp_fc3.c b/drivers/ptp/ptp_fc3.c index 0e2286ba088a..6ef982862e27 100644 --- a/drivers/ptp/ptp_fc3.c +++ b/drivers/ptp/ptp_fc3.c @@ -996,13 +996,11 @@ static int idtfc3_probe(struct platform_device *pdev) return 0; } -static int idtfc3_remove(struct platform_device *pdev) +static void idtfc3_remove(struct platform_device *pdev) { struct idtfc3 *idtfc3 = platform_get_drvdata(pdev); ptp_clock_unregister(idtfc3->ptp_clock); - - return 0; } static struct platform_driver idtfc3_driver = { @@ -1010,7 +1008,7 @@ static struct platform_driver idtfc3_driver = { .name = "rc38xxx-phc", }, .probe = idtfc3_probe, - .remove = idtfc3_remove, + .remove_new = idtfc3_remove, }; module_platform_driver(idtfc3_driver); From 49489bb03a501547450e8fdc6d85d023d8a3b2c4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Jan 2024 23:47:57 +0000 Subject: [PATCH 1892/2255] rxrpc: Do zerocopy using MSG_SPLICE_PAGES and page frags Switch from keeping the transmission buffers in the rxrpc_txbuf struct and allocated from the slab, to allocating them using page fragment allocators (which uses raw pages), thereby allowing them to be passed to MSG_SPLICE_PAGES and avoid copying into the UDP buffers. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/ar-internal.h | 32 +++---- net/rxrpc/conn_object.c | 4 + net/rxrpc/insecure.c | 11 +-- net/rxrpc/local_object.c | 3 + net/rxrpc/output.c | 67 +++++++-------- net/rxrpc/rxkad.c | 46 +++++----- net/rxrpc/sendmsg.c | 22 ++--- net/rxrpc/txbuf.c | 176 ++++++++++++++++++++++++++++++--------- 8 files changed, 218 insertions(+), 143 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 9ea4e7e9d9f7..47f4689379ca 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -248,10 +248,9 @@ struct rxrpc_security { struct rxrpc_key_token *); /* Work out how much data we can store in a packet, given an estimate - * of the amount of data remaining. + * of the amount of data remaining and allocate a data buffer. */ - int (*how_much_data)(struct rxrpc_call *, size_t, - size_t *, size_t *, size_t *); + struct rxrpc_txbuf *(*alloc_txbuf)(struct rxrpc_call *call, size_t remaining, gfp_t gfp); /* impose security on a packet */ int (*secure_packet)(struct rxrpc_call *, struct rxrpc_txbuf *); @@ -292,6 +291,7 @@ struct rxrpc_local { struct socket *socket; /* my UDP socket */ struct task_struct *io_thread; struct completion io_thread_ready; /* Indication that the I/O thread started */ + struct page_frag_cache tx_alloc; /* Tx control packet allocation (I/O thread only) */ struct rxrpc_sock *service; /* Service(s) listening on this endpoint */ #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY struct sk_buff_head rx_delay_queue; /* Delay injection queue */ @@ -500,6 +500,8 @@ struct rxrpc_connection { struct list_head proc_link; /* link in procfs list */ struct list_head link; /* link in master connection list */ struct sk_buff_head rx_queue; /* received conn-level packets */ + struct page_frag_cache tx_data_alloc; /* Tx DATA packet allocation */ + struct mutex tx_data_alloc_lock; struct mutex security_lock; /* Lock for security management */ const struct rxrpc_security *security; /* applied security module */ @@ -788,7 +790,6 @@ struct rxrpc_send_params { * Buffer of data to be output as a packet. */ struct rxrpc_txbuf { - struct rcu_head rcu; struct list_head call_link; /* Link in call->tx_sendmsg/tx_buffer */ struct list_head tx_link; /* Link in live Enc queue or Tx queue */ ktime_t last_sent; /* Time at which last transmitted */ @@ -806,22 +807,8 @@ struct rxrpc_txbuf { __be16 cksum; /* Checksum to go in header */ unsigned short ack_rwind; /* ACK receive window */ u8 /*enum rxrpc_propose_ack_trace*/ ack_why; /* If ack, why */ - u8 nr_kvec; - struct kvec kvec[1]; - struct { - /* The packet for encrypting and DMA'ing. We align it such - * that data[] aligns correctly for any crypto blocksize. - */ - u8 pad[64 - sizeof(struct rxrpc_wire_header)]; - struct rxrpc_wire_header _wire; /* Network-ready header */ - union { - u8 data[RXRPC_JUMBO_DATALEN]; /* Data packet */ - struct { - struct rxrpc_ackpacket _ack; - DECLARE_FLEX_ARRAY(u8, acks); - }; - }; - } __aligned(64); + u8 nr_kvec; /* Amount of kvec[] used */ + struct kvec kvec[3]; }; static inline bool rxrpc_sending_to_server(const struct rxrpc_txbuf *txb) @@ -1299,8 +1286,9 @@ static inline void rxrpc_sysctl_exit(void) {} * txbuf.c */ extern atomic_t rxrpc_nr_txbuf; -struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, - gfp_t gfp); +struct rxrpc_txbuf *rxrpc_alloc_data_txbuf(struct rxrpc_call *call, size_t data_size, + size_t data_align, gfp_t gfp); +struct rxrpc_txbuf *rxrpc_alloc_ack_txbuf(struct rxrpc_call *call, size_t sack_size); void rxrpc_get_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what); void rxrpc_see_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what); void rxrpc_put_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what); diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index df8a271948a1..0af4642aeec4 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -68,6 +68,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *rxnet, INIT_LIST_HEAD(&conn->proc_link); INIT_LIST_HEAD(&conn->link); mutex_init(&conn->security_lock); + mutex_init(&conn->tx_data_alloc_lock); skb_queue_head_init(&conn->rx_queue); conn->rxnet = rxnet; conn->security = &rxrpc_no_security; @@ -341,6 +342,9 @@ static void rxrpc_clean_up_connection(struct work_struct *work) */ rxrpc_purge_queue(&conn->rx_queue); + if (conn->tx_data_alloc.va) + __page_frag_cache_drain(virt_to_page(conn->tx_data_alloc.va), + conn->tx_data_alloc.pagecnt_bias); call_rcu(&conn->rcu, rxrpc_rcu_free_connection); } diff --git a/net/rxrpc/insecure.c b/net/rxrpc/insecure.c index 34353b6e584b..f2701068ed9e 100644 --- a/net/rxrpc/insecure.c +++ b/net/rxrpc/insecure.c @@ -15,14 +15,11 @@ static int none_init_connection_security(struct rxrpc_connection *conn, } /* - * Work out how much data we can put in an unsecured packet. + * Allocate an appropriately sized buffer for the amount of data remaining. */ -static int none_how_much_data(struct rxrpc_call *call, size_t remain, - size_t *_buf_size, size_t *_data_size, size_t *_offset) +static struct rxrpc_txbuf *none_alloc_txbuf(struct rxrpc_call *call, size_t remain, gfp_t gfp) { - *_buf_size = *_data_size = min_t(size_t, remain, RXRPC_JUMBO_DATALEN); - *_offset = 0; - return 0; + return rxrpc_alloc_data_txbuf(call, min_t(size_t, remain, RXRPC_JUMBO_DATALEN), 0, gfp); } static int none_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) @@ -79,7 +76,7 @@ const struct rxrpc_security rxrpc_no_security = { .exit = none_exit, .init_connection_security = none_init_connection_security, .free_call_crypto = none_free_call_crypto, - .how_much_data = none_how_much_data, + .alloc_txbuf = none_alloc_txbuf, .secure_packet = none_secure_packet, .verify_packet = none_verify_packet, .respond_to_challenge = none_respond_to_challenge, diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 34d307368135..504453c688d7 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -452,6 +452,9 @@ void rxrpc_destroy_local(struct rxrpc_local *local) #endif rxrpc_purge_queue(&local->rx_queue); rxrpc_purge_client_connections(local); + if (local->tx_alloc.va) + __page_frag_cache_drain(virt_to_page(local->tx_alloc.va), + local->tx_alloc.pagecnt_bias); } /* diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 5398aa24bb8e..0a317498b8e0 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -83,18 +83,16 @@ static void rxrpc_fill_out_ack(struct rxrpc_call *call, rxrpc_serial_t serial) { struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; + struct rxrpc_acktrailer *trailer = txb->kvec[2].iov_base + 3; struct rxrpc_ackpacket *ack = (struct rxrpc_ackpacket *)(whdr + 1); - struct rxrpc_acktrailer trailer; unsigned int qsize, sack, wrap, to; rxrpc_seq_t window, wtop; int rsize; u32 mtu, jmax; - u8 *ackp = txb->acks; + u8 *filler = txb->kvec[2].iov_base; + u8 *sackp = txb->kvec[1].iov_base; - call->ackr_nr_unacked = 0; - atomic_set(&call->ackr_nr_consumed, 0); rxrpc_inc_stat(call->rxnet, stat_tx_ack_fill); - clear_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags); window = call->ackr_window; wtop = call->ackr_wtop; @@ -110,20 +108,27 @@ static void rxrpc_fill_out_ack(struct rxrpc_call *call, ack->serial = htonl(serial); ack->reason = ack_reason; ack->nAcks = wtop - window; + filler[0] = 0; + filler[1] = 0; + filler[2] = 0; + + if (ack_reason == RXRPC_ACK_PING) + txb->flags |= RXRPC_REQUEST_ACK; if (after(wtop, window)) { + txb->len += ack->nAcks; + txb->kvec[1].iov_base = sackp; + txb->kvec[1].iov_len = ack->nAcks; + wrap = RXRPC_SACK_SIZE - sack; to = min_t(unsigned int, ack->nAcks, RXRPC_SACK_SIZE); if (sack + ack->nAcks <= RXRPC_SACK_SIZE) { - memcpy(txb->acks, call->ackr_sack_table + sack, ack->nAcks); + memcpy(sackp, call->ackr_sack_table + sack, ack->nAcks); } else { - memcpy(txb->acks, call->ackr_sack_table + sack, wrap); - memcpy(txb->acks + wrap, call->ackr_sack_table, - to - wrap); + memcpy(sackp, call->ackr_sack_table + sack, wrap); + memcpy(sackp + wrap, call->ackr_sack_table, to - wrap); } - - ackp += to; } else if (before(wtop, window)) { pr_warn("ack window backward %x %x", window, wtop); } else if (ack->reason == RXRPC_ACK_DELAY) { @@ -135,18 +140,11 @@ static void rxrpc_fill_out_ack(struct rxrpc_call *call, jmax = rxrpc_rx_jumbo_max; qsize = (window - 1) - call->rx_consumed; rsize = max_t(int, call->rx_winsize - qsize, 0); - txb->ack_rwind = rsize; - trailer.maxMTU = htonl(rxrpc_rx_mtu); - trailer.ifMTU = htonl(mtu); - trailer.rwind = htonl(rsize); - trailer.jumbo_max = htonl(jmax); - - *ackp++ = 0; - *ackp++ = 0; - *ackp++ = 0; - memcpy(ackp, &trailer, sizeof(trailer)); - txb->kvec[0].iov_len += sizeof(*ack) + ack->nAcks + 3 + sizeof(trailer); - txb->len = txb->kvec[0].iov_len; + txb->ack_rwind = rsize; + trailer->maxMTU = htonl(rxrpc_rx_mtu); + trailer->ifMTU = htonl(mtu); + trailer->rwind = htonl(rsize); + trailer->jumbo_max = htonl(jmax); } /* @@ -195,7 +193,7 @@ static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call, /* * Transmit an ACK packet. */ -static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) +static void rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) { struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; struct rxrpc_connection *conn; @@ -204,7 +202,7 @@ static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *tx int ret, rtt_slot = -1; if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) - return -ECONNRESET; + return; conn = call->conn; @@ -212,10 +210,8 @@ static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *tx msg.msg_namelen = call->peer->srx.transport_len; msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_flags = 0; + msg.msg_flags = MSG_SPLICE_PAGES; - if (ack->reason == RXRPC_ACK_PING) - txb->flags |= RXRPC_REQUEST_ACK; whdr->flags = txb->flags & RXRPC_TXBUF_WIRE_FLAGS; txb->serial = rxrpc_get_next_serial(conn); @@ -250,8 +246,6 @@ static int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *tx rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); rxrpc_set_keepalive(call); } - - return ret; } /* @@ -267,16 +261,19 @@ void rxrpc_send_ACK(struct rxrpc_call *call, u8 ack_reason, rxrpc_inc_stat(call->rxnet, stat_tx_acks[ack_reason]); - txb = rxrpc_alloc_txbuf(call, RXRPC_PACKET_TYPE_ACK, - rcu_read_lock_held() ? GFP_ATOMIC | __GFP_NOWARN : GFP_NOFS); + txb = rxrpc_alloc_ack_txbuf(call, call->ackr_wtop - call->ackr_window); if (!txb) { kleave(" = -ENOMEM"); return; } - rxrpc_fill_out_ack(call, txb, ack_reason, serial); - txb->ack_why = why; + + rxrpc_fill_out_ack(call, txb, ack_reason, serial); + call->ackr_nr_unacked = 0; + atomic_set(&call->ackr_nr_consumed, 0); + clear_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags); + trace_rxrpc_send_ack(call, why, ack_reason, serial); rxrpc_send_ack_packet(call, txb); rxrpc_put_txbuf(txb, rxrpc_txbuf_put_ack_tx); @@ -465,7 +462,7 @@ static int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *t msg.msg_namelen = call->peer->srx.transport_len; msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_flags = 0; + msg.msg_flags = MSG_SPLICE_PAGES; /* Track what we've attempted to transmit at least once so that the * retransmission algorithm doesn't try to resend what we haven't sent diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index ef0849c8329c..f1a68270862d 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -145,16 +145,17 @@ error: /* * Work out how much data we can put in a packet. */ -static int rxkad_how_much_data(struct rxrpc_call *call, size_t remain, - size_t *_buf_size, size_t *_data_size, size_t *_offset) +static struct rxrpc_txbuf *rxkad_alloc_txbuf(struct rxrpc_call *call, size_t remain, gfp_t gfp) { - size_t shdr, buf_size, chunk; + struct rxrpc_txbuf *txb; + size_t shdr, space; + + remain = min(remain, 65535 - sizeof(struct rxrpc_wire_header)); switch (call->conn->security_level) { default: - buf_size = chunk = min_t(size_t, remain, RXRPC_JUMBO_DATALEN); - shdr = 0; - goto out; + space = min_t(size_t, remain, RXRPC_JUMBO_DATALEN); + return rxrpc_alloc_data_txbuf(call, space, 0, gfp); case RXRPC_SECURITY_AUTH: shdr = sizeof(struct rxkad_level1_hdr); break; @@ -163,17 +164,16 @@ static int rxkad_how_much_data(struct rxrpc_call *call, size_t remain, break; } - buf_size = round_down(RXRPC_JUMBO_DATALEN, RXKAD_ALIGN); + space = min_t(size_t, round_down(RXRPC_JUMBO_DATALEN, RXKAD_ALIGN), remain + shdr); + space = round_up(space, RXKAD_ALIGN); - chunk = buf_size - shdr; - if (remain < chunk) - buf_size = round_up(shdr + remain, RXKAD_ALIGN); + txb = rxrpc_alloc_data_txbuf(call, space, RXKAD_ALIGN, gfp); + if (!txb) + return NULL; -out: - *_buf_size = buf_size; - *_data_size = chunk; - *_offset = shdr; - return 0; + txb->offset += shdr; + txb->space -= shdr; + return txb; } /* @@ -251,7 +251,8 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call, struct rxrpc_txbuf *txb, struct skcipher_request *req) { - struct rxkad_level1_hdr *hdr = (void *)txb->data; + struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; + struct rxkad_level1_hdr *hdr = (void *)(whdr + 1); struct rxrpc_crypt iv; struct scatterlist sg; size_t pad; @@ -267,14 +268,14 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call, pad = RXKAD_ALIGN - pad; pad &= RXKAD_ALIGN - 1; if (pad) { - memset(txb->data + txb->offset, 0, pad); + memset(txb->kvec[0].iov_base + txb->offset, 0, pad); txb->len += pad; } /* start the encryption afresh */ memset(&iv, 0, sizeof(iv)); - sg_init_one(&sg, txb->data, 8); + sg_init_one(&sg, hdr, 8); skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x); @@ -293,7 +294,8 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, struct skcipher_request *req) { const struct rxrpc_key_token *token; - struct rxkad_level2_hdr *rxkhdr = (void *)txb->data; + struct rxrpc_wire_header *whdr = txb->kvec[0].iov_base; + struct rxkad_level2_hdr *rxkhdr = (void *)(whdr + 1); struct rxrpc_crypt iv; struct scatterlist sg; size_t pad; @@ -312,7 +314,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, pad = RXKAD_ALIGN - pad; pad &= RXKAD_ALIGN - 1; if (pad) { - memset(txb->data + txb->offset, 0, pad); + memset(txb->kvec[0].iov_base + txb->offset, 0, pad); txb->len += pad; } @@ -320,7 +322,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, token = call->conn->key->payload.data[0]; memcpy(&iv, token->kad->session_key, sizeof(iv)); - sg_init_one(&sg, txb->data, txb->len); + sg_init_one(&sg, rxkhdr, txb->len); skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, txb->len, iv.x); @@ -1255,7 +1257,7 @@ const struct rxrpc_security rxkad = { .free_preparse_server_key = rxkad_free_preparse_server_key, .destroy_server_key = rxkad_destroy_server_key, .init_connection_security = rxkad_init_connection_security, - .how_much_data = rxkad_how_much_data, + .alloc_txbuf = rxkad_alloc_txbuf, .secure_packet = rxkad_secure_packet, .verify_packet = rxkad_verify_packet, .free_call_crypto = rxkad_free_call_crypto, diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index 1e81046ea8a6..4d152f06b039 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -336,7 +336,7 @@ reload: do { if (!txb) { - size_t remain, bufsize, chunk, offset; + size_t remain; _debug("alloc"); @@ -348,23 +348,11 @@ reload: * region (enc blocksize), but the trailer is not. */ remain = more ? INT_MAX : msg_data_left(msg); - ret = call->conn->security->how_much_data(call, remain, - &bufsize, &chunk, &offset); - if (ret < 0) + txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation); + if (IS_ERR(txb)) { + ret = PTR_ERR(txb); goto maybe_error; - - _debug("SIZE: %zu/%zu @%zu", chunk, bufsize, offset); - - /* create a buffer that we can retain until it's ACK'd */ - ret = -ENOMEM; - txb = rxrpc_alloc_txbuf(call, RXRPC_PACKET_TYPE_DATA, - GFP_KERNEL); - if (!txb) - goto maybe_error; - - txb->offset = offset + sizeof(struct rxrpc_wire_header); - txb->space -= offset; - txb->space = min_t(size_t, chunk, txb->space); + } } _debug("append"); diff --git a/net/rxrpc/txbuf.c b/net/rxrpc/txbuf.c index 2e8c5b15a84f..b2a82ab756c2 100644 --- a/net/rxrpc/txbuf.c +++ b/net/rxrpc/txbuf.c @@ -14,53 +14,146 @@ static atomic_t rxrpc_txbuf_debug_ids; atomic_t rxrpc_nr_txbuf; /* - * Allocate and partially initialise an I/O request structure. + * Allocate and partially initialise a data transmission buffer. */ -struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, - gfp_t gfp) +struct rxrpc_txbuf *rxrpc_alloc_data_txbuf(struct rxrpc_call *call, size_t data_size, + size_t data_align, gfp_t gfp) { struct rxrpc_wire_header *whdr; struct rxrpc_txbuf *txb; + size_t total, hoff = 0; + void *buf; txb = kmalloc(sizeof(*txb), gfp); - if (txb) { - whdr = &txb->_wire; + if (!txb) + return NULL; - INIT_LIST_HEAD(&txb->call_link); - INIT_LIST_HEAD(&txb->tx_link); - refcount_set(&txb->ref, 1); - txb->call_debug_id = call->debug_id; - txb->debug_id = atomic_inc_return(&rxrpc_txbuf_debug_ids); - txb->space = sizeof(txb->data); - txb->len = 0; - txb->offset = 0; - txb->flags = call->conn->out_clientflag; - txb->ack_why = 0; - txb->seq = call->tx_prepared + 1; - txb->serial = 0; - txb->cksum = 0; - txb->nr_kvec = 1; - txb->kvec[0].iov_base = whdr; - txb->kvec[0].iov_len = sizeof(*whdr); - whdr->epoch = htonl(call->conn->proto.epoch); - whdr->cid = htonl(call->cid); - whdr->callNumber = htonl(call->call_id); - whdr->seq = htonl(txb->seq); - whdr->type = packet_type; - whdr->flags = 0; - whdr->userStatus = 0; - whdr->securityIndex = call->security_ix; - whdr->_rsvd = 0; - whdr->serviceId = htons(call->dest_srx.srx_service); + if (data_align) + hoff = round_up(sizeof(*whdr), data_align) - sizeof(*whdr); + total = hoff + sizeof(*whdr) + data_size; - trace_rxrpc_txbuf(txb->debug_id, - txb->call_debug_id, txb->seq, 1, - packet_type == RXRPC_PACKET_TYPE_DATA ? - rxrpc_txbuf_alloc_data : - rxrpc_txbuf_alloc_ack); - atomic_inc(&rxrpc_nr_txbuf); + mutex_lock(&call->conn->tx_data_alloc_lock); + buf = page_frag_alloc_align(&call->conn->tx_data_alloc, total, gfp, + ~(data_align - 1) & ~(L1_CACHE_BYTES - 1)); + mutex_unlock(&call->conn->tx_data_alloc_lock); + if (!buf) { + kfree(txb); + return NULL; } + whdr = buf + hoff; + + INIT_LIST_HEAD(&txb->call_link); + INIT_LIST_HEAD(&txb->tx_link); + refcount_set(&txb->ref, 1); + txb->last_sent = KTIME_MIN; + txb->call_debug_id = call->debug_id; + txb->debug_id = atomic_inc_return(&rxrpc_txbuf_debug_ids); + txb->space = data_size; + txb->len = 0; + txb->offset = sizeof(*whdr); + txb->flags = call->conn->out_clientflag; + txb->ack_why = 0; + txb->seq = call->tx_prepared + 1; + txb->serial = 0; + txb->cksum = 0; + txb->nr_kvec = 1; + txb->kvec[0].iov_base = whdr; + txb->kvec[0].iov_len = sizeof(*whdr); + + whdr->epoch = htonl(call->conn->proto.epoch); + whdr->cid = htonl(call->cid); + whdr->callNumber = htonl(call->call_id); + whdr->seq = htonl(txb->seq); + whdr->type = RXRPC_PACKET_TYPE_DATA; + whdr->flags = 0; + whdr->userStatus = 0; + whdr->securityIndex = call->security_ix; + whdr->_rsvd = 0; + whdr->serviceId = htons(call->dest_srx.srx_service); + + trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 1, + rxrpc_txbuf_alloc_data); + + atomic_inc(&rxrpc_nr_txbuf); + return txb; +} + +/* + * Allocate and partially initialise an ACK packet. + */ +struct rxrpc_txbuf *rxrpc_alloc_ack_txbuf(struct rxrpc_call *call, size_t sack_size) +{ + struct rxrpc_wire_header *whdr; + struct rxrpc_acktrailer *trailer; + struct rxrpc_ackpacket *ack; + struct rxrpc_txbuf *txb; + gfp_t gfp = rcu_read_lock_held() ? GFP_ATOMIC | __GFP_NOWARN : GFP_NOFS; + void *buf, *buf2 = NULL; + u8 *filler; + + txb = kmalloc(sizeof(*txb), gfp); + if (!txb) + return NULL; + + buf = page_frag_alloc(&call->local->tx_alloc, + sizeof(*whdr) + sizeof(*ack) + 1 + 3 + sizeof(*trailer), gfp); + if (!buf) { + kfree(txb); + return NULL; + } + + if (sack_size) { + buf2 = page_frag_alloc(&call->local->tx_alloc, sack_size, gfp); + if (!buf2) { + page_frag_free(buf); + kfree(txb); + return NULL; + } + } + + whdr = buf; + ack = buf + sizeof(*whdr); + filler = buf + sizeof(*whdr) + sizeof(*ack) + 1; + trailer = buf + sizeof(*whdr) + sizeof(*ack) + 1 + 3; + + INIT_LIST_HEAD(&txb->call_link); + INIT_LIST_HEAD(&txb->tx_link); + refcount_set(&txb->ref, 1); + txb->call_debug_id = call->debug_id; + txb->debug_id = atomic_inc_return(&rxrpc_txbuf_debug_ids); + txb->space = 0; + txb->len = sizeof(*whdr) + sizeof(*ack) + 3 + sizeof(*trailer); + txb->offset = 0; + txb->flags = call->conn->out_clientflag; + txb->ack_rwind = 0; + txb->seq = 0; + txb->serial = 0; + txb->cksum = 0; + txb->nr_kvec = 3; + txb->kvec[0].iov_base = whdr; + txb->kvec[0].iov_len = sizeof(*whdr) + sizeof(*ack); + txb->kvec[1].iov_base = buf2; + txb->kvec[1].iov_len = sack_size; + txb->kvec[2].iov_base = filler; + txb->kvec[2].iov_len = 3 + sizeof(*trailer); + + whdr->epoch = htonl(call->conn->proto.epoch); + whdr->cid = htonl(call->cid); + whdr->callNumber = htonl(call->call_id); + whdr->seq = 0; + whdr->type = RXRPC_PACKET_TYPE_ACK; + whdr->flags = 0; + whdr->userStatus = 0; + whdr->securityIndex = call->security_ix; + whdr->_rsvd = 0; + whdr->serviceId = htons(call->dest_srx.srx_service); + + get_page(virt_to_head_page(trailer)); + + trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 1, + rxrpc_txbuf_alloc_ack); + atomic_inc(&rxrpc_nr_txbuf); return txb; } @@ -79,12 +172,15 @@ void rxrpc_see_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, r, what); } -static void rxrpc_free_txbuf(struct rcu_head *rcu) +static void rxrpc_free_txbuf(struct rxrpc_txbuf *txb) { - struct rxrpc_txbuf *txb = container_of(rcu, struct rxrpc_txbuf, rcu); + int i; trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 0, rxrpc_txbuf_free); + for (i = 0; i < txb->nr_kvec; i++) + if (txb->kvec[i].iov_base) + page_frag_free(txb->kvec[i].iov_base); kfree(txb); atomic_dec(&rxrpc_nr_txbuf); } @@ -103,7 +199,7 @@ void rxrpc_put_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) dead = __refcount_dec_and_test(&txb->ref, &r); trace_rxrpc_txbuf(debug_id, call_debug_id, seq, r - 1, what); if (dead) - call_rcu(&txb->rcu, rxrpc_free_txbuf); + rxrpc_free_txbuf(txb); } } From 3e0b83ee535d44befddb3f0a6c75a531cf47f869 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 29 Feb 2024 16:46:21 +0000 Subject: [PATCH 1893/2255] rxrpc: Parse received packets before dealing with timeouts Parse the received packets before going and processing timeouts as the timeouts may be reset by the reception of a packet. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/call_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index e19ea54dce54..58826710322d 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -358,6 +358,9 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) if (skb && skb->mark == RXRPC_SKB_MARK_ERROR) goto out; + if (skb) + rxrpc_input_call_packet(call, skb); + /* If we see our async-event poke, check for timeout trippage. */ now = jiffies; t = call->expect_rx_by; @@ -417,9 +420,6 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) resend = true; } - if (skb) - rxrpc_input_call_packet(call, skb); - rxrpc_transmit_some_data(call); if (skb) { From a711d976e1cd7a58a51ecf2816e705fd01fe3489 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 29 Feb 2024 16:50:52 +0000 Subject: [PATCH 1894/2255] rxrpc: Don't permit resending after all Tx packets acked Once all the packets transmitted as part of a call have been acked, don't permit any resending. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/call_event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 58826710322d..ef28ebf37c7d 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -450,7 +450,9 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, rxrpc_propose_ack_ping_for_lost_ack); - if (resend && __rxrpc_call_state(call) != RXRPC_CALL_CLIENT_RECV_REPLY) + if (resend && + __rxrpc_call_state(call) != RXRPC_CALL_CLIENT_RECV_REPLY && + !test_bit(RXRPC_CALL_TX_ALL_ACKED, &call->flags)) rxrpc_resend(call, NULL); if (test_and_clear_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags)) From 12a66e77c4999b97a2c2b8f5e4e7533c656cee12 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 30 Jan 2024 20:30:03 +0000 Subject: [PATCH 1895/2255] rxrpc: Differentiate PING ACK transmission traces. There are three points that transmit PING ACKs and all of them use the same trace string. Change two of them to use different strings. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- include/trace/events/rxrpc.h | 2 ++ net/rxrpc/call_event.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index c730cd732348..3b726a6c8c42 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -364,11 +364,13 @@ #define rxrpc_propose_ack_traces \ EM(rxrpc_propose_ack_client_tx_end, "ClTxEnd") \ + EM(rxrpc_propose_ack_delayed_ack, "DlydAck") \ EM(rxrpc_propose_ack_input_data, "DataIn ") \ EM(rxrpc_propose_ack_input_data_hole, "DataInH") \ EM(rxrpc_propose_ack_ping_for_keepalive, "KeepAlv") \ EM(rxrpc_propose_ack_ping_for_lost_ack, "LostAck") \ EM(rxrpc_propose_ack_ping_for_lost_reply, "LostRpl") \ + EM(rxrpc_propose_ack_ping_for_0_retrans, "0-Retrn") \ EM(rxrpc_propose_ack_ping_for_old_rtt, "OldRtt ") \ EM(rxrpc_propose_ack_ping_for_params, "Params ") \ EM(rxrpc_propose_ack_ping_for_rtt, "Rtt ") \ diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index ef28ebf37c7d..bc1a5abb7d6f 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -197,7 +197,7 @@ no_resend: if (ktime_to_us(ack_ts) < (call->peer->srtt_us >> 3)) goto out; rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, - rxrpc_propose_ack_ping_for_lost_ack); + rxrpc_propose_ack_ping_for_0_retrans); goto out; } @@ -387,7 +387,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) trace_rxrpc_timer(call, rxrpc_timer_exp_ack, now); call->delay_ack_at = now + MAX_JIFFY_OFFSET; rxrpc_send_ACK(call, RXRPC_ACK_DELAY, 0, - rxrpc_propose_ack_ping_for_lost_ack); + rxrpc_propose_ack_delayed_ack); } t = call->ack_lost_at; From 153f90a066dd4a91ef7edc0df3964dd097a5e2a5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 30 Jan 2024 21:37:16 +0000 Subject: [PATCH 1896/2255] rxrpc: Use ktimes for call timeout tracking and set the timer lazily Track the call timeouts as ktimes rather than jiffies as the latter's granularity is too high and only set the timer at the end of the event handling function. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- include/trace/events/rxrpc.h | 176 +++++++++++++++++--------------- net/rxrpc/af_rxrpc.c | 12 +-- net/rxrpc/ar-internal.h | 35 +++---- net/rxrpc/call_event.c | 189 +++++++++++++++++------------------ net/rxrpc/call_object.c | 54 +++++----- net/rxrpc/input.c | 28 +++--- net/rxrpc/misc.c | 8 +- net/rxrpc/output.c | 40 +++----- net/rxrpc/proc.c | 10 +- net/rxrpc/rtt.c | 36 +++---- net/rxrpc/sendmsg.c | 25 ++--- net/rxrpc/sysctl.c | 16 +-- 12 files changed, 307 insertions(+), 322 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 3b726a6c8c42..a1b126a6b0d7 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -119,6 +119,7 @@ EM(rxrpc_call_poke_complete, "Compl") \ EM(rxrpc_call_poke_error, "Error") \ EM(rxrpc_call_poke_idle, "Idle") \ + EM(rxrpc_call_poke_set_timeout, "Set-timo") \ EM(rxrpc_call_poke_start, "Start") \ EM(rxrpc_call_poke_timer, "Timer") \ E_(rxrpc_call_poke_timer_now, "Timer-now") @@ -340,27 +341,16 @@ E_(rxrpc_rtt_rx_requested_ack, "RACK") #define rxrpc_timer_traces \ - EM(rxrpc_timer_begin, "Begin ") \ - EM(rxrpc_timer_exp_ack, "ExpAck") \ - EM(rxrpc_timer_exp_hard, "ExpHrd") \ - EM(rxrpc_timer_exp_idle, "ExpIdl") \ - EM(rxrpc_timer_exp_keepalive, "ExpKA ") \ - EM(rxrpc_timer_exp_lost_ack, "ExpLoA") \ - EM(rxrpc_timer_exp_normal, "ExpNml") \ - EM(rxrpc_timer_exp_ping, "ExpPng") \ - EM(rxrpc_timer_exp_resend, "ExpRsn") \ - EM(rxrpc_timer_init_for_reply, "IniRpl") \ - EM(rxrpc_timer_init_for_send_reply, "SndRpl") \ - EM(rxrpc_timer_restart, "Restrt") \ - EM(rxrpc_timer_set_for_ack, "SetAck") \ - EM(rxrpc_timer_set_for_hard, "SetHrd") \ - EM(rxrpc_timer_set_for_idle, "SetIdl") \ - EM(rxrpc_timer_set_for_keepalive, "KeepAl") \ - EM(rxrpc_timer_set_for_lost_ack, "SetLoA") \ - EM(rxrpc_timer_set_for_normal, "SetNml") \ - EM(rxrpc_timer_set_for_ping, "SetPng") \ - EM(rxrpc_timer_set_for_resend, "SetRTx") \ - E_(rxrpc_timer_set_for_send, "SetSnd") + EM(rxrpc_timer_trace_delayed_ack, "DelayAck ") \ + EM(rxrpc_timer_trace_expect_rx, "ExpectRx ") \ + EM(rxrpc_timer_trace_hard, "HardLimit") \ + EM(rxrpc_timer_trace_idle, "IdleLimit") \ + EM(rxrpc_timer_trace_keepalive, "KeepAlive") \ + EM(rxrpc_timer_trace_lost_ack, "LostAck ") \ + EM(rxrpc_timer_trace_ping, "DelayPing") \ + EM(rxrpc_timer_trace_resend, "Resend ") \ + EM(rxrpc_timer_trace_resend_reset, "ResendRst") \ + E_(rxrpc_timer_trace_resend_tx, "ResendTx ") #define rxrpc_propose_ack_traces \ EM(rxrpc_propose_ack_client_tx_end, "ClTxEnd") \ @@ -1314,90 +1304,112 @@ TRACE_EVENT(rxrpc_rtt_rx, __entry->rto) ); -TRACE_EVENT(rxrpc_timer, - TP_PROTO(struct rxrpc_call *call, enum rxrpc_timer_trace why, - unsigned long now), +TRACE_EVENT(rxrpc_timer_set, + TP_PROTO(struct rxrpc_call *call, ktime_t delay, + enum rxrpc_timer_trace why), - TP_ARGS(call, why, now), + TP_ARGS(call, delay, why), TP_STRUCT__entry( __field(unsigned int, call) __field(enum rxrpc_timer_trace, why) - __field(long, now) - __field(long, ack_at) - __field(long, ack_lost_at) - __field(long, resend_at) - __field(long, ping_at) - __field(long, expect_rx_by) - __field(long, expect_req_by) - __field(long, expect_term_by) - __field(long, timer) + __field(ktime_t, delay) ), TP_fast_assign( __entry->call = call->debug_id; __entry->why = why; - __entry->now = now; - __entry->ack_at = call->delay_ack_at; - __entry->ack_lost_at = call->ack_lost_at; - __entry->resend_at = call->resend_at; - __entry->expect_rx_by = call->expect_rx_by; - __entry->expect_req_by = call->expect_req_by; - __entry->expect_term_by = call->expect_term_by; - __entry->timer = call->timer.expires; + __entry->delay = delay; ), - TP_printk("c=%08x %s a=%ld la=%ld r=%ld xr=%ld xq=%ld xt=%ld t=%ld", + TP_printk("c=%08x %s to=%lld", __entry->call, __print_symbolic(__entry->why, rxrpc_timer_traces), - __entry->ack_at - __entry->now, - __entry->ack_lost_at - __entry->now, - __entry->resend_at - __entry->now, - __entry->expect_rx_by - __entry->now, - __entry->expect_req_by - __entry->now, - __entry->expect_term_by - __entry->now, - __entry->timer - __entry->now) + ktime_to_us(__entry->delay)) ); -TRACE_EVENT(rxrpc_timer_expired, - TP_PROTO(struct rxrpc_call *call, unsigned long now), +TRACE_EVENT(rxrpc_timer_exp, + TP_PROTO(struct rxrpc_call *call, ktime_t delay, + enum rxrpc_timer_trace why), - TP_ARGS(call, now), + TP_ARGS(call, delay, why), TP_STRUCT__entry( - __field(unsigned int, call) - __field(long, now) - __field(long, ack_at) - __field(long, ack_lost_at) - __field(long, resend_at) - __field(long, ping_at) - __field(long, expect_rx_by) - __field(long, expect_req_by) - __field(long, expect_term_by) - __field(long, timer) + __field(unsigned int, call) + __field(enum rxrpc_timer_trace, why) + __field(ktime_t, delay) ), TP_fast_assign( __entry->call = call->debug_id; - __entry->now = now; - __entry->ack_at = call->delay_ack_at; - __entry->ack_lost_at = call->ack_lost_at; - __entry->resend_at = call->resend_at; - __entry->expect_rx_by = call->expect_rx_by; - __entry->expect_req_by = call->expect_req_by; - __entry->expect_term_by = call->expect_term_by; - __entry->timer = call->timer.expires; + __entry->why = why; + __entry->delay = delay; ), - TP_printk("c=%08x EXPIRED a=%ld la=%ld r=%ld xr=%ld xq=%ld xt=%ld t=%ld", + TP_printk("c=%08x %s to=%lld", __entry->call, - __entry->ack_at - __entry->now, - __entry->ack_lost_at - __entry->now, - __entry->resend_at - __entry->now, - __entry->expect_rx_by - __entry->now, - __entry->expect_req_by - __entry->now, - __entry->expect_term_by - __entry->now, - __entry->timer - __entry->now) + __print_symbolic(__entry->why, rxrpc_timer_traces), + ktime_to_us(__entry->delay)) + ); + +TRACE_EVENT(rxrpc_timer_can, + TP_PROTO(struct rxrpc_call *call, enum rxrpc_timer_trace why), + + TP_ARGS(call, why), + + TP_STRUCT__entry( + __field(unsigned int, call) + __field(enum rxrpc_timer_trace, why) + ), + + TP_fast_assign( + __entry->call = call->debug_id; + __entry->why = why; + ), + + TP_printk("c=%08x %s", + __entry->call, + __print_symbolic(__entry->why, rxrpc_timer_traces)) + ); + +TRACE_EVENT(rxrpc_timer_restart, + TP_PROTO(struct rxrpc_call *call, ktime_t delay, unsigned long delayj), + + TP_ARGS(call, delay, delayj), + + TP_STRUCT__entry( + __field(unsigned int, call) + __field(unsigned long, delayj) + __field(ktime_t, delay) + ), + + TP_fast_assign( + __entry->call = call->debug_id; + __entry->delayj = delayj; + __entry->delay = delay; + ), + + TP_printk("c=%08x to=%lld j=%ld", + __entry->call, + ktime_to_us(__entry->delay), + __entry->delayj) + ); + +TRACE_EVENT(rxrpc_timer_expired, + TP_PROTO(struct rxrpc_call *call), + + TP_ARGS(call), + + TP_STRUCT__entry( + __field(unsigned int, call) + ), + + TP_fast_assign( + __entry->call = call->debug_id; + ), + + TP_printk("c=%08x EXPIRED", + __entry->call) ); TRACE_EVENT(rxrpc_rx_lose, @@ -1507,7 +1519,7 @@ TRACE_EVENT(rxrpc_drop_ack, TRACE_EVENT(rxrpc_retransmit, TP_PROTO(struct rxrpc_call *call, rxrpc_seq_t seq, - rxrpc_serial_t serial, s64 expiry), + rxrpc_serial_t serial, ktime_t expiry), TP_ARGS(call, seq, serial, expiry), @@ -1515,7 +1527,7 @@ TRACE_EVENT(rxrpc_retransmit, __field(unsigned int, call) __field(rxrpc_seq_t, seq) __field(rxrpc_serial_t, serial) - __field(s64, expiry) + __field(ktime_t, expiry) ), TP_fast_assign( @@ -1529,7 +1541,7 @@ TRACE_EVENT(rxrpc_retransmit, __entry->call, __entry->seq, __entry->serial, - __entry->expiry) + ktime_to_us(__entry->expiry)) ); TRACE_EVENT(rxrpc_congest, diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 465bfe5eb061..5222bc97d192 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -487,7 +487,7 @@ EXPORT_SYMBOL(rxrpc_kernel_new_call_notification); * rxrpc_kernel_set_max_life - Set maximum lifespan on a call * @sock: The socket the call is on * @call: The call to configure - * @hard_timeout: The maximum lifespan of the call in jiffies + * @hard_timeout: The maximum lifespan of the call in ms * * Set the maximum lifespan of a call. The call will end with ETIME or * ETIMEDOUT if it takes longer than this. @@ -495,14 +495,14 @@ EXPORT_SYMBOL(rxrpc_kernel_new_call_notification); void rxrpc_kernel_set_max_life(struct socket *sock, struct rxrpc_call *call, unsigned long hard_timeout) { - unsigned long now; + ktime_t delay = ms_to_ktime(hard_timeout), expect_term_by; mutex_lock(&call->user_mutex); - now = jiffies; - hard_timeout += now; - WRITE_ONCE(call->expect_term_by, hard_timeout); - rxrpc_reduce_call_timer(call, hard_timeout, now, rxrpc_timer_set_for_hard); + expect_term_by = ktime_add(ktime_get_real(), delay); + WRITE_ONCE(call->expect_term_by, expect_term_by); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_hard); + rxrpc_poke_call(call, rxrpc_call_poke_set_timeout); mutex_unlock(&call->user_mutex); } diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 47f4689379ca..21ecac22b51d 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -352,8 +352,8 @@ struct rxrpc_peer { u32 mdev_us; /* medium deviation */ u32 mdev_max_us; /* maximal mdev for the last rtt period */ u32 rttvar_us; /* smoothed mdev_max */ - u32 rto_j; /* Retransmission timeout in jiffies */ - u8 backoff; /* Backoff timeout */ + u32 rto_us; /* Retransmission timeout in usec */ + u8 backoff; /* Backoff timeout (as shift) */ u8 cong_ssthresh; /* Congestion slow-start threshold */ }; @@ -620,17 +620,17 @@ struct rxrpc_call { const struct rxrpc_security *security; /* applied security module */ struct mutex user_mutex; /* User access mutex */ struct sockaddr_rxrpc dest_srx; /* Destination address */ - unsigned long delay_ack_at; /* When DELAY ACK needs to happen */ - unsigned long ack_lost_at; /* When ACK is figured as lost */ - unsigned long resend_at; /* When next resend needs to happen */ - unsigned long ping_at; /* When next to send a ping */ - unsigned long keepalive_at; /* When next to send a keepalive ping */ - unsigned long expect_rx_by; /* When we expect to get a packet by */ - unsigned long expect_req_by; /* When we expect to get a request DATA packet by */ - unsigned long expect_term_by; /* When we expect call termination by */ - u32 next_rx_timo; /* Timeout for next Rx packet (jif) */ - u32 next_req_timo; /* Timeout for next Rx request packet (jif) */ - u32 hard_timo; /* Maximum lifetime or 0 (jif) */ + ktime_t delay_ack_at; /* When DELAY ACK needs to happen */ + ktime_t ack_lost_at; /* When ACK is figured as lost */ + ktime_t resend_at; /* When next resend needs to happen */ + ktime_t ping_at; /* When next to send a ping */ + ktime_t keepalive_at; /* When next to send a keepalive ping */ + ktime_t expect_rx_by; /* When we expect to get a packet by */ + ktime_t expect_req_by; /* When we expect to get a request DATA packet by */ + ktime_t expect_term_by; /* When we expect call termination by */ + u32 next_rx_timo; /* Timeout for next Rx packet (ms) */ + u32 next_req_timo; /* Timeout for next Rx request packet (ms) */ + u32 hard_timo; /* Maximum lifetime or 0 (s) */ struct timer_list timer; /* Combined event timer */ struct work_struct destroyer; /* In-process-context destroyer */ rxrpc_notify_rx_t notify_rx; /* kernel service Rx notification function */ @@ -675,7 +675,7 @@ struct rxrpc_call { rxrpc_seq_t tx_transmitted; /* Highest packet transmitted */ rxrpc_seq_t tx_prepared; /* Highest Tx slot prepared. */ rxrpc_seq_t tx_top; /* Highest Tx slot allocated. */ - u16 tx_backoff; /* Delay to insert due to Tx failure */ + u16 tx_backoff; /* Delay to insert due to Tx failure (ms) */ u8 tx_winsize; /* Maximum size of Tx window */ #define RXRPC_TX_MAX_WINDOW 128 ktime_t tx_last_sent; /* Last time a transmission occurred */ @@ -866,11 +866,6 @@ void rxrpc_propose_delay_ACK(struct rxrpc_call *, rxrpc_serial_t, void rxrpc_shrink_call_tx_buffer(struct rxrpc_call *); void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb); -void rxrpc_reduce_call_timer(struct rxrpc_call *call, - unsigned long expire_at, - unsigned long now, - enum rxrpc_timer_trace why); - bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb); /* @@ -1214,7 +1209,7 @@ static inline int rxrpc_abort_eproto(struct rxrpc_call *call, */ void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace, int, rxrpc_serial_t, rxrpc_serial_t, ktime_t, ktime_t); -unsigned long rxrpc_get_rto_backoff(struct rxrpc_peer *, bool); +ktime_t rxrpc_get_rto_backoff(struct rxrpc_peer *peer, bool retrans); void rxrpc_peer_init_rtt(struct rxrpc_peer *); /* diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index bc1a5abb7d6f..2a9f74eb7c46 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -23,14 +23,14 @@ void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial, enum rxrpc_propose_ack_trace why) { - unsigned long now = jiffies; - unsigned long ping_at = now + rxrpc_idle_ack_delay; + ktime_t delay = ms_to_ktime(READ_ONCE(rxrpc_idle_ack_delay)); + ktime_t now = ktime_get_real(); + ktime_t ping_at = ktime_add(now, delay); - if (time_before(ping_at, call->ping_at)) { + trace_rxrpc_propose_ack(call, why, RXRPC_ACK_PING, serial); + if (ktime_before(ping_at, call->ping_at)) { call->ping_at = ping_at; - rxrpc_reduce_call_timer(call, ping_at, now, - rxrpc_timer_set_for_ping); - trace_rxrpc_propose_ack(call, why, RXRPC_ACK_PING, serial); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_ping); } } @@ -40,25 +40,18 @@ void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial, void rxrpc_propose_delay_ACK(struct rxrpc_call *call, rxrpc_serial_t serial, enum rxrpc_propose_ack_trace why) { - unsigned long expiry = rxrpc_soft_ack_delay; - unsigned long now = jiffies, ack_at; - - if (rxrpc_soft_ack_delay < expiry) - expiry = rxrpc_soft_ack_delay; - if (call->peer->srtt_us != 0) - ack_at = usecs_to_jiffies(call->peer->srtt_us >> 3); - else - ack_at = expiry; - - ack_at += READ_ONCE(call->tx_backoff); - ack_at += now; - if (time_before(ack_at, call->delay_ack_at)) { - call->delay_ack_at = ack_at; - rxrpc_reduce_call_timer(call, ack_at, now, - rxrpc_timer_set_for_ack); - } + ktime_t now = ktime_get_real(), delay; trace_rxrpc_propose_ack(call, why, RXRPC_ACK_DELAY, serial); + + if (call->peer->srtt_us) + delay = (call->peer->srtt_us >> 3) * NSEC_PER_USEC; + else + delay = ms_to_ktime(READ_ONCE(rxrpc_soft_ack_delay)); + ktime_add_ms(delay, call->tx_backoff); + + call->delay_ack_at = ktime_add(now, delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_delayed_ack); } /* @@ -77,9 +70,8 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) struct rxrpc_ackpacket *ack = NULL; struct rxrpc_skb_priv *sp; struct rxrpc_txbuf *txb; - unsigned long resend_at; rxrpc_seq_t transmitted = call->tx_transmitted; - ktime_t now, max_age, oldest, ack_ts; + ktime_t now, max_age, oldest, ack_ts, delay; bool unacked = false; unsigned int i; LIST_HEAD(retrans_queue); @@ -87,7 +79,7 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) _enter("{%d,%d}", call->acks_hard_ack, call->tx_top); now = ktime_get_real(); - max_age = ktime_sub_us(now, jiffies_to_usecs(call->peer->rto_j)); + max_age = ktime_sub_us(now, call->peer->rto_us); oldest = now; if (list_empty(&call->tx_buffer)) @@ -178,10 +170,8 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) no_further_resend: no_resend: - resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(now, oldest))); - resend_at += jiffies + rxrpc_get_rto_backoff(call->peer, - !list_empty(&retrans_queue)); - call->resend_at = resend_at; + delay = rxrpc_get_rto_backoff(call->peer, !list_empty(&retrans_queue)); + call->resend_at = ktime_add(oldest, delay); if (unacked) rxrpc_congestion_timeout(call); @@ -191,8 +181,7 @@ no_resend: * retransmitting data. */ if (list_empty(&retrans_queue)) { - rxrpc_reduce_call_timer(call, resend_at, jiffies, - rxrpc_timer_set_for_resend); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_resend_reset); ack_ts = ktime_sub(now, call->acks_latest_ts); if (ktime_to_us(ack_ts) < (call->peer->srtt_us >> 3)) goto out; @@ -218,13 +207,11 @@ out: */ static void rxrpc_begin_service_reply(struct rxrpc_call *call) { - unsigned long now = jiffies; - rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SEND_REPLY); - call->delay_ack_at = now + MAX_JIFFY_OFFSET; if (call->ackr_reason == RXRPC_ACK_DELAY) call->ackr_reason = 0; - trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now); + call->delay_ack_at = KTIME_MAX; + trace_rxrpc_timer_can(call, rxrpc_timer_trace_delayed_ack); } /* @@ -333,8 +320,8 @@ static void rxrpc_send_initial_ping(struct rxrpc_call *call) */ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) { - unsigned long now, next, t; - bool resend = false, expired = false; + ktime_t now, t; + bool resend = false; s32 abort_code; rxrpc_see_call(call, rxrpc_call_see_input); @@ -362,66 +349,69 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) rxrpc_input_call_packet(call, skb); /* If we see our async-event poke, check for timeout trippage. */ - now = jiffies; - t = call->expect_rx_by; - if (time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_normal, now); - expired = true; + now = ktime_get_real(); + t = ktime_sub(call->expect_rx_by, now); + if (t <= 0) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_expect_rx); + goto expired; } - t = call->expect_req_by; - if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST && - time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_idle, now); - expired = true; + t = ktime_sub(call->expect_req_by, now); + if (t <= 0) { + call->expect_req_by = KTIME_MAX; + if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_idle); + goto expired; + } } - t = READ_ONCE(call->expect_term_by); - if (time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_hard, now); - expired = true; + t = ktime_sub(READ_ONCE(call->expect_term_by), now); + if (t <= 0) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_hard); + goto expired; } - t = call->delay_ack_at; - if (time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_ack, now); - call->delay_ack_at = now + MAX_JIFFY_OFFSET; + t = ktime_sub(call->delay_ack_at, now); + if (t <= 0) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_delayed_ack); + call->delay_ack_at = KTIME_MAX; rxrpc_send_ACK(call, RXRPC_ACK_DELAY, 0, rxrpc_propose_ack_delayed_ack); } - t = call->ack_lost_at; - if (time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_lost_ack, now); - call->ack_lost_at = now + MAX_JIFFY_OFFSET; + t = ktime_sub(call->ack_lost_at, now); + if (t <= 0) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_lost_ack); + call->ack_lost_at = KTIME_MAX; set_bit(RXRPC_CALL_EV_ACK_LOST, &call->events); } - t = call->keepalive_at; - if (time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now); - call->keepalive_at = now + MAX_JIFFY_OFFSET; + t = ktime_sub(call->ping_at, now); + if (t <= 0) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_ping); + call->ping_at = KTIME_MAX; rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, rxrpc_propose_ack_ping_for_keepalive); } - t = call->ping_at; - if (time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now); - call->ping_at = now + MAX_JIFFY_OFFSET; - rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, - rxrpc_propose_ack_ping_for_keepalive); - } - - t = call->resend_at; - if (time_after_eq(now, t)) { - trace_rxrpc_timer(call, rxrpc_timer_exp_resend, now); - call->resend_at = now + MAX_JIFFY_OFFSET; + t = ktime_sub(call->resend_at, now); + if (t <= 0) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_resend); + call->resend_at = KTIME_MAX; resend = true; } rxrpc_transmit_some_data(call); + now = ktime_get_real(); + t = ktime_sub(call->keepalive_at, now); + if (t <= 0) { + trace_rxrpc_timer_exp(call, t, rxrpc_timer_trace_keepalive); + call->keepalive_at = KTIME_MAX; + rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, + rxrpc_propose_ack_ping_for_keepalive); + } + if (skb) { struct rxrpc_skb_priv *sp = rxrpc_skb(skb); @@ -433,19 +423,6 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) rxrpc_send_initial_ping(call); /* Process events */ - if (expired) { - if (test_bit(RXRPC_CALL_RX_HEARD, &call->flags) && - (int)call->conn->hi_serial - (int)call->rx_serial > 0) { - trace_rxrpc_call_reset(call); - rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ECONNRESET, - rxrpc_abort_call_reset); - } else { - rxrpc_abort_call(call, 0, RX_CALL_TIMEOUT, -ETIME, - rxrpc_abort_call_timeout); - } - goto out; - } - if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, rxrpc_propose_ack_ping_for_lost_ack); @@ -474,23 +451,33 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) /* Make sure the timer is restarted */ if (!__rxrpc_call_is_complete(call)) { - next = call->expect_rx_by; + ktime_t next = READ_ONCE(call->expect_term_by), delay; -#define set(T) { t = READ_ONCE(T); if (time_before(t, next)) next = t; } +#define set(T) { ktime_t _t = (T); if (ktime_before(_t, next)) next = _t; } set(call->expect_req_by); - set(call->expect_term_by); + set(call->expect_rx_by); set(call->delay_ack_at); set(call->ack_lost_at); set(call->resend_at); set(call->keepalive_at); set(call->ping_at); - now = jiffies; - if (time_after_eq(now, next)) + now = ktime_get_real(); + delay = ktime_sub(next, now); + if (delay <= 0) { rxrpc_poke_call(call, rxrpc_call_poke_timer_now); + } else { + unsigned long nowj = jiffies, delayj, nextj; - rxrpc_reduce_call_timer(call, next, now, rxrpc_timer_restart); + delayj = max(nsecs_to_jiffies(delay), 1); + nextj = nowj + delayj; + if (time_before(nextj, call->timer.expires) || + !timer_pending(&call->timer)) { + trace_rxrpc_timer_restart(call, delay, delayj); + timer_reduce(&call->timer, nextj); + } + } } out: @@ -505,4 +492,16 @@ out: rxrpc_shrink_call_tx_buffer(call); _leave(""); return true; + +expired: + if (test_bit(RXRPC_CALL_RX_HEARD, &call->flags) && + (int)call->conn->hi_serial - (int)call->rx_serial > 0) { + trace_rxrpc_call_reset(call); + rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ECONNRESET, + rxrpc_abort_call_reset); + } else { + rxrpc_abort_call(call, 0, RX_CALL_TIMEOUT, -ETIME, + rxrpc_abort_call_timeout); + } + goto out; } diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 9fc9a6c3f685..01fa71e8b1f7 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -70,20 +70,11 @@ static void rxrpc_call_timer_expired(struct timer_list *t) _enter("%d", call->debug_id); if (!__rxrpc_call_is_complete(call)) { - trace_rxrpc_timer_expired(call, jiffies); + trace_rxrpc_timer_expired(call); rxrpc_poke_call(call, rxrpc_call_poke_timer); } } -void rxrpc_reduce_call_timer(struct rxrpc_call *call, - unsigned long expire_at, - unsigned long now, - enum rxrpc_timer_trace why) -{ - trace_rxrpc_timer(call, why, now); - timer_reduce(&call->timer, expire_at); -} - static struct lock_class_key rxrpc_call_user_mutex_lock_class_key; static void rxrpc_destroy_call(struct work_struct *); @@ -163,12 +154,20 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, spin_lock_init(&call->notify_lock); spin_lock_init(&call->tx_lock); refcount_set(&call->ref, 1); - call->debug_id = debug_id; - call->tx_total_len = -1; - call->next_rx_timo = 20 * HZ; - call->next_req_timo = 1 * HZ; - call->ackr_window = 1; - call->ackr_wtop = 1; + call->debug_id = debug_id; + call->tx_total_len = -1; + call->next_rx_timo = 20 * HZ; + call->next_req_timo = 1 * HZ; + call->ackr_window = 1; + call->ackr_wtop = 1; + call->delay_ack_at = KTIME_MAX; + call->ack_lost_at = KTIME_MAX; + call->resend_at = KTIME_MAX; + call->ping_at = KTIME_MAX; + call->keepalive_at = KTIME_MAX; + call->expect_rx_by = KTIME_MAX; + call->expect_req_by = KTIME_MAX; + call->expect_term_by = KTIME_MAX; memset(&call->sock_node, 0xed, sizeof(call->sock_node)); @@ -226,11 +225,11 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, __set_bit(RXRPC_CALL_EXCLUSIVE, &call->flags); if (p->timeouts.normal) - call->next_rx_timo = min(msecs_to_jiffies(p->timeouts.normal), 1UL); + call->next_rx_timo = min(p->timeouts.normal, 1); if (p->timeouts.idle) - call->next_req_timo = min(msecs_to_jiffies(p->timeouts.idle), 1UL); + call->next_req_timo = min(p->timeouts.idle, 1); if (p->timeouts.hard) - call->hard_timo = p->timeouts.hard * HZ; + call->hard_timo = p->timeouts.hard; ret = rxrpc_init_client_call_security(call); if (ret < 0) { @@ -253,18 +252,13 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, */ void rxrpc_start_call_timer(struct rxrpc_call *call) { - unsigned long now = jiffies; - unsigned long j = now + MAX_JIFFY_OFFSET; + if (call->hard_timo) { + ktime_t delay = ms_to_ktime(call->hard_timo * 1000); - call->delay_ack_at = j; - call->ack_lost_at = j; - call->resend_at = j; - call->ping_at = j; - call->keepalive_at = j; - call->expect_rx_by = j; - call->expect_req_by = j; - call->expect_term_by = j + call->hard_timo; - call->timer.expires = now; + call->expect_term_by = ktime_add(ktime_get_real(), delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_hard); + } + call->timer.expires = jiffies; } /* diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index e53a49accc16..09cce1d5d605 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -252,6 +252,9 @@ static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun, { ASSERT(test_bit(RXRPC_CALL_TX_LAST, &call->flags)); + call->resend_at = KTIME_MAX; + trace_rxrpc_timer_can(call, rxrpc_timer_trace_resend); + if (unlikely(call->cong_last_nack)) { rxrpc_free_skb(call->cong_last_nack, rxrpc_skb_put_last_nack); call->cong_last_nack = NULL; @@ -288,13 +291,11 @@ static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun, static bool rxrpc_receiving_reply(struct rxrpc_call *call) { struct rxrpc_ack_summary summary = { 0 }; - unsigned long now; rxrpc_seq_t top = READ_ONCE(call->tx_top); if (call->ackr_reason) { - now = jiffies; - call->delay_ack_at = now + MAX_JIFFY_OFFSET; - trace_rxrpc_timer(call, rxrpc_timer_init_for_reply, now); + call->delay_ack_at = KTIME_MAX; + trace_rxrpc_timer_can(call, rxrpc_timer_trace_delayed_ack); } if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) { @@ -327,7 +328,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial) case RXRPC_CALL_SERVER_RECV_REQUEST: rxrpc_set_call_state(call, RXRPC_CALL_SERVER_ACK_REQUEST); - call->expect_req_by = jiffies + MAX_JIFFY_OFFSET; + call->expect_req_by = KTIME_MAX; rxrpc_propose_delay_ACK(call, serial, rxrpc_propose_ack_processing_op); break; @@ -587,14 +588,12 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) case RXRPC_CALL_SERVER_RECV_REQUEST: { unsigned long timo = READ_ONCE(call->next_req_timo); - unsigned long now, expect_req_by; if (timo) { - now = jiffies; - expect_req_by = now + timo; - call->expect_req_by = now + timo; - rxrpc_reduce_call_timer(call, expect_req_by, now, - rxrpc_timer_set_for_idle); + ktime_t delay = ms_to_ktime(timo); + + call->expect_req_by = ktime_add(ktime_get_real(), delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_idle); } break; } @@ -1046,11 +1045,10 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb) timo = READ_ONCE(call->next_rx_timo); if (timo) { - unsigned long now = jiffies; + ktime_t delay = ms_to_ktime(timo); - call->expect_rx_by = now + timo; - rxrpc_reduce_call_timer(call, call->expect_rx_by, now, - rxrpc_timer_set_for_normal); + call->expect_rx_by = ktime_add(ktime_get_real(), delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_expect_rx); } switch (sp->hdr.type) { diff --git a/net/rxrpc/misc.c b/net/rxrpc/misc.c index 825b81183046..657cf35089a6 100644 --- a/net/rxrpc/misc.c +++ b/net/rxrpc/misc.c @@ -17,22 +17,22 @@ unsigned int rxrpc_max_backlog __read_mostly = 10; /* - * How long to wait before scheduling an ACK with subtype DELAY (in jiffies). + * How long to wait before scheduling an ACK with subtype DELAY (in ms). * * We use this when we've received new data packets. If those packets aren't * all consumed within this time we will send a DELAY ACK if an ACK was not * requested to let the sender know it doesn't need to resend. */ -unsigned long rxrpc_soft_ack_delay = HZ; +unsigned long rxrpc_soft_ack_delay = 1000; /* - * How long to wait before scheduling an ACK with subtype IDLE (in jiffies). + * How long to wait before scheduling an ACK with subtype IDLE (in ms). * * We use this when we've consumed some previously soft-ACK'd packets when * further packets aren't immediately received to decide when to send an IDLE * ACK let the other end know that it can free up its Tx buffer space. */ -unsigned long rxrpc_idle_ack_delay = HZ / 2; +unsigned long rxrpc_idle_ack_delay = 500; /* * Receive window size in packets. This indicates the maximum number of diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 0a317498b8e0..ec82193e5681 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -48,12 +48,10 @@ static const char rxrpc_keepalive_string[] = ""; static void rxrpc_tx_backoff(struct rxrpc_call *call, int ret) { if (ret < 0) { - u16 tx_backoff = READ_ONCE(call->tx_backoff); - - if (tx_backoff < HZ) - WRITE_ONCE(call->tx_backoff, tx_backoff + 1); + if (call->tx_backoff < 1000) + call->tx_backoff += 100; } else { - WRITE_ONCE(call->tx_backoff, 0); + call->tx_backoff = 0; } } @@ -67,11 +65,10 @@ static void rxrpc_tx_backoff(struct rxrpc_call *call, int ret) */ static void rxrpc_set_keepalive(struct rxrpc_call *call) { - unsigned long now = jiffies; + ktime_t delay = ms_to_ktime(READ_ONCE(call->next_rx_timo) / 6); - call->keepalive_at = now + call->next_rx_timo / 6; - rxrpc_reduce_call_timer(call, call->keepalive_at, now, - rxrpc_timer_set_for_keepalive); + call->keepalive_at = ktime_add(ktime_get_real(), delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_keepalive); } /* @@ -515,24 +512,21 @@ done: if (txb->flags & RXRPC_REQUEST_ACK) { call->peer->rtt_last_req = txb->last_sent; if (call->peer->rtt_count > 1) { - unsigned long nowj = jiffies, ack_lost_at; + ktime_t delay = rxrpc_get_rto_backoff(call->peer, false); + ktime_t now = ktime_get_real(); - ack_lost_at = rxrpc_get_rto_backoff(call->peer, false); - ack_lost_at += nowj; - call->ack_lost_at = ack_lost_at; - rxrpc_reduce_call_timer(call, ack_lost_at, nowj, - rxrpc_timer_set_for_lost_ack); + call->ack_lost_at = ktime_add(now, delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_lost_ack); } } if (txb->seq == 1 && !test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, &call->flags)) { - unsigned long nowj = jiffies; + ktime_t delay = ms_to_ktime(READ_ONCE(call->next_rx_timo)); - call->expect_rx_by = nowj + call->next_rx_timo; - rxrpc_reduce_call_timer(call, call->expect_rx_by, nowj, - rxrpc_timer_set_for_normal); + call->expect_rx_by = ktime_add(ktime_get_real(), delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_expect_rx); } rxrpc_set_keepalive(call); @@ -755,11 +749,9 @@ void rxrpc_transmit_one(struct rxrpc_call *call, struct rxrpc_txbuf *txb) rxrpc_instant_resend(call, txb); } } else { - unsigned long now = jiffies; - unsigned long resend_at = now + call->peer->rto_j; + ktime_t delay = ns_to_ktime(call->peer->rto_us * NSEC_PER_USEC); - call->resend_at = resend_at; - rxrpc_reduce_call_timer(call, resend_at, now, - rxrpc_timer_set_for_send); + call->resend_at = ktime_add(ktime_get_real(), delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_resend_tx); } } diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c index 26dc2f26d92d..263a2251e3d2 100644 --- a/net/rxrpc/proc.c +++ b/net/rxrpc/proc.c @@ -52,9 +52,9 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) struct rxrpc_call *call; struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); enum rxrpc_call_state state; - unsigned long timeout = 0; rxrpc_seq_t acks_hard_ack; char lbuff[50], rbuff[50]; + long timeout = 0; if (v == &rxnet->calls) { seq_puts(seq, @@ -76,10 +76,8 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) sprintf(rbuff, "%pISpc", &call->dest_srx.transport); state = rxrpc_call_state(call); - if (state != RXRPC_CALL_SERVER_PREALLOC) { - timeout = READ_ONCE(call->expect_rx_by); - timeout -= jiffies; - } + if (state != RXRPC_CALL_SERVER_PREALLOC) + timeout = ktime_ms_delta(READ_ONCE(call->expect_rx_by), ktime_get_real()); acks_hard_ack = READ_ONCE(call->acks_hard_ack); seq_printf(seq, @@ -309,7 +307,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v) peer->mtu, now - peer->last_tx_at, peer->srtt_us >> 3, - jiffies_to_usecs(peer->rto_j)); + peer->rto_us); return 0; } diff --git a/net/rxrpc/rtt.c b/net/rxrpc/rtt.c index be61d6f5be8d..cdab7b7d08a0 100644 --- a/net/rxrpc/rtt.c +++ b/net/rxrpc/rtt.c @@ -11,8 +11,8 @@ #include #include "ar-internal.h" -#define RXRPC_RTO_MAX ((unsigned)(120 * HZ)) -#define RXRPC_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC6298 2.1 initial RTO value */ +#define RXRPC_RTO_MAX (120 * USEC_PER_SEC) +#define RXRPC_TIMEOUT_INIT ((unsigned int)(1 * MSEC_PER_SEC)) /* RFC6298 2.1 initial RTO value */ #define rxrpc_jiffies32 ((u32)jiffies) /* As rxrpc_jiffies32 */ static u32 rxrpc_rto_min_us(struct rxrpc_peer *peer) @@ -22,7 +22,7 @@ static u32 rxrpc_rto_min_us(struct rxrpc_peer *peer) static u32 __rxrpc_set_rto(const struct rxrpc_peer *peer) { - return usecs_to_jiffies((peer->srtt_us >> 3) + peer->rttvar_us); + return (peer->srtt_us >> 3) + peer->rttvar_us; } static u32 rxrpc_bound_rto(u32 rto) @@ -124,7 +124,7 @@ static void rxrpc_set_rto(struct rxrpc_peer *peer) /* NOTE: clamping at RXRPC_RTO_MIN is not required, current algo * guarantees that rto is higher. */ - peer->rto_j = rxrpc_bound_rto(rto); + peer->rto_us = rxrpc_bound_rto(rto); } static void rxrpc_ack_update_rtt(struct rxrpc_peer *peer, long rtt_us) @@ -163,33 +163,33 @@ void rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why, spin_unlock(&peer->rtt_input_lock); trace_rxrpc_rtt_rx(call, why, rtt_slot, send_serial, resp_serial, - peer->srtt_us >> 3, peer->rto_j); + peer->srtt_us >> 3, peer->rto_us); } /* - * Get the retransmission timeout to set in jiffies, backing it off each time - * we retransmit. + * Get the retransmission timeout to set in nanoseconds, backing it off each + * time we retransmit. */ -unsigned long rxrpc_get_rto_backoff(struct rxrpc_peer *peer, bool retrans) +ktime_t rxrpc_get_rto_backoff(struct rxrpc_peer *peer, bool retrans) { - u64 timo_j; - u8 backoff = READ_ONCE(peer->backoff); + u64 timo_us; + u32 backoff = READ_ONCE(peer->backoff); - timo_j = peer->rto_j; - timo_j <<= backoff; - if (retrans && timo_j * 2 <= RXRPC_RTO_MAX) + timo_us = peer->rto_us; + timo_us <<= backoff; + if (retrans && timo_us * 2 <= RXRPC_RTO_MAX) WRITE_ONCE(peer->backoff, backoff + 1); - if (timo_j < 1) - timo_j = 1; + if (timo_us < 1) + timo_us = 1; - return timo_j; + return ns_to_ktime(timo_us * NSEC_PER_USEC); } void rxrpc_peer_init_rtt(struct rxrpc_peer *peer) { - peer->rto_j = RXRPC_TIMEOUT_INIT; - peer->mdev_us = jiffies_to_usecs(RXRPC_TIMEOUT_INIT); + peer->rto_us = RXRPC_TIMEOUT_INIT; + peer->mdev_us = RXRPC_TIMEOUT_INIT; peer->backoff = 0; //minmax_reset(&peer->rtt_min, rxrpc_jiffies32, ~0U); } diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index 4d152f06b039..6f765768c49c 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -609,7 +609,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) __releases(&rx->sk.sk_lock.slock) { struct rxrpc_call *call; - unsigned long now, j; bool dropped_lock = false; int ret; @@ -687,25 +686,21 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) switch (p.call.nr_timeouts) { case 3: - j = msecs_to_jiffies(p.call.timeouts.normal); - if (p.call.timeouts.normal > 0 && j == 0) - j = 1; - WRITE_ONCE(call->next_rx_timo, j); + WRITE_ONCE(call->next_rx_timo, p.call.timeouts.normal); fallthrough; case 2: - j = msecs_to_jiffies(p.call.timeouts.idle); - if (p.call.timeouts.idle > 0 && j == 0) - j = 1; - WRITE_ONCE(call->next_req_timo, j); + WRITE_ONCE(call->next_req_timo, p.call.timeouts.idle); fallthrough; case 1: if (p.call.timeouts.hard > 0) { - j = p.call.timeouts.hard * HZ; - now = jiffies; - j += now; - WRITE_ONCE(call->expect_term_by, j); - rxrpc_reduce_call_timer(call, j, now, - rxrpc_timer_set_for_hard); + ktime_t delay = ms_to_ktime(p.call.timeouts.hard * MSEC_PER_SEC); + + WRITE_ONCE(call->expect_term_by, + ktime_add(p.call.timeouts.hard, + ktime_get_real())); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_hard); + rxrpc_poke_call(call, rxrpc_call_poke_set_timeout); + } break; } diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c index ecaeb4ecfb58..c9bedd0e2d86 100644 --- a/net/rxrpc/sysctl.c +++ b/net/rxrpc/sysctl.c @@ -15,6 +15,8 @@ static const unsigned int four = 4; static const unsigned int max_backlog = RXRPC_BACKLOG_MAX - 1; static const unsigned int n_65535 = 65535; static const unsigned int n_max_acks = 255; +static const unsigned long one_ms = 1; +static const unsigned long max_ms = 1000; static const unsigned long one_jiffy = 1; static const unsigned long max_jiffies = MAX_JIFFY_OFFSET; #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY @@ -28,24 +30,24 @@ static const unsigned long max_500 = 500; * information on the individual parameters. */ static struct ctl_table rxrpc_sysctl_table[] = { - /* Values measured in milliseconds but used in jiffies */ + /* Values measured in milliseconds */ { .procname = "soft_ack_delay", .data = &rxrpc_soft_ack_delay, .maxlen = sizeof(unsigned long), .mode = 0644, - .proc_handler = proc_doulongvec_ms_jiffies_minmax, - .extra1 = (void *)&one_jiffy, - .extra2 = (void *)&max_jiffies, + .proc_handler = proc_doulongvec_minmax, + .extra1 = (void *)&one_ms, + .extra2 = (void *)&max_ms, }, { .procname = "idle_ack_delay", .data = &rxrpc_idle_ack_delay, .maxlen = sizeof(unsigned long), .mode = 0644, - .proc_handler = proc_doulongvec_ms_jiffies_minmax, - .extra1 = (void *)&one_jiffy, - .extra2 = (void *)&max_jiffies, + .proc_handler = proc_doulongvec_minmax, + .extra1 = (void *)&one_ms, + .extra2 = (void *)&max_ms, }, { .procname = "idle_conn_expiry", From 4d267ad6fd566c58d33ac899fefd5357b9a71908 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 Jan 2024 11:03:52 +0000 Subject: [PATCH 1897/2255] rxrpc: Record probes after transmission and reduce number of time-gets Move the recording of a successfully transmitted DATA or ACK packet that will provide RTT probing to after the transmission. With the I/O thread model, this can be done because parsing of the responding ACK can no longer race with the post-transmission code. Move the various timeout-settings done after successfully transmitting a DATA packet into rxrpc_tstamp_data_packets() and eliminate a number of calls to get the current time. As a consequence we no longer need to cancel a proposed RTT probe on transmission failure. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/output.c | 105 +++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 65 deletions(-) diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index ec82193e5681..5ea9601efd05 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -63,7 +63,7 @@ static void rxrpc_tx_backoff(struct rxrpc_call *call, int ret) * Receiving a response to the ping will prevent the ->expect_rx_by timer from * expiring. */ -static void rxrpc_set_keepalive(struct rxrpc_call *call) +static void rxrpc_set_keepalive(struct rxrpc_call *call, ktime_t now) { ktime_t delay = ms_to_ktime(READ_ONCE(call->next_rx_timo) / 6); @@ -147,8 +147,8 @@ static void rxrpc_fill_out_ack(struct rxrpc_call *call, /* * Record the beginning of an RTT probe. */ -static int rxrpc_begin_rtt_probe(struct rxrpc_call *call, rxrpc_serial_t serial, - enum rxrpc_rtt_tx_trace why) +static void rxrpc_begin_rtt_probe(struct rxrpc_call *call, rxrpc_serial_t serial, + ktime_t now, enum rxrpc_rtt_tx_trace why) { unsigned long avail = call->rtt_avail; int rtt_slot = 9; @@ -161,30 +161,15 @@ static int rxrpc_begin_rtt_probe(struct rxrpc_call *call, rxrpc_serial_t serial, goto no_slot; call->rtt_serial[rtt_slot] = serial; - call->rtt_sent_at[rtt_slot] = ktime_get_real(); + call->rtt_sent_at[rtt_slot] = now; smp_wmb(); /* Write data before avail bit */ set_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail); trace_rxrpc_rtt_tx(call, why, rtt_slot, serial); - return rtt_slot; + return; no_slot: trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_no_slot, rtt_slot, serial); - return -1; -} - -/* - * Cancel an RTT probe. - */ -static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call, - rxrpc_serial_t serial, int rtt_slot) -{ - if (rtt_slot != -1) { - clear_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail); - smp_wmb(); /* Clear pending bit before setting slot */ - set_bit(rtt_slot, &call->rtt_avail); - trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_cancel, rtt_slot, serial); - } } /* @@ -196,7 +181,8 @@ static void rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *t struct rxrpc_connection *conn; struct rxrpc_ackpacket *ack = (struct rxrpc_ackpacket *)(whdr + 1); struct msghdr msg; - int ret, rtt_slot = -1; + ktime_t now; + int ret; if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) return; @@ -218,9 +204,6 @@ static void rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *t ntohl(ack->serial), ack->reason, ack->nAcks, txb->ack_rwind); - if (ack->reason == RXRPC_ACK_PING) - rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_ping); - rxrpc_inc_stat(call->rxnet, stat_tx_ack_send); iov_iter_kvec(&msg.msg_iter, WRITE, txb->kvec, txb->nr_kvec, txb->len); @@ -233,16 +216,14 @@ static void rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *t } else { trace_rxrpc_tx_packet(call->debug_id, whdr, rxrpc_tx_point_call_ack); + now = ktime_get_real(); + if (ack->reason == RXRPC_ACK_PING) + rxrpc_begin_rtt_probe(call, txb->serial, now, rxrpc_rtt_tx_ping); if (txb->flags & RXRPC_REQUEST_ACK) - call->peer->rtt_last_req = ktime_get_real(); + call->peer->rtt_last_req = now; + rxrpc_set_keepalive(call, now); } rxrpc_tx_backoff(call, ret); - - if (!__rxrpc_call_is_complete(call)) { - if (ret < 0) - rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); - rxrpc_set_keepalive(call); - } } /* @@ -413,18 +394,36 @@ static size_t rxrpc_prepare_data_packet(struct rxrpc_call *call, struct rxrpc_tx } /* - * Set the times on a packet before transmission + * Set timeouts after transmitting a packet. */ -static int rxrpc_tstamp_data_packets(struct rxrpc_call *call, struct rxrpc_txbuf *txb) +static void rxrpc_tstamp_data_packets(struct rxrpc_call *call, struct rxrpc_txbuf *txb) { - ktime_t tstamp = ktime_get_real(); - int rtt_slot = -1; + ktime_t now = ktime_get_real(); + bool ack_requested = txb->flags & RXRPC_REQUEST_ACK; - txb->last_sent = tstamp; - if (txb->flags & RXRPC_REQUEST_ACK) - rtt_slot = rxrpc_begin_rtt_probe(call, txb->serial, rxrpc_rtt_tx_data); + call->tx_last_sent = now; + txb->last_sent = now; - return rtt_slot; + if (ack_requested) { + rxrpc_begin_rtt_probe(call, txb->serial, now, rxrpc_rtt_tx_data); + + call->peer->rtt_last_req = now; + if (call->peer->rtt_count > 1) { + ktime_t delay = rxrpc_get_rto_backoff(call->peer, false); + + call->ack_lost_at = ktime_add(now, delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_lost_ack); + } + } + + if (!test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, &call->flags)) { + ktime_t delay = ms_to_ktime(READ_ONCE(call->next_rx_timo)); + + call->expect_rx_by = ktime_add(now, delay); + trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_expect_rx); + } + + rxrpc_set_keepalive(call, now); } /* @@ -437,7 +436,7 @@ static int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *t enum rxrpc_tx_point frag; struct msghdr msg; size_t len; - int ret, rtt_slot = -1; + int ret; _enter("%x,{%d}", txb->seq, txb->len); @@ -479,8 +478,6 @@ static int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *t } retry: - rtt_slot = rxrpc_tstamp_data_packets(call, txb); - /* send the packet by UDP * - returns -EMSGSIZE if UDP would have to fragment the packet * to go out of the interface @@ -493,7 +490,6 @@ retry: if (ret < 0) { rxrpc_inc_stat(call->rxnet, stat_tx_data_send_fail); - rxrpc_cancel_rtt_probe(call, txb->serial, rtt_slot); trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret, frag); } else { trace_rxrpc_tx_packet(call->debug_id, whdr, frag); @@ -508,28 +504,7 @@ retry: done: if (ret >= 0) { - call->tx_last_sent = txb->last_sent; - if (txb->flags & RXRPC_REQUEST_ACK) { - call->peer->rtt_last_req = txb->last_sent; - if (call->peer->rtt_count > 1) { - ktime_t delay = rxrpc_get_rto_backoff(call->peer, false); - ktime_t now = ktime_get_real(); - - call->ack_lost_at = ktime_add(now, delay); - trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_lost_ack); - } - } - - if (txb->seq == 1 && - !test_and_set_bit(RXRPC_CALL_BEGAN_RX_TIMER, - &call->flags)) { - ktime_t delay = ms_to_ktime(READ_ONCE(call->next_rx_timo)); - - call->expect_rx_by = ktime_add(ktime_get_real(), delay); - trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_expect_rx); - } - - rxrpc_set_keepalive(call); + rxrpc_tstamp_data_packets(call, txb); } else { /* Cancel the call if the initial transmission fails, * particularly if that's due to network routing issues that From 37473e41623409286ab2f5db628a59d4da9a79d7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 Jan 2024 14:58:40 +0000 Subject: [PATCH 1898/2255] rxrpc: Clean up the resend algorithm Clean up the DATA packet resending algorithm to retransmit packets as we come across them whilst walking the transmission buffer rather than queuing them for retransmission at the end. This can be done as ACK parsing - and thus the discarding of successful packets - is now done in the same thread rather than separately in softirq context and a locked section is no longer required. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/call_event.c | 81 ++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 2a9f74eb7c46..6c5e3054209b 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -71,23 +71,18 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) struct rxrpc_skb_priv *sp; struct rxrpc_txbuf *txb; rxrpc_seq_t transmitted = call->tx_transmitted; - ktime_t now, max_age, oldest, ack_ts, delay; - bool unacked = false; + ktime_t next_resend = KTIME_MAX, rto = ns_to_ktime(call->peer->rto_us * NSEC_PER_USEC); + ktime_t resend_at = KTIME_MAX, now, delay; + bool unacked = false, did_send = false; unsigned int i; - LIST_HEAD(retrans_queue); _enter("{%d,%d}", call->acks_hard_ack, call->tx_top); now = ktime_get_real(); - max_age = ktime_sub_us(now, call->peer->rto_us); - oldest = now; if (list_empty(&call->tx_buffer)) goto no_resend; - if (list_empty(&call->tx_buffer)) - goto no_further_resend; - trace_rxrpc_resend(call, ack_skb); txb = list_first_entry(&call->tx_buffer, struct rxrpc_txbuf, call_link); @@ -115,19 +110,23 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) goto no_further_resend; found_txb: - if (after(txb->serial, call->acks_highest_serial)) + resend_at = ktime_add(txb->last_sent, rto); + if (after(txb->serial, call->acks_highest_serial)) { + if (ktime_after(resend_at, now) && + ktime_before(resend_at, next_resend)) + next_resend = resend_at; continue; /* Ack point not yet reached */ + } rxrpc_see_txbuf(txb, rxrpc_txbuf_see_unacked); - if (list_empty(&txb->tx_link)) { - list_add_tail(&txb->tx_link, &retrans_queue); - txb->flags |= RXRPC_TXBUF_RESENT; - } - trace_rxrpc_retransmit(call, txb->seq, txb->serial, - ktime_to_ns(ktime_sub(txb->last_sent, - max_age))); + ktime_sub(resend_at, now)); + + txb->flags |= RXRPC_TXBUF_RESENT; + rxrpc_transmit_one(call, txb); + did_send = true; + now = ktime_get_real(); if (list_is_last(&txb->call_link, &call->tx_buffer)) goto no_further_resend; @@ -144,6 +143,8 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) goto no_further_resend; list_for_each_entry_from(txb, &call->tx_buffer, call_link) { + resend_at = ktime_add(txb->last_sent, rto); + if (before_eq(txb->seq, call->acks_prev_seq)) continue; if (after(txb->seq, call->tx_transmitted)) @@ -153,25 +154,30 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) before(txb->serial, ntohl(ack->serial))) goto do_resend; /* Wasn't accounted for by a more recent ping. */ - if (ktime_after(txb->last_sent, max_age)) { - if (ktime_before(txb->last_sent, oldest)) - oldest = txb->last_sent; + if (ktime_after(resend_at, now)) { + if (ktime_before(resend_at, next_resend)) + next_resend = resend_at; continue; } do_resend: unacked = true; - if (list_empty(&txb->tx_link)) { - list_add_tail(&txb->tx_link, &retrans_queue); - txb->flags |= RXRPC_TXBUF_RESENT; - rxrpc_inc_stat(call->rxnet, stat_tx_data_retrans); - } + + txb->flags |= RXRPC_TXBUF_RESENT; + rxrpc_transmit_one(call, txb); + did_send = true; + rxrpc_inc_stat(call->rxnet, stat_tx_data_retrans); + now = ktime_get_real(); } no_further_resend: no_resend: - delay = rxrpc_get_rto_backoff(call->peer, !list_empty(&retrans_queue)); - call->resend_at = ktime_add(oldest, delay); + if (resend_at < KTIME_MAX) { + delay = rxrpc_get_rto_backoff(call->peer, did_send); + resend_at = ktime_add(resend_at, delay); + trace_rxrpc_timer_set(call, resend_at - now, rxrpc_timer_trace_resend_reset); + } + call->resend_at = resend_at; if (unacked) rxrpc_congestion_timeout(call); @@ -180,24 +186,15 @@ no_resend: * that an ACK got lost somewhere. Send a ping to find out instead of * retransmitting data. */ - if (list_empty(&retrans_queue)) { - trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_resend_reset); - ack_ts = ktime_sub(now, call->acks_latest_ts); - if (ktime_to_us(ack_ts) < (call->peer->srtt_us >> 3)) - goto out; - rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, - rxrpc_propose_ack_ping_for_0_retrans); - goto out; + if (!did_send) { + ktime_t next_ping = ktime_add_us(call->acks_latest_ts, + call->peer->srtt_us >> 3); + + if (ktime_sub(next_ping, now) <= 0) + rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, + rxrpc_propose_ack_ping_for_0_retrans); } - /* Retransmit the queue */ - while ((txb = list_first_entry_or_null(&retrans_queue, - struct rxrpc_txbuf, tx_link))) { - list_del_init(&txb->tx_link); - rxrpc_transmit_one(call, txb); - } - -out: _leave(""); } From 4b68137a20bc88fbbdf32301ed604ef000c94e5c Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 1 Feb 2024 10:29:36 +0000 Subject: [PATCH 1899/2255] rxrpc: Extract useful fields from a received ACK to skb priv data Extract useful fields from a received ACK packet into the skb private data early on in the process of parsing incoming packets. This makes the ACK fields available even before we've matched the ACK up to a call and will allow us to deal with path MTU discovery probe responses even after the relevant call has been completed. Signed-off-by: David Howells cc: Marc Dionne cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org --- net/rxrpc/ar-internal.h | 7 +++-- net/rxrpc/call_event.c | 4 +-- net/rxrpc/input.c | 59 ++++++++++++++++++----------------------- net/rxrpc/io_thread.c | 11 ++++++++ 4 files changed, 44 insertions(+), 37 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 21ecac22b51d..08c0a32db8c7 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -198,8 +198,8 @@ struct rxrpc_host_header { * - max 48 bytes (struct sk_buff::cb) */ struct rxrpc_skb_priv { - struct rxrpc_connection *conn; /* Connection referred to (poke packet) */ union { + struct rxrpc_connection *conn; /* Connection referred to (poke packet) */ struct { u16 offset; /* Offset of data */ u16 len; /* Length of data */ @@ -208,9 +208,12 @@ struct rxrpc_skb_priv { }; struct { rxrpc_seq_t first_ack; /* First packet in acks table */ + rxrpc_seq_t prev_ack; /* Highest seq seen */ + rxrpc_serial_t acked_serial; /* Packet in response to (or 0) */ + u8 reason; /* Reason for ack */ u8 nr_acks; /* Number of acks+nacks */ u8 nr_nacks; /* Number of nacks */ - }; + } ack; }; struct rxrpc_host_header hdr; /* RxRPC packet header from this packet */ }; diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 6c5e3054209b..7bbb68504766 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -93,12 +93,12 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) sp = rxrpc_skb(ack_skb); ack = (void *)ack_skb->data + sizeof(struct rxrpc_wire_header); - for (i = 0; i < sp->nr_acks; i++) { + for (i = 0; i < sp->ack.nr_acks; i++) { rxrpc_seq_t seq; if (ack->acks[i] & 1) continue; - seq = sp->first_ack + i; + seq = sp->ack.first_ack + i; if (after(txb->seq, transmitted)) break; if (after(txb->seq, seq)) diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index 09cce1d5d605..3dedb8c0618c 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -710,20 +710,19 @@ static rxrpc_seq_t rxrpc_input_check_prev_ack(struct rxrpc_call *call, rxrpc_seq_t seq) { struct sk_buff *skb = call->cong_last_nack; - struct rxrpc_ackpacket ack; struct rxrpc_skb_priv *sp = rxrpc_skb(skb); unsigned int i, new_acks = 0, retained_nacks = 0; - rxrpc_seq_t old_seq = sp->first_ack; - u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(ack); + rxrpc_seq_t old_seq = sp->ack.first_ack; + u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket); - if (after_eq(seq, old_seq + sp->nr_acks)) { - summary->nr_new_acks += sp->nr_nacks; - summary->nr_new_acks += seq - (old_seq + sp->nr_acks); + if (after_eq(seq, old_seq + sp->ack.nr_acks)) { + summary->nr_new_acks += sp->ack.nr_nacks; + summary->nr_new_acks += seq - (old_seq + sp->ack.nr_acks); summary->nr_retained_nacks = 0; } else if (seq == old_seq) { - summary->nr_retained_nacks = sp->nr_nacks; + summary->nr_retained_nacks = sp->ack.nr_nacks; } else { - for (i = 0; i < sp->nr_acks; i++) { + for (i = 0; i < sp->ack.nr_acks; i++) { if (acks[i] == RXRPC_ACK_TYPE_NACK) { if (before(old_seq + i, seq)) new_acks++; @@ -736,7 +735,7 @@ static rxrpc_seq_t rxrpc_input_check_prev_ack(struct rxrpc_call *call, summary->nr_retained_nacks = retained_nacks; } - return old_seq + sp->nr_acks; + return old_seq + sp->ack.nr_acks; } /* @@ -756,10 +755,10 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call, { struct rxrpc_skb_priv *sp = rxrpc_skb(skb); unsigned int i, old_nacks = 0; - rxrpc_seq_t lowest_nak = seq + sp->nr_acks; + rxrpc_seq_t lowest_nak = seq + sp->ack.nr_acks; u8 *acks = skb->data + sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket); - for (i = 0; i < sp->nr_acks; i++) { + for (i = 0; i < sp->ack.nr_acks; i++) { if (acks[i] == RXRPC_ACK_TYPE_ACK) { summary->nr_acks++; if (after_eq(seq, since)) @@ -771,7 +770,7 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call, old_nacks++; } else { summary->nr_new_nacks++; - sp->nr_nacks++; + sp->ack.nr_nacks++; } if (before(seq, lowest_nak)) @@ -832,7 +831,6 @@ static bool rxrpc_is_ack_valid(struct rxrpc_call *call, static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) { struct rxrpc_ack_summary summary = { 0 }; - struct rxrpc_ackpacket ack; struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_acktrailer trailer; rxrpc_serial_t ack_serial, acked_serial; @@ -841,29 +839,24 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) _enter(""); - offset = sizeof(struct rxrpc_wire_header); - if (skb_copy_bits(skb, offset, &ack, sizeof(ack)) < 0) - return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack); - offset += sizeof(ack); + offset = sizeof(struct rxrpc_wire_header) + sizeof(struct rxrpc_ackpacket); - ack_serial = sp->hdr.serial; - acked_serial = ntohl(ack.serial); - first_soft_ack = ntohl(ack.firstPacket); - prev_pkt = ntohl(ack.previousPacket); - hard_ack = first_soft_ack - 1; - nr_acks = ack.nAcks; - sp->first_ack = first_soft_ack; - sp->nr_acks = nr_acks; - summary.ack_reason = (ack.reason < RXRPC_ACK__INVALID ? - ack.reason : RXRPC_ACK__INVALID); + ack_serial = sp->hdr.serial; + acked_serial = sp->ack.acked_serial; + first_soft_ack = sp->ack.first_ack; + prev_pkt = sp->ack.prev_ack; + nr_acks = sp->ack.nr_acks; + hard_ack = first_soft_ack - 1; + summary.ack_reason = (sp->ack.reason < RXRPC_ACK__INVALID ? + sp->ack.reason : RXRPC_ACK__INVALID); trace_rxrpc_rx_ack(call, ack_serial, acked_serial, first_soft_ack, prev_pkt, summary.ack_reason, nr_acks); - rxrpc_inc_stat(call->rxnet, stat_rx_acks[ack.reason]); + rxrpc_inc_stat(call->rxnet, stat_rx_acks[summary.ack_reason]); if (acked_serial != 0) { - switch (ack.reason) { + switch (summary.ack_reason) { case RXRPC_ACK_PING_RESPONSE: rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial, rxrpc_rtt_rx_ping_response); @@ -883,7 +876,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) * indicates that the client address changed due to NAT. The server * lost the call because it switched to a different peer. */ - if (unlikely(ack.reason == RXRPC_ACK_EXCEEDS_WINDOW) && + if (unlikely(summary.ack_reason == RXRPC_ACK_EXCEEDS_WINDOW) && first_soft_ack == 1 && prev_pkt == 0 && rxrpc_is_client_call(call)) { @@ -896,7 +889,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) * indicate a change of address. However, we can retransmit the call * if we still have it buffered to the beginning. */ - if (unlikely(ack.reason == RXRPC_ACK_OUT_OF_SEQUENCE) && + if (unlikely(summary.ack_reason == RXRPC_ACK_OUT_OF_SEQUENCE) && first_soft_ack == 1 && prev_pkt == 0 && call->acks_hard_ack == 0 && @@ -937,7 +930,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) call->acks_first_seq = first_soft_ack; call->acks_prev_seq = prev_pkt; - switch (ack.reason) { + switch (summary.ack_reason) { case RXRPC_ACK_PING: break; default: @@ -994,7 +987,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) rxrpc_congestion_management(call, skb, &summary, acked_serial); send_response: - if (ack.reason == RXRPC_ACK_PING) + if (summary.ack_reason == RXRPC_ACK_PING) rxrpc_send_ACK(call, RXRPC_ACK_PING_RESPONSE, ack_serial, rxrpc_propose_ack_respond_to_ping); else if (sp->hdr.flags & RXRPC_REQUEST_ACK) diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c index 4a3a08a0e2cd..0300baa9afcd 100644 --- a/net/rxrpc/io_thread.c +++ b/net/rxrpc/io_thread.c @@ -124,6 +124,7 @@ static bool rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb) { struct rxrpc_wire_header whdr; + struct rxrpc_ackpacket ack; /* dig out the RxRPC connection details */ if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0) @@ -141,6 +142,16 @@ static bool rxrpc_extract_header(struct rxrpc_skb_priv *sp, sp->hdr.securityIndex = whdr.securityIndex; sp->hdr._rsvd = ntohs(whdr._rsvd); sp->hdr.serviceId = ntohs(whdr.serviceId); + + if (sp->hdr.type == RXRPC_PACKET_TYPE_ACK) { + if (skb_copy_bits(skb, sizeof(whdr), &ack, sizeof(ack)) < 0) + return rxrpc_bad_message(skb, rxrpc_badmsg_short_ack); + sp->ack.first_ack = ntohl(ack.firstPacket); + sp->ack.prev_ack = ntohl(ack.previousPacket); + sp->ack.acked_serial = ntohl(ack.serial); + sp->ack.reason = ack.reason; + sp->ack.nr_acks = ack.nAcks; + } return true; } From 46f480ec145886641374c4c4bdc7e6b56bc97adb Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 4 Mar 2024 10:38:07 -0800 Subject: [PATCH 1900/2255] net: tuntap: Leverage core stats allocator With commit 34d21de99cea9 ("net: Move {l,t,d}stats allocation to core and convert veth & vrf"), stats allocation could be done on net core instead of in this driver. With this new approach, the driver doesn't have to bother with error handling (allocation failure checking, making sure free happens in the right spot, etc). This is core responsibility now. Remove the allocation in the tun/tap driver and leverage the network core allocation instead. Signed-off-by: Breno Leitao Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20240304183810.1474883-1-leitao@debian.org Signed-off-by: Jakub Kicinski --- drivers/net/tun.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index be37235af55d..6c594a3c2c37 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -977,20 +977,15 @@ static int tun_net_init(struct net_device *dev) struct ifreq *ifr = tun->ifr; int err; - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - spin_lock_init(&tun->lock); err = security_tun_dev_alloc_security(&tun->security); - if (err < 0) { - free_percpu(dev->tstats); + if (err < 0) return err; - } tun_flow_init(tun); + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; @@ -1008,7 +1003,6 @@ static int tun_net_init(struct net_device *dev) if (err < 0) { tun_flow_uninit(tun); security_tun_dev_free_security(tun->security); - free_percpu(dev->tstats); return err; } return 0; @@ -2317,7 +2311,6 @@ static void tun_free_netdev(struct net_device *dev) BUG_ON(!(list_empty(&tun->disabled))); - free_percpu(dev->tstats); tun_flow_uninit(tun); security_tun_dev_free_security(tun->security); __tun_set_ebpf(tun, &tun->steering_prog, NULL); From 4166204d7ec26aee3d1f26847e88e4e41841fbe3 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 4 Mar 2024 10:38:08 -0800 Subject: [PATCH 1901/2255] net: tap: Remove generic .ndo_get_stats64 Commit 3e2f544dd8a33 ("net: get stats64 if device if driver is configured") moved the callback to dev_get_tstats64() to net core, so, unless the driver is doing some custom stats collection, it does not need to set .ndo_get_stats64. Since this driver is now relying in NETDEV_PCPU_STAT_TSTATS, then, it doesn't need to set the dev_get_tstats64() generic .ndo_get_stats64 function pointer. Signed-off-by: Breno Leitao Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20240304183810.1474883-2-leitao@debian.org Signed-off-by: Jakub Kicinski --- drivers/net/tun.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 6c594a3c2c37..8d258e263f54 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1338,7 +1338,6 @@ static const struct net_device_ops tap_netdev_ops = { .ndo_select_queue = tun_select_queue, .ndo_features_check = passthru_features_check, .ndo_set_rx_headroom = tun_set_headroom, - .ndo_get_stats64 = dev_get_tstats64, .ndo_bpf = tun_xdp, .ndo_xdp_xmit = tun_xdp_xmit, .ndo_change_carrier = tun_net_change_carrier, From ff73f8344e58e7557819f92c88f289ffa6116be7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 4 Mar 2024 13:29:31 -0800 Subject: [PATCH 1902/2255] sock: Use unsafe_memcpy() for sock_copy() While testing for places where zero-sized destinations were still showing up in the kernel, sock_copy() and inet_reqsk_clone() were found, which are using very specific memcpy() offsets for both avoiding a portion of struct sock, and copying beyond the end of it (since struct sock is really just a common header before the protocol-specific allocation). Instead of trying to unravel this historical lack of container_of(), just switch to unsafe_memcpy(), since that's effectively what was happening already (memcpy() wasn't checking 0-sized destinations while the code base was being converted away from fake flexible arrays). Avoid the following false positive warning with future changes to CONFIG_FORTIFY_SOURCE: memcpy: detected field-spanning write (size 3068) of destination "&nsk->__sk_common.skc_dontcopy_end" at net/core/sock.c:2057 (size 0) Signed-off-by: Kees Cook Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20240304212928.make.772-kees@kernel.org Signed-off-by: Jakub Kicinski --- net/core/sock.c | 5 +++-- net/ipv4/inet_connection_sock.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index df2ac54a8f74..43bf3818c19e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2053,8 +2053,9 @@ static void sock_copy(struct sock *nsk, const struct sock *osk) memcpy(nsk, osk, offsetof(struct sock, sk_dontcopy_begin)); - memcpy(&nsk->sk_dontcopy_end, &osk->sk_dontcopy_end, - prot->obj_size - offsetof(struct sock, sk_dontcopy_end)); + unsafe_memcpy(&nsk->sk_dontcopy_end, &osk->sk_dontcopy_end, + prot->obj_size - offsetof(struct sock, sk_dontcopy_end), + /* alloc is larger than struct, see sk_prot_alloc() */); #ifdef CONFIG_SECURITY_NETWORK nsk->sk_security = sptr; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 747ed7344cbe..7d8090f109ef 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -906,8 +906,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req, memcpy(nreq_sk, req_sk, offsetof(struct sock, sk_dontcopy_begin)); - memcpy(&nreq_sk->sk_dontcopy_end, &req_sk->sk_dontcopy_end, - req->rsk_ops->obj_size - offsetof(struct sock, sk_dontcopy_end)); + unsafe_memcpy(&nreq_sk->sk_dontcopy_end, &req_sk->sk_dontcopy_end, + req->rsk_ops->obj_size - offsetof(struct sock, sk_dontcopy_end), + /* alloc is larger than struct, see above */); sk_node_init(&nreq_sk->sk_node); nreq_sk->sk_tx_queue_mapping = req_sk->sk_tx_queue_mapping; From 344f7a4651497ffc62166ec6318b33f79d71c3df Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 2 Mar 2024 15:18:27 +0100 Subject: [PATCH 1903/2255] ethtool: ignore unused/unreliable fields in set_eee op This function is used with the set_eee() ethtool operation. Certain fields of struct ethtool_keee() are relevant only for the get_eee() operation. In addition, in case of the ioctl interface, we have no guarantee that userspace sends sane values in struct ethtool_eee. Therefore explicitly ignore all fields not needed for set_eee(). This protects from drivers trying to use unchecked and unreliable data, relying on specific userspace behavior. Note: Such unsafe driver behavior has been found and fixed in the tg3 driver. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/ad7ee11e-eb7a-4975-9122-547e13a161d8@gmail.com Signed-off-by: Jakub Kicinski --- net/ethtool/ioctl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 317308bdbda9..5a55270aa86e 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1514,17 +1514,12 @@ static void eee_to_keee(struct ethtool_keee *keee, { memset(keee, 0, sizeof(*keee)); - keee->eee_active = eee->eee_active; keee->eee_enabled = eee->eee_enabled; keee->tx_lpi_enabled = eee->tx_lpi_enabled; keee->tx_lpi_timer = eee->tx_lpi_timer; - ethtool_convert_legacy_u32_to_link_mode(keee->supported, - eee->supported); ethtool_convert_legacy_u32_to_link_mode(keee->advertised, eee->advertised); - ethtool_convert_legacy_u32_to_link_mode(keee->lp_advertised, - eee->lp_advertised); } static void keee_to_eee(struct ethtool_eee *eee, From 6f2fc8584a46bb35787bfc1dad1fb7dd5898e21f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 2 Mar 2024 20:53:00 +0100 Subject: [PATCH 1904/2255] net: add helpers for EEE configuration Add helpers that phylib and phylink can use to manage EEE configuration and determine whether the MAC should be permitted to use LPI based on that configuration. Signed-off-by: Russell King (Oracle) Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20240302195306.3207716-2-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- include/net/eee.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 include/net/eee.h diff --git a/include/net/eee.h b/include/net/eee.h new file mode 100644 index 000000000000..84837aba3cd9 --- /dev/null +++ b/include/net/eee.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _EEE_H +#define _EEE_H + +#include + +struct eee_config { + u32 tx_lpi_timer; + bool tx_lpi_enabled; + bool eee_enabled; +}; + +static inline bool eeecfg_mac_can_tx_lpi(const struct eee_config *eeecfg) +{ + /* eee_enabled is the master on/off */ + if (!eeecfg->eee_enabled || !eeecfg->tx_lpi_enabled) + return false; + + return true; +} + +static inline void eeecfg_to_eee(struct ethtool_keee *eee, + const struct eee_config *eeecfg) +{ + eee->tx_lpi_timer = eeecfg->tx_lpi_timer; + eee->tx_lpi_enabled = eeecfg->tx_lpi_enabled; + eee->eee_enabled = eeecfg->eee_enabled; +} + +static inline void eee_to_eeecfg(struct eee_config *eeecfg, + const struct ethtool_keee *eee) +{ + eeecfg->tx_lpi_timer = eee->tx_lpi_timer; + eeecfg->tx_lpi_enabled = eee->tx_lpi_enabled; + eeecfg->eee_enabled = eee->eee_enabled; +} + +#endif From e3b6876ab85061e7de198f023a0c2bfc7478b420 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 2 Mar 2024 20:53:01 +0100 Subject: [PATCH 1905/2255] net: phy: Add phydev->enable_tx_lpi to simplify adjust link callbacks MAC drivers which support EEE need to know the results of the EEE auto-neg in order to program the hardware to perform EEE or not. The oddly named phy_init_eee() can be used to determine this, it returns 0 if EEE should be used, or a negative error code, e.g. -EOPPROTONOTSUPPORT if the PHY does not support EEE or negotiate resulted in it not being used. However, many MAC drivers get this wrong. Add phydev->enable_tx_lpi which indicates the result of the autoneg for EEE, including if EEE is administratively disabled with ethtool. The MAC driver can then access this in the same way as link speed and duplex in the adjust link callback. If enable_tx_lpi is true, the MAC should send low power indications and does not need to consider anything else with respect to EEE. Reviewed-by: Florian Fainelli Signed-off-by: Andrew Lunn Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20240302195306.3207716-3-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy.c | 7 +++++++ include/linux/phy.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 14224e06d69f..2bc0a7d51c63 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -983,9 +983,16 @@ static int phy_check_link_status(struct phy_device *phydev) if (phydev->link && phydev->state != PHY_RUNNING) { phy_check_downshift(phydev); phydev->state = PHY_RUNNING; + err = genphy_c45_eee_is_active(phydev, + NULL, NULL, NULL); + if (err < 0) + phydev->enable_tx_lpi = false; + else + phydev->enable_tx_lpi = !!err; phy_link_up(phydev); } else if (!phydev->link && phydev->state != PHY_NOLINK) { phydev->state = PHY_NOLINK; + phydev->enable_tx_lpi = false; phy_link_down(phydev); } diff --git a/include/linux/phy.h b/include/linux/phy.h index e3ab2c347a59..a880f6d7170e 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -594,6 +594,7 @@ struct macsec_ops; * @supported_eee: supported PHY EEE linkmodes * @advertising_eee: Currently advertised EEE linkmodes * @eee_enabled: Flag indicating whether the EEE feature is enabled + * @enable_tx_lpi: When True, MAC should transmit LPI to PHY * @lp_advertising: Current link partner advertised linkmodes * @host_interfaces: PHY interface modes supported by host * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited @@ -713,6 +714,7 @@ struct phy_device { /* Energy efficient ethernet modes which should be prohibited */ u32 eee_broken_modes; + bool enable_tx_lpi; #ifdef CONFIG_LED_TRIGGER_PHY struct phy_led_trigger *phy_led_triggers; From fe0d4fd9285e5013b4bafbd3338847235b805a1c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 2 Mar 2024 20:53:02 +0100 Subject: [PATCH 1906/2255] net: phy: Keep track of EEE configuration Have phylib keep track of the EEE configuration. This simplifies the MAC drivers, in that they don't need to store it. Future patches to phylib will also make use of this information to further simplify the MAC drivers. Reviewed-by: Russell King (Oracle) Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20240302195306.3207716-4-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy.c | 7 +++++-- include/linux/phy.h | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 2bc0a7d51c63..95c4ef5d4e97 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1640,8 +1640,8 @@ EXPORT_SYMBOL(phy_get_eee_err); * @phydev: target phy_device struct * @data: ethtool_keee data * - * Description: it reportes the Supported/Advertisement/LP Advertisement - * capabilities. + * Description: reports the Supported/Advertisement/LP Advertisement + * capabilities, etc. */ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data) { @@ -1652,6 +1652,7 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data) mutex_lock(&phydev->lock); ret = genphy_c45_ethtool_get_eee(phydev, data); + eeecfg_to_eee(data, &phydev->eee_cfg); mutex_unlock(&phydev->lock); return ret; @@ -1674,6 +1675,8 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data) mutex_lock(&phydev->lock); ret = genphy_c45_ethtool_set_eee(phydev, data); + if (!ret) + eee_to_eeecfg(&phydev->eee_cfg, data); mutex_unlock(&phydev->lock); return ret; diff --git a/include/linux/phy.h b/include/linux/phy.h index a880f6d7170e..695e366bd75c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -30,6 +30,7 @@ #include #include +#include #define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \ SUPPORTED_TP | \ @@ -595,6 +596,7 @@ struct macsec_ops; * @advertising_eee: Currently advertised EEE linkmodes * @eee_enabled: Flag indicating whether the EEE feature is enabled * @enable_tx_lpi: When True, MAC should transmit LPI to PHY + * @eee_cfg: User configuration of EEE * @lp_advertising: Current link partner advertised linkmodes * @host_interfaces: PHY interface modes supported by host * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited @@ -715,6 +717,7 @@ struct phy_device { /* Energy efficient ethernet modes which should be prohibited */ u32 eee_broken_modes; bool enable_tx_lpi; + struct eee_config eee_cfg; #ifdef CONFIG_LED_TRIGGER_PHY struct phy_led_trigger *phy_led_triggers; From 3e43b903da04927f60894a603678f761c66d6e37 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 2 Mar 2024 20:53:03 +0100 Subject: [PATCH 1907/2255] net: phy: Immediately call adjust_link if only tx_lpi_enabled changes The MAC driver changes its EEE hardware configuration in its adjust_link callback. This is called when auto-neg completes. Disabling EEE via eee_enabled false will trigger an autoneg, and as a result the adjust_link callback will be called with phydev->enable_tx_lpi set to false. Similarly, eee_enabled set to true and with a change of advertised link modes will result in a new autoneg, and a call the adjust_link call. If set_eee is called with only a change to tx_lpi_enabled which does not trigger an auto-neg, it is necessary to call the adjust_link callback so that the MAC is reconfigured to take this change into account. When setting phydev->enable_tx_lpi, take both eee_enabled and tx_lpi_enabled into account, so the MAC drivers just needs to act on phydev->enable_tx_lpi and not the whole EEE configuration. The same check should be done for tx_lpi_timer too. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Oleksij Rempel Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20240302195306.3207716-5-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy-c45.c | 14 ++++++++++++-- drivers/net/phy/phy.c | 40 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 3e95b8a15f44..5695935fdce9 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1550,6 +1550,8 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee); * advertised, but the previously advertised link modes are * retained. This allows EEE to be enabled/disabled in a * non-destructive way. + * Returns either error code, 0 if there was no change, or positive + * value if there was a change which triggered auto-neg. */ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data) @@ -1576,8 +1578,16 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, phydev->eee_enabled = data->eee_enabled; ret = genphy_c45_an_config_eee_aneg(phydev); - if (ret > 0) - return phy_restart_aneg(phydev); + if (ret > 0) { + ret = phy_restart_aneg(phydev); + if (ret < 0) + return ret; + + /* explicitly return 1, otherwise (ret > 0) value will be + * overwritten by phy_restart_aneg(). + */ + return 1; + } return ret; } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 95c4ef5d4e97..c3a0a5ee5f11 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -988,7 +988,8 @@ static int phy_check_link_status(struct phy_device *phydev) if (err < 0) phydev->enable_tx_lpi = false; else - phydev->enable_tx_lpi = !!err; + phydev->enable_tx_lpi = (err & phydev->eee_cfg.tx_lpi_enabled); + phy_link_up(phydev); } else if (!phydev->link && phydev->state != PHY_NOLINK) { phydev->state = PHY_NOLINK; @@ -1659,6 +1660,36 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data) } EXPORT_SYMBOL(phy_ethtool_get_eee); +/** + * phy_ethtool_set_eee_noneg - Adjusts MAC LPI configuration without PHY + * renegotiation + * @phydev: pointer to the target PHY device structure + * @data: pointer to the ethtool_keee structure containing the new EEE settings + * + * This function updates the Energy Efficient Ethernet (EEE) configuration + * for cases where only the MAC's Low Power Idle (LPI) configuration changes, + * without triggering PHY renegotiation. It ensures that the MAC is properly + * informed of the new LPI settings by cycling the link down and up, which + * is necessary for the MAC to adopt the new configuration. This adjustment + * is done only if there is a change in the tx_lpi_enabled or tx_lpi_timer + * configuration. + */ +static void phy_ethtool_set_eee_noneg(struct phy_device *phydev, + struct ethtool_keee *data) +{ + if (phydev->eee_cfg.tx_lpi_enabled != data->tx_lpi_enabled || + phydev->eee_cfg.tx_lpi_timer != data->tx_lpi_timer) { + eee_to_eeecfg(&phydev->eee_cfg, data); + phydev->enable_tx_lpi = eeecfg_mac_can_tx_lpi(&phydev->eee_cfg); + if (phydev->link) { + phydev->link = false; + phy_link_down(phydev); + phydev->link = true; + phy_link_up(phydev); + } + } +} + /** * phy_ethtool_set_eee - set EEE supported and status * @phydev: target phy_device struct @@ -1675,11 +1706,14 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data) mutex_lock(&phydev->lock); ret = genphy_c45_ethtool_set_eee(phydev, data); - if (!ret) + if (ret >= 0) { + if (ret == 0) + phy_ethtool_set_eee_noneg(phydev, data); eee_to_eeecfg(&phydev->eee_cfg, data); + } mutex_unlock(&phydev->lock); - return ret; + return ret < 0 ? ret : 0; } EXPORT_SYMBOL(phy_ethtool_set_eee); From 49168d1980e220cf3d1b761e1eafac62041cb94d Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 2 Mar 2024 20:53:04 +0100 Subject: [PATCH 1908/2255] net: phy: Add phy_support_eee() indicating MAC support EEE In order for EEE to operate, both the MAC and the PHY need to support it, similar to how pause works. With some exception - a number of PHYs have SmartEEE or AutoGrEEEn support in order to provide some EEE-like power savings with non-EEE capable MACs. Copy the pause concept and add the call phy_support_eee() which the MAC makes after connecting the PHY to indicate it supports EEE. phylib will then advertise EEE when auto-neg is performed. Signed-off-by: Andrew Lunn Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20240302195306.3207716-6-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy_device.c | 28 ++++++++++++++++++++++++++++ include/linux/phy.h | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2eefee970851..72452e6a478c 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2910,6 +2910,34 @@ void phy_advertise_eee_all(struct phy_device *phydev) } EXPORT_SYMBOL_GPL(phy_advertise_eee_all); +/** + * phy_support_eee - Set initial EEE policy configuration + * @phydev: Target phy_device struct + * + * This function configures the initial policy for Energy Efficient Ethernet + * (EEE) on the specified PHY device, influencing that EEE capabilities are + * advertised before the link is established. It should be called during PHY + * registration by the MAC driver and/or the PHY driver (for SmartEEE PHYs) + * if MAC supports LPI or PHY is capable to compensate missing LPI functionality + * of the MAC. + * + * The function sets default EEE policy parameters, including preparing the PHY + * to advertise EEE capabilities based on hardware support. + * + * It also sets the expected configuration for Low Power Idle (LPI) in the MAC + * driver. If the PHY framework determines that both local and remote + * advertisements support EEE, and the negotiated link mode is compatible with + * EEE, it will set enable_tx_lpi = true. The MAC driver is expected to act on + * this setting by enabling the LPI timer if enable_tx_lpi is set. + */ +void phy_support_eee(struct phy_device *phydev) +{ + linkmode_copy(phydev->advertising_eee, phydev->supported_eee); + phydev->eee_cfg.tx_lpi_enabled = true; + phydev->eee_cfg.eee_enabled = true; +} +EXPORT_SYMBOL(phy_support_eee); + /** * phy_support_sym_pause - Enable support of symmetrical pause * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index 695e366bd75c..3f68b8239bb1 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -706,7 +706,7 @@ struct phy_device { __ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising); /* used with phy_speed_down */ __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); - /* used for eee validation */ + /* used for eee validation and configuration*/ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported_eee); __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising_eee); bool eee_enabled; @@ -1973,6 +1973,7 @@ void phy_advertise_supported(struct phy_device *phydev); void phy_advertise_eee_all(struct phy_device *phydev); void phy_support_sym_pause(struct phy_device *phydev); void phy_support_asym_pause(struct phy_device *phydev); +void phy_support_eee(struct phy_device *phydev); void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx, bool autoneg); void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx); From aff1b8c84b44894f305f94b1a7aa4fc1e773c614 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 2 Mar 2024 20:53:05 +0100 Subject: [PATCH 1909/2255] net: fec: Move fec_enet_eee_mode_set() and helper earlier FEC is about to get its EEE code re-written. To allow this, move fec_enet_eee_mode_set() before fec_enet_adjust_link() which will need to call it. Signed-off-by: Andrew Lunn Signed-off-by: Oleksij Rempel Reviewed-by: Wei Fang Link: https://lore.kernel.org/r/20240302195306.3207716-7-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fec_main.c | 75 ++++++++++++----------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 207f1f66c117..a2c786550342 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2017,6 +2017,44 @@ static int fec_get_mac(struct net_device *ndev) /* * Phy section */ + +/* LPI Sleep Ts count base on tx clk (clk_ref). + * The lpi sleep cnt value = X us / (cycle_ns). + */ +static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + return us * (fep->clk_ref_rate / 1000) / 1000; +} + +static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + struct ethtool_keee *p = &fep->eee; + unsigned int sleep_cycle, wake_cycle; + int ret = 0; + + if (enable) { + ret = phy_init_eee(ndev->phydev, false); + if (ret) + return ret; + + sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer); + wake_cycle = sleep_cycle; + } else { + sleep_cycle = 0; + wake_cycle = 0; + } + + p->tx_lpi_enabled = enable; + + writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP); + writel(wake_cycle, fep->hwp + FEC_LPI_WAKE); + + return 0; +} + static void fec_enet_adjust_link(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); @@ -3121,43 +3159,6 @@ static int fec_enet_set_coalesce(struct net_device *ndev, return 0; } -/* LPI Sleep Ts count base on tx clk (clk_ref). - * The lpi sleep cnt value = X us / (cycle_ns). - */ -static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us) -{ - struct fec_enet_private *fep = netdev_priv(ndev); - - return us * (fep->clk_ref_rate / 1000) / 1000; -} - -static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) -{ - struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_keee *p = &fep->eee; - unsigned int sleep_cycle, wake_cycle; - int ret = 0; - - if (enable) { - ret = phy_init_eee(ndev->phydev, false); - if (ret) - return ret; - - sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer); - wake_cycle = sleep_cycle; - } else { - sleep_cycle = 0; - wake_cycle = 0; - } - - p->tx_lpi_enabled = enable; - - writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP); - writel(wake_cycle, fep->hwp + FEC_LPI_WAKE); - - return 0; -} - static int fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { From 6a2495adc0c83d039a872b75d9d348a5dd3eb9f4 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 2 Mar 2024 20:53:06 +0100 Subject: [PATCH 1910/2255] net: fec: Fixup EEE The enabling/disabling of EEE in the MAC should happen as a result of auto negotiation. So move the enable/disable into fec_enet_adjust_link() which gets called by phylib when there is a change in link status. fec_enet_set_eee() now just stores away the LPI timer value. Everything else is passed to phylib, so it can correctly setup the PHY. fec_enet_get_eee() relies on phylib doing most of the work, the MAC driver just adds the LPI timer value. Call phy_support_eee() if the quirk is present to indicate the MAC actually supports EEE. Signed-off-by: Andrew Lunn Tested-by: Oleksij Rempel (On iMX8MP debix) Signed-off-by: Oleksij Rempel Reviewed-by: Wei Fang Link: https://lore.kernel.org/r/20240302195306.3207716-8-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fec_main.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index a2c786550342..d7693fdf640d 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2033,13 +2033,8 @@ static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) struct fec_enet_private *fep = netdev_priv(ndev); struct ethtool_keee *p = &fep->eee; unsigned int sleep_cycle, wake_cycle; - int ret = 0; if (enable) { - ret = phy_init_eee(ndev->phydev, false); - if (ret) - return ret; - sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer); wake_cycle = sleep_cycle; } else { @@ -2047,8 +2042,6 @@ static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) wake_cycle = 0; } - p->tx_lpi_enabled = enable; - writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP); writel(wake_cycle, fep->hwp + FEC_LPI_WAKE); @@ -2094,6 +2087,8 @@ static void fec_enet_adjust_link(struct net_device *ndev) netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); } + if (fep->quirks & FEC_QUIRK_HAS_EEE) + fec_enet_eee_mode_set(ndev, phy_dev->enable_tx_lpi); } else { if (fep->link) { netif_stop_queue(ndev); @@ -2453,6 +2448,9 @@ static int fec_enet_mii_probe(struct net_device *ndev) else phy_set_max_speed(phy_dev, 100); + if (fep->quirks & FEC_QUIRK_HAS_EEE) + phy_support_eee(phy_dev); + fep->link = 0; fep->full_duplex = 0; @@ -3172,7 +3170,6 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata) return -ENETDOWN; edata->tx_lpi_timer = p->tx_lpi_timer; - edata->tx_lpi_enabled = p->tx_lpi_enabled; return phy_ethtool_get_eee(ndev->phydev, edata); } @@ -3182,7 +3179,6 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct fec_enet_private *fep = netdev_priv(ndev); struct ethtool_keee *p = &fep->eee; - int ret = 0; if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) return -EOPNOTSUPP; @@ -3192,15 +3188,6 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata) p->tx_lpi_timer = edata->tx_lpi_timer; - if (!edata->eee_enabled || !edata->tx_lpi_enabled || - !edata->tx_lpi_timer) - ret = fec_enet_eee_mode_set(ndev, false); - else - ret = fec_enet_eee_mode_set(ndev, true); - - if (ret) - return ret; - return phy_ethtool_set_eee(ndev->phydev, edata); } From e3350ba4a5b7573d4e14ee1dff8c414646435a04 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 15:36:20 -0800 Subject: [PATCH 1911/2255] selftests: avoid using SKIP(exit()) in harness fixure setup selftest harness uses various exit codes to signal test results. Avoid calling exit() directly, otherwise tests may get broken by harness refactoring (like the commit under Fixes). SKIP() will instruct the harness that the test shouldn't run, it used to not be the case, but that has been fixed. So just return, no need to exit. Note that for hmm-tests this actually changes the result from pass to skip. Which seems fair, the test is skipped, after all. Reported-by: Mark Brown Link: https://lore.kernel.org/all/05f7bf89-04a5-4b65-bf59-c19456aeb1f0@sirena.org.uk Fixes: a724707976b0 ("selftests: kselftest_harness: use KSFT_* exit codes") Reviewed-by: Kees Cook Reviewed-by: Mark Brown Tested-by: Mark Brown Reviewed-by: Przemek Kitszel Link: https://lore.kernel.org/r/20240304233621.646054-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/alsa/test-pcmtest-driver.c | 4 ++-- tools/testing/selftests/mm/hmm-tests.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/alsa/test-pcmtest-driver.c b/tools/testing/selftests/alsa/test-pcmtest-driver.c index a52ecd43dbe3..ca81afa4ee90 100644 --- a/tools/testing/selftests/alsa/test-pcmtest-driver.c +++ b/tools/testing/selftests/alsa/test-pcmtest-driver.c @@ -127,11 +127,11 @@ FIXTURE_SETUP(pcmtest) { int err; if (geteuid()) - SKIP(exit(-1), "This test needs root to run!"); + SKIP(return, "This test needs root to run!"); err = read_patterns(); if (err) - SKIP(exit(-1), "Can't read patterns. Probably, module isn't loaded"); + SKIP(return, "Can't read patterns. Probably, module isn't loaded"); card_name = malloc(127); ASSERT_NE(card_name, NULL); diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c index 20294553a5dd..d2cfc9b494a0 100644 --- a/tools/testing/selftests/mm/hmm-tests.c +++ b/tools/testing/selftests/mm/hmm-tests.c @@ -138,7 +138,7 @@ FIXTURE_SETUP(hmm) self->fd = hmm_open(variant->device_number); if (self->fd < 0 && hmm_is_coherent_type(variant->device_number)) - SKIP(exit(0), "DEVICE_COHERENT not available"); + SKIP(return, "DEVICE_COHERENT not available"); ASSERT_GE(self->fd, 0); } @@ -149,7 +149,7 @@ FIXTURE_SETUP(hmm2) self->fd0 = hmm_open(variant->device_number0); if (self->fd0 < 0 && hmm_is_coherent_type(variant->device_number0)) - SKIP(exit(0), "DEVICE_COHERENT not available"); + SKIP(return, "DEVICE_COHERENT not available"); ASSERT_GE(self->fd0, 0); self->fd1 = hmm_open(variant->device_number1); ASSERT_GE(self->fd1, 0); From b5a899154aa94cc573db3ae1f61dabe7bfe8b579 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 2 Mar 2024 21:24:06 -0800 Subject: [PATCH 1912/2255] netlink: handle EMSGSIZE errors in the core Eric points out that our current suggested way of handling EMSGSIZE errors ((err == -EMSGSIZE) ? skb->len : err) will break if we didn't fit even a single object into the buffer provided by the user. This should not happen for well behaved applications, but we can fix that, and free netlink families from dealing with that completely by moving error handling into the core. Let's assume from now on that all EMSGSIZE errors in dumps are because we run out of skb space. Families can now propagate the error nla_put_*() etc generated and not worry about any return value magic. If some family really wants to send EMSGSIZE to user space, assuming it generates the same error on the next dump iteration the skb->len should be 0, and user space should still see the EMSGSIZE. This should simplify families and prevent mistakes in return values which lead to DONE being forced into a separate recv() call as discovered by Ido some time ago. Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index ad7b645e3ae7..da846212fb9b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2267,6 +2267,15 @@ static int netlink_dump(struct sock *sk, bool lock_taken) if (extra_mutex) mutex_unlock(extra_mutex); + /* EMSGSIZE plus something already in the skb means + * that there's more to dump but current skb has filled up. + * If the callback really wants to return EMSGSIZE to user space + * it needs to do so again, on the next cb->dump() call, + * without putting data in the skb. + */ + if (nlk->dump_done_errno == -EMSGSIZE && skb->len) + nlk->dump_done_errno = skb->len; + cb->extack = NULL; } From 0b11b1c5c320555483e8a94c44549db24c289987 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 2 Mar 2024 21:24:07 -0800 Subject: [PATCH 1913/2255] netdev: let netlink core handle -EMSGSIZE errors Previous change added -EMSGSIZE handling to af_netlink, we don't have to hide these errors any longer. Theoretically the error handling changes from: if (err == -EMSGSIZE) to if (err == -EMSGSIZE && skb->len) everywhere, but in practice it doesn't matter. All messages fit into NLMSG_GOODSIZE, so overflow of an empty skb cannot happen. Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- net/core/netdev-genl.c | 15 +++------------ net/core/page_pool_user.c | 2 -- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index fd98936da3ae..918b109e0cf4 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -152,10 +152,7 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } rtnl_unlock(); - if (err != -EMSGSIZE) - return err; - - return skb->len; + return err; } static int @@ -287,10 +284,7 @@ int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } rtnl_unlock(); - if (err != -EMSGSIZE) - return err; - - return skb->len; + return err; } static int @@ -463,10 +457,7 @@ int netdev_nl_queue_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } rtnl_unlock(); - if (err != -EMSGSIZE) - return err; - - return skb->len; + return err; } static int netdev_genl_netdevice_event(struct notifier_block *nb, diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index ffe5244e5597..53ad96f71b63 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -102,8 +102,6 @@ netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb, mutex_unlock(&page_pools_lock); rtnl_unlock(); - if (skb->len && err == -EMSGSIZE) - return skb->len; return err; } From 87d381973e49404f658d6923a617932eeda9415f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 2 Mar 2024 21:24:08 -0800 Subject: [PATCH 1914/2255] genetlink: fit NLMSG_DONE into same read() as families Make sure ctrl_fill_info() returns sensible error codes and propagate them out to netlink core. Let netlink core decide when to return skb->len and when to treat the exit as an error. Netlink core does better job at it, if we always return skb->len the core doesn't know when we're done dumping and NLMSG_DONE ends up in a separate read(). Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 50ec599a5cff..3b7666944b11 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1232,7 +1232,7 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq, hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd); if (hdr == NULL) - return -1; + return -EMSGSIZE; if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) || nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id) || @@ -1355,6 +1355,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) struct net *net = sock_net(skb->sk); int fams_to_skip = cb->args[0]; unsigned int id; + int err = 0; idr_for_each_entry(&genl_fam_idr, rt, id) { if (!rt->netnsok && !net_eq(net, &init_net)) @@ -1363,16 +1364,17 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) if (n++ < fams_to_skip) continue; - if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, - skb, CTRL_CMD_NEWFAMILY) < 0) { + err = ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + skb, CTRL_CMD_NEWFAMILY); + if (err) { n--; break; } } cb->args[0] = n; - return skb->len; + return err; } static struct sk_buff *ctrl_build_family_msg(const struct genl_family *family, From 4123c3fbf8632e5c553222bf1c10b3a3e0a8dc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 4 Mar 2024 12:08:53 +0100 Subject: [PATCH 1915/2255] ravb: Group descriptor types used in Rx ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rx ring can either be made up of normal or extended descriptors, not a mix of the two at the same time. Make this explicit by grouping the two variables in a rx_ring union. The extension of the storage for more than one queue of normal descriptors from a single to NUM_RX_QUEUE queues have no practical effect. But aids in making the code readable as the code that uses it already piggyback on other members of struct ravb_private that are arrays of max length NUM_RX_QUEUE, e.g. rx_desc_dma. This will also make further refactoring easier. While at it, rename the normal descriptor Rx ring to make it clear it's not strictly related to the GbEthernet E-MAC IP found in RZ/G2L, normal descriptors could be used on R-Car SoCs too. Signed-off-by: Niklas Söderlund Reviewed-by: Paul Barker Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 6 ++- drivers/net/ethernet/renesas/ravb_main.c | 57 ++++++++++++------------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 35e642fc4b2a..aecc98282c7e 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1092,8 +1092,10 @@ struct ravb_private { struct ravb_desc *desc_bat; dma_addr_t rx_desc_dma[NUM_RX_QUEUE]; dma_addr_t tx_desc_dma[NUM_TX_QUEUE]; - struct ravb_rx_desc *gbeth_rx_ring; - struct ravb_ex_rx_desc *rx_ring[NUM_RX_QUEUE]; + union { + struct ravb_rx_desc *desc; + struct ravb_ex_rx_desc *ex_desc; + } rx_ring[NUM_RX_QUEUE]; struct ravb_tx_desc *tx_ring[NUM_TX_QUEUE]; void *tx_align[NUM_TX_QUEUE]; struct sk_buff *rx_1st_skb; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index f9fb772b05c7..c25a80f4d3b9 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -241,11 +241,11 @@ static void ravb_rx_ring_free_gbeth(struct net_device *ndev, int q) unsigned int ring_size; unsigned int i; - if (!priv->gbeth_rx_ring) + if (!priv->rx_ring[q].desc) return; for (i = 0; i < priv->num_rx_ring[q]; i++) { - struct ravb_rx_desc *desc = &priv->gbeth_rx_ring[i]; + struct ravb_rx_desc *desc = &priv->rx_ring[q].desc[i]; if (!dma_mapping_error(ndev->dev.parent, le32_to_cpu(desc->dptr))) @@ -255,9 +255,9 @@ static void ravb_rx_ring_free_gbeth(struct net_device *ndev, int q) DMA_FROM_DEVICE); } ring_size = sizeof(struct ravb_rx_desc) * (priv->num_rx_ring[q] + 1); - dma_free_coherent(ndev->dev.parent, ring_size, priv->gbeth_rx_ring, + dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q].desc, priv->rx_desc_dma[q]); - priv->gbeth_rx_ring = NULL; + priv->rx_ring[q].desc = NULL; } static void ravb_rx_ring_free_rcar(struct net_device *ndev, int q) @@ -266,11 +266,11 @@ static void ravb_rx_ring_free_rcar(struct net_device *ndev, int q) unsigned int ring_size; unsigned int i; - if (!priv->rx_ring[q]) + if (!priv->rx_ring[q].ex_desc) return; for (i = 0; i < priv->num_rx_ring[q]; i++) { - struct ravb_ex_rx_desc *desc = &priv->rx_ring[q][i]; + struct ravb_ex_rx_desc *desc = &priv->rx_ring[q].ex_desc[i]; if (!dma_mapping_error(ndev->dev.parent, le32_to_cpu(desc->dptr))) @@ -281,9 +281,9 @@ static void ravb_rx_ring_free_rcar(struct net_device *ndev, int q) } ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1); - dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q], + dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q].ex_desc, priv->rx_desc_dma[q]); - priv->rx_ring[q] = NULL; + priv->rx_ring[q].ex_desc = NULL; } /* Free skb's and DMA buffers for Ethernet AVB */ @@ -335,11 +335,11 @@ static void ravb_rx_ring_format_gbeth(struct net_device *ndev, int q) unsigned int i; rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; - memset(priv->gbeth_rx_ring, 0, rx_ring_size); + memset(priv->rx_ring[q].desc, 0, rx_ring_size); /* Build RX ring buffer */ for (i = 0; i < priv->num_rx_ring[q]; i++) { /* RX descriptor */ - rx_desc = &priv->gbeth_rx_ring[i]; + rx_desc = &priv->rx_ring[q].desc[i]; rx_desc->ds_cc = cpu_to_le16(GBETH_RX_DESC_DATA_SIZE); dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, GBETH_RX_BUFF_MAX, @@ -352,7 +352,7 @@ static void ravb_rx_ring_format_gbeth(struct net_device *ndev, int q) rx_desc->dptr = cpu_to_le32(dma_addr); rx_desc->die_dt = DT_FEMPTY; } - rx_desc = &priv->gbeth_rx_ring[i]; + rx_desc = &priv->rx_ring[q].desc[i]; rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]); rx_desc->die_dt = DT_LINKFIX; /* type */ } @@ -365,11 +365,11 @@ static void ravb_rx_ring_format_rcar(struct net_device *ndev, int q) dma_addr_t dma_addr; unsigned int i; - memset(priv->rx_ring[q], 0, rx_ring_size); + memset(priv->rx_ring[q].ex_desc, 0, rx_ring_size); /* Build RX ring buffer */ for (i = 0; i < priv->num_rx_ring[q]; i++) { /* RX descriptor */ - rx_desc = &priv->rx_ring[q][i]; + rx_desc = &priv->rx_ring[q].ex_desc[i]; rx_desc->ds_cc = cpu_to_le16(RX_BUF_SZ); dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, RX_BUF_SZ, @@ -382,7 +382,7 @@ static void ravb_rx_ring_format_rcar(struct net_device *ndev, int q) rx_desc->dptr = cpu_to_le32(dma_addr); rx_desc->die_dt = DT_FEMPTY; } - rx_desc = &priv->rx_ring[q][i]; + rx_desc = &priv->rx_ring[q].ex_desc[i]; rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]); rx_desc->die_dt = DT_LINKFIX; /* type */ } @@ -437,10 +437,10 @@ static void *ravb_alloc_rx_desc_gbeth(struct net_device *ndev, int q) ring_size = sizeof(struct ravb_rx_desc) * (priv->num_rx_ring[q] + 1); - priv->gbeth_rx_ring = dma_alloc_coherent(ndev->dev.parent, ring_size, - &priv->rx_desc_dma[q], - GFP_KERNEL); - return priv->gbeth_rx_ring; + priv->rx_ring[q].desc = dma_alloc_coherent(ndev->dev.parent, ring_size, + &priv->rx_desc_dma[q], + GFP_KERNEL); + return priv->rx_ring[q].desc; } static void *ravb_alloc_rx_desc_rcar(struct net_device *ndev, int q) @@ -450,10 +450,11 @@ static void *ravb_alloc_rx_desc_rcar(struct net_device *ndev, int q) ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1); - priv->rx_ring[q] = dma_alloc_coherent(ndev->dev.parent, ring_size, - &priv->rx_desc_dma[q], - GFP_KERNEL); - return priv->rx_ring[q]; + priv->rx_ring[q].ex_desc = dma_alloc_coherent(ndev->dev.parent, + ring_size, + &priv->rx_desc_dma[q], + GFP_KERNEL); + return priv->rx_ring[q].ex_desc; } /* Init skb and descriptor buffer for Ethernet AVB */ @@ -830,7 +831,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) limit = priv->dirty_rx[q] + priv->num_rx_ring[q] - priv->cur_rx[q]; stats = &priv->stats[q]; - desc = &priv->gbeth_rx_ring[entry]; + desc = &priv->rx_ring[q].desc[entry]; for (i = 0; i < limit && rx_packets < *quota && desc->die_dt != DT_FEMPTY; i++) { /* Descriptor type must be checked before all other reads */ dma_rmb(); @@ -901,13 +902,13 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) } entry = (++priv->cur_rx[q]) % priv->num_rx_ring[q]; - desc = &priv->gbeth_rx_ring[entry]; + desc = &priv->rx_ring[q].desc[entry]; } /* Refill the RX ring buffers. */ for (; priv->cur_rx[q] - priv->dirty_rx[q] > 0; priv->dirty_rx[q]++) { entry = priv->dirty_rx[q] % priv->num_rx_ring[q]; - desc = &priv->gbeth_rx_ring[entry]; + desc = &priv->rx_ring[q].desc[entry]; desc->ds_cc = cpu_to_le16(GBETH_RX_DESC_DATA_SIZE); if (!priv->rx_skb[q][entry]) { @@ -957,7 +958,7 @@ static bool ravb_rx_rcar(struct net_device *ndev, int *quota, int q) boguscnt = min(boguscnt, *quota); limit = boguscnt; - desc = &priv->rx_ring[q][entry]; + desc = &priv->rx_ring[q].ex_desc[entry]; while (desc->die_dt != DT_FEMPTY) { /* Descriptor type must be checked before all other reads */ dma_rmb(); @@ -1017,13 +1018,13 @@ static bool ravb_rx_rcar(struct net_device *ndev, int *quota, int q) } entry = (++priv->cur_rx[q]) % priv->num_rx_ring[q]; - desc = &priv->rx_ring[q][entry]; + desc = &priv->rx_ring[q].ex_desc[entry]; } /* Refill the RX ring buffers. */ for (; priv->cur_rx[q] - priv->dirty_rx[q] > 0; priv->dirty_rx[q]++) { entry = priv->dirty_rx[q] % priv->num_rx_ring[q]; - desc = &priv->rx_ring[q][entry]; + desc = &priv->rx_ring[q].ex_desc[entry]; desc->ds_cc = cpu_to_le16(RX_BUF_SZ); if (!priv->rx_skb[q][entry]) { From e82700b8662ce5470ebefebc4dc40949f6b14627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 4 Mar 2024 12:08:54 +0100 Subject: [PATCH 1916/2255] ravb: Make it clear the information relates to maximum frame size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct member rx_max_buf_size was added before split descriptor support was added. It is unclear if the value describes the full skb frame buffer or the data descriptor buffer which can be combined into a single skb. Rename it to make it clear it referees to the maximum frame size and can cover multiple descriptors. Signed-off-by: Niklas Söderlund Reviewed-by: Paul Barker Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 2 +- drivers/net/ethernet/renesas/ravb_main.c | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index aecc98282c7e..7f9e8b2c012a 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1059,7 +1059,7 @@ struct ravb_hw_info { int stats_len; size_t max_rx_len; u32 tccr_mask; - u32 rx_max_buf_size; + u32 rx_max_frame_size; unsigned aligned_tx: 1; /* hardware features */ diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index c25a80f4d3b9..5c72b780d623 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2684,7 +2684,7 @@ static const struct ravb_hw_info ravb_gen3_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, - .rx_max_buf_size = SZ_2K, + .rx_max_frame_size = SZ_2K, .internal_delay = 1, .tx_counters = 1, .multi_irqs = 1, @@ -2710,7 +2710,7 @@ static const struct ravb_hw_info ravb_gen2_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, - .rx_max_buf_size = SZ_2K, + .rx_max_frame_size = SZ_2K, .aligned_tx = 1, .gptp = 1, .nc_queues = 1, @@ -2733,7 +2733,7 @@ static const struct ravb_hw_info ravb_rzv2m_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, - .rx_max_buf_size = SZ_2K, + .rx_max_frame_size = SZ_2K, .multi_irqs = 1, .err_mgmt_irqs = 1, .gptp = 1, @@ -2758,7 +2758,7 @@ static const struct ravb_hw_info gbeth_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats_gbeth), .max_rx_len = ALIGN(GBETH_RX_BUFF_MAX, RAVB_ALIGN), .tccr_mask = TCCR_TSRQ0, - .rx_max_buf_size = SZ_8K, + .rx_max_frame_size = SZ_8K, .aligned_tx = 1, .tx_counters = 1, .carrier_counters = 1, @@ -2967,7 +2967,8 @@ static int ravb_probe(struct platform_device *pdev) priv->avb_link_active_low = of_property_read_bool(np, "renesas,ether-link-active-low"); - ndev->max_mtu = info->rx_max_buf_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); + ndev->max_mtu = info->rx_max_frame_size - + (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); ndev->min_mtu = ETH_MIN_MTU; /* FIXME: R-Car Gen2 has 4byte alignment restriction for tx buffer From cfbad64706c1c9d555fba5dbb545967262bd9f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 4 Mar 2024 12:08:55 +0100 Subject: [PATCH 1917/2255] ravb: Create helper to allocate skb and align it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EtherAVB device requires the SKB data to be aligned to 128 bytes. The alignment is done by allocating an skb 128 bytes larger than the maximum frame size supported by the device and adjusting the headroom to fit the requirement. This code has been refactored a few times and small issues have been added along the way. The issues are not harmful but prevent merging parts of the Rx code which have been split in two implementations with the addition of RZ/G2L support, a device that supports larger frame sizes. This change removes the need for duplicated and somewhat inaccurate hardware alignment constrains stored in the hardware information struct by creating a helper to handle the allocation of an skb and alignment of an skb data. For the R-Car class of devices the maximum frame size is 4K and each descriptor is limited to 2K of data. The current implementation does not support split descriptors, this limits the frame size to 2K. The current hardware information however records the descriptor size just under 2K due to bad understanding of the device when larger MTUs where added. For the RZ/G2L device the maximum frame size is 8K and each descriptor is limited to 4K of data. The current hardware information records this correctly, but it gets the alignment constrains wrong as just aligns it by 128, it does not extend it by 128 bytes to allow the full frame to be stored. This works because the RZ/G2L device supports split descriptors and allocates each skb to 8K and aligns each 4K descriptor in this space. Signed-off-by: Niklas Söderlund Reviewed-by: Paul Barker Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 1 - drivers/net/ethernet/renesas/ravb_main.c | 43 +++++++++++++----------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 7f9e8b2c012a..751bb29cd488 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1057,7 +1057,6 @@ struct ravb_hw_info { netdev_features_t net_hw_features; netdev_features_t net_features; int stats_len; - size_t max_rx_len; u32 tccr_mask; u32 rx_max_frame_size; unsigned aligned_tx: 1; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 5c72b780d623..e6b025058847 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -113,12 +113,23 @@ static void ravb_set_rate_rcar(struct net_device *ndev) } } -static void ravb_set_buffer_align(struct sk_buff *skb) +static struct sk_buff * +ravb_alloc_skb(struct net_device *ndev, const struct ravb_hw_info *info, + gfp_t gfp_mask) { - u32 reserve = (unsigned long)skb->data & (RAVB_ALIGN - 1); + struct sk_buff *skb; + u32 reserve; + skb = __netdev_alloc_skb(ndev, info->rx_max_frame_size + RAVB_ALIGN - 1, + gfp_mask); + if (!skb) + return NULL; + + reserve = (unsigned long)skb->data & (RAVB_ALIGN - 1); if (reserve) skb_reserve(skb, RAVB_ALIGN - reserve); + + return skb; } /* Get MAC address from the MAC address registers @@ -251,7 +262,7 @@ static void ravb_rx_ring_free_gbeth(struct net_device *ndev, int q) le32_to_cpu(desc->dptr))) dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr), - GBETH_RX_BUFF_MAX, + priv->info->rx_max_frame_size, DMA_FROM_DEVICE); } ring_size = sizeof(struct ravb_rx_desc) * (priv->num_rx_ring[q] + 1); @@ -276,7 +287,7 @@ static void ravb_rx_ring_free_rcar(struct net_device *ndev, int q) le32_to_cpu(desc->dptr))) dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr), - RX_BUF_SZ, + priv->info->rx_max_frame_size, DMA_FROM_DEVICE); } ring_size = sizeof(struct ravb_ex_rx_desc) * @@ -342,7 +353,7 @@ static void ravb_rx_ring_format_gbeth(struct net_device *ndev, int q) rx_desc = &priv->rx_ring[q].desc[i]; rx_desc->ds_cc = cpu_to_le16(GBETH_RX_DESC_DATA_SIZE); dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, - GBETH_RX_BUFF_MAX, + priv->info->rx_max_frame_size, DMA_FROM_DEVICE); /* We just set the data size to 0 for a failed mapping which * should prevent DMA from happening... @@ -372,7 +383,7 @@ static void ravb_rx_ring_format_rcar(struct net_device *ndev, int q) rx_desc = &priv->rx_ring[q].ex_desc[i]; rx_desc->ds_cc = cpu_to_le16(RX_BUF_SZ); dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, - RX_BUF_SZ, + priv->info->rx_max_frame_size, DMA_FROM_DEVICE); /* We just set the data size to 0 for a failed mapping which * should prevent DMA from happening... @@ -476,10 +487,9 @@ static int ravb_ring_init(struct net_device *ndev, int q) goto error; for (i = 0; i < priv->num_rx_ring[q]; i++) { - skb = __netdev_alloc_skb(ndev, info->max_rx_len, GFP_KERNEL); + skb = ravb_alloc_skb(ndev, info, GFP_KERNEL); if (!skb) goto error; - ravb_set_buffer_align(skb); priv->rx_skb[q][i] = skb; } @@ -805,7 +815,8 @@ static struct sk_buff *ravb_get_skb_gbeth(struct net_device *ndev, int entry, skb = priv->rx_skb[RAVB_BE][entry]; priv->rx_skb[RAVB_BE][entry] = NULL; dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr), - ALIGN(GBETH_RX_BUFF_MAX, 16), DMA_FROM_DEVICE); + ALIGN(priv->info->rx_max_frame_size, 16), + DMA_FROM_DEVICE); return skb; } @@ -912,13 +923,12 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) desc->ds_cc = cpu_to_le16(GBETH_RX_DESC_DATA_SIZE); if (!priv->rx_skb[q][entry]) { - skb = netdev_alloc_skb(ndev, info->max_rx_len); + skb = ravb_alloc_skb(ndev, info, GFP_ATOMIC); if (!skb) break; - ravb_set_buffer_align(skb); dma_addr = dma_map_single(ndev->dev.parent, skb->data, - GBETH_RX_BUFF_MAX, + priv->info->rx_max_frame_size, DMA_FROM_DEVICE); skb_checksum_none_assert(skb); /* We just set the data size to 0 for a failed mapping @@ -992,7 +1002,7 @@ static bool ravb_rx_rcar(struct net_device *ndev, int *quota, int q) skb = priv->rx_skb[q][entry]; priv->rx_skb[q][entry] = NULL; dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr), - RX_BUF_SZ, + priv->info->rx_max_frame_size, DMA_FROM_DEVICE); get_ts &= (q == RAVB_NC) ? RAVB_RXTSTAMP_TYPE_V2_L2_EVENT : @@ -1028,10 +1038,9 @@ static bool ravb_rx_rcar(struct net_device *ndev, int *quota, int q) desc->ds_cc = cpu_to_le16(RX_BUF_SZ); if (!priv->rx_skb[q][entry]) { - skb = netdev_alloc_skb(ndev, info->max_rx_len); + skb = ravb_alloc_skb(ndev, info, GFP_ATOMIC); if (!skb) break; /* Better luck next round. */ - ravb_set_buffer_align(skb); dma_addr = dma_map_single(ndev->dev.parent, skb->data, le16_to_cpu(desc->ds_cc), DMA_FROM_DEVICE); @@ -2682,7 +2691,6 @@ static const struct ravb_hw_info ravb_gen3_hw_info = { .net_hw_features = NETIF_F_RXCSUM, .net_features = NETIF_F_RXCSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats), - .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, .internal_delay = 1, @@ -2708,7 +2716,6 @@ static const struct ravb_hw_info ravb_gen2_hw_info = { .net_hw_features = NETIF_F_RXCSUM, .net_features = NETIF_F_RXCSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats), - .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, .aligned_tx = 1, @@ -2731,7 +2738,6 @@ static const struct ravb_hw_info ravb_rzv2m_hw_info = { .net_hw_features = NETIF_F_RXCSUM, .net_features = NETIF_F_RXCSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats), - .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, .multi_irqs = 1, @@ -2756,7 +2762,6 @@ static const struct ravb_hw_info gbeth_hw_info = { .net_hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM, .net_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats_gbeth), - .max_rx_len = ALIGN(GBETH_RX_BUFF_MAX, RAVB_ALIGN), .tccr_mask = TCCR_TSRQ0, .rx_max_frame_size = SZ_8K, .aligned_tx = 1, From 496863388136bcba95298ab7dacaf55489af2b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 4 Mar 2024 12:08:56 +0100 Subject: [PATCH 1918/2255] ravb: Use the max frame size from hardware info for RZ/G2L MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the define describing the RZ/G2L maximum frame size and only use the information in the hardware information struct. This will make it easier to merge the R-Car and RZ/G2L code paths. There is no functional change as both the define and the maximum frame length in the hardware information is set to 8K. Signed-off-by: Niklas Söderlund Reviewed-by: Paul Barker Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 1 - drivers/net/ethernet/renesas/ravb_main.c | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 751bb29cd488..7fa60fccb6ea 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1017,7 +1017,6 @@ enum CSR2_BIT { #define RX_BUF_SZ (2048 - ETH_FCS_LEN + sizeof(__sum16)) -#define GBETH_RX_BUFF_MAX 8192 #define GBETH_RX_DESC_DATA_SIZE 4080 struct ravb_tstamp_skb { diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index e6b025058847..45383635e8e2 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -568,7 +568,7 @@ static void ravb_emac_init_gbeth(struct net_device *ndev) } /* Receive frame limit set register */ - ravb_write(ndev, GBETH_RX_BUFF_MAX + ETH_FCS_LEN, RFLR); + ravb_write(ndev, priv->info->rx_max_frame_size + ETH_FCS_LEN, RFLR); /* EMAC Mode: PAUSE prohibition; Duplex; TX; RX; CRC Pass Through */ ravb_write(ndev, ECMR_ZPF | ((priv->duplex > 0) ? ECMR_DM : 0) | @@ -629,6 +629,7 @@ static void ravb_emac_init(struct net_device *ndev) static int ravb_dmac_init_gbeth(struct net_device *ndev) { + struct ravb_private *priv = netdev_priv(ndev); int error; error = ravb_ring_init(ndev, RAVB_BE); @@ -642,7 +643,7 @@ static int ravb_dmac_init_gbeth(struct net_device *ndev) ravb_write(ndev, 0x60000000, RCR); /* Set Max Frame Length (RTC) */ - ravb_write(ndev, 0x7ffc0000 | GBETH_RX_BUFF_MAX, RTC); + ravb_write(ndev, 0x7ffc0000 | priv->info->rx_max_frame_size, RTC); /* Set FIFO size */ ravb_write(ndev, 0x00222200, TGC); From 555419b2259b96b5259ea207a6b6d2e45c2d6eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 4 Mar 2024 12:08:57 +0100 Subject: [PATCH 1919/2255] ravb: Move maximum Rx descriptor data usage to info struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make it possible to merge the R-Car and RZ/G2L code paths move the maximum usable size of a single Rx descriptor data slice into the hardware information instead of using two different defines in the two different code paths. Signed-off-by: Niklas Söderlund Reviewed-by: Paul Barker Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 5 +---- drivers/net/ethernet/renesas/ravb_main.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 7fa60fccb6ea..b12b379baf5a 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1015,10 +1015,6 @@ enum CSR2_BIT { #define NUM_RX_QUEUE 2 #define NUM_TX_QUEUE 2 -#define RX_BUF_SZ (2048 - ETH_FCS_LEN + sizeof(__sum16)) - -#define GBETH_RX_DESC_DATA_SIZE 4080 - struct ravb_tstamp_skb { struct list_head list; struct sk_buff *skb; @@ -1058,6 +1054,7 @@ struct ravb_hw_info { int stats_len; u32 tccr_mask; u32 rx_max_frame_size; + u32 rx_max_desc_use; unsigned aligned_tx: 1; /* hardware features */ diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 45383635e8e2..4ef4be9e152e 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -351,7 +351,7 @@ static void ravb_rx_ring_format_gbeth(struct net_device *ndev, int q) for (i = 0; i < priv->num_rx_ring[q]; i++) { /* RX descriptor */ rx_desc = &priv->rx_ring[q].desc[i]; - rx_desc->ds_cc = cpu_to_le16(GBETH_RX_DESC_DATA_SIZE); + rx_desc->ds_cc = cpu_to_le16(priv->info->rx_max_desc_use); dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, priv->info->rx_max_frame_size, DMA_FROM_DEVICE); @@ -381,7 +381,7 @@ static void ravb_rx_ring_format_rcar(struct net_device *ndev, int q) for (i = 0; i < priv->num_rx_ring[q]; i++) { /* RX descriptor */ rx_desc = &priv->rx_ring[q].ex_desc[i]; - rx_desc->ds_cc = cpu_to_le16(RX_BUF_SZ); + rx_desc->ds_cc = cpu_to_le16(priv->info->rx_max_desc_use); dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, priv->info->rx_max_frame_size, DMA_FROM_DEVICE); @@ -921,7 +921,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) for (; priv->cur_rx[q] - priv->dirty_rx[q] > 0; priv->dirty_rx[q]++) { entry = priv->dirty_rx[q] % priv->num_rx_ring[q]; desc = &priv->rx_ring[q].desc[entry]; - desc->ds_cc = cpu_to_le16(GBETH_RX_DESC_DATA_SIZE); + desc->ds_cc = cpu_to_le16(priv->info->rx_max_desc_use); if (!priv->rx_skb[q][entry]) { skb = ravb_alloc_skb(ndev, info, GFP_ATOMIC); @@ -1036,7 +1036,7 @@ static bool ravb_rx_rcar(struct net_device *ndev, int *quota, int q) for (; priv->cur_rx[q] - priv->dirty_rx[q] > 0; priv->dirty_rx[q]++) { entry = priv->dirty_rx[q] % priv->num_rx_ring[q]; desc = &priv->rx_ring[q].ex_desc[entry]; - desc->ds_cc = cpu_to_le16(RX_BUF_SZ); + desc->ds_cc = cpu_to_le16(priv->info->rx_max_desc_use); if (!priv->rx_skb[q][entry]) { skb = ravb_alloc_skb(ndev, info, GFP_ATOMIC); @@ -2694,6 +2694,7 @@ static const struct ravb_hw_info ravb_gen3_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, + .rx_max_desc_use = SZ_2K - ETH_FCS_LEN + sizeof(__sum16), .internal_delay = 1, .tx_counters = 1, .multi_irqs = 1, @@ -2719,6 +2720,7 @@ static const struct ravb_hw_info ravb_gen2_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, + .rx_max_desc_use = SZ_2K - ETH_FCS_LEN + sizeof(__sum16), .aligned_tx = 1, .gptp = 1, .nc_queues = 1, @@ -2741,6 +2743,7 @@ static const struct ravb_hw_info ravb_rzv2m_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, + .rx_max_desc_use = SZ_2K - ETH_FCS_LEN + sizeof(__sum16), .multi_irqs = 1, .err_mgmt_irqs = 1, .gptp = 1, @@ -2765,6 +2768,7 @@ static const struct ravb_hw_info gbeth_hw_info = { .stats_len = ARRAY_SIZE(ravb_gstrings_stats_gbeth), .tccr_mask = TCCR_TSRQ0, .rx_max_frame_size = SZ_8K, + .rx_max_desc_use = 4080, .aligned_tx = 1, .tx_counters = 1, .carrier_counters = 1, From 644d037b2c44692cf81a27b79f9824ae0a8055b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 4 Mar 2024 12:08:58 +0100 Subject: [PATCH 1920/2255] ravb: Unify Rx ring maintenance code paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The R-Car and RZ/G2L Rx code paths were split in two separate implementations when support for RZ/G2L was added due to the fact that R-Car uses the extended descriptor format while RZ/G2L uses normal descriptors. This has led to a duplication of Rx logic with the only difference being the different Rx descriptors types used. The implementation however neglects to take into account that extended descriptors are normal descriptors with additional metadata at the end to carry hardware timestamp information. The hardware timestamp information is only consumed in the R-Car Rx loop and all the maintenance code around the Rx ring can be shared between the two implementations if the difference in descriptor length is carefully considered. This change merges the two implementations for Rx ring maintenance by adding a method to access both types of descriptors as normal descriptors, as this part covers all the fields needed for Rx ring maintenance the only difference between using normal or extended descriptor is the size of the memory region to allocate/free and the step size between each descriptor in the ring. Signed-off-by: Niklas Söderlund Reviewed-by: Paul Barker Reviewed-by: Sergey Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 5 +- drivers/net/ethernet/renesas/ravb_main.c | 134 ++++++----------------- 2 files changed, 33 insertions(+), 106 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index b12b379baf5a..b48935ec7e28 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1039,9 +1039,6 @@ struct ravb_ptp { }; struct ravb_hw_info { - void (*rx_ring_free)(struct net_device *ndev, int q); - void (*rx_ring_format)(struct net_device *ndev, int q); - void *(*alloc_rx_desc)(struct net_device *ndev, int q); bool (*receive)(struct net_device *ndev, int *quota, int q); void (*set_rate)(struct net_device *ndev); int (*set_feature)(struct net_device *ndev, netdev_features_t features); @@ -1055,6 +1052,7 @@ struct ravb_hw_info { u32 tccr_mask; u32 rx_max_frame_size; u32 rx_max_desc_use; + u32 rx_desc_size; unsigned aligned_tx: 1; /* hardware features */ @@ -1090,6 +1088,7 @@ struct ravb_private { union { struct ravb_rx_desc *desc; struct ravb_ex_rx_desc *ex_desc; + void *raw; } rx_ring[NUM_RX_QUEUE]; struct ravb_tx_desc *tx_ring[NUM_TX_QUEUE]; void *tx_align[NUM_TX_QUEUE]; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 4ef4be9e152e..fa48ff4aba2d 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -202,6 +202,13 @@ static const struct mdiobb_ops bb_ops = { .get_mdio_data = ravb_get_mdio_data, }; +static struct ravb_rx_desc * +ravb_rx_get_desc(struct ravb_private *priv, unsigned int q, + unsigned int i) +{ + return priv->rx_ring[q].raw + priv->info->rx_desc_size * i; +} + /* Free TX skb function for AVB-IP */ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) { @@ -246,17 +253,17 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) return free_num; } -static void ravb_rx_ring_free_gbeth(struct net_device *ndev, int q) +static void ravb_rx_ring_free(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); unsigned int ring_size; unsigned int i; - if (!priv->rx_ring[q].desc) + if (!priv->rx_ring[q].raw) return; for (i = 0; i < priv->num_rx_ring[q]; i++) { - struct ravb_rx_desc *desc = &priv->rx_ring[q].desc[i]; + struct ravb_rx_desc *desc = ravb_rx_get_desc(priv, q, i); if (!dma_mapping_error(ndev->dev.parent, le32_to_cpu(desc->dptr))) @@ -265,48 +272,21 @@ static void ravb_rx_ring_free_gbeth(struct net_device *ndev, int q) priv->info->rx_max_frame_size, DMA_FROM_DEVICE); } - ring_size = sizeof(struct ravb_rx_desc) * (priv->num_rx_ring[q] + 1); - dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q].desc, + ring_size = priv->info->rx_desc_size * (priv->num_rx_ring[q] + 1); + dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q].raw, priv->rx_desc_dma[q]); - priv->rx_ring[q].desc = NULL; -} - -static void ravb_rx_ring_free_rcar(struct net_device *ndev, int q) -{ - struct ravb_private *priv = netdev_priv(ndev); - unsigned int ring_size; - unsigned int i; - - if (!priv->rx_ring[q].ex_desc) - return; - - for (i = 0; i < priv->num_rx_ring[q]; i++) { - struct ravb_ex_rx_desc *desc = &priv->rx_ring[q].ex_desc[i]; - - if (!dma_mapping_error(ndev->dev.parent, - le32_to_cpu(desc->dptr))) - dma_unmap_single(ndev->dev.parent, - le32_to_cpu(desc->dptr), - priv->info->rx_max_frame_size, - DMA_FROM_DEVICE); - } - ring_size = sizeof(struct ravb_ex_rx_desc) * - (priv->num_rx_ring[q] + 1); - dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q].ex_desc, - priv->rx_desc_dma[q]); - priv->rx_ring[q].ex_desc = NULL; + priv->rx_ring[q].raw = NULL; } /* Free skb's and DMA buffers for Ethernet AVB */ static void ravb_ring_free(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); - const struct ravb_hw_info *info = priv->info; unsigned int num_tx_desc = priv->num_tx_desc; unsigned int ring_size; unsigned int i; - info->rx_ring_free(ndev, q); + ravb_rx_ring_free(ndev, q); if (priv->tx_ring[q]) { ravb_tx_free(ndev, q, false); @@ -337,7 +317,7 @@ static void ravb_ring_free(struct net_device *ndev, int q) priv->tx_skb[q] = NULL; } -static void ravb_rx_ring_format_gbeth(struct net_device *ndev, int q) +static void ravb_rx_ring_format(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); struct ravb_rx_desc *rx_desc; @@ -345,12 +325,12 @@ static void ravb_rx_ring_format_gbeth(struct net_device *ndev, int q) dma_addr_t dma_addr; unsigned int i; - rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; - memset(priv->rx_ring[q].desc, 0, rx_ring_size); + rx_ring_size = priv->info->rx_desc_size * priv->num_rx_ring[q]; + memset(priv->rx_ring[q].raw, 0, rx_ring_size); /* Build RX ring buffer */ for (i = 0; i < priv->num_rx_ring[q]; i++) { /* RX descriptor */ - rx_desc = &priv->rx_ring[q].desc[i]; + rx_desc = ravb_rx_get_desc(priv, q, i); rx_desc->ds_cc = cpu_to_le16(priv->info->rx_max_desc_use); dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, priv->info->rx_max_frame_size, @@ -363,37 +343,7 @@ static void ravb_rx_ring_format_gbeth(struct net_device *ndev, int q) rx_desc->dptr = cpu_to_le32(dma_addr); rx_desc->die_dt = DT_FEMPTY; } - rx_desc = &priv->rx_ring[q].desc[i]; - rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]); - rx_desc->die_dt = DT_LINKFIX; /* type */ -} - -static void ravb_rx_ring_format_rcar(struct net_device *ndev, int q) -{ - struct ravb_private *priv = netdev_priv(ndev); - struct ravb_ex_rx_desc *rx_desc; - unsigned int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; - dma_addr_t dma_addr; - unsigned int i; - - memset(priv->rx_ring[q].ex_desc, 0, rx_ring_size); - /* Build RX ring buffer */ - for (i = 0; i < priv->num_rx_ring[q]; i++) { - /* RX descriptor */ - rx_desc = &priv->rx_ring[q].ex_desc[i]; - rx_desc->ds_cc = cpu_to_le16(priv->info->rx_max_desc_use); - dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data, - priv->info->rx_max_frame_size, - DMA_FROM_DEVICE); - /* We just set the data size to 0 for a failed mapping which - * should prevent DMA from happening... - */ - if (dma_mapping_error(ndev->dev.parent, dma_addr)) - rx_desc->ds_cc = cpu_to_le16(0); - rx_desc->dptr = cpu_to_le32(dma_addr); - rx_desc->die_dt = DT_FEMPTY; - } - rx_desc = &priv->rx_ring[q].ex_desc[i]; + rx_desc = ravb_rx_get_desc(priv, q, i); rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]); rx_desc->die_dt = DT_LINKFIX; /* type */ } @@ -402,7 +352,6 @@ static void ravb_rx_ring_format_rcar(struct net_device *ndev, int q) static void ravb_ring_format(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); - const struct ravb_hw_info *info = priv->info; unsigned int num_tx_desc = priv->num_tx_desc; struct ravb_tx_desc *tx_desc; struct ravb_desc *desc; @@ -415,7 +364,7 @@ static void ravb_ring_format(struct net_device *ndev, int q) priv->dirty_rx[q] = 0; priv->dirty_tx[q] = 0; - info->rx_ring_format(ndev, q); + ravb_rx_ring_format(ndev, q); memset(priv->tx_ring[q], 0, tx_ring_size); /* Build TX ring buffer */ @@ -441,31 +390,18 @@ static void ravb_ring_format(struct net_device *ndev, int q) desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]); } -static void *ravb_alloc_rx_desc_gbeth(struct net_device *ndev, int q) +static void *ravb_alloc_rx_desc(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); unsigned int ring_size; - ring_size = sizeof(struct ravb_rx_desc) * (priv->num_rx_ring[q] + 1); + ring_size = priv->info->rx_desc_size * (priv->num_rx_ring[q] + 1); - priv->rx_ring[q].desc = dma_alloc_coherent(ndev->dev.parent, ring_size, - &priv->rx_desc_dma[q], - GFP_KERNEL); - return priv->rx_ring[q].desc; -} + priv->rx_ring[q].raw = dma_alloc_coherent(ndev->dev.parent, ring_size, + &priv->rx_desc_dma[q], + GFP_KERNEL); -static void *ravb_alloc_rx_desc_rcar(struct net_device *ndev, int q) -{ - struct ravb_private *priv = netdev_priv(ndev); - unsigned int ring_size; - - ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1); - - priv->rx_ring[q].ex_desc = dma_alloc_coherent(ndev->dev.parent, - ring_size, - &priv->rx_desc_dma[q], - GFP_KERNEL); - return priv->rx_ring[q].ex_desc; + return priv->rx_ring[q].raw; } /* Init skb and descriptor buffer for Ethernet AVB */ @@ -502,7 +438,7 @@ static int ravb_ring_init(struct net_device *ndev, int q) } /* Allocate all RX descriptors. */ - if (!info->alloc_rx_desc(ndev, q)) + if (!ravb_alloc_rx_desc(ndev, q)) goto error; priv->dirty_rx[q] = 0; @@ -2679,9 +2615,6 @@ static int ravb_mdio_release(struct ravb_private *priv) } static const struct ravb_hw_info ravb_gen3_hw_info = { - .rx_ring_free = ravb_rx_ring_free_rcar, - .rx_ring_format = ravb_rx_ring_format_rcar, - .alloc_rx_desc = ravb_alloc_rx_desc_rcar, .receive = ravb_rx_rcar, .set_rate = ravb_set_rate_rcar, .set_feature = ravb_set_features_rcar, @@ -2695,6 +2628,7 @@ static const struct ravb_hw_info ravb_gen3_hw_info = { .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, .rx_max_desc_use = SZ_2K - ETH_FCS_LEN + sizeof(__sum16), + .rx_desc_size = sizeof(struct ravb_ex_rx_desc), .internal_delay = 1, .tx_counters = 1, .multi_irqs = 1, @@ -2705,9 +2639,6 @@ static const struct ravb_hw_info ravb_gen3_hw_info = { }; static const struct ravb_hw_info ravb_gen2_hw_info = { - .rx_ring_free = ravb_rx_ring_free_rcar, - .rx_ring_format = ravb_rx_ring_format_rcar, - .alloc_rx_desc = ravb_alloc_rx_desc_rcar, .receive = ravb_rx_rcar, .set_rate = ravb_set_rate_rcar, .set_feature = ravb_set_features_rcar, @@ -2721,6 +2652,7 @@ static const struct ravb_hw_info ravb_gen2_hw_info = { .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, .rx_max_desc_use = SZ_2K - ETH_FCS_LEN + sizeof(__sum16), + .rx_desc_size = sizeof(struct ravb_ex_rx_desc), .aligned_tx = 1, .gptp = 1, .nc_queues = 1, @@ -2728,9 +2660,6 @@ static const struct ravb_hw_info ravb_gen2_hw_info = { }; static const struct ravb_hw_info ravb_rzv2m_hw_info = { - .rx_ring_free = ravb_rx_ring_free_rcar, - .rx_ring_format = ravb_rx_ring_format_rcar, - .alloc_rx_desc = ravb_alloc_rx_desc_rcar, .receive = ravb_rx_rcar, .set_rate = ravb_set_rate_rcar, .set_feature = ravb_set_features_rcar, @@ -2744,6 +2673,7 @@ static const struct ravb_hw_info ravb_rzv2m_hw_info = { .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, .rx_max_frame_size = SZ_2K, .rx_max_desc_use = SZ_2K - ETH_FCS_LEN + sizeof(__sum16), + .rx_desc_size = sizeof(struct ravb_ex_rx_desc), .multi_irqs = 1, .err_mgmt_irqs = 1, .gptp = 1, @@ -2753,9 +2683,6 @@ static const struct ravb_hw_info ravb_rzv2m_hw_info = { }; static const struct ravb_hw_info gbeth_hw_info = { - .rx_ring_free = ravb_rx_ring_free_gbeth, - .rx_ring_format = ravb_rx_ring_format_gbeth, - .alloc_rx_desc = ravb_alloc_rx_desc_gbeth, .receive = ravb_rx_gbeth, .set_rate = ravb_set_rate_gbeth, .set_feature = ravb_set_features_gbeth, @@ -2769,6 +2696,7 @@ static const struct ravb_hw_info gbeth_hw_info = { .tccr_mask = TCCR_TSRQ0, .rx_max_frame_size = SZ_8K, .rx_max_desc_use = 4080, + .rx_desc_size = sizeof(struct ravb_rx_desc), .aligned_tx = 1, .tx_counters = 1, .carrier_counters = 1, From 4e887471e8e3a513607495d18333c44f59a82c5a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:13:26 -0800 Subject: [PATCH 1921/2255] tools: ynl: rename make hardclean -> distclean The make target to remove all generated files used to be called "hardclean" because it deleted files which were tracked by git. We no longer track generated user space files, so use the more common "distclean" name. Signed-off-by: Jakub Kicinski Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- tools/net/ynl/Makefile | 2 +- tools/net/ynl/generated/Makefile | 4 ++-- tools/net/ynl/lib/Makefile | 2 +- tools/net/ynl/samples/Makefile | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile index da1aa10bbcc3..1874296665e1 100644 --- a/tools/net/ynl/Makefile +++ b/tools/net/ynl/Makefile @@ -11,7 +11,7 @@ $(SUBDIRS): $(MAKE) -C $@ ; \ fi -clean hardclean: +clean distclean: @for dir in $(SUBDIRS) ; do \ if [ -f "$$dir/Makefile" ] ; then \ $(MAKE) -C $$dir $@; \ diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 7135028cb449..713f5fb9cc2d 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -43,11 +43,11 @@ protos.a: $(OBJS) clean: rm -f *.o -hardclean: clean +distclean: clean rm -f *.c *.h *.a regen: @../ynl-regen.sh -.PHONY: all clean hardclean regen +.PHONY: all clean distclean regen .DEFAULT_GOAL: all diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile index d2e50fd0a52d..2201dafc62b3 100644 --- a/tools/net/ynl/lib/Makefile +++ b/tools/net/ynl/lib/Makefile @@ -18,7 +18,7 @@ ynl.a: $(OBJS) clean: rm -f *.o *.d *~ -hardclean: clean +distclean: clean rm -f *.a %.o: %.c diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index 1d33e98e3ffe..3e81432f7b27 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -28,7 +28,7 @@ $(BINS): ../lib/ynl.a ../generated/protos.a $(SRCS) clean: rm -f *.o *.d *~ -hardclean: clean +distclean: clean rm -f $(BINS) .PHONY: all clean From 1d8617b2a610f36e361a91846725c065dc233541 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:13:27 -0800 Subject: [PATCH 1922/2255] tools: ynl: add distclean to .PHONY in all makefiles Donald points out most YNL makefiles are missing distclean in .PHONY, even tho generated/Makefile does list it. Suggested-by: Donald Hunter Signed-off-by: Jakub Kicinski Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- tools/net/ynl/Makefile | 2 +- tools/net/ynl/lib/Makefile | 2 +- tools/net/ynl/samples/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile index 1874296665e1..8e9e09d84e26 100644 --- a/tools/net/ynl/Makefile +++ b/tools/net/ynl/Makefile @@ -18,4 +18,4 @@ clean distclean: fi \ done -.PHONY: clean all $(SUBDIRS) +.PHONY: all clean distclean $(SUBDIRS) diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile index 2201dafc62b3..1507833d05c5 100644 --- a/tools/net/ynl/lib/Makefile +++ b/tools/net/ynl/lib/Makefile @@ -24,5 +24,5 @@ distclean: clean %.o: %.c $(COMPILE.c) -MMD -c -o $@ $< -.PHONY: all clean +.PHONY: all clean distclean .DEFAULT_GOAL=all diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index 3e81432f7b27..e194a7565861 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -31,5 +31,5 @@ clean: distclean: clean rm -f $(BINS) -.PHONY: all clean +.PHONY: all clean distclean .DEFAULT_GOAL=all From 72fa191bfdf611e5362e71d4cacae26c4c8d302c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:13:28 -0800 Subject: [PATCH 1923/2255] tools: ynl: remove __pycache__ during clean Build process uses python to generate the user space code. Remove __pycache__ on make clean. Signed-off-by: Jakub Kicinski Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- tools/net/ynl/lib/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile index 1507833d05c5..dfff3ecd1cba 100644 --- a/tools/net/ynl/lib/Makefile +++ b/tools/net/ynl/lib/Makefile @@ -17,6 +17,7 @@ ynl.a: $(OBJS) ar rcs $@ $(OBJS) clean: rm -f *.o *.d *~ + rm -rf __pycache__ distclean: clean rm -f *.a From 7df7231d6a6b68b4b68fb4e38a4639997a208fd2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:33:07 -0800 Subject: [PATCH 1924/2255] tools: ynl: move the new line in NlMsg __repr__ We add the new line even if message has no error or extack, which leads to print(nl_msg) ending with two new lines. Reviewed-by: Donald Hunter Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/lib/ynl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index ac55aa5a3083..92ade9105f31 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -213,11 +213,11 @@ class NlMsg: return self.nl_type def __repr__(self): - msg = f"nl_len = {self.nl_len} ({len(self.raw)}) nl_flags = 0x{self.nl_flags:x} nl_type = {self.nl_type}\n" + msg = f"nl_len = {self.nl_len} ({len(self.raw)}) nl_flags = 0x{self.nl_flags:x} nl_type = {self.nl_type}" if self.error: - msg += '\terror: ' + str(self.error) + msg += '\n\terror: ' + str(self.error) if self.extack: - msg += '\textack: ' + repr(self.extack) + msg += '\n\textack: ' + repr(self.extack) return msg From 7c93a88785dae6b61dc736b46594d088989e484b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:33:08 -0800 Subject: [PATCH 1925/2255] tools: ynl: allow setting recv() size Make the size of the buffer we use for recv() configurable. The details of the buffer sizing in netlink are somewhat arcane, we could spend a lot of time polishing this API. Let's just leave some hopefully helpful comments for now. This is a for-developers-only feature, anyway. Signed-off-by: Jakub Kicinski Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- tools/net/ynl/lib/ynl.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 92ade9105f31..c3ff5be33e4e 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -84,6 +84,10 @@ class NlError(Exception): return f"Netlink error: {os.strerror(-self.nl_msg.error)}\n{self.nl_msg}" +class ConfigError(Exception): + pass + + class NlAttr: ScalarFormat = namedtuple('ScalarFormat', ['native', 'big', 'little']) type_formats = { @@ -400,7 +404,8 @@ class SpaceAttrs: class YnlFamily(SpecFamily): - def __init__(self, def_path, schema=None, process_unknown=False): + def __init__(self, def_path, schema=None, process_unknown=False, + recv_size=0): super().__init__(def_path, schema) self.include_raw = False @@ -415,6 +420,16 @@ class YnlFamily(SpecFamily): except KeyError: raise Exception(f"Family '{self.yaml['name']}' not supported by the kernel") + # Note that netlink will use conservative (min) message size for + # the first dump recv() on the socket, our setting will only matter + # from the second recv() on. + self._recv_size = recv_size if recv_size else 131072 + # Netlink will always allocate at least PAGE_SIZE - sizeof(skb_shinfo) + # for a message, so smaller receive sizes will lead to truncation. + # Note that the min size for other families may be larger than 4k! + if self._recv_size < 4000: + raise ConfigError() + self.sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, self.nlproto.proto_num) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_EXT_ACK, 1) @@ -799,7 +814,7 @@ class YnlFamily(SpecFamily): def check_ntf(self): while True: try: - reply = self.sock.recv(128 * 1024, socket.MSG_DONTWAIT) + reply = self.sock.recv(self._recv_size, socket.MSG_DONTWAIT) except BlockingIOError: return @@ -854,7 +869,7 @@ class YnlFamily(SpecFamily): done = False rsp = [] while not done: - reply = self.sock.recv(128 * 1024) + reply = self.sock.recv(self._recv_size) nms = NlMsgs(reply, attr_space=op.attr_set) for nl_msg in nms: if nl_msg.extack: From a6a41521f95e5263a52ac79c02167a59ccc7183b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:33:09 -0800 Subject: [PATCH 1926/2255] tools: ynl: support debug printing messages For manual debug, allow printing the netlink level messages to stderr. Reviewed-by: Donald Hunter Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/lib/ynl.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index c3ff5be33e4e..239e22b7a85f 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -7,6 +7,7 @@ import random import socket import struct from struct import Struct +import sys import yaml import ipaddress import uuid @@ -420,6 +421,7 @@ class YnlFamily(SpecFamily): except KeyError: raise Exception(f"Family '{self.yaml['name']}' not supported by the kernel") + self._recv_dbg = False # Note that netlink will use conservative (min) message size for # the first dump recv() on the socket, our setting will only matter # from the second recv() on. @@ -453,6 +455,17 @@ class YnlFamily(SpecFamily): self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP, mcast_id) + def set_recv_dbg(self, enabled): + self._recv_dbg = enabled + + def _recv_dbg_print(self, reply, nl_msgs): + if not self._recv_dbg: + return + print("Recv: read", len(reply), "bytes,", + len(nl_msgs.msgs), "messages", file=sys.stderr) + for nl_msg in nl_msgs: + print(" ", nl_msg, file=sys.stderr) + def _encode_enum(self, attr_spec, value): enum = self.consts[attr_spec['enum']] if enum.type == 'flags' or attr_spec.get('enum-as-flags', False): @@ -819,6 +832,7 @@ class YnlFamily(SpecFamily): return nms = NlMsgs(reply) + self._recv_dbg_print(reply, nms) for nl_msg in nms: if nl_msg.error: print("Netlink error in ntf!?", os.strerror(-nl_msg.error)) @@ -871,6 +885,7 @@ class YnlFamily(SpecFamily): while not done: reply = self.sock.recv(self._recv_size) nms = NlMsgs(reply, attr_space=op.attr_set) + self._recv_dbg_print(reply, nms) for nl_msg in nms: if nl_msg.extack: self._decode_extack(msg, op, nl_msg.extack) From c0111878d45e3bb8779886fbf956b574bac8a3aa Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:33:10 -0800 Subject: [PATCH 1927/2255] tools: ynl: add --dbg-small-recv for easier kernel testing Most "production" netlink clients use large buffers to make dump efficient, which means that handling of dump continuation in the kernel is not very well tested. Add an option for debugging / testing handling of dumps. It enables printing of extra netlink-level debug and lowers the recv() buffer size in one go. When used without any argument (--dbg-small-recv) it picks a very small default (4000), explicit size can be set, too (--dbg-small-recv 5000). Example: $ ./cli.py [...] --dbg-small-recv Recv: read 3712 bytes, 29 messages nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 [...] nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 Recv: read 3968 bytes, 31 messages nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 [...] nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 Recv: read 532 bytes, 5 messages nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 [...] nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 nl_len = 20 (4) nl_flags = 0x2 nl_type = 3 (the [...] are edits to shorten the commit message). Note that the first message of the dump is sized conservatively by the kernel. Signed-off-by: Jakub Kicinski Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- tools/net/ynl/cli.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index 0f8239979670..e8a65fbc3698 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -38,6 +38,8 @@ def main(): const=Netlink.NLM_F_APPEND) parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction) parser.add_argument('--output-json', action='store_true') + parser.add_argument('--dbg-small-recv', default=0, const=4000, + action='store', nargs='?', type=int) args = parser.parse_args() def output(msg): @@ -53,7 +55,10 @@ def main(): if args.json_text: attrs = json.loads(args.json_text) - ynl = YnlFamily(args.spec, args.schema, args.process_unknown) + ynl = YnlFamily(args.spec, args.schema, args.process_unknown, + recv_size=args.dbg_small_recv) + if args.dbg_small_recv: + ynl.set_recv_dbg(True) if args.ntf: ynl.ntf_subscribe(args.ntf) From eeb78df4063c0b162324a9408ef573b24791871f Mon Sep 17 00:00:00 2001 From: Juntong Deng Date: Mon, 4 Mar 2024 11:32:08 +0000 Subject: [PATCH 1928/2255] inet: Add getsockopt support for IP_ROUTER_ALERT and IPV6_ROUTER_ALERT Currently getsockopt does not support IP_ROUTER_ALERT and IPV6_ROUTER_ALERT, and we are unable to get the values of these two socket options through getsockopt. This patch adds getsockopt support for IP_ROUTER_ALERT and IPV6_ROUTER_ALERT. Signed-off-by: Juntong Deng Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_sock.h | 1 + net/ipv4/ip_sockglue.c | 13 ++++++++++--- net/ipv6/ipv6_sockglue.c | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index d94c242eb3ed..f9ddd47dc4f8 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -274,6 +274,7 @@ enum { INET_FLAGS_REPFLOW = 27, INET_FLAGS_RTALERT_ISOLATE = 28, INET_FLAGS_SNDFLOW = 29, + INET_FLAGS_RTALERT = 30, }; /* cmsg flags for inet */ diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 21d2ffa919e9..cf377377b52d 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -894,7 +894,7 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, { struct inet_sock *inet = inet_sk(sk); struct net *net = sock_net(sk); - int val = 0, err; + int val = 0, err, retv; bool needs_rtnl = setsockopt_needs_rtnl(optname); switch (optname) { @@ -938,8 +938,12 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, /* If optlen==0, it is equivalent to val == 0 */ - if (optname == IP_ROUTER_ALERT) - return ip_ra_control(sk, val ? 1 : 0, NULL); + if (optname == IP_ROUTER_ALERT) { + retv = ip_ra_control(sk, val ? 1 : 0, NULL); + if (retv == 0) + inet_assign_bit(RTALERT, sk, val); + return retv; + } if (ip_mroute_opt(optname)) return ip_mroute_setsockopt(sk, optname, optval, optlen); @@ -1575,6 +1579,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_BIND_ADDRESS_NO_PORT: val = inet_test_bit(BIND_ADDRESS_NO_PORT, sk); goto copyval; + case IP_ROUTER_ALERT: + val = inet_test_bit(RTALERT, sk); + goto copyval; case IP_TTL: val = READ_ONCE(inet->uc_ttl); if (val < 0) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f61d977ac052..d4c28ec1bc51 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -948,6 +948,8 @@ done: if (optlen < sizeof(int)) goto e_inval; retv = ip6_ra_control(sk, val); + if (retv == 0) + inet6_assign_bit(RTALERT, sk, valbool); break; case IPV6_FLOWLABEL_MGR: retv = ipv6_flowlabel_opt(sk, optval, optlen); @@ -1445,6 +1447,10 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, val = np->rxopt.bits.recvfragsize; break; + case IPV6_ROUTER_ALERT: + val = inet6_test_bit(RTALERT, sk); + break; + case IPV6_ROUTER_ALERT_ISOLATE: val = inet6_test_bit(RTALERT_ISOLATE, sk); break; From 244ae992e3e80e5c9c272c77324c831148457f95 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Tue, 20 Feb 2024 15:57:10 -0800 Subject: [PATCH 1929/2255] igc: Fix missing time sync events Fix "double" clearing of interrupts, which can cause external events or timestamps to be missed. The IGC_TSIRC Time Sync Interrupt Cause register can be cleared in two ways, by either reading it or by writing '1' into the specific cause bit. This is documented in section 8.16.1. The following flow was used: 1. read IGC_TSIRC into 'tsicr'; 2. handle the interrupts present in 'tsirc' and mark them in 'ack'; 3. write 'ack' into IGC_TSICR; As both (1) and (3) will clear the interrupt cause, if the same interrupt happens again between (1) and (3) it will be ignored, causing events to be missed. Remove the extra clear in (3). Fixes: 2c344ae24501 ("igc: Add support for TX timestamping") Reviewed-by: Kurt Kanzenbach Tested-by: Kurt Kanzenbach # Intel i225 Signed-off-by: Vinicius Costa Gomes Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_main.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 81c21a893ede..e447ba037056 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -5302,25 +5302,22 @@ igc_features_check(struct sk_buff *skb, struct net_device *dev, static void igc_tsync_interrupt(struct igc_adapter *adapter) { - u32 ack, tsauxc, sec, nsec, tsicr; struct igc_hw *hw = &adapter->hw; + u32 tsauxc, sec, nsec, tsicr; struct ptp_clock_event event; struct timespec64 ts; tsicr = rd32(IGC_TSICR); - ack = 0; if (tsicr & IGC_TSICR_SYS_WRAP) { event.type = PTP_CLOCK_PPS; if (adapter->ptp_caps.pps) ptp_clock_event(adapter->ptp_clock, &event); - ack |= IGC_TSICR_SYS_WRAP; } if (tsicr & IGC_TSICR_TXTS) { /* retrieve hardware timestamp */ igc_ptp_tx_tstamp_event(adapter); - ack |= IGC_TSICR_TXTS; } if (tsicr & IGC_TSICR_TT0) { @@ -5334,7 +5331,6 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) wr32(IGC_TSAUXC, tsauxc); adapter->perout[0].start = ts; spin_unlock(&adapter->tmreg_lock); - ack |= IGC_TSICR_TT0; } if (tsicr & IGC_TSICR_TT1) { @@ -5348,7 +5344,6 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) wr32(IGC_TSAUXC, tsauxc); adapter->perout[1].start = ts; spin_unlock(&adapter->tmreg_lock); - ack |= IGC_TSICR_TT1; } if (tsicr & IGC_TSICR_AUTT0) { @@ -5358,7 +5353,6 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) event.index = 0; event.timestamp = sec * NSEC_PER_SEC + nsec; ptp_clock_event(adapter->ptp_clock, &event); - ack |= IGC_TSICR_AUTT0; } if (tsicr & IGC_TSICR_AUTT1) { @@ -5368,11 +5362,7 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) event.index = 1; event.timestamp = sec * NSEC_PER_SEC + nsec; ptp_clock_event(adapter->ptp_clock, &event); - ack |= IGC_TSICR_AUTT1; } - - /* acknowledge the interrupts */ - wr32(IGC_TSICR, ack); } /** From ee14cc9ea19ba9678177e2224a9c58cce5937c73 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Tue, 20 Feb 2024 15:57:11 -0800 Subject: [PATCH 1930/2255] igb: Fix missing time sync events Fix "double" clearing of interrupts, which can cause external events or timestamps to be missed. The E1000_TSIRC Time Sync Interrupt Cause register can be cleared in two ways, by either reading it or by writing '1' into the specific cause bit. This is documented in section 8.16.1. The following flow was used: 1. read E1000_TSIRC into 'tsicr'; 2. handle the interrupts present into 'tsirc' and mark them in 'ack'; 3. write 'ack' into E1000_TSICR; As both (1) and (3) will clear the interrupt cause, if the same interrupt happens again between (1) and (3) it will be ignored, causing events to be missed. Remove the extra clear in (3). Fixes: 00c65578b47b ("igb: enable internal PPS for the i210") Acked-by: Richard Cochran Signed-off-by: Vinicius Costa Gomes Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igb/igb_main.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index cebb44f51d5f..7662c42e35c1 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6985,44 +6985,31 @@ static void igb_extts(struct igb_adapter *adapter, int tsintr_tt) static void igb_tsync_interrupt(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; - u32 ack = 0, tsicr = rd32(E1000_TSICR); + u32 tsicr = rd32(E1000_TSICR); struct ptp_clock_event event; if (tsicr & TSINTR_SYS_WRAP) { event.type = PTP_CLOCK_PPS; if (adapter->ptp_caps.pps) ptp_clock_event(adapter->ptp_clock, &event); - ack |= TSINTR_SYS_WRAP; } if (tsicr & E1000_TSICR_TXTS) { /* retrieve hardware timestamp */ schedule_work(&adapter->ptp_tx_work); - ack |= E1000_TSICR_TXTS; } - if (tsicr & TSINTR_TT0) { + if (tsicr & TSINTR_TT0) igb_perout(adapter, 0); - ack |= TSINTR_TT0; - } - if (tsicr & TSINTR_TT1) { + if (tsicr & TSINTR_TT1) igb_perout(adapter, 1); - ack |= TSINTR_TT1; - } - if (tsicr & TSINTR_AUTT0) { + if (tsicr & TSINTR_AUTT0) igb_extts(adapter, 0); - ack |= TSINTR_AUTT0; - } - if (tsicr & TSINTR_AUTT1) { + if (tsicr & TSINTR_AUTT1) igb_extts(adapter, 1); - ack |= TSINTR_AUTT1; - } - - /* acknowledge the interrupts */ - wr32(E1000_TSICR, ack); } static irqreturn_t igb_msix_other(int irq, void *data) From 257310e998700e60382fbd3f4fd275fdbd9b2aaf Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Tue, 27 Feb 2024 15:31:06 +0100 Subject: [PATCH 1931/2255] ice: fix stats being updated by way too large values Simplify stats accumulation logic to fix the case where we don't take previous stat value into account, we should always respect it. Main netdev stats of our PF (Tx/Rx packets/bytes) were reported orders of magnitude too big during OpenStack reconfiguration events, possibly other reconfiguration cases too. The regression was reported to be between 6.1 and 6.2, so I was almost certain that on of the two "preserve stats over reset" commits were the culprit. While reading the code, it was found that in some cases we will increase the stats by arbitrarily large number (thanks to ignoring "-prev" part of condition, after zeroing it). Note that this fixes also the case where we were around limits of u64, but that was not the regression reported. Full disclosure: I remember suggesting this particular piece of code to Ben a few years ago, so blame on me. Fixes: 2fd5e433cd26 ("ice: Accumulate HW and Netdev statistics over reset") Reported-by: Nebojsa Stevanovic Link: https://lore.kernel.org/intel-wired-lan/VI1PR02MB439744DEDAA7B59B9A2833FE912EA@VI1PR02MB4397.eurprd02.prod.outlook.com Reported-by: Christian Rohmann Link: https://lore.kernel.org/intel-wired-lan/f38a6ca4-af05-48b1-a3e6-17ef2054e525@inovex.de Reviewed-by: Jacob Keller Signed-off-by: Przemek Kitszel Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 24 +++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index df6a68ab747e..6d256dbcb77d 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -6737,6 +6737,7 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi) { struct rtnl_link_stats64 *net_stats, *stats_prev; struct rtnl_link_stats64 *vsi_stats; + struct ice_pf *pf = vsi->back; u64 pkts, bytes; int i; @@ -6782,21 +6783,18 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi) net_stats = &vsi->net_stats; stats_prev = &vsi->net_stats_prev; - /* clear prev counters after reset */ - if (vsi_stats->tx_packets < stats_prev->tx_packets || - vsi_stats->rx_packets < stats_prev->rx_packets) { - stats_prev->tx_packets = 0; - stats_prev->tx_bytes = 0; - stats_prev->rx_packets = 0; - stats_prev->rx_bytes = 0; + /* Update netdev counters, but keep in mind that values could start at + * random value after PF reset. And as we increase the reported stat by + * diff of Prev-Cur, we need to be sure that Prev is valid. If it's not, + * let's skip this round. + */ + if (likely(pf->stat_prev_loaded)) { + net_stats->tx_packets += vsi_stats->tx_packets - stats_prev->tx_packets; + net_stats->tx_bytes += vsi_stats->tx_bytes - stats_prev->tx_bytes; + net_stats->rx_packets += vsi_stats->rx_packets - stats_prev->rx_packets; + net_stats->rx_bytes += vsi_stats->rx_bytes - stats_prev->rx_bytes; } - /* update netdev counters */ - net_stats->tx_packets += vsi_stats->tx_packets - stats_prev->tx_packets; - net_stats->tx_bytes += vsi_stats->tx_bytes - stats_prev->tx_bytes; - net_stats->rx_packets += vsi_stats->rx_packets - stats_prev->rx_packets; - net_stats->rx_bytes += vsi_stats->rx_bytes - stats_prev->rx_bytes; - stats_prev->tx_packets = vsi_stats->tx_packets; stats_prev->tx_bytes = vsi_stats->tx_bytes; stats_prev->rx_packets = vsi_stats->rx_packets; From 0ed3bba16d37618c7776a44ef02ad3039966d687 Mon Sep 17 00:00:00 2001 From: Takeru Hayasaka Date: Mon, 12 Feb 2024 02:04:03 +0000 Subject: [PATCH 1932/2255] ethtool: Add GTP RSS hash options to ethtool.h This is a patch that enables RSS functionality for GTP packets using ethtool. A user can include TEID and make RSS work for GTP-U over IPv4 by doing the following:`ethtool -N ens3 rx-flow-hash gtpu4 sde` In addition to gtpu(4|6), we now support gtpc(4|6),gtpc(4|6)t,gtpu(4|6)e, gtpu(4|6)u, and gtpu(4|6)d. gtpc(4|6): Used for GTP-C in IPv4 and IPv6, where the GTP header format does not include a TEID. gtpc(4|6)t: Used for GTP-C in IPv4 and IPv6, with a GTP header format that includes a TEID. gtpu(4|6): Used for GTP-U in both IPv4 and IPv6 scenarios. gtpu(4|6)e: Used for GTP-U with extended headers in both IPv4 and IPv6. gtpu(4|6)u: Used when the PSC (PDU session container) in the GTP-U extended header includes Uplink, applicable to both IPv4 and IPv6. gtpu(4|6)d: Used when the PSC in the GTP-U extended header includes Downlink, for both IPv4 and IPv6. GTP generates a flow that includes an ID called TEID to identify the tunnel. This tunnel is created for each UE (User Equipment).By performing RSS based on this flow, it is possible to apply RSS for each communication unit from the UE. Without this, RSS would only be effective within the range of IP addresses. For instance, the PGW can only perform RSS within the IP range of the SGW. Problematic from a load distribution perspective, especially if there's a bias in the terminals connected to a particular base station.This case can be solved by using this patch. Signed-off-by: Takeru Hayasaka Reviewed-by: Marcin Szycik Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- include/uapi/linux/ethtool.h | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 06ef6b78b7de..11fc18988bc2 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -2023,6 +2023,53 @@ static inline int ethtool_validate_duplex(__u8 duplex) #define IPV4_FLOW 0x10 /* hash only */ #define IPV6_FLOW 0x11 /* hash only */ #define ETHER_FLOW 0x12 /* spec only (ether_spec) */ + +/* Used for GTP-U IPv4 and IPv6. + * The format of GTP packets only includes + * elements such as TEID and GTP version. + * It is primarily intended for data communication of the UE. + */ +#define GTPU_V4_FLOW 0x13 /* hash only */ +#define GTPU_V6_FLOW 0x14 /* hash only */ + +/* Use for GTP-C IPv4 and v6. + * The format of these GTP packets does not include TEID. + * Primarily expected to be used for communication + * to create sessions for UE data communication, + * commonly referred to as CSR (Create Session Request). + */ +#define GTPC_V4_FLOW 0x15 /* hash only */ +#define GTPC_V6_FLOW 0x16 /* hash only */ + +/* Use for GTP-C IPv4 and v6. + * Unlike GTPC_V4_FLOW, the format of these GTP packets includes TEID. + * After session creation, it becomes this packet. + * This is mainly used for requests to realize UE handover. + */ +#define GTPC_TEID_V4_FLOW 0x17 /* hash only */ +#define GTPC_TEID_V6_FLOW 0x18 /* hash only */ + +/* Use for GTP-U and extended headers for the PSC (PDU Session Container). + * The format of these GTP packets includes TEID and QFI. + * In 5G communication using UPF (User Plane Function), + * data communication with this extended header is performed. + */ +#define GTPU_EH_V4_FLOW 0x19 /* hash only */ +#define GTPU_EH_V6_FLOW 0x1a /* hash only */ + +/* Use for GTP-U IPv4 and v6 PSC (PDU Session Container) extended headers. + * This differs from GTPU_EH_V(4|6)_FLOW in that it is distinguished by + * UL/DL included in the PSC. + * There are differences in the data included based on Downlink/Uplink, + * and can be used to distinguish packets. + * The functions described so far are useful when you want to + * handle communication from the mobile network in UPF, PGW, etc. + */ +#define GTPU_UL_V4_FLOW 0x1b /* hash only */ +#define GTPU_UL_V6_FLOW 0x1c /* hash only */ +#define GTPU_DL_V4_FLOW 0x1d /* hash only */ +#define GTPU_DL_V6_FLOW 0x1e /* hash only */ + /* Flag to enable additional fields in struct ethtool_rx_flow_spec */ #define FLOW_EXT 0x80000000 #define FLOW_MAC_EXT 0x40000000 @@ -2037,6 +2084,7 @@ static inline int ethtool_validate_duplex(__u8 duplex) #define RXH_IP_DST (1 << 5) #define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */ #define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */ +#define RXH_GTP_TEID (1 << 8) /* teid in case of GTP */ #define RXH_DISCARD (1 << 31) #define RX_CLS_FLOW_DISC 0xffffffffffffffffULL From a6d63bbf2c52d0a9d1550cd9a5ba58ea6371991b Mon Sep 17 00:00:00 2001 From: Takeru Hayasaka Date: Mon, 12 Feb 2024 02:04:05 +0000 Subject: [PATCH 1933/2255] ice: Implement RSS settings for GTP using ethtool Following the addition of new GTP RSS hash options to ethtool.h, this patch implements the corresponding RSS settings for GTP packets in the Intel ice driver. It enables users to configure RSS for GTP-U and GTP-C traffic over IPv4 and IPv6, utilizing the newly defined hash options. The implementation covers the handling of gtpu(4|6), gtpc(4|6), gtpc(4|6)t, gtpu(4|6)e, gtpu(4|6)u, and gtpu(4|6)d traffic, providing enhanced load distribution for GTP traffic across multiple processing units. Signed-off-by: Takeru Hayasaka Reviewed-by: Marcin Szycik Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- .../device_drivers/ethernet/intel/ice.rst | 21 ++++- drivers/net/ethernet/intel/ice/ice_ethtool.c | 82 +++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_flow.h | 31 +++++-- drivers/net/ethernet/intel/ice/ice_lib.c | 37 +++++++++ 4 files changed, 162 insertions(+), 9 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst index 5038e54586af..934752f675ba 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst @@ -368,15 +368,28 @@ more options for Receive Side Scaling (RSS) hash byte configuration. # ethtool -N rx-flow-hash