[PATCH 090/109] drm/amd/ras: refactor ras cper to simplify adding new cper events
Alex Deucher <[email protected]>
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
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(§ion_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], ¬ify_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, ¬ify_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