ACPI, APEI, Printk queued error record before panic
Because printk is not safe inside NMI handler, the recoverable error records received in NMI handler will be queued to be printked in a delayed IRQ context via irq_work. If a fatal error occurs after the recoverable error and before the irq_work processed, we lost a error report. To solve the issue, the queued error records are printked in NMI handler if system will go panic. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
5ba82ab534
commit
46d12f0bcb
1 changed files with 47 additions and 12 deletions
|
@ -740,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ghes_proc_in_irq(struct irq_work *irq_work)
|
static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
|
||||||
{
|
{
|
||||||
struct llist_node *llnode, *next, *tail = NULL;
|
struct llist_node *next, *tail = NULL;
|
||||||
struct ghes_estatus_node *estatus_node;
|
|
||||||
struct acpi_hest_generic *generic;
|
|
||||||
struct acpi_hest_generic_status *estatus;
|
|
||||||
u32 len, node_len;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Because the time order of estatus in list is reversed,
|
|
||||||
* revert it back to proper order.
|
|
||||||
*/
|
|
||||||
llnode = llist_del_all(&ghes_estatus_llist);
|
|
||||||
while (llnode) {
|
while (llnode) {
|
||||||
next = llnode->next;
|
next = llnode->next;
|
||||||
llnode->next = tail;
|
llnode->next = tail;
|
||||||
tail = llnode;
|
tail = llnode;
|
||||||
llnode = next;
|
llnode = next;
|
||||||
}
|
}
|
||||||
llnode = tail;
|
|
||||||
|
return tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ghes_proc_in_irq(struct irq_work *irq_work)
|
||||||
|
{
|
||||||
|
struct llist_node *llnode, *next;
|
||||||
|
struct ghes_estatus_node *estatus_node;
|
||||||
|
struct acpi_hest_generic *generic;
|
||||||
|
struct acpi_hest_generic_status *estatus;
|
||||||
|
u32 len, node_len;
|
||||||
|
|
||||||
|
llnode = llist_del_all(&ghes_estatus_llist);
|
||||||
|
/*
|
||||||
|
* Because the time order of estatus in list is reversed,
|
||||||
|
* revert it back to proper order.
|
||||||
|
*/
|
||||||
|
llnode = llist_nodes_reverse(llnode);
|
||||||
while (llnode) {
|
while (llnode) {
|
||||||
next = llnode->next;
|
next = llnode->next;
|
||||||
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
|
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
|
||||||
|
@ -779,6 +787,32 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ghes_print_queued_estatus(void)
|
||||||
|
{
|
||||||
|
struct llist_node *llnode;
|
||||||
|
struct ghes_estatus_node *estatus_node;
|
||||||
|
struct acpi_hest_generic *generic;
|
||||||
|
struct acpi_hest_generic_status *estatus;
|
||||||
|
u32 len, node_len;
|
||||||
|
|
||||||
|
llnode = llist_del_all(&ghes_estatus_llist);
|
||||||
|
/*
|
||||||
|
* Because the time order of estatus in list is reversed,
|
||||||
|
* revert it back to proper order.
|
||||||
|
*/
|
||||||
|
llnode = llist_nodes_reverse(llnode);
|
||||||
|
while (llnode) {
|
||||||
|
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
|
||||||
|
llnode);
|
||||||
|
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
|
||||||
|
len = apei_estatus_len(estatus);
|
||||||
|
node_len = GHES_ESTATUS_NODE_LEN(len);
|
||||||
|
generic = estatus_node->generic;
|
||||||
|
ghes_print_estatus(NULL, generic, estatus);
|
||||||
|
llnode = llnode->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
|
static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct ghes *ghes, *ghes_global = NULL;
|
struct ghes *ghes, *ghes_global = NULL;
|
||||||
|
@ -804,6 +838,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
|
||||||
|
|
||||||
if (sev_global >= GHES_SEV_PANIC) {
|
if (sev_global >= GHES_SEV_PANIC) {
|
||||||
oops_begin();
|
oops_begin();
|
||||||
|
ghes_print_queued_estatus();
|
||||||
__ghes_print_estatus(KERN_EMERG, ghes_global->generic,
|
__ghes_print_estatus(KERN_EMERG, ghes_global->generic,
|
||||||
ghes_global->estatus);
|
ghes_global->estatus);
|
||||||
/* reboot to log the error! */
|
/* reboot to log the error! */
|
||||||
|
|
Reference in a new issue