summaryrefslogtreecommitdiff
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig27
-rw-r--r--arch/powerpc/include/asm/asm-compat.h5
-rw-r--r--arch/powerpc/include/asm/atomic.h48
-rw-r--r--arch/powerpc/include/asm/bitops.h56
-rw-r--r--arch/powerpc/include/asm/cputable.h4
-rw-r--r--arch/powerpc/include/asm/futex.h6
-rw-r--r--arch/powerpc/include/asm/hardirq.h30
-rw-r--r--arch/powerpc/include/asm/local.h12
-rw-r--r--arch/powerpc/include/asm/mutex.h6
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h18
-rw-r--r--arch/powerpc/include/asm/ppc-pci.h5
-rw-r--r--arch/powerpc/include/asm/processor.h36
-rw-r--r--arch/powerpc/include/asm/ptrace.h77
-rw-r--r--arch/powerpc/include/asm/reg_booke.h96
-rw-r--r--arch/powerpc/include/asm/spinlock.h32
-rw-r--r--arch/powerpc/include/asm/synch.h12
-rw-r--r--arch/powerpc/include/asm/system.h21
-rw-r--r--arch/powerpc/kernel/irq.c118
-rw-r--r--arch/powerpc/kernel/kgdb.c2
-rw-r--r--arch/powerpc/kernel/kprobes.c4
-rw-r--r--arch/powerpc/kernel/process.c116
-rw-r--r--arch/powerpc/kernel/ptrace.c516
-rw-r--r--arch/powerpc/kernel/signal.c6
-rw-r--r--arch/powerpc/kernel/signal_32.c16
-rw-r--r--arch/powerpc/kernel/time.c2
-rw-r--r--arch/powerpc/kernel/traps.c101
-rw-r--r--arch/powerpc/lib/copypage_64.S28
-rw-r--r--arch/powerpc/lib/copyuser_64.S80
-rw-r--r--arch/powerpc/lib/feature-fixups.c2
-rw-r--r--arch/powerpc/mm/hash_native_64.c5
-rw-r--r--arch/powerpc/mm/tlb_hash64.c12
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads_cpld.c2
-rw-r--r--arch/powerpc/platforms/85xx/socrates_fpga_pic.c2
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.c2
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c4
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c2
-rw-r--r--arch/powerpc/platforms/iseries/irq.c2
-rw-r--r--arch/powerpc/platforms/powermac/pic.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c4
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c4
-rw-r--r--arch/powerpc/platforms/pseries/eeh_event.c2
-rw-r--r--arch/powerpc/platforms/pseries/xics.c44
-rw-r--r--arch/powerpc/sysdev/cpm1.c2
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c2
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c2
-rw-r--r--arch/powerpc/sysdev/i8259.c2
-rw-r--r--arch/powerpc/sysdev/ipic.c4
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c2
-rw-r--r--arch/powerpc/sysdev/mpic_pasemi_msi.c2
-rw-r--r--arch/powerpc/sysdev/mv64x60_dev.c3
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c2
-rw-r--r--arch/powerpc/sysdev/uic.c2
52 files changed, 1290 insertions, 302 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index bf15e7b4cd3d..654bba5cf6b4 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -240,6 +240,33 @@ config PPC_OF_PLATFORM_PCI
config ARCH_SUPPORTS_DEBUG_PAGEALLOC
def_bool y
+config PPC_ADV_DEBUG_REGS
+ bool
+ depends on 40x || BOOKE
+ default y
+
+config PPC_ADV_DEBUG_IACS
+ int
+ depends on PPC_ADV_DEBUG_REGS
+ default 4 if 44x
+ default 2
+
+config PPC_ADV_DEBUG_DACS
+ int
+ depends on PPC_ADV_DEBUG_REGS
+ default 2
+
+config PPC_ADV_DEBUG_DVCS
+ int
+ depends on PPC_ADV_DEBUG_REGS
+ default 2 if 44x
+ default 0
+
+config PPC_ADV_DEBUG_DAC_RANGE
+ bool
+ depends on PPC_ADV_DEBUG_REGS && 44x
+ default y
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h
index 8f0fe7971949..c1b475a941eb 100644
--- a/arch/powerpc/include/asm/asm-compat.h
+++ b/arch/powerpc/include/asm/asm-compat.h
@@ -2,6 +2,7 @@
#define _ASM_POWERPC_ASM_COMPAT_H
#include <asm/types.h>
+#include <asm/ppc-opcode.h>
#ifdef __ASSEMBLY__
# define stringify_in_c(...) __VA_ARGS__
@@ -24,7 +25,7 @@
#define PPC_LONG stringify_in_c(.llong)
#define PPC_LONG_ALIGN stringify_in_c(.balign 8)
#define PPC_TLNEI stringify_in_c(tdnei)
-#define PPC_LLARX stringify_in_c(ldarx)
+#define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh)
#define PPC_STLCX stringify_in_c(stdcx.)
#define PPC_CNTLZL stringify_in_c(cntlzd)
@@ -46,7 +47,7 @@
#define PPC_LONG stringify_in_c(.long)
#define PPC_LONG_ALIGN stringify_in_c(.balign 4)
#define PPC_TLNEI stringify_in_c(twnei)
-#define PPC_LLARX stringify_in_c(lwarx)
+#define PPC_LLARX(t, a, b, eh) PPC_LWARX(t, a, b, eh)
#define PPC_STLCX stringify_in_c(stwcx.)
#define PPC_CNTLZL stringify_in_c(cntlzw)
#define PPC_MTOCRF stringify_in_c(mtcrf)
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index 4012483b1899..b8f152ece025 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -49,13 +49,13 @@ static __inline__ int atomic_add_return(int a, atomic_t *v)
int t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%2 # atomic_add_return\n\
add %0,%1,%0\n"
PPC405_ERR77(0,%2)
" stwcx. %0,0,%2 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (a), "r" (&v->counter)
: "cc", "memory");
@@ -85,13 +85,13 @@ static __inline__ int atomic_sub_return(int a, atomic_t *v)
int t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%2 # atomic_sub_return\n\
subf %0,%1,%0\n"
PPC405_ERR77(0,%2)
" stwcx. %0,0,%2 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (a), "r" (&v->counter)
: "cc", "memory");
@@ -119,13 +119,13 @@ static __inline__ int atomic_inc_return(atomic_t *v)
int t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%1 # atomic_inc_return\n\
addic %0,%0,1\n"
PPC405_ERR77(0,%1)
" stwcx. %0,0,%1 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (&v->counter)
: "cc", "xer", "memory");
@@ -163,13 +163,13 @@ static __inline__ int atomic_dec_return(atomic_t *v)
int t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%1 # atomic_dec_return\n\
addic %0,%0,-1\n"
PPC405_ERR77(0,%1)
" stwcx. %0,0,%1\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (&v->counter)
: "cc", "xer", "memory");
@@ -194,7 +194,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
int t;
__asm__ __volatile__ (
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%1 # atomic_add_unless\n\
cmpw 0,%0,%3 \n\
beq- 2f \n\
@@ -202,7 +202,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
PPC405_ERR77(0,%2)
" stwcx. %0,0,%1 \n\
bne- 1b \n"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
" subf %0,%2,%0 \n\
2:"
: "=&r" (t)
@@ -227,7 +227,7 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
int t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\
cmpwi %0,1\n\
addi %0,%0,-1\n\
@@ -235,7 +235,7 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
PPC405_ERR77(0,%1)
" stwcx. %0,0,%1\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
"\n\
2:" : "=&b" (t)
: "r" (&v->counter)
@@ -286,12 +286,12 @@ static __inline__ long atomic64_add_return(long a, atomic64_t *v)
long t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%2 # atomic64_add_return\n\
add %0,%1,%0\n\
stdcx. %0,0,%2 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (a), "r" (&v->counter)
: "cc", "memory");
@@ -320,12 +320,12 @@ static __inline__ long atomic64_sub_return(long a, atomic64_t *v)
long t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%2 # atomic64_sub_return\n\
subf %0,%1,%0\n\
stdcx. %0,0,%2 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (a), "r" (&v->counter)
: "cc", "memory");
@@ -352,12 +352,12 @@ static __inline__ long atomic64_inc_return(atomic64_t *v)
long t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%1 # atomic64_inc_return\n\
addic %0,%0,1\n\
stdcx. %0,0,%1 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (&v->counter)
: "cc", "xer", "memory");
@@ -394,12 +394,12 @@ static __inline__ long atomic64_dec_return(atomic64_t *v)
long t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%1 # atomic64_dec_return\n\
addic %0,%0,-1\n\
stdcx. %0,0,%1\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (&v->counter)
: "cc", "xer", "memory");
@@ -419,13 +419,13 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
long t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%1 # atomic64_dec_if_positive\n\
addic. %0,%0,-1\n\
blt- 2f\n\
stdcx. %0,0,%1\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
"\n\
2:" : "=&r" (t)
: "r" (&v->counter)
@@ -451,14 +451,14 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
long t;
__asm__ __volatile__ (
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%1 # atomic_add_unless\n\
cmpd 0,%0,%3 \n\
beq- 2f \n\
add %0,%2,%0 \n"
" stdcx. %0,0,%1 \n\
bne- 1b \n"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
" subf %0,%2,%0 \n\
2:"
: "=&r" (t)
diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h
index 56f2f2ea5631..30964ae2d096 100644
--- a/arch/powerpc/include/asm/bitops.h
+++ b/arch/powerpc/include/asm/bitops.h
@@ -65,7 +65,7 @@ static __inline__ void fn(unsigned long mask, \
unsigned long *p = (unsigned long *)_p; \
__asm__ __volatile__ ( \
prefix \
-"1:" PPC_LLARX "%0,0,%3\n" \
+"1:" PPC_LLARX(%0,0,%3,0) "\n" \
stringify_in_c(op) "%0,%0,%2\n" \
PPC405_ERR77(0,%3) \
PPC_STLCX "%0,0,%3\n" \
@@ -78,7 +78,7 @@ static __inline__ void fn(unsigned long mask, \
DEFINE_BITOP(set_bits, or, "", "")
DEFINE_BITOP(clear_bits, andc, "", "")
-DEFINE_BITOP(clear_bits_unlock, andc, LWSYNC_ON_SMP, "")
+DEFINE_BITOP(clear_bits_unlock, andc, PPC_RELEASE_BARRIER, "")
DEFINE_BITOP(change_bits, xor, "", "")
static __inline__ void set_bit(int nr, volatile unsigned long *addr)
@@ -103,31 +103,35 @@ static __inline__ void change_bit(int nr, volatile unsigned long *addr)
/* Like DEFINE_BITOP(), with changes to the arguments to 'op' and the output
* operands. */
-#define DEFINE_TESTOP(fn, op, prefix, postfix) \
-static __inline__ unsigned long fn( \
- unsigned long mask, \
- volatile unsigned long *_p) \
-{ \
- unsigned long old, t; \
- unsigned long *p = (unsigned long *)_p; \
- __asm__ __volatile__ ( \
- prefix \
-"1:" PPC_LLARX "%0,0,%3\n" \
- stringify_in_c(op) "%1,%0,%2\n" \
- PPC405_ERR77(0,%3) \
- PPC_STLCX "%1,0,%3\n" \
- "bne- 1b\n" \
- postfix \
- : "=&r" (old), "=&r" (t) \
- : "r" (mask), "r" (p) \
- : "cc", "memory"); \
- return (old & mask); \
+#define DEFINE_TESTOP(fn, op, prefix, postfix, eh) \
+static __inline__ unsigned long fn( \
+ unsigned long mask, \
+ volatile unsigned long *_p) \
+{ \
+ unsigned long old, t; \
+ unsigned long *p = (unsigned long *)_p; \
+ __asm__ __volatile__ ( \
+ prefix \
+"1:" PPC_LLARX(%0,0,%3,eh) "\n" \
+ stringify_in_c(op) "%1,%0,%2\n" \
+ PPC405_ERR77(0,%3) \
+ PPC_STLCX "%1,0,%3\n" \
+ "bne- 1b\n" \
+ postfix \
+ : "=&r" (old), "=&r" (t) \
+ : "r" (mask), "r" (p) \
+ : "cc", "memory"); \
+ return (old & mask); \
}
-DEFINE_TESTOP(test_and_set_bits, or, LWSYNC_ON_SMP, ISYNC_ON_SMP)
-DEFINE_TESTOP(test_and_set_bits_lock, or, "", ISYNC_ON_SMP)
-DEFINE_TESTOP(test_and_clear_bits, andc, LWSYNC_ON_SMP, ISYNC_ON_SMP)
-DEFINE_TESTOP(test_and_change_bits, xor, LWSYNC_ON_SMP, ISYNC_ON_SMP)
+DEFINE_TESTOP(test_and_set_bits, or, PPC_RELEASE_BARRIER,
+ PPC_ACQUIRE_BARRIER, 0)
+DEFINE_TESTOP(test_and_set_bits_lock, or, "",
+ PPC_ACQUIRE_BARRIER, 1)
+DEFINE_TESTOP(test_and_clear_bits, andc, PPC_RELEASE_BARRIER,
+ PPC_ACQUIRE_BARRIER, 0)
+DEFINE_TESTOP(test_and_change_bits, xor, PPC_RELEASE_BARRIER,
+ PPC_ACQUIRE_BARRIER, 0)
static __inline__ int test_and_set_bit(unsigned long nr,
volatile unsigned long *addr)
@@ -158,7 +162,7 @@ static __inline__ int test_and_change_bit(unsigned long nr,
static __inline__ void __clear_bit_unlock(int nr, volatile unsigned long *addr)
{
- __asm__ __volatile__(LWSYNC_ON_SMP "" ::: "memory");
+ __asm__ __volatile__(PPC_RELEASE_BARRIER "" ::: "memory");
__clear_bit(nr, addr);
}
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 80f315e8a421..abb833b0e58f 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -381,9 +381,9 @@ extern const char *powerpc_base_platform;
#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
/* 64-bit CPUs */
-#define CPU_FTRS_POWER3 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
+#define CPU_FTRS_POWER3 (CPU_FTR_USE_TB | \
CPU_FTR_IABR | CPU_FTR_PPC_LE)
-#define CPU_FTRS_RS64 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
+#define CPU_FTRS_RS64 (CPU_FTR_USE_TB | \
CPU_FTR_IABR | \
CPU_FTR_MMCRA | CPU_FTR_CTRL)
#define CPU_FTRS_POWER4 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 9696cc36d2dc..7c589ef81fb0 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -11,7 +11,7 @@
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
__asm__ __volatile ( \
- LWSYNC_ON_SMP \
+ PPC_RELEASE_BARRIER \
"1: lwarx %0,0,%2\n" \
insn \
PPC405_ERR77(0, %2) \
@@ -90,14 +90,14 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
return -EFAULT;
__asm__ __volatile__ (
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
cmpw 0,%0,%3\n\
bne- 3f\n"
PPC405_ERR77(0,%2)
"2: stwcx. %4,0,%2\n\
bne- 1b\n"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
"3: .section .fixup,\"ax\"\n\
4: li %0,%5\n\
b 3b\n\
diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h
index fb3c05a0cbbf..3147a2970125 100644
--- a/arch/powerpc/include/asm/hardirq.h
+++ b/arch/powerpc/include/asm/hardirq.h
@@ -1 +1,29 @@
-#include <asm-generic/hardirq.h>
+#ifndef _ASM_POWERPC_HARDIRQ_H
+#define _ASM_POWERPC_HARDIRQ_H
+
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int timer_irqs;
+ unsigned int pmu_irqs;
+ unsigned int mce_exceptions;
+ unsigned int spurious_irqs;
+} ____cacheline_aligned irq_cpustat_t;
+
+DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
+
+#define __ARCH_IRQ_STAT
+
+#define local_softirq_pending() __get_cpu_var(irq_stat).__softirq_pending
+
+static inline void ack_bad_irq(unsigned int irq)
+{
+ printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
+}
+
+extern u64 arch_irq_stat_cpu(unsigned int cpu);
+#define arch_irq_stat_cpu arch_irq_stat_cpu
+
+#endif /* _ASM_POWERPC_HARDIRQ_H */
diff --git a/arch/powerpc/include/asm/local.h b/arch/powerpc/include/asm/local.h
index 84b457a3c1bc..ce58c80e1bcf 100644
--- a/arch/powerpc/include/asm/local.h
+++ b/arch/powerpc/include/asm/local.h
@@ -24,7 +24,7 @@ static __inline__ long local_add_return(long a, local_t *l)
long t;
__asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%2 # local_add_return\n\
+"1:" PPC_LLARX(%0,0,%2,0) " # local_add_return\n\
add %0,%1,%0\n"
PPC405_ERR77(0,%2)
PPC_STLCX "%0,0,%2 \n\
@@ -43,7 +43,7 @@ static __inline__ long local_sub_return(long a, local_t *l)
long t;
__asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%2 # local_sub_return\n\
+"1:" PPC_LLARX(%0,0,%2,0) " # local_sub_return\n\
subf %0,%1,%0\n"
PPC405_ERR77(0,%2)
PPC_STLCX "%0,0,%2 \n\
@@ -60,7 +60,7 @@ static __inline__ long local_inc_return(local_t *l)
long t;
__asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%1 # local_inc_return\n\
+"1:" PPC_LLARX(%0,0,%1,0) " # local_inc_return\n\
addic %0,%0,1\n"
PPC405_ERR77(0,%1)
PPC_STLCX "%0,0,%1 \n\
@@ -87,7 +87,7 @@ static __inline__ long local_dec_return(local_t *l)
long t;
__asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%1 # local_dec_return\n\
+"1:" PPC_LLARX(%0,0,%1,0) " # local_dec_return\n\
addic %0,%0,-1\n"
PPC405_ERR77(0,%1)
PPC_STLCX "%0,0,%1\n\
@@ -117,7 +117,7 @@ static __inline__ int local_add_unless(local_t *l, long a, long u)
long t;
__asm__ __volatile__ (
-"1:" PPC_LLARX "%0,0,%1 # local_add_unless\n\
+"1:" PPC_LLARX(%0,0,%1,0) " # local_add_unless\n\
cmpw 0,%0,%3 \n\
beq- 2f \n\
add %0,%2,%0 \n"
@@ -147,7 +147,7 @@ static __inline__ long local_dec_if_positive(local_t *l)
long t;
__asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%1 # local_dec_if_positive\n\
+"1:" PPC_LLARX(%0,0,%1,0) " # local_dec_if_positive\n\
cmpwi %0,1\n\
addi %0,%0,-1\n\
blt- 2f\n"
diff --git a/arch/powerpc/include/asm/mutex.h b/arch/powerpc/include/asm/mutex.h
index dabc01c727b8..5399f7e18102 100644
--- a/arch/powerpc/include/asm/mutex.h
+++ b/arch/powerpc/include/asm/mutex.h
@@ -15,7 +15,7 @@ static inline int __mutex_cmpxchg_lock(atomic_t *v, int old, int new)
PPC405_ERR77(0,%1)
" stwcx. %3,0,%1\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
"\n\
2:"
: "=&r" (t)
@@ -35,7 +35,7 @@ static inline int __mutex_dec_return_lock(atomic_t *v)
PPC405_ERR77(0,%1)
" stwcx. %0,0,%1\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (t)
: "r" (&v->counter)
: "cc", "memory");
@@ -48,7 +48,7 @@ static inline int __mutex_inc_return_unlock(atomic_t *v)
int t;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%1 # mutex unlock\n\
addic %0,%0,1\n"
PPC405_ERR77(0,%1)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index ef9aa84cac5a..aea714797590 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -22,8 +22,10 @@
#define PPC_INST_DCBZL 0x7c2007ec
#define PPC_INST_ISEL 0x7c00001e
#define PPC_INST_ISEL_MASK 0xfc00003e
+#define PPC_INST_LDARX 0x7c0000a8
#define PPC_INST_LSWI 0x7c0004aa
#define PPC_INST_LSWX 0x7c00042a
+#define PPC_INST_LWARX 0x7c000029
#define PPC_INST_LWSYNC 0x7c2004ac
#define PPC_INST_LXVD2X 0x7c000698
#define PPC_INST_MCRXR 0x7c000400
@@ -55,15 +57,31 @@
#define __PPC_RA(a) (((a) & 0x1f) << 16)
#define __PPC_RB(b) (((b) & 0x1f) << 11)
#define __PPC_RS(s) (((s) & 0x1f) << 21)
+#define __PPC_RT(s) __PPC_RS(s)
#define __PPC_XS(s) ((((s) & 0x1f) << 21) | (((s) & 0x20) >> 5))
#define __PPC_T_TLB(t) (((t) & 0x3) << 21)
#define __PPC_WC(w) (((w) & 0x3) << 21)
+/*
+ * Only use the larx hint bit on 64bit CPUs. Once we verify it doesn't have
+ * any side effects on all 32bit processors, we can do this all the time.
+ */
+#ifdef CONFIG_PPC64
+#define __PPC_EH(eh) (((eh) & 0x1) << 0)
+#else
+#define __PPC_EH(eh) 0
+#endif
/* Deal with instructions that older assemblers aren't aware of */
#define PPC_DCBAL(a, b) stringify_in_c(.long PPC_INST_DCBAL | \
__PPC_RA(a) | __PPC_RB(b))
#define PPC_DCBZL(a, b) stringify_in_c(.long PPC_INST_DCBZL | \
__PPC_RA(a) | __PPC_RB(b))
+#define PPC_LDARX(t, a, b, eh) stringify_in_c(.long PPC_INST_LDARX | \
+ __PPC_RT(t) | __PPC_RA(a) | \
+ __PPC_RB(b) | __PPC_EH(eh))
+#define PPC_LWARX(t, a, b, eh) stringify_in_c(.long PPC_INST_LWARX | \
+ __PPC_RT(t) | __PPC_RA(a) | \
+ __PPC_RB(b) | __PPC_EH(eh))
#define PPC_MSGSND(b) stringify_in_c(.long PPC_INST_MSGSND | \
__PPC_RB(b))
#define PPC_RFCI stringify_in_c(.long PPC_INST_RFCI)
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index 2828f9d0f66d..42fdff0e4b32 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -137,6 +137,11 @@ struct device_node * find_device_pe(struct device_node *dn);
void eeh_sysfs_add_device(struct pci_dev *pdev);
void eeh_sysfs_remove_device(struct pci_dev *pdev);
+static inline const char *eeh_pci_name(struct pci_dev *pdev)
+{
+ return pdev ? pci_name(pdev) : "<null>";
+}
+
#endif /* CONFIG_EEH */
#else /* CONFIG_PCI */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 9eed29eee604..221ba6240464 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -161,9 +161,41 @@ struct thread_struct {
#ifdef CONFIG_PPC32
void *pgdir; /* root of page-table tree */
#endif
-#if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
- unsigned long dbcr0; /* debug control register values */
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ /*
+ * The following help to manage the use of Debug Control Registers
+ * om the BookE platforms.
+ */
+ unsigned long dbcr0;
unsigned long dbcr1;
+#ifdef CONFIG_BOOKE
+ unsigned long dbcr2;
+#endif
+ /*
+ * The stored value of the DBSR register will be the value at the
+ * last debug interrupt. This register can only be read from the
+ * user (will never be written to) and has value while helping to
+ * describe the reason for the last debug trap. Torez
+ */
+ unsigned long dbsr;
+ /*
+ * The following will contain addresses used by debug applications
+ * to help trace and trap on particular address locations.
+ * The bits in the Debug Control Registers above help define which
+ * of the following registers will contain valid data and/or addresses.
+ */
+ unsigned long iac1;
+ unsigned long iac2;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ unsigned long iac3;
+ unsigned long iac4;
+#endif
+ unsigned long dac1;
+ unsigned long dac2;
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+ unsigned long dvc1;
+ unsigned long dvc2;
+#endif
#endif
/* FP and VSX 0-31 register set */
double fpr[32][TS_FPRWIDTH];
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index cbd759e3cd78..b45108126562 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -24,6 +24,12 @@
* 2 of the License, or (at your option) any later version.
*/
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
#ifndef __ASSEMBLY__
struct pt_regs {
@@ -294,4 +300,75 @@ extern void user_disable_single_step(struct task_struct *);
#define PTRACE_SINGLEBLOCK 0x100 /* resume execution until next branch */
+#define PPC_PTRACE_GETHWDBGINFO 0x89
+#define PPC_PTRACE_SETHWDEBUG 0x88
+#define PPC_PTRACE_DELHWDEBUG 0x87
+
+#ifndef __ASSEMBLY__
+
+struct ppc_debug_info {
+ uint32_t version; /* Only version 1 exists to date */
+ uint32_t num_instruction_bps;
+ uint32_t num_data_bps;
+ uint32_t num_condition_regs;
+ uint32_t data_bp_alignment;
+ uint32_t sizeof_condition; /* size of the DVC register */
+ uint64_t features;
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * features will have bits indication whether there is support for:
+ */
+#define PPC_DEBUG_FEATURE_INSN_BP_RANGE 0x0000000000000001
+#define PPC_DEBUG_FEATURE_INSN_BP_MASK 0x0000000000000002
+#define PPC_DEBUG_FEATURE_DATA_BP_RANGE 0x0000000000000004
+#define PPC_DEBUG_FEATURE_DATA_BP_MASK 0x0000000000000008
+
+#ifndef __ASSEMBLY__
+
+struct ppc_hw_breakpoint {
+ uint32_t version; /* currently, version must be 1 */
+ uint32_t trigger_type; /* only some combinations allowed */
+ uint32_t addr_mode; /* address match mode */
+ uint32_t condition_mode; /* break/watchpoint condition flags */
+ uint64_t addr; /* break/watchpoint address */
+ uint64_t addr2; /* range end or mask */
+ uint64_t condition_value; /* contents of the DVC register */
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Trigger Type
+ */
+#define PPC_BREAKPOINT_TRIGGER_EXECUTE 0x00000001
+#define PPC_BREAKPOINT_TRIGGER_READ 0x00000002
+#define PPC_BREAKPOINT_TRIGGER_WRITE 0x00000004
+#define PPC_BREAKPOINT_TRIGGER_RW \
+ (PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE)
+
+/*
+ * Address Mode
+ */
+#define PPC_BREAKPOINT_MODE_EXACT 0x00000000
+#define PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE 0x00000001
+#define PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE 0x00000002
+#define PPC_BREAKPOINT_MODE_MASK 0x00000003
+
+/*
+ * Condition Mode
+ */
+#define PPC_BREAKPOINT_CONDITION_MODE 0x00000003
+#define PPC_BREAKPOINT_CONDITION_NONE 0x00000000
+#define PPC_BREAKPOINT_CONDITION_AND 0x00000001
+#define PPC_BREAKPOINT_CONDITION_EXACT PPC_BREAKPOINT_CONDITION_AND
+#define PPC_BREAKPOINT_CONDITION_OR 0x00000002
+#define PPC_BREAKPOINT_CONDITION_AND_OR 0x00000003
+#define PPC_BREAKPOINT_CONDITION_BE_ALL 0x00ff0000
+#define PPC_BREAKPOINT_CONDITION_BE_SHIFT 16
+#define PPC_BREAKPOINT_CONDITION_BE(n) \
+ (1<<((n)+PPC_BREAKPOINT_CONDITION_BE_SHIFT))
+
#endif /* _ASM_POWERPC_PTRACE_H */
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 3bf783505528..8808d307fe7e 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -248,6 +248,8 @@
#define DBSR_RET 0x00008000 /* Return Debug Event */
#define DBSR_CIRPT 0x00000040 /* Critical Interrupt Taken Event */
#define DBSR_CRET 0x00000020 /* Critical Return Debug Event */
+#define DBSR_IAC12ATS 0x00000002 /* Instr Address Compare 1/2 Toggle */
+#define DBSR_IAC34ATS 0x00000001 /* Instr Address Compare 3/4 Toggle */
#endif
#ifdef CONFIG_40x
#define DBSR_IC 0x80000000 /* Instruction Completion */
@@ -313,6 +315,38 @@
#define DBCR0_IA12T 0x00008000 /* Instr Addr 1-2 range Toggle */
#define DBCR0_IA34T 0x00004000 /* Instr Addr 3-4 range Toggle */
#define DBCR0_FT 0x00000001 /* Freeze Timers on debug event */
+
+#define dbcr_iac_range(task) ((task)->thread.dbcr0)
+#define DBCR_IAC12I DBCR0_IA12 /* Range Inclusive */
+#define DBCR_IAC12X (DBCR0_IA12 | DBCR0_IA12X) /* Range Exclusive */
+#define DBCR_IAC12MODE (DBCR0_IA12 | DBCR0_IA12X) /* IAC 1-2 Mode Bits */
+#define DBCR_IAC34I DBCR0_IA34 /* Range Inclusive */
+#define DBCR_IAC34X (DBCR0_IA34 | DBCR0_IA34X) /* Range Exclusive */
+#define DBCR_IAC34MODE (DBCR0_IA34 | DBCR0_IA34X) /* IAC 3-4 Mode Bits */
+
+/* Bit definitions related to the DBCR1. */
+#define DBCR1_DAC1R 0x80000000 /* DAC1 Read Debug Event */
+#define DBCR1_DAC2R 0x40000000 /* DAC2 Read Debug Event */
+#define DBCR1_DAC1W 0x20000000 /* DAC1 Write Debug Event */
+#define DBCR1_DAC2W 0x10000000 /* DAC2 Write Debug Event */
+
+#define dbcr_dac(task) ((task)->thread.dbcr1)
+#define DBCR_DAC1R DBCR1_DAC1R
+#define DBCR_DAC1W DBCR1_DAC1W
+#define DBCR_DAC2R DBCR1_DAC2R
+#define DBCR_DAC2W DBCR1_DAC2W
+
+/*
+ * Are there any active Debug Events represented in the
+ * Debug Control Registers?
+ */
+#define DBCR0_ACTIVE_EVENTS (DBCR0_ICMP | DBCR0_IAC1 | DBCR0_IAC2 | \
+ DBCR0_IAC3 | DBCR0_IAC4)
+#define DBCR1_ACTIVE_EVENTS (DBCR1_DAC1R | DBCR1_DAC2R | \
+ DBCR1_DAC1W | DBCR1_DAC2W)
+#define DBCR_ACTIVE_EVENTS(dbcr0, dbcr1) (((dbcr0) & DBCR0_ACTIVE_EVENTS) || \
+ ((dbcr1) & DBCR1_ACTIVE_EVENTS))
+
#elif defined(CONFIG_BOOKE)
#define DBCR0_EDM 0x80000000 /* External Debug Mode */
#define DBCR0_IDM 0x40000000 /* Internal Debug Mode */
@@ -342,19 +376,79 @@
#define DBCR0_CRET 0x00000020 /* Critical Return Debug Event */
#define DBCR0_FT 0x00000001 /* Freeze Timers on debug event */
+#define dbcr_dac(task) ((task)->thread.dbcr0)
+#define DBCR_DAC1R DBCR0_DAC1R
+#define DBCR_DAC1W DBCR0_DAC1W
+#define DBCR_DAC2R DBCR0_DAC2R
+#define DBCR_DAC2W DBCR0_DAC2W
+
/* Bit definitions related to the DBCR1. */
+#define DBCR1_IAC1US 0xC0000000 /* Instr Addr Cmp 1 Sup/User */
+#define DBCR1_IAC1ER 0x30000000 /* Instr Addr Cmp 1 Eff/Real */
+#define DBCR1_IAC1ER_01 0x10000000 /* reserved */
+#define DBCR1_IAC1ER_10 0x20000000 /* Instr Addr Cmp 1 Eff/Real MSR[IS]=0 */
+#define DBCR1_IAC1ER_11 0x30000000 /* Instr Addr Cmp 1 Eff/Real MSR[IS]=1 */
+#define DBCR1_IAC2US 0x0C000000 /* Instr Addr Cmp 2 Sup/User */
+#define DBCR1_IAC2ER 0x03000000 /* Instr Addr Cmp 2 Eff/Real */
+#define DBCR1_IAC2ER_01 0x01000000 /* reserved */
+#define DBCR1_IAC2ER_10 0x02000000 /* Instr Addr Cmp 2 Eff/Real MSR[IS]=0 */
+#define DBCR1_IAC2ER_11 0x03000000 /* Instr Addr Cmp 2 Eff/Real MSR[IS]=1 */
#define DBCR1_IAC12M 0x00800000 /* Instr Addr 1-2 range enable */
#define DBCR1_IAC12MX 0x00C00000 /* Instr Addr 1-2 range eXclusive */
#define DBCR1_IAC12AT 0x00010000 /* Instr Addr 1-2 range Toggle */
+#define DBCR1_IAC3US 0x0000C000 /* Instr Addr Cmp 3 Sup/User */
+#define DBCR1_IAC3ER 0x00003000 /* Instr Addr Cmp 3 Eff/Real */
+#define DBCR1_IAC3ER_01 0x00001000 /* reserved */
+#define DBCR1_IAC3ER_10 0x00002000 /* Instr Addr Cmp 3 Eff/Real MSR[IS]=0 */
+#define DBCR1_IAC3ER_11 0x00003000 /* Instr Addr Cmp 3 Eff/Real MSR[IS]=1 */
+#define DBCR1_IAC4US 0x00000C00 /* Instr Addr Cmp 4 Sup/User */
+#define DBCR1_IAC4ER 0x00000300 /* Instr Addr Cmp 4 Eff/Real */
+#define DBCR1_IAC4ER_01 0x00000100 /* Instr Addr Cmp 4 Eff/Real MSR[IS]=0 */
+#define DBCR1_IAC4ER_10 0x00000200 /* Instr Addr Cmp 4 Eff/Real MSR[IS]=0 */
+#define DBCR1_IAC4ER_11 0x00000300 /* Instr Addr Cmp 4 Eff/Real MSR[IS]=1 */
#define DBCR1_IAC34M 0x00000080 /* Instr Addr 3-4 range enable */
#define DBCR1_IAC34MX 0x000000C0 /* Instr Addr 3-4 range eXclusive */
#define DBCR1_IAC34AT 0x00000001 /* Instr Addr 3-4 range Toggle */
+#define dbcr_iac_range(task) ((task)->thread.dbcr1)
+#define DBCR_IAC12I DBCR1_IAC12M /* Range Inclusive */
+#define DBCR_IAC12X DBCR1_IAC12MX /* Range Exclusive */
+#define DBCR_IAC12MODE DBCR1_IAC12MX /* IAC 1-2 Mode Bits */
+#define DBCR_IAC34I DBCR1_IAC34M /* Range Inclusive */
+#define DBCR_IAC34X DBCR1_IAC34MX /* Range Exclusive */
+#define DBCR_IAC34MODE DBCR1_IAC34MX /* IAC 3-4 Mode Bits */
+
/* Bit definitions related to the DBCR2. */
+#define DBCR2_DAC1US 0xC0000000 /* Data Addr Cmp 1 Sup/User */
+#define DBCR2_DAC1ER 0x30000000 /* Data Addr Cmp 1 Eff/Real */
+#define DBCR2_DAC2US 0x00000000 /* Data Addr Cmp 2 Sup/User */
+#define DBCR2_DAC2ER 0x00000000 /* Data Addr Cmp 2 Eff/Real */
#define DBCR2_DAC12M 0x00800000 /* DAC 1-2 range enable */
+#define DBCR2_DAC12MM 0x00400000 /* DAC 1-2 Mask mode*/
#define DBCR2_DAC12MX 0x00C00000 /* DAC 1-2 range eXclusive */
+#define DBCR2_DAC12MODE 0x00C00000 /* DAC 1-2 Mode Bits */
#define DBCR2_DAC12A 0x00200000 /* DAC 1-2 Asynchronous */
-#endif
+#define DBCR2_DVC1M 0x000C0000 /* Data Value Comp 1 Mode */
+#define DBCR2_DVC1M_SHIFT 18 /* # of bits to shift DBCR2_DVC1M */
+#define DBCR2_DVC2M 0x00030000 /* Data Value Comp 2 Mode */
+#define DBCR2_DVC2M_SHIFT 16 /* # of bits to shift DBCR2_DVC2M */
+#define DBCR2_DVC1BE 0x00000F00 /* Data Value Comp 1 Byte */
+#define DBCR2_DVC1BE_SHIFT 8 /* # of bits to shift DBCR2_DVC1BE */
+#define DBCR2_DVC2BE 0x0000000F /* Data Value Comp 2 Byte */
+#define DBCR2_DVC2BE_SHIFT 0 /* # of bits to shift DBCR2_DVC2BE */
+
+/*
+ * Are there any active Debug Events represented in the
+ * Debug Control Registers?
+ */
+#define DBCR0_ACTIVE_EVENTS (DBCR0_ICMP | DBCR0_IAC1 | DBCR0_IAC2 | \
+ DBCR0_IAC3 | DBCR0_IAC4 | DBCR0_DAC1R | \
+ DBCR0_DAC1W | DBCR0_DAC2R | DBCR0_DAC2W)
+#define DBCR1_ACTIVE_EVENTS 0
+
+#define DBCR_ACTIVE_EVENTS(dbcr0, dbcr1) (((dbcr0) & DBCR0_ACTIVE_EVENTS) || \
+ ((dbcr1) & DBCR1_ACTIVE_EVENTS))
+#endif /* #elif defined(CONFIG_BOOKE) */
/* Bit definitions related to the TCR. */
#define TCR_WP(x) (((x)&0x3)<<30) /* WDT Period */
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index 764094cff681..f9611bd69ed2 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -27,6 +27,7 @@
#endif
#include <asm/asm-compat.h>
#include <asm/synch.h>
+#include <asm/ppc-opcode.h>
#define arch_spin_is_locked(x) ((x)->slock != 0)
@@ -60,13 +61,14 @@ static inline unsigned long __arch_spin_trylock(arch_spinlock_t *lock)
token = LOCK_TOKEN;
__asm__ __volatile__(
-"1: lwarx %0,0,%2\n\
+"1: " PPC_LWARX(%0,0,%2,1) "\n\
cmpwi 0,%0,0\n\
bne- 2f\n\
stwcx. %1,0,%2\n\
- bne- 1b\n\
- isync\n\
-2:" : "=&r" (tmp)
+ bne- 1b\n"
+ PPC_ACQUIRE_BARRIER
+"2:"
+ : "=&r" (tmp)
: "r" (token), "r" (&lock->slock)
: "cr0", "memory");
@@ -144,7 +146,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
SYNC_IO;
__asm__ __volatile__("# arch_spin_unlock\n\t"
- LWSYNC_ON_SMP: : :"memory");
+ PPC_RELEASE_BARRIER: : :"memory");
lock->slock = 0;
}
@@ -186,15 +188,15 @@ static inline long __arch_read_trylock(arch_rwlock_t *rw)
long tmp;
__asm__ __volatile__(
-"1: lwarx %0,0,%1\n"
+"1: " PPC_LWARX(%0,0,%1,1) "\n"
__DO_SIGN_EXTEND
" addic. %0,%0,1\n\
ble- 2f\n"
PPC405_ERR77(0,%1)
" stwcx. %0,0,%1\n\
- bne- 1b\n\
- isync\n\
-2:" : "=&r" (tmp)
+ bne- 1b\n"
+ PPC_ACQUIRE_BARRIER
+"2:" : "=&r" (tmp)
: "r" (&rw->lock)
: "cr0", "xer", "memory");
@@ -211,14 +213,14 @@ static inline long __arch_write_trylock(arch_rwlock_t *rw)
token = WRLOCK_TOKEN;
__asm__ __volatile__(
-"1: lwarx %0,0,%2\n\
+"1: " PPC_LWARX(%0,0,%2,1) "\n\
cmpwi 0,%0,0\n\
bne- 2f\n"
PPC405_ERR77(0,%1)
" stwcx. %1,0,%2\n\
- bne- 1b\n\
- isync\n\
-2:" : "=&r" (tmp)
+ bne- 1b\n"
+ PPC_ACQUIRE_BARRIER
+"2:" : "=&r" (tmp)
: "r" (token), "r" (&rw->lock)
: "cr0", "memory");
@@ -269,7 +271,7 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
__asm__ __volatile__(
"# read_unlock\n\t"
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%1\n\
addic %0,%0,-1\n"
PPC405_ERR77(0,%1)
@@ -283,7 +285,7 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
static inline void arch_write_unlock(arch_rwlock_t *rw)
{
__asm__ __volatile__("# write_unlock\n\t"
- LWSYNC_ON_SMP: : :"memory");
+ PPC_RELEASE_BARRIER: : :"memory");
rw->lock = 0;
}
diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h
index 28f6ddbff4cf..d7cab44643c5 100644
--- a/arch/powerpc/include/asm/synch.h
+++ b/arch/powerpc/include/asm/synch.h
@@ -37,11 +37,15 @@ static inline void isync(void)
#endif
#ifdef CONFIG_SMP
-#define ISYNC_ON_SMP "\n\tisync\n"
-#define LWSYNC_ON_SMP stringify_in_c(LWSYNC) "\n"
+#define __PPC_ACQUIRE_BARRIER \
+ START_LWSYNC_SECTION(97); \
+ isync; \
+ MAKE_LWSYNC_SECTION_ENTRY(97, __lwsync_fixup);
+#define PPC_ACQUIRE_BARRIER "\n" stringify_in_c(__PPC_ACQUIRE_BARRIER)
+#define PPC_RELEASE_BARRIER stringify_in_c(LWSYNC) "\n"
#else
-#define ISYNC_ON_SMP
-#define LWSYNC_ON_SMP
+#define PPC_ACQUIRE_BARRIER
+#define PPC_RELEASE_BARRIER
#endif
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index bb8e006a47c6..a6297c67c3d6 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -112,8 +112,13 @@ static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
#endif
extern int set_dabr(unsigned long dabr);
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+extern void do_send_trap(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code, int signal_code, int brkpt);
+#else
extern void do_dabr(struct pt_regs *regs, unsigned long address,
unsigned long error_code);
+#endif
extern void print_backtrace(unsigned long *);
extern void show_regs(struct pt_regs * regs);
extern void flush_instruction_cache(void);
@@ -232,12 +237,12 @@ __xchg_u32(volatile void *p, unsigned long val)
unsigned long prev;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%2 \n"
PPC405_ERR77(0,%2)
" stwcx. %3,0,%2 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
: "r" (p), "r" (val)
: "cc", "memory");
@@ -275,12 +280,12 @@ __xchg_u64(volatile void *p, unsigned long val)
unsigned long prev;
__asm__ __volatile__(
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%2 \n"
PPC405_ERR77(0,%2)
" stdcx. %3,0,%2 \n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
: "r" (p), "r" (val)
: "cc", "memory");
@@ -366,14 +371,14 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
unsigned int prev;
__asm__ __volatile__ (
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: lwarx %0,0,%2 # __cmpxchg_u32\n\
cmpw 0,%0,%3\n\
bne- 2f\n"
PPC405_ERR77(0,%2)
" stwcx. %4,0,%2\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
"\n\
2:"
: "=&r" (prev), "+m" (*p)
@@ -412,13 +417,13 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
unsigned long prev;
__asm__ __volatile__ (
- LWSYNC_ON_SMP
+ PPC_RELEASE_BARRIER
"1: ldarx %0,0,%2 # __cmpxchg_u64\n\
cmpd 0,%0,%3\n\
bne- 2f\n\
stdcx. %4,0,%2\n\
bne- 1b"
- ISYNC_ON_SMP
+ PPC_ACQUIRE_BARRIER
"\n\
2:"
: "=&r" (prev), "+m" (*p)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 9040330b0530..9ae77e52f9d3 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -73,8 +73,10 @@
#define CREATE_TRACE_POINTS
#include <asm/trace.h>
+DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
+EXPORT_PER_CPU_SYMBOL(irq_stat);
+
int __irq_offset_value;
-static int ppc_spurious_interrupts;
#ifdef CONFIG_PPC32
EXPORT_SYMBOL(__irq_offset_value);
@@ -180,30 +182,64 @@ notrace void raw_local_irq_restore(unsigned long en)
EXPORT_SYMBOL(raw_local_irq_restore);
#endif /* CONFIG_PPC64 */
+static int show_other_interrupts(struct seq_file *p, int prec)
+{
+ int j;
+
+#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
+ if (tau_initialized) {
+ seq_printf(p, "%*s: ", prec, "TAU");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", tau_interrupts(j));
+ seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n");
+ }
+#endif /* CONFIG_PPC32 && CONFIG_TAU_INT */
+
+ seq_printf(p, "%*s: ", prec, "LOC");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs);
+ seq_printf(p, " Local timer interrupts\n");
+
+ seq_printf(p, "%*s: ", prec, "SPU");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs);
+ seq_printf(p, " Spurious interrupts\n");
+
+ seq_printf(p, "%*s: ", prec, "CNT");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs);
+ seq_printf(p, " Performance monitoring interrupts\n");
+
+ seq_printf(p, "%*s: ", prec, "MCE");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", per_cpu(irq_stat, j).mce_exceptions);
+ seq_printf(p, " Machine check exceptions\n");
+
+ return 0;
+}
+
int show_interrupts(struct seq_file *p, void *v)
{
- int i = *(loff_t *)v, j;
+ unsigned long flags, any_count = 0;
+ int i = *(loff_t *) v, j, prec;
struct irqaction *action;
struct irq_desc *desc;
- unsigned long flags;
+ if (i > nr_irqs)
+ return 0;
+
+ for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
+ j *= 10;
+
+ if (i == nr_irqs)
+ return show_other_interrupts(p, prec);
+
+ /* print header */
if (i == 0) {
- seq_puts(p, " ");
+ seq_printf(p, "%*s", prec + 8, "");
for_each_online_cpu(j)
- seq_printf(p, "CPU%d ", j);
+ seq_printf(p, "CPU%-8d", j);
seq_putc(p, '\n');
- } else if (i == nr_irqs) {
-#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
- if (tau_initialized){
- seq_puts(p, "TAU: ");
- for_each_online_cpu(j)
- seq_printf(p, "%10u ", tau_interrupts(j));
- seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n");
- }
-#endif /* CONFIG_PPC32 && CONFIG_TAU_INT*/
- seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts);
-
- return 0;
}
desc = irq_to_desc(i);
@@ -211,37 +247,48 @@ int show_interrupts(struct seq_file *p, void *v)
return 0;
raw_spin_lock_irqsave(&desc->lock, flags);
-
+ for_each_online_cpu(j)
+ any_count |= kstat_irqs_cpu(i, j);
action = desc->action;
- if (!action || !action->handler)
- goto skip;
+ if (!action && !any_count)
+ goto out;
- seq_printf(p, "%3d: ", i);
-#ifdef CONFIG_SMP
+ seq_printf(p, "%*d: ", prec, i);
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-#else
- seq_printf(p, "%10u ", kstat_irqs(i));
-#endif /* CONFIG_SMP */
if (desc->chip)
- seq_printf(p, " %s ", desc->chip->name);
+ seq_printf(p, " %-16s", desc->chip->name);
else
- seq_puts(p, " None ");
+ seq_printf(p, " %-16s", "None");
+ seq_printf(p, " %-8s", (desc->status & IRQ_LEVEL) ? "Level" : "Edge");
- seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge ");
- seq_printf(p, " %s", action->name);
+ if (action) {
+ seq_printf(p, " %s", action->name);
+ while ((action = action->next) != NULL)
+ seq_printf(p, ", %s", action->name);
+ }
- for (action = action->next; action; action = action->next)
- seq_printf(p, ", %s", action->name);
seq_putc(p, '\n');
-
-skip:
+out:
raw_spin_unlock_irqrestore(&desc->lock, flags);
-
return 0;
}
+/*
+ * /proc/stat helpers
+ */
+u64 arch_irq_stat_cpu(unsigned int cpu)
+{
+ u64 sum = per_cpu(irq_stat, cpu).timer_irqs;
+
+ sum += per_cpu(irq_stat, cpu).pmu_irqs;
+ sum += per_cpu(irq_stat, cpu).mce_exceptions;
+ sum += per_cpu(irq_stat, cpu).spurious_irqs;
+
+ return sum;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
void fixup_irqs(cpumask_t map)
{
@@ -353,8 +400,7 @@ void do_IRQ(struct pt_regs *regs)
if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
handle_one_irq(irq);
else if (irq != NO_IRQ_IGNORE)
- /* That's not SMP safe ... but who cares ? */
- ppc_spurious_interrupts++;
+ __get_cpu_var(irq_stat).spurious_irqs++;
irq_exit();
set_irq_regs(old_regs);
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index b6bd1eaa1c24..41bada0298c8 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -333,7 +333,7 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
atomic_set(&kgdb_cpu_doing_single_step, -1);
/* set the trace bit if we're stepping */
if (remcom_in_buffer[0] == 's') {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
mtspr(SPRN_DBCR0,
mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
linux_regs->msr |= MSR_DE;
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index c9329786073b..3fd1af902112 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -36,7 +36,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#ifdef CONFIG_BOOKE
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
#define MSR_SINGLESTEP (MSR_DE)
#else
#define MSR_SINGLESTEP (MSR_SE)
@@ -110,7 +110,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
* like Decrementer or External Interrupt */
regs->msr &= ~MSR_EE;
regs->msr |= MSR_SINGLESTEP;
-#ifdef CONFIG_BOOKE
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
regs->msr &= ~MSR_CE;
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
#endif
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 7b816daf3eba..e4d71ced97ef 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -245,6 +245,24 @@ void discard_lazy_cpu_state(void)
}
#endif /* CONFIG_SMP */
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+void do_send_trap(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code, int signal_code, int breakpt)
+{
+ siginfo_t info;
+
+ if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
+ 11, SIGSEGV) == NOTIFY_STOP)
+ return;
+
+ /* Deliver the signal to userspace */
+ info.si_signo = SIGTRAP;
+ info.si_errno = breakpt; /* breakpoint or watchpoint id */
+ info.si_code = signal_code;
+ info.si_addr = (void __user *)address;
+ force_sig_info(SIGTRAP, &info, current);
+}
+#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
void do_dabr(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
@@ -257,12 +275,6 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
if (debugger_dabr_match(regs))
return;
- /* Clear the DAC and struct entries. One shot trigger */
-#if defined(CONFIG_BOOKE)
- mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W
- | DBCR0_IDM));
-#endif
-
/* Clear the DABR */
set_dabr(0);
@@ -273,9 +285,82 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
info.si_addr = (void __user *)address;
force_sig_info(SIGTRAP, &info, current);
}
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
static DEFINE_PER_CPU(unsigned long, current_dabr);
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+/*
+ * Set the debug registers back to their default "safe" values.
+ */
+static void set_debug_reg_defaults(struct thread_struct *thread)
+{
+ thread->iac1 = thread->iac2 = 0;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ thread->iac3 = thread->iac4 = 0;
+#endif
+ thread->dac1 = thread->dac2 = 0;
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+ thread->dvc1 = thread->dvc2 = 0;
+#endif
+ thread->dbcr0 = 0;
+#ifdef CONFIG_BOOKE
+ /*
+ * Force User/Supervisor bits to b11 (user-only MSR[PR]=1)
+ */
+ thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | \
+ DBCR1_IAC3US | DBCR1_IAC4US;
+ /*
+ * Force Data Address Compare User/Supervisor bits to be User-only
+ * (0b11 MSR[PR]=1) and set all other bits in DBCR2 register to be 0.
+ */
+ thread->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
+#else
+ thread->dbcr1 = 0;
+#endif
+}
+
+static void prime_debug_regs(struct thread_struct *thread)
+{
+ mtspr(SPRN_IAC1, thread->iac1);
+ mtspr(SPRN_IAC2, thread->iac2);
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ mtspr(SPRN_IAC3, thread->iac3);
+ mtspr(SPRN_IAC4, thread->iac4);
+#endif
+ mtspr(SPRN_DAC1, thread->dac1);
+ mtspr(SPRN_DAC2, thread->dac2);
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+ mtspr(SPRN_DVC1, thread->dvc1);
+ mtspr(SPRN_DVC2, thread->dvc2);
+#endif
+ mtspr(SPRN_DBCR0, thread->dbcr0);
+ mtspr(SPRN_DBCR1, thread->dbcr1);
+#ifdef CONFIG_BOOKE
+ mtspr(SPRN_DBCR2, thread->dbcr2);
+#endif
+}
+/*
+ * Unless neither the old or new thread are making use of the
+ * debug registers, set the debug registers from the values
+ * stored in the new thread.
+ */
+static void switch_booke_debug_regs(struct thread_struct *new_thread)
+{
+ if ((current->thread.dbcr0 & DBCR0_IDM)
+ || (new_thread->dbcr0 & DBCR0_IDM))
+ prime_debug_regs(new_thread);
+}
+#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
+static void set_debug_reg_defaults(struct thread_struct *thread)
+{
+ if (thread->dabr) {
+ thread->dabr = 0;
+ set_dabr(0);
+ }
+}
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
+
int set_dabr(unsigned long dabr)
{
__get_cpu_var(current_dabr) = dabr;
@@ -284,7 +369,7 @@ int set_dabr(unsigned long dabr)
return ppc_md.set_dabr(dabr);
/* XXX should we have a CPU_FTR_HAS_DABR ? */
-#if defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
mtspr(SPRN_DAC1, dabr);
#elif defined(CONFIG_PPC_BOOK3S)
mtspr(SPRN_DABR, dabr);
@@ -371,10 +456,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
#endif /* CONFIG_SMP */
-#if defined(CONFIG_BOOKE)
- /* If new thread DAC (HW breakpoint) is the same then leave it */
- if (new->thread.dabr)
- set_dabr(new->thread.dabr);
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ switch_booke_debug_regs(&new->thread);
#else
if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
set_dabr(new->thread.dabr);
@@ -514,7 +597,7 @@ void show_regs(struct pt_regs * regs)
printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer);
trap = TRAP(regs);
if (trap == 0x300 || trap == 0x600)
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
printk("DEAR: "REG", ESR: "REG"\n", regs->dar, regs->dsisr);
#else
printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
@@ -556,14 +639,7 @@ void flush_thread(void)
{
discard_lazy_cpu_state();
- if (current->thread.dabr) {
- current->thread.dabr = 0;
- set_dabr(0);
-
-#if defined(CONFIG_BOOKE)
- current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W);
-#endif
- }
+ set_debug_reg_defaults(&current->thread);
}
void
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index ef149880c145..d9b05866615f 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -46,7 +46,7 @@
/*
* Set of msr bits that gdb can change on behalf of a process.
*/
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
#define MSR_DEBUGCHANGE 0
#else
#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
@@ -703,7 +703,7 @@ void user_enable_single_step(struct task_struct *task)
struct pt_regs *regs = task->thread.regs;
if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
task->thread.dbcr0 &= ~DBCR0_BT;
task->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
regs->msr |= MSR_DE;
@@ -720,7 +720,7 @@ void user_enable_block_step(struct task_struct *task)
struct pt_regs *regs = task->thread.regs;
if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
task->thread.dbcr0 &= ~DBCR0_IC;
task->thread.dbcr0 = DBCR0_IDM | DBCR0_BT;
regs->msr |= MSR_DE;
@@ -737,17 +737,25 @@ void user_disable_single_step(struct task_struct *task)
struct pt_regs *regs = task->thread.regs;
if (regs != NULL) {
-#if defined(CONFIG_BOOKE)
- /* If DAC don't clear DBCRO_IDM or MSR_DE */
- if (task->thread.dabr)
- task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT);
- else {
- task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT | DBCR0_IDM);
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ /*
+ * The logic to disable single stepping should be as
+ * simple as turning off the Instruction Complete flag.
+ * And, after doing so, if all debug flags are off, turn
+ * off DBCR0(IDM) and MSR(DE) .... Torez
+ */
+ task->thread.dbcr0 &= ~DBCR0_IC;
+ /*
+ * Test to see if any of the DBCR_ACTIVE_EVENTS bits are set.
+ */
+ if (!DBCR_ACTIVE_EVENTS(task->thread.dbcr0,
+ task->thread.dbcr1)) {
+ /*
+ * All debug events were off.....
+ */
+ task->thread.dbcr0 &= ~DBCR0_IDM;
regs->msr &= ~MSR_DE;
}
-#elif defined(CONFIG_40x)
- task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT | DBCR0_IDM);
- regs->msr &= ~MSR_DE;
#else
regs->msr &= ~(MSR_SE | MSR_BE);
#endif
@@ -769,8 +777,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
if ((data & ~0x7UL) >= TASK_SIZE)
return -EIO;
-#ifndef CONFIG_BOOKE
-
+#ifndef CONFIG_PPC_ADV_DEBUG_REGS
/* For processors using DABR (i.e. 970), the bottom 3 bits are flags.
* It was assumed, on previous implementations, that 3 bits were
* passed together with the data address, fitting the design of the
@@ -789,21 +796,22 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
/* Move contents to the DABR register */
task->thread.dabr = data;
-
-#endif
-#if defined(CONFIG_BOOKE)
-
+#else /* CONFIG_PPC_ADV_DEBUG_REGS */
/* As described above, it was assumed 3 bits were passed with the data
* address, but we will assume only the mode bits will be passed
* as to not cause alignment restrictions for DAC-based processors.
*/
/* DAC's hold the whole address without any mode flags */
- task->thread.dabr = data & ~0x3UL;
-
- if (task->thread.dabr == 0) {
- task->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | DBCR0_IDM);
- task->thread.regs->msr &= ~MSR_DE;
+ task->thread.dac1 = data & ~0x3UL;
+
+ if (task->thread.dac1 == 0) {
+ dbcr_dac(task) &= ~(DBCR_DAC1R | DBCR_DAC1W);
+ if (!DBCR_ACTIVE_EVENTS(task->thread.dbcr0,
+ task->thread.dbcr1)) {
+ task->thread.regs->msr &= ~MSR_DE;
+ task->thread.dbcr0 &= ~DBCR0_IDM;
+ }
return 0;
}
@@ -814,17 +822,17 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
/* Set the Internal Debugging flag (IDM bit 1) for the DBCR0
register */
- task->thread.dbcr0 = DBCR0_IDM;
+ task->thread.dbcr0 |= DBCR0_IDM;
/* Check for write and read flags and set DBCR0
accordingly */
+ dbcr_dac(task) &= ~(DBCR_DAC1R|DBCR_DAC1W);
if (data & 0x1UL)
- task->thread.dbcr0 |= DBSR_DAC1R;
+ dbcr_dac(task) |= DBCR_DAC1R;
if (data & 0x2UL)
- task->thread.dbcr0 |= DBSR_DAC1W;
-
+ dbcr_dac(task) |= DBCR_DAC1W;
task->thread.regs->msr |= MSR_DE;
-#endif
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
return 0;
}
@@ -839,6 +847,394 @@ void ptrace_disable(struct task_struct *child)
user_disable_single_step(child);
}
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+static long set_intruction_bp(struct task_struct *child,
+ struct ppc_hw_breakpoint *bp_info)
+{
+ int slot;
+ int slot1_in_use = ((child->thread.dbcr0 & DBCR0_IAC1) != 0);
+ int slot2_in_use = ((child->thread.dbcr0 & DBCR0_IAC2) != 0);
+ int slot3_in_use = ((child->thread.dbcr0 & DBCR0_IAC3) != 0);
+ int slot4_in_use = ((child->thread.dbcr0 & DBCR0_IAC4) != 0);
+
+ if (dbcr_iac_range(child) & DBCR_IAC12MODE)
+ slot2_in_use = 1;
+ if (dbcr_iac_range(child) & DBCR_IAC34MODE)
+ slot4_in_use = 1;
+
+ if (bp_info->addr >= TASK_SIZE)
+ return -EIO;
+
+ if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
+
+ /* Make sure range is valid. */
+ if (bp_info->addr2 >= TASK_SIZE)
+ return -EIO;
+
+ /* We need a pair of IAC regsisters */
+ if ((!slot1_in_use) && (!slot2_in_use)) {
+ slot = 1;
+ child->thread.iac1 = bp_info->addr;
+ child->thread.iac2 = bp_info->addr2;
+ child->thread.dbcr0 |= DBCR0_IAC1;
+ if (bp_info->addr_mode ==
+ PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
+ dbcr_iac_range(child) |= DBCR_IAC12X;
+ else
+ dbcr_iac_range(child) |= DBCR_IAC12I;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ } else if ((!slot3_in_use) && (!slot4_in_use)) {
+ slot = 3;
+ child->thread.iac3 = bp_info->addr;
+ child->thread.iac4 = bp_info->addr2;
+ child->thread.dbcr0 |= DBCR0_IAC3;
+ if (bp_info->addr_mode ==
+ PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
+ dbcr_iac_range(child) |= DBCR_IAC34X;
+ else
+ dbcr_iac_range(child) |= DBCR_IAC34I;
+#endif
+ } else
+ return -ENOSPC;
+ } else {
+ /* We only need one. If possible leave a pair free in
+ * case a range is needed later
+ */
+ if (!slot1_in_use) {
+ /*
+ * Don't use iac1 if iac1-iac2 are free and either
+ * iac3 or iac4 (but not both) are free
+ */
+ if (slot2_in_use || (slot3_in_use == slot4_in_use)) {
+ slot = 1;
+ child->thread.iac1 = bp_info->addr;
+ child->thread.dbcr0 |= DBCR0_IAC1;
+ goto out;
+ }
+ }
+ if (!slot2_in_use) {
+ slot = 2;
+ child->thread.iac2 = bp_info->addr;
+ child->thread.dbcr0 |= DBCR0_IAC2;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ } else if (!slot3_in_use) {
+ slot = 3;
+ child->thread.iac3 = bp_info->addr;
+ child->thread.dbcr0 |= DBCR0_IAC3;
+ } else if (!slot4_in_use) {
+ slot = 4;
+ child->thread.iac4 = bp_info->addr;
+ child->thread.dbcr0 |= DBCR0_IAC4;
+#endif
+ } else
+ return -ENOSPC;
+ }
+out:
+ child->thread.dbcr0 |= DBCR0_IDM;
+ child->thread.regs->msr |= MSR_DE;
+
+ return slot;
+}
+
+static int del_instruction_bp(struct task_struct *child, int slot)
+{
+ switch (slot) {
+ case 1:
+ if (child->thread.iac1 == 0)
+ return -ENOENT;
+
+ if (dbcr_iac_range(child) & DBCR_IAC12MODE) {
+ /* address range - clear slots 1 & 2 */
+ child->thread.iac2 = 0;
+ dbcr_iac_range(child) &= ~DBCR_IAC12MODE;
+ }
+ child->thread.iac1 = 0;
+ child->thread.dbcr0 &= ~DBCR0_IAC1;
+ break;
+ case 2:
+ if (child->thread.iac2 == 0)
+ return -ENOENT;
+
+ if (dbcr_iac_range(child) & DBCR_IAC12MODE)
+ /* used in a range */
+ return -EINVAL;
+ child->thread.iac2 = 0;
+ child->thread.dbcr0 &= ~DBCR0_IAC2;
+ break;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ case 3:
+ if (child->thread.iac3 == 0)
+ return -ENOENT;
+
+ if (dbcr_iac_range(child) & DBCR_IAC34MODE) {
+ /* address range - clear slots 3 & 4 */
+ child->thread.iac4 = 0;
+ dbcr_iac_range(child) &= ~DBCR_IAC34MODE;
+ }
+ child->thread.iac3 = 0;
+ child->thread.dbcr0 &= ~DBCR0_IAC3;
+ break;
+ case 4:
+ if (child->thread.iac4 == 0)
+ return -ENOENT;
+
+ if (dbcr_iac_range(child) & DBCR_IAC34MODE)
+ /* Used in a range */
+ return -EINVAL;
+ child->thread.iac4 = 0;
+ child->thread.dbcr0 &= ~DBCR0_IAC4;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int set_dac(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
+{
+ int byte_enable =
+ (bp_info->condition_mode >> PPC_BREAKPOINT_CONDITION_BE_SHIFT)
+ & 0xf;
+ int condition_mode =
+ bp_info->condition_mode & PPC_BREAKPOINT_CONDITION_MODE;
+ int slot;
+
+ if (byte_enable && (condition_mode == 0))
+ return -EINVAL;
+
+ if (bp_info->addr >= TASK_SIZE)
+ return -EIO;
+
+ if ((dbcr_dac(child) & (DBCR_DAC1R | DBCR_DAC1W)) == 0) {
+ slot = 1;
+ if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
+ dbcr_dac(child) |= DBCR_DAC1R;
+ if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
+ dbcr_dac(child) |= DBCR_DAC1W;
+ child->thread.dac1 = (unsigned long)bp_info->addr;
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+ if (byte_enable) {
+ child->thread.dvc1 =
+ (unsigned long)bp_info->condition_value;
+ child->thread.dbcr2 |=
+ ((byte_enable << DBCR2_DVC1BE_SHIFT) |
+ (condition_mode << DBCR2_DVC1M_SHIFT));
+ }
+#endif
+#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
+ } else if (child->thread.dbcr2 & DBCR2_DAC12MODE) {
+ /* Both dac1 and dac2 are part of a range */
+ return -ENOSPC;
+#endif
+ } else if ((dbcr_dac(child) & (DBCR_DAC2R | DBCR_DAC2W)) == 0) {
+ slot = 2;
+ if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
+ dbcr_dac(child) |= DBCR_DAC2R;
+ if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
+ dbcr_dac(child) |= DBCR_DAC2W;
+ child->thread.dac2 = (unsigned long)bp_info->addr;
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+ if (byte_enable) {
+ child->thread.dvc2 =
+ (unsigned long)bp_info->condition_value;
+ child->thread.dbcr2 |=
+ ((byte_enable << DBCR2_DVC2BE_SHIFT) |
+ (condition_mode << DBCR2_DVC2M_SHIFT));
+ }
+#endif
+ } else
+ return -ENOSPC;
+ child->thread.dbcr0 |= DBCR0_IDM;
+ child->thread.regs->msr |= MSR_DE;
+
+ return slot + 4;
+}
+
+static int del_dac(struct task_struct *child, int slot)
+{
+ if (slot == 1) {
+ if (child->thread.dac1 == 0)
+ return -ENOENT;
+
+ child->thread.dac1 = 0;
+ dbcr_dac(child) &= ~(DBCR_DAC1R | DBCR_DAC1W);
+#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
+ if (child->thread.dbcr2 & DBCR2_DAC12MODE) {
+ child->thread.dac2 = 0;
+ child->thread.dbcr2 &= ~DBCR2_DAC12MODE;
+ }
+ child->thread.dbcr2 &= ~(DBCR2_DVC1M | DBCR2_DVC1BE);
+#endif
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+ child->thread.dvc1 = 0;
+#endif
+ } else if (slot == 2) {
+ if (child->thread.dac1 == 0)
+ return -ENOENT;
+
+#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
+ if (child->thread.dbcr2 & DBCR2_DAC12MODE)
+ /* Part of a range */
+ return -EINVAL;
+ child->thread.dbcr2 &= ~(DBCR2_DVC2M | DBCR2_DVC2BE);
+#endif
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+ child->thread.dvc2 = 0;
+#endif
+ child->thread.dac2 = 0;
+ dbcr_dac(child) &= ~(DBCR_DAC2R | DBCR_DAC2W);
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
+
+#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
+static int set_dac_range(struct task_struct *child,
+ struct ppc_hw_breakpoint *bp_info)
+{
+ int mode = bp_info->addr_mode & PPC_BREAKPOINT_MODE_MASK;
+
+ /* We don't allow range watchpoints to be used with DVC */
+ if (bp_info->condition_mode)
+ return -EINVAL;
+
+ /*
+ * Best effort to verify the address range. The user/supervisor bits
+ * prevent trapping in kernel space, but let's fail on an obvious bad
+ * range. The simple test on the mask is not fool-proof, and any
+ * exclusive range will spill over into kernel space.
+ */
+ if (bp_info->addr >= TASK_SIZE)
+ return -EIO;
+ if (mode == PPC_BREAKPOINT_MODE_MASK) {
+ /*
+ * dac2 is a bitmask. Don't allow a mask that makes a
+ * kernel space address from a valid dac1 value
+ */
+ if (~((unsigned long)bp_info->addr2) >= TASK_SIZE)
+ return -EIO;
+ } else {
+ /*
+ * For range breakpoints, addr2 must also be a valid address
+ */
+ if (bp_info->addr2 >= TASK_SIZE)
+ return -EIO;
+ }
+
+ if (child->thread.dbcr0 &
+ (DBCR0_DAC1R | DBCR0_DAC1W | DBCR0_DAC2R | DBCR0_DAC2W))
+ return -ENOSPC;
+
+ if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
+ child->thread.dbcr0 |= (DBCR0_DAC1R | DBCR0_IDM);
+ if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
+ child->thread.dbcr0 |= (DBCR0_DAC1W | DBCR0_IDM);
+ child->thread.dac1 = bp_info->addr;
+ child->thread.dac2 = bp_info->addr2;
+ if (mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
+ child->thread.dbcr2 |= DBCR2_DAC12M;
+ else if (mode == PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
+ child->thread.dbcr2 |= DBCR2_DAC12MX;
+ else /* PPC_BREAKPOINT_MODE_MASK */
+ child->thread.dbcr2 |= DBCR2_DAC12MM;
+ child->thread.regs->msr |= MSR_DE;
+
+ return 5;
+}
+#endif /* CONFIG_PPC_ADV_DEBUG_DAC_RANGE */
+
+static long ppc_set_hwdebug(struct task_struct *child,
+ struct ppc_hw_breakpoint *bp_info)
+{
+ if (bp_info->version != 1)
+ return -ENOTSUPP;
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ /*
+ * Check for invalid flags and combinations
+ */
+ if ((bp_info->trigger_type == 0) ||
+ (bp_info->trigger_type & ~(PPC_BREAKPOINT_TRIGGER_EXECUTE |
+ PPC_BREAKPOINT_TRIGGER_RW)) ||
+ (bp_info->addr_mode & ~PPC_BREAKPOINT_MODE_MASK) ||
+ (bp_info->condition_mode &
+ ~(PPC_BREAKPOINT_CONDITION_MODE |
+ PPC_BREAKPOINT_CONDITION_BE_ALL)))
+ return -EINVAL;
+#if CONFIG_PPC_ADV_DEBUG_DVCS == 0
+ if (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
+ return -EINVAL;
+#endif
+
+ if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_EXECUTE) {
+ if ((bp_info->trigger_type != PPC_BREAKPOINT_TRIGGER_EXECUTE) ||
+ (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE))
+ return -EINVAL;
+ return set_intruction_bp(child, bp_info);
+ }
+ if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT)
+ return set_dac(child, bp_info);
+
+#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
+ return set_dac_range(child, bp_info);
+#else
+ return -EINVAL;
+#endif
+#else /* !CONFIG_PPC_ADV_DEBUG_DVCS */
+ /*
+ * We only support one data breakpoint
+ */
+ if (((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0) ||
+ ((bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0) ||
+ (bp_info->trigger_type != PPC_BREAKPOINT_TRIGGER_WRITE) ||
+ (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) ||
+ (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE))
+ return -EINVAL;
+
+ if (child->thread.dabr)
+ return -ENOSPC;
+
+ if ((unsigned long)bp_info->addr >= TASK_SIZE)
+ return -EIO;
+
+ child->thread.dabr = (unsigned long)bp_info->addr;
+
+ return 1;
+#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
+}
+
+static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
+{
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ int rc;
+
+ if (data <= 4)
+ rc = del_instruction_bp(child, (int)data);
+ else
+ rc = del_dac(child, (int)data - 4);
+
+ if (!rc) {
+ if (!DBCR_ACTIVE_EVENTS(child->thread.dbcr0,
+ child->thread.dbcr1)) {
+ child->thread.dbcr0 &= ~DBCR0_IDM;
+ child->thread.regs->msr &= ~MSR_DE;
+ }
+ }
+ return rc;
+#else
+ if (data != 1)
+ return -EINVAL;
+ if (child->thread.dabr == 0)
+ return -ENOENT;
+
+ child->thread.dabr = 0;
+
+ return 0;
+#endif
+}
+
/*
* Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
* we mark them as obsolete now, they will be removed in a future version
@@ -932,13 +1328,77 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
+ case PPC_PTRACE_GETHWDBGINFO: {
+ struct ppc_debug_info dbginfo;
+
+ dbginfo.version = 1;
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ dbginfo.num_instruction_bps = CONFIG_PPC_ADV_DEBUG_IACS;
+ dbginfo.num_data_bps = CONFIG_PPC_ADV_DEBUG_DACS;
+ dbginfo.num_condition_regs = CONFIG_PPC_ADV_DEBUG_DVCS;
+ dbginfo.data_bp_alignment = 4;
+ dbginfo.sizeof_condition = 4;
+ dbginfo.features = PPC_DEBUG_FEATURE_INSN_BP_RANGE |
+ PPC_DEBUG_FEATURE_INSN_BP_MASK;
+#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
+ dbginfo.features |=
+ PPC_DEBUG_FEATURE_DATA_BP_RANGE |
+ PPC_DEBUG_FEATURE_DATA_BP_MASK;
+#endif
+#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
+ dbginfo.num_instruction_bps = 0;
+ dbginfo.num_data_bps = 1;
+ dbginfo.num_condition_regs = 0;
+#ifdef CONFIG_PPC64
+ dbginfo.data_bp_alignment = 8;
+#else
+ dbginfo.data_bp_alignment = 4;
+#endif
+ dbginfo.sizeof_condition = 0;
+ dbginfo.features = 0;
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
+
+ if (!access_ok(VERIFY_WRITE, data,
+ sizeof(struct ppc_debug_info)))
+ return -EFAULT;
+ ret = __copy_to_user((struct ppc_debug_info __user *)data,
+ &dbginfo, sizeof(struct ppc_debug_info)) ?
+ -EFAULT : 0;
+ break;
+ }
+
+ case PPC_PTRACE_SETHWDEBUG: {
+ struct ppc_hw_breakpoint bp_info;
+
+ if (!access_ok(VERIFY_READ, data,
+ sizeof(struct ppc_hw_breakpoint)))
+ return -EFAULT;
+ ret = __copy_from_user(&bp_info,
+ (struct ppc_hw_breakpoint __user *)data,
+ sizeof(struct ppc_hw_breakpoint)) ?
+ -EFAULT : 0;
+ if (!ret)
+ ret = ppc_set_hwdebug(child, &bp_info);
+ break;
+ }
+
+ case PPC_PTRACE_DELHWDEBUG: {
+ ret = ppc_del_hwdebug(child, addr, data);
+ break;
+ }
+
case PTRACE_GET_DEBUGREG: {
ret = -EINVAL;
/* We only support one DABR and no IABRS at the moment */
if (addr > 0)
break;
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ ret = put_user(child->thread.dac1,
+ (unsigned long __user *)data);
+#else
ret = put_user(child->thread.dabr,
(unsigned long __user *)data);
+#endif
break;
}
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 00b5078da9a3..a0afb555a7c9 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -140,17 +140,15 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs)
return 0; /* no signals delivered */
}
+#ifndef CONFIG_PPC_ADV_DEBUG_REGS
/*
* Reenable the DABR before delivering the signal to
* user space. The DABR will have been cleared if it
* triggered inside the kernel.
*/
- if (current->thread.dabr) {
+ if (current->thread.dabr)
set_dabr(current->thread.dabr);
-#if defined(CONFIG_BOOKE)
- mtspr(SPRN_DBCR0, current->thread.dbcr0);
#endif
- }
if (is32) {
if (ka.sa.sa_flags & SA_SIGINFO)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d670429a1608..266610119f66 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -1078,7 +1078,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
int i;
unsigned char tmp;
unsigned long new_msr = regs->msr;
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
unsigned long new_dbcr0 = current->thread.dbcr0;
#endif
@@ -1087,13 +1087,17 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
return -EFAULT;
switch (op.dbg_type) {
case SIG_DBG_SINGLE_STEPPING:
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
if (op.dbg_value) {
new_msr |= MSR_DE;
new_dbcr0 |= (DBCR0_IDM | DBCR0_IC);
} else {
- new_msr &= ~MSR_DE;
- new_dbcr0 &= ~(DBCR0_IDM | DBCR0_IC);
+ new_dbcr0 &= ~DBCR0_IC;
+ if (!DBCR_ACTIVE_EVENTS(new_dbcr0,
+ current->thread.dbcr1)) {
+ new_msr &= ~MSR_DE;
+ new_dbcr0 &= ~DBCR0_IDM;
+ }
}
#else
if (op.dbg_value)
@@ -1103,7 +1107,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
#endif
break;
case SIG_DBG_BRANCH_TRACING:
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
return -EINVAL;
#else
if (op.dbg_value)
@@ -1124,7 +1128,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
failure is a problem, anyway, and it's very unlikely unless
the user is really doing something wrong. */
regs->msr = new_msr;
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
current->thread.dbcr0 = new_dbcr0;
#endif
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index ed1c0f58344a..1b16b9a3e49a 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -575,6 +575,8 @@ void timer_interrupt(struct pt_regs * regs)
trace_timer_interrupt_entry(regs);
+ __get_cpu_var(irq_stat).timer_irqs++;
+
/* Ensure a positive value is written to the decrementer, or else
* some CPUs will continuue to take decrementer exceptions */
set_dec(DECREMENTER_MAX);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 0a320dbd950a..987437e04e61 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -299,7 +299,7 @@ static inline int check_io_access(struct pt_regs *regs)
return 0;
}
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
/* On 4xx, the reason for the machine check or program exception
is in the ESR. */
#define get_reason(regs) ((regs)->dsisr)
@@ -483,6 +483,8 @@ void machine_check_exception(struct pt_regs *regs)
{
int recover = 0;
+ __get_cpu_var(irq_stat).mce_exceptions++;
+
/* See if any machine dependent calls. In theory, we would want
* to call the CPU first, and call the ppc_md. one if the CPU
* one returns a positive number. However there is existing code
@@ -965,6 +967,8 @@ void vsx_unavailable_exception(struct pt_regs *regs)
void performance_monitor_exception(struct pt_regs *regs)
{
+ __get_cpu_var(irq_stat).pmu_irqs++;
+
perf_irq(regs);
}
@@ -1029,10 +1033,69 @@ void SoftwareEmulation(struct pt_regs *regs)
}
#endif /* CONFIG_8xx */
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
+{
+ int changed = 0;
+ /*
+ * Determine the cause of the debug event, clear the
+ * event flags and send a trap to the handler. Torez
+ */
+ if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) {
+ dbcr_dac(current) &= ~(DBCR_DAC1R | DBCR_DAC1W);
+#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
+ current->thread.dbcr2 &= ~DBCR2_DAC12MODE;
+#endif
+ do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT,
+ 5);
+ changed |= 0x01;
+ } else if (debug_status & (DBSR_DAC2R | DBSR_DAC2W)) {
+ dbcr_dac(current) &= ~(DBCR_DAC2R | DBCR_DAC2W);
+ do_send_trap(regs, mfspr(SPRN_DAC2), debug_status, TRAP_HWBKPT,
+ 6);
+ changed |= 0x01;
+ } else if (debug_status & DBSR_IAC1) {
+ current->thread.dbcr0 &= ~DBCR0_IAC1;
+ dbcr_iac_range(current) &= ~DBCR_IAC12MODE;
+ do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT,
+ 1);
+ changed |= 0x01;
+ } else if (debug_status & DBSR_IAC2) {
+ current->thread.dbcr0 &= ~DBCR0_IAC2;
+ do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT,
+ 2);
+ changed |= 0x01;
+ } else if (debug_status & DBSR_IAC3) {
+ current->thread.dbcr0 &= ~DBCR0_IAC3;
+ dbcr_iac_range(current) &= ~DBCR_IAC34MODE;
+ do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT,
+ 3);
+ changed |= 0x01;
+ } else if (debug_status & DBSR_IAC4) {
+ current->thread.dbcr0 &= ~DBCR0_IAC4;
+ do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT,
+ 4);
+ changed |= 0x01;
+ }
+ /*
+ * At the point this routine was called, the MSR(DE) was turned off.
+ * Check all other debug flags and see if that bit needs to be turned
+ * back on or not.
+ */
+ if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, current->thread.dbcr1))
+ regs->msr |= MSR_DE;
+ else
+ /* Make sure the IDM flag is off */
+ current->thread.dbcr0 &= ~DBCR0_IDM;
+
+ if (changed & 0x01)
+ mtspr(SPRN_DBCR0, current->thread.dbcr0);
+}
void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
{
+ current->thread.dbsr = debug_status;
+
/* Hack alert: On BookE, Branch Taken stops on the branch itself, while
* on server, it stops on the target of the branch. In order to simulate
* the server behaviour, we thus restart right away with a single step
@@ -1076,29 +1139,23 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
if (debugger_sstep(regs))
return;
- if (user_mode(regs))
- current->thread.dbcr0 &= ~(DBCR0_IC);
-
- _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
- } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) {
- regs->msr &= ~MSR_DE;
-
if (user_mode(regs)) {
- current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W |
- DBCR0_IDM);
- } else {
- /* Disable DAC interupts */
- mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R |
- DBSR_DAC1W | DBCR0_IDM));
-
- /* Clear the DAC event */
- mtspr(SPRN_DBSR, (DBSR_DAC1R | DBSR_DAC1W));
+ current->thread.dbcr0 &= ~DBCR0_IC;
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0,
+ current->thread.dbcr1))
+ regs->msr |= MSR_DE;
+ else
+ /* Make sure the IDM bit is off */
+ current->thread.dbcr0 &= ~DBCR0_IDM;
+#endif
}
- /* Setup and send the trap to the handler */
- do_dabr(regs, mfspr(SPRN_DAC1), debug_status);
- }
+
+ _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
+ } else
+ handle_debug(regs, debug_status);
}
-#endif /* CONFIG_4xx || CONFIG_BOOKE */
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
#if !defined(CONFIG_TAU_INT)
void TAUException(struct pt_regs *regs)
diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S
index e68beac0a171..4d4eeb900486 100644
--- a/arch/powerpc/lib/copypage_64.S
+++ b/arch/powerpc/lib/copypage_64.S
@@ -43,62 +43,62 @@ END_FTR_SECTION_IFSET(CPU_FTR_CP_USE_DCBTZ)
ld r7,16(r4)
ldu r8,24(r4)
1: std r5,8(r3)
- ld r9,8(r4)
std r6,16(r3)
+ ld r9,8(r4)
ld r10,16(r4)
std r7,24(r3)
- ld r11,24(r4)
std r8,32(r3)
+ ld r11,24(r4)
ld r12,32(r4)
std r9,40(r3)
- ld r5,40(r4)
std r10,48(r3)
+ ld r5,40(r4)
ld r6,48(r4)
std r11,56(r3)
- ld r7,56(r4)
std r12,64(r3)
+ ld r7,56(r4)
ld r8,64(r4)
std r5,72(r3)
- ld r9,72(r4)
std r6,80(r3)
+ ld r9,72(r4)
ld r10,80(r4)
std r7,88(r3)
- ld r11,88(r4)
std r8,96(r3)
+ ld r11,88(r4)
ld r12,96(r4)
std r9,104(r3)
- ld r5,104(r4)
std r10,112(r3)
+ ld r5,104(r4)
ld r6,112(r4)
std r11,120(r3)
- ld r7,120(r4)
stdu r12,128(r3)
+ ld r7,120(r4)
ldu r8,128(r4)
bdnz 1b
std r5,8(r3)
- ld r9,8(r4)
std r6,16(r3)
+ ld r9,8(r4)
ld r10,16(r4)
std r7,24(r3)
- ld r11,24(r4)
std r8,32(r3)
+ ld r11,24(r4)
ld r12,32(r4)
std r9,40(r3)
- ld r5,40(r4)
std r10,48(r3)
+ ld r5,40(r4)
ld r6,48(r4)
std r11,56(r3)
- ld r7,56(r4)
std r12,64(r3)
+ ld r7,56(r4)
ld r8,64(r4)
std r5,72(r3)
- ld r9,72(r4)
std r6,80(r3)
+ ld r9,72(r4)
ld r10,80(r4)
std r7,88(r3)
- ld r11,88(r4)
std r8,96(r3)
+ ld r11,88(r4)
ld r12,96(r4)
std r9,104(r3)
std r10,112(r3)
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
index 693b14a778fa..578b625d6a3c 100644
--- a/arch/powerpc/lib/copyuser_64.S
+++ b/arch/powerpc/lib/copyuser_64.S
@@ -44,37 +44,55 @@ BEGIN_FTR_SECTION
andi. r0,r4,7
bne .Lsrc_unaligned
END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
- srdi r7,r5,4
-20: ld r9,0(r4)
- addi r4,r4,-8
- mtctr r7
- andi. r5,r5,7
- bf cr7*4+0,22f
- addi r3,r3,8
- addi r4,r4,8
- mr r8,r9
- blt cr1,72f
-21: ld r9,8(r4)
-70: std r8,8(r3)
-22: ldu r8,16(r4)
-71: stdu r9,16(r3)
+ blt cr1,.Ldo_tail /* if < 16 bytes to copy */
+ srdi r0,r5,5
+ cmpdi cr1,r0,0
+20: ld r7,0(r4)
+220: ld r6,8(r4)
+ addi r4,r4,16
+ mtctr r0
+ andi. r0,r5,0x10
+ beq 22f
+ addi r3,r3,16
+ addi r4,r4,-16
+ mr r9,r7
+ mr r8,r6
+ beq cr1,72f
+21: ld r7,16(r4)
+221: ld r6,24(r4)
+ addi r4,r4,32
+70: std r9,0(r3)
+270: std r8,8(r3)
+22: ld r9,0(r4)
+222: ld r8,8(r4)
+71: std r7,16(r3)
+271: std r6,24(r3)
+ addi r3,r3,32
bdnz 21b
-72: std r8,8(r3)
+72: std r9,0(r3)
+272: std r8,8(r3)
+ andi. r5,r5,0xf
beq+ 3f
- addi r3,r3,16
+ addi r4,r4,16
.Ldo_tail:
- bf cr7*4+1,1f
-23: lwz r9,8(r4)
+ addi r3,r3,16
+ bf cr7*4+0,246f
+244: ld r9,0(r4)
+ addi r4,r4,8
+245: std r9,0(r3)
+ addi r3,r3,8
+246: bf cr7*4+1,1f
+23: lwz r9,0(r4)
addi r4,r4,4
73: stw r9,0(r3)
addi r3,r3,4
1: bf cr7*4+2,2f
-44: lhz r9,8(r4)
+44: lhz r9,0(r4)
addi r4,r4,2
74: sth r9,0(r3)
addi r3,r3,2
2: bf cr7*4+3,3f
-45: lbz r9,8(r4)
+45: lbz r9,0(r4)
75: stb r9,0(r3)
3: li r3,0
blr
@@ -220,7 +238,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
131:
addi r3,r3,8
120:
+320:
122:
+322:
124:
125:
126:
@@ -229,9 +249,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
129:
133:
addi r3,r3,8
-121:
132:
addi r3,r3,8
+121:
+321:
+344:
134:
135:
138:
@@ -303,18 +325,22 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
183:
add r3,r3,r7
b 1f
+371:
180:
addi r3,r3,8
171:
177:
addi r3,r3,8
-170:
-172:
+370:
+372:
176:
178:
addi r3,r3,4
185:
addi r3,r3,4
+170:
+172:
+345:
173:
174:
175:
@@ -341,11 +367,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
.section __ex_table,"a"
.align 3
.llong 20b,120b
+ .llong 220b,320b
.llong 21b,121b
+ .llong 221b,321b
.llong 70b,170b
+ .llong 270b,370b
.llong 22b,122b
+ .llong 222b,322b
.llong 71b,171b
+ .llong 271b,371b
.llong 72b,172b
+ .llong 272b,372b
+ .llong 244b,344b
+ .llong 245b,345b
.llong 23b,123b
.llong 73b,173b
.llong 44b,144b
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 7e8865bcd683..4dee652dfcad 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -112,7 +112,7 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
{
- unsigned int *start, *end, *dest;
+ int *start, *end, *dest;
if (!(value & CPU_FTR_LWSYNC))
return ;
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 056d23a1b105..9e1aa4f99fac 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -122,7 +122,7 @@ static inline void native_lock_hpte(struct hash_pte *hptep)
unsigned long *word = &hptep->v;
while (1) {
- if (!test_and_set_bit(HPTE_LOCK_BIT, word))
+ if (!test_and_set_bit_lock(HPTE_LOCK_BIT, word))
break;
while(test_bit(HPTE_LOCK_BIT, word))
cpu_relax();
@@ -133,8 +133,7 @@ static inline void native_unlock_hpte(struct hash_pte *hptep)
{
unsigned long *word = &hptep->v;
- asm volatile("lwsync":::"memory");
- clear_bit(HPTE_LOCK_BIT, word);
+ clear_bit_unlock(HPTE_LOCK_BIT, word);
}
static long native_hpte_insert(unsigned long hpte_group, unsigned long va,
diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c
index 282d9306361f..1ec06576f619 100644
--- a/arch/powerpc/mm/tlb_hash64.c
+++ b/arch/powerpc/mm/tlb_hash64.c
@@ -63,15 +63,21 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
if (huge) {
#ifdef CONFIG_HUGETLB_PAGE
psize = get_slice_psize(mm, addr);
+ /* Mask the address for the correct page size */
+ addr &= ~((1UL << mmu_psize_defs[psize].shift) - 1);
#else
BUG();
psize = pte_pagesize_index(mm, addr, pte); /* shutup gcc */
#endif
- } else
+ } else {
psize = pte_pagesize_index(mm, addr, pte);
+ /* Mask the address for the standard page size. If we
+ * have a 64k page kernel, but the hardware does not
+ * support 64k pages, this might be different from the
+ * hardware page size encoded in the slice table. */
+ addr &= PAGE_MASK;
+ }
- /* Mask the address for the correct page size */
- addr &= ~((1UL << mmu_psize_defs[psize].shift) - 1);
/* Build full vaddr */
if (!is_kernel_addr(addr)) {
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
index da9b20a63769..4ecf4cf9a51b 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
@@ -79,7 +79,7 @@ cpld_unmask_irq(unsigned int irq)
}
static struct irq_chip cpld_pic = {
- .name = " CPLD PIC ",
+ .name = "CPLD PIC",
.mask = cpld_mask_irq,
.ack = cpld_mask_irq,
.unmask = cpld_unmask_irq,
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
index e5da5f62b24a..42e87f08aa01 100644
--- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
+++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
@@ -232,7 +232,7 @@ static int socrates_fpga_pic_set_type(unsigned int virq,
}
static struct irq_chip socrates_fpga_pic_chip = {
- .name = " FPGA-PIC ",
+ .name = "FPGA-PIC",
.ack = socrates_fpga_pic_ack,
.mask = socrates_fpga_pic_mask,
.mask_ack = socrates_fpga_pic_mask_ack,
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 36052a9ebcda..8d29290f6070 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -110,7 +110,7 @@ static void beatic_end_irq(unsigned int irq_plug)
}
static struct irq_chip beatic_pic = {
- .name = " CELL-BEAT ",
+ .name = "CELL-BEAT",
.unmask = beatic_unmask_irq,
.mask = beatic_mask_irq,
.eoi = beatic_end_irq,
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 6829cf7e2bda..10eb1a443626 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -88,7 +88,7 @@ static void iic_eoi(unsigned int irq)
}
static struct irq_chip iic_chip = {
- .name = " CELL-IIC ",
+ .name = "CELL-IIC",
.mask = iic_mask,
.unmask = iic_unmask,
.eoi = iic_eoi,
@@ -133,7 +133,7 @@ static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc)
static struct irq_chip iic_ioexc_chip = {
- .name = " CELL-IOEX",
+ .name = "CELL-IOEX",
.mask = iic_mask,
.unmask = iic_unmask,
.eoi = iic_ioexc_eoi,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 01244f254a11..5876e888e412 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -168,7 +168,7 @@ static int spider_set_irq_type(unsigned int virq, unsigned int type)
}
static struct irq_chip spider_pic = {
- .name = " SPIDER ",
+ .name = "SPIDER",
.unmask = spider_unmask_irq,
.mask = spider_mask_irq,
.ack = spider_ack_irq,
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 86c4b29eea89..ba446bf355a9 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -273,7 +273,7 @@ static void iseries_end_IRQ(unsigned int irq)
}
static struct irq_chip iseries_pic = {
- .name = "iSeries irq controller",
+ .name = "iSeries",
.startup = iseries_startup_IRQ,
.shutdown = iseries_shutdown_IRQ,
.unmask = iseries_enable_IRQ,
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 09e827296276..3b62896f9a5b 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -195,7 +195,7 @@ static int pmac_retrigger(unsigned int virq)
}
static struct irq_chip pmac_pic = {
- .name = " PMAC-PIC ",
+ .name = "PMAC-PIC",
.startup = pmac_startup_irq,
.mask = pmac_mask_irq,
.ack = pmac_ack_irq,
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index ccd8dd03b8c9..3304f32fc7b8 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -491,7 +491,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
pdn->eeh_mode & EEH_MODE_NOCHECK) {
ignored_check++;
pr_debug("EEH: Ignored check (%x) for %s %s\n",
- pdn->eeh_mode, pci_name (dev), dn->full_name);
+ pdn->eeh_mode, eeh_pci_name(dev), dn->full_name);
return 0;
}
@@ -515,7 +515,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
printk (KERN_ERR "EEH: %d reads ignored for recovering device at "
"location=%s driver=%s pci addr=%s\n",
pdn->eeh_check_count, location,
- dev->driver->name, pci_name(dev));
+ dev->driver->name, eeh_pci_name(dev));
printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n",
dev->driver->name);
dump_stack();
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 0c252c3a5f9f..b8d70f5d9aa9 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -337,7 +337,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
location = location ? location : "unknown";
printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
"for location=%s pci addr=%s\n",
- location, pci_name(event->dev));
+ location, eeh_pci_name(event->dev));
return NULL;
}
@@ -368,7 +368,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
pci_str = pci_name (frozen_pdn->pcidev);
drv_str = pcid_name (frozen_pdn->pcidev);
} else {
- pci_str = pci_name (event->dev);
+ pci_str = eeh_pci_name(event->dev);
drv_str = pcid_name (event->dev);
}
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c
index ddb80f5d850b..ec5df8f519c7 100644
--- a/arch/powerpc/platforms/pseries/eeh_event.c
+++ b/arch/powerpc/platforms/pseries/eeh_event.c
@@ -80,7 +80,7 @@ static int eeh_event_handler(void * dummy)
eeh_mark_slot(event->dn, EEH_MODE_RECOVERING);
printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n",
- pci_name(event->dev));
+ eeh_pci_name(event->dev));
pdn = handle_eeh_events(event);
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index e9a52ec05a0f..4ca641042ec3 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -424,7 +424,7 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
}
static struct irq_chip xics_pic_direct = {
- .name = " XICS ",
+ .name = "XICS",
.startup = xics_startup,
.mask = xics_mask_irq,
.unmask = xics_unmask_irq,
@@ -433,7 +433,7 @@ static struct irq_chip xics_pic_direct = {
};
static struct irq_chip xics_pic_lpar = {
- .name = " XICS ",
+ .name = "XICS",
.startup = xics_startup,
.mask = xics_mask_irq,
.unmask = xics_unmask_irq,
@@ -510,15 +510,13 @@ static void __init xics_init_host(void)
/*
* XICS only has a single IPI, so encode the messages per CPU
*/
-struct xics_ipi_struct {
- unsigned long value;
- } ____cacheline_aligned;
-
-static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
+static DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
static inline void smp_xics_do_message(int cpu, int msg)
{
- set_bit(msg, &xics_ipi_message[cpu].value);
+ unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
+
+ set_bit(msg, tgt);
mb();
if (firmware_has_feature(FW_FEATURE_LPAR))
lpar_qirr_info(cpu, IPI_PRIORITY);
@@ -544,25 +542,23 @@ void smp_xics_message_pass(int target, int msg)
static irqreturn_t xics_ipi_dispatch(int cpu)
{
+ unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
+
WARN_ON(cpu_is_offline(cpu));
mb(); /* order mmio clearing qirr */
- while (xics_ipi_message[cpu].value) {
- if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
- &xics_ipi_message[cpu].value)) {
+ while (*tgt) {
+ if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) {
smp_message_recv(PPC_MSG_CALL_FUNCTION);
}
- if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
- &xics_ipi_message[cpu].value)) {
+ if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) {
smp_message_recv(PPC_MSG_RESCHEDULE);
}
- if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE,
- &xics_ipi_message[cpu].value)) {
+ if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) {
smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
}
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
- if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
- &xics_ipi_message[cpu].value)) {
+ if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) {
smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
}
#endif
@@ -784,9 +780,13 @@ static void xics_set_cpu_priority(unsigned char cppr)
{
struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
- BUG_ON(os_cppr->index != 0);
+ /*
+ * we only really want to set the priority when there's
+ * just one cppr value on the stack
+ */
+ WARN_ON(os_cppr->index != 0);
- os_cppr->stack[os_cppr->index] = cppr;
+ os_cppr->stack[0] = cppr;
if (firmware_has_feature(FW_FEATURE_LPAR))
lpar_cppr_info(cppr);
@@ -821,8 +821,14 @@ void xics_setup_cpu(void)
void xics_teardown_cpu(void)
{
+ struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
int cpu = smp_processor_id();
+ /*
+ * we have to reset the cppr index to 0 because we're
+ * not going to return from the IPI
+ */
+ os_cppr->index = 0;
xics_set_cpu_priority(0);
/* Clear any pending IPI request */
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index a4b41dbde128..ecad10d4e928 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -77,7 +77,7 @@ static void cpm_end_irq(unsigned int irq)
}
static struct irq_chip cpm_pic = {
- .name = " CPM PIC ",
+ .name = "CPM PIC",
.mask = cpm_mask_irq,
.unmask = cpm_unmask_irq,
.eoi = cpm_end_irq,
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 1709ac5aac7c..fcea4ff825dd 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -198,7 +198,7 @@ err_sense:
}
static struct irq_chip cpm2_pic = {
- .name = " CPM2 SIU ",
+ .name = "CPM2 SIU",
.mask = cpm2_mask_irq,
.unmask = cpm2_unmask_irq,
.ack = cpm2_ack,
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index c6e11b077108..e094367d7739 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -47,7 +47,7 @@ static struct irq_chip fsl_msi_chip = {
.mask = mask_msi_irq,
.unmask = unmask_msi_irq,
.ack = fsl_msi_end_irq,
- .name = " FSL-MSI ",
+ .name = "FSL-MSI",
};
static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index 0a55db8a5a29..d32581764bde 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -135,7 +135,7 @@ static void i8259_unmask_irq(unsigned int irq_nr)
}
static struct irq_chip i8259_pic = {
- .name = " i8259 ",
+ .name = "i8259",
.mask = i8259_mask_irq,
.disable = i8259_mask_irq,
.unmask = i8259_unmask_irq,
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 28cdddd2f89e..16486716970a 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -660,7 +660,7 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
/* level interrupts and edge interrupts have different ack operations */
static struct irq_chip ipic_level_irq_chip = {
- .name = " IPIC ",
+ .name = "IPIC",
.unmask = ipic_unmask_irq,
.mask = ipic_mask_irq,
.mask_ack = ipic_mask_irq,
@@ -668,7 +668,7 @@ static struct irq_chip ipic_level_irq_chip = {
};
static struct irq_chip ipic_edge_irq_chip = {
- .name = " IPIC ",
+ .name = "IPIC",
.unmask = ipic_unmask_irq,
.mask = ipic_mask_irq,
.mask_ack = ipic_mask_irq_and_ack,
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index 69bd6f4dff83..8c27d261aba8 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -94,7 +94,7 @@ static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
}
static struct irq_chip mpc8xx_pic = {
- .name = " MPC8XX SIU ",
+ .name = "MPC8XX SIU",
.unmask = mpc8xx_unmask_irq,
.mask = mpc8xx_mask_irq,
.ack = mpc8xx_ack,
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
index 0f6ab06f8474..3b6a9a43718f 100644
--- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
+++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
@@ -60,7 +60,7 @@ static struct irq_chip mpic_pasemi_msi_chip = {
.eoi = mpic_end_irq,
.set_type = mpic_set_irq_type,
.set_affinity = mpic_set_affinity,
- .name = "PASEMI-MSI ",
+ .name = "PASEMI-MSI",
};
static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
index b6bd775d2e22..31acd3b1718b 100644
--- a/arch/powerpc/sysdev/mv64x60_dev.c
+++ b/arch/powerpc/sysdev/mv64x60_dev.c
@@ -16,6 +16,7 @@
#include <linux/mv643xx.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
#include <asm/prom.h>
@@ -189,6 +190,7 @@ static int __init mv64x60_mpsc_device_setup(struct device_node *np, int id)
pdev = platform_device_alloc(MPSC_CTLR_NAME, port_number);
if (!pdev)
return -ENOMEM;
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
err = platform_device_add_resources(pdev, r, 5);
if (err)
@@ -302,6 +304,7 @@ static int __init mv64x60_eth_device_setup(struct device_node *np, int id,
if (!pdev)
return -ENOMEM;
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
err = platform_device_add_resources(pdev, r, 1);
if (err)
goto error;
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 5f0b0368a209..d927da893ec4 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -237,7 +237,7 @@ static void qe_ic_mask_irq(unsigned int virq)
}
static struct irq_chip qe_ic_irq_chip = {
- .name = " QEIC ",
+ .name = "QEIC",
.unmask = qe_ic_unmask_irq,
.mask = qe_ic_mask_irq,
.mask_ack = qe_ic_mask_irq,
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 6f220a913e42..0038fb78f094 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -177,7 +177,7 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
}
static struct irq_chip uic_irq_chip = {
- .name = " UIC ",
+ .name = "UIC",
.unmask = uic_unmask_irq,
.mask = uic_mask_irq,
.mask_ack = uic_mask_ack_irq,