diff -Nur A/arch/ia64/kernel/efi.c B/arch/ia64/kernel/efi.c
--- A/arch/ia64/kernel/efi.c	Tue May 27 19:07:44 2003
+++ B/arch/ia64/kernel/efi.c	Tue May 27 19:08:24 2003
@@ -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
 	}
 }
 
diff -Nur A/arch/ia64/kernel/mca.c B/arch/ia64/kernel/mca.c
--- A/arch/ia64/kernel/mca.c	Tue May 27 19:07:44 2003
+++ B/arch/ia64/kernel/mca.c	Tue May 27 19:08:25 2003
@@ -80,11 +80,8 @@
 u64				ia64_mca_stackframe[32];
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[INIT_TASK_SIZE/8] __attribute__((aligned(16)));
-u64				ia64_mca_sal_data_area[1356];
-u64				ia64_tlb_functional;
 u64				ia64_os_mca_recovery_successful;
-/* TODO: need to assign min-state structure to UC memory */
-u64				ia64_mca_min_state_save_info[MIN_STATE_AREA_SIZE] __attribute__((aligned(512)));
+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);
@@ -93,6 +90,11 @@
 extern void			ia64_slave_init_handler (void);
 extern struct hw_interrupt_type	irq_type_iosapic_level;
 
+/*
+ * Saved state of TLB TR registers for mca recovery
+ */
+struct ia64_kernel_tr_info ia64_kernel_tr_list[NR_CPUS][IA64_TR_MAXTR];
+
 static struct irqaction cmci_irqaction = {
 	.handler =	ia64_mca_cmc_int_handler,
 	.flags =	SA_INTERRUPT,
@@ -415,26 +417,6 @@
 #endif /* PLATFORM_MCA_HANDLERS */
 
 /*
- * routine to process and prepare to dump min_state_save
- * information for debugging purposes.
- */
-void
-ia64_process_min_state_save (pal_min_state_area_t *pmss)
-{
-	int i, max = MIN_STATE_AREA_SIZE;
-	u64 *tpmss_ptr = (u64 *)pmss;
-	u64 *return_min_state_ptr = ia64_mca_min_state_save_info;
-
-	for (i=0;i<max;i++) {
-
-		/* copy min-state register info for eventual return to PAL */
-		*return_min_state_ptr++ = *tpmss_ptr;
-
-		tpmss_ptr++;  /* skip to next entry */
-	}
-}
-
-/*
  * ia64_mca_cmc_vector_setup
  *
  *  Setup the corrected machine check vector register in the processor and
@@ -661,7 +643,7 @@
 	/* Register the os mca handler with SAL */
 	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
 				       ia64_mc_info.imi_mca_handler,
-				       mca_hldlr_ptr->gp,
+				       __pa(mca_hldlr_ptr->gp),
 				       ia64_mc_info.imi_mca_handler_size,
 				       0, 0, 0)))
 	{
@@ -786,7 +768,7 @@
 			irr = ia64_get_irr3();
 			break;
 		}
-	} while (!(irr & (1 << irr_bit))) ;
+	} while (!(irr & (1UL << irr_bit))) ;
 }
 
 /*
@@ -911,13 +893,14 @@
 
 	/* Cold Boot for uncorrectable MCA */
 	ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
+	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;
 
-	/* Register pointer to new min state values */
 	ia64_os_to_sal_handoff_state.imots_new_min_state =
-		ia64_mca_min_state_save_info;
+		ia64_sal_to_os_handoff_state.pal_min_state;
+
 }
 
 /*
@@ -1244,8 +1227,6 @@
 	plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
 	proc_ptr = &plog_ptr->proc_err;
 
-	ia64_process_min_state_save(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area);
-
 	init_handler_platform(proc_ptr, pt, sw);	/* call platform specific routines */
 }
 
@@ -1262,8 +1243,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
@@ -1415,6 +1396,12 @@
 			lh->timestamp.slh_second, lh->severity);
 }
 
+/* Bitmasks of implemented registers */
+static u64 arbits[2] = { 0x11117f2f00ffUL, 0x7UL };
+static u64 brbits[1] = { 0xffUL };
+static u64 crbits[2] = { 0x3fb0107UL, 0x307ffUL };
+static u64 rrbits[1] = { 0xffUL };
+
 /*
  * ia64_log_processor_regs_print
  *	Print the contents of the saved processor register(s) in the format
@@ -1430,6 +1417,7 @@
 void
 ia64_log_processor_regs_print(u64	*regs,
 			      int	reg_num,
+			      u64	*reg_bits,
 			      char	*reg_class,
 			      char	*reg_prefix,
 			      prfunc_t	prfunc)
@@ -1438,7 +1426,8 @@
 
 	prfunc("+%s Registers\n", reg_class);
 	for (i = 0; i < reg_num; i++)
-		prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]);
+		if (reg_bits[i/64] & (1UL << (i%64)))
+			prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]);
 }
 
 /*
@@ -2071,27 +2060,24 @@
 	if (slpi->valid.psi_static_struct) {
 		spsi = (sal_processor_static_info_t *)p_data;
 
-		/* copy interrupted context PAL min-state info */
-		ia64_process_min_state_save(&spsi->min_state_area);
-
 		/* Print branch register contents if valid */
 		if (spsi->valid.br)
-			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
+			ia64_log_processor_regs_print(spsi->br, 8, brbits, "Branch", "br",
 						      prfunc);
 
 		/* Print control register contents if valid */
 		if (spsi->valid.cr)
-			ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr",
+			ia64_log_processor_regs_print(spsi->cr, 128, crbits, "Control", "cr",
 						      prfunc);
 
 		/* Print application register contents if valid */
 		if (spsi->valid.ar)
-			ia64_log_processor_regs_print(spsi->ar, 128, "Application",
+			ia64_log_processor_regs_print(spsi->ar, 128, arbits, "Application",
 						      "ar", prfunc);
 
 		/* Print region register contents if valid */
 		if (spsi->valid.rr)
-			ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr",
+			ia64_log_processor_regs_print(spsi->rr, 8, rrbits, "Region", "rr",
 						      prfunc);
 
 		/* Print floating-point register contents if valid */
@@ -2319,3 +2305,107 @@
 	}
 	return platform_err;
 }
+
+/*
+ * Purge all entries from the TLB (TC and TR).  Then reload
+ * the TR registers needed by the kernel.
+ *
+ * WARNING: This function executes in physical mode.  This means
+ * that it can't reach out and use functions/data from elsewhere
+ * in the kernel (without jumping through hoops to get the physical
+ * address first).
+ */
+void
+ia64_os_mca_tlb_purge_and_reload(void)
+{
+	unsigned long i, j, count0, count1, stride0, stride1, addr;
+	struct cpuinfo_ia64 *lcd;
+	int cpu;
+	unsigned long pte;
+	struct task_struct *pcurrent;
+	struct ia64_kernel_tr_info *trp;
+
+	/*
+	 * Want to use this:
+	 *	pcurrent = (struct task_struct *)ia64_get_kr(IA64_KR_CURRENT);
+	 * But, the compiler doesn't optimize away the switch, and ends up
+	 * leaving some virtual memory accesses. Same for ar.k4 access later
+	 * in this function.
+	 */
+	asm volatile ("mov %0=ar.k6" : "=r"(pcurrent));
+	cpu = pcurrent->processor;
+
+	trp = (struct ia64_kernel_tr_info *)__pa(&ia64_kernel_tr_list[cpu][0]);
+
+	/* compute physical address of our local_cpu_data */
+	lcd = (struct cpuinfo_ia64 *)(pte_val(trp[IA64_TR_PERCPU_DATA].d_pte) & _PFN_MASK);
+	addr    = lcd->ptce_base;
+	count0  = lcd->ptce_count[0];
+	count1  = lcd->ptce_count[1];
+	stride0 = lcd->ptce_stride[0];
+	stride1 = lcd->ptce_stride[1];
+
+	for (i = 0; i < count0; ++i) {
+		for (j = 0; j < count1; ++j) {
+			asm volatile ("ptc.e %0" :: "r"(addr));
+			addr += stride1;
+		}
+		addr += stride0;
+	}
+	ia64_srlz_i();			/* srlz.i implies srlz.d */
+
+
+	/* Now purge addresses formerly mapped by TR registers */
+	for (i = 0; i < IA64_TR_MAXTR; i++) {
+		/* If trp[i] contains ITR data, purget it here. */
+		if (trp[i].i_valid==1)
+		{
+			addr=trp[i].i_vmaddr;
+			ia64_ptr(1, addr, trp[i].i_log_pgsize);
+		}
+		/* If trp[i] contains DTR data, purge it here. */
+		if (trp[i].d_valid==1)
+		{
+			if (i == IA64_TR_CURRENT_STACK) {
+				/* trp[i] only contains DTR for IA64_TR_CURRENT_STACK */
+				/* ia64_get_kr(IA64_KR_CURRENT_STACK) */
+				asm volatile ("mov %0=ar.k4" : "=r"(addr));
+				addr <<= IA64_GRANULE_SHIFT;
+				addr = (unsigned long)__va(addr);
+			}
+			else
+				addr=trp[i].d_vmaddr;
+
+			ia64_ptr(2, addr, trp[i].d_log_pgsize);
+		}
+	}
+
+	ia64_srlz_i();			/* srlz.i implies srlz.d */
+
+	/* Finally reload the TR registers */
+	for (i = 0; i < IA64_TR_MAXTR; i++) {
+		/* If trp[i] contains ITR data, insert it to ITR. */
+		if (trp[i].i_valid==1)
+		{
+			addr = trp[i].i_vmaddr;
+			pte = pte_val(trp[i].i_pte);
+			ia64_itr(1, i, addr, pte, trp[i].i_log_pgsize);
+		}
+		/* If trp[i] contains DTR data, insert it to DTR. */
+		if (trp[i].d_valid==1)
+		{
+			if (i == IA64_TR_CURRENT_STACK) {
+				/* ia64_get_kr(IA64_KR_CURRENT_STACK) */
+				asm volatile ("mov %0=ar.k4" : "=r"(pte));
+				pte <<= IA64_GRANULE_SHIFT;
+				addr = (u64)__va(pte);
+				pte = pte_val(mk_pte_phys(pte, PAGE_KERNEL));
+			}
+			else {
+				addr = trp[i].d_vmaddr;
+				pte = pte_val(trp[i].d_pte);
+			}
+			ia64_itr(2, i, addr, pte, trp[i].d_log_pgsize);
+		}
+	}
+}
diff -Nur A/arch/ia64/kernel/mca_asm.S B/arch/ia64/kernel/mca_asm.S
--- A/arch/ia64/kernel/mca_asm.S	Tue May 27 19:07:44 2003
+++ B/arch/ia64/kernel/mca_asm.S	Tue May 27 19:08:25 2003
@@ -13,6 +13,9 @@
 //		   2. Restore current thread pointer to kr6
 //		   3. Move stack ptr 16 bytes to conform to C calling convention
 //
+// 02/10/01 J.Hall <jenna.s.hall@intel.com>
+//		   1. Added TLB error recovery:  purge TC's and re-load TR's
+//
 #include <linux/config.h>
 
 #include <asm/asmmacro.h>
@@ -22,22 +25,18 @@
 #include <asm/mca.h>
 
 /*
- * When we get an machine check, the kernel stack pointer is no longer
+ * When we get a machine check, the kernel stack pointer is no longer
  * valid, so we need to set a new stack pointer.
  */
 #define	MINSTATE_PHYS	/* Make sure stack access is physical for MINSTATE */
 
 /*
- * Needed for ia64_sal call
- */
-#define SAL_GET_STATE_INFO      0x01000001
-
-/*
  * Needed for return context to SAL
  */
-#define IA64_MCA_SAME_CONTEXT	0x0
+#define IA64_MCA_SAME_CONTEXT	0
 #define IA64_MCA_COLD_BOOT	-2
 
+
 #include "minstate.h"
 
 /*
@@ -57,12 +56,12 @@
 	st8	[_tmp]=r9,0x08;;			\
 	st8	[_tmp]=r10,0x08;;			\
 	st8	[_tmp]=r11,0x08;;			\
-	st8	[_tmp]=r12,0x08
+	st8	[_tmp]=r12,0x08;;			\
+	st8	[_tmp]=r17,0x08;;			\
+	st8	[_tmp]=r18,0x08
 
 /*
  * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec)
- * (p6) is executed if we never entered virtual mode (TLB error)
- * (p7) is executed if we entered virtual mode as expected (normal case)
  *	1. GR8 = OS_MCA return status
  *	2. GR9 = SAL GP (physical)
  *	3. GR10 = 0/1 returning same/new context
@@ -70,19 +69,14 @@
  *	returns ptr to SAL rtn save loc in _tmp
  */
 #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp)	\
-(p6)	movl	_tmp=ia64_sal_to_os_handoff_state;;	\
-(p7)	movl	_tmp=ia64_os_to_sal_handoff_state;;	\
+	movl	_tmp=ia64_os_to_sal_handoff_state;;	\
 	DATA_VA_TO_PA(_tmp);;				\
-(p6)	movl	r8=IA64_MCA_COLD_BOOT;			\
-(p6)	movl	r10=IA64_MCA_SAME_CONTEXT;		\
-(p6)	add     _tmp=0x18,_tmp;;			\
-(p6)	ld8	r9=[_tmp],0x10;				\
-(p6)	movl	r22=ia64_mca_min_state_save_info;;	\
-(p7)	ld8	r8=[_tmp],0x08;;			\
-(p7)	ld8	r9=[_tmp],0x08;;			\
-(p7)	ld8     r10=[_tmp],0x08;;			\
-(p7)	ld8     r22=[_tmp],0x08;;			\
-	DATA_VA_TO_PA(r22)
+	ld8	r8=[_tmp],0x08;;			\
+	ld8	r9=[_tmp],0x08;;			\
+	ld8	r10=[_tmp],0x08;;			\
+	ld8	r22=[_tmp],0x08;;			\
+	DATA_VA_TO_PA(r22);;				\
+	dep	r22=-1,r22,63,1
 	// now _tmp is pointing to SAL rtn save location
 
 
@@ -95,21 +89,20 @@
 	.global	ia64_mca_stackframe
 	.global	ia64_mca_bspstore
 	.global ia64_init_stack
-	.global ia64_mca_sal_data_area
-	.global ia64_tlb_functional
-	.global ia64_mca_min_state_save_info
 
 	.text
 	.align 16
 
 ia64_os_mca_dispatch:
 
-#if defined(MCA_TEST)
-	// Pretend that we are in interrupt context
-	mov		r2=psr
-	dep		r2=0, r2, PSR_IC, 2;
-	mov		psr.l = r2
-#endif	/* #if defined(MCA_TEST) */
+	// Serialize all MCA processing
+	movl	r2=ia64_mca_serialize
+	mov	r3=1;;
+	DATA_VA_TO_PA(r2);;
+ia64_os_mca_spin:
+	xchg8	r4=[r2],r3;;
+	cmp.ne	p6,p0=r4,r0
+(p6)	br ia64_os_mca_spin
 
 	// Save the SAL to OS MCA handoff state as defined
 	// by SAL SPEC 3.0
@@ -139,17 +132,20 @@
 					// (C calling convention)
 	DATA_VA_TO_PA(r12);;
 
-	// Check to see if the MCA resulted from a TLB error
-begin_tlb_error_check:
-        br      ia64_os_mca_tlb_error_check;;
+	// Unconditionally purge and re-load TLB to recover any resident errors
+begin_tlb_purge_and_reload:
+	movl		r2=ia64_os_mca_tlb_purge_and_reload;;
+	INST_VA_TO_PA(r2);;		// find phys address of function pointer
+	mov		b6=r2;;
+	br.call.sptk.many    b0=b6;;
 
-done_tlb_error_check:
+done_tlb_purge_and_reload:
 
-        // If TLB is functional, enter virtual mode from physical mode
+        // Enter virtual mode from physical mode
 	VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
 ia64_os_mca_virtual_begin:
 
-	// call our handler
+	// Call virtual mode handler
 	movl		r2=ia64_mca_ucmc_handler;;
 	mov		b6=r2;;
 	br.call.sptk.many    b0=b6;;
@@ -158,13 +154,6 @@
 	PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
 ia64_os_mca_virtual_end:
 
-#if defined(MCA_TEST)
-	// Pretend that we are in interrupt context
-	mov	r2=psr;;
-	dep	r2=0, r2, PSR_IC, 2;;
-	mov	psr.l = r2;;
-#endif	/* #if defined(MCA_TEST) */
-
 	// restore the original stack frame here
 	movl    r2=ia64_mca_stackframe	// restore stack frame from memory at r2
 	;;
@@ -180,14 +169,16 @@
 	br	ia64_os_mca_proc_state_restore;;
 
 ia64_os_mca_done_restore:
-	movl	r3=ia64_tlb_functional;;
-	DATA_VA_TO_PA(r3);;
-	ld8	r3=[r3];;
-	cmp.eq	p6,p7=r0,r3;;
 	OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2);;
 	// branch back to SALE_CHECK
 	ld8		r3=[r2];;
 	mov		b0=r3;;		// SAL_CHECK return address
+
+	// release lock
+	movl		r3=ia64_mca_serialize;;
+	DATA_VA_TO_PA(r3);;
+	st8		[r3]=r0
+
 	br		b0
 	;;
 ia64_os_mca_dispatch_end:
@@ -311,46 +302,43 @@
 	st8		[r2]=r3,160;;               // 160 byte rement
 
 SkipIntrRegs:
-	st8		[r2]=r0,168                 // another 168 byte .
-
-	mov		r3=cr66;;                   // cr.lid
-	st8		[r2]=r3,40                  // 40 byte rement
+	st8		[r2]=r0,152;;               // another 152 byte .
 
-	mov		r3=cr71;;                   // cr.ivr
-	st8		[r2]=r3,8
+	add		r4=8,r2                     // duplicate r2 in r4
+	add		r6=2*8,r2                   // duplicate r2 in r6
 
-	mov		r3=cr72;;                   // cr.tpr
-	st8		[r2]=r3,24                  // 24 byte increment
-
-	mov		r3=r0;;                     // cr.eoi => cr75
-	st8		[r2]=r3,168                 // 168 byte inc.
-
-	mov		r3=r0;;                     // cr.irr0 => cr96
-	st8		[r2]=r3,16               // 16 byte inc.
-
-	mov		r3=r0;;                     // cr.irr1 => cr98
-	st8		[r2]=r3,16               // 16 byte inc.
-
-	mov		r3=r0;;                     // cr.irr2 => cr100
-	st8		[r2]=r3,16               // 16 byte inc
-
-	mov		r3=r0;;                     // cr.irr3 => cr100
-	st8		[r2]=r3,16               // 16b inc.
-
-	mov		r3=r0;;                     // cr.itv => cr114
-	st8		[r2]=r3,16               // 16 byte inc.
+	mov		r3=cr64                     // cr.lid
+//	mov		r5=cr65                     // cr.ivr, don't read it
+	mov		r7=cr66;;                   // cr.tpr
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
 
-	mov		r3=r0;;                     // cr.pmv => cr116
-	st8		[r2]=r3,8
+	mov		r3=r0                       // cr.eoi => cr67
+	mov		r5=r0                       // cr.irr0 => cr68
+	mov		r7=r0;;                     // cr.irr1 => cr69
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
 
-	mov		r3=r0;;                     // cr.lrr0 => cr117
-	st8		[r2]=r3,8
+	mov		r3=r0                       // cr.irr2 => cr70
+	mov		r5=r0                       // cr.irr3 => cr71
+	mov		r7=cr72;;                   // cr.itv => cr72
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
 
-	mov		r3=r0;;                     // cr.lrr1 => cr118
-	st8		[r2]=r3,8
+	mov		r3=cr73                     // cr.pmv => cr73
+	mov		r5=cr74;;                   // cr.cmcv => cr74
+	st8		[r2]=r3,7*8
+	st8		[r4]=r5,7*8;;
+
+	mov		r3=r0                       // cr.lrr0 => cr80
+	mov		r5=r0;;                     // cr.lrr1 => cr81
+	st8		[r2]=r3,23*8
+	st8		[r4]=r5,23*8;;
 
-	mov		r3=r0;;                     // cr.cmcv => cr119
-	st8		[r2]=r3,8*10;;
+	adds		r2=25*8,r2;;
 
 cSaveARs:
 // save ARs
@@ -417,7 +405,8 @@
 	movl		r4=0x00;;
 
 cStRR:
-	mov		r3=rr[r4];;
+	dep.z		r5=r4,61,3;;
+	mov		r3=rr[r5];;
 	st8		[r2]=r3,8
 	add		r4=1,r4
 	br.cloop.sptk.few	cStRR
@@ -524,7 +513,7 @@
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;
 	mov		cr16=r3                     // cr.ipsr
-	mov		cr17=r5                     // cr.isr is read only
+//	mov		cr17=r5                     // cr.isr is read only
 //      mov     cr18=r7;;                   // cr.ida (reserved - don't restore)
 
 	ld8		r3=[r2],3*8
@@ -545,42 +534,45 @@
 	mov		cr25=r3                     // cr.iha
 
 rSkipIntrRegs:
-	ld8		r3=[r2],168;;               // another 168 byte inc.
-
-	ld8		r3=[r2],40;;                // 40 byte increment
-	mov		cr66=r3                     // cr.lid
-
-	ld8		r3=[r2],8;;
-//      mov		cr71=r3                     // cr.ivr is read only
-	ld8		r3=[r2],24;;                // 24 byte increment
-	mov		cr72=r3                     // cr.tpr
+	ld8		r3=[r2],152;;               // another 152 byte inc.
 
-	ld8		r3=[r2],168;;               // 168 byte inc.
-//      mov		cr75=r3                     // cr.eoi
+	add		r4=8,r2                     // duplicate r2 in r4
+	add		r6=2*8,r2;;                 // duplicate r2 in r6
 
-	ld8		r3=[r2],16;;             // 16 byte inc.
-//      mov		cr96=r3                     // cr.irr0 is read only
+	ld8		r3=[r2],8*3
+	ld8		r5=[r4],8*3
+	ld8		r7=[r6],8*3;;
+	mov		cr64=r3                     // cr.lid
+//	mov		cr65=r5                     // cr.ivr is read only
+	mov		cr66=r7;;                   // cr.tpr
+
+	ld8		r3=[r2],8*3
+	ld8		r5=[r4],8*3
+	ld8		r7=[r6],8*3;;
+//	mov		cr67=r3                     // cr.eoi
+//	mov		cr68=r5                     // cr.irr0 is read only
+//	mov		cr69=r7;;                   // cr.irr1 is read only
+
+	ld8		r3=[r2],8*3
+	ld8		r5=[r4],8*3
+	ld8		r7=[r6],8*3;;
+//	mov		cr70=r3                     // cr.irr2 is read only
+//	mov		cr71=r5                     // cr.irr3 is read only
+	mov		cr72=r7;;                   // cr.itv
+
+	ld8		r3=[r2],8*7
+	ld8		r5=[r4],8*7;;
+	mov		cr73=r3                     // cr.pmv
+	mov		cr74=r5;;                   // cr.cmcv
+
+	ld8		r3=[r2],8*23
+	ld8		r5=[r4],8*23;;
+	adds		r2=8*23,r2
+	adds		r4=8*23,r4;;
+//	mov		cr80=r3                     // cr.lrr0
+//	mov		cr81=r5                     // cr.lrr1
 
-	ld8		r3=[r2],16;;             // 16 byte inc.
-//      mov		cr98=r3                     // cr.irr1 is read only
-
-	ld8		r3=[r2],16;;             // 16 byte inc
-//      mov		cr100=r3                    // cr.irr2 is read only
-
-	ld8		r3=[r2],16;;             // 16b inc.
-//      mov		cr102=r3                    // cr.irr3 is read only
-
-	ld8		r3=[r2],16;;             // 16 byte inc.
-//      mov		cr114=r3                    // cr.itv
-
-	ld8		r3=[r2],8;;
-//      mov		cr116=r3                    // cr.pmv
-	ld8		r3=[r2],8;;
-//      mov		cr117=r3                    // cr.lrr0
-	ld8		r3=[r2],8;;
-//      mov		cr118=r3                    // cr.lrr1
-	ld8		r3=[r2],8*10;;
-//      mov		cr119=r3                    // cr.cmcv
+	adds		r2=8*2,r2;;
 
 restore_ARs:
 	add		r4=8,r2                  // duplicate r2 in r4
@@ -646,10 +638,11 @@
 restore_RRs:
 	mov		r5=ar.lc
 	mov		ar.lc=0x08-1
-	movl		r4=0x00
+	movl		r4=0x00;;
 cStRRr:
+	dep.z		r7=r4,61,3
 	ld8		r3=[r2],8;;
-//      mov		rr[r4]=r3                   // what are its access previledges?
+	mov		rr[r7]=r3                   // what are its access previledges?
 	add		r4=1,r4
 	br.cloop.sptk.few	cStRRr
 	;;
@@ -660,79 +653,6 @@
 
 //EndStub//////////////////////////////////////////////////////////////////////
 
-//++
-// Name:
-//	ia64_os_mca_tlb_error_check()
-//
-// Stub Description:
-//
-//	This stub checks to see if the MCA resulted from a TLB error
-//
-//--
-
-ia64_os_mca_tlb_error_check:
-
-	// Retrieve sal data structure for uncorrected MCA
-
-	// Make the ia64_sal_get_state_info() call
-	movl	r4=ia64_mca_sal_data_area;;
-	movl	r7=ia64_sal;;
-	mov	r6=r1			// save gp
-	DATA_VA_TO_PA(r4)		// convert to physical address
-	DATA_VA_TO_PA(r7);;		// convert to physical address
-	ld8	r7=[r7]			// get addr of pdesc from ia64_sal
-	movl	r3=SAL_GET_STATE_INFO;;
-	DATA_VA_TO_PA(r7);;		// convert to physical address
-	ld8	r8=[r7],8;;		// get pdesc function pointer
-	dep	r8=0,r8,61,3;;		// convert SAL VA to PA
-	ld8	r1=[r7];;		// set new (ia64_sal) gp
-	dep	r1=0,r1,61,3;;		// convert SAL VA to PA
-	mov	b6=r8
-
-	alloc	r5=ar.pfs,8,0,8,0;;	// allocate stack frame for SAL call
-	mov	out0=r3			// which SAL proc to call
-	mov	out1=r0			// error type == MCA
-	mov	out2=r0			// null arg
-	mov	out3=r4			// data copy area
-	mov	out4=r0			// null arg
-	mov	out5=r0			// null arg
-	mov	out6=r0			// null arg
-	mov	out7=r0;;		// null arg
-
-	br.call.sptk.few	b0=b6;;
-
-	mov	r1=r6			// restore gp
-	mov	ar.pfs=r5;;		// restore ar.pfs
-
-	movl	r6=ia64_tlb_functional;;
-	DATA_VA_TO_PA(r6)		// needed later
-
-	cmp.eq	p6,p7=r0,r8;;		// check SAL call return address
-(p7)	st8	[r6]=r0			// clear tlb_functional flag
-(p7)    br	tlb_failure		// error; return to SAL
-
-	// examine processor error log for type of error
-	add	r4=40+24,r4;;		// parse past record header (length=40)
-					// and section header (length=24)
-	ld4	r4=[r4]			// get valid field of processor log
-	mov	r5=0xf00;;
-	and	r5=r4,r5;;		// read bits 8-11 of valid field
-					// to determine if we have a TLB error
-	movl	r3=0x1
-	cmp.eq	p6,p7=r0,r5;;
-	// if no TLB failure, set tlb_functional flag
-(p6)	st8	[r6]=r3
-	// else clear flag
-(p7)	st8	[r6]=r0
-
-	// if no TLB failure, continue with normal virtual mode logging
-(p6)    br	done_tlb_error_check
-	// else no point in entering virtual mode for logging
-tlb_failure:
-	br      ia64_os_mca_virtual_end
-
-//EndStub//////////////////////////////////////////////////////////////////////
-
 
 // ok, the issue here is that we need to save state information so
 // it can be useable by the kernel debugger and show regs routines.
diff -Nur A/arch/ia64/kernel/setup.c B/arch/ia64/kernel/setup.c
--- A/arch/ia64/kernel/setup.c	Tue May 27 19:07:44 2003
+++ B/arch/ia64/kernel/setup.c	Tue May 27 19:08:25 2003
@@ -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
diff -Nur A/arch/ia64/mm/init.c B/arch/ia64/mm/init.c
--- A/arch/ia64/mm/init.c	Tue May 27 19:07:44 2003
+++ B/arch/ia64/mm/init.c	Tue May 27 19:08:33 2003
@@ -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
diff -Nur A/include/asm-ia64/kregs.h B/include/asm-ia64/kregs.h
--- A/include/asm-ia64/kregs.h	Tue May 27 19:08:10 2003
+++ B/include/asm-ia64/kregs.h	Tue May 27 19:11:09 2003
@@ -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
diff -Nur A/include/asm-ia64/mca.h B/include/asm-ia64/mca.h
--- A/include/asm-ia64/mca.h	Tue May 27 19:08:10 2003
+++ B/include/asm-ia64/mca.h	Tue May 27 19:11:10 2003
@@ -5,6 +5,7 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
  * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ * Copyright (C) Jenna Hall (jenna.s.hall@intel.com)
  */
 
 #ifndef _ASM_IA64_MCA_H
@@ -15,6 +16,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;
@@ -58,6 +60,18 @@
 	IA64_MCA_RENDEZ_CHECKIN_DONE	=	0x1
 };
 
+/* the following data structures are used for TLB error recovery purposes */
+extern struct ia64_kernel_tr_info {
+	u32	i_valid;	/* 1=ITR, 0=void */
+	u64	i_vmaddr;	/* virtual address in ITR */
+	pte_t	i_pte;		/* physical address & permissions in ITR */
+	u64	i_log_pgsize;	/* pagesize = 2**log_pagesize in ITR */
+	u32	d_valid;	/* 1=DTR, 0=void */
+	u64	d_vmaddr;	/* virtual address in DTR */
+	pte_t	d_pte;		/* physical address & permissions in DTR */
+	u64	d_log_pgsize;	/* pagesize = 2**log_pagesize in DTR */
+} ia64_kernel_tr_list[NR_CPUS][IA64_TR_MAXTR];
+
 /* Information maintained by the MC infrastructure */
 typedef struct ia64_mc_info_s {
 	u64		imi_mca_handler;
@@ -89,6 +103,8 @@
 	u64		imsto_sal_check_ra;	/* Return address in SAL_CHECK while going
 						 * back to SAL from OS after MCA handling.
 						 */
+	u64		*pal_min_state;		/* from PAL in r17 */
+	u64		proc_state_param;	/* from PAL in r18. See SDV 2:268 11.3.2.1 */
 } ia64_mca_sal_to_os_state_t;
 
 enum {
@@ -103,7 +119,7 @@
 	IA64_MCA_NEW_CONTEXT	=	-1	/* SAL to return to new context */
 };
 
-#define MIN_STATE_AREA_SIZE     57
+#define MIN_STATE_AREA_SIZE     58
 
 typedef struct ia64_mca_os_to_sal_state_s {
 	u64		imots_os_status;	/*   OS status to SAL as to what happened
@@ -138,6 +154,31 @@
 extern int  ia64_mca_check_errors(void);
 extern u64  ia64_log_get(int, prfunc_t);
 
+/*
+ * Insert a translation entry into ia64_kernel_tr_list[][] for MCA recoverary purpose.
+ */
+static void
+ia64_itr_list (int cpu, __u64 target_mask, __u64 tr_num,
+	  __u64 vmaddr, __u64 pte,
+	  __u64 log_page_size)
+{
+	if (target_mask & 0x1)
+	{
+		ia64_kernel_tr_list[cpu][tr_num].i_valid=1;
+		pte_val(ia64_kernel_tr_list[cpu][tr_num].i_pte)=pte;
+		ia64_kernel_tr_list[cpu][tr_num].i_vmaddr=vmaddr;
+		ia64_kernel_tr_list[cpu][tr_num].i_log_pgsize=log_page_size;
+	}
+
+	if (target_mask & 0x2)
+	{
+		ia64_kernel_tr_list[cpu][tr_num].d_valid=1;
+		pte_val(ia64_kernel_tr_list[cpu][tr_num].d_pte)=pte;
+		ia64_kernel_tr_list[cpu][tr_num].d_vmaddr=vmaddr;
+		ia64_kernel_tr_list[cpu][tr_num].d_log_pgsize=log_page_size;
+	} 
+}
+
 #define PLATFORM_CALL(fn, args)	printk("Platform call TBD\n")
 
 #define platform_mem_dev_err_print ia64_log_prt_oem_data
