Skip to contentSkip to conversation

2.6.0 MCA TLB error recovery

PATCH New Luck, Tony 1 participant 1 message Dec 18, 2003 EFI

lore
Share & tools
lore

Luck, Tony

author
#0 lore raw

PATCH 1/1 2.6.0 MCA TLB error recovery

David,

Here's the updated version of the MCA TLB recovery patch (and I've made the assumption that you'll take Keith's salinfo patch from 11/25 and the deadlock fix that he posted on 12/7 first ... so this patch is against base 2.6.0 with Keith's patches applied).

One slight glitch that I don't understand. When I injected a TLB error I saw this printk on the console:

+CPU 3: SAL log contains MCA error record
+Err Record ID: 545586543104884737 SAL Rev: 0.03
+Time: 12/18/2003 10:28:32 Severity 0

But the salinfo_decode daemon didn't wake up to pluck this from the kernel and deposit it in /var/log/salinfo/{raw,decoded}/* After I rebooted the daemon picked up the log and decoded it and reported 4 copies of the same stuff, one from each cpu:

BEGIN HARDWARE ERROR STATE from mca on cpu 3
Err Record ID: 545586543104884737 SAL Rev: 0.03
Time: 2003-12-18 10:28:32 Severity 0
Processor Device Error Info Section

     UNCORRECTED PROCESSOR ERROR: TLB Check
       processor lid            : 0x00000000c6180000
         cpu: M nasid: 0x618
       processor state parameter: 0x10000000ff7211a0

blah, blah, blah

It looks like salinfo_log_wakeup() is called right before ia64_log_print() ... so I'm not sure why the salinfo_decode daemon kept on snoozing. Keith: am I missing something obvious?

Here's the patch (substantial portions of this code written by Fenghua Yu):

arch/ia64/kernel/asm-offsets.c +4 -0
diff -ru linux-2.6.0/arch/ia64/kernel/asm-offsets.c tlbfix/arch/ia64/kernel/asm-offsets.c
@@ -12,6 +12,7 @@
 #include <asm-ia64/ptrace.h>
 #include <asm-ia64/siginfo.h>
 #include <asm-ia64/sigcontext.h>
+#include <asm-ia64/mca.h>
 
 #include "../kernel/sigframe.h"
 
@@ -204,4 +205,7 @@
 # error "CLONE_SETTLS_BIT incorrect, please fix"
 #endif
 
+	BLANK();
+	DEFINE(IA64_MCA_TLB_INFO_SIZE, sizeof (struct ia64_mca_tlb_info));
+
 }
arch/ia64/kernel/efi.c +12 -0
diff -ru linux-2.6.0/arch/ia64/kernel/efi.c tlbfix/arch/ia64/kernel/efi.c
@@ -30,6 +30,7 @@
 #include <asm/kregs.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
+#include <asm/mca.h>
 
 #define EFI_DEBUG	0
 
@@ -395,6 +396,9 @@
 	int pal_code_count = 0;
 	u64 mask, psr;
 	u64 vaddr;
+#ifdef CONFIG_IA64_MCA
+	int cpu;
+#endif
 
 	efi_map_start = __va(ia64_boot_param->efi_memmap);
 	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
@@ -455,6 +459,14 @@
 			 IA64_GRANULE_SHIFT);
 		ia64_set_psr(psr);		/* restore psr */
 		ia64_srlz_i();
+
+#ifdef CONFIG_IA64_MCA
+		cpu = smp_processor_id();
+
+		/* insert this TR into our list for MCA recovery purposes */
+		ia64_mca_tlb_list[cpu].pal_base=vaddr & mask;
+		ia64_mca_tlb_list[cpu].pal_paddr= pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL));
+#endif
 	}
 }
 
arch/ia64/kernel/mca_asm.S +237 -120

440 lines not on this page · raw message

arch/ia64/kernel/mca.c +18 -6
diff -ru linux-2.6.0/arch/ia64/kernel/mca.c tlbfix/arch/ia64/kernel/mca.c
@@ -78,9 +78,8 @@
 u64				ia64_mca_stackframe[32];
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[KERNEL_STACK_SIZE/8] __attribute__((aligned(16)));
-u64				ia64_mca_sal_data_area[1356];
-u64				ia64_tlb_functional;
 u64				ia64_os_mca_recovery_successful;
+u64				ia64_mca_serialize;
 static void			ia64_mca_wakeup_ipi_wait(void);
 static void			ia64_mca_wakeup(int cpu);
 static void			ia64_mca_wakeup_all(void);
@@ -90,6 +89,8 @@
 static u64			ia64_log_get(int sal_info_type, u8 **buffer);
 extern struct hw_interrupt_type	irq_type_iosapic_level;
 
+struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS];
+
 static struct irqaction cmci_irqaction = {
 	.handler =	ia64_mca_cmc_int_handler,
 	.flags =	SA_INTERRUPT,
@@ -944,6 +945,9 @@
 void
 ia64_return_to_sal_check(void)
 {
+	pal_processor_state_info_t *psp = (pal_processor_state_info_t *)
+		&ia64_sal_to_os_handoff_state.proc_state_param;
+
 	/* Copy over some relevant stuff from the sal_to_os_mca_handoff
 	 * so that it can be used at the time of os_mca_to_sal_handoff
 	 */
@@ -953,14 +957,22 @@
 	ia64_os_to_sal_handoff_state.imots_sal_check_ra  		ia64_sal_to_os_handoff_state.imsto_sal_check_ra;
 
-	/* Cold Boot for uncorrectable MCA */
-	ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
+	/*
+	 * Did we correct the error? At the moment the only error that
+	 * we fix is a TLB error, if any other kind of error occurred
+	 * we must reboot.
+	 */
+	if (psp->cc = 1 && psp->bc = 1 && psp->rc = 1 && psp->uc = 1)
+		ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
+	else
+		ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED;
 
 	/* Default = tell SAL to return to same context */
 	ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
 
 	ia64_os_to_sal_handoff_state.imots_new_min_state  		(u64 *)ia64_sal_to_os_handoff_state.pal_min_state;
+
 }
 
 /*
@@ -1338,8 +1350,8 @@
 void
 ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc)
 {
-	char out[40];
-	printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out));
+	//char out[40];
+	//printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out));
 }
 
 static void
arch/ia64/mm/init.c +22 -0
diff -ru linux-2.6.0/arch/ia64/mm/init.c tlbfix/arch/ia64/mm/init.c
@@ -34,6 +34,7 @@
 #include <asm/tlb.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/mca.h>
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
@@ -277,6 +278,10 @@
 {
 	unsigned long psr, pta, impl_va_bits;
 	extern void __init tlb_init (void);
+#ifdef CONFIG_IA64_MCA
+	int cpu;
+#endif
+
 #ifdef CONFIG_DISABLE_VHPT
 #	define VHPT_ENABLE_BIT	0
 #else
@@ -335,6 +340,23 @@
 	ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT);
 
 	ia64_tlb_init();
+
+#ifdef	CONFIG_IA64_MCA
+	cpu = smp_processor_id();
+
+	/* mca handler uses cr.lid as key to pick the right entry */
+	ia64_mca_tlb_list[cpu].cr_lid = ia64_getreg(_IA64_REG_CR_LID);
+
+	/* insert this percpu data information into our list for MCA recovery purposes */
+	ia64_mca_tlb_list[cpu].percpu_paddr=pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL));
+	/* Also save per-cpu tlb flush recipe for use in physical mode mca handler */
+	ia64_mca_tlb_list[cpu].ptce_base=local_cpu_data->ptce_base;
+	ia64_mca_tlb_list[cpu].ptce_count[0]=local_cpu_data->ptce_count[0];
+	ia64_mca_tlb_list[cpu].ptce_count[1]=local_cpu_data->ptce_count[1];
+	ia64_mca_tlb_list[cpu].ptce_stride[0]=local_cpu_data->ptce_stride[0];
+	ia64_mca_tlb_list[cpu].ptce_stride[1]=local_cpu_data->ptce_stride[1];
+#endif
+
 }
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
include/asm-ia64/mca.h +12 -0
diff -ru linux-2.6.0/include/asm-ia64/mca.h tlbfix/include/asm-ia64/mca.h
@@ -18,6 +18,7 @@
 #include <asm/param.h>
 #include <asm/sal.h>
 #include <asm/processor.h>
+#include <asm/mca_asm.h>
 
 /* These are the return codes from all the IA64_MCA specific interfaces */
 typedef	int ia64_mca_return_code_t;
@@ -61,6 +62,17 @@
 	IA64_MCA_RENDEZ_CHECKIN_DONE	=	0x1
 };
 
+/* the following data structure is used for TLB error recovery purposes */
+extern struct ia64_mca_tlb_info {
+	u64	cr_lid;
+	u64	percpu_paddr;
+	u64	ptce_base;
+	u32	ptce_count[2];
+	u32	ptce_stride[2]; 
+	u64	pal_paddr;
+	u64	pal_base;
+} ia64_mca_tlb_list[NR_CPUS];
+
 /* Information maintained by the MC infrastructure */
 typedef struct ia64_mc_info_s {
 	u64		imi_mca_handler;
include/asm-ia64/pgtable.h +4 -0
diff -ru linux-2.6.0/include/asm-ia64/pgtable.h tlbfix/include/asm-ia64/pgtable.h
@@ -230,6 +230,10 @@
 
 #define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
 
+/* This takes a physical page address that is used by the remapping functions */
+#define mk_pte_phys(physpage, pgprot) \
+({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
+
 #define pte_modify(_pte, newprot) \
 	(__pte((pte_val(_pte) & ~_PAGE_CHG_MASK) | (pgprot_val(newprot) & _PAGE_CHG_MASK)))