From 29458e62d0829cbc99435f3e44fd560f9bbf1da7 Mon Sep 17 00:00:00 2001 From: Terry Bowman Date: Mon, 3 Aug 2026 17:17:57 -0500 Subject: [PATCH 1/5] cxl/ras: Fix cxl_rch_get_aer_info() out-of-bounds AER register read cxl_rch_get_aer_info() copies the RCH Downstream Port AER capability from the RCRB MMIO block using a readl() loop bounded by sizeof(struct aer_capability_regs). This struct is a software layout and its embedded struct pcie_tlp_log is larger than the on-wire AER capability. As a result the loop reads past the mapped AER register block. The over-read also populates the software-only tail fields including header_log.header_len. An out-of-range header_len passed to pcie_print_tlp_log() can then loop past the header log buffer and cause a second out-of-bounds read. The read was correct when introduced, but struct pcie_tlp_log has since grown (Header Log and TLP Prefix Log sizes, header_len and flit fields), so sizeof(struct aer_capability_regs) no longer matches the physical AER capability. Bound the read to the physical AER registers, header through the 16 byte Header Log. Zero the destination first so the software-only fields are deterministic. Fixes: 6ac07883dbb5 ("cxl/pci: Add RCH downstream port error logging") Reported-by: Sashiko Cc: stable@vger.kernel.org Signed-off-by: Terry Bowman Reviewed-by: Alison Schofield Link: https://patch.msgid.link/20260803221810.3685703-2-terry.bowman@amd.com Signed-off-by: Dave Jiang --- drivers/cxl/core/ras_rch.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/cxl/core/ras_rch.c b/drivers/cxl/core/ras_rch.c index 0a8b3b9b6388..8a3965edaa12 100644 --- a/drivers/cxl/core/ras_rch.c +++ b/drivers/cxl/core/ras_rch.c @@ -58,13 +58,28 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport) static bool cxl_rch_get_aer_info(void __iomem *aer_base, struct aer_capability_regs *aer_regs) { - int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32); + /* + * Bound the copy to the physically-defined AER registers (header + * through the 16-byte Header Log). struct aer_capability_regs is a + * software layout whose embedded struct pcie_tlp_log is larger than + * the on-wire AER capability; copying sizeof(*aer_regs) would + * over-read the RCRB-mapped MMIO block. + */ + int read_cnt = (PCI_ERR_HEADER_LOG + 16) / sizeof(u32); u32 *aer_regs_buf = (u32 *)aer_regs; int n; if (!aer_base) return false; + /* + * Zero the destination so the software-only tail fields + * (e.g. header_log.header_len) are deterministic rather than + * left as uninitialized stack, which could drive a bogus loop + * length in pcie_print_tlp_log(). + */ + memset(aer_regs, 0, sizeof(*aer_regs)); + /* Use readl() to guarantee 32-bit accesses */ for (n = 0; n < read_cnt; n++) aer_regs_buf[n] = readl(aer_base + n * sizeof(u32)); From 9d399526128bae184b153deab42b49f5f3eea2ed Mon Sep 17 00:00:00 2001 From: Terry Bowman Date: Mon, 3 Aug 2026 17:17:58 -0500 Subject: [PATCH 2/5] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register cxl_rch_get_aer_severity() classifies RCH Downstream Port uncorrectable errors as fatal or non-fatal by ANDing uncorrectable status with PCI_ERR_ROOT_FATAL_RCV. This is wrong because PCI_ERR_ROOT_FATAL_RCV is a Root Error Status register bit (bit 6), not a severity bit. ANDing it against uncorrectable status tests a reserved bit and produces incorrect severity classification. Fix by ANDing the unmasked uncor_status against uncor_severity. Per PCIe Base Spec r6.0 Section 7.8.4.4, each bit in the Uncorrectable Error Severity register indicates whether the corresponding error is fatal (1) or non-fatal (0). Fixes: 6ac07883dbb5 ("cxl/pci: Add RCH downstream port error logging") Cc: stable@vger.kernel.org Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Richard Cheng Reviewed-by: Alison Schofield Link: https://patch.msgid.link/20260803221810.3685703-3-terry.bowman@amd.com Signed-off-by: Dave Jiang --- drivers/cxl/core/ras_rch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cxl/core/ras_rch.c b/drivers/cxl/core/ras_rch.c index 8a3965edaa12..e0e01aa5eba6 100644 --- a/drivers/cxl/core/ras_rch.c +++ b/drivers/cxl/core/ras_rch.c @@ -94,11 +94,11 @@ static bool cxl_rch_get_aer_info(void __iomem *aer_base, static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, int *severity) { - if (aer_regs->uncor_status & ~aer_regs->uncor_mask) { - if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV) - *severity = AER_FATAL; - else - *severity = AER_NONFATAL; + u32 uncor_status = aer_regs->uncor_status & ~aer_regs->uncor_mask; + + if (uncor_status) { + *severity = (uncor_status & aer_regs->uncor_severity) ? + AER_FATAL : AER_NONFATAL; return true; } From 6625ca499c3131ef63be3215f8f942d7a097ea3a Mon Sep 17 00:00:00 2001 From: Terry Bowman Date: Mon, 3 Aug 2026 17:17:59 -0500 Subject: [PATCH 3/5] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks The CXL CPER work registration and unregistration helpers acquire cxl_cper_work_lock and cxl_cper_prot_err_work_lock with a spinlock guard(), which leaves local interrupts enabled. The corresponding post paths (cxl_cper_post_event(), cxl_cper_post_prot_err()) execute in hard IRQ context (they are called from the GHES error notification path) and acquire the same locks with an irqsave guard(). If a CPU is holding one of these locks via a spinlock guard() when a GHES interrupt arrives on the same CPU, the IRQ handler spins on the held lock waiting for it to release, while the lock holder is preempted by the IRQ. The result is a deadlock. Convert both locks from spinlock_t to raw_spinlock_t and use guard() at all call sites. On PREEMPT_RT kernels spinlock_t is backed by rt_mutex and sleeping from hard IRQ context is not permitted; raw_spinlock_t is safe in both contexts. Add WARN_ONCE to both register functions to surface double-registration bugs at runtime. Restructure both unregister functions to clear the global work pointer under the lock before calling cancel_work_sync(), closing the window where a CPER interrupt could schedule work on a pointer about to be freed. Add kfifo_reset() after cancel_work_sync() so stale entries are not replayed on next module load. Both kfifos are single-consumer: only one work_struct is registered at a time, enforced by the WARN_ONCE guard in the register functions. kfifo_reset() is safe outside the lock because cancel_work_sync() has already quiesced the consumer, and no new consumer can register until the current module exit completes and a fresh module init runs. Remove the redundant cancel_work_sync() call from cxl_ras_exit() and cxl_pci_driver_exit(). The CPER unregister functions now quiesce the work internally. Reported-by: Sashiko Signed-off-by: Terry Bowman Fixes: 5e4a264bf8b5 ("acpi/ghes: Process CXL Component Events") Fixes: 36f257e3b0ba ("acpi/ghes, cxl/pci: Process CXL CPER Protocol Errors") Cc: stable@vger.kernel.org Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Reviewed-by: Tony Luck Link: https://patch.msgid.link/20260803221810.3685703-4-terry.bowman@amd.com Signed-off-by: Dave Jiang --- drivers/acpi/apei/ghes.c | 50 ++++++++++++++++++++++++++-------------- drivers/cxl/core/ras.c | 1 - drivers/cxl/pci.c | 1 - 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 3236a3ce79d6..ca7a138c1ff2 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -749,7 +749,7 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data, CXL_CPER_PROT_ERR_FIFO_DEPTH); /* Synchronize schedule_work() with cxl_cper_prot_err_work changes */ -static DEFINE_SPINLOCK(cxl_cper_prot_err_work_lock); +static DEFINE_RAW_SPINLOCK(cxl_cper_prot_err_work_lock); struct work_struct *cxl_cper_prot_err_work; static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, @@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, if (cxl_cper_sec_prot_err_valid(prot_err)) return; - guard(spinlock_irqsave)(&cxl_cper_prot_err_work_lock); + guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock); if (!cxl_cper_prot_err_work) return; @@ -780,10 +780,11 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, int cxl_cper_register_prot_err_work(struct work_struct *work) { - if (cxl_cper_prot_err_work) - return -EINVAL; + guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock); - guard(spinlock)(&cxl_cper_prot_err_work_lock); + if (WARN_ONCE(cxl_cper_prot_err_work, + "CPER-CXL kfifo consumer already registered\n")) + return -EINVAL; cxl_cper_prot_err_work = work; return 0; } @@ -791,11 +792,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL"); int cxl_cper_unregister_prot_err_work(struct work_struct *work) { - if (cxl_cper_prot_err_work != work) - return -EINVAL; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { + if (WARN_ONCE(cxl_cper_prot_err_work != work, + "CPER-CXL kfifo consumer mismatch on unregister\n")) + return -EINVAL; + cxl_cper_prot_err_work = NULL; + } + + cancel_work_sync(work); + + /* Discard stale entries so they are not replayed on next module load */ + kfifo_reset(&cxl_cper_prot_err_fifo); - guard(spinlock)(&cxl_cper_prot_err_work_lock); - cxl_cper_prot_err_work = NULL; return 0; } EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_prot_err_work, "CXL"); @@ -811,7 +819,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL"); DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH); /* Synchronize schedule_work() with cxl_cper_work changes */ -static DEFINE_SPINLOCK(cxl_cper_work_lock); +static DEFINE_RAW_SPINLOCK(cxl_cper_work_lock); struct work_struct *cxl_cper_work; static void cxl_cper_post_event(enum cxl_event_type event_type, @@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type, return; } - guard(spinlock_irqsave)(&cxl_cper_work_lock); + guard(raw_spinlock_irqsave)(&cxl_cper_work_lock); if (!cxl_cper_work) return; @@ -849,10 +857,11 @@ static void cxl_cper_post_event(enum cxl_event_type event_type, int cxl_cper_register_work(struct work_struct *work) { - if (cxl_cper_work) + guard(raw_spinlock_irqsave)(&cxl_cper_work_lock); + if (WARN_ONCE(cxl_cper_work, + "CXL CPER kfifo consumer already registered\n")) return -EINVAL; - guard(spinlock)(&cxl_cper_work_lock); cxl_cper_work = work; return 0; } @@ -860,11 +869,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL"); int cxl_cper_unregister_work(struct work_struct *work) { - if (cxl_cper_work != work) - return -EINVAL; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) { + if (WARN_ONCE(cxl_cper_work != work, + "CXL CPER kfifo consumer mismatch on unregister\n")) + return -EINVAL; + cxl_cper_work = NULL; + } + + cancel_work_sync(work); + + /* Discard stale entries so they are not replayed on next module load */ + kfifo_reset(&cxl_cper_fifo); - guard(spinlock)(&cxl_cper_work_lock); - cxl_cper_work = NULL; return 0; } EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, "CXL"); diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c index 99fb00949c2f..bc74d4848132 100644 --- a/drivers/cxl/core/ras.c +++ b/drivers/cxl/core/ras.c @@ -137,7 +137,6 @@ int cxl_ras_init(void) void cxl_ras_exit(void) { cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work); - cancel_work_sync(&cxl_cper_prot_err_work); } static void cxl_dport_map_ras(struct cxl_dport *dport) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 267c679b0b3c..7c6faee7f85e 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) { cxl_cper_unregister_work(&cxl_cper_work); - cancel_work_sync(&cxl_cper_work); pci_unregister_driver(&cxl_pci_driver); } From 59a37f9200688916650e1d60774c90f023c79b57 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 Aug 2026 17:18:00 -0500 Subject: [PATCH 4/5] cxl: Tighten CPER kfifo registration API and symbol visibility Tighten the CPER protocol error kfifo registration API and symbol visibility. Use EXPORT_SYMBOL_FOR_MODULES() instead of EXPORT_SYMBOL_NS_GPL() for the CPER kfifo registration symbols. This names the consuming module explicitly and gives compile-time enforcement. Drop the work_struct argument from the unregister path. Change the WARN_ONCE condition to a NULL check since there is no caller pointer to compare against anymore. Return void from the registration helpers whose result callers ignore. cxl_cper_register_work() keeps its int return as the only one consumed by a caller. Flag double registration with WARN_ONCE() inside the lock instead of returning an error. Change cxl_ras_init() to void because there is one consumer and one producer so the error return was unnecessary. Remove the now-dead error check in cxl_core_init(). Co-developed-by: Terry Bowman Signed-off-by: Terry Bowman Signed-off-by: Dan Williams Reviewed-by: Dave Jiang Reviewed-by: Alison Schofield Link: https://patch.msgid.link/20260803221810.3685703-5-terry.bowman@amd.com Signed-off-by: Dave Jiang --- drivers/acpi/apei/ghes.c | 32 +++++++++++++++----------------- drivers/cxl/core/core.h | 7 ++----- drivers/cxl/core/port.c | 6 +----- drivers/cxl/core/ras.c | 6 +++--- include/cxl/event.h | 21 ++++++--------------- 5 files changed, 27 insertions(+), 45 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index ca7a138c1ff2..187f54e31c33 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -778,41 +778,41 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, #endif } -int cxl_cper_register_prot_err_work(struct work_struct *work) +void cxl_cper_register_prot_err_work(struct work_struct *work) { guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock); if (WARN_ONCE(cxl_cper_prot_err_work, "CPER-CXL kfifo consumer already registered\n")) - return -EINVAL; + return; cxl_cper_prot_err_work = work; - return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL"); +EXPORT_SYMBOL_FOR_MODULES(cxl_cper_register_prot_err_work, "cxl_core"); -int cxl_cper_unregister_prot_err_work(struct work_struct *work) +void cxl_cper_unregister_prot_err_work(void) { + struct work_struct *old; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { - if (WARN_ONCE(cxl_cper_prot_err_work != work, - "CPER-CXL kfifo consumer mismatch on unregister\n")) - return -EINVAL; + WARN_ONCE(!cxl_cper_prot_err_work, + "CPER-CXL kfifo consumer not registered on unregister\n"); + old = cxl_cper_prot_err_work; cxl_cper_prot_err_work = NULL; } - cancel_work_sync(work); + if (old) + cancel_work_sync(old); /* Discard stale entries so they are not replayed on next module load */ kfifo_reset(&cxl_cper_prot_err_fifo); - - return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_prot_err_work, "CXL"); +EXPORT_SYMBOL_FOR_MODULES(cxl_cper_unregister_prot_err_work, "cxl_core"); int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd) { return kfifo_get(&cxl_cper_prot_err_fifo, wd); } -EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL"); +EXPORT_SYMBOL_FOR_MODULES(cxl_cper_prot_err_kfifo_get, "cxl_core"); /* Room for 8 entries for each of the 4 event log queues */ #define CXL_CPER_FIFO_DEPTH 32 @@ -867,12 +867,12 @@ int cxl_cper_register_work(struct work_struct *work) } EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL"); -int cxl_cper_unregister_work(struct work_struct *work) +void cxl_cper_unregister_work(struct work_struct *work) { scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) { if (WARN_ONCE(cxl_cper_work != work, "CXL CPER kfifo consumer mismatch on unregister\n")) - return -EINVAL; + return; cxl_cper_work = NULL; } @@ -880,8 +880,6 @@ int cxl_cper_unregister_work(struct work_struct *work) /* Discard stale entries so they are not replayed on next module load */ kfifo_reset(&cxl_cper_fifo); - - return 0; } EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, "CXL"); diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 07555ae63859..23fe40ddf4c6 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -183,7 +183,7 @@ static inline struct device *dport_to_host(struct cxl_dport *dport) return &port->dev; } #ifdef CONFIG_CXL_RAS -int cxl_ras_init(void); +void cxl_ras_init(void); void cxl_ras_exit(void); bool cxl_handle_ras(struct device *dev, void __iomem *ras_base); void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base); @@ -192,10 +192,7 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport); void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds); void devm_cxl_dport_ras_setup(struct cxl_dport *dport); #else -static inline int cxl_ras_init(void) -{ - return 0; -} +static inline void cxl_ras_init(void) { } static inline void cxl_ras_exit(void) { } static inline bool cxl_handle_ras(struct device *dev, void __iomem *ras_base) { diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 1215ee4f4035..f90f899c31d0 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -2531,14 +2531,10 @@ static __init int cxl_core_init(void) if (rc) goto err_region; - rc = cxl_ras_init(); - if (rc) - goto err_ras; + cxl_ras_init(); return 0; -err_ras: - cxl_region_exit(); err_region: bus_unregister(&cxl_bus_type); err_bus: diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c index bc74d4848132..e307361bb39e 100644 --- a/drivers/cxl/core/ras.c +++ b/drivers/cxl/core/ras.c @@ -129,14 +129,14 @@ static void cxl_cper_prot_err_work_fn(struct work_struct *work) } static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn); -int cxl_ras_init(void) +void cxl_ras_init(void) { - return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work); + cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work); } void cxl_ras_exit(void) { - cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work); + cxl_cper_unregister_prot_err_work(); } static void cxl_dport_map_ras(struct cxl_dport *dport) diff --git a/include/cxl/event.h b/include/cxl/event.h index ff97fea718d2..b5673384d930 100644 --- a/include/cxl/event.h +++ b/include/cxl/event.h @@ -287,10 +287,10 @@ struct cxl_cper_prot_err_work_data { #ifdef CONFIG_ACPI_APEI_GHES int cxl_cper_register_work(struct work_struct *work); -int cxl_cper_unregister_work(struct work_struct *work); +void cxl_cper_unregister_work(struct work_struct *work); int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd); -int cxl_cper_register_prot_err_work(struct work_struct *work); -int cxl_cper_unregister_prot_err_work(struct work_struct *work); +void cxl_cper_register_prot_err_work(struct work_struct *work); +void cxl_cper_unregister_prot_err_work(void); int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd); #else static inline int cxl_cper_register_work(struct work_struct *work) @@ -298,22 +298,13 @@ static inline int cxl_cper_register_work(struct work_struct *work) return 0; } -static inline int cxl_cper_unregister_work(struct work_struct *work) -{ - return 0; -} +static inline void cxl_cper_unregister_work(struct work_struct *work) { } static inline int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd) { return 0; } -static inline int cxl_cper_register_prot_err_work(struct work_struct *work) -{ - return 0; -} -static inline int cxl_cper_unregister_prot_err_work(struct work_struct *work) -{ - return 0; -} +static inline void cxl_cper_register_prot_err_work(struct work_struct *work) { } +static inline void cxl_cper_unregister_prot_err_work(void) { } static inline int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd) { return 0; From 658fb50cc8882608dc72dfa6b2e052f87d265ce6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 Aug 2026 17:18:01 -0500 Subject: [PATCH 5/5] cxl: Rename find_cxl_port() to find_cxl_port_by_dport() find_cxl_port() and find_cxl_port_by_uport() are internal port lookup functions that search the CXL bus by dport and uport respectively, but their names do not make the lookup method clear. Rename find_cxl_port() to find_cxl_port_by_dport() to make the lookup method explicit and consistent with find_cxl_port_by_uport(). Both functions remain static to port.c; the upcoming patch that adds the first cross-file caller will widen their scope. Make the same naming change to static helper __find_cxl_port_by_dport(). Co-developed-by: Terry Bowman Signed-off-by: Terry Bowman Signed-off-by: Dan Williams Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20260803221810.3685703-6-terry.bowman@amd.com Signed-off-by: Dave Jiang --- drivers/cxl/core/port.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index f90f899c31d0..cadb51f70f85 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1379,7 +1379,7 @@ static int match_port_by_dport(struct device *dev, const void *data) return dport != NULL; } -static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx) +static struct cxl_port *__find_cxl_port_by_dport(struct cxl_find_port_ctx *ctx) { struct device *dev; @@ -1392,8 +1392,16 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx) return NULL; } -static struct cxl_port *find_cxl_port(struct device *dport_dev, - struct cxl_dport **dport) +/** + * find_cxl_port_by_dport - find a cxl_port by one of its targets + * @dport_dev: device representing the dport target + * @dport: optional output of the 'struct cxl_dport' companion of the @dport_dev + * + * Return a 'struct cxl_port' with an elevated reference if found. Use + * __free(put_cxl_port) to release. + */ +static struct cxl_port *find_cxl_port_by_dport(struct device *dport_dev, + struct cxl_dport **dport) { struct cxl_find_port_ctx ctx = { .dport_dev = dport_dev, @@ -1401,7 +1409,7 @@ static struct cxl_port *find_cxl_port(struct device *dport_dev, }; struct cxl_port *port; - port = __find_cxl_port(&ctx); + port = __find_cxl_port_by_dport(&ctx); return port; } @@ -1895,14 +1903,14 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, "CXL"); struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev, struct cxl_dport **dport) { - return find_cxl_port(pdev->dev.parent, dport); + return find_cxl_port_by_dport(pdev->dev.parent, dport); } EXPORT_SYMBOL_NS_GPL(cxl_pci_find_port, "CXL"); struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, struct cxl_dport **dport) { - return find_cxl_port(grandparent(&cxlmd->dev), dport); + return find_cxl_port_by_dport(grandparent(&cxlmd->dev), dport); } EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, "CXL");