[PATCH 8/9] RDMA/hfi2: Align probe error unwinding with device removal

Dennis Dalessandro <[email protected]> Mon, 03 Aug 2026 12:11:32 -0400
Newsgroups org.kernel.vger.linux-rdma
Message-ID <178577349246.1793053.13693369826252005139.stgit@awdrv-04>
Restructure init_one() to allocate the device data only after PCIe
initialization and early module-parameter validation have succeeded,
matching the order used by hfi1. The rcvhdrcnt, HdrQ entry size, and
eager buffer size checks, along with hfi2_pcie_init(), now run before
struct hfi2_devdata exists and report errors via dev_err()/pci_info()
directly on the struct pci_dev.

Hoist the debugfs initialization out of the conditional success block
so it unconditionally runs only once the whole probe sequence has
succeeded, rather than being nested inside an if-statement alongside
other success-path work.

Unify the success and failure teardown paths in init_one() using a
sequential goto-label chain (free_ib_dev/free_mad/teardown/
destroy_wqs/free_dd/clean_pcie) instead of a large nested
if (initfail || ret) block, mirroring the order used to tear the
device down in remove_one(). postinit_cleanup() is trimmed to only
perform the parts of cleanup that are common to both the error path
and remove_one(); destroy_workqueues(), hfi2_free_devdata(), and
hfi2_pcie_cleanup() are now called explicitly by each caller
(init_one()'s teardown labels and remove_one()) instead of being
folded into postinit_cleanup() itself. remove_one() is reordered to
match, calling postinit_cleanup() before destroying workqueues and
freeing the device data and PCIe resources.

hfi2 carries extra initialization steps not present in hfi1 (MAD
init/deinit, CPort trap setup, per-port stop_port() dispatch), which
are threaded into the new goto chain at the appropriate points.

Matches hfi1 fixes 9f674ba674a0 ("RDMA/hfi1: Allocate device data
after PCI initialization"), bb18740b302f ("RDMA/hfi1: Initialize
debugfs after probe completes"), and e26c48cf23a4 ("RDMA/hfi1: Align
probe error unwinding with device removal").

Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: Dennis Dalessandro <[email protected]>
---
 drivers/infiniband/hw/hfi2/init.c |  118 +++++++++++++++++--------------------
 1 file changed, 55 insertions(+), 63 deletions(-)

diff --git a/drivers/infiniband/hw/hfi2/init.c b/drivers/infiniband/hw/hfi2/init.c
index 12035b21b582..9e71fc8e5979 100644
--- a/drivers/infiniband/hw/hfi2/init.c
+++ b/drivers/infiniband/hw/hfi2/init.c
@@ -2372,15 +2372,11 @@ static void postinit_cleanup(struct hfi2_devdata *dd)
 	hfi2_release_rsm_rules(dd);
 
 	cleanup_device_data(dd);
-
-	destroy_workqueues(dd);
-	hfi2_pcie_cleanup(dd->pcidev);
-	hfi2_free_devdata(dd);
 }
 
 static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	int ret = 0, pidx, initfail = 0;
+	int ret = 0, pidx;
 	struct hfi2_devdata *dd;
 	const struct chip_params *params;
 
@@ -2428,22 +2424,16 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		return -EINVAL;
 	}
 
-	/* Allocate the dd so we can get to work */
-	dd = hfi2_alloc_devdata(pdev, params);
-	if (IS_ERR(dd))
-		return PTR_ERR(dd);
-
 	/* Validate some global module parameters */
 	ret = hfi2_validate_rcvhdrcnt(pdev, rcvhdrcnt);
 	if (ret)
-		goto free_dd;
+		return ret;
 
 	/* use the encoding function as a sanitization check */
 	if (!hfi2_encode_rcv_header_entry_size(hfi2_hdrq_entsize)) {
-		dd_dev_err(dd, "Invalid HdrQ Entry size %u\n",
-			   hfi2_hdrq_entsize);
-		ret = -EINVAL;
-		goto free_dd;
+		dev_err(&pdev->dev, "Invalid HdrQ Entry size %u\n",
+			hfi2_hdrq_entsize);
+		return -EINVAL;
 	}
 
 	/* The receive eager buffer size must be set before the receive
@@ -2462,11 +2452,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		eager_buffer_size = clamp_val(eager_buffer_size,
 					      MIN_EAGER_BUFFER * 8,
 					      MAX_EAGER_BUFFER_TOTAL);
-		dd_dev_info(dd, "Eager buffer size %u\n", eager_buffer_size);
+		pci_info(pdev, "Eager buffer size %u\n", eager_buffer_size);
 	} else {
-		dd_dev_err(dd, "Invalid Eager buffer size of 0\n");
-		ret = -EINVAL;
-		goto free_dd;
+		dev_err(&pdev->dev, "Invalid Eager buffer size of 0\n");
+		return -EINVAL;
 	}
 
 	/* restrict value of hfi2_rcvarr_split */
@@ -2474,13 +2463,20 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	ret = hfi2_pcie_init(pdev);
 	if (ret)
-		goto free_dd;
+		return ret;
 	if (params->chip_type == CHIP_JKR)
 		mask_aer_unsupported_request(pdev);
 
+	/* Allocate the dd so we can get to work */
+	dd = hfi2_alloc_devdata(pdev, params);
+	if (IS_ERR(dd)) {
+		ret = PTR_ERR(dd);
+		goto clean_pcie;
+	}
+
 	ret = create_workqueues(dd);
 	if (ret)
-		goto pcie_cleanup;
+		goto free_dd;
 
 	/*
 	 * Do device-specific initialization.  If hfi2_init_dd() fails, it
@@ -2491,55 +2487,37 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		goto destroy_wqs; /* error already printed */
 
 	/* do the generic initialization */
-	if (!ret)
-		initfail = hfi2_init(dd, 0);
+	ret = hfi2_init(dd, 0);
+	if (ret)
+		goto teardown;
 
-	if (!initfail && !ret)
-		ret = hfi2_mad_init(dd);
+	ret = hfi2_mad_init(dd);
+	if (ret)
+		goto teardown;
 
-	if (!initfail && !ret)
-		ret = hfi2_register_ib_device(dd);
+	ret = hfi2_register_ib_device(dd);
+	if (ret)
+		goto free_mad;
 
-	if (!initfail && !ret)
-		ret = hfi2_init_cport_trap128(
-			dd); /* after IB device register */
+	ret = hfi2_init_cport_trap128(dd); /* after IB device register */
+	if (ret)
+		goto free_ib_dev;
 
 	/*
 	 * Now ready for use.  this should be cleared whenever we
-	 * detect a reset, or initiate one.  If earlier failure,
-	 * we still create devices, so diags, etc. can be used
-	 * to determine cause of problem.
+	 * detect a reset, or initiate one.
 	 */
-	if (!initfail && !ret) {
-		int pidx;
-
-		dd->flags |= HFI2_INITTED;
-		for (pidx = 0; pidx < dd->num_pports; pidx++) {
-			struct hfi2_pportdata *ppd = dd->pport + pidx;
+	dd->flags |= HFI2_INITTED;
+	for (pidx = 0; pidx < dd->num_pports; pidx++) {
+		struct hfi2_pportdata *ppd = dd->pport + pidx;
 
-			if (ppd->host_link_state == HLS_UP_ACTIVE)
-				hfi2_go_port_active(ppd);
-		}
-		/* create debufs files after init and ib register */
-		hfi2_dbg_ibdev_init(&dd->verbs_dev);
-	}
-
-	if (initfail || ret) {
-		stop_cport(dd);
-		hfi2_msix_clean_up_interrupts(dd);
-		stop_timers(dd);
-		for (pidx = 0; pidx < dd->num_pports; ++pidx)
-			dd->params->stop_port(dd->pport + pidx);
-		if (!ret) {
-			hfi2_unregister_ib_device(dd);
-			hfi2_mad_deinit(dd);
-		}
-		postinit_cleanup(dd);
-		if (initfail)
-			ret = initfail;
-		goto bail; /* everything already cleaned */
+		if (ppd->host_link_state == HLS_UP_ACTIVE)
+			hfi2_go_port_active(ppd);
 	}
 
+	/* create debugfs files after init and ib register */
+	hfi2_dbg_ibdev_init(&dd->verbs_dev);
+
 	hfi2_sdma_start(dd);
 	hfi2_init_cport_overtemp(dd);
 
@@ -2547,13 +2525,24 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	hfi2_vf2pf_ready(dd);
 	return 0;
 
+free_ib_dev:
+	hfi2_unregister_ib_device(dd);
+free_mad:
+	hfi2_mad_deinit(dd);
+teardown:
+	stop_cport(dd);
+	hfi2_msix_clean_up_interrupts(dd);
+	stop_timers(dd);
+	for (pidx = 0; pidx < dd->num_pports; ++pidx)
+		dd->params->stop_port(dd->pport + pidx);
+	postinit_cleanup(dd);
+
 destroy_wqs:
 	destroy_workqueues(dd);
-pcie_cleanup:
-	hfi2_pcie_cleanup(pdev);
 free_dd:
 	hfi2_free_devdata(dd);
-bail:
+clean_pcie:
+	hfi2_pcie_cleanup(pdev);
 	return ret;
 }
 
@@ -2613,6 +2602,9 @@ static void remove_one(struct pci_dev *pdev)
 	stop_timers(dd);
 
 	postinit_cleanup(dd);
+	destroy_workqueues(dd);
+	hfi2_free_devdata(dd);
+	hfi2_pcie_cleanup(pdev);
 }
 
 /*