Merge branch 'for-6.8/cxl-cper' into for-6.8/cxl
Pick up the CPER to CXL driver integration work for v6.8. Some additional cleanup of cper_estatus_print() messages is needed, but that is to be handled incrementally.
This commit is contained in:
@@ -5245,6 +5245,7 @@ M: Dan Williams <dan.j.williams@intel.com>
|
||||
L: linux-cxl@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/cxl/
|
||||
F: include/linux/cxl-event.h
|
||||
F: include/uapi/linux/cxl_mem.h
|
||||
F: tools/testing/cxl/
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/cper.h>
|
||||
#include <linux/cxl-event.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ratelimit.h>
|
||||
@@ -657,6 +658,78 @@ static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
|
||||
schedule_work(&entry->work);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only a single callback can be registered for CXL CPER events.
|
||||
*/
|
||||
static DECLARE_RWSEM(cxl_cper_rw_sem);
|
||||
static cxl_cper_callback cper_callback;
|
||||
|
||||
/* CXL Event record UUIDs are formatted as GUIDs and reported in section type */
|
||||
|
||||
/*
|
||||
* General Media Event Record
|
||||
* CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
|
||||
*/
|
||||
#define CPER_SEC_CXL_GEN_MEDIA_GUID \
|
||||
GUID_INIT(0xfbcd0a77, 0xc260, 0x417f, \
|
||||
0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6)
|
||||
|
||||
/*
|
||||
* DRAM Event Record
|
||||
* CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
|
||||
*/
|
||||
#define CPER_SEC_CXL_DRAM_GUID \
|
||||
GUID_INIT(0x601dcbb3, 0x9c06, 0x4eab, \
|
||||
0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24)
|
||||
|
||||
/*
|
||||
* Memory Module Event Record
|
||||
* CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
|
||||
*/
|
||||
#define CPER_SEC_CXL_MEM_MODULE_GUID \
|
||||
GUID_INIT(0xfe927475, 0xdd59, 0x4339, \
|
||||
0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74)
|
||||
|
||||
static void cxl_cper_post_event(enum cxl_event_type event_type,
|
||||
struct cxl_cper_event_rec *rec)
|
||||
{
|
||||
if (rec->hdr.length <= sizeof(rec->hdr) ||
|
||||
rec->hdr.length > sizeof(*rec)) {
|
||||
pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n",
|
||||
rec->hdr.length);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(rec->hdr.validation_bits & CPER_CXL_COMP_EVENT_LOG_VALID)) {
|
||||
pr_err(FW_WARN "CXL CPER invalid event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
guard(rwsem_read)(&cxl_cper_rw_sem);
|
||||
if (cper_callback)
|
||||
cper_callback(event_type, rec);
|
||||
}
|
||||
|
||||
int cxl_cper_register_callback(cxl_cper_callback callback)
|
||||
{
|
||||
guard(rwsem_write)(&cxl_cper_rw_sem);
|
||||
if (cper_callback)
|
||||
return -EINVAL;
|
||||
cper_callback = callback;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_register_callback, CXL);
|
||||
|
||||
int cxl_cper_unregister_callback(cxl_cper_callback callback)
|
||||
{
|
||||
guard(rwsem_write)(&cxl_cper_rw_sem);
|
||||
if (callback != cper_callback)
|
||||
return -EINVAL;
|
||||
cper_callback = NULL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_callback, CXL);
|
||||
|
||||
static bool ghes_do_proc(struct ghes *ghes,
|
||||
const struct acpi_hest_generic_status *estatus)
|
||||
{
|
||||
@@ -690,6 +763,22 @@ static bool ghes_do_proc(struct ghes *ghes,
|
||||
}
|
||||
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
|
||||
queued = ghes_handle_arm_hw_error(gdata, sev);
|
||||
} else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
|
||||
struct cxl_cper_event_rec *rec =
|
||||
acpi_hest_get_payload(gdata);
|
||||
|
||||
cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec);
|
||||
} else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) {
|
||||
struct cxl_cper_event_rec *rec =
|
||||
acpi_hest_get_payload(gdata);
|
||||
|
||||
cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec);
|
||||
} else if (guid_equal(sec_type,
|
||||
&CPER_SEC_CXL_MEM_MODULE_GUID)) {
|
||||
struct cxl_cper_event_rec *rec =
|
||||
acpi_hest_get_payload(gdata);
|
||||
|
||||
cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec);
|
||||
} else {
|
||||
void *err = acpi_hest_get_payload(gdata);
|
||||
|
||||
|
||||
+33
-47
@@ -837,54 +837,37 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL);
|
||||
|
||||
/*
|
||||
* General Media Event Record
|
||||
* CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
|
||||
*/
|
||||
static const uuid_t gen_media_event_uuid =
|
||||
UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
|
||||
0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6);
|
||||
|
||||
/*
|
||||
* DRAM Event Record
|
||||
* CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
|
||||
*/
|
||||
static const uuid_t dram_event_uuid =
|
||||
UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
|
||||
0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24);
|
||||
|
||||
/*
|
||||
* Memory Module Event Record
|
||||
* CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
|
||||
*/
|
||||
static const uuid_t mem_mod_event_uuid =
|
||||
UUID_INIT(0xfe927475, 0xdd59, 0x4339,
|
||||
0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74);
|
||||
|
||||
static void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
|
||||
enum cxl_event_log_type type,
|
||||
struct cxl_event_record_raw *record)
|
||||
void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
|
||||
enum cxl_event_log_type type,
|
||||
enum cxl_event_type event_type,
|
||||
const uuid_t *uuid, union cxl_event *evt)
|
||||
{
|
||||
uuid_t *id = &record->hdr.id;
|
||||
if (event_type == CXL_CPER_EVENT_GEN_MEDIA)
|
||||
trace_cxl_general_media(cxlmd, type, &evt->gen_media);
|
||||
else if (event_type == CXL_CPER_EVENT_DRAM)
|
||||
trace_cxl_dram(cxlmd, type, &evt->dram);
|
||||
else if (event_type == CXL_CPER_EVENT_MEM_MODULE)
|
||||
trace_cxl_memory_module(cxlmd, type, &evt->mem_module);
|
||||
else
|
||||
trace_cxl_generic_event(cxlmd, type, uuid, &evt->generic);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, CXL);
|
||||
|
||||
if (uuid_equal(id, &gen_media_event_uuid)) {
|
||||
struct cxl_event_gen_media *rec =
|
||||
(struct cxl_event_gen_media *)record;
|
||||
static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd,
|
||||
enum cxl_event_log_type type,
|
||||
struct cxl_event_record_raw *record)
|
||||
{
|
||||
enum cxl_event_type ev_type = CXL_CPER_EVENT_GENERIC;
|
||||
const uuid_t *uuid = &record->id;
|
||||
|
||||
trace_cxl_general_media(cxlmd, type, rec);
|
||||
} else if (uuid_equal(id, &dram_event_uuid)) {
|
||||
struct cxl_event_dram *rec = (struct cxl_event_dram *)record;
|
||||
if (uuid_equal(uuid, &CXL_EVENT_GEN_MEDIA_UUID))
|
||||
ev_type = CXL_CPER_EVENT_GEN_MEDIA;
|
||||
else if (uuid_equal(uuid, &CXL_EVENT_DRAM_UUID))
|
||||
ev_type = CXL_CPER_EVENT_DRAM;
|
||||
else if (uuid_equal(uuid, &CXL_EVENT_MEM_MODULE_UUID))
|
||||
ev_type = CXL_CPER_EVENT_MEM_MODULE;
|
||||
|
||||
trace_cxl_dram(cxlmd, type, rec);
|
||||
} else if (uuid_equal(id, &mem_mod_event_uuid)) {
|
||||
struct cxl_event_mem_module *rec =
|
||||
(struct cxl_event_mem_module *)record;
|
||||
|
||||
trace_cxl_memory_module(cxlmd, type, rec);
|
||||
} else {
|
||||
/* For unknown record types print just the header */
|
||||
trace_cxl_generic_event(cxlmd, type, record);
|
||||
}
|
||||
cxl_event_trace_record(cxlmd, type, ev_type, uuid, &record->event);
|
||||
}
|
||||
|
||||
static int cxl_clear_event_record(struct cxl_memdev_state *mds,
|
||||
@@ -927,7 +910,10 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds,
|
||||
*/
|
||||
i = 0;
|
||||
for (cnt = 0; cnt < total; cnt++) {
|
||||
payload->handles[i++] = get_pl->records[cnt].hdr.handle;
|
||||
struct cxl_event_record_raw *raw = &get_pl->records[cnt];
|
||||
struct cxl_event_generic *gen = &raw->event.generic;
|
||||
|
||||
payload->handles[i++] = gen->hdr.handle;
|
||||
dev_dbg(mds->cxlds.dev, "Event log '%d': Clearing %u\n", log,
|
||||
le16_to_cpu(payload->handles[i]));
|
||||
|
||||
@@ -992,8 +978,8 @@ static void cxl_mem_get_records_log(struct cxl_memdev_state *mds,
|
||||
break;
|
||||
|
||||
for (i = 0; i < nr_rec; i++)
|
||||
cxl_event_trace_record(cxlmd, type,
|
||||
&payload->records[i]);
|
||||
__cxl_event_trace_record(cxlmd, type,
|
||||
&payload->records[i]);
|
||||
|
||||
if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW)
|
||||
trace_cxl_overflow(cxlmd, type, payload);
|
||||
|
||||
@@ -181,6 +181,7 @@ TRACE_EVENT(cxl_overflow,
|
||||
* 1) Add CXL_EVT_TP_entry to TP_STRUCT__entry
|
||||
* 2) Use CXL_EVT_TP_fast_assign within TP_fast_assign;
|
||||
* pass the dev, log, and CXL event header
|
||||
* NOTE: The uuid must be assigned by the specific trace event
|
||||
* 3) Use CXL_EVT_TP_printk() instead of TP_printk()
|
||||
*
|
||||
* See the generic_event tracepoint as an example.
|
||||
@@ -203,7 +204,6 @@ TRACE_EVENT(cxl_overflow,
|
||||
__assign_str(host, dev_name((cxlmd)->dev.parent)); \
|
||||
__entry->log = (l); \
|
||||
__entry->serial = (cxlmd)->cxlds->serial; \
|
||||
memcpy(&__entry->hdr_uuid, &(hdr).id, sizeof(uuid_t)); \
|
||||
__entry->hdr_length = (hdr).length; \
|
||||
__entry->hdr_flags = get_unaligned_le24((hdr).flags); \
|
||||
__entry->hdr_handle = le16_to_cpu((hdr).handle); \
|
||||
@@ -225,9 +225,9 @@ TRACE_EVENT(cxl_overflow,
|
||||
TRACE_EVENT(cxl_generic_event,
|
||||
|
||||
TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log,
|
||||
struct cxl_event_record_raw *rec),
|
||||
const uuid_t *uuid, struct cxl_event_generic *gen_rec),
|
||||
|
||||
TP_ARGS(cxlmd, log, rec),
|
||||
TP_ARGS(cxlmd, log, uuid, gen_rec),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
CXL_EVT_TP_entry
|
||||
@@ -235,8 +235,9 @@ TRACE_EVENT(cxl_generic_event,
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
|
||||
memcpy(__entry->data, &rec->data, CXL_EVENT_RECORD_DATA_LENGTH);
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, gen_rec->hdr);
|
||||
memcpy(&__entry->hdr_uuid, uuid, sizeof(uuid_t));
|
||||
memcpy(__entry->data, gen_rec->data, CXL_EVENT_RECORD_DATA_LENGTH);
|
||||
),
|
||||
|
||||
CXL_EVT_TP_printk("%s",
|
||||
@@ -337,6 +338,7 @@ TRACE_EVENT(cxl_general_media,
|
||||
|
||||
TP_fast_assign(
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
|
||||
memcpy(&__entry->hdr_uuid, &CXL_EVENT_GEN_MEDIA_UUID, sizeof(uuid_t));
|
||||
|
||||
/* General Media */
|
||||
__entry->dpa = le64_to_cpu(rec->phys_addr);
|
||||
@@ -423,6 +425,7 @@ TRACE_EVENT(cxl_dram,
|
||||
|
||||
TP_fast_assign(
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
|
||||
memcpy(&__entry->hdr_uuid, &CXL_EVENT_DRAM_UUID, sizeof(uuid_t));
|
||||
|
||||
/* DRAM */
|
||||
__entry->dpa = le64_to_cpu(rec->phys_addr);
|
||||
@@ -570,6 +573,7 @@ TRACE_EVENT(cxl_memory_module,
|
||||
|
||||
TP_fast_assign(
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
|
||||
memcpy(&__entry->hdr_uuid, &CXL_EVENT_MEM_MODULE_UUID, sizeof(uuid_t));
|
||||
|
||||
/* Memory Module Event */
|
||||
__entry->event_type = rec->event_type;
|
||||
|
||||
+25
-85
@@ -6,6 +6,7 @@
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/rcuwait.h>
|
||||
#include <linux/cxl-event.h>
|
||||
#include <linux/node.h>
|
||||
#include "cxl.h"
|
||||
|
||||
@@ -602,25 +603,28 @@ struct cxl_mbox_identify {
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Common Event Record Format
|
||||
* CXL rev 3.0 section 8.2.9.2.1; Table 8-42
|
||||
* General Media Event Record UUID
|
||||
* CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
|
||||
*/
|
||||
struct cxl_event_record_hdr {
|
||||
uuid_t id;
|
||||
u8 length;
|
||||
u8 flags[3];
|
||||
__le16 handle;
|
||||
__le16 related_handle;
|
||||
__le64 timestamp;
|
||||
u8 maint_op_class;
|
||||
u8 reserved[15];
|
||||
} __packed;
|
||||
#define CXL_EVENT_GEN_MEDIA_UUID \
|
||||
UUID_INIT(0xfbcd0a77, 0xc260, 0x417f, 0x85, 0xa9, 0x08, 0x8b, 0x16, \
|
||||
0x21, 0xeb, 0xa6)
|
||||
|
||||
#define CXL_EVENT_RECORD_DATA_LENGTH 0x50
|
||||
struct cxl_event_record_raw {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
u8 data[CXL_EVENT_RECORD_DATA_LENGTH];
|
||||
} __packed;
|
||||
/*
|
||||
* DRAM Event Record UUID
|
||||
* CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
|
||||
*/
|
||||
#define CXL_EVENT_DRAM_UUID \
|
||||
UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab, 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, \
|
||||
0x5c, 0x96, 0x24)
|
||||
|
||||
/*
|
||||
* Memory Module Event Record UUID
|
||||
* CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
|
||||
*/
|
||||
#define CXL_EVENT_MEM_MODULE_UUID \
|
||||
UUID_INIT(0xfe927475, 0xdd59, 0x4339, 0xa5, 0x86, 0x79, 0xba, 0xb1, \
|
||||
0x13, 0xb7, 0x74)
|
||||
|
||||
/*
|
||||
* Get Event Records output payload
|
||||
@@ -663,74 +667,6 @@ struct cxl_mbox_clear_event_payload {
|
||||
} __packed;
|
||||
#define CXL_CLEAR_EVENT_MAX_HANDLES U8_MAX
|
||||
|
||||
/*
|
||||
* General Media Event Record
|
||||
* CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
|
||||
*/
|
||||
#define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10
|
||||
struct cxl_event_gen_media {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
__le64 phys_addr;
|
||||
u8 descriptor;
|
||||
u8 type;
|
||||
u8 transaction_type;
|
||||
u8 validity_flags[2];
|
||||
u8 channel;
|
||||
u8 rank;
|
||||
u8 device[3];
|
||||
u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE];
|
||||
u8 reserved[46];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* DRAM Event Record - DER
|
||||
* CXL rev 3.0 section 8.2.9.2.1.2; Table 3-44
|
||||
*/
|
||||
#define CXL_EVENT_DER_CORRECTION_MASK_SIZE 0x20
|
||||
struct cxl_event_dram {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
__le64 phys_addr;
|
||||
u8 descriptor;
|
||||
u8 type;
|
||||
u8 transaction_type;
|
||||
u8 validity_flags[2];
|
||||
u8 channel;
|
||||
u8 rank;
|
||||
u8 nibble_mask[3];
|
||||
u8 bank_group;
|
||||
u8 bank;
|
||||
u8 row[3];
|
||||
u8 column[2];
|
||||
u8 correction_mask[CXL_EVENT_DER_CORRECTION_MASK_SIZE];
|
||||
u8 reserved[0x17];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Get Health Info Record
|
||||
* CXL rev 3.0 section 8.2.9.8.3.1; Table 8-100
|
||||
*/
|
||||
struct cxl_get_health_info {
|
||||
u8 health_status;
|
||||
u8 media_status;
|
||||
u8 add_status;
|
||||
u8 life_used;
|
||||
u8 device_temp[2];
|
||||
u8 dirty_shutdown_cnt[4];
|
||||
u8 cor_vol_err_cnt[4];
|
||||
u8 cor_per_err_cnt[4];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Memory Module Event Record
|
||||
* CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
|
||||
*/
|
||||
struct cxl_event_mem_module {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
u8 event_type;
|
||||
struct cxl_get_health_info info;
|
||||
u8 reserved[0x3d];
|
||||
} __packed;
|
||||
|
||||
struct cxl_mbox_get_partition_info {
|
||||
__le64 active_volatile_cap;
|
||||
__le64 active_persistent_cap;
|
||||
@@ -888,6 +824,10 @@ void set_exclusive_cxl_commands(struct cxl_memdev_state *mds,
|
||||
void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
|
||||
unsigned long *cmds);
|
||||
void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status);
|
||||
void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
|
||||
enum cxl_event_log_type type,
|
||||
enum cxl_event_type event_type,
|
||||
const uuid_t *uuid, union cxl_event *evt);
|
||||
int cxl_set_timestamp(struct cxl_memdev_state *mds);
|
||||
int cxl_poison_state_init(struct cxl_memdev_state *mds);
|
||||
int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len,
|
||||
|
||||
+57
-1
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
|
||||
#include <asm-generic/unaligned.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/module.h>
|
||||
@@ -969,6 +970,61 @@ static struct pci_driver cxl_pci_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
#define CXL_EVENT_HDR_FLAGS_REC_SEVERITY GENMASK(1, 0)
|
||||
static void cxl_cper_event_call(enum cxl_event_type ev_type,
|
||||
struct cxl_cper_event_rec *rec)
|
||||
{
|
||||
struct cper_cxl_event_devid *device_id = &rec->hdr.device_id;
|
||||
struct pci_dev *pdev __free(pci_dev_put) = NULL;
|
||||
enum cxl_event_log_type log_type;
|
||||
struct cxl_dev_state *cxlds;
|
||||
unsigned int devfn;
|
||||
u32 hdr_flags;
|
||||
|
||||
devfn = PCI_DEVFN(device_id->device_num, device_id->func_num);
|
||||
pdev = pci_get_domain_bus_and_slot(device_id->segment_num,
|
||||
device_id->bus_num, devfn);
|
||||
if (!pdev)
|
||||
return;
|
||||
|
||||
guard(pci_dev)(pdev);
|
||||
if (pdev->driver != &cxl_pci_driver)
|
||||
return;
|
||||
|
||||
cxlds = pci_get_drvdata(pdev);
|
||||
if (!cxlds)
|
||||
return;
|
||||
|
||||
/* Fabricate a log type */
|
||||
hdr_flags = get_unaligned_le24(rec->event.generic.hdr.flags);
|
||||
log_type = FIELD_GET(CXL_EVENT_HDR_FLAGS_REC_SEVERITY, hdr_flags);
|
||||
|
||||
cxl_event_trace_record(cxlds->cxlmd, log_type, ev_type,
|
||||
&uuid_null, &rec->event);
|
||||
}
|
||||
|
||||
static int __init cxl_pci_driver_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = cxl_cper_register_callback(cxl_cper_event_call);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_register_driver(&cxl_pci_driver);
|
||||
if (rc)
|
||||
cxl_cper_unregister_callback(cxl_cper_event_call);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit cxl_pci_driver_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cxl_pci_driver);
|
||||
cxl_cper_unregister_callback(cxl_cper_event_call);
|
||||
}
|
||||
|
||||
module_init(cxl_pci_driver_init);
|
||||
module_exit(cxl_pci_driver_exit);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
module_pci_driver(cxl_pci_driver);
|
||||
MODULE_IMPORT_NS(CXL);
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright(c) 2023 Intel Corporation. */
|
||||
#ifndef _LINUX_CXL_EVENT_H
|
||||
#define _LINUX_CXL_EVENT_H
|
||||
|
||||
/*
|
||||
* Common Event Record Format
|
||||
* CXL rev 3.0 section 8.2.9.2.1; Table 8-42
|
||||
*/
|
||||
struct cxl_event_record_hdr {
|
||||
u8 length;
|
||||
u8 flags[3];
|
||||
__le16 handle;
|
||||
__le16 related_handle;
|
||||
__le64 timestamp;
|
||||
u8 maint_op_class;
|
||||
u8 reserved[15];
|
||||
} __packed;
|
||||
|
||||
#define CXL_EVENT_RECORD_DATA_LENGTH 0x50
|
||||
struct cxl_event_generic {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
u8 data[CXL_EVENT_RECORD_DATA_LENGTH];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* General Media Event Record
|
||||
* CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
|
||||
*/
|
||||
#define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10
|
||||
struct cxl_event_gen_media {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
__le64 phys_addr;
|
||||
u8 descriptor;
|
||||
u8 type;
|
||||
u8 transaction_type;
|
||||
u8 validity_flags[2];
|
||||
u8 channel;
|
||||
u8 rank;
|
||||
u8 device[3];
|
||||
u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE];
|
||||
u8 reserved[46];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* DRAM Event Record - DER
|
||||
* CXL rev 3.0 section 8.2.9.2.1.2; Table 3-44
|
||||
*/
|
||||
#define CXL_EVENT_DER_CORRECTION_MASK_SIZE 0x20
|
||||
struct cxl_event_dram {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
__le64 phys_addr;
|
||||
u8 descriptor;
|
||||
u8 type;
|
||||
u8 transaction_type;
|
||||
u8 validity_flags[2];
|
||||
u8 channel;
|
||||
u8 rank;
|
||||
u8 nibble_mask[3];
|
||||
u8 bank_group;
|
||||
u8 bank;
|
||||
u8 row[3];
|
||||
u8 column[2];
|
||||
u8 correction_mask[CXL_EVENT_DER_CORRECTION_MASK_SIZE];
|
||||
u8 reserved[0x17];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Get Health Info Record
|
||||
* CXL rev 3.0 section 8.2.9.8.3.1; Table 8-100
|
||||
*/
|
||||
struct cxl_get_health_info {
|
||||
u8 health_status;
|
||||
u8 media_status;
|
||||
u8 add_status;
|
||||
u8 life_used;
|
||||
u8 device_temp[2];
|
||||
u8 dirty_shutdown_cnt[4];
|
||||
u8 cor_vol_err_cnt[4];
|
||||
u8 cor_per_err_cnt[4];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Memory Module Event Record
|
||||
* CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
|
||||
*/
|
||||
struct cxl_event_mem_module {
|
||||
struct cxl_event_record_hdr hdr;
|
||||
u8 event_type;
|
||||
struct cxl_get_health_info info;
|
||||
u8 reserved[0x3d];
|
||||
} __packed;
|
||||
|
||||
union cxl_event {
|
||||
struct cxl_event_generic generic;
|
||||
struct cxl_event_gen_media gen_media;
|
||||
struct cxl_event_dram dram;
|
||||
struct cxl_event_mem_module mem_module;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Common Event Record Format; in event logs
|
||||
* CXL rev 3.0 section 8.2.9.2.1; Table 8-42
|
||||
*/
|
||||
struct cxl_event_record_raw {
|
||||
uuid_t id;
|
||||
union cxl_event event;
|
||||
} __packed;
|
||||
|
||||
enum cxl_event_type {
|
||||
CXL_CPER_EVENT_GENERIC,
|
||||
CXL_CPER_EVENT_GEN_MEDIA,
|
||||
CXL_CPER_EVENT_DRAM,
|
||||
CXL_CPER_EVENT_MEM_MODULE,
|
||||
};
|
||||
|
||||
#define CPER_CXL_DEVICE_ID_VALID BIT(0)
|
||||
#define CPER_CXL_DEVICE_SN_VALID BIT(1)
|
||||
#define CPER_CXL_COMP_EVENT_LOG_VALID BIT(2)
|
||||
struct cxl_cper_event_rec {
|
||||
struct {
|
||||
u32 length;
|
||||
u64 validation_bits;
|
||||
struct cper_cxl_event_devid {
|
||||
u16 vendor_id;
|
||||
u16 device_id;
|
||||
u8 func_num;
|
||||
u8 device_num;
|
||||
u8 bus_num;
|
||||
u16 segment_num;
|
||||
u16 slot_num; /* bits 2:0 reserved */
|
||||
u8 reserved;
|
||||
} __packed device_id;
|
||||
struct cper_cxl_event_sn {
|
||||
u32 lower_dw;
|
||||
u32 upper_dw;
|
||||
} __packed dev_serial_num;
|
||||
} __packed hdr;
|
||||
|
||||
union cxl_event event;
|
||||
} __packed;
|
||||
|
||||
typedef void (*cxl_cper_callback)(enum cxl_event_type type,
|
||||
struct cxl_cper_event_rec *rec);
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI_GHES
|
||||
int cxl_cper_register_callback(cxl_cper_callback callback);
|
||||
int cxl_cper_unregister_callback(cxl_cper_callback callback);
|
||||
#else
|
||||
static inline int cxl_cper_register_callback(cxl_cper_callback callback)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int cxl_cper_unregister_callback(cxl_cper_callback callback)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_CXL_EVENT_H */
|
||||
@@ -1170,6 +1170,7 @@ int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
|
||||
u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
|
||||
struct pci_dev *pci_dev_get(struct pci_dev *dev);
|
||||
void pci_dev_put(struct pci_dev *dev);
|
||||
DEFINE_FREE(pci_dev_put, struct pci_dev *, if (_T) pci_dev_put(_T))
|
||||
void pci_remove_bus(struct pci_bus *b);
|
||||
void pci_stop_and_remove_bus_device(struct pci_dev *dev);
|
||||
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev);
|
||||
@@ -1875,6 +1876,7 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
|
||||
void pci_dev_lock(struct pci_dev *dev);
|
||||
int pci_dev_trylock(struct pci_dev *dev);
|
||||
void pci_dev_unlock(struct pci_dev *dev);
|
||||
DEFINE_GUARD(pci_dev, struct pci_dev *, pci_dev_lock(_T), pci_dev_unlock(_T))
|
||||
|
||||
/*
|
||||
* PCI domain support. Sometimes called PCI segment (eg by ACPI),
|
||||
|
||||
@@ -251,7 +251,8 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd)
|
||||
for (i = 0; i < CXL_TEST_EVENT_CNT && !event_log_empty(log); i++) {
|
||||
memcpy(&pl->records[i], event_get_current(log),
|
||||
sizeof(pl->records[i]));
|
||||
pl->records[i].hdr.handle = event_get_cur_event_handle(log);
|
||||
pl->records[i].event.generic.hdr.handle =
|
||||
event_get_cur_event_handle(log);
|
||||
log->cur_idx++;
|
||||
}
|
||||
|
||||
@@ -337,87 +338,109 @@ static void cxl_mock_event_trigger(struct device *dev)
|
||||
}
|
||||
|
||||
struct cxl_event_record_raw maint_needed = {
|
||||
.hdr = {
|
||||
.id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB,
|
||||
0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
|
||||
.length = sizeof(struct cxl_event_record_raw),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0xa5b6),
|
||||
.id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB,
|
||||
0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
|
||||
.event.generic = {
|
||||
.hdr = {
|
||||
.length = sizeof(struct cxl_event_record_raw),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0xa5b6),
|
||||
},
|
||||
.data = { 0xDE, 0xAD, 0xBE, 0xEF },
|
||||
},
|
||||
.data = { 0xDE, 0xAD, 0xBE, 0xEF },
|
||||
};
|
||||
|
||||
struct cxl_event_record_raw hardware_replace = {
|
||||
.hdr = {
|
||||
.id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E,
|
||||
0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
|
||||
.length = sizeof(struct cxl_event_record_raw),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0xb6a5),
|
||||
.id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E,
|
||||
0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
|
||||
.event.generic = {
|
||||
.hdr = {
|
||||
.length = sizeof(struct cxl_event_record_raw),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0xb6a5),
|
||||
},
|
||||
.data = { 0xDE, 0xAD, 0xBE, 0xEF },
|
||||
},
|
||||
.data = { 0xDE, 0xAD, 0xBE, 0xEF },
|
||||
};
|
||||
|
||||
struct cxl_event_gen_media gen_media = {
|
||||
.hdr = {
|
||||
.id = UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
|
||||
0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6),
|
||||
.length = sizeof(struct cxl_event_gen_media),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0),
|
||||
struct cxl_test_gen_media {
|
||||
uuid_t id;
|
||||
struct cxl_event_gen_media rec;
|
||||
} __packed;
|
||||
|
||||
struct cxl_test_gen_media gen_media = {
|
||||
.id = CXL_EVENT_GEN_MEDIA_UUID,
|
||||
.rec = {
|
||||
.hdr = {
|
||||
.length = sizeof(struct cxl_test_gen_media),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0),
|
||||
},
|
||||
.phys_addr = cpu_to_le64(0x2000),
|
||||
.descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT,
|
||||
.type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR,
|
||||
.transaction_type = CXL_GMER_TRANS_HOST_WRITE,
|
||||
/* .validity_flags = <set below> */
|
||||
.channel = 1,
|
||||
.rank = 30
|
||||
},
|
||||
.phys_addr = cpu_to_le64(0x2000),
|
||||
.descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT,
|
||||
.type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR,
|
||||
.transaction_type = CXL_GMER_TRANS_HOST_WRITE,
|
||||
/* .validity_flags = <set below> */
|
||||
.channel = 1,
|
||||
.rank = 30
|
||||
};
|
||||
|
||||
struct cxl_event_dram dram = {
|
||||
.hdr = {
|
||||
.id = UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
|
||||
0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24),
|
||||
.length = sizeof(struct cxl_event_dram),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0),
|
||||
struct cxl_test_dram {
|
||||
uuid_t id;
|
||||
struct cxl_event_dram rec;
|
||||
} __packed;
|
||||
|
||||
struct cxl_test_dram dram = {
|
||||
.id = CXL_EVENT_DRAM_UUID,
|
||||
.rec = {
|
||||
.hdr = {
|
||||
.length = sizeof(struct cxl_test_dram),
|
||||
.flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED,
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0),
|
||||
},
|
||||
.phys_addr = cpu_to_le64(0x8000),
|
||||
.descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT,
|
||||
.type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR,
|
||||
.transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB,
|
||||
/* .validity_flags = <set below> */
|
||||
.channel = 1,
|
||||
.bank_group = 5,
|
||||
.bank = 2,
|
||||
.column = {0xDE, 0xAD},
|
||||
},
|
||||
.phys_addr = cpu_to_le64(0x8000),
|
||||
.descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT,
|
||||
.type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR,
|
||||
.transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB,
|
||||
/* .validity_flags = <set below> */
|
||||
.channel = 1,
|
||||
.bank_group = 5,
|
||||
.bank = 2,
|
||||
.column = {0xDE, 0xAD},
|
||||
};
|
||||
|
||||
struct cxl_event_mem_module mem_module = {
|
||||
.hdr = {
|
||||
.id = UUID_INIT(0xfe927475, 0xdd59, 0x4339,
|
||||
0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74),
|
||||
.length = sizeof(struct cxl_event_mem_module),
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0),
|
||||
struct cxl_test_mem_module {
|
||||
uuid_t id;
|
||||
struct cxl_event_mem_module rec;
|
||||
} __packed;
|
||||
|
||||
struct cxl_test_mem_module mem_module = {
|
||||
.id = CXL_EVENT_MEM_MODULE_UUID,
|
||||
.rec = {
|
||||
.hdr = {
|
||||
.length = sizeof(struct cxl_test_mem_module),
|
||||
/* .handle = Set dynamically */
|
||||
.related_handle = cpu_to_le16(0),
|
||||
},
|
||||
.event_type = CXL_MMER_TEMP_CHANGE,
|
||||
.info = {
|
||||
.health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED,
|
||||
.media_status = CXL_DHI_MS_ALL_DATA_LOST,
|
||||
.add_status = (CXL_DHI_AS_CRITICAL << 2) |
|
||||
(CXL_DHI_AS_WARNING << 4) |
|
||||
(CXL_DHI_AS_WARNING << 5),
|
||||
.device_temp = { 0xDE, 0xAD},
|
||||
.dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef },
|
||||
.cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
|
||||
.cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
|
||||
}
|
||||
},
|
||||
.event_type = CXL_MMER_TEMP_CHANGE,
|
||||
.info = {
|
||||
.health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED,
|
||||
.media_status = CXL_DHI_MS_ALL_DATA_LOST,
|
||||
.add_status = (CXL_DHI_AS_CRITICAL << 2) |
|
||||
(CXL_DHI_AS_WARNING << 4) |
|
||||
(CXL_DHI_AS_WARNING << 5),
|
||||
.device_temp = { 0xDE, 0xAD},
|
||||
.dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef },
|
||||
.cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
|
||||
.cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
|
||||
}
|
||||
};
|
||||
|
||||
static int mock_set_timestamp(struct cxl_dev_state *cxlds,
|
||||
@@ -439,11 +462,11 @@ static int mock_set_timestamp(struct cxl_dev_state *cxlds,
|
||||
static void cxl_mock_add_event_logs(struct mock_event_store *mes)
|
||||
{
|
||||
put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK,
|
||||
&gen_media.validity_flags);
|
||||
&gen_media.rec.validity_flags);
|
||||
|
||||
put_unaligned_le16(CXL_DER_VALID_CHANNEL | CXL_DER_VALID_BANK_GROUP |
|
||||
CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN,
|
||||
&dram.validity_flags);
|
||||
&dram.rec.validity_flags);
|
||||
|
||||
mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed);
|
||||
mes_add_event(mes, CXL_EVENT_TYPE_INFO,
|
||||
|
||||
Reference in New Issue
Block a user