aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc/include/asm/mmu_context_64.h8
-rw-r--r--arch/sparc/kernel/irq_64.c2
-rw-r--r--arch/sparc/kernel/sstate.c6
-rw-r--r--arch/sparc/kernel/traps_64.c73
4 files changed, 81 insertions, 8 deletions
diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h
index b84be675e507..d0317993e947 100644
--- a/arch/sparc/include/asm/mmu_context_64.h
+++ b/arch/sparc/include/asm/mmu_context_64.h
@@ -35,15 +35,15 @@ void __tsb_context_switch(unsigned long pgd_pa,
35static inline void tsb_context_switch(struct mm_struct *mm) 35static inline void tsb_context_switch(struct mm_struct *mm)
36{ 36{
37 __tsb_context_switch(__pa(mm->pgd), 37 __tsb_context_switch(__pa(mm->pgd),
38 &mm->context.tsb_block[0], 38 &mm->context.tsb_block[MM_TSB_BASE],
39#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 39#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
40 (mm->context.tsb_block[1].tsb ? 40 (mm->context.tsb_block[MM_TSB_HUGE].tsb ?
41 &mm->context.tsb_block[1] : 41 &mm->context.tsb_block[MM_TSB_HUGE] :
42 NULL) 42 NULL)
43#else 43#else
44 NULL 44 NULL
45#endif 45#endif
46 , __pa(&mm->context.tsb_descr[0])); 46 , __pa(&mm->context.tsb_descr[MM_TSB_BASE]));
47} 47}
48 48
49void tsb_grow(struct mm_struct *mm, 49void tsb_grow(struct mm_struct *mm,
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
index 3bebf395252c..4d0248aa0928 100644
--- a/arch/sparc/kernel/irq_64.c
+++ b/arch/sparc/kernel/irq_64.c
@@ -1021,7 +1021,7 @@ static void __init alloc_one_queue(unsigned long *pa_ptr, unsigned long qmask)
1021 unsigned long order = get_order(size); 1021 unsigned long order = get_order(size);
1022 unsigned long p; 1022 unsigned long p;
1023 1023
1024 p = __get_free_pages(GFP_KERNEL, order); 1024 p = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
1025 if (!p) { 1025 if (!p) {
1026 prom_printf("SUN4V: Error, cannot allocate queue.\n"); 1026 prom_printf("SUN4V: Error, cannot allocate queue.\n");
1027 prom_halt(); 1027 prom_halt();
diff --git a/arch/sparc/kernel/sstate.c b/arch/sparc/kernel/sstate.c
index c59af546f522..3caed4023589 100644
--- a/arch/sparc/kernel/sstate.c
+++ b/arch/sparc/kernel/sstate.c
@@ -43,8 +43,8 @@ static const char poweroff_msg[32] __attribute__((aligned(32))) =
43 "Linux powering off"; 43 "Linux powering off";
44static const char rebooting_msg[32] __attribute__((aligned(32))) = 44static const char rebooting_msg[32] __attribute__((aligned(32))) =
45 "Linux rebooting"; 45 "Linux rebooting";
46static const char panicing_msg[32] __attribute__((aligned(32))) = 46static const char panicking_msg[32] __attribute__((aligned(32))) =
47 "Linux panicing"; 47 "Linux panicking";
48 48
49static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused) 49static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
50{ 50{
@@ -76,7 +76,7 @@ static struct notifier_block sstate_reboot_notifier = {
76 76
77static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr) 77static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
78{ 78{
79 do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg); 79 do_set_sstate(HV_SOFT_STATE_TRANSITION, panicking_msg);
80 80
81 return NOTIFY_DONE; 81 return NOTIFY_DONE;
82} 82}
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index 4bc10e44d1ca..dfc97a47c9a0 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -2051,6 +2051,73 @@ void sun4v_resum_overflow(struct pt_regs *regs)
2051 atomic_inc(&sun4v_resum_oflow_cnt); 2051 atomic_inc(&sun4v_resum_oflow_cnt);
2052} 2052}
2053 2053
2054/* Given a set of registers, get the virtual addressi that was being accessed
2055 * by the faulting instructions at tpc.
2056 */
2057static unsigned long sun4v_get_vaddr(struct pt_regs *regs)
2058{
2059 unsigned int insn;
2060
2061 if (!copy_from_user(&insn, (void __user *)regs->tpc, 4)) {
2062 return compute_effective_address(regs, insn,
2063 (insn >> 25) & 0x1f);
2064 }
2065 return 0;
2066}
2067
2068/* Attempt to handle non-resumable errors generated from userspace.
2069 * Returns true if the signal was handled, false otherwise.
2070 */
2071bool sun4v_nonresum_error_user_handled(struct pt_regs *regs,
2072 struct sun4v_error_entry *ent) {
2073
2074 unsigned int attrs = ent->err_attrs;
2075
2076 if (attrs & SUN4V_ERR_ATTRS_MEMORY) {
2077 unsigned long addr = ent->err_raddr;
2078 siginfo_t info;
2079
2080 if (addr == ~(u64)0) {
2081 /* This seems highly unlikely to ever occur */
2082 pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory error detected in unknown location!\n");
2083 } else {
2084 unsigned long page_cnt = DIV_ROUND_UP(ent->err_size,
2085 PAGE_SIZE);
2086
2087 /* Break the unfortunate news. */
2088 pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory failed at %016lX\n",
2089 addr);
2090 pr_emerg("SUN4V NON-RECOVERABLE ERROR: Claiming %lu ages.\n",
2091 page_cnt);
2092
2093 while (page_cnt-- > 0) {
2094 if (pfn_valid(addr >> PAGE_SHIFT))
2095 get_page(pfn_to_page(addr >> PAGE_SHIFT));
2096 addr += PAGE_SIZE;
2097 }
2098 }
2099 info.si_signo = SIGKILL;
2100 info.si_errno = 0;
2101 info.si_trapno = 0;
2102 force_sig_info(info.si_signo, &info, current);
2103
2104 return true;
2105 }
2106 if (attrs & SUN4V_ERR_ATTRS_PIO) {
2107 siginfo_t info;
2108
2109 info.si_signo = SIGBUS;
2110 info.si_code = BUS_ADRERR;
2111 info.si_addr = (void __user *)sun4v_get_vaddr(regs);
2112 force_sig_info(info.si_signo, &info, current);
2113
2114 return true;
2115 }
2116
2117 /* Default to doing nothing */
2118 return false;
2119}
2120
2054/* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate. 2121/* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate.
2055 * Log the event, clear the first word of the entry, and die. 2122 * Log the event, clear the first word of the entry, and die.
2056 */ 2123 */
@@ -2075,6 +2142,12 @@ void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)
2075 2142
2076 put_cpu(); 2143 put_cpu();
2077 2144
2145 if (!(regs->tstate & TSTATE_PRIV) &&
2146 sun4v_nonresum_error_user_handled(regs, &local_copy)) {
2147 /* DON'T PANIC: This userspace error was handled. */
2148 return;
2149 }
2150
2078#ifdef CONFIG_PCI 2151#ifdef CONFIG_PCI
2079 /* Check for the special PCI poke sequence. */ 2152 /* Check for the special PCI poke sequence. */
2080 if (pci_poke_in_progress && pci_poke_cpu == cpu) { 2153 if (pci_poke_in_progress && pci_poke_cpu == cpu) {