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 #include #include +#include #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;igp, + __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 +// 1. Added TLB error recovery: purge TC's and re-load TR's +// #include #include @@ -22,22 +25,18 @@ #include /* - * 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 #include #include +#include /* 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 #include #include +#include /* 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