aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2011-12-07 22:25:45 -0500
committerLen Brown <len.brown@intel.com>2012-01-17 03:54:33 -0500
commit46d12f0bcb17b2de89a059114349d472b7eb1783 (patch)
treea87b3aff8d51c483c2c48e51106fa9a2f9b50a68 /drivers/acpi
parent5ba82ab534a325d310fe02af1c149f1072792c7b (diff)
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>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/apei/ghes.c53
1 files changed, 44 insertions, 9 deletions
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 9dcb2d86aea..aaf36090de1 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -740,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this,
740 return ret; 740 return ret;
741} 741}
742 742
743static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
744{
745 struct llist_node *next, *tail = NULL;
746
747 while (llnode) {
748 next = llnode->next;
749 llnode->next = tail;
750 tail = llnode;
751 llnode = next;
752 }
753
754 return tail;
755}
756
743static void ghes_proc_in_irq(struct irq_work *irq_work) 757static void ghes_proc_in_irq(struct irq_work *irq_work)
744{ 758{
745 struct llist_node *llnode, *next, *tail = NULL; 759 struct llist_node *llnode, *next;
746 struct ghes_estatus_node *estatus_node; 760 struct ghes_estatus_node *estatus_node;
747 struct acpi_hest_generic *generic; 761 struct acpi_hest_generic *generic;
748 struct acpi_hest_generic_status *estatus; 762 struct acpi_hest_generic_status *estatus;
749 u32 len, node_len; 763 u32 len, node_len;
750 764
765 llnode = llist_del_all(&ghes_estatus_llist);
751 /* 766 /*
752 * Because the time order of estatus in list is reversed, 767 * Because the time order of estatus in list is reversed,
753 * revert it back to proper order. 768 * revert it back to proper order.
754 */ 769 */
755 llnode = llist_del_all(&ghes_estatus_llist); 770 llnode = llist_nodes_reverse(llnode);
756 while (llnode) {
757 next = llnode->next;
758 llnode->next = tail;
759 tail = llnode;
760 llnode = next;
761 }
762 llnode = tail;
763 while (llnode) { 771 while (llnode) {
764 next = llnode->next; 772 next = llnode->next;
765 estatus_node = llist_entry(llnode, struct ghes_estatus_node, 773 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 } 787 }
780} 788}
781 789
790static void ghes_print_queued_estatus(void)
791{
792 struct llist_node *llnode;
793 struct ghes_estatus_node *estatus_node;
794 struct acpi_hest_generic *generic;
795 struct acpi_hest_generic_status *estatus;
796 u32 len, node_len;
797
798 llnode = llist_del_all(&ghes_estatus_llist);
799 /*
800 * Because the time order of estatus in list is reversed,
801 * revert it back to proper order.
802 */
803 llnode = llist_nodes_reverse(llnode);
804 while (llnode) {
805 estatus_node = llist_entry(llnode, struct ghes_estatus_node,
806 llnode);
807 estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
808 len = apei_estatus_len(estatus);
809 node_len = GHES_ESTATUS_NODE_LEN(len);
810 generic = estatus_node->generic;
811 ghes_print_estatus(NULL, generic, estatus);
812 llnode = llnode->next;
813 }
814}
815
782static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) 816static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
783{ 817{
784 struct ghes *ghes, *ghes_global = NULL; 818 struct ghes *ghes, *ghes_global = NULL;
@@ -804,6 +838,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
804 838
805 if (sev_global >= GHES_SEV_PANIC) { 839 if (sev_global >= GHES_SEV_PANIC) {
806 oops_begin(); 840 oops_begin();
841 ghes_print_queued_estatus();
807 __ghes_print_estatus(KERN_EMERG, ghes_global->generic, 842 __ghes_print_estatus(KERN_EMERG, ghes_global->generic,
808 ghes_global->estatus); 843 ghes_global->estatus);
809 /* reboot to log the error! */ 844 /* reboot to log the error! */