Commit 46d12f0b authored by Huang Ying's avatar Huang Ying Committed by Len Brown

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: default avatarHuang Ying <ying.huang@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 5ba82ab5
...@@ -740,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this, ...@@ -740,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this,
return ret; return ret;
} }
static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
{
struct llist_node *next, *tail = NULL;
while (llnode) {
next = llnode->next;
llnode->next = tail;
tail = llnode;
llnode = next;
}
return tail;
}
static void ghes_proc_in_irq(struct irq_work *irq_work) static void ghes_proc_in_irq(struct irq_work *irq_work)
{ {
struct llist_node *llnode, *next, *tail = NULL; struct llist_node *llnode, *next;
struct ghes_estatus_node *estatus_node; struct ghes_estatus_node *estatus_node;
struct acpi_hest_generic *generic; struct acpi_hest_generic *generic;
struct acpi_hest_generic_status *estatus; struct acpi_hest_generic_status *estatus;
u32 len, node_len; u32 len, node_len;
llnode = llist_del_all(&ghes_estatus_llist);
/* /*
* Because the time order of estatus in list is reversed, * Because the time order of estatus in list is reversed,
* revert it back to proper order. * revert it back to proper order.
*/ */
llnode = llist_del_all(&ghes_estatus_llist); llnode = llist_nodes_reverse(llnode);
while (llnode) {
next = llnode->next;
llnode->next = tail;
tail = llnode;
llnode = next;
}
llnode = tail;
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) ...@@ -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) ...@@ -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! */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment