+++ /dev/null
-From 31ffcb4f7329c601cd6e065d80e4485a468e9980 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 4 Sep 2024 17:47:48 +0200
-Subject: idpf: enable WB_ON_ITR
-
-From: Joshua Hay <joshua.a.hay@intel.com>
-
-[ Upstream commit 9c4a27da0ecc4080dfcd63903dd94f01ba1399dd ]
-
-Tell hardware to write back completed descriptors even when interrupts
-are disabled. Otherwise, descriptors might not be written back until
-the hardware can flush a full cacheline of descriptors. This can cause
-unnecessary delays when traffic is light (or even trigger Tx queue
-timeout).
-
-The example scenario to reproduce the Tx timeout if the fix is not
-applied:
- - configure at least 2 Tx queues to be assigned to the same q_vector,
- - generate a huge Tx traffic on the first Tx queue
- - try to send a few packets using the second Tx queue.
-In such a case Tx timeout will appear on the second Tx queue because no
-completion descriptors are written back for that queue while interrupts
-are disabled due to NAPI polling.
-
-Fixes: c2d548cad150 ("idpf: add TX splitq napi poll support")
-Fixes: a5ab9ee0df0b ("idpf: add singleq start_xmit and napi poll")
-Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
-Co-developed-by: Michal Kubiak <michal.kubiak@intel.com>
-Signed-off-by: Michal Kubiak <michal.kubiak@intel.com>
-Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
-Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
-Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/net/ethernet/intel/idpf/idpf_dev.c | 2 ++
- .../ethernet/intel/idpf/idpf_singleq_txrx.c | 6 ++++-
- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 7 ++++-
- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 27 ++++++++++++++++++-
- drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 2 ++
- 5 files changed, 41 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
-index 3df9935685e96..6c913a703df64 100644
---- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
-+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
-@@ -97,8 +97,10 @@ static int idpf_intr_reg_init(struct idpf_vport *vport)
- intr->dyn_ctl = idpf_get_reg_addr(adapter,
- reg_vals[vec_id].dyn_ctl_reg);
- intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
-+ intr->dyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;
- intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
- intr->dyn_ctl_intrvl_s = PF_GLINT_DYN_CTL_INTERVAL_S;
-+ intr->dyn_ctl_wb_on_itr_m = PF_GLINT_DYN_CTL_WB_ON_ITR_M;
-
- spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
- IDPF_PF_ITR_IDX_SPACING);
-diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
-index fe64febf7436f..73ed024c5b862 100644
---- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
-+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
-@@ -1134,8 +1134,10 @@ int idpf_vport_singleq_napi_poll(struct napi_struct *napi, int budget)
- &work_done);
-
- /* If work not completed, return budget and polling will return */
-- if (!clean_complete)
-+ if (!clean_complete) {
-+ idpf_vport_intr_set_wb_on_itr(q_vector);
- return budget;
-+ }
-
- work_done = min_t(int, work_done, budget - 1);
-
-@@ -1144,6 +1146,8 @@ int idpf_vport_singleq_napi_poll(struct napi_struct *napi, int budget)
- */
- if (likely(napi_complete_done(napi, work_done)))
- idpf_vport_intr_update_itr_ena_irq(q_vector);
-+ else
-+ idpf_vport_intr_set_wb_on_itr(q_vector);
-
- return work_done;
- }
-diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
-index 585c3dadd9bfa..1431e503f76aa 100644
---- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
-+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
-@@ -3749,6 +3749,7 @@ void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector)
- /* net_dim() updates ITR out-of-band using a work item */
- idpf_net_dim(q_vector);
-
-+ q_vector->wb_on_itr = false;
- intval = idpf_vport_intr_buildreg_itr(q_vector,
- IDPF_NO_ITR_UPDATE_IDX, 0);
-
-@@ -4051,8 +4052,10 @@ static int idpf_vport_splitq_napi_poll(struct napi_struct *napi, int budget)
- clean_complete &= idpf_tx_splitq_clean_all(q_vector, budget, &work_done);
-
- /* If work not completed, return budget and polling will return */
-- if (!clean_complete)
-+ if (!clean_complete) {
-+ idpf_vport_intr_set_wb_on_itr(q_vector);
- return budget;
-+ }
-
- work_done = min_t(int, work_done, budget - 1);
-
-@@ -4061,6 +4064,8 @@ static int idpf_vport_splitq_napi_poll(struct napi_struct *napi, int budget)
- */
- if (likely(napi_complete_done(napi, work_done)))
- idpf_vport_intr_update_itr_ena_irq(q_vector);
-+ else
-+ idpf_vport_intr_set_wb_on_itr(q_vector);
-
- /* Switch to poll mode in the tear-down path after sending disable
- * queues virtchnl message, as the interrupts will be disabled after
-diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
-index 6215dbee55465..62a9656e96e85 100644
---- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
-+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
-@@ -390,9 +390,11 @@ struct idpf_vec_regs {
- * struct idpf_intr_reg
- * @dyn_ctl: Dynamic control interrupt register
- * @dyn_ctl_intena_m: Mask for dyn_ctl interrupt enable
-+ * @dyn_ctl_intena_msk_m: Mask for dyn_ctl interrupt enable mask
- * @dyn_ctl_itridx_s: Register bit offset for ITR index
- * @dyn_ctl_itridx_m: Mask for ITR index
- * @dyn_ctl_intrvl_s: Register bit offset for ITR interval
-+ * @dyn_ctl_wb_on_itr_m: Mask for WB on ITR feature
- * @rx_itr: RX ITR register
- * @tx_itr: TX ITR register
- * @icr_ena: Interrupt cause register offset
-@@ -401,9 +403,11 @@ struct idpf_vec_regs {
- struct idpf_intr_reg {
- void __iomem *dyn_ctl;
- u32 dyn_ctl_intena_m;
-+ u32 dyn_ctl_intena_msk_m;
- u32 dyn_ctl_itridx_s;
- u32 dyn_ctl_itridx_m;
- u32 dyn_ctl_intrvl_s;
-+ u32 dyn_ctl_wb_on_itr_m;
- void __iomem *rx_itr;
- void __iomem *tx_itr;
- void __iomem *icr_ena;
-@@ -424,6 +428,7 @@ struct idpf_intr_reg {
- * @intr_reg: See struct idpf_intr_reg
- * @napi: napi handler
- * @total_events: Number of interrupts processed
-+ * @wb_on_itr: whether WB on ITR is enabled
- * @tx_dim: Data for TX net_dim algorithm
- * @tx_itr_value: TX interrupt throttling rate
- * @tx_intr_mode: Dynamic ITR or not
-@@ -454,6 +459,7 @@ struct idpf_q_vector {
- __cacheline_group_begin_aligned(read_write);
- struct napi_struct napi;
- u16 total_events;
-+ bool wb_on_itr;
-
- struct dim tx_dim;
- u16 tx_itr_value;
-@@ -472,7 +478,7 @@ struct idpf_q_vector {
- cpumask_var_t affinity_mask;
- __cacheline_group_end_aligned(cold);
- };
--libeth_cacheline_set_assert(struct idpf_q_vector, 104,
-+libeth_cacheline_set_assert(struct idpf_q_vector, 112,
- 424 + 2 * sizeof(struct dim),
- 8 + sizeof(cpumask_var_t));
-
-@@ -1033,6 +1039,25 @@ static inline void idpf_tx_splitq_build_desc(union idpf_tx_flex_desc *desc,
- idpf_tx_splitq_build_flow_desc(desc, params, td_cmd, size);
- }
-
-+/**
-+ * idpf_vport_intr_set_wb_on_itr - enable descriptor writeback on disabled interrupts
-+ * @q_vector: pointer to queue vector struct
-+ */
-+static inline void idpf_vport_intr_set_wb_on_itr(struct idpf_q_vector *q_vector)
-+{
-+ struct idpf_intr_reg *reg;
-+
-+ if (q_vector->wb_on_itr)
-+ return;
-+
-+ q_vector->wb_on_itr = true;
-+ reg = &q_vector->intr_reg;
-+
-+ writel(reg->dyn_ctl_wb_on_itr_m | reg->dyn_ctl_intena_msk_m |
-+ (IDPF_NO_ITR_UPDATE_IDX << reg->dyn_ctl_itridx_s),
-+ reg->dyn_ctl);
-+}
-+
- int idpf_vport_singleq_napi_poll(struct napi_struct *napi, int budget);
- void idpf_vport_init_num_qs(struct idpf_vport *vport,
- struct virtchnl2_create_vport *vport_msg);
-diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
-index 629cb5cb7c9fc..99b8dbaf4225c 100644
---- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
-+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
-@@ -97,7 +97,9 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport)
- intr->dyn_ctl = idpf_get_reg_addr(adapter,
- reg_vals[vec_id].dyn_ctl_reg);
- intr->dyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M;
-+ intr->dyn_ctl_intena_msk_m = VF_INT_DYN_CTLN_INTENA_MSK_M;
- intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;
-+ intr->dyn_ctl_wb_on_itr_m = VF_INT_DYN_CTLN_WB_ON_ITR_M;
-
- spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
- IDPF_VF_ITR_IDX_SPACING);
---
-2.43.0
-