public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
From: "Luck, Tony" <tony.luck@intel.com>
To: linux-ia64@vger.kernel.org
Subject: [Linux-ia64] [PATCH] MCA recovery for TLB faults for 2.4
Date: Wed, 28 May 2003 20:35:53 +0000	[thread overview]
Message-ID: <marc-linux-ia64-105590723706058@msgid-missing> (raw)

[-- Attachment #1: Type: text/plain, Size: 1256 bytes --]

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


[-- Attachment #2: mca.patch --]
[-- Type: application/octet-stream, Size: 28622 bytes --]

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

             reply	other threads:[~2003-05-28 20:35 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-05-28 20:35 Luck, Tony [this message]
2003-05-28 22:37 ` [Linux-ia64] [PATCH] MCA recovery for TLB faults for 2.4 Keith Owens
2003-05-31  1:34 ` David Mosberger
2003-06-02 17:00 ` Luck, Tony
2003-06-02 18:19 ` David Mosberger
2003-06-02 18:34 ` Luck, Tony
2003-06-02 18:39 ` David Mosberger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=marc-linux-ia64-105590723706058@msgid-missing \
    --to=tony.luck@intel.com \
    --cc=linux-ia64@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox