Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Browse files Browse the repository at this point in the history
Pull sparc fixes from David Miller:
 "Several small bug fixes and tidies, along with a fix for non-resumable
  memory errors triggered by userspace"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
  sparc64: Handle PIO & MEM non-resumable errors.
  sparc64: Zero pages on allocation for mondo and error queues.
  sparc: Fixed typo in sstate.c. Replaced panicing with panicking
  sparc: use symbolic names for tsb indexing
  • Loading branch information
torvalds committed Jan 30, 2017
2 parents 751321b + 54791b2 commit f9a42e0
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 8 deletions.
8 changes: 4 additions & 4 deletions arch/sparc/include/asm/mmu_context_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ void __tsb_context_switch(unsigned long pgd_pa,
static inline void tsb_context_switch(struct mm_struct *mm)
{
__tsb_context_switch(__pa(mm->pgd),
&mm->context.tsb_block[0],
&mm->context.tsb_block[MM_TSB_BASE],
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
(mm->context.tsb_block[1].tsb ?
&mm->context.tsb_block[1] :
(mm->context.tsb_block[MM_TSB_HUGE].tsb ?
&mm->context.tsb_block[MM_TSB_HUGE] :
NULL)
#else
NULL
#endif
, __pa(&mm->context.tsb_descr[0]));
, __pa(&mm->context.tsb_descr[MM_TSB_BASE]));
}

void tsb_grow(struct mm_struct *mm,
Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/kernel/irq_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ static void __init alloc_one_queue(unsigned long *pa_ptr, unsigned long qmask)
unsigned long order = get_order(size);
unsigned long p;

p = __get_free_pages(GFP_KERNEL, order);
p = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
if (!p) {
prom_printf("SUN4V: Error, cannot allocate queue.\n");
prom_halt();
Expand Down
6 changes: 3 additions & 3 deletions arch/sparc/kernel/sstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ static const char poweroff_msg[32] __attribute__((aligned(32))) =
"Linux powering off";
static const char rebooting_msg[32] __attribute__((aligned(32))) =
"Linux rebooting";
static const char panicing_msg[32] __attribute__((aligned(32))) =
"Linux panicing";
static const char panicking_msg[32] __attribute__((aligned(32))) =
"Linux panicking";

static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
{
Expand Down Expand Up @@ -76,7 +76,7 @@ static struct notifier_block sstate_reboot_notifier = {

static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
{
do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
do_set_sstate(HV_SOFT_STATE_TRANSITION, panicking_msg);

return NOTIFY_DONE;
}
Expand Down
73 changes: 73 additions & 0 deletions arch/sparc/kernel/traps_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -2051,6 +2051,73 @@ void sun4v_resum_overflow(struct pt_regs *regs)
atomic_inc(&sun4v_resum_oflow_cnt);
}

/* Given a set of registers, get the virtual addressi that was being accessed
* by the faulting instructions at tpc.
*/
static unsigned long sun4v_get_vaddr(struct pt_regs *regs)
{
unsigned int insn;

if (!copy_from_user(&insn, (void __user *)regs->tpc, 4)) {
return compute_effective_address(regs, insn,
(insn >> 25) & 0x1f);
}
return 0;
}

/* Attempt to handle non-resumable errors generated from userspace.
* Returns true if the signal was handled, false otherwise.
*/
bool sun4v_nonresum_error_user_handled(struct pt_regs *regs,
struct sun4v_error_entry *ent) {

unsigned int attrs = ent->err_attrs;

if (attrs & SUN4V_ERR_ATTRS_MEMORY) {
unsigned long addr = ent->err_raddr;
siginfo_t info;

if (addr == ~(u64)0) {
/* This seems highly unlikely to ever occur */
pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory error detected in unknown location!\n");
} else {
unsigned long page_cnt = DIV_ROUND_UP(ent->err_size,
PAGE_SIZE);

/* Break the unfortunate news. */
pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory failed at %016lX\n",
addr);
pr_emerg("SUN4V NON-RECOVERABLE ERROR: Claiming %lu ages.\n",
page_cnt);

while (page_cnt-- > 0) {
if (pfn_valid(addr >> PAGE_SHIFT))
get_page(pfn_to_page(addr >> PAGE_SHIFT));
addr += PAGE_SIZE;
}
}
info.si_signo = SIGKILL;
info.si_errno = 0;
info.si_trapno = 0;
force_sig_info(info.si_signo, &info, current);

return true;
}
if (attrs & SUN4V_ERR_ATTRS_PIO) {
siginfo_t info;

info.si_signo = SIGBUS;
info.si_code = BUS_ADRERR;
info.si_addr = (void __user *)sun4v_get_vaddr(regs);
force_sig_info(info.si_signo, &info, current);

return true;
}

/* Default to doing nothing */
return false;
}

/* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate.
* Log the event, clear the first word of the entry, and die.
*/
Expand All @@ -2075,6 +2142,12 @@ void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)

put_cpu();

if (!(regs->tstate & TSTATE_PRIV) &&
sun4v_nonresum_error_user_handled(regs, &local_copy)) {
/* DON'T PANIC: This userspace error was handled. */
return;
}

#ifdef CONFIG_PCI
/* Check for the special PCI poke sequence. */
if (pci_poke_in_progress && pci_poke_cpu == cpu) {
Expand Down

0 comments on commit f9a42e0

Please sign in to comment.