(Pulling in Tony) On Tue, 04 Mar, at 04:10:57PM, Adrian Huang12 wrote: > Some fields might be added to the Error Section in the newer UEFI > spec. For example, the fields 'Reserved', 'Rank Number', > 'Card Handle' and 'Module Handle' are added to the Memory Error > Section started from UEFI spec 2.3. Unfortunately, there will have > the following warning message if the memory corrected error is > detected and the field 'revision' in struct acpi_generic_data is > less then 0x203 (UEFI spec 2.3): > > {1}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 3 > {1}[Hardware Error]: It has been corrected by h/w and requires no further action > {1}[Hardware Error]: event severity: corrected > {1}[Hardware Error]: Error 0, type: corrected > {1}[Hardware Error]: section_type: memory error > [Firmware Warn]: error section length is too small > > This behavior causes this corrected error cannot be displayed > correctly. To solve the issue, this patch supports different > length of the Error Section for different UEFI spec version. > > And, this patch employs a pre-defined structure to clean up the > duplicated codes in function cper_estatus_print_section. > > With applying this patch, the memory corrected error could be > displayed correctly after injecting the error. > > Tested on v3.14-rc5 with Grantley platform and Intel RAStool. > > Signed-off-by: Adrian Huang <ahuang12@xxxxxxxxxx> > --- > drivers/firmware/efi/cper.c | 110 +++++++++++++++++++++++++++++++++----------- > 1 file changed, 84 insertions(+), 26 deletions(-) > > diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c > index 1491dd4..c33f1e3 100644 > --- a/drivers/firmware/efi/cper.c > +++ b/drivers/firmware/efi/cper.c > @@ -132,9 +132,11 @@ static const char * const cper_proc_flag_strs[] = { > "corrected", > }; > > -static void cper_print_proc_generic(const char *pfx, > - const struct cper_sec_proc_generic *proc) > +static void cper_print_proc_generic(const char *pfx, const void *data) > { > + const struct cper_sec_proc_generic *proc = > + (struct cper_sec_proc_generic *) data; > + > if (proc->validation_bits & CPER_PROC_VALID_TYPE) > printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, > proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ? > @@ -196,8 +198,10 @@ static const char *cper_mem_err_type_strs[] = { > "physical memory map-out event", > }; > > -static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) > +static void cper_print_mem(const char *pfx, const void *data) > { > + const struct cper_sec_mem_err *mem = (struct cper_sec_mem_err *) data; > + > if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) > printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); > if (mem->validation_bits & CPER_MEM_VALID_PA) > @@ -261,9 +265,10 @@ static const char *cper_pcie_port_type_strs[] = { > "root complex event collector", > }; > > -static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, > - const struct acpi_generic_data *gdata) > +static void cper_print_pcie(const char *pfx, const void *data) > { > + struct cper_sec_pcie *pcie = (struct cper_sec_pcie *) data; > + > if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) > printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, > pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ? > @@ -297,12 +302,73 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, > pfx, pcie->bridge.secondary_status, pcie->bridge.control); > } > > +struct cper_section_length { > + u32 revision; > + u32 length; > +}; > + > +/* Per ACPI spec 4.0/5.0, the referred UEFI revision is 2.1. */ > +static struct cper_section_length proc_generic_section_len[] = { > + {0x201, sizeof(struct cper_sec_proc_generic)}, > + {} > +}; > + > +/* > + * Per ACPI spec 4.0/5.0, the referred UEFI revision is 2.1. > + * Some fields are added to Memory Error Section in UEFI 2.3 and later, > + * so we need to distinguish the difference. > + */ > +static struct cper_section_length mem_section_len[] = { > + {0x203, sizeof(struct cper_sec_mem_err)}, > + {0x201, offsetof(struct cper_sec_mem_err, reserved)}, > + {} > +}; > + > +/* Per ACPI spec 4.0/5.0, the referred UEFI revision is 2.1. */ > +static struct cper_section_length pcie_section_len[] = { > + {0x201, sizeof(struct cper_sec_pcie)}, > + {} > +}; > + > +struct cper_estatus_section_info { > + uuid_le type; > + char *name; > + struct cper_section_length *section_length; > + void (*print_fn)(const char *, const void *); > +}; > + > +static struct cper_estatus_section_info section_info[] = { > + {CPER_SEC_PROC_GENERIC, "general processor", proc_generic_section_len, > + cper_print_proc_generic}, > + {CPER_SEC_PLATFORM_MEM, "memory", mem_section_len, cper_print_mem}, > + {CPER_SEC_PCIE, "PCIe", pcie_section_len, cper_print_pcie}, > + {} > +}; > + > +static int cper_estatus_check_section(const struct acpi_generic_data *gdata, > + struct cper_section_length *len) > +{ > + struct cper_section_length *sec_length; > + > + for (sec_length = len; sec_length->revision; sec_length++) { > + /* Find the corresponding entry. */ > + if (gdata->revision >= (u16) sec_length->revision) > + break; > + } > + > + if (!sec_length || !sec_length->revision) > + return -EINVAL; > + > + return gdata->error_data_length >= sec_length->length ? 0 : -EINVAL; > +} > + > static void cper_estatus_print_section( > const char *pfx, const struct acpi_generic_data *gdata, int sec_no) > { > uuid_le *sec_type = (uuid_le *)gdata->section_type; > __u16 severity; > char newpfx[64]; > + struct cper_estatus_section_info *s_info; > > severity = gdata->error_severity; > printk("%s""Error %d, type: %s\n", pfx, sec_no, > @@ -313,28 +379,20 @@ static void cper_estatus_print_section( > printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); > > snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); > - if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { > - struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1); > - printk("%s""section_type: general processor error\n", newpfx); > - if (gdata->error_data_length >= sizeof(*proc_err)) > - cper_print_proc_generic(newpfx, proc_err); > - else > - goto err_section_too_small; > - } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { > - struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); > - printk("%s""section_type: memory error\n", newpfx); > - if (gdata->error_data_length >= sizeof(*mem_err)) > - cper_print_mem(newpfx, mem_err); > - else > - goto err_section_too_small; > - } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { > - struct cper_sec_pcie *pcie = (void *)(gdata + 1); > - printk("%s""section_type: PCIe error\n", newpfx); > - if (gdata->error_data_length >= sizeof(*pcie)) > - cper_print_pcie(newpfx, pcie, gdata); > - else > + > + for (s_info = section_info; s_info->print_fn; s_info++) { > + if (uuid_le_cmp(*sec_type, s_info->type)) > + continue; > + > + if (cper_estatus_check_section(gdata, s_info->section_length)) > goto err_section_too_small; > - } else > + > + printk("%s""section_type: %s\n", newpfx, s_info->name); > + s_info->print_fn(newpfx, (void *) (gdata + 1)); > + break; > + } > + > + if (!s_info->print_fn) > printk("%s""section type: unknown, %pUl\n", newpfx, sec_type); > > return; > -- > 1.8.1.2 > > -- Matt Fleming, Intel Open Source Technology Center -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html