[PATCH net] mlxsw: pci: Quiesce EQ tasklet and CQ NAPI before teardown

Myeonghun Pak posted 1 patch 3 days, 18 hours ago
There is a newer version of this series
drivers/net/ethernet/mellanox/mlxsw/pci.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
[PATCH net] mlxsw: pci: Quiesce EQ tasklet and CQ NAPI before teardown
Posted by Myeonghun Pak 3 days, 18 hours ago
mlxsw_pci_eq_irq_handler() schedules the EQ tasklet. The tasklet reads
the EQ ring and schedules CQ NAPI instances. The CQ poll callbacks, in
turn, dereference the RDQ or SDQ associated with the CQ.

mlxsw_pci_fini() unregisters the IRQ and immediately tears down the
asynchronous queues in RDQ, SDQ, CQ, EQ order. free_irq() waits for IRQ
handlers, but not for a tasklet already scheduled by one. In addition,
mlxsw_pci_cq_fini() disables each CQ NAPI only after all RDQs and SDQs
have been freed. A pending tasklet or NAPI poll can therefore access
freed queue storage.

Kill the EQ tasklet after free_irq() so it cannot schedule any more CQ
NAPI instances. Disable all CQ NAPI instances before freeing the first
descriptor queue, ensuring their poll callbacks have completed. Track
the enabled state per CQ to avoid disabling a NAPI instance twice when
the CQ is later destroyed, while preserving the partial initialization
unwind.

Fixes: eda6500a987a ("mlxsw: Add PCI bus implementation")
Cc: stable@vger.kernel.org
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
---
Found by static analysis on v7.2-rc2; not tested on hardware.

 drivers/net/ethernet/mellanox/mlxsw/pci.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index 0da85d36647d..feeb32134d2a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -86,6 +86,7 @@ struct mlxsw_pci_queue {
 			enum mlxsw_pci_cqe_v v;
 			struct mlxsw_pci_queue *dq;
 			struct napi_struct napi;
+			bool napi_enabled;
 			struct page_pool *page_pool;
 		} cq;
 		struct {
@@ -989,6 +990,15 @@ static void mlxsw_pci_cq_napi_teardown(struct mlxsw_pci_queue *q)
 	netif_napi_del(&q->u.cq.napi);
 }
 
+static void mlxsw_pci_cq_napi_disable(struct mlxsw_pci_queue *q)
+{
+	if (!q->u.cq.napi_enabled)
+		return;
+
+	napi_disable(&q->u.cq.napi);
+	q->u.cq.napi_enabled = false;
+}
+
 static int mlxsw_pci_cq_page_pool_init(struct mlxsw_pci_queue *q,
 				       enum mlxsw_pci_cq_type cq_type)
 {
@@ -1064,6 +1074,7 @@ static int mlxsw_pci_cq_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
 		goto err_page_pool_init;
 
 	napi_enable(&q->u.cq.napi);
+	q->u.cq.napi_enabled = truea
 	mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
 	mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q);
 	return 0;
@@ -1078,7 +1089,7 @@ static void mlxsw_pci_cq_fini(struct mlxsw_pci *mlxsw_pci,
 {
 	enum mlxsw_pci_cq_type cq_type = mlxsw_pci_cq_type(mlxsw_pci, q);
 
-	napi_disable(&q->u.cq.napi);
+	mlxsw_pci_cq_napi_disable(q);
 	mlxsw_pci_cq_page_pool_fini(q, cq_type);
 	mlxsw_pci_cq_napi_teardown(q);
 	mlxsw_cmd_hw2sw_cq(mlxsw_pci->core, q->num);
@@ -1439,6 +1450,14 @@ err_cqs_init:
 
 static void mlxsw_pci_aqs_fini(struct mlxsw_pci *mlxsw_pci)
 {
+	struct mlxsw_pci_queue_type_group *queue_group;
+	int i;
+
+	queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci,
+						     MLXSW_PCI_QUEUE_TYPE_CQ);
+	for (i = 0; i < queue_group->count; i++)
+		mlxsw_pci_cq_napi_disable(&queue_group->q[i]);
+
 	mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_rdq_ops);
 	mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_sdq_ops);
 	mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_cq_ops);
@@ -2089,6 +2108,7 @@ static void mlxsw_pci_fini(void *bus_priv)
 	struct mlxsw_pci *mlxsw_pci = bus_priv;
 
 	free_irq(pci_irq_vector(mlxsw_pci->pdev, 0), mlxsw_pci);
+	tasklet_kill(&mlxsw_pci_eq_get(mlxsw_pci)->u.eq.tasklet);
 	mlxsw_pci_aqs_fini(mlxsw_pci);
 	mlxsw_pci_napi_devs_fini(mlxsw_pci);
 	mlxsw_pci_fw_area_fini(mlxsw_pci);
-- 
2.47.1
Re: [PATCH net] mlxsw: pci: Quiesce EQ tasklet and CQ NAPI before teardown
Posted by kernel test robot 3 days, 12 hours ago
Hi Myeonghun,

kernel test robot noticed the following build errors:

[auto build test ERROR on net/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Myeonghun-Pak/mlxsw-pci-Quiesce-EQ-tasklet-and-CQ-NAPI-before-teardown/20260721-142527
base:   net/main
patch link:    https://lore.kernel.org/r/20260721062105.55014-1-mhun512%40gmail.com
patch subject: [PATCH net] mlxsw: pci: Quiesce EQ tasklet and CQ NAPI before teardown
config: x86_64-rhel-9.4-bpf (https://download.01.org/0day-ci/archive/20260721/202607211419.DxdkHKb7-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260721/202607211419.DxdkHKb7-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202607211419.DxdkHKb7-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/net/ethernet/mellanox/mlxsw/pci.c: In function 'mlxsw_pci_cq_init':
>> drivers/net/ethernet/mellanox/mlxsw/pci.c:1077:32: error: 'truea' undeclared (first use in this function); did you mean 'true'?
    1077 |         q->u.cq.napi_enabled = truea
         |                                ^~~~~
         |                                true
   drivers/net/ethernet/mellanox/mlxsw/pci.c:1077:32: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/net/ethernet/mellanox/mlxsw/pci.c:1077:37: error: expected ';' before 'mlxsw_pci_queue_doorbell_consumer_ring'
    1077 |         q->u.cq.napi_enabled = truea
         |                                     ^
         |                                     ;
    1078 |         mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
         |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +1077 drivers/net/ethernet/mellanox/mlxsw/pci.c

  1036	
  1037	static int mlxsw_pci_cq_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
  1038				     struct mlxsw_pci_queue *q)
  1039	{
  1040		enum mlxsw_pci_cq_type cq_type = mlxsw_pci_cq_type(mlxsw_pci, q);
  1041		int i;
  1042		int err;
  1043	
  1044		q->consumer_counter = 0;
  1045	
  1046		for (i = 0; i < q->count; i++) {
  1047			char *elem = mlxsw_pci_queue_elem_get(q, i);
  1048	
  1049			mlxsw_pci_cqe_owner_set(q->u.cq.v, elem, 1);
  1050		}
  1051	
  1052		if (q->u.cq.v == MLXSW_PCI_CQE_V1)
  1053			mlxsw_cmd_mbox_sw2hw_cq_cqe_ver_set(mbox,
  1054					MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_1);
  1055		else if (q->u.cq.v == MLXSW_PCI_CQE_V2)
  1056			mlxsw_cmd_mbox_sw2hw_cq_cqe_ver_set(mbox,
  1057					MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_2);
  1058	
  1059		mlxsw_cmd_mbox_sw2hw_cq_c_eqn_set(mbox, MLXSW_PCI_EQ_COMP_NUM);
  1060		mlxsw_cmd_mbox_sw2hw_cq_st_set(mbox, 0);
  1061		mlxsw_cmd_mbox_sw2hw_cq_log_cq_size_set(mbox, ilog2(q->count));
  1062		for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) {
  1063			dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i);
  1064	
  1065			mlxsw_cmd_mbox_sw2hw_cq_pa_set(mbox, i, mapaddr);
  1066		}
  1067		err = mlxsw_cmd_sw2hw_cq(mlxsw_pci->core, mbox, q->num);
  1068		if (err)
  1069			return err;
  1070		mlxsw_pci_cq_napi_setup(q, cq_type);
  1071	
  1072		err = mlxsw_pci_cq_page_pool_init(q, cq_type);
  1073		if (err)
  1074			goto err_page_pool_init;
  1075	
  1076		napi_enable(&q->u.cq.napi);
> 1077		q->u.cq.napi_enabled = truea
  1078		mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
  1079		mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q);
  1080		return 0;
  1081	
  1082	err_page_pool_init:
  1083		mlxsw_pci_cq_napi_teardown(q);
  1084		return err;
  1085	}
  1086	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki