From: YiPeng Chai <[email protected]>

Restructure ras cper to improve extensibility, making it straightforward
to add and handle new cper event types.

Signed-off-by: YiPeng Chai <[email protected]>
Reviewed-by: Hawking Zhang <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/ras/core/cmd.c            |   2 +-
 drivers/gpu/drm/amd/ras/core/core.c           |   6 +-
 drivers/gpu/drm/amd/ras/core/ras.h            |   1 +
 drivers/gpu/drm/amd/ras/core/ras_cper.c       | 532 +++++++++++-------
 drivers/gpu/drm/amd/ras/core/ras_cper.h       |  62 +-
 .../drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c |   2 +-
 6 files changed, 395 insertions(+), 210 deletions(-)

diff --git a/drivers/gpu/drm/amd/ras/core/cmd.c 
b/drivers/gpu/drm/amd/ras/core/cmd.c
index 2c328116f339c..ea5f6194d9863 100644
--- a/drivers/gpu/drm/amd/ras/core/cmd.c
+++ b/drivers/gpu/drm/amd/ras/core/cmd.c
@@ -229,7 +229,7 @@ static int ras_cmd_get_cper_records(struct ras_core_context 
*ras_core,
                count = ras_log_ring_get_batch_records(ras_core, batch_id, 
trace,
                                        trace_count);
                if (count > 0) {
-                       ret = ras_cper_generate_cper(ras_core, trace, count,
+                       ret = ras_cper_generate_batch_cper(ras_core, trace, 
count,
                                        &buf_ptr[offset], req->buf_size - 
offset, &real_data_len);
                        if (ret)
                                break;
diff --git a/drivers/gpu/drm/amd/ras/core/core.c 
b/drivers/gpu/drm/amd/ras/core/core.c
index e03f6889e1db5..d833e7de16d9e 100644
--- a/drivers/gpu/drm/amd/ras/core/core.c
+++ b/drivers/gpu/drm/amd/ras/core/core.c
@@ -408,6 +408,10 @@ int ras_core_sw_init(struct ras_core_context *ras_core)
        if (ret)
                return ret;
 
+       ret = ras_cper_sw_init(ras_core);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
@@ -424,7 +428,7 @@ int ras_core_sw_fini(struct ras_core_context *ras_core)
        ras_aca_sw_fini(ras_core);
        ras_eeprom_mgr_sw_fini(ras_core);
        ras_mce_sw_fini(ras_core);
-
+       ras_cper_sw_fini(ras_core);
        return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/ras/core/ras.h 
b/drivers/gpu/drm/amd/ras/core/ras.h
index 6ae23a677f57b..464ad7381c5c0 100644
--- a/drivers/gpu/drm/amd/ras/core/ras.h
+++ b/drivers/gpu/drm/amd/ras/core/ras.h
@@ -402,6 +402,7 @@ struct ras_core_context {
        struct ras_process ras_proc;
        struct ras_log_ring ras_log_ring;
        struct ras_mce ras_mce;
+       struct ras_cper ras_cper;
 
        const struct ras_sys_func *sys_fn;
 
diff --git a/drivers/gpu/drm/amd/ras/core/ras_cper.c 
b/drivers/gpu/drm/amd/ras/core/ras_cper.c
index bb60fcd283a87..03240715b4aaf 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_cper.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_cper.c
@@ -27,12 +27,8 @@
 #include "ras_cper.h"
 #define ns_to_seconds(ns)   div_u64(ns, NSEC_PER_SEC)
 
-static const struct ras_cper_guid MCE  = CPER_NOTIFY__MCE;
-static const struct ras_cper_guid CMC  = CPER_NOTIFY__CMC;
-static const struct ras_cper_guid BOOT = BOOT__TYPE;
-
-static const struct ras_cper_guid CRASHDUMP = GPU__CRASHDUMP;
-static const struct ras_cper_guid RUNTIME = GPU__NONSTANDARD_ERROR;
+static int ras_cper_get_profile(struct ras_core_context *ras_core,
+               enum ras_log_event event, struct ras_cper_profile **profile);
 
 static void cper_get_timestamp(struct ras_core_context *ras_core,
                struct ras_cper_timestamp *timestamp, uint64_t 
utc_second_timestamp)
@@ -51,8 +47,8 @@ static void cper_get_timestamp(struct ras_core_context 
*ras_core,
 }
 
 static void fill_section_hdr(struct ras_core_context *ras_core,
-                               struct cper_section_hdr *hdr, enum 
ras_cper_type type,
-                               enum ras_cper_severity sev, struct ras_log_info 
*trace)
+               struct cper_section_hdr *hdr, struct ras_cper_guid notify_type,
+               enum ras_cper_severity sev, struct ras_log_info *log)
 {
        struct device_system_info dev_info = {0};
        char record_id[32];
@@ -70,10 +66,10 @@ static void fill_section_hdr(struct ras_core_context 
*ras_core,
 
        ras_core_get_device_system_info(ras_core, &dev_info);
 
-       cper_get_timestamp(ras_core, &hdr->timestamp, 
ns_to_seconds(trace->timestamp));
+       cper_get_timestamp(ras_core, &hdr->timestamp, 
ns_to_seconds(log->timestamp));
 
        snprintf(record_id, sizeof(record_id), "%d:%llX", dev_info.socket_id,
-                   RAS_LOG_SEQNO_TO_BATCH_IDX(trace->seqno));
+                   RAS_LOG_SEQNO_TO_BATCH_IDX(log->seqno));
        memcpy(hdr->record_id, record_id, 8);
 
        snprintf(hdr->platform_id, 16, "0x%04X:0x%04X",
@@ -81,40 +77,20 @@ static void fill_section_hdr(struct ras_core_context 
*ras_core,
        /* pmfw version should be part of creator_id according to CPER spec */
        snprintf(hdr->creator_id, 16, "%s", CPER_CREATOR_ID__AMDGPU);
 
-       switch (type) {
-       case RAS_CPER_TYPE_BOOT:
-               hdr->notify_type = BOOT;
-               break;
-       case RAS_CPER_TYPE_FATAL:
-       case RAS_CPER_TYPE_RMA:
-               hdr->notify_type = MCE;
-               break;
-       case RAS_CPER_TYPE_RUNTIME:
-               if (sev == RAS_CPER_SEV_NON_FATAL_CE)
-                       hdr->notify_type = CMC;
-               else
-                       hdr->notify_type = MCE;
-               break;
-       default:
-               RAS_DEV_ERR(ras_core->dev, "Unknown CPER Type\n");
-               break;
-       }
+       hdr->notify_type = notify_type;
 }
 
 static int fill_section_descriptor(struct ras_core_context *ras_core,
-                                       struct cper_section_desc *descriptor,
-                                       enum ras_cper_severity sev,
-                                       struct ras_cper_guid sec_type,
-                                       uint32_t section_offset,
-                                       uint32_t section_length)
+               struct cper_section_desc *descriptor, enum ras_cper_severity 
sev,
+               struct ras_cper_guid sec_type, uint32_t sec_offset, uint32_t 
sec_len)
 {
        struct device_system_info dev_info = {0};
 
        descriptor->revision_minor              = CPER_SEC__MINOR_REV_1;
        descriptor->revision_major              = CPER_SEC__MAJOR_REV_22;
-       descriptor->sec_offset          = section_offset;
-       descriptor->sec_length          = section_length;
-       descriptor->valid_bits.fru_text = 1;
+       descriptor->sec_offset          = sec_offset;
+       descriptor->sec_length          = sec_len;
+       descriptor->valid_bits.fru_text = 1;
        descriptor->flag_bits.primary   = 1;
        descriptor->severity = (sev == RAS_CPER_SEV_RMA ? RAS_CPER_SEV_FATAL_UE 
: sev);
        descriptor->sec_type                    = sec_type;
@@ -132,28 +108,31 @@ static int fill_section_descriptor(struct 
ras_core_context *ras_core,
        return 0;
 }
 
-static int fill_section_fatal(struct ras_core_context *ras_core,
-               struct cper_section_fatal *fatal, struct ras_log_info *trace)
+static int fill_section_fatal(struct ras_core_context *ras_core, void *section,
+               struct ras_log_info *log, enum ras_cper_severity sev)
 {
+       struct cper_section_fatal *fatal = section;
+
        fatal->data.reg_ctx_type = CPER_CTX_TYPE__CRASH;
        fatal->data.reg_arr_size = sizeof(fatal->data.reg);
 
-       fatal->data.reg.status = 
trace->body.aca_reg.regs[RAS_CPER_ACA_REG_STATUS];
-       fatal->data.reg.addr   = 
trace->body.aca_reg.regs[RAS_CPER_ACA_REG_ADDR];
-       fatal->data.reg.ipid   = 
trace->body.aca_reg.regs[RAS_CPER_ACA_REG_IPID];
-       fatal->data.reg.synd   = 
trace->body.aca_reg.regs[RAS_CPER_ACA_REG_SYND];
+       fatal->data.reg.status = 
log->body.aca_reg.regs[RAS_CPER_ACA_REG_STATUS];
+       fatal->data.reg.addr   = log->body.aca_reg.regs[RAS_CPER_ACA_REG_ADDR];
+       fatal->data.reg.ipid   = log->body.aca_reg.regs[RAS_CPER_ACA_REG_IPID];
+       fatal->data.reg.synd   = log->body.aca_reg.regs[RAS_CPER_ACA_REG_SYND];
 
        return 0;
 }
 
-static int fill_section_runtime(struct ras_core_context *ras_core,
-               struct cper_section_runtime *runtime, struct ras_log_info 
*trace,
-               enum ras_cper_severity sev)
+static int fill_section_runtime(struct ras_core_context *ras_core, void 
*section,
+               struct ras_log_info *log, enum ras_cper_severity sev)
 {
+       struct cper_section_runtime *runtime = section;
+
        runtime->hdr.valid_bits.err_info_cnt = 1;
        runtime->hdr.valid_bits.err_context_cnt = 1;
 
-       runtime->descriptor.error_type = RUNTIME;
+       runtime->descriptor.error_type = GPU__NONSTANDARD_ERROR;
        runtime->descriptor.ms_chk_bits.err_type_valid = 1;
        if (sev == RAS_CPER_SEV_RMA) {
                runtime->descriptor.valid_bits.ms_chk = 1;
@@ -165,26 +144,27 @@ static int fill_section_runtime(struct ras_core_context 
*ras_core,
        runtime->reg.reg_arr_size = sizeof(runtime->reg.reg_dump);
 
        runtime->reg.reg_dump[RAS_CPER_ACA_REG_CTL] =
-                       trace->body.aca_reg.regs[ACA_REG_IDX__CTL];
+                       log->body.aca_reg.regs[ACA_REG_IDX__CTL];
        runtime->reg.reg_dump[RAS_CPER_ACA_REG_STATUS] =
-                       trace->body.aca_reg.regs[ACA_REG_IDX__STATUS];
+                       log->body.aca_reg.regs[ACA_REG_IDX__STATUS];
        runtime->reg.reg_dump[RAS_CPER_ACA_REG_ADDR] =
-                       trace->body.aca_reg.regs[ACA_REG_IDX__ADDR];
+                       log->body.aca_reg.regs[ACA_REG_IDX__ADDR];
        runtime->reg.reg_dump[RAS_CPER_ACA_REG_MISC0] =
-                       trace->body.aca_reg.regs[ACA_REG_IDX__MISC0];
+                       log->body.aca_reg.regs[ACA_REG_IDX__MISC0];
        runtime->reg.reg_dump[RAS_CPER_ACA_REG_CONFIG] =
-                       trace->body.aca_reg.regs[ACA_REG_IDX__CONFG];
+                       log->body.aca_reg.regs[ACA_REG_IDX__CONFG];
        runtime->reg.reg_dump[RAS_CPER_ACA_REG_IPID] =
-                       trace->body.aca_reg.regs[ACA_REG_IDX__IPID];
+                       log->body.aca_reg.regs[ACA_REG_IDX__IPID];
        runtime->reg.reg_dump[RAS_CPER_ACA_REG_SYND] =
-                       trace->body.aca_reg.regs[ACA_REG_IDX__SYND];
+                       log->body.aca_reg.regs[ACA_REG_IDX__SYND];
 
        return 0;
 }
 
-static int fill_section_boot(struct ras_core_context *ras_core, struct 
cper_section_boot *boot,
-                            struct ras_log_info *log)
+static int fill_section_boot(struct ras_core_context *ras_core, void *section,
+               struct ras_log_info *log, enum ras_cper_severity sev)
 {
+       struct cper_section_boot *boot = section;
        struct ras_boot_err_ctx *ctx = &log->body.boot_err_ctx;
        struct crashdump_boot *data = &boot->data;
 
@@ -196,138 +176,114 @@ static int fill_section_boot(struct ras_core_context 
*ras_core, struct cper_sect
        return 0;
 }
 
-static int cper_generate_runtime_record(struct ras_core_context *ras_core,
-       struct cper_section_hdr *hdr, struct ras_log_info *trace_arr, uint32_t 
arr_num,
-               enum ras_cper_severity sev)
+static int cper_boot_get_severity(struct ras_log_info *log,
+                       enum ras_cper_severity *sev)
 {
-       struct cper_section_desc *descriptor;
-       struct cper_section_runtime *runtime;
-       int i;
-
-       fill_section_hdr(ras_core, hdr, RAS_CPER_TYPE_RUNTIME, sev, 
&trace_arr[0]);
-       hdr->record_length =  RAS_HDR_LEN + ((RAS_SEC_DESC_LEN + 
RAS_NONSTD_SEC_LEN) * arr_num);
-       hdr->sec_cnt = arr_num;
-       for (i = 0; i < arr_num; i++) {
-               descriptor = (struct cper_section_desc *)((uint8_t *)hdr +
-                            RAS_SEC_DESC_OFFSET(i));
-               runtime = (struct cper_section_runtime *)((uint8_t *)hdr +
-                         RAS_NONSTD_SEC_OFFSET(hdr->sec_cnt, i));
-
-               fill_section_descriptor(ras_core, descriptor, sev, RUNTIME,
-                       RAS_NONSTD_SEC_OFFSET(hdr->sec_cnt, i),
-                       sizeof(struct cper_section_runtime));
-               fill_section_runtime(ras_core, runtime, &trace_arr[i], sev);
-       }
-
+       *sev = log->body.boot_err_ctx.error_severity;
        return 0;
 }
 
-static int cper_generate_fatal_record(struct ras_core_context *ras_core,
-       uint8_t *buffer, struct ras_log_info *trace_arr, uint32_t arr_num)
+static int cper_boot_get_sec_type(struct ras_log_info *log, struct 
ras_cper_guid *out)
 {
-       struct ras_cper_fatal_record record = {0};
-       int i = 0;
-
-       for (i = 0; i < arr_num; i++) {
-               fill_section_hdr(ras_core, &record.hdr, RAS_CPER_TYPE_FATAL,
-                                RAS_CPER_SEV_FATAL_UE, &trace_arr[i]);
-               record.hdr.record_length =  RAS_HDR_LEN + RAS_SEC_DESC_LEN + 
RAS_FATAL_SEC_LEN;
-               record.hdr.sec_cnt = 1;
-
-               fill_section_descriptor(ras_core, &record.descriptor, 
RAS_CPER_SEV_FATAL_UE,
-                                       CRASHDUMP, offsetof(struct 
ras_cper_fatal_record, fatal),
-                                       sizeof(struct cper_section_fatal));
-
-               fill_section_fatal(ras_core, &record.fatal, &trace_arr[i]);
+       memcpy(out, &log->body.boot_err_ctx.section_type,
+               min(sizeof(*out), sizeof(log->body.boot_err_ctx.section_type)));
+       return 0;
+}
 
-               memcpy(buffer + (i * record.hdr.record_length),
-                               &record, record.hdr.record_length);
-       }
+static uint32_t cper_get_record_size(const struct ras_cper_profile *profile,
+               uint32_t section_count)
+{
+       if (profile->build_record_per_log)
+               return (RAS_HDR_LEN + RAS_SEC_DESC_LEN + profile->section_size) 
*
+                       section_count;
 
-       return 0;
+       return RAS_HDR_LEN +
+               (RAS_SEC_DESC_LEN + profile->section_size) * section_count;
 }
 
-static int cper_generate_boot_record(struct ras_core_context *ras_core, u8 
*buffer,
-                                    struct ras_log_info *trace_arr, u32 
arr_num)
+static int cper_build_single_record(struct ras_core_context *ras_core,
+               struct cper_section_hdr *hdr, const struct ras_cper_profile 
*profile,
+               struct ras_log_info *batch_logs, uint32_t nr_batch_logs)
 {
-       struct ras_cper_boot_record *record;
-       int i;
+       enum ras_cper_severity sev = profile->severity;
+       struct ras_cper_guid sec_type = profile->sec_type;
+       struct ras_cper_guid notify_type = profile->notify_type;
+       struct cper_section_desc *descriptor;
+       uint32_t desc_off, sec_off;
+       void *section;
+       uint32_t i;
 
-       record = kzalloc(sizeof(*record), GFP_KERNEL);
-       if (!record)
-               return -ENOMEM;
+       if (profile->get_severity)
+               profile->get_severity(&batch_logs[0], &sev);
 
-       for (i = 0; i < arr_num; i++) {
-               u32 severity = trace_arr[i].body.boot_err_ctx.error_severity;
-               struct ras_cper_guid section_type;
+       if (profile->get_sec_type)
+               profile->get_sec_type(&batch_logs[0], &sec_type);
 
-               memcpy(&section_type, 
&trace_arr[i].body.boot_err_ctx.section_type,
-                       min(sizeof(section_type),
-                           
sizeof(trace_arr[i].body.boot_err_ctx.section_type)));
+       if (profile->get_notify_type)
+               profile->get_notify_type(&batch_logs[0], &notify_type);
 
-               fill_section_hdr(ras_core, &record->hdr, RAS_CPER_TYPE_BOOT, 
severity,
-                                &trace_arr[i]);
-               record->hdr.record_length = RAS_HDR_LEN + RAS_SEC_DESC_LEN + 
RAS_BOOT_SEC_LEN;
-               record->hdr.sec_cnt = 1;
+       fill_section_hdr(ras_core, hdr, notify_type, sev, &batch_logs[0]);
+       hdr->sec_cnt = nr_batch_logs;
+       hdr->record_length = RAS_HDR_LEN +
+               (RAS_SEC_DESC_LEN + profile->section_size) * nr_batch_logs;
 
-               fill_section_descriptor(ras_core, &record->descriptor, 
severity, section_type,
-                                       offsetof(struct ras_cper_boot_record, 
boot),
-                                       sizeof(struct ras_cper_boot_record));
+       for (i = 0; i < nr_batch_logs; i++) {
+               desc_off = RAS_HDR_LEN + (RAS_SEC_DESC_LEN * i);
+               sec_off  = RAS_HDR_LEN + (RAS_SEC_DESC_LEN * nr_batch_logs) +
+                          (profile->section_size * i);
 
-               fill_section_boot(ras_core, &record->boot, &trace_arr[i]);
+               descriptor = (struct cper_section_desc *)((uint8_t *)hdr + 
desc_off);
+               section = (uint8_t *)hdr + sec_off;
 
-               memcpy(buffer + (i * record->hdr.record_length), record, 
record->hdr.record_length);
+               fill_section_descriptor(ras_core, descriptor, sev,
+                       sec_type, sec_off, profile->section_size);
+
+               profile->fill_section(ras_core, section, &batch_logs[i], sev);
        }
 
-       kfree(record);
        return 0;
 }
 
-static int cper_get_record_size(enum ras_cper_type type, uint16_t 
section_count)
+static int cper_build_multiple_records(struct ras_core_context *ras_core,
+               uint8_t *buffer, const struct ras_cper_profile *profile,
+               struct ras_log_info *batch_logs, uint32_t nr_batch_logs)
 {
-       int size = 0;
-
-       size += RAS_HDR_LEN;
-       size += (RAS_SEC_DESC_LEN * section_count);
-
-       switch (type) {
-       case RAS_CPER_TYPE_RUNTIME:
-       case RAS_CPER_TYPE_RMA:
-               size += (RAS_NONSTD_SEC_LEN * section_count);
-               break;
-       case RAS_CPER_TYPE_FATAL:
-               size += (RAS_FATAL_SEC_LEN * section_count);
-               size += (RAS_HDR_LEN * (section_count - 1));
-               break;
-       case RAS_CPER_TYPE_BOOT:
-               size += (RAS_BOOT_SEC_LEN * section_count);
-               break;
-       default:
-               /* should never reach here */
-               break;
-       }
+       uint32_t rec_len = RAS_HDR_LEN + RAS_SEC_DESC_LEN + 
profile->section_size;
+       uint32_t i;
 
-       return size;
-}
+       for (i = 0; i < nr_batch_logs; i++) {
+               struct ras_log_info *log = &batch_logs[i];
+               enum ras_cper_severity sev = profile->severity;
+               struct ras_cper_guid sec_type = profile->sec_type;
+               struct ras_cper_guid notify_type = profile->notify_type;
+               struct cper_section_hdr *hdr;
+               struct cper_section_desc *descriptor;
+               void *section;
 
-static enum ras_cper_type cper_ras_log_event_to_cper_type(enum ras_log_event 
event)
-{
-       switch (event) {
-       case RAS_LOG_EVENT_UE:
-               return RAS_CPER_TYPE_FATAL;
-       case RAS_LOG_EVENT_DE:
-       case RAS_LOG_EVENT_CE:
-       case RAS_LOG_EVENT_POISON_CREATION:
-       case RAS_LOG_EVENT_POISON_CONSUMPTION:
-               return RAS_CPER_TYPE_RUNTIME;
-       case RAS_LOG_EVENT_RMA:
-               return RAS_CPER_TYPE_RMA;
-       case RAS_LOG_EVENT_BOOT:
-               return RAS_CPER_TYPE_BOOT;
-       default:
-               /* should never reach here */
-               return RAS_CPER_TYPE_RUNTIME;
+               if (profile->get_severity)
+                       profile->get_severity(log, &sev);
+
+               if (profile->get_sec_type)
+                       profile->get_sec_type(log, &sec_type);
+
+               if (profile->get_notify_type)
+                       profile->get_notify_type(log, &notify_type);
+
+               hdr = (struct cper_section_hdr *)(buffer + (i * rec_len));
+               descriptor = (struct cper_section_desc *)((uint8_t *)hdr + 
RAS_HDR_LEN);
+               section = (uint8_t *)hdr + RAS_HDR_LEN + RAS_SEC_DESC_LEN;
+
+               fill_section_hdr(ras_core, hdr, notify_type, sev, log);
+               hdr->sec_cnt = 1;
+               hdr->record_length = rec_len;
+
+               fill_section_descriptor(ras_core, descriptor, sev, sec_type,
+                       RAS_HDR_LEN + RAS_SEC_DESC_LEN, profile->section_size);
+
+               profile->fill_section(ras_core, section, log, sev);
        }
+
+       return 0;
 }
 
 static enum ras_log_event cper_mce_parse_err_type(struct ras_core_context 
*ras_core,
@@ -350,57 +306,235 @@ static enum ras_log_event cper_mce_parse_err_type(struct 
ras_core_context *ras_c
        return RAS_LOG_EVENT_NONE;
 }
 
-int ras_cper_generate_cper(struct ras_core_context *ras_core,
-               struct ras_log_info *trace_list, uint32_t count,
+int ras_cper_generate_batch_cper(struct ras_core_context *ras_core,
+               struct ras_log_info *batch_logs, uint32_t nr_batch_logs,
                uint8_t *buf, uint32_t buf_len, uint32_t *real_data_len)
 {
-       uint8_t *buffer = buf;
-       uint64_t buf_size = buf_len;
-       int record_size, saved_size = 0;
-       struct cper_section_hdr *hdr;
+       struct ras_cper *cper = &ras_core->ras_cper;
+       struct ras_cper_profile *profile;
+       enum ras_log_event event;
+       uint32_t record_size;
+       int ret = 0;
 
-       if (trace_list[0].event == RAS_LOG_EVENT_MCE) {
+       if (!batch_logs || !nr_batch_logs || !buf || !buf_len || !real_data_len)
+               return -EINVAL;
+
+       *real_data_len = 0;
+
+       event = batch_logs[0].event;
+       if (event == RAS_LOG_EVENT_MCE) {
                struct aca_bank_reg bank = { 0 };
 
                /* MCE is encoded as 1 record each */
-               memcpy(&bank.regs, &trace_list[0].body.aca_reg.regs, 
sizeof(bank.regs));
-               trace_list[0].event = cper_mce_parse_err_type(ras_core, &bank);
+               memcpy(&bank.regs, &batch_logs[0].body.aca_reg.regs, 
sizeof(bank.regs));
+               event = cper_mce_parse_err_type(ras_core, &bank);
+               batch_logs[0].event = event;
        }
 
-       /* All the batch traces share the same event */
-       record_size = cper_get_record_size(
-                       cper_ras_log_event_to_cper_type(trace_list[0].event), 
count);
+       mutex_lock(&cper->profile_mutex);
+       /* All the batch logs share the same event */
+       ret = ras_cper_get_profile(ras_core, event, &profile);
+       if (ret) {
+               RAS_DEV_ERR(ras_core->dev,
+                       "Unprocessed ras log event: %d, ret:%d\n", event, ret);
+               goto out;
+       }
+
+       record_size = cper_get_record_size(profile, nr_batch_logs);
+       if (record_size > buf_len) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
-       if ((record_size + saved_size) > buf_size)
+       memset(buf, 0, record_size);
+
+       if (profile->build_record_per_log)
+               cper_build_multiple_records(ras_core, buf, profile, batch_logs, 
nr_batch_logs);
+       else
+               cper_build_single_record(ras_core,
+                       (struct cper_section_hdr *)buf, profile, batch_logs, 
nr_batch_logs);
+
+       *real_data_len = record_size;
+
+out:
+       mutex_unlock(&cper->profile_mutex);
+       return ret;
+}
+
+static int ras_cper_get_profile(struct ras_core_context *ras_core,
+               enum ras_log_event event, struct ras_cper_profile **profile)
+{
+       struct ras_cper *cper = &ras_core->ras_cper;
+
+       if (!profile || event < 0 || event >= cper->nr_profiles)
+               return -EINVAL;
+
+       if (!cper->profiles)
+               return -EPERM;
+
+       if (!cper->profiles[event].fill_section)
+               return -ENOENT;
+
+       *profile = &cper->profiles[event];
+
+       return 0;
+}
+
+static struct ras_cper_profile ras_ue_profile = {
+       .cper_type        = RAS_CPER_TYPE_FATAL,
+       .severity         = RAS_CPER_SEV_FATAL_UE,
+       .notify_type      = CPER_NOTIFY__MCE,
+       .sec_type         = GPU__CRASHDUMP,
+       .section_size     = sizeof(struct cper_section_fatal),
+       .build_record_per_log = true,
+       .fill_section     = fill_section_fatal,
+};
+
+static struct ras_cper_profile ras_de_profile = {
+       .cper_type        = RAS_CPER_TYPE_RUNTIME,
+       .severity         = RAS_CPER_SEV_NON_FATAL_UE,
+       .notify_type      = CPER_NOTIFY__MCE,
+       .sec_type         = GPU__NONSTANDARD_ERROR,
+       .section_size     = sizeof(struct cper_section_runtime),
+       .build_record_per_log = false,
+       .fill_section     = fill_section_runtime,
+};
+
+static struct ras_cper_profile ras_ce_profile = {
+       .cper_type        = RAS_CPER_TYPE_RUNTIME,
+       .severity         = RAS_CPER_SEV_NON_FATAL_CE,
+       .notify_type      = CPER_NOTIFY__CMC,
+       .sec_type         = GPU__NONSTANDARD_ERROR,
+       .section_size     = sizeof(struct cper_section_runtime),
+       .build_record_per_log = false,
+       .fill_section     = fill_section_runtime,
+};
+
+static struct ras_cper_profile ras_rma_profile = {
+       .cper_type        = RAS_CPER_TYPE_RUNTIME,
+       .severity         = RAS_CPER_SEV_RMA,
+       .notify_type      = CPER_NOTIFY__MCE,
+       .sec_type         = GPU__NONSTANDARD_ERROR,
+       .section_size     = sizeof(struct cper_section_runtime),
+       .build_record_per_log = false,
+       .fill_section     = fill_section_runtime,
+};
+
+static struct ras_cper_profile ras_boot_profile = {
+       .cper_type        = RAS_CPER_TYPE_BOOT,
+       .severity         = RAS_CPER_SEV_FATAL_UE,
+       .notify_type      = BOOT__TYPE,
+       .sec_type         = GPU__CRASHDUMP,
+       .section_size     = sizeof(struct cper_section_boot),
+       .build_record_per_log = true,
+       .get_severity     = cper_boot_get_severity,
+       .get_sec_type     = cper_boot_get_sec_type,
+       .fill_section     = fill_section_boot,
+};
+
+static struct ras_event_profile_map ras_event_profile_maps[] = {
+       {RAS_LOG_EVENT_UE,   &ras_ue_profile},
+       {RAS_LOG_EVENT_DE,   &ras_de_profile},
+       {RAS_LOG_EVENT_CE,   &ras_ce_profile},
+       {RAS_LOG_EVENT_RMA,  &ras_rma_profile},
+       {RAS_LOG_EVENT_BOOT, &ras_boot_profile},
+};
+
+int ras_cper_sw_init(struct ras_core_context *ras_core)
+{
+       struct ras_cper *cper = &ras_core->ras_cper;
+       struct ras_cper_profile *profiles;
+       uint32_t nr_profiles = RAS_LOG_EVENT_COUNT_MAX;
+       int i, ret = 0;
+
+       profiles = kcalloc(nr_profiles, sizeof(*profiles), GFP_KERNEL);
+       if (!profiles)
                return -ENOMEM;
 
-       hdr = (struct cper_section_hdr *)(buffer + saved_size);
-
-       switch (trace_list[0].event) {
-       case RAS_LOG_EVENT_RMA:
-               cper_generate_runtime_record(ras_core, hdr, trace_list, count, 
RAS_CPER_SEV_RMA);
-               break;
-       case RAS_LOG_EVENT_DE:
-               cper_generate_runtime_record(ras_core,
-                       hdr, trace_list, count, RAS_CPER_SEV_NON_FATAL_UE);
-               break;
-       case RAS_LOG_EVENT_CE:
-               cper_generate_runtime_record(ras_core,
-                       hdr, trace_list, count, RAS_CPER_SEV_NON_FATAL_CE);
-               break;
-       case RAS_LOG_EVENT_UE:
-               cper_generate_fatal_record(ras_core, buffer + saved_size, 
trace_list, count);
-               break;
-       case RAS_LOG_EVENT_BOOT:
-               cper_generate_boot_record(ras_core, buffer + saved_size, 
trace_list, count);
-               break;
-       default:
-               RAS_DEV_WARN(ras_core->dev, "Unprocessed trace event: %d\n", 
trace_list[0].event);
-               break;
+       cper->profiles = profiles;
+       cper->nr_profiles = nr_profiles;
+       mutex_init(&cper->profile_mutex);
+
+       for (i = 0; i < ARRAY_SIZE(ras_event_profile_maps); i++) {
+               ret = ras_cper_register_profile(ras_core,
+                               ras_event_profile_maps[i].event,
+                               ras_event_profile_maps[i].profile);
+               if (ret) {
+                       RAS_DEV_ERR(ras_core->dev,
+                               "Failed to register %u profile. ret:%d\n",
+                               ras_event_profile_maps[i].event, ret);
+                       goto out;
+               }
        }
 
-       saved_size += record_size;
+       return 0;
+
+out:
+       ras_cper_sw_fini(ras_core);
+       return ret;
+}
+
+int ras_cper_sw_fini(struct ras_core_context *ras_core)
+{
+       struct ras_cper *cper = &ras_core->ras_cper;
+
+       if (!cper->profiles)
+               return 0;
+
+       kfree(cper->profiles);
+       cper->profiles = NULL;
+       cper->nr_profiles = 0;
+       mutex_destroy(&cper->profile_mutex);
 
-       *real_data_len = saved_size;
        return 0;
 }
+
+int ras_cper_register_profile(struct ras_core_context *ras_core,
+       enum ras_log_event event, struct ras_cper_profile *profile)
+{
+       struct ras_cper *cper = &ras_core->ras_cper;
+       int ret = 0;
+
+       if (!profile || event >= cper->nr_profiles)
+               return -EINVAL;
+
+       if (!cper->profiles)
+               return -EPERM;
+
+       mutex_lock(&cper->profile_mutex);
+       if (cper->profiles[event].fill_section) {
+               ret = -EEXIST;
+               goto out;
+       }
+
+       memcpy(&cper->profiles[event], profile, sizeof(struct 
ras_cper_profile));
+
+out:
+       mutex_unlock(&cper->profile_mutex);
+       return ret;
+}
+
+int ras_cper_unregister_profile(struct ras_core_context *ras_core,
+       enum ras_log_event event)
+{
+       struct ras_cper *cper = &ras_core->ras_cper;
+       int ret = 0;
+
+       if (event >= cper->nr_profiles)
+               return -EINVAL;
+
+       if (!cper->profiles)
+               return -EPERM;
+
+       mutex_lock(&cper->profile_mutex);
+       if (!cper->profiles[event].fill_section) {
+               ret = 0;
+               goto out;
+       }
+
+       memset(&cper->profiles[event], 0, sizeof(struct ras_cper_profile));
+
+out:
+       mutex_unlock(&cper->profile_mutex);
+       return ret;
+}
diff --git a/drivers/gpu/drm/amd/ras/core/ras_cper.h 
b/drivers/gpu/drm/amd/ras/core/ras_cper.h
index 037e8072eb2bc..f69f4e4de9ec9 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_cper.h
+++ b/drivers/gpu/drm/amd/ras/core/ras_cper.h
@@ -23,6 +23,7 @@
  */
 #ifndef __RAS_CPER_H__
 #define __RAS_CPER_H__
+#include "log_ring.h"
 
 #define CPER_UUID_MAX_SIZE 16
 struct ras_cper_guid {
@@ -46,6 +47,7 @@ struct ras_cper_guid {
 
 #define CPER_CREATOR_ID__AMDGPU        "amdgpu"
 
+/* Cper Notification Type */
 #define CPER_NOTIFY__MCE                                               \
        CPER_GUID__INIT(0xE8F56FFE, 0x919C, 0x4cc5, 0xBA, 0x88, 0x65, 0xAB, \
                  0xE1, 0x49, 0x13, 0xBB)
@@ -56,6 +58,7 @@ struct ras_cper_guid {
        CPER_GUID__INIT(0x3D61A466, 0xAB40, 0x409a, 0xA6, 0x98, 0xF3, 0x62, \
                  0xD4, 0x64, 0xB3, 0x8F)
 
+/* Cper Section Type */
 #define GPU__CRASHDUMP                                                 \
        CPER_GUID__INIT(0x32AC0C78, 0x2623, 0x48F6, 0xB0, 0xD0, 0x73, 0x65, \
                  0x72, 0x5F, 0xD6, 0xAE)
@@ -73,6 +76,7 @@ enum ras_cper_type {
        RAS_CPER_TYPE_RMA,
 };
 
+/* Cper Error Severity */
 enum ras_cper_severity {
        RAS_CPER_SEV_NON_FATAL_UE   = 0,
        RAS_CPER_SEV_FATAL_UE       = 1,
@@ -286,12 +290,50 @@ struct ras_cper_boot_record {
 };
 #pragma pack(pop)
 
+struct ras_core_context;
+struct ras_log_info;
+enum ras_log_event;
+/*
+ * Per-event description of how to build its CPER record(s).
+ *
+ * Fixed fields (severity/notify_type/sec_type) are used as-is unless the 
matching
+ * optional hook (get_severity/get_notify_type/get_sec_type) is provided.
+ */
+struct ras_cper_profile {
+       enum ras_cper_type     cper_type;
+       enum ras_cper_severity severity;
+       struct ras_cper_guid   notify_type;
+       struct ras_cper_guid   sec_type;
+       uint32_t section_size;
+       /* true: one CPER record per log */
+       bool build_record_per_log;
+
+       int (*get_severity)(struct ras_log_info *log, enum ras_cper_severity 
*out);
+       int (*get_notify_type)(struct ras_log_info *log, struct ras_cper_guid 
*out);
+       int (*get_sec_type)(struct ras_log_info *log, struct ras_cper_guid 
*out);
+
+       /* Required: fill the error-type specific section body for one log */
+       int (*fill_section)(struct ras_core_context *ras_core, void *section,
+                           struct ras_log_info *log, enum ras_cper_severity 
sev);
+};
+
+struct ras_event_profile_map {
+       uint32_t event;
+       struct ras_cper_profile *profile;
+};
+
+struct ras_cper {
+       struct ras_cper_profile *profiles;
+       uint32_t nr_profiles;
+       struct mutex profile_mutex;
+};
+
 #define RAS_HDR_LEN                            (sizeof(struct 
cper_section_hdr))
-#define RAS_SEC_DESC_LEN                       (sizeof(struct cper_sec_desc))
+#define RAS_SEC_DESC_LEN                       (sizeof(struct 
cper_section_desc))
 
-#define RAS_BOOT_SEC_LEN                       (sizeof(struct 
cper_sec_crashdump_boot))
-#define RAS_FATAL_SEC_LEN                      (sizeof(struct 
cper_sec_crashdump_fatal))
-#define RAS_NONSTD_SEC_LEN                     (sizeof(struct 
cper_sec_nonstd_err))
+#define RAS_BOOT_SEC_LEN                       (sizeof(struct 
cper_section_boot))
+#define RAS_FATAL_SEC_LEN                      (sizeof(struct 
cper_section_fatal))
+#define RAS_NONSTD_SEC_LEN                     (sizeof(struct 
cper_section_runtime))
 
 #define RAS_SEC_DESC_OFFSET(idx)               (RAS_HDR_LEN + 
(RAS_SEC_DESC_LEN * idx))
 
@@ -302,9 +344,13 @@ struct ras_cper_boot_record {
 #define RAS_NONSTD_SEC_OFFSET(count, idx) \
        (RAS_HDR_LEN + (RAS_SEC_DESC_LEN * count) + (RAS_NONSTD_SEC_LEN * idx))
 
-struct ras_core_context;
-struct ras_log_info;
-int ras_cper_generate_cper(struct ras_core_context *ras_core,
-               struct ras_log_info *trace_list, uint32_t count,
+int ras_cper_sw_init(struct ras_core_context *ras_core);
+int ras_cper_sw_fini(struct ras_core_context *ras_core);
+int ras_cper_generate_batch_cper(struct ras_core_context *ras_core,
+               struct ras_log_info *batch_logs, uint32_t nr_batch_logs,
                uint8_t *buf, uint32_t buf_len, uint32_t *real_data_len);
+int ras_cper_register_profile(struct ras_core_context *ras_core,
+       enum ras_log_event event, struct ras_cper_profile *profile);
+int ras_cper_unregister_profile(struct ras_core_context *ras_core,
+       enum ras_log_event event);
 #endif
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c 
b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c
index f6b114d9d613f..9c7430aec3f3a 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c
@@ -308,7 +308,7 @@ static int amdgpu_virt_ras_get_cper_records(struct 
ras_core_context *ras_core,
                                                          trace, trace_count,
                                                          rsp_cache);
                if (count > 0) {
-                       ret = ras_cper_generate_cper(ras_core, trace, count,
+                       ret = ras_cper_generate_batch_cper(ras_core, trace, 
count,
                                        &out_buf[offset], req->buf_size - 
offset, &real_data_len);
                        if (ret)
                                break;
-- 
2.55.0

Reply via email to