aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/arch_timer.c29
-rw-r--r--arch/arm/kernel/asm-offsets.c14
-rw-r--r--arch/arm/kernel/atags_proc.c28
-rw-r--r--arch/arm/kernel/bios32.c6
-rw-r--r--arch/arm/kernel/devtree.c7
-rw-r--r--arch/arm/kernel/early_printk.c17
-rw-r--r--arch/arm/kernel/entry-armv.S59
-rw-r--r--arch/arm/kernel/entry-common.S8
-rw-r--r--arch/arm/kernel/entry-header.S66
-rw-r--r--arch/arm/kernel/etm.c2
-rw-r--r--arch/arm/kernel/head-common.S9
-rw-r--r--arch/arm/kernel/head-nommu.S8
-rw-r--r--arch/arm/kernel/irq.c6
-rw-r--r--arch/arm/kernel/process.c121
-rw-r--r--arch/arm/kernel/return_address.c5
-rw-r--r--arch/arm/kernel/sched_clock.c15
-rw-r--r--arch/arm/kernel/setup.c17
-rw-r--r--arch/arm/kernel/smp.c44
-rw-r--r--arch/arm/kernel/smp_scu.c2
-rw-r--r--arch/arm/kernel/smp_tlb.c9
-rw-r--r--arch/arm/kernel/smp_twd.c17
-rw-r--r--arch/arm/kernel/swp_emulate.c43
-rw-r--r--arch/arm/kernel/time.c7
-rw-r--r--arch/arm/kernel/topology.c2
-rw-r--r--arch/arm/kernel/traps.c7
-rw-r--r--arch/arm/kernel/vmlinux.lds.S7
26 files changed, 290 insertions, 265 deletions
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index d957a51435d8..59dcdced6e30 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -22,9 +22,11 @@ static unsigned long arch_timer_read_counter_long(void)
return arch_timer_read_counter();
}
-static u32 arch_timer_read_counter_u32(void)
+static u32 sched_clock_mult __read_mostly;
+
+static unsigned long long notrace arch_timer_sched_clock(void)
{
- return arch_timer_read_counter();
+ return arch_timer_read_counter() * sched_clock_mult;
}
static struct delay_timer arch_delay_timer;
@@ -37,25 +39,20 @@ static void __init arch_timer_delay_timer_register(void)
register_current_timer_delay(&arch_delay_timer);
}
-int __init arch_timer_of_register(void)
+int __init arch_timer_arch_init(void)
{
- int ret;
+ u32 arch_timer_rate = arch_timer_get_rate();
- ret = arch_timer_init();
- if (ret)
- return ret;
+ if (arch_timer_rate == 0)
+ return -ENXIO;
arch_timer_delay_timer_register();
- return 0;
-}
-
-int __init arch_timer_sched_clock_init(void)
-{
- if (arch_timer_get_rate() == 0)
- return -ENXIO;
+ /* Cache the sched_clock multiplier to save a divide in the hot path. */
+ sched_clock_mult = NSEC_PER_SEC / arch_timer_rate;
+ sched_clock_func = arch_timer_sched_clock;
+ pr_info("sched_clock: ARM arch timer >56 bits at %ukHz, resolution %uns\n",
+ arch_timer_rate / 1000, sched_clock_mult);
- setup_sched_clock(arch_timer_read_counter_u32,
- 32, arch_timer_get_rate());
return 0;
}
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 923eec7105cf..ee68cce6b48e 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -149,12 +149,16 @@ int main(void)
DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL);
DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE);
DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE);
+ BLANK();
+ DEFINE(CACHE_WRITEBACK_ORDER, __CACHE_WRITEBACK_ORDER);
+ DEFINE(CACHE_WRITEBACK_GRANULE, __CACHE_WRITEBACK_GRANULE);
+ BLANK();
#ifdef CONFIG_KVM_ARM_HOST
DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
DEFINE(VCPU_MIDR, offsetof(struct kvm_vcpu, arch.midr));
DEFINE(VCPU_CP15, offsetof(struct kvm_vcpu, arch.cp15));
DEFINE(VCPU_VFP_GUEST, offsetof(struct kvm_vcpu, arch.vfp_guest));
- DEFINE(VCPU_VFP_HOST, offsetof(struct kvm_vcpu, arch.vfp_host));
+ DEFINE(VCPU_VFP_HOST, offsetof(struct kvm_vcpu, arch.host_cpu_context));
DEFINE(VCPU_REGS, offsetof(struct kvm_vcpu, arch.regs));
DEFINE(VCPU_USR_REGS, offsetof(struct kvm_vcpu, arch.regs.usr_regs));
DEFINE(VCPU_SVC_REGS, offsetof(struct kvm_vcpu, arch.regs.svc_regs));
@@ -165,10 +169,10 @@ int main(void)
DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_pc));
DEFINE(VCPU_CPSR, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_cpsr));
DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
- DEFINE(VCPU_HSR, offsetof(struct kvm_vcpu, arch.hsr));
- DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.hxfar));
- DEFINE(VCPU_HPFAR, offsetof(struct kvm_vcpu, arch.hpfar));
- DEFINE(VCPU_HYP_PC, offsetof(struct kvm_vcpu, arch.hyp_pc));
+ DEFINE(VCPU_HSR, offsetof(struct kvm_vcpu, arch.fault.hsr));
+ DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.fault.hxfar));
+ DEFINE(VCPU_HPFAR, offsetof(struct kvm_vcpu, arch.fault.hpfar));
+ DEFINE(VCPU_HYP_PC, offsetof(struct kvm_vcpu, arch.fault.hyp_pc));
#ifdef CONFIG_KVM_ARM_VGIC
DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
diff --git a/arch/arm/kernel/atags_proc.c b/arch/arm/kernel/atags_proc.c
index 42a1a1415fa6..c7ff8073416f 100644
--- a/arch/arm/kernel/atags_proc.c
+++ b/arch/arm/kernel/atags_proc.c
@@ -9,24 +9,18 @@ struct buffer {
char data[];
};
-static int
-read_buffer(char* page, char** start, off_t off, int count,
- int* eof, void* data)
+static ssize_t atags_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
- struct buffer *buffer = (struct buffer *)data;
-
- if (off >= buffer->size) {
- *eof = 1;
- return 0;
- }
-
- count = min((int) (buffer->size - off), count);
-
- memcpy(page, &buffer->data[off], count);
-
- return count;
+ struct buffer *b = PDE_DATA(file_inode(file));
+ return simple_read_from_buffer(buf, count, ppos, b->data, b->size);
}
+static const struct file_operations atags_fops = {
+ .read = atags_read,
+ .llseek = default_llseek,
+};
+
#define BOOT_PARAMS_SIZE 1536
static char __initdata atags_copy[BOOT_PARAMS_SIZE];
@@ -66,9 +60,7 @@ static int __init init_atags_procfs(void)
b->size = size;
memcpy(b->data, atags_copy, size);
- tags_entry = create_proc_read_entry("atags", 0400,
- NULL, read_buffer, b);
-
+ tags_entry = proc_create_data("atags", 0400, NULL, &atags_fops, b);
if (!tags_entry)
goto nomem;
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index a1f73b502ef0..b2ed73c45489 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -462,6 +462,7 @@ static void pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
sys->busnr = busnr;
sys->swizzle = hw->swizzle;
sys->map_irq = hw->map_irq;
+ sys->align_resource = hw->align_resource;
INIT_LIST_HEAD(&sys->resources);
if (hw->private_data)
@@ -574,6 +575,8 @@ char * __init pcibios_setup(char *str)
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
resource_size_t size, resource_size_t align)
{
+ struct pci_dev *dev = data;
+ struct pci_sys_data *sys = dev->sysdata;
resource_size_t start = res->start;
if (res->flags & IORESOURCE_IO && start & 0x300)
@@ -581,6 +584,9 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
start = (start + align - 1) & ~(align - 1);
+ if (sys->align_resource)
+ return sys->align_resource(dev, res, start, size, align);
+
return start;
}
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 70f1bdeb241b..5af04f6daa33 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -180,6 +180,13 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
unsigned long dt_root;
const char *model;
+#ifdef CONFIG_ARCH_MULTIPLATFORM
+ DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
+ MACHINE_END
+
+ mdesc_best = (struct machine_desc *)&__mach_desc_GENERIC_DT;
+#endif
+
if (!dt_phys)
return NULL;
diff --git a/arch/arm/kernel/early_printk.c b/arch/arm/kernel/early_printk.c
index 85aa2b292692..43076536965c 100644
--- a/arch/arm/kernel/early_printk.c
+++ b/arch/arm/kernel/early_printk.c
@@ -29,28 +29,17 @@ static void early_console_write(struct console *con, const char *s, unsigned n)
early_write(s, n);
}
-static struct console early_console = {
+static struct console early_console_dev = {
.name = "earlycon",
.write = early_console_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
-asmlinkage void early_printk(const char *fmt, ...)
-{
- char buf[512];
- int n;
- va_list ap;
-
- va_start(ap, fmt);
- n = vscnprintf(buf, sizeof(buf), fmt, ap);
- early_write(buf, n);
- va_end(ap);
-}
-
static int __init setup_early_printk(char *buf)
{
- register_console(&early_console);
+ early_console = &early_console_dev;
+ register_console(&early_console_dev);
return 0;
}
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0f82098c9bfe..582b405befc5 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -192,18 +192,6 @@ __dabt_svc:
svc_entry
mov r2, sp
dabt_helper
-
- @
- @ IRQs off again before pulling preserved data off the stack
- @
- disable_irq_notrace
-
-#ifdef CONFIG_TRACE_IRQFLAGS
- tst r5, #PSR_I_BIT
- bleq trace_hardirqs_on
- tst r5, #PSR_I_BIT
- blne trace_hardirqs_off
-#endif
svc_exit r5 @ return from exception
UNWIND(.fnend )
ENDPROC(__dabt_svc)
@@ -223,12 +211,7 @@ __irq_svc:
blne svc_preempt
#endif
-#ifdef CONFIG_TRACE_IRQFLAGS
- @ The parent context IRQs must have been enabled to get here in
- @ the first place, so there's no point checking the PSR I bit.
- bl trace_hardirqs_on
-#endif
- svc_exit r5 @ return from exception
+ svc_exit r5, irq = 1 @ return from exception
UNWIND(.fnend )
ENDPROC(__irq_svc)
@@ -295,22 +278,8 @@ __und_svc_fault:
mov r0, sp @ struct pt_regs *regs
bl __und_fault
- @
- @ IRQs off again before pulling preserved data off the stack
- @
__und_svc_finish:
- disable_irq_notrace
-
- @
- @ restore SPSR and restart the instruction
- @
ldr r5, [sp, #S_PSR] @ Get SVC cpsr
-#ifdef CONFIG_TRACE_IRQFLAGS
- tst r5, #PSR_I_BIT
- bleq trace_hardirqs_on
- tst r5, #PSR_I_BIT
- blne trace_hardirqs_off
-#endif
svc_exit r5 @ return from exception
UNWIND(.fnend )
ENDPROC(__und_svc)
@@ -320,18 +289,6 @@ __pabt_svc:
svc_entry
mov r2, sp @ regs
pabt_helper
-
- @
- @ IRQs off again before pulling preserved data off the stack
- @
- disable_irq_notrace
-
-#ifdef CONFIG_TRACE_IRQFLAGS
- tst r5, #PSR_I_BIT
- bleq trace_hardirqs_on
- tst r5, #PSR_I_BIT
- blne trace_hardirqs_off
-#endif
svc_exit r5 @ return from exception
UNWIND(.fnend )
ENDPROC(__pabt_svc)
@@ -396,6 +353,7 @@ ENDPROC(__pabt_svc)
#ifdef CONFIG_IRQSOFF_TRACER
bl trace_hardirqs_off
#endif
+ ct_user_exit save = 0
.endm
.macro kuser_cmpxchg_check
@@ -562,21 +520,21 @@ ENDPROC(__und_usr)
@ Fall-through from Thumb-2 __und_usr
@
#ifdef CONFIG_NEON
+ get_thread_info r10 @ get current thread
adr r6, .LCneon_thumb_opcodes
b 2f
#endif
call_fpe:
+ get_thread_info r10 @ get current thread
#ifdef CONFIG_NEON
adr r6, .LCneon_arm_opcodes
-2:
- ldr r7, [r6], #4 @ mask value
- cmp r7, #0 @ end mask?
- beq 1f
- and r8, r0, r7
+2: ldr r5, [r6], #4 @ mask value
ldr r7, [r6], #4 @ opcode bits matching in mask
+ cmp r5, #0 @ end mask?
+ beq 1f
+ and r8, r0, r5
cmp r8, r7 @ NEON instruction?
bne 2b
- get_thread_info r10
mov r7, #1
strb r7, [r10, #TI_USED_CP + 10] @ mark CP#10 as used
strb r7, [r10, #TI_USED_CP + 11] @ mark CP#11 as used
@@ -586,7 +544,6 @@ call_fpe:
tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27
tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2
moveq pc, lr
- get_thread_info r10 @ get current thread
and r8, r0, #0x00000f00 @ mask out CP number
THUMB( lsr r8, r8, #8 )
mov r7, #1
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index fefd7f971437..bc5bc0a97131 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -35,12 +35,11 @@ ret_fast_syscall:
ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK
bne fast_work_pending
-#if defined(CONFIG_IRQSOFF_TRACER)
asm_trace_hardirqs_on
-#endif
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
+ ct_user_enter
restore_user_regs fast = 1, offset = S_OFF
UNWIND(.fnend )
@@ -71,11 +70,11 @@ ENTRY(ret_to_user_from_irq)
tst r1, #_TIF_WORK_MASK
bne work_pending
no_work_pending:
-#if defined(CONFIG_IRQSOFF_TRACER)
asm_trace_hardirqs_on
-#endif
+
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
+ ct_user_enter save = 0
restore_user_regs fast = 0, offset = 0
ENDPROC(ret_to_user_from_irq)
@@ -406,6 +405,7 @@ ENTRY(vector_swi)
mcr p15, 0, ip, c1, c0 @ update control register
#endif
enable_irq
+ ct_user_exit
get_thread_info tsk
adr tbl, sys_call_table @ load syscall table pointer
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 9a8531eadd3d..160f3376ba6d 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -74,7 +74,24 @@
.endm
#ifndef CONFIG_THUMB2_KERNEL
- .macro svc_exit, rpsr
+ .macro svc_exit, rpsr, irq = 0
+ .if \irq != 0
+ @ IRQs already off
+#ifdef CONFIG_TRACE_IRQFLAGS
+ @ The parent context IRQs must have been enabled to get here in
+ @ the first place, so there's no point checking the PSR I bit.
+ bl trace_hardirqs_on
+#endif
+ .else
+ @ IRQs off again before pulling preserved data off the stack
+ disable_irq_notrace
+#ifdef CONFIG_TRACE_IRQFLAGS
+ tst \rpsr, #PSR_I_BIT
+ bleq trace_hardirqs_on
+ tst \rpsr, #PSR_I_BIT
+ blne trace_hardirqs_off
+#endif
+ .endif
msr spsr_cxsf, \rpsr
#if defined(CONFIG_CPU_V6)
ldr r0, [sp]
@@ -120,7 +137,24 @@
mov pc, \reg
.endm
#else /* CONFIG_THUMB2_KERNEL */
- .macro svc_exit, rpsr
+ .macro svc_exit, rpsr, irq = 0
+ .if \irq != 0
+ @ IRQs already off
+#ifdef CONFIG_TRACE_IRQFLAGS
+ @ The parent context IRQs must have been enabled to get here in
+ @ the first place, so there's no point checking the PSR I bit.
+ bl trace_hardirqs_on
+#endif
+ .else
+ @ IRQs off again before pulling preserved data off the stack
+ disable_irq_notrace
+#ifdef CONFIG_TRACE_IRQFLAGS
+ tst \rpsr, #PSR_I_BIT
+ bleq trace_hardirqs_on
+ tst \rpsr, #PSR_I_BIT
+ blne trace_hardirqs_off
+#endif
+ .endif
ldr lr, [sp, #S_SP] @ top of the stack
ldrd r0, r1, [sp, #S_LR] @ calling lr and pc
clrex @ clear the exclusive monitor
@@ -164,6 +198,34 @@
#endif /* !CONFIG_THUMB2_KERNEL */
/*
+ * Context tracking subsystem. Used to instrument transitions
+ * between user and kernel mode.
+ */
+ .macro ct_user_exit, save = 1
+#ifdef CONFIG_CONTEXT_TRACKING
+ .if \save
+ stmdb sp!, {r0-r3, ip, lr}
+ bl user_exit
+ ldmia sp!, {r0-r3, ip, lr}
+ .else
+ bl user_exit
+ .endif
+#endif
+ .endm
+
+ .macro ct_user_enter, save = 1
+#ifdef CONFIG_CONTEXT_TRACKING
+ .if \save
+ stmdb sp!, {r0-r3, ip, lr}
+ bl user_enter
+ ldmia sp!, {r0-r3, ip, lr}
+ .else
+ bl user_enter
+ .endif
+#endif
+ .endm
+
+/*
* These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - r0 to r6.
*
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index 9b6de8c988f3..8ff0ecdc637f 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -254,7 +254,7 @@ static void sysrq_etm_dump(int key)
static struct sysrq_key_op sysrq_etm_op = {
.handler = sysrq_etm_dump,
- .help_msg = "ETM buffer dump",
+ .help_msg = "etm-buffer-dump(v)",
.action_msg = "etm",
};
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 854bd22380d3..5b391a689b47 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -98,8 +98,9 @@ __mmap_switched:
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
str r2, [r6] @ Save atags pointer
- bic r4, r0, #CR_A @ Clear 'A' bit
- stmia r7, {r0, r4} @ Save control register values
+ cmp r7, #0
+ bicne r4, r0, #CR_A @ Clear 'A' bit
+ stmneia r7, {r0, r4} @ Save control register values
b start_kernel
ENDPROC(__mmap_switched)
@@ -113,7 +114,11 @@ __mmap_switched_data:
.long processor_id @ r4
.long __machine_arch_type @ r5
.long __atags_pointer @ r6
+#ifdef CONFIG_CPU_CP15
.long cr_alignment @ r7
+#else
+ .long 0 @ r7
+#endif
.long init_thread_union + THREAD_START_SP @ sp
.size __mmap_switched_data, . - __mmap_switched_data
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 2c228a07e58c..6a2e09c952c7 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -32,15 +32,21 @@
* numbers for r1.
*
*/
- .arm
__HEAD
+
+#ifdef CONFIG_CPU_THUMBONLY
+ .thumb
+ENTRY(stext)
+#else
+ .arm
ENTRY(stext)
THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
+#endif
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 8e4ef4c83a74..9723d17b8f38 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -26,6 +26,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/init.h>
@@ -114,7 +115,10 @@ EXPORT_SYMBOL_GPL(set_irq_flags);
void __init init_IRQ(void)
{
- machine_desc->init_irq();
+ if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
+ irqchip_init();
+ else
+ machine_desc->init_irq();
}
#ifdef CONFIG_MULTI_IRQ_HANDLER
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 047d3e40e470..f21970316836 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -57,38 +57,6 @@ static const char *isa_modes[] = {
"ARM" , "Thumb" , "Jazelle", "ThumbEE"
};
-static volatile int hlt_counter;
-
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
- hlt_counter--;
- BUG_ON(hlt_counter < 0);
-}
-
-EXPORT_SYMBOL(enable_hlt);
-
-static int __init nohlt_setup(char *__unused)
-{
- hlt_counter = 1;
- return 1;
-}
-
-static int __init hlt_setup(char *__unused)
-{
- hlt_counter = 0;
- return 1;
-}
-
-__setup("nohlt", nohlt_setup);
-__setup("hlt", hlt_setup);
-
extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
typedef void (*phys_reset_t)(unsigned long);
@@ -172,54 +140,38 @@ static void default_idle(void)
local_irq_enable();
}
-/*
- * The idle thread.
- * We always respect 'hlt_counter' to prevent low power idle.
- */
-void cpu_idle(void)
+void arch_cpu_idle_prepare(void)
{
local_fiq_enable();
+}
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- ledtrig_cpu(CPU_LED_IDLE_START);
- while (!need_resched()) {
-#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
+void arch_cpu_idle_enter(void)
+{
+ ledtrig_cpu(CPU_LED_IDLE_START);
+#ifdef CONFIG_PL310_ERRATA_769419
+ wmb();
#endif
+}
- /*
- * We need to disable interrupts here
- * to ensure we don't miss a wakeup call.
- */
- local_irq_disable();
-#ifdef CONFIG_PL310_ERRATA_769419
- wmb();
+void arch_cpu_idle_exit(void)
+{
+ ledtrig_cpu(CPU_LED_IDLE_END);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void arch_cpu_idle_dead(void)
+{
+ cpu_die();
+}
#endif
- if (hlt_counter) {
- local_irq_enable();
- cpu_relax();
- } else if (!need_resched()) {
- stop_critical_timings();
- if (cpuidle_idle_call())
- default_idle();
- start_critical_timings();
- /*
- * default_idle functions must always
- * return with IRQs enabled.
- */
- WARN_ON(irqs_disabled());
- } else
- local_irq_enable();
- }
- ledtrig_cpu(CPU_LED_IDLE_END);
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+
+/*
+ * Called from the core idle loop.
+ */
+void arch_cpu_idle(void)
+{
+ if (cpuidle_idle_call())
+ default_idle();
}
static char reboot_mode = 'h';
@@ -273,11 +225,8 @@ void __show_regs(struct pt_regs *regs)
unsigned long flags;
char buf[64];
- printk("CPU: %d %s (%s %.*s)\n",
- raw_smp_processor_id(), print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
+ show_regs_print_info(KERN_DEFAULT);
+
print_symbol("PC is at %s\n", instruction_pointer(regs));
print_symbol("LR is at %s\n", regs->ARM_lr);
printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n"
@@ -332,7 +281,6 @@ void __show_regs(struct pt_regs *regs)
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm);
__show_regs(regs);
dump_stack();
}
@@ -459,15 +407,16 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
* atomic helpers and the signal restart code. Insert it into the
* gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
*/
-static struct vm_area_struct gate_vma;
+static struct vm_area_struct gate_vma = {
+ .vm_start = 0xffff0000,
+ .vm_end = 0xffff0000 + PAGE_SIZE,
+ .vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC,
+ .vm_mm = &init_mm,
+};
static int __init gate_vma_init(void)
{
- gate_vma.vm_start = 0xffff0000;
- gate_vma.vm_end = 0xffff0000 + PAGE_SIZE;
- gate_vma.vm_page_prot = PAGE_READONLY_EXEC;
- gate_vma.vm_flags = VM_READ | VM_EXEC |
- VM_MAYREAD | VM_MAYEXEC;
+ gate_vma.vm_page_prot = PAGE_READONLY_EXEC;
return 0;
}
arch_initcall(gate_vma_init);
diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c
index 8085417555dd..fafedd86885d 100644
--- a/arch/arm/kernel/return_address.c
+++ b/arch/arm/kernel/return_address.c
@@ -26,7 +26,7 @@ static int save_return_addr(struct stackframe *frame, void *d)
struct return_address_data *data = d;
if (!data->level) {
- data->addr = (void *)frame->lr;
+ data->addr = (void *)frame->pc;
return 1;
} else {
@@ -41,7 +41,8 @@ void *return_address(unsigned int level)
struct stackframe frame;
register unsigned long current_sp asm ("sp");
- data.level = level + 1;
+ data.level = level + 2;
+ data.addr = NULL;
frame.fp = (unsigned long)__builtin_frame_address(0);
frame.sp = current_sp;
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index 59d2adb764a9..e8edcaa0e432 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -20,6 +20,7 @@ struct clock_data {
u64 epoch_ns;
u32 epoch_cyc;
u32 epoch_cyc_copy;
+ unsigned long rate;
u32 mult;
u32 shift;
bool suspended;
@@ -113,11 +114,14 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
u64 res, wrap;
char r_unit;
+ if (cd.rate > rate)
+ return;
+
BUG_ON(bits > 32);
WARN_ON(!irqs_disabled());
- WARN_ON(read_sched_clock != jiffy_sched_clock_read);
read_sched_clock = read;
sched_clock_mask = (1 << bits) - 1;
+ cd.rate = rate;
/* calculate the mult/shift to convert counter ticks to ns. */
clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 0);
@@ -161,12 +165,19 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
pr_debug("Registered %pF as sched_clock source\n", read);
}
-unsigned long long notrace sched_clock(void)
+static unsigned long long notrace sched_clock_32(void)
{
u32 cyc = read_sched_clock();
return cyc_to_sched_clock(cyc, sched_clock_mask);
}
+unsigned long long __read_mostly (*sched_clock_func)(void) = sched_clock_32;
+
+unsigned long long notrace sched_clock(void)
+{
+ return sched_clock_func();
+}
+
void __init sched_clock_postinit(void)
{
/*
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 234e339196c0..1522c7ae31b0 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -18,6 +18,7 @@
#include <linux/bootmem.h>
#include <linux/seq_file.h>
#include <linux/screen_info.h>
+#include <linux/of_platform.h>
#include <linux/init.h>
#include <linux/kexec.h>
#include <linux/of_fdt.h>
@@ -290,10 +291,10 @@ static int cpu_has_aliasing_icache(unsigned int arch)
static void __init cacheid_init(void)
{
- unsigned int cachetype = read_cpuid_cachetype();
unsigned int arch = cpu_architecture();
if (arch >= CPU_ARCH_ARMv6) {
+ unsigned int cachetype = read_cpuid_cachetype();
if ((cachetype & (7 << 29)) == 4 << 29) {
/* ARMv7 register format */
arch = CPU_ARCH_ARMv7;
@@ -389,7 +390,7 @@ static void __init feat_v6_fixup(void)
*
* cpu_init sets up the per-CPU stacks.
*/
-void cpu_init(void)
+void notrace cpu_init(void)
{
unsigned int cpu = smp_processor_id();
struct stack *stk = &stacks[cpu];
@@ -659,9 +660,19 @@ struct screen_info screen_info = {
static int __init customize_machine(void)
{
- /* customizes platform devices, or adds new ones */
+ /*
+ * customizes platform devices, or adds new ones
+ * On DT based machines, we fall back to populating the
+ * machine from the device tree, if no callback is provided,
+ * otherwise we would always need an init_machine callback.
+ */
if (machine_desc->init_machine)
machine_desc->init_machine();
+#ifdef CONFIG_OF
+ else
+ of_platform_populate(NULL, of_default_bus_match_table,
+ NULL, NULL);
+#endif
return 0;
}
arch_initcall(customize_machine);
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 1f2ccccaf009..47ab90563bf4 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -211,6 +211,13 @@ void __cpuinit __cpu_die(unsigned int cpu)
}
printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+ /*
+ * platform_cpu_kill() is generally expected to do the powering off
+ * and/or cutting of clocks to the dying CPU. Optionally, this may
+ * be done by the CPU which is dying in preference to supporting
+ * this call, but that means there is _no_ synchronisation between
+ * the requesting CPU and the dying CPU actually losing power.
+ */
if (!platform_cpu_kill(cpu))
printk("CPU%u: unable to kill\n", cpu);
}
@@ -230,14 +237,41 @@ void __ref cpu_die(void)
idle_task_exit();
local_irq_disable();
- mb();
- /* Tell __cpu_die() that this CPU is now safe to dispose of */
+ /*
+ * Flush the data out of the L1 cache for this CPU. This must be
+ * before the completion to ensure that data is safely written out
+ * before platform_cpu_kill() gets called - which may disable
+ * *this* CPU and power down its cache.
+ */
+ flush_cache_louis();
+
+ /*
+ * Tell __cpu_die() that this CPU is now safe to dispose of. Once
+ * this returns, power and/or clocks can be removed at any point
+ * from this CPU and its cache by platform_cpu_kill().
+ */
RCU_NONIDLE(complete(&cpu_died));
/*
- * actual CPU shutdown procedure is at least platform (if not
- * CPU) specific.
+ * Ensure that the cache lines associated with that completion are
+ * written out. This covers the case where _this_ CPU is doing the
+ * powering down, to ensure that the completion is visible to the
+ * CPU waiting for this one.
+ */
+ flush_cache_louis();
+
+ /*
+ * The actual CPU shutdown procedure is at least platform (if not
+ * CPU) specific. This may remove power, or it may simply spin.
+ *
+ * Platforms are generally expected *NOT* to return from this call,
+ * although there are some which do because they have no way to
+ * power down the CPU. These platforms are the _only_ reason we
+ * have a return path which uses the fragment of assembly below.
+ *
+ * The return path should not be used for platforms which can
+ * power off the CPU.
*/
if (smp_ops.cpu_die)
smp_ops.cpu_die(cpu);
@@ -336,7 +370,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
/*
* OK, it's off to the idle thread for us
*/
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
void __init smp_cpus_done(unsigned int max_cpus)
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 45eac87ed66a..5bc1a63284e3 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -41,7 +41,7 @@ void scu_enable(void __iomem *scu_base)
#ifdef CONFIG_ARM_ERRATA_764369
/* Cortex-A9 only */
- if ((read_cpuid(CPUID_ID) & 0xff0ffff0) == 0x410fc090) {
+ if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090) {
scu_ctrl = __raw_readl(scu_base + 0x30);
if (!(scu_ctrl & 1))
__raw_writel(scu_ctrl | 0x1, scu_base + 0x30);
diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c
index e82e1d248772..9a52a07aa40e 100644
--- a/arch/arm/kernel/smp_tlb.c
+++ b/arch/arm/kernel/smp_tlb.c
@@ -98,21 +98,21 @@ static void broadcast_tlb_a15_erratum(void)
return;
dummy_flush_tlb_a15_erratum();
- smp_call_function_many(cpu_online_mask, ipi_flush_tlb_a15_erratum,
- NULL, 1);
+ smp_call_function(ipi_flush_tlb_a15_erratum, NULL, 1);
}
static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
{
- int cpu;
+ int cpu, this_cpu;
cpumask_t mask = { CPU_BITS_NONE };
if (!erratum_a15_798181())
return;
dummy_flush_tlb_a15_erratum();
+ this_cpu = get_cpu();
for_each_online_cpu(cpu) {
- if (cpu == smp_processor_id())
+ if (cpu == this_cpu)
continue;
/*
* We only need to send an IPI if the other CPUs are running
@@ -127,6 +127,7 @@ static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
cpumask_set_cpu(cpu, &mask);
}
smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1);
+ put_cpu();
}
void flush_tlb_all(void)
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 3f2565037480..90525d9d290b 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -362,25 +362,13 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
}
#ifdef CONFIG_OF
-const static struct of_device_id twd_of_match[] __initconst = {
- { .compatible = "arm,cortex-a9-twd-timer", },
- { .compatible = "arm,cortex-a5-twd-timer", },
- { .compatible = "arm,arm11mp-twd-timer", },
- { },
-};
-
-void __init twd_local_timer_of_register(void)
+static void __init twd_local_timer_of_register(struct device_node *np)
{
- struct device_node *np;
int err;
if (!is_smp() || !setup_max_cpus)
return;
- np = of_find_matching_node(NULL, twd_of_match);
- if (!np)
- return;
-
twd_ppi = irq_of_parse_and_map(np, 0);
if (!twd_ppi) {
err = -EINVAL;
@@ -398,4 +386,7 @@ void __init twd_local_timer_of_register(void)
out:
WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
}
+CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register);
+CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register);
+CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register);
#endif
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index ab1017bd1667..b1b89882b113 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/perf_event.h>
@@ -79,27 +80,27 @@ static unsigned long abtcounter;
static pid_t previous_pid;
#ifdef CONFIG_PROC_FS
-static int proc_read_status(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int proc_status_show(struct seq_file *m, void *v)
{
- char *p = page;
- int len;
-
- p += sprintf(p, "Emulated SWP:\t\t%lu\n", swpcounter);
- p += sprintf(p, "Emulated SWPB:\t\t%lu\n", swpbcounter);
- p += sprintf(p, "Aborted SWP{B}:\t\t%lu\n", abtcounter);
+ seq_printf(m, "Emulated SWP:\t\t%lu\n", swpcounter);
+ seq_printf(m, "Emulated SWPB:\t\t%lu\n", swpbcounter);
+ seq_printf(m, "Aborted SWP{B}:\t\t%lu\n", abtcounter);
if (previous_pid != 0)
- p += sprintf(p, "Last process:\t\t%d\n", previous_pid);
-
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
+ seq_printf(m, "Last process:\t\t%d\n", previous_pid);
+ return 0;
+}
- return len;
+static int proc_status_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_status_show, PDE_DATA(inode));
}
+
+static const struct file_operations proc_status_fops = {
+ .open = proc_status_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
/*
@@ -266,14 +267,8 @@ static struct undef_hook swp_hook = {
static int __init swp_emulation_init(void)
{
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *res;
-
- res = create_proc_entry("cpu/swp_emulation", S_IRUGO, NULL);
-
- if (!res)
+ if (!proc_create("cpu/swp_emulation", S_IRUGO, NULL, &proc_status_fops))
return -ENOMEM;
-
- res->read_proc = proc_read_status;
#endif /* CONFIG_PROC_FS */
printk(KERN_NOTICE "Registering SWP/SWPB emulation handler\n");
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 955d92d265e5..abff4e9aaee0 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/profile.h>
#include <linux/timer.h>
+#include <linux/clocksource.h>
#include <linux/irq.h>
#include <asm/thread_info.h>
@@ -115,6 +116,10 @@ int __init register_persistent_clock(clock_access_fn read_boot,
void __init time_init(void)
{
- machine_desc->init_time();
+ if (machine_desc->init_time)
+ machine_desc->init_time();
+ else
+ clocksource_of_init();
+
sched_clock_postinit();
}
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 79282ebcd939..f10316b4ecdc 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -100,7 +100,7 @@ static void __init parse_dt_topology(void)
int alloc_size, cpu = 0;
alloc_size = nr_cpu_ids * sizeof(struct cpu_capacity);
- cpu_capacity = (struct cpu_capacity *)kzalloc(alloc_size, GFP_NOWAIT);
+ cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT);
while ((cn = of_find_node_by_type(cn, "cpu"))) {
const u32 *rate, *reg;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 1c089119b2d7..18b32e8e4497 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -204,13 +204,6 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
}
#endif
-void dump_stack(void)
-{
- dump_backtrace(NULL, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
dump_backtrace(NULL, tsk);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index b571484e9f03..a871b8e00fca 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -20,7 +20,7 @@
VMLINUX_SYMBOL(__idmap_text_start) = .; \
*(.idmap.text) \
VMLINUX_SYMBOL(__idmap_text_end) = .; \
- ALIGN_FUNCTION(); \
+ . = ALIGN(32); \
VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \
*(.hyp.idmap.text) \
VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;
@@ -315,3 +315,8 @@ SECTIONS
*/
ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
+/*
+ * The HYP init code can't be more than a page long.
+ * The above comment applies as well.
+ */
+ASSERT(((__hyp_idmap_text_end - __hyp_idmap_text_start) <= PAGE_SIZE), "HYP init code too big")