Commit e225ca27 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc

Pull Sparc updates from David Miller:

 1) Updated syscall tracing fix from Al Viro.

 2) SUN4V error reporting was deficient in several areas.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
  sparc64: fix ptrace interaction with force_successful_syscall_return()
  sparc64: Fix deficiencies in sun4v error reporting.
parents 54f7fc25 55c2770e
...@@ -265,6 +265,11 @@ extern __must_check long strnlen_user(const char __user *str, long n); ...@@ -265,6 +265,11 @@ extern __must_check long strnlen_user(const char __user *str, long n);
#define __copy_to_user_inatomic ___copy_to_user #define __copy_to_user_inatomic ___copy_to_user
#define __copy_from_user_inatomic ___copy_from_user #define __copy_from_user_inatomic ___copy_from_user
struct pt_regs;
extern unsigned long compute_effective_address(struct pt_regs *,
unsigned int insn,
unsigned int rd);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* _ASM_UACCESS_H */ #endif /* _ASM_UACCESS_H */
...@@ -212,24 +212,20 @@ linux_sparc_syscall: ...@@ -212,24 +212,20 @@ linux_sparc_syscall:
3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] 3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
ret_sys_call: ret_sys_call:
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3 ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
sra %o0, 0, %o0 sra %o0, 0, %o0
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
sllx %g2, 32, %g2 sllx %g2, 32, %g2
/* Check if force_successful_syscall_return()
* was invoked.
*/
ldub [%g6 + TI_SYS_NOERROR], %l2
brnz,a,pn %l2, 80f
stb %g0, [%g6 + TI_SYS_NOERROR]
cmp %o0, -ERESTART_RESTARTBLOCK cmp %o0, -ERESTART_RESTARTBLOCK
bgeu,pn %xcc, 1f bgeu,pn %xcc, 1f
andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %l6 andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0
80: ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
2:
stb %g0, [%g6 + TI_SYS_NOERROR]
/* System call success, clear Carry condition code. */ /* System call success, clear Carry condition code. */
andn %g3, %g2, %g3 andn %g3, %g2, %g3
3:
stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2 bne,pn %icc, linux_syscall_trace2
add %l1, 0x4, %l2 ! npc = npc+4 add %l1, 0x4, %l2 ! npc = npc+4
...@@ -238,20 +234,20 @@ ret_sys_call: ...@@ -238,20 +234,20 @@ ret_sys_call:
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
1: 1:
/* Check if force_successful_syscall_return()
* was invoked.
*/
ldub [%g6 + TI_SYS_NOERROR], %l2
brnz,pn %l2, 2b
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
/* System call failure, set Carry condition code. /* System call failure, set Carry condition code.
* Also, get abs(errno) to return to the process. * Also, get abs(errno) to return to the process.
*/ */
andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %l6
sub %g0, %o0, %o0 sub %g0, %o0, %o0
or %g3, %g2, %g3
stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] ba,pt %xcc, 3b
bne,pn %icc, linux_syscall_trace2 or %g3, %g2, %g3
add %l1, 0x4, %l2 ! npc = npc+4
stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
b,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
linux_syscall_trace2: linux_syscall_trace2:
call syscall_trace_leave call syscall_trace_leave
add %sp, PTREGS_OFF, %o0 add %sp, PTREGS_OFF, %o0
......
/* arch/sparc64/kernel/traps.c /* arch/sparc64/kernel/traps.c
* *
* Copyright (C) 1995,1997,2008,2009 David S. Miller (davem@davemloft.net) * Copyright (C) 1995,1997,2008,2009,2012 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com) * Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com)
*/ */
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/reboot.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <asm/smp.h> #include <asm/smp.h>
...@@ -1760,85 +1761,223 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs) ...@@ -1760,85 +1761,223 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs)
} }
struct sun4v_error_entry { struct sun4v_error_entry {
u64 err_handle; /* Unique error handle */
u64 err_stick; /*0x00*/u64 err_handle;
u32 err_type; /* %stick value at the time of the error */
/*0x08*/u64 err_stick;
/*0x10*/u8 reserved_1[3];
/* Error type */
/*0x13*/u8 err_type;
#define SUN4V_ERR_TYPE_UNDEFINED 0 #define SUN4V_ERR_TYPE_UNDEFINED 0
#define SUN4V_ERR_TYPE_UNCORRECTED_RES 1 #define SUN4V_ERR_TYPE_UNCORRECTED_RES 1
#define SUN4V_ERR_TYPE_PRECISE_NONRES 2 #define SUN4V_ERR_TYPE_PRECISE_NONRES 2
#define SUN4V_ERR_TYPE_DEFERRED_NONRES 3 #define SUN4V_ERR_TYPE_DEFERRED_NONRES 3
#define SUN4V_ERR_TYPE_WARNING_RES 4 #define SUN4V_ERR_TYPE_SHUTDOWN_RQST 4
#define SUN4V_ERR_TYPE_DUMP_CORE 5
#define SUN4V_ERR_TYPE_SP_STATE_CHANGE 6
#define SUN4V_ERR_TYPE_NUM 7
u32 err_attrs; /* Error attributes */
/*0x14*/u32 err_attrs;
#define SUN4V_ERR_ATTRS_PROCESSOR 0x00000001 #define SUN4V_ERR_ATTRS_PROCESSOR 0x00000001
#define SUN4V_ERR_ATTRS_MEMORY 0x00000002 #define SUN4V_ERR_ATTRS_MEMORY 0x00000002
#define SUN4V_ERR_ATTRS_PIO 0x00000004 #define SUN4V_ERR_ATTRS_PIO 0x00000004
#define SUN4V_ERR_ATTRS_INT_REGISTERS 0x00000008 #define SUN4V_ERR_ATTRS_INT_REGISTERS 0x00000008
#define SUN4V_ERR_ATTRS_FPU_REGISTERS 0x00000010 #define SUN4V_ERR_ATTRS_FPU_REGISTERS 0x00000010
#define SUN4V_ERR_ATTRS_USER_MODE 0x01000000 #define SUN4V_ERR_ATTRS_SHUTDOWN_RQST 0x00000020
#define SUN4V_ERR_ATTRS_PRIV_MODE 0x02000000 #define SUN4V_ERR_ATTRS_ASR 0x00000040
#define SUN4V_ERR_ATTRS_ASI 0x00000080
#define SUN4V_ERR_ATTRS_PRIV_REG 0x00000100
#define SUN4V_ERR_ATTRS_SPSTATE_MSK 0x00000600
#define SUN4V_ERR_ATTRS_SPSTATE_SHFT 9
#define SUN4V_ERR_ATTRS_MODE_MSK 0x03000000
#define SUN4V_ERR_ATTRS_MODE_SHFT 24
#define SUN4V_ERR_ATTRS_RES_QUEUE_FULL 0x80000000 #define SUN4V_ERR_ATTRS_RES_QUEUE_FULL 0x80000000
u64 err_raddr; #define SUN4V_ERR_SPSTATE_FAULTED 0
u32 err_size; #define SUN4V_ERR_SPSTATE_AVAILABLE 1
u16 err_cpu; #define SUN4V_ERR_SPSTATE_NOT_PRESENT 2
u16 err_pad;
#define SUN4V_ERR_MODE_USER 1
#define SUN4V_ERR_MODE_PRIV 2
/* Real address of the memory region or PIO transaction */
/*0x18*/u64 err_raddr;
/* Size of the operation triggering the error, in bytes */
/*0x20*/u32 err_size;
/* ID of the CPU */
/*0x24*/u16 err_cpu;
/* Grace periof for shutdown, in seconds */
/*0x26*/u16 err_secs;
/* Value of the %asi register */
/*0x28*/u8 err_asi;
/*0x29*/u8 reserved_2;
/* Value of the ASR register number */
/*0x2a*/u16 err_asr;
#define SUN4V_ERR_ASR_VALID 0x8000
/*0x2c*/u32 reserved_3;
/*0x30*/u64 reserved_4;
/*0x38*/u64 reserved_5;
}; };
static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0); static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0);
static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0); static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0);
static const char *sun4v_err_type_to_str(u32 type) static const char *sun4v_err_type_to_str(u8 type)
{ {
switch (type) { static const char *types[SUN4V_ERR_TYPE_NUM] = {
case SUN4V_ERR_TYPE_UNDEFINED: "undefined",
return "undefined"; "uncorrected resumable",
case SUN4V_ERR_TYPE_UNCORRECTED_RES: "precise nonresumable",
return "uncorrected resumable"; "deferred nonresumable",
case SUN4V_ERR_TYPE_PRECISE_NONRES: "shutdown request",
return "precise nonresumable"; "dump core",
case SUN4V_ERR_TYPE_DEFERRED_NONRES: "SP state change",
return "deferred nonresumable"; };
case SUN4V_ERR_TYPE_WARNING_RES:
return "warning resumable"; if (type < SUN4V_ERR_TYPE_NUM)
default: return types[type];
return "unknown";
return "unknown";
}
static void sun4v_emit_err_attr_strings(u32 attrs)
{
static const char *attr_names[] = {
"processor",
"memory",
"PIO",
"int-registers",
"fpu-registers",
"shutdown-request",
"ASR",
"ASI",
"priv-reg",
};
static const char *sp_states[] = {
"sp-faulted",
"sp-available",
"sp-not-present",
"sp-state-reserved",
};
static const char *modes[] = {
"mode-reserved0",
"user",
"priv",
"mode-reserved1",
};
u32 sp_state, mode;
int i;
for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
if (attrs & (1U << i)) {
const char *s = attr_names[i];
pr_cont("%s ", s);
}
} }
sp_state = ((attrs & SUN4V_ERR_ATTRS_SPSTATE_MSK) >>
SUN4V_ERR_ATTRS_SPSTATE_SHFT);
pr_cont("%s ", sp_states[sp_state]);
mode = ((attrs & SUN4V_ERR_ATTRS_MODE_MSK) >>
SUN4V_ERR_ATTRS_MODE_SHFT);
pr_cont("%s ", modes[mode]);
if (attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL)
pr_cont("res-queue-full ");
} }
static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt) /* When the report contains a real-address of "-1" it means that the
* hardware did not provide the address. So we compute the effective
* address of the load or store instruction at regs->tpc and report
* that. Usually when this happens it's a PIO and in such a case we
* are using physical addresses with bypass ASIs anyways, so what we
* report here is exactly what we want.
*/
static void sun4v_report_real_raddr(const char *pfx, struct pt_regs *regs)
{ {
unsigned int insn;
u64 addr;
if (!(regs->tstate & TSTATE_PRIV))
return;
insn = *(unsigned int *) regs->tpc;
addr = compute_effective_address(regs, insn, 0);
printk("%s: insn effective address [0x%016llx]\n",
pfx, addr);
}
static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent,
int cpu, const char *pfx, atomic_t *ocnt)
{
u64 *raw_ptr = (u64 *) ent;
u32 attrs;
int cnt; int cnt;
printk("%s: Reporting on cpu %d\n", pfx, cpu); printk("%s: Reporting on cpu %d\n", pfx, cpu);
printk("%s: err_handle[%llx] err_stick[%llx] err_type[%08x:%s]\n", printk("%s: TPC [0x%016lx] <%pS>\n",
pfx, pfx, regs->tpc, (void *) regs->tpc);
ent->err_handle, ent->err_stick,
ent->err_type, printk("%s: RAW [%016llx:%016llx:%016llx:%016llx\n",
sun4v_err_type_to_str(ent->err_type)); pfx, raw_ptr[0], raw_ptr[1], raw_ptr[2], raw_ptr[3]);
printk("%s: err_attrs[%08x:%s %s %s %s %s %s %s %s]\n", printk("%s: %016llx:%016llx:%016llx:%016llx]\n",
pfx, pfx, raw_ptr[4], raw_ptr[5], raw_ptr[6], raw_ptr[7]);
ent->err_attrs,
((ent->err_attrs & SUN4V_ERR_ATTRS_PROCESSOR) ? printk("%s: handle [0x%016llx] stick [0x%016llx]\n",
"processor" : ""), pfx, ent->err_handle, ent->err_stick);
((ent->err_attrs & SUN4V_ERR_ATTRS_MEMORY) ?
"memory" : ""), printk("%s: type [%s]\n", pfx, sun4v_err_type_to_str(ent->err_type));
((ent->err_attrs & SUN4V_ERR_ATTRS_PIO) ?
"pio" : ""), attrs = ent->err_attrs;
((ent->err_attrs & SUN4V_ERR_ATTRS_INT_REGISTERS) ? printk("%s: attrs [0x%08x] < ", pfx, attrs);
"integer-regs" : ""), sun4v_emit_err_attr_strings(attrs);
((ent->err_attrs & SUN4V_ERR_ATTRS_FPU_REGISTERS) ? pr_cont(">\n");
"fpu-regs" : ""),
((ent->err_attrs & SUN4V_ERR_ATTRS_USER_MODE) ? /* Various fields in the error report are only valid if
"user" : ""), * certain attribute bits are set.
((ent->err_attrs & SUN4V_ERR_ATTRS_PRIV_MODE) ? */
"privileged" : ""), if (attrs & (SUN4V_ERR_ATTRS_MEMORY |
((ent->err_attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) ? SUN4V_ERR_ATTRS_PIO |
"queue-full" : "")); SUN4V_ERR_ATTRS_ASI)) {
printk("%s: err_raddr[%016llx] err_size[%u] err_cpu[%u]\n", printk("%s: raddr [0x%016llx]\n", pfx, ent->err_raddr);
pfx,
ent->err_raddr, ent->err_size, ent->err_cpu); if (ent->err_raddr == ~(u64)0)
sun4v_report_real_raddr(pfx, regs);
}
if (attrs & (SUN4V_ERR_ATTRS_MEMORY | SUN4V_ERR_ATTRS_ASI))
printk("%s: size [0x%x]\n", pfx, ent->err_size);
if (attrs & (SUN4V_ERR_ATTRS_PROCESSOR |
SUN4V_ERR_ATTRS_INT_REGISTERS |
SUN4V_ERR_ATTRS_FPU_REGISTERS |
SUN4V_ERR_ATTRS_PRIV_REG))
printk("%s: cpu[%u]\n", pfx, ent->err_cpu);
if (attrs & SUN4V_ERR_ATTRS_ASI)
printk("%s: asi [0x%02x]\n", pfx, ent->err_asi);
if ((attrs & (SUN4V_ERR_ATTRS_INT_REGISTERS |
SUN4V_ERR_ATTRS_FPU_REGISTERS |
SUN4V_ERR_ATTRS_PRIV_REG)) &&
(ent->err_asr & SUN4V_ERR_ASR_VALID) != 0)
printk("%s: reg [0x%04x]\n",
pfx, ent->err_asr & ~SUN4V_ERR_ASR_VALID);
show_regs(regs); show_regs(regs);
...@@ -1874,13 +2013,15 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset) ...@@ -1874,13 +2013,15 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
put_cpu(); put_cpu();
if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) { if (local_copy.err_type == SUN4V_ERR_TYPE_SHUTDOWN_RQST) {
/* If err_type is 0x4, it's a powerdown request. Do /* We should really take the seconds field of
* not do the usual resumable error log because that * the error report and use it for the shutdown
* makes it look like some abnormal error. * invocation, but for now do the same thing we
* do for a DS shutdown request.
*/ */
printk(KERN_INFO "Power down request...\n"); pr_info("Shutdown request, %u seconds...\n",
kill_cad_pid(SIGINT, 1); local_copy.err_secs);
orderly_poweroff(true);
return; return;
} }
......
...@@ -151,8 +151,6 @@ show_signal_msg(struct pt_regs *regs, int sig, int code, ...@@ -151,8 +151,6 @@ show_signal_msg(struct pt_regs *regs, int sig, int code,
printk(KERN_CONT "\n"); printk(KERN_CONT "\n");
} }
extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int);
static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
unsigned int insn, int fault_code) unsigned int insn, int fault_code)
{ {
......
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