Merge branches 'atags', 'cache-l2x0', 'clkdev', 'fixes', 'integrator', 'misc', 'opcodes' and 'syscall' into for-linus
This commit is contained in:
@@ -19,7 +19,9 @@ obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \
|
||||
process.o ptrace.o return_address.o sched_clock.o \
|
||||
setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
|
||||
|
||||
obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
|
||||
obj-$(CONFIG_ATAGS) += atags_parse.o
|
||||
obj-$(CONFIG_ATAGS_PROC) += atags_proc.o
|
||||
obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
|
||||
|
||||
obj-$(CONFIG_LEDS) += leds.o
|
||||
obj-$(CONFIG_OC_ETM) += etm.o
|
||||
@@ -52,7 +54,6 @@ test-kprobes-objs += kprobes-test-thumb.o
|
||||
else
|
||||
test-kprobes-objs += kprobes-test-arm.o
|
||||
endif
|
||||
obj-$(CONFIG_ATAGS_PROC) += atags.o
|
||||
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
|
||||
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
|
@@ -3,3 +3,17 @@ extern void save_atags(struct tag *tags);
|
||||
#else
|
||||
static inline void save_atags(struct tag *tags) { }
|
||||
#endif
|
||||
|
||||
void convert_to_tag_list(struct tag *tags);
|
||||
|
||||
#ifdef CONFIG_ATAGS
|
||||
struct machine_desc *setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr);
|
||||
#else
|
||||
static inline struct machine_desc *
|
||||
setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
|
||||
{
|
||||
early_print("no ATAGS support: can't continue\n");
|
||||
while (true);
|
||||
unreachable();
|
||||
}
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/arch/arm/kernel/compat.c
|
||||
* linux/arch/arm/kernel/atags_compat.c
|
||||
*
|
||||
* Copyright (C) 2001 Russell King
|
||||
*
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "atags.h"
|
||||
|
||||
/*
|
||||
* Usage:
|
238
arch/arm/kernel/atags_parse.c
Normal file
238
arch/arm/kernel/atags_parse.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Tag parsing.
|
||||
*
|
||||
* Copyright (C) 1995-2001 Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the traditional way of passing data to the kernel at boot time. Rather
|
||||
* than passing a fixed inflexible structure to the kernel, we pass a list
|
||||
* of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
|
||||
* tag for the list to be recognised (to distinguish the tagged list from
|
||||
* a param_struct). The list is terminated with a zero-length tag (this tag
|
||||
* is not parsed in any way).
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/root_dev.h>
|
||||
#include <linux/screen_info.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/system_info.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "atags.h"
|
||||
|
||||
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
|
||||
|
||||
#ifndef MEM_SIZE
|
||||
#define MEM_SIZE (16*1024*1024)
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
struct tag_header hdr1;
|
||||
struct tag_core core;
|
||||
struct tag_header hdr2;
|
||||
struct tag_mem32 mem;
|
||||
struct tag_header hdr3;
|
||||
} default_tags __initdata = {
|
||||
{ tag_size(tag_core), ATAG_CORE },
|
||||
{ 1, PAGE_SIZE, 0xff },
|
||||
{ tag_size(tag_mem32), ATAG_MEM },
|
||||
{ MEM_SIZE },
|
||||
{ 0, ATAG_NONE }
|
||||
};
|
||||
|
||||
static int __init parse_tag_core(const struct tag *tag)
|
||||
{
|
||||
if (tag->hdr.size > 2) {
|
||||
if ((tag->u.core.flags & 1) == 0)
|
||||
root_mountflags &= ~MS_RDONLY;
|
||||
ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_CORE, parse_tag_core);
|
||||
|
||||
static int __init parse_tag_mem32(const struct tag *tag)
|
||||
{
|
||||
return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
|
||||
}
|
||||
|
||||
__tagtable(ATAG_MEM, parse_tag_mem32);
|
||||
|
||||
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
|
||||
static int __init parse_tag_videotext(const struct tag *tag)
|
||||
{
|
||||
screen_info.orig_x = tag->u.videotext.x;
|
||||
screen_info.orig_y = tag->u.videotext.y;
|
||||
screen_info.orig_video_page = tag->u.videotext.video_page;
|
||||
screen_info.orig_video_mode = tag->u.videotext.video_mode;
|
||||
screen_info.orig_video_cols = tag->u.videotext.video_cols;
|
||||
screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
|
||||
screen_info.orig_video_lines = tag->u.videotext.video_lines;
|
||||
screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
|
||||
screen_info.orig_video_points = tag->u.videotext.video_points;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_RAM
|
||||
static int __init parse_tag_ramdisk(const struct tag *tag)
|
||||
{
|
||||
extern int rd_size, rd_image_start, rd_prompt, rd_doload;
|
||||
|
||||
rd_image_start = tag->u.ramdisk.start;
|
||||
rd_doload = (tag->u.ramdisk.flags & 1) == 0;
|
||||
rd_prompt = (tag->u.ramdisk.flags & 2) == 0;
|
||||
|
||||
if (tag->u.ramdisk.size)
|
||||
rd_size = tag->u.ramdisk.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
|
||||
#endif
|
||||
|
||||
static int __init parse_tag_serialnr(const struct tag *tag)
|
||||
{
|
||||
system_serial_low = tag->u.serialnr.low;
|
||||
system_serial_high = tag->u.serialnr.high;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_SERIAL, parse_tag_serialnr);
|
||||
|
||||
static int __init parse_tag_revision(const struct tag *tag)
|
||||
{
|
||||
system_rev = tag->u.revision.rev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_REVISION, parse_tag_revision);
|
||||
|
||||
static int __init parse_tag_cmdline(const struct tag *tag)
|
||||
{
|
||||
#if defined(CONFIG_CMDLINE_EXTEND)
|
||||
strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
|
||||
strlcat(default_command_line, tag->u.cmdline.cmdline,
|
||||
COMMAND_LINE_SIZE);
|
||||
#elif defined(CONFIG_CMDLINE_FORCE)
|
||||
pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
|
||||
#else
|
||||
strlcpy(default_command_line, tag->u.cmdline.cmdline,
|
||||
COMMAND_LINE_SIZE);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
|
||||
|
||||
/*
|
||||
* Scan the tag table for this tag, and call its parse function.
|
||||
* The tag table is built by the linker from all the __tagtable
|
||||
* declarations.
|
||||
*/
|
||||
static int __init parse_tag(const struct tag *tag)
|
||||
{
|
||||
extern struct tagtable __tagtable_begin, __tagtable_end;
|
||||
struct tagtable *t;
|
||||
|
||||
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
|
||||
if (tag->hdr.tag == t->tag) {
|
||||
t->parse(tag);
|
||||
break;
|
||||
}
|
||||
|
||||
return t < &__tagtable_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse all tags in the list, checking both the global and architecture
|
||||
* specific tag tables.
|
||||
*/
|
||||
static void __init parse_tags(const struct tag *t)
|
||||
{
|
||||
for (; t->hdr.size; t = tag_next(t))
|
||||
if (!parse_tag(t))
|
||||
printk(KERN_WARNING
|
||||
"Ignoring unrecognised tag 0x%08x\n",
|
||||
t->hdr.tag);
|
||||
}
|
||||
|
||||
static void __init squash_mem_tags(struct tag *tag)
|
||||
{
|
||||
for (; tag->hdr.size; tag = tag_next(tag))
|
||||
if (tag->hdr.tag == ATAG_MEM)
|
||||
tag->hdr.tag = ATAG_NONE;
|
||||
}
|
||||
|
||||
struct machine_desc * __init setup_machine_tags(phys_addr_t __atags_pointer,
|
||||
unsigned int machine_nr)
|
||||
{
|
||||
struct tag *tags = (struct tag *)&default_tags;
|
||||
struct machine_desc *mdesc = NULL, *p;
|
||||
char *from = default_command_line;
|
||||
|
||||
default_tags.mem.start = PHYS_OFFSET;
|
||||
|
||||
/*
|
||||
* locate machine in the list of supported machines.
|
||||
*/
|
||||
for_each_machine_desc(p)
|
||||
if (machine_nr == p->nr) {
|
||||
printk("Machine: %s\n", p->name);
|
||||
mdesc = p;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mdesc) {
|
||||
early_print("\nError: unrecognized/unsupported machine ID"
|
||||
" (r1 = 0x%08x).\n\n", machine_nr);
|
||||
dump_machine_table(); /* does not return */
|
||||
}
|
||||
|
||||
if (__atags_pointer)
|
||||
tags = phys_to_virt(__atags_pointer);
|
||||
else if (mdesc->atag_offset)
|
||||
tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
|
||||
|
||||
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
|
||||
/*
|
||||
* If we have the old style parameters, convert them to
|
||||
* a tag list.
|
||||
*/
|
||||
if (tags->hdr.tag != ATAG_CORE)
|
||||
convert_to_tag_list(tags);
|
||||
#endif
|
||||
if (tags->hdr.tag != ATAG_CORE) {
|
||||
early_print("Warning: Neither atags nor dtb found\n");
|
||||
tags = (struct tag *)&default_tags;
|
||||
}
|
||||
|
||||
if (mdesc->fixup)
|
||||
mdesc->fixup(tags, &from, &meminfo);
|
||||
|
||||
if (tags->hdr.tag == ATAG_CORE) {
|
||||
if (meminfo.nr_banks != 0)
|
||||
squash_mem_tags(tags);
|
||||
save_atags(tags);
|
||||
parse_tags(tags);
|
||||
}
|
||||
|
||||
/* parse_early_param needs a boot_command_line */
|
||||
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
|
||||
|
||||
return mdesc;
|
||||
}
|
@@ -387,6 +387,7 @@
|
||||
/* 375 */ CALL(sys_setns)
|
||||
CALL(sys_process_vm_readv)
|
||||
CALL(sys_process_vm_writev)
|
||||
CALL(sys_ni_syscall) /* reserved for sys_kcmp */
|
||||
#ifndef syscalls_counted
|
||||
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
|
||||
#define syscalls_counted
|
||||
|
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/kernel/compat.h
|
||||
*
|
||||
* Copyright (C) 2001 Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
extern void convert_to_tag_list(struct tag *tags);
|
@@ -94,6 +94,15 @@ ENDPROC(ret_from_fork)
|
||||
.equ NR_syscalls,0
|
||||
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
|
||||
#include "calls.S"
|
||||
|
||||
/*
|
||||
* Ensure that the system call table is equal to __NR_syscalls,
|
||||
* which is the value the rest of the system sees
|
||||
*/
|
||||
.ifne NR_syscalls - __NR_syscalls
|
||||
.error "__NR_syscalls is not equal to the size of the syscall table"
|
||||
.endif
|
||||
|
||||
#undef CALL
|
||||
#define CALL(x) .long x
|
||||
|
||||
|
@@ -159,6 +159,12 @@ static int debug_arch_supported(void)
|
||||
arch >= ARM_DEBUG_ARCH_V7_1;
|
||||
}
|
||||
|
||||
/* Can we determine the watchpoint access type from the fsr? */
|
||||
static int debug_exception_updates_fsr(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine number of WRP registers available. */
|
||||
static int get_num_wrp_resources(void)
|
||||
{
|
||||
@@ -604,13 +610,14 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
/* Aligned */
|
||||
break;
|
||||
case 1:
|
||||
/* Allow single byte watchpoint. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
|
||||
break;
|
||||
case 2:
|
||||
/* Allow halfword watchpoints and breakpoints. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
|
||||
break;
|
||||
case 3:
|
||||
/* Allow single byte watchpoint. */
|
||||
if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@@ -619,18 +626,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
||||
info->address &= ~alignment_mask;
|
||||
info->ctrl.len <<= offset;
|
||||
|
||||
/*
|
||||
* Currently we rely on an overflow handler to take
|
||||
* care of single-stepping the breakpoint when it fires.
|
||||
* In the case of userspace breakpoints on a core with V7 debug,
|
||||
* we can use the mismatch feature as a poor-man's hardware
|
||||
* single-step, but this only works for per-task breakpoints.
|
||||
*/
|
||||
if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) ||
|
||||
!core_has_mismatch_brps() || !bp->hw.bp_target)) {
|
||||
pr_warning("overflow handler required but none found\n");
|
||||
ret = -EINVAL;
|
||||
if (!bp->overflow_handler) {
|
||||
/*
|
||||
* Mismatch breakpoints are required for single-stepping
|
||||
* breakpoints.
|
||||
*/
|
||||
if (!core_has_mismatch_brps())
|
||||
return -EINVAL;
|
||||
|
||||
/* We don't allow mismatch breakpoints in kernel space. */
|
||||
if (arch_check_bp_in_kernelspace(bp))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* Per-cpu breakpoints are not supported by our stepping
|
||||
* mechanism.
|
||||
*/
|
||||
if (!bp->hw.bp_target)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* We only support specific access types if the fsr
|
||||
* reports them.
|
||||
*/
|
||||
if (!debug_exception_updates_fsr() &&
|
||||
(info->ctrl.type == ARM_BREAKPOINT_LOAD ||
|
||||
info->ctrl.type == ARM_BREAKPOINT_STORE))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -706,10 +730,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
|
||||
goto unlock;
|
||||
|
||||
/* Check that the access type matches. */
|
||||
access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
|
||||
HW_BREAKPOINT_R;
|
||||
if (!(access & hw_breakpoint_type(wp)))
|
||||
goto unlock;
|
||||
if (debug_exception_updates_fsr()) {
|
||||
access = (fsr & ARM_FSR_ACCESS_MASK) ?
|
||||
HW_BREAKPOINT_W : HW_BREAKPOINT_R;
|
||||
if (!(access & hw_breakpoint_type(wp)))
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* We have a winner. */
|
||||
info->trigger = addr;
|
||||
|
@@ -8,7 +8,9 @@
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/cacheflush.h>
|
||||
@@ -32,6 +34,29 @@ static atomic_t waiting_for_crash_ipi;
|
||||
|
||||
int machine_kexec_prepare(struct kimage *image)
|
||||
{
|
||||
struct kexec_segment *current_segment;
|
||||
__be32 header;
|
||||
int i, err;
|
||||
|
||||
/*
|
||||
* No segment at default ATAGs address. try to locate
|
||||
* a dtb using magic.
|
||||
*/
|
||||
for (i = 0; i < image->nr_segments; i++) {
|
||||
current_segment = &image->segment[i];
|
||||
|
||||
err = memblock_is_region_memory(current_segment->mem,
|
||||
current_segment->memsz);
|
||||
if (err)
|
||||
return - EINVAL;
|
||||
|
||||
err = get_user(header, (__be32*)current_segment->buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (be32_to_cpu(header) == OF_DT_HEADER)
|
||||
kexec_boot_atags = current_segment->mem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -122,7 +147,9 @@ void machine_kexec(struct kimage *image)
|
||||
kexec_start_address = image->start;
|
||||
kexec_indirection_page = page_list;
|
||||
kexec_mach_type = machine_arch_type;
|
||||
kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
|
||||
if (!kexec_boot_atags)
|
||||
kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
|
||||
|
||||
|
||||
/* copy our kernel relocation code to the control code page */
|
||||
memcpy(reboot_code_buffer,
|
||||
|
@@ -30,6 +30,9 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/syscalls.h>
|
||||
|
||||
#define REG_PC 15
|
||||
#define REG_PSR 16
|
||||
/*
|
||||
@@ -918,11 +921,11 @@ static int ptrace_syscall_trace(struct pt_regs *regs, int scno,
|
||||
{
|
||||
unsigned long ip;
|
||||
|
||||
current_thread_info()->syscall = scno;
|
||||
|
||||
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
return scno;
|
||||
|
||||
current_thread_info()->syscall = scno;
|
||||
|
||||
/*
|
||||
* IP is used to denote syscall entry/exit:
|
||||
* IP = 0 -> entry, =1 -> exit
|
||||
@@ -941,15 +944,19 @@ static int ptrace_syscall_trace(struct pt_regs *regs, int scno,
|
||||
|
||||
asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
|
||||
{
|
||||
int ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER);
|
||||
scno = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER);
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
|
||||
trace_sys_enter(regs, scno);
|
||||
audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
|
||||
regs->ARM_r2, regs->ARM_r3);
|
||||
return ret;
|
||||
return scno;
|
||||
}
|
||||
|
||||
asmlinkage int syscall_trace_exit(struct pt_regs *regs, int scno)
|
||||
{
|
||||
int ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_EXIT);
|
||||
scno = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_EXIT);
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
|
||||
trace_sys_exit(regs, scno);
|
||||
audit_syscall_exit(regs);
|
||||
return ret;
|
||||
return scno;
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/timer.h>
|
||||
@@ -21,10 +22,15 @@ struct clock_data {
|
||||
u32 epoch_cyc_copy;
|
||||
u32 mult;
|
||||
u32 shift;
|
||||
bool suspended;
|
||||
bool needs_suspend;
|
||||
};
|
||||
|
||||
static void sched_clock_poll(unsigned long wrap_ticks);
|
||||
static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0);
|
||||
static int irqtime = -1;
|
||||
|
||||
core_param(irqtime, irqtime, int, 0400);
|
||||
|
||||
static struct clock_data cd = {
|
||||
.mult = NSEC_PER_SEC / HZ,
|
||||
@@ -49,6 +55,9 @@ static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
|
||||
u64 epoch_ns;
|
||||
u32 epoch_cyc;
|
||||
|
||||
if (cd.suspended)
|
||||
return cd.epoch_ns;
|
||||
|
||||
/*
|
||||
* Load the epoch_cyc and epoch_ns atomically. We do this by
|
||||
* ensuring that we always write epoch_cyc, epoch_ns and
|
||||
@@ -98,6 +107,13 @@ static void sched_clock_poll(unsigned long wrap_ticks)
|
||||
update_sched_clock();
|
||||
}
|
||||
|
||||
void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
|
||||
unsigned long rate)
|
||||
{
|
||||
setup_sched_clock(read, bits, rate);
|
||||
cd.needs_suspend = true;
|
||||
}
|
||||
|
||||
void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
|
||||
{
|
||||
unsigned long r, w;
|
||||
@@ -145,6 +161,10 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
|
||||
*/
|
||||
cd.epoch_ns = 0;
|
||||
|
||||
/* Enable IRQ time accounting if we have a fast enough sched_clock */
|
||||
if (irqtime > 0 || (irqtime == -1 && rate >= 1000000))
|
||||
enable_sched_clock_irqtime();
|
||||
|
||||
pr_debug("Registered %pF as sched_clock source\n", read);
|
||||
}
|
||||
|
||||
@@ -169,11 +189,23 @@ void __init sched_clock_postinit(void)
|
||||
static int sched_clock_suspend(void)
|
||||
{
|
||||
sched_clock_poll(sched_clock_timer.data);
|
||||
if (cd.needs_suspend)
|
||||
cd.suspended = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sched_clock_resume(void)
|
||||
{
|
||||
if (cd.needs_suspend) {
|
||||
cd.epoch_cyc = read_sched_clock();
|
||||
cd.epoch_cyc_copy = cd.epoch_cyc;
|
||||
cd.suspended = false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct syscore_ops sched_clock_ops = {
|
||||
.suspend = sched_clock_suspend,
|
||||
.resume = sched_clock_resume,
|
||||
};
|
||||
|
||||
static int __init sched_clock_syscore_init(void)
|
||||
|
@@ -21,11 +21,9 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/root_dev.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/bug.h>
|
||||
@@ -56,15 +54,9 @@
|
||||
#include <asm/unwind.h>
|
||||
#include <asm/memblock.h>
|
||||
|
||||
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
|
||||
#include "compat.h"
|
||||
#endif
|
||||
#include "atags.h"
|
||||
#include "tcm.h"
|
||||
|
||||
#ifndef MEM_SIZE
|
||||
#define MEM_SIZE (16*1024*1024)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
|
||||
char fpe_type[8];
|
||||
@@ -145,7 +137,6 @@ static const char *machine_name;
|
||||
static char __initdata cmd_line[COMMAND_LINE_SIZE];
|
||||
struct machine_desc *machine_desc __initdata;
|
||||
|
||||
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
|
||||
static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
|
||||
#define ENDIANNESS ((char)endian_test.l)
|
||||
|
||||
@@ -583,21 +574,6 @@ static int __init early_mem(char *p)
|
||||
}
|
||||
early_param("mem", early_mem);
|
||||
|
||||
static void __init
|
||||
setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
|
||||
{
|
||||
#ifdef CONFIG_BLK_DEV_RAM
|
||||
extern int rd_size, rd_image_start, rd_prompt, rd_doload;
|
||||
|
||||
rd_image_start = image_start;
|
||||
rd_prompt = prompt;
|
||||
rd_doload = doload;
|
||||
|
||||
if (rd_sz)
|
||||
rd_size = rd_sz;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init request_standard_resources(struct machine_desc *mdesc)
|
||||
{
|
||||
struct memblock_region *region;
|
||||
@@ -643,35 +619,6 @@ static void __init request_standard_resources(struct machine_desc *mdesc)
|
||||
request_resource(&ioport_resource, &lp2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tag parsing.
|
||||
*
|
||||
* This is the new way of passing data to the kernel at boot time. Rather
|
||||
* than passing a fixed inflexible structure to the kernel, we pass a list
|
||||
* of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
|
||||
* tag for the list to be recognised (to distinguish the tagged list from
|
||||
* a param_struct). The list is terminated with a zero-length tag (this tag
|
||||
* is not parsed in any way).
|
||||
*/
|
||||
static int __init parse_tag_core(const struct tag *tag)
|
||||
{
|
||||
if (tag->hdr.size > 2) {
|
||||
if ((tag->u.core.flags & 1) == 0)
|
||||
root_mountflags &= ~MS_RDONLY;
|
||||
ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_CORE, parse_tag_core);
|
||||
|
||||
static int __init parse_tag_mem32(const struct tag *tag)
|
||||
{
|
||||
return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
|
||||
}
|
||||
|
||||
__tagtable(ATAG_MEM, parse_tag_mem32);
|
||||
|
||||
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
|
||||
struct screen_info screen_info = {
|
||||
.orig_video_lines = 30,
|
||||
@@ -681,117 +628,8 @@ struct screen_info screen_info = {
|
||||
.orig_video_isVGA = 1,
|
||||
.orig_video_points = 8
|
||||
};
|
||||
|
||||
static int __init parse_tag_videotext(const struct tag *tag)
|
||||
{
|
||||
screen_info.orig_x = tag->u.videotext.x;
|
||||
screen_info.orig_y = tag->u.videotext.y;
|
||||
screen_info.orig_video_page = tag->u.videotext.video_page;
|
||||
screen_info.orig_video_mode = tag->u.videotext.video_mode;
|
||||
screen_info.orig_video_cols = tag->u.videotext.video_cols;
|
||||
screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
|
||||
screen_info.orig_video_lines = tag->u.videotext.video_lines;
|
||||
screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
|
||||
screen_info.orig_video_points = tag->u.videotext.video_points;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
|
||||
#endif
|
||||
|
||||
static int __init parse_tag_ramdisk(const struct tag *tag)
|
||||
{
|
||||
setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
|
||||
(tag->u.ramdisk.flags & 2) == 0,
|
||||
tag->u.ramdisk.start, tag->u.ramdisk.size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
|
||||
|
||||
static int __init parse_tag_serialnr(const struct tag *tag)
|
||||
{
|
||||
system_serial_low = tag->u.serialnr.low;
|
||||
system_serial_high = tag->u.serialnr.high;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_SERIAL, parse_tag_serialnr);
|
||||
|
||||
static int __init parse_tag_revision(const struct tag *tag)
|
||||
{
|
||||
system_rev = tag->u.revision.rev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_REVISION, parse_tag_revision);
|
||||
|
||||
static int __init parse_tag_cmdline(const struct tag *tag)
|
||||
{
|
||||
#if defined(CONFIG_CMDLINE_EXTEND)
|
||||
strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
|
||||
strlcat(default_command_line, tag->u.cmdline.cmdline,
|
||||
COMMAND_LINE_SIZE);
|
||||
#elif defined(CONFIG_CMDLINE_FORCE)
|
||||
pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
|
||||
#else
|
||||
strlcpy(default_command_line, tag->u.cmdline.cmdline,
|
||||
COMMAND_LINE_SIZE);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
|
||||
|
||||
/*
|
||||
* Scan the tag table for this tag, and call its parse function.
|
||||
* The tag table is built by the linker from all the __tagtable
|
||||
* declarations.
|
||||
*/
|
||||
static int __init parse_tag(const struct tag *tag)
|
||||
{
|
||||
extern struct tagtable __tagtable_begin, __tagtable_end;
|
||||
struct tagtable *t;
|
||||
|
||||
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
|
||||
if (tag->hdr.tag == t->tag) {
|
||||
t->parse(tag);
|
||||
break;
|
||||
}
|
||||
|
||||
return t < &__tagtable_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse all tags in the list, checking both the global and architecture
|
||||
* specific tag tables.
|
||||
*/
|
||||
static void __init parse_tags(const struct tag *t)
|
||||
{
|
||||
for (; t->hdr.size; t = tag_next(t))
|
||||
if (!parse_tag(t))
|
||||
printk(KERN_WARNING
|
||||
"Ignoring unrecognised tag 0x%08x\n",
|
||||
t->hdr.tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* This holds our defaults.
|
||||
*/
|
||||
static struct init_tags {
|
||||
struct tag_header hdr1;
|
||||
struct tag_core core;
|
||||
struct tag_header hdr2;
|
||||
struct tag_mem32 mem;
|
||||
struct tag_header hdr3;
|
||||
} init_tags __initdata = {
|
||||
{ tag_size(tag_core), ATAG_CORE },
|
||||
{ 1, PAGE_SIZE, 0xff },
|
||||
{ tag_size(tag_mem32), ATAG_MEM },
|
||||
{ MEM_SIZE },
|
||||
{ 0, ATAG_NONE }
|
||||
};
|
||||
|
||||
static int __init customize_machine(void)
|
||||
{
|
||||
/* customizes platform devices, or adds new ones */
|
||||
@@ -858,78 +696,6 @@ static void __init reserve_crashkernel(void)
|
||||
static inline void reserve_crashkernel(void) {}
|
||||
#endif /* CONFIG_KEXEC */
|
||||
|
||||
static void __init squash_mem_tags(struct tag *tag)
|
||||
{
|
||||
for (; tag->hdr.size; tag = tag_next(tag))
|
||||
if (tag->hdr.tag == ATAG_MEM)
|
||||
tag->hdr.tag = ATAG_NONE;
|
||||
}
|
||||
|
||||
static struct machine_desc * __init setup_machine_tags(unsigned int nr)
|
||||
{
|
||||
struct tag *tags = (struct tag *)&init_tags;
|
||||
struct machine_desc *mdesc = NULL, *p;
|
||||
char *from = default_command_line;
|
||||
|
||||
init_tags.mem.start = PHYS_OFFSET;
|
||||
|
||||
/*
|
||||
* locate machine in the list of supported machines.
|
||||
*/
|
||||
for_each_machine_desc(p)
|
||||
if (nr == p->nr) {
|
||||
printk("Machine: %s\n", p->name);
|
||||
mdesc = p;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mdesc) {
|
||||
early_print("\nError: unrecognized/unsupported machine ID"
|
||||
" (r1 = 0x%08x).\n\n", nr);
|
||||
dump_machine_table(); /* does not return */
|
||||
}
|
||||
|
||||
if (__atags_pointer)
|
||||
tags = phys_to_virt(__atags_pointer);
|
||||
else if (mdesc->atag_offset)
|
||||
tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
|
||||
|
||||
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
|
||||
/*
|
||||
* If we have the old style parameters, convert them to
|
||||
* a tag list.
|
||||
*/
|
||||
if (tags->hdr.tag != ATAG_CORE)
|
||||
convert_to_tag_list(tags);
|
||||
#endif
|
||||
|
||||
if (tags->hdr.tag != ATAG_CORE) {
|
||||
#if defined(CONFIG_OF)
|
||||
/*
|
||||
* If CONFIG_OF is set, then assume this is a reasonably
|
||||
* modern system that should pass boot parameters
|
||||
*/
|
||||
early_print("Warning: Neither atags nor dtb found\n");
|
||||
#endif
|
||||
tags = (struct tag *)&init_tags;
|
||||
}
|
||||
|
||||
if (mdesc->fixup)
|
||||
mdesc->fixup(tags, &from, &meminfo);
|
||||
|
||||
if (tags->hdr.tag == ATAG_CORE) {
|
||||
if (meminfo.nr_banks != 0)
|
||||
squash_mem_tags(tags);
|
||||
save_atags(tags);
|
||||
parse_tags(tags);
|
||||
}
|
||||
|
||||
/* parse_early_param needs a boot_command_line */
|
||||
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
|
||||
|
||||
return mdesc;
|
||||
}
|
||||
|
||||
static int __init meminfo_cmp(const void *_a, const void *_b)
|
||||
{
|
||||
const struct membank *a = _a, *b = _b;
|
||||
@@ -944,7 +710,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
setup_processor();
|
||||
mdesc = setup_machine_fdt(__atags_pointer);
|
||||
if (!mdesc)
|
||||
mdesc = setup_machine_tags(machine_arch_type);
|
||||
mdesc = setup_machine_tags(__atags_pointer, machine_arch_type);
|
||||
machine_desc = mdesc;
|
||||
machine_name = mdesc->name;
|
||||
|
||||
|
@@ -51,7 +51,8 @@
|
||||
struct secondary_data secondary_data;
|
||||
|
||||
enum ipi_msg_type {
|
||||
IPI_TIMER = 2,
|
||||
IPI_WAKEUP,
|
||||
IPI_TIMER,
|
||||
IPI_RESCHEDULE,
|
||||
IPI_CALL_FUNC,
|
||||
IPI_CALL_FUNC_SINGLE,
|
||||
@@ -347,7 +348,8 @@ void arch_send_call_function_single_ipi(int cpu)
|
||||
}
|
||||
|
||||
static const char *ipi_types[NR_IPI] = {
|
||||
#define S(x,s) [x - IPI_TIMER] = s
|
||||
#define S(x,s) [x] = s
|
||||
S(IPI_WAKEUP, "CPU wakeup interrupts"),
|
||||
S(IPI_TIMER, "Timer broadcast interrupts"),
|
||||
S(IPI_RESCHEDULE, "Rescheduling interrupts"),
|
||||
S(IPI_CALL_FUNC, "Function call interrupts"),
|
||||
@@ -500,10 +502,13 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
||||
if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI)
|
||||
__inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]);
|
||||
if (ipinr < NR_IPI)
|
||||
__inc_irq_stat(cpu, ipi_irqs[ipinr]);
|
||||
|
||||
switch (ipinr) {
|
||||
case IPI_WAKEUP:
|
||||
break;
|
||||
|
||||
case IPI_TIMER:
|
||||
irq_enter();
|
||||
ipi_timer();
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
@@ -96,7 +95,52 @@ static void twd_timer_stop(struct clock_event_device *clk)
|
||||
disable_percpu_irq(clk->irq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
|
||||
/*
|
||||
* Updates clockevent frequency when the cpu frequency changes.
|
||||
* Called on the cpu that is changing frequency with interrupts disabled.
|
||||
*/
|
||||
static void twd_update_frequency(void *new_rate)
|
||||
{
|
||||
twd_timer_rate = *((unsigned long *) new_rate);
|
||||
|
||||
clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
|
||||
}
|
||||
|
||||
static int twd_rate_change(struct notifier_block *nb,
|
||||
unsigned long flags, void *data)
|
||||
{
|
||||
struct clk_notifier_data *cnd = data;
|
||||
|
||||
/*
|
||||
* The twd clock events must be reprogrammed to account for the new
|
||||
* frequency. The timer is local to a cpu, so cross-call to the
|
||||
* changing cpu.
|
||||
*/
|
||||
if (flags == POST_RATE_CHANGE)
|
||||
smp_call_function(twd_update_frequency,
|
||||
(void *)&cnd->new_rate, 1);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block twd_clk_nb = {
|
||||
.notifier_call = twd_rate_change,
|
||||
};
|
||||
|
||||
static int twd_clk_init(void)
|
||||
{
|
||||
if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
|
||||
return clk_notifier_register(twd_clk, &twd_clk_nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(twd_clk_init);
|
||||
|
||||
#elif defined (CONFIG_CPU_FREQ)
|
||||
|
||||
#include <linux/cpufreq.h>
|
||||
|
||||
/*
|
||||
* Updates clockevent frequency when the cpu frequency changes.
|
||||
|
@@ -321,7 +321,7 @@ void store_cpu_topology(unsigned int cpuid)
|
||||
* init_cpu_topology is called at boot when only one cpu is running
|
||||
* which prevent simultaneous write access to cpu_topology array
|
||||
*/
|
||||
void init_cpu_topology(void)
|
||||
void __init init_cpu_topology(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
|
@@ -420,20 +420,23 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
||||
#endif
|
||||
instr = *(u32 *) pc;
|
||||
} else if (thumb_mode(regs)) {
|
||||
get_user(instr, (u16 __user *)pc);
|
||||
if (get_user(instr, (u16 __user *)pc))
|
||||
goto die_sig;
|
||||
if (is_wide_instruction(instr)) {
|
||||
unsigned int instr2;
|
||||
get_user(instr2, (u16 __user *)pc+1);
|
||||
if (get_user(instr2, (u16 __user *)pc+1))
|
||||
goto die_sig;
|
||||
instr <<= 16;
|
||||
instr |= instr2;
|
||||
}
|
||||
} else {
|
||||
get_user(instr, (u32 __user *)pc);
|
||||
} else if (get_user(instr, (u32 __user *)pc)) {
|
||||
goto die_sig;
|
||||
}
|
||||
|
||||
if (call_undef_hook(regs, instr) == 0)
|
||||
return;
|
||||
|
||||
die_sig:
|
||||
#ifdef CONFIG_DEBUG_USER
|
||||
if (user_debug & UDBG_UNDEFINED) {
|
||||
printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
|
||||
|
Reference in New Issue
Block a user