Skip to contentSkip to conversation

MCA recovery for TLB faults for 2.4

PATCH In review Luck, Tony 3 participants 7 messages May 28, 2003 – Jun 2, 2003 EFI

lore
Share & tools
lore

Luck, Tony

author
#0 lore raw

PATCH 1/1 MCA recovery for TLB faults for 2.4

This patch is against a tree created by cloning Bjorn's BK tree on May 20, and applying his error logging patch (posted to ia64 list on May 8th ... since I'm sure he's going to include it as it is so good).

The underlying algorithm is to save information about what each of the ITR/DTR registers is mapping, then at MCA time we can purge the whole TLB (TC and TR) and reload the TR registers before jumping to virtual mode.

DTR[2] gets some special treatment as we didn't want to touch the context switch path to update the saved area on potentially every context switch, so it gets reconstructed from ar.k4.

There is a major cleanup of the processor save/restore code in mca_asm.S (which apparently was written before silicon, it was using some out-of-date spec for control registers).

There's a minor cleanup in the logging code to only print implemented registers (this just needs to be moved over to Bjorn's new "salinfo" tool when all the print code gets deleted from the kernel).

-Tony Luck. With special thanks to Jenna Hall (who started work on this, oh so long ago) and Fenghua Yu (who ported to 2.4.21 and tidied up my messes).

2.5 version needs some more work to co-exist with the kernel relocation patch

arch/ia64/kernel/efi.c +16 -0
diff -Nur A/arch/ia64/kernel/efi.c B/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
 
@@ -402,6 +403,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;
@@ -459,6 +463,18 @@
 			 pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), 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_itr_list(cpu,
+			      0x01,
+			      IA64_TR_PALCODE,
+			      vaddr & mask,
+			      pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)),
+			      IA64_GRANULE_SHIFT);
+#endif
 	}
 }
 
arch/ia64/kernel/mca.c +130 -40

265 lines not on this page · raw message

arch/ia64/kernel/mca_asm.S +112 -192

427 lines not on this page · raw message

arch/ia64/kernel/setup.c +30 -1
diff -Nur A/arch/ia64/kernel/setup.c B/arch/ia64/kernel/setup.c
@@ -291,6 +291,36 @@
 {
 	extern unsigned long ia64_iobase;
 	unsigned long phys_iobase;
+	int	cpu;
+#ifdef CONFIG_IA64_MCA
+	int	i;
+#endif
+
+#ifdef CONFIG_IA64_MCA
+	/*
+	 * Save information for kernel TR value (loaded in head.S) and
+	 * partial information for the stack TR too.
+	 * Do this for all CPU's, since the kernel TR value is the
+	 * same for each.
+	 */
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		/* Save ITR & DTR data for kernel code. */
+		ia64_itr_list(cpu, 
+			 0x01 | 0x02,
+			 IA64_TR_KERNEL,
+			 KERNEL_START,
+			 (1 << KERNEL_TR_PAGE_SHIFT) | pgprot_val(PAGE_KERNEL),
+			 KERNEL_TR_PAGE_SHIFT);
+
+		/* save partial info for stack TR */
+		ia64_itr_list(cpu,
+			 0x02,
+			 IA64_TR_CURRENT_STACK,
+			 0,
+			 0,
+			 IA64_GRANULE_SHIFT);
+	}
+#endif
 
 	unw_init();
 
@@ -589,7 +619,6 @@
 	my_cpu_data = cpu_data(smp_processor_id());
 	my_cpu_data->mmu_gathers = &mmu_gathers[smp_processor_id()];
 #endif
-
 	/*
 	 * We can't pass "local_cpu_data" to identify_cpu() because we haven't called
 	 * ia64_mmu_init() yet.  And we can't call ia64_mmu_init() first because it
arch/ia64/mm/init.c +16 -0
diff -Nur A/arch/ia64/mm/init.c B/arch/ia64/mm/init.c
@@ -26,6 +26,7 @@
 #include <asm/sal.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/mca.h>
 
 /* References to section boundaries: */
 extern char _stext, _etext, _edata, __init_begin, __init_end;
@@ -282,6 +283,10 @@
 {
 	unsigned long psr, rid, 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
@@ -309,6 +314,17 @@
 	ia64_set_psr(psr);
 	ia64_srlz_i();
 
+#ifdef	CONFIG_IA64_MCA
+	cpu = smp_processor_id();
+	/* insert this TR into our list for MCA recovery purposes */
+	ia64_itr_list(cpu,
+		 0x02, 
+		 IA64_TR_PERCPU_DATA,
+		 PERCPU_ADDR,
+		 pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)),
+		 PAGE_SHIFT);
+#endif
+
 	/*
 	 * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped
 	 * address space.  The IA-64 architecture guarantees that at least 50 bits of
include/asm-ia64/kregs.h +2 -0
diff -Nur A/include/asm-ia64/kregs.h B/include/asm-ia64/kregs.h
@@ -31,6 +31,8 @@
 #define IA64_TR_PERCPU_DATA	1	/* dtr1: percpu data */
 #define IA64_TR_CURRENT_STACK	2	/* dtr2: maps kernel's memory- & register-stacks */
 
+#define IA64_TR_MAXTR		3	/* maxium number of TR registers.*/
+
 /* Processor status register bits: */
 #define IA64_PSR_BE_BIT		1
 #define IA64_PSR_UP_BIT		2
include/asm-ia64/mca.h +42 -1

79 lines not on this page · raw message

#1 lore raw
Quoted 4 lines · Tony

The underlying algorithm is to save information about what each of the ITR/DTR registers is mapping, then at MCA time we can purge the whole TLB (TC and TR) and reload the TR registers before jumping to virtual mode.

ia64_os_mca_tlb_purge_and_reload() will break if somebody compiles the kernel with -pg, say for profiling or stack monitoring. -pg adds a call to mcount() at the start of every function and mcount expects to run in virtual mode. kdb has the same problem, I get around it by adding this line to the Makefile.

override CFLAGS := $(CFLAGS:%-pg=% )

That affects all objects in the directory, we do not want to apply that to all objects in arch/ia64/kernel, we do not even want to apply it to all functions in mca.c. Please move ia64_os_mca_tlb_purge_and_reload() to its own source file in a sub directory, say arch/ia64/kernel/physical.

#2 lore raw
In reply to Luck, Tony
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Tony

Tony> The underlying algorithm is to save information about what Tony> each of the ITR/DTR registers is mapping, then at MCA time we Tony> can purge the whole TLB (TC and TR) and reload the TR Tony> registers before jumping to virtual mode.

Are you just blindly trusting that memory is still correct after getting a TLB error report? Wouldn't you want to have a checksum to validate that the list of saved translations is probably correct. Otherwise, it seems to me the TLB purge could make a bad situation worse.

	--david
author
#3 lore raw
In reply to Luck, Tony
Quoted 5 lines

Are you just blindly trusting that memory is still correct after getting a TLB error report? Wouldn't you want to have a checksum to validate that the list of saved translations is probably correct. Otherwise, it seems to me the TLB purge could make a bad situation worse.

At the moment the trust level is extremely high. Linux doesn't even provide a checksum for the ia64_os_mca_dispatch entry code when it registers it with the SAL.

A checksum in the list of saved translations would only be part of reducing the level of trust ... we'd also need to validate that the entire code path has the correct code (not just the entry point). There are several other data items on which the code also relies which a truly paranoid MCA handler would also need to validate.

-Tony

#4 lore raw
In reply to Luck, Tony
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Tony

Tony> At the moment the trust level is extremely high. Linux Tony> doesn't even provide a checksum for the ia64_os_mca_dispatch Tony> entry code when it registers it with the SAL.

That's true.

Tony> A checksum in the list of saved translations would only be Tony> part of reducing the level of trust ... we'd also need to Tony> validate that the entire code path has the correct code (not Tony> just the entry point). There are several other data items on Tony> which the code also relies which a truly paranoid MCA handler Tony> would also need to validate.

I probably just don't understand what the plan is here. Are you planning to fix everything in one fell swoop? If not, I think incrementally improving the situation makes sense (i.e., if you work on piece X, make X as solid as possible; over time do this for more and more pieces of the MCA subsystem). There is no doubt that making the entire MCA subsystem as robust as possible involves a huge amount of rather tricky work. Same goes for the INIT path, of course (there are obvious ways to deadlock it right now; probably something that could benefit from a reasonably generic lock-busting infrastructure).

	--david
author
#5 lore raw
In reply to Luck, Tony
Quoted 9 lines

I probably just don't understand what the plan is here. Are you planning to fix everything in one fell swoop? If not, I think incrementally improving the situation makes sense (i.e., if you work on piece X, make X as solid as possible; over time do this for more and more pieces of the MCA subsystem). There is no doubt that making the entire MCA subsystem as robust as possible involves a huge amount of rather tricky work. Same goes for the INIT path, of course (there are obvious ways to deadlock it right now; probably something that could benefit from a reasonably generic lock-busting infrastructure).

We are using the incremental plan ... fix a piece, make it solid, move on to the next piece.

TLB recovery was chosen as the first piece as it appears to be the simplest to implement, though its probably one of the lowest value adds (frequency of TLB errors should be *far* lower than memory errors, PCI bus errors and cache errors). But it will get the infrastructure together to pass control up to C-code to handle more complex cases (e.g. multi-bit ECC error in memory, where processes will need to be sacrificed to allow the OS to continue).

-Tony

#6 lore raw
In reply to Luck, Tony
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Tony

Tony> TLB recovery was chosen as the first piece as it appears to be Tony> the simplest to implement,

Ah, I see.

Tony> though its probably one of the lowest value adds (frequency of Tony> TLB errors should be *far* lower than memory errors

Yes, I guess that's what surprised me.

	--david