Skip to content

Commit 2e92500

Browse files
committed
Merge tag 'cxl-for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
Pull CXL updates from Dave Jiang: - Three CXL mailbox passthrough commands are added to support the populating and clearing of vendor debug logs: - Get Log Capabilities - Get Supported Log Sub-List Commands - Clear Log - Add support of Device Phyiscal Address (DPA) to Host Physical Address (HPA) translation for CXL events of cxl_dram and cxl_general media. This allows user space to figure out which CXL region the event occured via trace event. - Connect CXL to CPER reporting. If a device is configured for firmware first, CXL event records are not sent directly to the host. Those records are reported through EFI Common Platform Error Records (CPER). Add support to route the CPER records through the CXL sub-system in order to provide DPA to HPA translation and also event decoding and tracing. This is useful for users to determine which system issues may correspond to specific hardware events. - A number of misc cleanups and fixes: - Fix for compile warning of cxl_security_ops - Add debug message for invalid interleave granularity - Enhancement to cxl-test event testing - Add dev_warn() on unsupported mixed mode decoder - Fix use of phys_to_target_node() for x86 - Use helper function for decoder enum instead of open coding - Include missing headers for cxl-event - Fix MAINTAINERS file entry - Fix cxlr_pmem memory leak - Cleanup __cxl_parse_cfmws via scope-based resource menagement - Convert cxl_pmem_region_alloc() to scope-based resource management * tag 'cxl-for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: (21 commits) cxl/cper: Remove duplicated GUID defines cxl/cper: Fix non-ACPI-APEI-GHES build cxl/pci: Process CPER events acpi/ghes: Process CXL Component Events cxl/region: Convert cxl_pmem_region_alloc to scope-based resource management cxl/acpi: Cleanup __cxl_parse_cfmws() cxl/region: Fix cxlr_pmem leaks cxl/core: Add region info to cxl_general_media and cxl_dram events cxl/region: Move cxl_trace_hpa() work to the region driver cxl/region: Move cxl_dpa_to_region() work to the region driver cxl/trace: Correct DPA field masks for general_media & dram events MAINTAINERS: repair file entry in COMPUTE EXPRESS LINK cxl/cxl-event: include missing <linux/types.h> and <linux/uuid.h> cxl/hdm: Debug, use decoder name function cxl: Fix use of phys_to_target_node() for x86 cxl/hdm: dev_warn() on unsupported mixed mode decoder cxl/test: Enhance event testing cxl/hdm: Add debug message for invalid interleave granularity cxl: Fix compile warning for cxl_security_ops extern cxl/mbox: Add Clear Log mailbox command ...
2 parents c405aa3 + d99f138 commit 2e92500

File tree

18 files changed

+527
-234
lines changed

18 files changed

+527
-234
lines changed

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5407,7 +5407,7 @@ M: Dan Williams <[email protected]>
54075407
54085408
S: Maintained
54095409
F: drivers/cxl/
5410-
F: include/linux/cxl-einj.h
5410+
F: include/linux/einj-cxl.h
54115411
F: include/linux/cxl-event.h
54125412
F: include/uapi/linux/cxl_mem.h
54135413
F: tools/testing/cxl/

drivers/acpi/apei/ghes.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@
2626
#include <linux/interrupt.h>
2727
#include <linux/timer.h>
2828
#include <linux/cper.h>
29+
#include <linux/cleanup.h>
30+
#include <linux/cxl-event.h>
2931
#include <linux/platform_device.h>
3032
#include <linux/mutex.h>
3133
#include <linux/ratelimit.h>
3234
#include <linux/vmalloc.h>
3335
#include <linux/irq_work.h>
3436
#include <linux/llist.h>
3537
#include <linux/genalloc.h>
38+
#include <linux/kfifo.h>
3639
#include <linux/pci.h>
3740
#include <linux/pfn.h>
3841
#include <linux/aer.h>
@@ -673,6 +676,75 @@ static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
673676
schedule_work(&entry->work);
674677
}
675678

679+
/* Room for 8 entries for each of the 4 event log queues */
680+
#define CXL_CPER_FIFO_DEPTH 32
681+
DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);
682+
683+
/* Synchronize schedule_work() with cxl_cper_work changes */
684+
static DEFINE_SPINLOCK(cxl_cper_work_lock);
685+
struct work_struct *cxl_cper_work;
686+
687+
static void cxl_cper_post_event(enum cxl_event_type event_type,
688+
struct cxl_cper_event_rec *rec)
689+
{
690+
struct cxl_cper_work_data wd;
691+
692+
if (rec->hdr.length <= sizeof(rec->hdr) ||
693+
rec->hdr.length > sizeof(*rec)) {
694+
pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n",
695+
rec->hdr.length);
696+
return;
697+
}
698+
699+
if (!(rec->hdr.validation_bits & CPER_CXL_COMP_EVENT_LOG_VALID)) {
700+
pr_err(FW_WARN "CXL CPER invalid event\n");
701+
return;
702+
}
703+
704+
guard(spinlock_irqsave)(&cxl_cper_work_lock);
705+
706+
if (!cxl_cper_work)
707+
return;
708+
709+
wd.event_type = event_type;
710+
memcpy(&wd.rec, rec, sizeof(wd.rec));
711+
712+
if (!kfifo_put(&cxl_cper_fifo, wd)) {
713+
pr_err_ratelimited("CXL CPER kfifo overflow\n");
714+
return;
715+
}
716+
717+
schedule_work(cxl_cper_work);
718+
}
719+
720+
int cxl_cper_register_work(struct work_struct *work)
721+
{
722+
if (cxl_cper_work)
723+
return -EINVAL;
724+
725+
guard(spinlock)(&cxl_cper_work_lock);
726+
cxl_cper_work = work;
727+
return 0;
728+
}
729+
EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, CXL);
730+
731+
int cxl_cper_unregister_work(struct work_struct *work)
732+
{
733+
if (cxl_cper_work != work)
734+
return -EINVAL;
735+
736+
guard(spinlock)(&cxl_cper_work_lock);
737+
cxl_cper_work = NULL;
738+
return 0;
739+
}
740+
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, CXL);
741+
742+
int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd)
743+
{
744+
return kfifo_get(&cxl_cper_fifo, wd);
745+
}
746+
EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, CXL);
747+
676748
static bool ghes_do_proc(struct ghes *ghes,
677749
const struct acpi_hest_generic_status *estatus)
678750
{
@@ -707,6 +779,18 @@ static bool ghes_do_proc(struct ghes *ghes,
707779
}
708780
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
709781
queued = ghes_handle_arm_hw_error(gdata, sev, sync);
782+
} else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
783+
struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
784+
785+
cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec);
786+
} else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) {
787+
struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
788+
789+
cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec);
790+
} else if (guid_equal(sec_type, &CPER_SEC_CXL_MEM_MODULE_GUID)) {
791+
struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
792+
793+
cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec);
710794
} else {
711795
void *err = acpi_hest_get_payload(gdata);
712796

drivers/cxl/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ menuconfig CXL_BUS
66
select FW_UPLOAD
77
select PCI_DOE
88
select FIRMWARE_TABLE
9+
select NUMA_KEEP_MEMINFO if (NUMA && X86)
910
help
1011
CXL is a bus that is electrically compatible with PCI Express, but
1112
layers three protocols on that signalling (CXL.io, CXL.cache, and

drivers/cxl/acpi.c

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -316,28 +316,59 @@ static const struct cxl_root_ops acpi_root_ops = {
316316
.qos_class = cxl_acpi_qos_class,
317317
};
318318

319+
static void del_cxl_resource(struct resource *res)
320+
{
321+
if (!res)
322+
return;
323+
kfree(res->name);
324+
kfree(res);
325+
}
326+
327+
static struct resource *alloc_cxl_resource(resource_size_t base,
328+
resource_size_t n, int id)
329+
{
330+
struct resource *res __free(kfree) = kzalloc(sizeof(*res), GFP_KERNEL);
331+
332+
if (!res)
333+
return NULL;
334+
335+
res->start = base;
336+
res->end = base + n - 1;
337+
res->flags = IORESOURCE_MEM;
338+
res->name = kasprintf(GFP_KERNEL, "CXL Window %d", id);
339+
if (!res->name)
340+
return NULL;
341+
342+
return no_free_ptr(res);
343+
}
344+
345+
static int add_or_reset_cxl_resource(struct resource *parent, struct resource *res)
346+
{
347+
int rc = insert_resource(parent, res);
348+
349+
if (rc)
350+
del_cxl_resource(res);
351+
return rc;
352+
}
353+
354+
DEFINE_FREE(put_cxlrd, struct cxl_root_decoder *,
355+
if (!IS_ERR_OR_NULL(_T)) put_device(&_T->cxlsd.cxld.dev))
356+
DEFINE_FREE(del_cxl_resource, struct resource *, if (_T) del_cxl_resource(_T))
319357
static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
320358
struct cxl_cfmws_context *ctx)
321359
{
322360
int target_map[CXL_DECODER_MAX_INTERLEAVE];
323361
struct cxl_port *root_port = ctx->root_port;
324-
struct resource *cxl_res = ctx->cxl_res;
325362
struct cxl_cxims_context cxims_ctx;
326-
struct cxl_root_decoder *cxlrd;
327363
struct device *dev = ctx->dev;
328364
cxl_calc_hb_fn cxl_calc_hb;
329365
struct cxl_decoder *cxld;
330366
unsigned int ways, i, ig;
331-
struct resource *res;
332367
int rc;
333368

334369
rc = cxl_acpi_cfmws_verify(dev, cfmws);
335-
if (rc) {
336-
dev_err(dev, "CFMWS range %#llx-%#llx not registered\n",
337-
cfmws->base_hpa,
338-
cfmws->base_hpa + cfmws->window_size - 1);
370+
if (rc)
339371
return rc;
340-
}
341372

342373
rc = eiw_to_ways(cfmws->interleave_ways, &ways);
343374
if (rc)
@@ -348,38 +379,32 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
348379
for (i = 0; i < ways; i++)
349380
target_map[i] = cfmws->interleave_targets[i];
350381

351-
res = kzalloc(sizeof(*res), GFP_KERNEL);
382+
struct resource *res __free(del_cxl_resource) = alloc_cxl_resource(
383+
cfmws->base_hpa, cfmws->window_size, ctx->id++);
352384
if (!res)
353385
return -ENOMEM;
354386

355-
res->name = kasprintf(GFP_KERNEL, "CXL Window %d", ctx->id++);
356-
if (!res->name)
357-
goto err_name;
358-
359-
res->start = cfmws->base_hpa;
360-
res->end = cfmws->base_hpa + cfmws->window_size - 1;
361-
res->flags = IORESOURCE_MEM;
362-
363387
/* add to the local resource tracking to establish a sort order */
364-
rc = insert_resource(cxl_res, res);
388+
rc = add_or_reset_cxl_resource(ctx->cxl_res, no_free_ptr(res));
365389
if (rc)
366-
goto err_insert;
390+
return rc;
367391

368392
if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_MODULO)
369393
cxl_calc_hb = cxl_hb_modulo;
370394
else
371395
cxl_calc_hb = cxl_hb_xor;
372396

373-
cxlrd = cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb);
397+
struct cxl_root_decoder *cxlrd __free(put_cxlrd) =
398+
cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb);
374399
if (IS_ERR(cxlrd))
375400
return PTR_ERR(cxlrd);
376401

377402
cxld = &cxlrd->cxlsd.cxld;
378403
cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
379404
cxld->target_type = CXL_DECODER_HOSTONLYMEM;
380405
cxld->hpa_range = (struct range) {
381-
.start = res->start,
382-
.end = res->end,
406+
.start = cfmws->base_hpa,
407+
.end = cfmws->base_hpa + cfmws->window_size - 1,
383408
};
384409
cxld->interleave_ways = ways;
385410
/*
@@ -399,30 +424,20 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
399424
rc = acpi_table_parse_cedt(ACPI_CEDT_TYPE_CXIMS,
400425
cxl_parse_cxims, &cxims_ctx);
401426
if (rc < 0)
402-
goto err_xormap;
427+
return rc;
403428
if (!cxlrd->platform_data) {
404429
dev_err(dev, "No CXIMS for HBIG %u\n", ig);
405-
rc = -EINVAL;
406-
goto err_xormap;
430+
return -EINVAL;
407431
}
408432
}
409433
}
410434

411435
cxlrd->qos_class = cfmws->qtg_id;
412436

413437
rc = cxl_decoder_add(cxld, target_map);
414-
err_xormap:
415438
if (rc)
416-
put_device(&cxld->dev);
417-
else
418-
rc = cxl_decoder_autoremove(dev, cxld);
419-
return rc;
420-
421-
err_insert:
422-
kfree(res->name);
423-
err_name:
424-
kfree(res);
425-
return -ENOMEM;
439+
return rc;
440+
return cxl_root_decoder_autoremove(dev, no_free_ptr(cxlrd));
426441
}
427442

428443
static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
@@ -683,12 +698,6 @@ static void cxl_acpi_lock_reset_class(void *dev)
683698
device_lock_reset_class(dev);
684699
}
685700

686-
static void del_cxl_resource(struct resource *res)
687-
{
688-
kfree(res->name);
689-
kfree(res);
690-
}
691-
692701
static void cxl_set_public_resource(struct resource *priv, struct resource *pub)
693702
{
694703
priv->desc = (unsigned long) pub;

drivers/cxl/core/core.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,21 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
2727
int cxl_region_init(void);
2828
void cxl_region_exit(void);
2929
int cxl_get_poison_by_endpoint(struct cxl_port *port);
30+
struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa);
31+
u64 cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
32+
u64 dpa);
33+
3034
#else
35+
static inline u64
36+
cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa)
37+
{
38+
return ULLONG_MAX;
39+
}
40+
static inline
41+
struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa)
42+
{
43+
return NULL;
44+
}
3145
static inline int cxl_get_poison_by_endpoint(struct cxl_port *port)
3246
{
3347
return 0;

drivers/cxl/core/hdm.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
319319
else if (resource_contains(&cxlds->ram_res, res))
320320
cxled->mode = CXL_DECODER_RAM;
321321
else {
322-
dev_dbg(dev, "decoder%d.%d: %pr mixed\n", port->id,
323-
cxled->cxld.id, cxled->dpa_res);
322+
dev_warn(dev, "decoder%d.%d: %pr mixed mode not supported\n",
323+
port->id, cxled->cxld.id, cxled->dpa_res);
324324
cxled->mode = CXL_DECODER_MIXED;
325325
}
326326

@@ -519,8 +519,7 @@ int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size)
519519

520520
if (size > avail) {
521521
dev_dbg(dev, "%pa exceeds available %s capacity: %pa\n", &size,
522-
cxled->mode == CXL_DECODER_RAM ? "ram" : "pmem",
523-
&avail);
522+
cxl_decoder_mode_name(cxled->mode), &avail);
524523
rc = -ENOSPC;
525524
goto out;
526525
}
@@ -888,8 +887,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
888887
}
889888
rc = eig_to_granularity(FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl),
890889
&cxld->interleave_granularity);
891-
if (rc)
890+
if (rc) {
891+
dev_warn(&port->dev,
892+
"decoder%d.%d: Invalid interleave granularity (ctrl: %#x)\n",
893+
port->id, cxld->id, ctrl);
892894
return rc;
895+
}
893896

894897
dev_dbg(&port->dev, "decoder%d.%d: range: %#llx-%#llx iw: %d ig: %d\n",
895898
port->id, cxld->id, cxld->hpa_range.start, cxld->hpa_range.end,

0 commit comments

Comments
 (0)