aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/devtree.c12
-rw-r--r--arch/arm/kernel/entry-armv.S33
-rw-r--r--arch/arm/kernel/hw_breakpoint.c1
-rw-r--r--arch/arm/kernel/kgdb.c31
-rw-r--r--arch/arm/kernel/smp.c12
-rw-r--r--arch/arm/kernel/smp_twd.c11
-rw-r--r--arch/arm/kernel/traps.c52
7 files changed, 40 insertions, 112 deletions
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 11c54de9f8cf..65addcbf5b30 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -101,6 +101,7 @@ void __init arm_dt_init_cpu_maps(void)
if (of_property_read_u32(cpu, "reg", &hwid)) {
pr_debug(" * %s missing reg property\n",
cpu->full_name);
+ of_node_put(cpu);
return;
}
@@ -108,8 +109,10 @@ void __init arm_dt_init_cpu_maps(void)
* 8 MSBs must be set to 0 in the DT since the reg property
* defines the MPIDR[23:0].
*/
- if (hwid & ~MPIDR_HWID_BITMASK)
+ if (hwid & ~MPIDR_HWID_BITMASK) {
+ of_node_put(cpu);
return;
+ }
/*
* Duplicate MPIDRs are a recipe for disaster.
@@ -119,9 +122,11 @@ void __init arm_dt_init_cpu_maps(void)
* to avoid matching valid MPIDR[23:0] values.
*/
for (j = 0; j < cpuidx; j++)
- if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg "
- "properties in the DT\n"))
+ if (WARN(tmp_map[j] == hwid,
+ "Duplicate /cpu reg properties in the DT\n")) {
+ of_node_put(cpu);
return;
+ }
/*
* Build a stashed array of MPIDR values. Numbering scheme
@@ -143,6 +148,7 @@ void __init arm_dt_init_cpu_maps(void)
"max cores %u, capping them\n",
cpuidx, nr_cpu_ids)) {
cpuidx = nr_cpu_ids;
+ of_node_put(cpu);
break;
}
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 3e1c26eb32b4..3ce377f7251f 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -427,8 +427,7 @@ ENDPROC(__fiq_abt)
.endm
.macro kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
- !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS)
#ifndef CONFIG_MMU
#warning "NPTL on non MMU needs fixing"
#else
@@ -859,20 +858,7 @@ __kuser_helper_start:
__kuser_cmpxchg64: @ 0xffff0f60
-#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-
- /*
- * Poor you. No fast solution possible...
- * The kernel itself must perform the operation.
- * A special ghost syscall is used for that (see traps.c).
- */
- stmfd sp!, {r7, lr}
- ldr r7, 1f @ it's 20 bits
- swi __ARM_NR_cmpxchg64
- ldmfd sp!, {r7, pc}
-1: .word __ARM_NR_cmpxchg64
-
-#elif defined(CONFIG_CPU_32v6K)
+#if defined(CONFIG_CPU_32v6K)
stmfd sp!, {r4, r5, r6, r7}
ldrd r4, r5, [r0] @ load old val
@@ -948,20 +934,7 @@ __kuser_memory_barrier: @ 0xffff0fa0
__kuser_cmpxchg: @ 0xffff0fc0
-#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-
- /*
- * Poor you. No fast solution possible...
- * The kernel itself must perform the operation.
- * A special ghost syscall is used for that (see traps.c).
- */
- stmfd sp!, {r7, lr}
- ldr r7, 1f @ it's 20 bits
- swi __ARM_NR_cmpxchg
- ldmfd sp!, {r7, pc}
-1: .word __ARM_NR_cmpxchg
-
-#elif __LINUX_ARM_ARCH__ < 6
+#if __LINUX_ARM_ARCH__ < 6
#ifdef CONFIG_MMU
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index dc7d0a95bd36..6284779d64ee 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -35,7 +35,6 @@
#include <asm/cputype.h>
#include <asm/current.h>
#include <asm/hw_breakpoint.h>
-#include <asm/kdebug.h>
#include <asm/traps.h>
/* Breakpoint currently in use for each BRP. */
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index fd9eefce0a7b..9232caee7060 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -74,7 +74,7 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
void
sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
{
- struct pt_regs *thread_regs;
+ struct thread_info *ti;
int regno;
/* Just making sure... */
@@ -86,24 +86,17 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
gdb_regs[regno] = 0;
/* Otherwise, we have only some registers from switch_to() */
- thread_regs = task_pt_regs(task);
- gdb_regs[_R0] = thread_regs->ARM_r0;
- gdb_regs[_R1] = thread_regs->ARM_r1;
- gdb_regs[_R2] = thread_regs->ARM_r2;
- gdb_regs[_R3] = thread_regs->ARM_r3;
- gdb_regs[_R4] = thread_regs->ARM_r4;
- gdb_regs[_R5] = thread_regs->ARM_r5;
- gdb_regs[_R6] = thread_regs->ARM_r6;
- gdb_regs[_R7] = thread_regs->ARM_r7;
- gdb_regs[_R8] = thread_regs->ARM_r8;
- gdb_regs[_R9] = thread_regs->ARM_r9;
- gdb_regs[_R10] = thread_regs->ARM_r10;
- gdb_regs[_FP] = thread_regs->ARM_fp;
- gdb_regs[_IP] = thread_regs->ARM_ip;
- gdb_regs[_SPT] = thread_regs->ARM_sp;
- gdb_regs[_LR] = thread_regs->ARM_lr;
- gdb_regs[_PC] = thread_regs->ARM_pc;
- gdb_regs[_CPSR] = thread_regs->ARM_cpsr;
+ ti = task_thread_info(task);
+ gdb_regs[_R4] = ti->cpu_context.r4;
+ gdb_regs[_R5] = ti->cpu_context.r5;
+ gdb_regs[_R6] = ti->cpu_context.r6;
+ gdb_regs[_R7] = ti->cpu_context.r7;
+ gdb_regs[_R8] = ti->cpu_context.r8;
+ gdb_regs[_R9] = ti->cpu_context.r9;
+ gdb_regs[_R10] = ti->cpu_context.sl;
+ gdb_regs[_FP] = ti->cpu_context.fp;
+ gdb_regs[_SPT] = ti->cpu_context.sp;
+ gdb_regs[_PC] = ti->cpu_context.pc;
}
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 48185a773852..b26361355dae 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -80,7 +80,7 @@ static DECLARE_COMPLETION(cpu_running);
static struct smp_operations smp_ops;
-void __init smp_set_ops(struct smp_operations *ops)
+void __init smp_set_ops(const struct smp_operations *ops)
{
if (ops)
smp_ops = *ops;
@@ -400,6 +400,7 @@ asmlinkage void secondary_start_kernel(void)
local_irq_enable();
local_fiq_enable();
+ local_abt_enable();
/*
* OK, it's off to the idle thread for us
@@ -748,6 +749,15 @@ core_initcall(register_cpufreq_notifier);
static void raise_nmi(cpumask_t *mask)
{
+ /*
+ * Generate the backtrace directly if we are running in a calling
+ * context that is not preemptible by the backtrace IPI. Note
+ * that nmi_cpu_backtrace() automatically removes the current cpu
+ * from mask.
+ */
+ if (cpumask_test_cpu(smp_processor_id(), mask) && irqs_disabled())
+ nmi_cpu_backtrace(NULL);
+
smp_cross_call(mask, IPI_CPU_BACKTRACE);
}
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index e9035cda1485..1bfa7a7f5533 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -23,7 +23,6 @@
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <asm/smp_plat.h>
#include <asm/smp_twd.h>
/* set up by the platform code */
@@ -34,6 +33,8 @@ static unsigned long twd_timer_rate;
static DEFINE_PER_CPU(bool, percpu_setup_called);
static struct clock_event_device __percpu *twd_evt;
+static unsigned int twd_features =
+ CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
static int twd_ppi;
static int twd_shutdown(struct clock_event_device *clk)
@@ -294,8 +295,7 @@ static void twd_timer_setup(void)
writel_relaxed(0, twd_base + TWD_TIMER_CONTROL);
clk->name = "local_timer";
- clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_C3STOP;
+ clk->features = twd_features;
clk->rating = 350;
clk->set_state_shutdown = twd_shutdown;
clk->set_state_periodic = twd_set_periodic;
@@ -350,6 +350,8 @@ static int __init twd_local_timer_common_register(struct device_node *np)
goto out_irq;
twd_get_clock(np);
+ if (!of_property_read_bool(np, "always-on"))
+ twd_features |= CLOCK_EVT_FEAT_C3STOP;
/*
* Immediately configure the timer on the boot CPU, unless we need
@@ -392,9 +394,6 @@ static void __init twd_local_timer_of_register(struct device_node *np)
{
int err;
- if (!is_smp() || !setup_max_cpus)
- return;
-
twd_ppi = irq_of_parse_and_map(np, 0);
if (!twd_ppi) {
err = -EINVAL;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 969f9d9e665f..bc698383e822 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -625,58 +625,6 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
set_tls(regs->ARM_r0);
return 0;
-#ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG
- /*
- * Atomically store r1 in *r2 if *r2 is equal to r0 for user space.
- * Return zero in r0 if *MEM was changed or non-zero if no exchange
- * happened. Also set the user C flag accordingly.
- * If access permissions have to be fixed up then non-zero is
- * returned and the operation has to be re-attempted.
- *
- * *NOTE*: This is a ghost syscall private to the kernel. Only the
- * __kuser_cmpxchg code in entry-armv.S should be aware of its
- * existence. Don't ever use this from user code.
- */
- case NR(cmpxchg):
- for (;;) {
- extern void do_DataAbort(unsigned long addr, unsigned int fsr,
- struct pt_regs *regs);
- unsigned long val;
- unsigned long addr = regs->ARM_r2;
- struct mm_struct *mm = current->mm;
- pgd_t *pgd; pmd_t *pmd; pte_t *pte;
- spinlock_t *ptl;
-
- regs->ARM_cpsr &= ~PSR_C_BIT;
- down_read(&mm->mmap_sem);
- pgd = pgd_offset(mm, addr);
- if (!pgd_present(*pgd))
- goto bad_access;
- pmd = pmd_offset(pgd, addr);
- if (!pmd_present(*pmd))
- goto bad_access;
- pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
- if (!pte_present(*pte) || !pte_write(*pte) || !pte_dirty(*pte)) {
- pte_unmap_unlock(pte, ptl);
- goto bad_access;
- }
- val = *(unsigned long *)addr;
- val -= regs->ARM_r0;
- if (val == 0) {
- *(unsigned long *)addr = regs->ARM_r1;
- regs->ARM_cpsr |= PSR_C_BIT;
- }
- pte_unmap_unlock(pte, ptl);
- up_read(&mm->mmap_sem);
- return val;
-
- bad_access:
- up_read(&mm->mmap_sem);
- /* simulate a write access fault */
- do_DataAbort(addr, 15 + (1 << 11), regs);
- }
-#endif
-
default:
/* Calls 9f00xx..9f07ff are defined to return -ENOSYS
if not implemented, rather than raising SIGILL. This