mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 06:23:02 +02:00
Merge branch 'for-7.3/cxl-port-err-prep' into cxl-for-next
cxl: Rename find_cxl_port() to find_cxl_port_by_dport() cxl: Tighten CPER kfifo registration API and symbol visibility acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register cxl/ras: Fix cxl_rch_get_aer_info() out-of-bounds AER register read
This commit is contained in:
commit
0673986e12
|
|
@ -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;
|
||||
|
|
@ -778,40 +778,48 @@ 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)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (cxl_cper_prot_err_work != work)
|
||||
return -EINVAL;
|
||||
struct work_struct *old;
|
||||
|
||||
guard(spinlock)(&cxl_cper_prot_err_work_lock);
|
||||
cxl_cper_prot_err_work = NULL;
|
||||
return 0;
|
||||
scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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
|
||||
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,23 +857,29 @@ 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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
cxl_cper_work = NULL;
|
||||
}
|
||||
|
||||
guard(spinlock)(&cxl_cper_work_lock);
|
||||
cxl_cper_work = NULL;
|
||||
return 0;
|
||||
cancel_work_sync(work);
|
||||
|
||||
/* Discard stale entries so they are not replayed on next module load */
|
||||
kfifo_reset(&cxl_cper_fifo);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, "CXL");
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,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);
|
||||
|
|
@ -194,10 +194,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
@ -2531,14 +2539,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:
|
||||
|
|
|
|||
|
|
@ -129,15 +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);
|
||||
cancel_work_sync(&cxl_cper_prot_err_work);
|
||||
cxl_cper_unregister_prot_err_work();
|
||||
}
|
||||
|
||||
static void cxl_dport_map_ras(struct cxl_dport *dport)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
@ -79,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1081,7 +1081,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user