Commit d1df9cdc authored by Tony Luck's avatar Tony Luck Committed by David Mosberger

[PATCH] ia64: enable recovery from TLB errors

Here's the updated version of the MCA TLB recovery patch.
parent d273c362
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <asm-ia64/ptrace.h> #include <asm-ia64/ptrace.h>
#include <asm-ia64/siginfo.h> #include <asm-ia64/siginfo.h>
#include <asm-ia64/sigcontext.h> #include <asm-ia64/sigcontext.h>
#include <asm-ia64/mca.h>
#include "../kernel/sigframe.h" #include "../kernel/sigframe.h"
...@@ -204,4 +205,7 @@ void foo(void) ...@@ -204,4 +205,7 @@ void foo(void)
# error "CLONE_SETTLS_BIT incorrect, please fix" # error "CLONE_SETTLS_BIT incorrect, please fix"
#endif #endif
BLANK();
DEFINE(IA64_MCA_TLB_INFO_SIZE, sizeof (struct ia64_mca_tlb_info));
} }
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <asm/kregs.h> #include <asm/kregs.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/mca.h>
#define EFI_DEBUG 0 #define EFI_DEBUG 0
...@@ -395,6 +396,9 @@ efi_map_pal_code (void) ...@@ -395,6 +396,9 @@ efi_map_pal_code (void)
int pal_code_count = 0; int pal_code_count = 0;
u64 mask, psr; u64 mask, psr;
u64 vaddr; u64 vaddr;
#ifdef CONFIG_IA64_MCA
int cpu;
#endif
efi_map_start = __va(ia64_boot_param->efi_memmap); efi_map_start = __va(ia64_boot_param->efi_memmap);
efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
...@@ -455,6 +459,14 @@ efi_map_pal_code (void) ...@@ -455,6 +459,14 @@ efi_map_pal_code (void)
IA64_GRANULE_SHIFT); IA64_GRANULE_SHIFT);
ia64_set_psr(psr); /* restore psr */ ia64_set_psr(psr); /* restore psr */
ia64_srlz_i(); ia64_srlz_i();
#ifdef CONFIG_IA64_MCA
cpu = smp_processor_id();
/* insert this TR into our list for MCA recovery purposes */
ia64_mca_tlb_list[cpu].pal_base = vaddr & mask;
ia64_mca_tlb_list[cpu].pal_paddr = pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL));
#endif
} }
} }
......
...@@ -83,9 +83,8 @@ u64 ia64_mca_stack[1024] __attribute__((aligned(16))); ...@@ -83,9 +83,8 @@ u64 ia64_mca_stack[1024] __attribute__((aligned(16)));
u64 ia64_mca_stackframe[32]; u64 ia64_mca_stackframe[32];
u64 ia64_mca_bspstore[1024]; u64 ia64_mca_bspstore[1024];
u64 ia64_init_stack[KERNEL_STACK_SIZE/8] __attribute__((aligned(16))); u64 ia64_init_stack[KERNEL_STACK_SIZE/8] __attribute__((aligned(16)));
u64 ia64_mca_sal_data_area[1356];
u64 ia64_tlb_functional;
u64 ia64_os_mca_recovery_successful; u64 ia64_os_mca_recovery_successful;
u64 ia64_mca_serialize;
static void ia64_mca_wakeup_ipi_wait(void); static void ia64_mca_wakeup_ipi_wait(void);
static void ia64_mca_wakeup(int cpu); static void ia64_mca_wakeup(int cpu);
static void ia64_mca_wakeup_all(void); static void ia64_mca_wakeup_all(void);
...@@ -95,6 +94,8 @@ extern void ia64_slave_init_handler (void); ...@@ -95,6 +94,8 @@ extern void ia64_slave_init_handler (void);
static u64 ia64_log_get(int sal_info_type, u8 **buffer); static u64 ia64_log_get(int sal_info_type, u8 **buffer);
extern struct hw_interrupt_type irq_type_iosapic_level; extern struct hw_interrupt_type irq_type_iosapic_level;
struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS];
static struct irqaction cmci_irqaction = { static struct irqaction cmci_irqaction = {
.handler = ia64_mca_cmc_int_handler, .handler = ia64_mca_cmc_int_handler,
.flags = SA_INTERRUPT, .flags = SA_INTERRUPT,
...@@ -984,6 +985,9 @@ ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) ...@@ -984,6 +985,9 @@ ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
void void
ia64_return_to_sal_check(void) ia64_return_to_sal_check(void)
{ {
pal_processor_state_info_t *psp = (pal_processor_state_info_t *)
&ia64_sal_to_os_handoff_state.proc_state_param;
/* Copy over some relevant stuff from the sal_to_os_mca_handoff /* Copy over some relevant stuff from the sal_to_os_mca_handoff
* so that it can be used at the time of os_mca_to_sal_handoff * so that it can be used at the time of os_mca_to_sal_handoff
*/ */
...@@ -993,14 +997,22 @@ ia64_return_to_sal_check(void) ...@@ -993,14 +997,22 @@ ia64_return_to_sal_check(void)
ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_os_to_sal_handoff_state.imots_sal_check_ra =
ia64_sal_to_os_handoff_state.imsto_sal_check_ra; ia64_sal_to_os_handoff_state.imsto_sal_check_ra;
/* Cold Boot for uncorrectable MCA */ /*
* Did we correct the error? At the moment the only error that
* we fix is a TLB error, if any other kind of error occurred
* we must reboot.
*/
if (psp->cc == 1 && psp->bc == 1 && psp->rc == 1 && psp->uc == 1)
ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
else
ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED;
/* Default = tell SAL to return to same context */ /* Default = tell SAL to return to same context */
ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
ia64_os_to_sal_handoff_state.imots_new_min_state = ia64_os_to_sal_handoff_state.imots_new_min_state =
(u64 *)ia64_sal_to_os_handoff_state.pal_min_state; (u64 *)ia64_sal_to_os_handoff_state.pal_min_state;
} }
/* /*
...@@ -1359,8 +1371,8 @@ ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) ...@@ -1359,8 +1371,8 @@ ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw)
void void
ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc) ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc)
{ {
char out[40]; //char out[40];
printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out)); //printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out));
} }
static void static void
......
This diff is collapsed.
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/mca.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
...@@ -277,6 +278,10 @@ ia64_mmu_init (void *my_cpu_data) ...@@ -277,6 +278,10 @@ ia64_mmu_init (void *my_cpu_data)
{ {
unsigned long psr, pta, impl_va_bits; unsigned long psr, pta, impl_va_bits;
extern void __init tlb_init (void); extern void __init tlb_init (void);
#ifdef CONFIG_IA64_MCA
int cpu;
#endif
#ifdef CONFIG_DISABLE_VHPT #ifdef CONFIG_DISABLE_VHPT
# define VHPT_ENABLE_BIT 0 # define VHPT_ENABLE_BIT 0
#else #else
...@@ -335,6 +340,22 @@ ia64_mmu_init (void *my_cpu_data) ...@@ -335,6 +340,22 @@ ia64_mmu_init (void *my_cpu_data)
ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT);
ia64_tlb_init(); ia64_tlb_init();
#ifdef CONFIG_IA64_MCA
cpu = smp_processor_id();
/* mca handler uses cr.lid as key to pick the right entry */
ia64_mca_tlb_list[cpu].cr_lid = ia64_getreg(_IA64_REG_CR_LID);
/* insert this percpu data information into our list for MCA recovery purposes */
ia64_mca_tlb_list[cpu].percpu_paddr = pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL));
/* Also save per-cpu tlb flush recipe for use in physical mode mca handler */
ia64_mca_tlb_list[cpu].ptce_base = local_cpu_data->ptce_base;
ia64_mca_tlb_list[cpu].ptce_count[0] = local_cpu_data->ptce_count[0];
ia64_mca_tlb_list[cpu].ptce_count[1] = local_cpu_data->ptce_count[1];
ia64_mca_tlb_list[cpu].ptce_stride[0] = local_cpu_data->ptce_stride[0];
ia64_mca_tlb_list[cpu].ptce_stride[1] = local_cpu_data->ptce_stride[1];
#endif
} }
#ifdef CONFIG_VIRTUAL_MEM_MAP #ifdef CONFIG_VIRTUAL_MEM_MAP
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <asm/param.h> #include <asm/param.h>
#include <asm/sal.h> #include <asm/sal.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/mca_asm.h>
/* These are the return codes from all the IA64_MCA specific interfaces */ /* These are the return codes from all the IA64_MCA specific interfaces */
typedef int ia64_mca_return_code_t; typedef int ia64_mca_return_code_t;
...@@ -61,6 +62,17 @@ enum { ...@@ -61,6 +62,17 @@ enum {
IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1
}; };
/* the following data structure is used for TLB error recovery purposes */
extern struct ia64_mca_tlb_info {
u64 cr_lid;
u64 percpu_paddr;
u64 ptce_base;
u32 ptce_count[2];
u32 ptce_stride[2];
u64 pal_paddr;
u64 pal_base;
} ia64_mca_tlb_list[NR_CPUS];
/* Information maintained by the MC infrastructure */ /* Information maintained by the MC infrastructure */
typedef struct ia64_mc_info_s { typedef struct ia64_mc_info_s {
u64 imi_mca_handler; u64 imi_mca_handler;
......
...@@ -230,6 +230,10 @@ ia64_phys_addr_valid (unsigned long addr) ...@@ -230,6 +230,10 @@ ia64_phys_addr_valid (unsigned long addr)
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
/* This takes a physical page address that is used by the remapping functions */
#define mk_pte_phys(physpage, pgprot) \
({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
#define pte_modify(_pte, newprot) \ #define pte_modify(_pte, newprot) \
(__pte((pte_val(_pte) & ~_PAGE_CHG_MASK) | (pgprot_val(newprot) & _PAGE_CHG_MASK))) (__pte((pte_val(_pte) & ~_PAGE_CHG_MASK) | (pgprot_val(newprot) & _PAGE_CHG_MASK)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment