[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);
}
/*