diff options
author | Lee Jones <lee.jones@linaro.org> | 2011-07-26 17:31:06 +0100 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2011-07-26 17:35:08 +0100 |
commit | 6f914cb1efe4aba81bb841ec8f4f5636163c0586 (patch) | |
tree | 7ef04a88618a05c53faa2fd4ccd03e90c06a89bd /arch | |
parent | 232bdfad970ce35177ca12c5527d1c96f7ce44f1 (diff) |
Apply mega patch to make GLK the ALK
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'arch')
35 files changed, 3816 insertions, 180 deletions
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 5a07162568f..c66ea272ae8 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -763,6 +763,8 @@ proc_types: @ b __arm6_mmu_cache_off @ b __armv3_mmu_cache_flush +#if !defined(CONFIG_CPU_V7) + /* This collides with some V7 IDs, preventing correct detection */ .word 0x00000000 @ old ARM ID .word 0x0000f000 mov pc, lr @@ -771,6 +773,7 @@ proc_types: THUMB( nop ) mov pc, lr THUMB( nop ) +#endif .word 0x41007000 @ ARM7/710 .word 0xfff8fe00 diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 4b71766fb21..cf82a884a5c 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -39,3 +39,54 @@ config SHARP_PARAM config SHARP_SCOOP bool + +config FIQ_GLUE + bool + select FIQ + +config FIQ_DEBUGGER + bool "FIQ Mode Serial Debugger" + select FIQ + select FIQ_GLUE + select KERNEL_DEBUGGER_CORE + default n + help + The FIQ serial debugger can accept commands even when the + kernel is unresponsive due to being stuck with interrupts + disabled. Depends on the kernel debugger core in drivers/misc. + + +config FIQ_DEBUGGER_NO_SLEEP + bool "Keep serial debugger active" + depends on FIQ_DEBUGGER + default n + help + Enables the serial debugger at boot. Passing + fiq_debugger.no_sleep on the kernel commandline will + override this config option. + +config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON + bool "Don't disable wakeup IRQ when debugger is active" + depends on FIQ_DEBUGGER + default n + help + Don't disable the wakeup irq when enabling the uart clock. This will + cause extra interrupts, but it makes the serial debugger usable with + on some MSM radio builds that ignore the uart clock request in power + collapse. + +config FIQ_DEBUGGER_CONSOLE + bool "Console on FIQ Serial Debugger port" + depends on FIQ_DEBUGGER + default n + help + Enables a console so that printk messages are displayed on + the debugger serial port as the occur. + +config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE + bool "Put the FIQ debugger into console mode by default" + depends on FIQ_DEBUGGER_CONSOLE + default n + help + If enabled, this puts the fiq debugger into console mode by default. + Otherwise, the fiq debugger will start out in debug mode. diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 86d67017c1e..a1d44926837 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -17,4 +17,6 @@ obj-$(CONFIG_ARCH_IXP2000) += uengine.o obj-$(CONFIG_ARCH_IXP23XX) += uengine.o obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o +obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o +obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o obj-$(CONFIG_BOOTTIME) += boottime.o diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c new file mode 100644 index 00000000000..080f69edd75 --- /dev/null +++ b/arch/arm/common/fiq_debugger.c @@ -0,0 +1,942 @@ +/* + * arch/arm/common/fiq_debugger.c + * + * Serial Debugger Interface accessed through an FIQ interrupt. + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdarg.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/console.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/kernel_debugger.h> +#include <linux/kernel_stat.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/wakelock.h> + +#include <asm/fiq_debugger.h> +#include <asm/fiq_glue.h> +#include <asm/stacktrace.h> + +#include <mach/system.h> + +#include <linux/uaccess.h> + +#include "fiq_debugger_ringbuf.h" + +#define DEBUG_MAX 64 +#define MAX_UNHANDLED_FIQ_COUNT 1000000 + +#define THREAD_INFO(sp) ((struct thread_info *) \ + ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) + +struct fiq_debugger_state { + struct fiq_glue_handler handler; + + int fiq; + int signal_irq; + int wakeup_irq; + bool wakeup_irq_no_set_wake; + struct clk *clk; + struct fiq_debugger_pdata *pdata; + struct platform_device *pdev; + + char debug_cmd[DEBUG_MAX]; + int debug_busy; + int debug_abort; + + char debug_buf[DEBUG_MAX]; + int debug_count; + + bool no_sleep; + bool debug_enable; + bool ignore_next_wakeup_irq; + struct timer_list sleep_timer; + bool uart_clk_enabled; + struct wake_lock debugger_wake_lock; + bool console_enable; + int current_cpu; + atomic_t unhandled_fiq_count; + bool in_fiq; + +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE + struct console console; + struct tty_driver *tty_driver; + struct tty_struct *tty; + int tty_open_count; + struct fiq_debugger_ringbuf *tty_rbuf; +#endif + + unsigned int last_irqs[NR_IRQS]; + unsigned int last_local_timer_irqs[NR_CPUS]; +}; + +#ifdef CONFIG_FIQ_DEBUGGER_NO_SLEEP +static bool initial_no_sleep = true; +#else +static bool initial_no_sleep; +#endif + +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE +static bool initial_debug_enable = true; +static bool initial_console_enable = true; +#else +static bool initial_debug_enable; +static bool initial_console_enable; +#endif + +module_param_named(no_sleep, initial_no_sleep, bool, 0644); +module_param_named(debug_enable, initial_debug_enable, bool, 0644); +module_param_named(console_enable, initial_console_enable, bool, 0644); + +#ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON +static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {} +static inline void disable_wakeup_irq(struct fiq_debugger_state *state) {} +#else +static inline void enable_wakeup_irq(struct fiq_debugger_state *state) +{ + if (state->wakeup_irq < 0) + return; + enable_irq(state->wakeup_irq); + if (!state->wakeup_irq_no_set_wake) + enable_irq_wake(state->wakeup_irq); +} +static inline void disable_wakeup_irq(struct fiq_debugger_state *state) +{ + if (state->wakeup_irq < 0) + return; + disable_irq_nosync(state->wakeup_irq); + if (!state->wakeup_irq_no_set_wake) + disable_irq_wake(state->wakeup_irq); +} +#endif + +static void debug_force_irq(struct fiq_debugger_state *state) +{ + unsigned int irq = state->signal_irq; + if (state->pdata->force_irq) + state->pdata->force_irq(state->pdev, irq); + else { + struct irq_chip *chip = irq_get_chip(irq); + if (chip && chip->irq_retrigger) + chip->irq_retrigger(irq_get_irq_data(irq)); + } +} + +static void debug_uart_flush(struct fiq_debugger_state *state) +{ + if (state->pdata->uart_flush) + state->pdata->uart_flush(state->pdev); +} + +static void debug_puts(struct fiq_debugger_state *state, char *s) +{ + unsigned c; + while ((c = *s++)) { + if (c == '\n') + state->pdata->uart_putc(state->pdev, '\r'); + state->pdata->uart_putc(state->pdev, c); + } +} + +static void debug_prompt(struct fiq_debugger_state *state) +{ + debug_puts(state, "debug> "); +} + +int log_buf_copy(char *dest, int idx, int len); +static void dump_kernel_log(struct fiq_debugger_state *state) +{ + char buf[1024]; + int idx = 0; + int ret; + int saved_oip; + + /* setting oops_in_progress prevents log_buf_copy() + * from trying to take a spinlock which will make it + * very unhappy in some cases... + */ + saved_oip = oops_in_progress; + oops_in_progress = 1; + for (;;) { + ret = log_buf_copy(buf, idx, 1023); + if (ret <= 0) + break; + buf[ret] = 0; + debug_puts(state, buf); + idx += ret; + } + oops_in_progress = saved_oip; +} + +static char *mode_name(unsigned cpsr) +{ + switch (cpsr & MODE_MASK) { + case USR_MODE: return "USR"; + case FIQ_MODE: return "FIQ"; + case IRQ_MODE: return "IRQ"; + case SVC_MODE: return "SVC"; + case ABT_MODE: return "ABT"; + case UND_MODE: return "UND"; + case SYSTEM_MODE: return "SYS"; + default: return "???"; + } +} + +static int debug_printf(void *cookie, const char *fmt, ...) +{ + struct fiq_debugger_state *state = cookie; + char buf[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + debug_puts(state, buf); + return state->debug_abort; +} + +/* Safe outside fiq context */ +static int debug_printf_nfiq(void *cookie, const char *fmt, ...) +{ + struct fiq_debugger_state *state = cookie; + char buf[256]; + va_list ap; + unsigned long irq_flags; + + va_start(ap, fmt); + vsnprintf(buf, 128, fmt, ap); + va_end(ap); + + local_irq_save(irq_flags); + debug_puts(state, buf); + debug_uart_flush(state); + local_irq_restore(irq_flags); + return state->debug_abort; +} + +static void dump_regs(struct fiq_debugger_state *state, unsigned *regs) +{ + debug_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + regs[0], regs[1], regs[2], regs[3]); + debug_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + regs[4], regs[5], regs[6], regs[7]); + debug_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", + regs[8], regs[9], regs[10], regs[11], + mode_name(regs[16])); + if ((regs[16] & MODE_MASK) == USR_MODE) + debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " + "cpsr %08x\n", regs[12], regs[13], regs[14], + regs[15], regs[16]); + else + debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " + "cpsr %08x spsr %08x\n", regs[12], regs[13], + regs[14], regs[15], regs[16], regs[17]); +} + +struct mode_regs { + unsigned long sp_svc; + unsigned long lr_svc; + unsigned long spsr_svc; + + unsigned long sp_abt; + unsigned long lr_abt; + unsigned long spsr_abt; + + unsigned long sp_und; + unsigned long lr_und; + unsigned long spsr_und; + + unsigned long sp_irq; + unsigned long lr_irq; + unsigned long spsr_irq; + + unsigned long r8_fiq; + unsigned long r9_fiq; + unsigned long r10_fiq; + unsigned long r11_fiq; + unsigned long r12_fiq; + unsigned long sp_fiq; + unsigned long lr_fiq; + unsigned long spsr_fiq; +}; + +void __naked get_mode_regs(struct mode_regs *regs) +{ + asm volatile ( + "mrs r1, cpsr\n" + "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r8 - r14}\n" + "mrs r2, spsr\n" + "stmia r0!, {r2}\n" + "msr cpsr_c, r1\n" + "bx lr\n"); +} + + +static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs) +{ + struct mode_regs mode_regs; + dump_regs(state, regs); + get_mode_regs(&mode_regs); + debug_printf(state, " svc: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); + debug_printf(state, " abt: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); + debug_printf(state, " und: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); + debug_printf(state, " irq: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); + debug_printf(state, " fiq: r8 %08x r9 %08x r10 %08x r11 %08x " + "r12 %08x\n", + mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, + mode_regs.r11_fiq, mode_regs.r12_fiq); + debug_printf(state, " fiq: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); +} + +static void dump_irqs(struct fiq_debugger_state *state) +{ + int n; + unsigned int cpu; + + debug_printf(state, "irqnr total since-last status name\n"); + for (n = 0; n < NR_IRQS; n++) { + struct irqaction *act = irq_desc[n].action; + if (!act && !kstat_irqs(n)) + continue; + debug_printf(state, "%5d: %10u %11u %8x %s\n", n, + kstat_irqs(n), + kstat_irqs(n) - state->last_irqs[n], + irq_desc[n].status_use_accessors, + (act && act->name) ? act->name : "???"); + state->last_irqs[n] = kstat_irqs(n); + } + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + + debug_printf(state, "LOC %d: %10u %11u\n", cpu, + __IRQ_STAT(cpu, local_timer_irqs), + __IRQ_STAT(cpu, local_timer_irqs) - + state->last_local_timer_irqs[cpu]); + state->last_local_timer_irqs[cpu] = + __IRQ_STAT(cpu, local_timer_irqs); + } +} + +struct stacktrace_state { + struct fiq_debugger_state *state; + unsigned int depth; +}; + +static int report_trace(struct stackframe *frame, void *d) +{ + struct stacktrace_state *sts = d; + + if (sts->depth) { + debug_printf(sts->state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + frame->pc, frame->pc, frame->lr, frame->lr, + frame->sp, frame->fp); + sts->depth--; + return 0; + } + debug_printf(sts->state, " ...\n"); + + return sts->depth == 0; +} + +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + +static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, + struct frame_tail *tail) +{ + struct frame_tail buftail[2]; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { + debug_printf(state, " invalid frame pointer %p\n", tail); + return NULL; + } + if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { + debug_printf(state, + " failed to copy frame pointer %p\n", tail); + return NULL; + } + + debug_printf(state, " %p\n", buftail[0].lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= buftail[0].fp) + return NULL; + + return buftail[0].fp-1; +} + +void dump_stacktrace(struct fiq_debugger_state *state, + struct pt_regs * const regs, unsigned int depth, void *ssp) +{ + struct frame_tail *tail; + struct thread_info *real_thread_info = THREAD_INFO(ssp); + struct stacktrace_state sts; + + sts.depth = depth; + sts.state = state; + *current_thread_info() = *real_thread_info; + + if (!current) + debug_printf(state, "current NULL\n"); + else + debug_printf(state, "pid: %d comm: %s\n", + current->pid, current->comm); + dump_regs(state, (unsigned *)regs); + + if (!user_mode(regs)) { + struct stackframe frame; + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + frame.pc = regs->ARM_pc; + debug_printf(state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, + regs->ARM_sp, regs->ARM_fp); + walk_stackframe(&frame, report_trace, &sts); + return; + } + + tail = ((struct frame_tail *) regs->ARM_fp) - 1; + while (depth-- && tail && !((unsigned long) tail & 3)) + tail = user_backtrace(state, tail); +} + +static void debug_help(struct fiq_debugger_state *state) +{ + debug_printf(state, "FIQ Debugger commands:\n" + " pc PC status\n" + " regs Register dump\n" + " allregs Extended Register dump\n" + " bt Stack trace\n" + " reboot Reboot\n" + " irqs Interupt status\n" + " kmsg Kernel log\n" + " version Kernel version\n"); + debug_printf(state, " sleep Allow sleep while in FIQ\n" + " nosleep Disable sleep while in FIQ\n" + " console Switch terminal to console\n" + " cpu Current CPU\n" + " cpu <number> Switch to CPU<number>\n"); + if (!state->debug_busy) { + strcpy(state->debug_cmd, "help"); + state->debug_busy = 1; + debug_force_irq(state); + } +} + +static void debug_exec(struct fiq_debugger_state *state, + const char *cmd, unsigned *regs, void *svc_sp) +{ + if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { + debug_help(state); + } else if (!strcmp(cmd, "pc")) { + debug_printf(state, " pc %08x cpsr %08x mode %s\n", + regs[15], regs[16], mode_name(regs[16])); + } else if (!strcmp(cmd, "regs")) { + dump_regs(state, regs); + } else if (!strcmp(cmd, "allregs")) { + dump_allregs(state, regs); + } else if (!strcmp(cmd, "bt")) { + dump_stacktrace(state, (struct pt_regs *)regs, 100, svc_sp); + } else if (!strcmp(cmd, "reboot")) { + arch_reset(0, 0); + } else if (!strcmp(cmd, "irqs")) { + dump_irqs(state); + } else if (!strcmp(cmd, "kmsg")) { + dump_kernel_log(state); + } else if (!strcmp(cmd, "version")) { + debug_printf(state, "%s\n", linux_banner); + } else if (!strcmp(cmd, "sleep")) { + state->no_sleep = false; + } else if (!strcmp(cmd, "nosleep")) { + state->no_sleep = true; + } else if (!strcmp(cmd, "console")) { + state->console_enable = true; + debug_printf(state, "console mode\n"); + } else if (!strcmp(cmd, "cpu")) { + debug_printf(state, "cpu %d\n", state->current_cpu); + } else if (!strncmp(cmd, "cpu ", 4)) { + unsigned long cpu = 0; + if (strict_strtoul(cmd + 4, 10, &cpu) == 0) + state->current_cpu = cpu; + else + debug_printf(state, "invalid cpu\n"); + debug_printf(state, "cpu %d\n", state->current_cpu); + } else { + if (state->debug_busy) { + debug_printf(state, + "command processor busy. trying to abort.\n"); + state->debug_abort = -1; + } else { + strcpy(state->debug_cmd, cmd); + state->debug_busy = 1; + } + + debug_force_irq(state); + + return; + } + if (!state->console_enable) + debug_prompt(state); +} + +static void sleep_timer_expired(unsigned long data) +{ + struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; + + if (state->uart_clk_enabled && !state->no_sleep) { + if (state->debug_enable) { + state->debug_enable = false; + debug_printf_nfiq(state, "suspending fiq debugger\n"); + } + state->ignore_next_wakeup_irq = true; + if (state->clk) + clk_disable(state->clk); + state->uart_clk_enabled = false; + enable_wakeup_irq(state); + } + wake_unlock(&state->debugger_wake_lock); +} + +static irqreturn_t wakeup_irq_handler(int irq, void *dev) +{ + struct fiq_debugger_state *state = dev; + + if (!state->no_sleep) + debug_puts(state, "WAKEUP\n"); + if (state->ignore_next_wakeup_irq) + state->ignore_next_wakeup_irq = false; + else if (!state->uart_clk_enabled) { + wake_lock(&state->debugger_wake_lock); + if (state->clk) + clk_enable(state->clk); + state->uart_clk_enabled = true; + disable_wakeup_irq(state); + mod_timer(&state->sleep_timer, jiffies + HZ / 2); + } + return IRQ_HANDLED; +} + +static irqreturn_t debug_irq(int irq, void *dev) +{ + struct fiq_debugger_state *state = dev; + if (state->pdata->force_irq_ack) + state->pdata->force_irq_ack(state->pdev, state->signal_irq); + + if (!state->no_sleep) { + wake_lock(&state->debugger_wake_lock); + mod_timer(&state->sleep_timer, jiffies + HZ * 5); + } +#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) + if (state->tty) { + int i; + int count = fiq_debugger_ringbuf_level(state->tty_rbuf); + for (i = 0; i < count; i++) { + int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, i); + tty_insert_flip_char(state->tty, c, TTY_NORMAL); + if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1)) + pr_warn("fiq tty failed to consume byte\n"); + } + tty_flip_buffer_push(state->tty); + } +#endif + if (state->debug_busy) { + struct kdbg_ctxt ctxt; + + ctxt.printf = debug_printf_nfiq; + ctxt.cookie = state; + kernel_debugger(&ctxt, state->debug_cmd); + debug_prompt(state); + + state->debug_busy = 0; + } + return IRQ_HANDLED; +} + +static int debug_getc(struct fiq_debugger_state *state) +{ + return state->pdata->uart_getc(state->pdev); +} + +static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) +{ + struct fiq_debugger_state *state = + container_of(h, struct fiq_debugger_state, handler); + int c; + static int last_c; + int count = 0; + unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; + + if (this_cpu != state->current_cpu) { + if (state->in_fiq) + return; + + if (atomic_inc_return(&state->unhandled_fiq_count) != + MAX_UNHANDLED_FIQ_COUNT) + return; + + debug_printf(state, "fiq_debugger: cpu %d not responding, " + "reverting to cpu %d\n", state->current_cpu, + this_cpu); + + atomic_set(&state->unhandled_fiq_count, 0); + state->current_cpu = this_cpu; + return; + } + + state->in_fiq = true; + + while ((c = debug_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { + count++; + if (!state->debug_enable) { + if ((c == 13) || (c == 10)) { + state->debug_enable = true; + state->debug_count = 0; + debug_prompt(state); + } + } else if (c == FIQ_DEBUGGER_BREAK) { + state->console_enable = false; + debug_puts(state, "fiq debugger mode\n"); + state->debug_count = 0; + debug_prompt(state); +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE + } else if (state->console_enable && state->tty_rbuf) { + fiq_debugger_ringbuf_push(state->tty_rbuf, c); + debug_force_irq(state); +#endif + } else if ((c >= ' ') && (c < 127)) { + if (state->debug_count < (DEBUG_MAX - 1)) { + state->debug_buf[state->debug_count++] = c; + state->pdata->uart_putc(state->pdev, c); + } + } else if ((c == 8) || (c == 127)) { + if (state->debug_count > 0) { + state->debug_count--; + state->pdata->uart_putc(state->pdev, 8); + state->pdata->uart_putc(state->pdev, ' '); + state->pdata->uart_putc(state->pdev, 8); + } + } else if ((c == 13) || (c == 10)) { + if (c == '\r' || (c == '\n' && last_c != '\r')) { + state->pdata->uart_putc(state->pdev, '\r'); + state->pdata->uart_putc(state->pdev, '\n'); + } + if (state->debug_count) { + state->debug_buf[state->debug_count] = 0; + state->debug_count = 0; + debug_exec(state, state->debug_buf, + regs, svc_sp); + } else { + debug_prompt(state); + } + } + last_c = c; + } + debug_uart_flush(state); + if (state->pdata->fiq_ack) + state->pdata->fiq_ack(state->pdev, state->fiq); + + /* poke sleep timer if necessary */ + if (state->debug_enable && !state->no_sleep) + debug_force_irq(state); + + atomic_set(&state->unhandled_fiq_count, 0); + state->in_fiq = false; +} + +static void debug_resume(struct fiq_glue_handler *h) +{ + struct fiq_debugger_state *state = + container_of(h, struct fiq_debugger_state, handler); + if (state->pdata->uart_resume) + state->pdata->uart_resume(state->pdev); +} + +#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) +struct tty_driver *debug_console_device(struct console *co, int *index) +{ + struct fiq_debugger_state *state; + state = container_of(co, struct fiq_debugger_state, console); + *index = 0; + return state->tty_driver; +} + +static void debug_console_write(struct console *co, + const char *s, unsigned int count) +{ + struct fiq_debugger_state *state; + + state = container_of(co, struct fiq_debugger_state, console); + + if (!state->console_enable) + return; + + while (count--) { + if (*s == '\n') + state->pdata->uart_putc(state->pdev, '\r'); + state->pdata->uart_putc(state->pdev, *s++); + } + debug_uart_flush(state); +} + +static struct console fiq_debugger_console = { + .name = "ttyFIQ", + .device = debug_console_device, + .write = debug_console_write, + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, +}; + +int fiq_tty_open(struct tty_struct *tty, struct file *filp) +{ + struct fiq_debugger_state *state = tty->driver->driver_state; + if (state->tty_open_count++) + return 0; + + tty->driver_data = state; + state->tty = tty; + return 0; +} + +void fiq_tty_close(struct tty_struct *tty, struct file *filp) +{ + struct fiq_debugger_state *state = tty->driver_data; + if (--state->tty_open_count) + return; + state->tty = NULL; +} + +int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + int i; + struct fiq_debugger_state *state = tty->driver_data; + + if (!state->console_enable) + return count; + + if (state->clk) + clk_enable(state->clk); + for (i = 0; i < count; i++) + state->pdata->uart_putc(state->pdev, *buf++); + if (state->clk) + clk_disable(state->clk); + + return count; +} + +int fiq_tty_write_room(struct tty_struct *tty) +{ + return 1024; +} + +static const struct tty_operations fiq_tty_driver_ops = { + .write = fiq_tty_write, + .write_room = fiq_tty_write_room, + .open = fiq_tty_open, + .close = fiq_tty_close, +}; + +static int fiq_debugger_tty_init(struct fiq_debugger_state *state) +{ + int ret = -EINVAL; + + state->tty_driver = alloc_tty_driver(1); + if (!state->tty_driver) { + pr_err("Failed to allocate fiq debugger tty\n"); + return -ENOMEM; + } + + state->tty_driver->owner = THIS_MODULE; + state->tty_driver->driver_name = "fiq-debugger"; + state->tty_driver->name = "ttyFIQ"; + state->tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + state->tty_driver->subtype = SERIAL_TYPE_NORMAL; + state->tty_driver->init_termios = tty_std_termios; + state->tty_driver->init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; + state->tty_driver->init_termios.c_ispeed = + state->tty_driver->init_termios.c_ospeed = 115200; + state->tty_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(state->tty_driver, &fiq_tty_driver_ops); + state->tty_driver->driver_state = state; + + ret = tty_register_driver(state->tty_driver); + if (ret) { + pr_err("Failed to register fiq tty: %d\n", ret); + goto err; + } + + state->tty_rbuf = fiq_debugger_ringbuf_alloc(1024); + if (!state->tty_rbuf) { + pr_err("Failed to allocate fiq debugger ringbuf\n"); + ret = -ENOMEM; + goto err; + } + + pr_info("Registered FIQ tty driver %p\n", state->tty_driver); + return 0; + +err: + fiq_debugger_ringbuf_free(state->tty_rbuf); + state->tty_rbuf = NULL; + put_tty_driver(state->tty_driver); + return ret; +} +#endif + +static int fiq_debugger_probe(struct platform_device *pdev) +{ + int ret; + struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev); + struct fiq_debugger_state *state; + + if (!pdata->uart_getc || !pdata->uart_putc || !pdata->fiq_enable) + return -EINVAL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + state->handler.fiq = debug_fiq; + state->handler.resume = debug_resume; + setup_timer(&state->sleep_timer, sleep_timer_expired, + (unsigned long)state); + state->pdata = pdata; + state->pdev = pdev; + state->no_sleep = initial_no_sleep; + state->debug_enable = initial_debug_enable; + state->console_enable = initial_console_enable; + + state->fiq = platform_get_irq_byname(pdev, "fiq"); + state->signal_irq = platform_get_irq_byname(pdev, "signal"); + state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); + + if (state->wakeup_irq < 0) + state->no_sleep = true; + state->ignore_next_wakeup_irq = !state->no_sleep; + + wake_lock_init(&state->debugger_wake_lock, + WAKE_LOCK_SUSPEND, "serial-debug"); + + state->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(state->clk)) + state->clk = NULL; + + if (state->clk) + clk_enable(state->clk); + + if (pdata->uart_init) { + ret = pdata->uart_init(pdev); + if (ret) + goto err_uart_init; + } + + debug_printf_nfiq(state, "<hit enter %sto activate fiq debugger>\n", + state->no_sleep ? "" : "twice "); + + ret = fiq_glue_register_handler(&state->handler); + if (ret) { + pr_err("serial_debugger: could not install fiq handler\n"); + goto err_register_fiq; + } + + pdata->fiq_enable(pdev, state->fiq, 1); + + if (state->clk) + clk_disable(state->clk); + + ret = request_irq(state->signal_irq, debug_irq, + IRQF_TRIGGER_RISING, "debug", state); + if (ret) + pr_err("serial_debugger: could not install signal_irq"); + + if (state->wakeup_irq >= 0) { + ret = request_irq(state->wakeup_irq, wakeup_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_DISABLED, + "debug-wakeup", state); + if (ret) { + pr_err("serial_debugger: " + "could not install wakeup irq\n"); + state->wakeup_irq = -1; + } else { + ret = enable_irq_wake(state->wakeup_irq); + if (ret) { + pr_err("serial_debugger: " + "could not enable wakeup\n"); + state->wakeup_irq_no_set_wake = true; + } + } + } + if (state->no_sleep) + wakeup_irq_handler(state->wakeup_irq, state); + +#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) + state->console = fiq_debugger_console; + register_console(&state->console); + fiq_debugger_tty_init(state); +#endif + return 0; + +err_register_fiq: + if (pdata->uart_free) + pdata->uart_free(pdev); +err_uart_init: + kfree(state); + if (state->clk) + clk_put(state->clk); + return ret; +} + +static struct platform_driver fiq_debugger_driver = { + .probe = fiq_debugger_probe, + .driver.name = "fiq_debugger", +}; + +static int __init fiq_debugger_init(void) +{ + return platform_driver_register(&fiq_debugger_driver); +} + +postcore_initcall(fiq_debugger_init); diff --git a/arch/arm/common/fiq_debugger_ringbuf.h b/arch/arm/common/fiq_debugger_ringbuf.h new file mode 100644 index 00000000000..2649b558108 --- /dev/null +++ b/arch/arm/common/fiq_debugger_ringbuf.h @@ -0,0 +1,94 @@ +/* + * arch/arm/common/fiq_debugger_ringbuf.c + * + * simple lockless ringbuffer + * + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> + +struct fiq_debugger_ringbuf { + int len; + int head; + int tail; + u8 buf[]; +}; + + +static inline struct fiq_debugger_ringbuf *fiq_debugger_ringbuf_alloc(int len) +{ + struct fiq_debugger_ringbuf *rbuf; + + rbuf = kzalloc(sizeof(*rbuf) + len, GFP_KERNEL); + if (rbuf == NULL) + return NULL; + + rbuf->len = len; + rbuf->head = 0; + rbuf->tail = 0; + smp_mb(); + + return rbuf; +} + +static inline void fiq_debugger_ringbuf_free(struct fiq_debugger_ringbuf *rbuf) +{ + kfree(rbuf); +} + +static inline int fiq_debugger_ringbuf_level(struct fiq_debugger_ringbuf *rbuf) +{ + int level = rbuf->head - rbuf->tail; + + if (level < 0) + level = rbuf->len + level; + + return level; +} + +static inline int fiq_debugger_ringbuf_room(struct fiq_debugger_ringbuf *rbuf) +{ + return rbuf->len - fiq_debugger_ringbuf_level(rbuf) - 1; +} + +static inline u8 +fiq_debugger_ringbuf_peek(struct fiq_debugger_ringbuf *rbuf, int i) +{ + return rbuf->buf[(rbuf->tail + i) % rbuf->len]; +} + +static inline int +fiq_debugger_ringbuf_consume(struct fiq_debugger_ringbuf *rbuf, int count) +{ + count = min(count, fiq_debugger_ringbuf_level(rbuf)); + + rbuf->tail = (rbuf->tail + count) % rbuf->len; + smp_mb(); + + return count; +} + +static inline int +fiq_debugger_ringbuf_push(struct fiq_debugger_ringbuf *rbuf, u8 datum) +{ + if (fiq_debugger_ringbuf_room(rbuf) == 0) + return 0; + + rbuf->buf[rbuf->head] = datum; + smp_mb(); + rbuf->head = (rbuf->head + 1) % rbuf->len; + smp_mb(); + + return 1; +} diff --git a/arch/arm/common/fiq_glue.S b/arch/arm/common/fiq_glue.S new file mode 100644 index 00000000000..9e3455a09f8 --- /dev/null +++ b/arch/arm/common/fiq_glue.S @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + + .global fiq_glue_end + + /* fiq stack: r0-r15,cpsr,spsr of interrupted mode */ + +ENTRY(fiq_glue) + /* store pc, cpsr from previous mode */ + mrs r12, spsr + sub r11, lr, #4 + subs r10, #1 + bne nested_fiq + + stmfd sp!, {r11-r12, lr} + + /* store r8-r14 from previous mode */ + sub sp, sp, #(7 * 4) + stmia sp, {r8-r14}^ + nop + + /* store r0-r7 from previous mode */ + stmfd sp!, {r0-r7} + + /* setup func(data,regs) arguments */ + mov r0, r9 + mov r1, sp + mov r3, r8 + + mov r7, sp + + /* Get sp and lr from non-user modes */ + and r4, r12, #MODE_MASK + cmp r4, #USR_MODE + beq fiq_from_usr_mode + + mov r7, sp + orr r4, r4, #(PSR_I_BIT | PSR_F_BIT) + msr cpsr_c, r4 + str sp, [r7, #(4 * 13)] + str lr, [r7, #(4 * 14)] + mrs r5, spsr + str r5, [r7, #(4 * 17)] + + cmp r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) + /* use fiq stack if we reenter this mode */ + subne sp, r7, #(4 * 3) + +fiq_from_usr_mode: + msr cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) + mov r2, sp + sub sp, r7, #12 + stmfd sp!, {r2, ip, lr} + /* call func(data,regs) */ + blx r3 + ldmfd sp, {r2, ip, lr} + mov sp, r2 + + /* restore/discard saved state */ + cmp r4, #USR_MODE + beq fiq_from_usr_mode_exit + + msr cpsr_c, r4 + ldr sp, [r7, #(4 * 13)] + ldr lr, [r7, #(4 * 14)] + msr spsr_cxsf, r5 + +fiq_from_usr_mode_exit: + msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) + + ldmfd sp!, {r0-r7} + add sp, sp, #(7 * 4) + ldmfd sp!, {r11-r12, lr} +exit_fiq: + msr spsr_cxsf, r12 + add r10, #1 + movs pc, r11 + +nested_fiq: + orr r12, r12, #(PSR_F_BIT) + b exit_fiq + +fiq_glue_end: + +ENTRY(fiq_glue_setup) /* func, data, sp */ + mrs r3, cpsr + msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) + movs r8, r0 + mov r9, r1 + mov sp, r2 + moveq r10, #0 + movne r10, #1 + msr cpsr_c, r3 + bx lr + diff --git a/arch/arm/common/fiq_glue_setup.c b/arch/arm/common/fiq_glue_setup.c new file mode 100644 index 00000000000..4044c7db95c --- /dev/null +++ b/arch/arm/common/fiq_glue_setup.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/percpu.h> +#include <linux/slab.h> +#include <asm/fiq.h> +#include <asm/fiq_glue.h> + +extern unsigned char fiq_glue, fiq_glue_end; +extern void fiq_glue_setup(void *func, void *data, void *sp); + +static struct fiq_handler fiq_debbuger_fiq_handler = { + .name = "fiq_glue", +}; +DEFINE_PER_CPU(void *, fiq_stack); +static struct fiq_glue_handler *current_handler; +static DEFINE_MUTEX(fiq_glue_lock); + +static void fiq_glue_setup_helper(void *info) +{ + struct fiq_glue_handler *handler = info; + fiq_glue_setup(handler->fiq, handler, + __get_cpu_var(fiq_stack) + THREAD_START_SP); +} + +int fiq_glue_register_handler(struct fiq_glue_handler *handler) +{ + int ret; + int cpu; + + if (!handler || !handler->fiq) + return -EINVAL; + + mutex_lock(&fiq_glue_lock); + if (fiq_stack) { + ret = -EBUSY; + goto err_busy; + } + + for_each_possible_cpu(cpu) { + void *stack; + stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); + if (WARN_ON(!stack)) { + ret = -ENOMEM; + goto err_alloc_fiq_stack; + } + per_cpu(fiq_stack, cpu) = stack; + } + + ret = claim_fiq(&fiq_debbuger_fiq_handler); + if (WARN_ON(ret)) + goto err_claim_fiq; + + current_handler = handler; + on_each_cpu(fiq_glue_setup_helper, handler, true); + set_fiq_handler(&fiq_glue, &fiq_glue_end - &fiq_glue); + + mutex_unlock(&fiq_glue_lock); + return 0; + +err_claim_fiq: +err_alloc_fiq_stack: + for_each_possible_cpu(cpu) { + __free_pages(per_cpu(fiq_stack, cpu), THREAD_SIZE_ORDER); + per_cpu(fiq_stack, cpu) = NULL; + } +err_busy: + mutex_unlock(&fiq_glue_lock); + return ret; +} + +/** + * fiq_glue_resume - Restore fiqs after suspend or low power idle states + * + * This must be called before calling local_fiq_enable after returning from a + * power state where the fiq mode registers were lost. If a driver provided + * a resume hook when it registered the handler it will be called. + */ + +void fiq_glue_resume(void) +{ + if (!current_handler) + return; + fiq_glue_setup(current_handler->fiq, current_handler, + __get_cpu_var(fiq_stack) + THREAD_START_SP); + if (current_handler->resume) + current_handler->resume(current_handler); +} + diff --git a/arch/arm/configs/android_omap3_defconfig b/arch/arm/configs/android_omap3_defconfig new file mode 100644 index 00000000000..56d0a74ce47 --- /dev/null +++ b/arch/arm/configs/android_omap3_defconfig @@ -0,0 +1,307 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_BLK_DEV_INITRD=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP3=y +# CONFIG_ARCH_OMAP4 is not set +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_32K_TIMER=y +CONFIG_MACH_OMAP_GENERIC=y +CONFIG_ARCH_OMAP3430=y +CONFIG_MACH_OMAP_H4=y +CONFIG_MACH_OMAP_APOLLON=y +CONFIG_MACH_OMAP_2430SDP=y +CONFIG_MACH_OMAP3_BEAGLE=y +CONFIG_MACH_DEVKIT8000=y +CONFIG_MACH_OMAP_LDP=y +CONFIG_MACH_OVERO=y +CONFIG_MACH_OMAP3EVM=y +CONFIG_MACH_OMAP3517EVM=y +CONFIG_MACH_OMAP3_PANDORA=y +CONFIG_MACH_OMAP3_TOUCHBOOK=y +CONFIG_MACH_OMAP_3430SDP=y +CONFIG_MACH_NOKIA_N8X0=y +CONFIG_MACH_NOKIA_RX51=y +CONFIG_MACH_OMAP_ZOOM2=y +CONFIG_MACH_OMAP_ZOOM3=y +CONFIG_MACH_CM_T35=y +CONFIG_MACH_IGEP0020=y +CONFIG_MACH_SBC3530=y +CONFIG_MACH_OMAP_3630SDP=y +CONFIG_MACH_OMAP_4430SDP=y +CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_ERRATA_411920=y +CONFIG_ASHMEM=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +# CONFIG_LOCAL_TIMERS is not set +CONFIG_AEABI=y +CONFIG_LEDS=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200" +CONFIG_KEXEC=y +CONFIG_FPE_NWFPE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_BINFMT_MISC=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_RUNTIME=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +# CONFIG_EARLYSUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_RC_PID=y +CONFIG_MAC80211_RC_DEFAULT_PID=y +CONFIG_MAC80211_LEDS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CONCAT=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_OOPS=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_OMAP2=y +CONFIG_MTD_ONENAND=y +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_ONENAND_OMAP2=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_EEPROM_LEGACY=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_MD=y +CONFIG_NETDEVICES=y +CONFIG_SMSC_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +CONFIG_KS8851=y +CONFIG_KS8851_MLL=y +CONFIG_LIBERTAS=y +CONFIG_LIBERTAS_USB=y +CONFIG_LIBERTAS_SDIO=y +CONFIG_LIBERTAS_DEBUG=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_TWL4030=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_TWL4030_PWRBUTTON=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_OMAP=y +CONFIG_SPI=y +CONFIG_SPI_OMAP24XX=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_TWL4030=y +CONFIG_W1=y +CONFIG_POWER_SUPPLY=y +CONFIG_WATCHDOG=y +CONFIG_OMAP_WATCHDOG=y +CONFIG_TWL4030_WATCHDOG=y +CONFIG_MENELAUS=y +CONFIG_TWL4030_CORE=y +CONFIG_TWL4030_POWER=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_TWL4030=y +CONFIG_REGULATOR_TPS65023=y +CONFIG_REGULATOR_TPS6507X=y +CONFIG_FB=y +CONFIG_OMAP2_VRAM=y +CONFIG_OMAP2_VRFB=y +CONFIG_OMAP2_DSS=y +CONFIG_OMAP2_VRAM_SIZE=4 +CONFIG_OMAP2_DSS_DPI=y +CONFIG_OMAP2_DSS_VENC=y +CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 +CONFIG_FB_OMAP2=y +CONFIG_FB_OMAP2_NUM_FBS=1 +CONFIG_PANEL_GENERIC_DPI=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_OMAP_LCD_VGA=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_PLATFORM=y +CONFIG_DISPLAY_SUPPORT=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_DEBUG=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_OMAP_SOC=y +CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_MON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_HCD_OMAP=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_OMAP2PLUS=y +CONFIG_USB_MUSB_OTG=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_MUSB_HDRC_HCD=y +CONFIG_MUSB_PIO_ONLY=y +CONFIG_USB_MUSB_DEBUG=y +CONFIG_USB_TUSB_OMAP_DMA=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_TEST=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_ANDROID=y +CONFIG_USB_ANDROID_ACM=y +CONFIG_USB_ANDROID_ADB=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_ANDROID_MASS_STORAGE=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_SDIO_UART=y +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP_HS=y +CONFIG_SWITCH=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_TWL92330=y +CONFIG_RTC_DRV_TWL4030=y +CONFIG_STAGING=y +# CONFIG_STAGING_EXCLUDE_BUILD is not set +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_BTRFS_FS=y +CONFIG_INOTIFY=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RUBIN=y +CONFIG_UBIFS_FS=y +CONFIG_CRAMFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_PROVE_LOCKING=y +# CONFIG_LOCK_STAT is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_SECURITY=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRC_CCITT=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y +CONFIG_LIBCRC32C=y diff --git a/arch/arm/configs/android_omap4_defconfig b/arch/arm/configs/android_omap4_defconfig new file mode 100644 index 00000000000..2a293ab527b --- /dev/null +++ b/arch/arm/configs/android_omap4_defconfig @@ -0,0 +1,307 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_BLK_DEV_INITRD=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP3=y +CONFIG_ARCH_OMAP4=y +# CONFIG_OMAP_RESET_CLOCKS is not set +CONFIG_OMAP_32K_TIMER=y +CONFIG_MACH_OMAP_GENERIC=y +CONFIG_ARCH_OMAP3430=y +CONFIG_MACH_OMAP_H4=y +CONFIG_MACH_OMAP_APOLLON=y +CONFIG_MACH_OMAP_2430SDP=y +CONFIG_MACH_OMAP3_BEAGLE=y +CONFIG_MACH_DEVKIT8000=y +CONFIG_MACH_OMAP_LDP=y +CONFIG_MACH_OVERO=y +CONFIG_MACH_OMAP3EVM=y +CONFIG_MACH_OMAP3517EVM=y +CONFIG_MACH_OMAP3_PANDORA=y +CONFIG_MACH_OMAP3_TOUCHBOOK=y +CONFIG_MACH_OMAP_3430SDP=y +CONFIG_MACH_NOKIA_N8X0=y +CONFIG_MACH_NOKIA_RX51=y +CONFIG_MACH_OMAP_ZOOM2=y +CONFIG_MACH_OMAP_ZOOM3=y +CONFIG_MACH_CM_T35=y +CONFIG_MACH_IGEP0020=y +CONFIG_MACH_SBC3530=y +CONFIG_MACH_OMAP_3630SDP=y +CONFIG_MACH_OMAP_4430SDP=y +CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_ERRATA_411920=y +CONFIG_ASHMEM=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +# CONFIG_LOCAL_TIMERS is not set +CONFIG_AEABI=y +CONFIG_LEDS=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200" +CONFIG_KEXEC=y +CONFIG_FPE_NWFPE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_BINFMT_MISC=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_RUNTIME=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +# CONFIG_EARLYSUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_RC_PID=y +CONFIG_MAC80211_RC_DEFAULT_PID=y +CONFIG_MAC80211_LEDS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CONCAT=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_OOPS=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_OMAP2=y +CONFIG_MTD_ONENAND=y +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_ONENAND_OMAP2=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_EEPROM_LEGACY=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_MD=y +CONFIG_NETDEVICES=y +CONFIG_SMSC_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +CONFIG_KS8851=y +CONFIG_KS8851_MLL=y +CONFIG_LIBERTAS=y +CONFIG_LIBERTAS_USB=y +CONFIG_LIBERTAS_SDIO=y +CONFIG_LIBERTAS_DEBUG=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_TWL4030=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_TWL4030_PWRBUTTON=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_OMAP=y +CONFIG_SPI=y +CONFIG_SPI_OMAP24XX=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_TWL4030=y +CONFIG_W1=y +CONFIG_POWER_SUPPLY=y +CONFIG_WATCHDOG=y +CONFIG_OMAP_WATCHDOG=y +CONFIG_TWL4030_WATCHDOG=y +CONFIG_MENELAUS=y +CONFIG_TWL4030_CORE=y +CONFIG_TWL4030_POWER=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_TWL4030=y +CONFIG_REGULATOR_TPS65023=y +CONFIG_REGULATOR_TPS6507X=y +CONFIG_FB=y +CONFIG_OMAP2_VRAM=y +CONFIG_OMAP2_VRFB=y +CONFIG_OMAP2_DSS=y +CONFIG_OMAP2_VRAM_SIZE=4 +CONFIG_OMAP2_DSS_DPI=y +# CONFIG_OMAP2_DSS_VENC is not set +CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 +CONFIG_FB_OMAP2=y +CONFIG_FB_OMAP2_NUM_FBS=1 +CONFIG_PANEL_GENERIC_DPI=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_OMAP_LCD_VGA=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_PLATFORM=y +CONFIG_DISPLAY_SUPPORT=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_DEBUG=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_OMAP_SOC=y +CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_MON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_HCD_OMAP=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_OMAP2PLUS=y +CONFIG_USB_MUSB_OTG=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_MUSB_HDRC_HCD=y +CONFIG_MUSB_PIO_ONLY=y +CONFIG_USB_MUSB_DEBUG=y +CONFIG_USB_TUSB_OMAP_DMA=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_TEST=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_ANDROID=y +CONFIG_USB_ANDROID_ACM=y +CONFIG_USB_ANDROID_ADB=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_ANDROID_MASS_STORAGE=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_SDIO_UART=y +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP_HS=y +CONFIG_SWITCH=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_TWL92330=y +CONFIG_RTC_DRV_TWL4030=y +CONFIG_STAGING=y +# CONFIG_STAGING_EXCLUDE_BUILD is not set +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_BTRFS_FS=y +CONFIG_INOTIFY=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RUBIN=y +CONFIG_UBIFS_FS=y +CONFIG_CRAMFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_PROVE_LOCKING=y +# CONFIG_LOCK_STAT is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_SECURITY=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRC_CCITT=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y +CONFIG_LIBCRC32C=y diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index c8b12f2782f..9bba2c91e99 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -9,6 +9,7 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y +CONFIG_ASHMEM=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y CONFIG_SLAB=y @@ -41,6 +42,7 @@ CONFIG_SMP=y CONFIG_NR_CPUS=2 CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_HIGHMEM=y CONFIG_CMDLINE="root=/dev/ram0 init=init rw console=ttyAMA2,115200n8 mem=256M initrd=0x800000,72M" CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y @@ -55,6 +57,7 @@ CONFIG_FPE_NWFPE=y CONFIG_VFP=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_WAKELOCK=y CONFIG_PM_RUNTIME=y CONFIG_NET=y CONFIG_PACKET=y @@ -148,7 +151,6 @@ CONFIG_SPI=y # CONFIG_STM_MSP_SPI is not set CONFIG_SPI_PL022=y CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_STMPE=y CONFIG_GPIO_TC3589X=y CONFIG_GPIO_AB8500=y CONFIG_POWER_SUPPLY=y @@ -200,17 +202,12 @@ CONFIG_USB_STORAGE=y CONFIG_USB_LIBUSUAL=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 -CONFIG_USB_ZERO=m -CONFIG_USB_ETH=m -CONFIG_USB_MASS_STORAGE=m -CONFIG_USB_G_SERIAL=m -CONFIG_USB_CDC_COMPOSITE=m -CONFIG_USB_G_MULTI=m -# CONFIG_USB_G_MULTI_RNDIS is not set +CONFIG_USB_G_ANDROID=y CONFIG_AB8500_USB=y CONFIG_MMC=y CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_CLKGATE=y +CONFIG_MMC_PARANOID_SD_INIT=y # CONFIG_MMC_BLOCK_BOUNCE is not set CONFIG_MMC_ARMMMCI=y CONFIG_NEW_LEDS=y @@ -219,6 +216,7 @@ CONFIG_LEDS_LM3530=y CONFIG_LEDS_LP5521=y CONFIG_LEDS_PWM=y CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_SWITCH=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_AB=y CONFIG_RTC_DRV_AB8500=y @@ -226,6 +224,12 @@ CONFIG_DMADEVICES=y CONFIG_STE_DMA40=y CONFIG_STAGING=y CONFIG_AB5500_SIM=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y CONFIG_CG2900=y CONFIG_CG2900_CHIP=y diff --git a/arch/arm/configs/u8500_snowball_android_defconfig b/arch/arm/configs/u8500_snowball_android_defconfig new file mode 100644 index 00000000000..c35e93dc39e --- /dev/null +++ b/arch/arm/configs/u8500_snowball_android_defconfig @@ -0,0 +1,286 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_ASHMEM=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +CONFIG_SLAB=y +CONFIG_BOOTTIME=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_ARCH_U8500=y +CONFIG_UX500_SOC_DB8500=y +CONFIG_MACH_HREFV60=y +CONFIG_MACH_SNOWBALL=y +CONFIG_UX500_PRCMU_TIMER=y +# CONFIG_DISPLAY_GENERIC_PRIMARY is not set +CONFIG_DISPLAY_AV8100_TERTIARY=y +CONFIG_UX500_SUSPEND=y +CONFIG_UX500_SUSPEND_STANDBY=y +CONFIG_UX500_SUSPEND_MEM=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMDLINE="root=/dev/ram0 init=init rw console=ttyAMA2,115200n8 mem=256M initrd=0x800000,72M" +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_FPE_NWFPE=y +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_IPV6_SIT is not set +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER=m +CONFIG_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_NET_SCHED=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_CFG80211=m +CONFIG_MAC80211=m +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_NET_9P=y +CONFIG_CAIF=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_STANDALONE is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=73728 +CONFIG_MISC_DEVICES=y +CONFIG_AB8500_PWM=y +CONFIG_DISPDEV=y +CONFIG_STM_TRACE=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_TUN=y +CONFIG_SMSC_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_SMSC911X=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_NOMADIK_SKE=y +CONFIG_KEYBOARD_TC3589X=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_BU21013=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_AB8500_PONKEY=y +CONFIG_INPUT_UINPUT=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_NOMADIK=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_NOMADIK=y +CONFIG_SPI=y +# CONFIG_STM_MSP_SPI is not set +CONFIG_SPI_PL022=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_TC3589X=y +CONFIG_GPIO_AB8500=y +CONFIG_POWER_SUPPLY=y +CONFIG_AB8500_BM=y +CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL=y +CONFIG_SENSORS_AB8500=y +CONFIG_SENSORS_DB8500=y +CONFIG_SENSORS_LSM303DLH=y +CONFIG_SENSORS_L3G4200D=y +CONFIG_WATCHDOG=y +CONFIG_MFD_TC3589X=y +CONFIG_AB8500_CORE=y +CONFIG_REGULATOR_DEBUG=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_AB8500=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +# CONFIG_VIDEO_CAPTURE_DRIVERS is not set +CONFIG_FB=y +CONFIG_FB_MCDE=y +CONFIG_MCDE_DISPLAY_GENERIC_DSI=y +CONFIG_AV8100_HWTRIG_I2SDAT3=y +CONFIG_FB_B2R2=y +CONFIG_B2R2_PLUG_CONF=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_UX500=y +CONFIG_SND_SOC_UX500_CG29XX=y +CONFIG_SND_SOC_UX500_AV8100=y +CONFIG_USB=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_MON=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_UX500=y +CONFIG_USB_MUSB_OTG=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_G_ANDROID=y +CONFIG_AB8500_USB=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_PARANOID_SD_INIT=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_ARMMMCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_AB8500=y +CONFIG_DMADEVICES=y +CONFIG_STE_DMA40=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y +CONFIG_CG2900=y +CONFIG_CG2900_CHIP=y +CONFIG_STLC2690_CHIP=y +CONFIG_CG2900_UART=y +CONFIG_CG2900_AUDIO=y +CONFIG_CG2900_TEST=y +CONFIG_BT_CG2900=y +CONFIG_U8500_CM=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=m +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HFS_FS=m +CONFIG_BEFS_FS=m +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_CIFS=y +CONFIG_9P_FS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_BLKDEV_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_SGI_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +CONFIG_DEBUG_INFO=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_FUNCTION_TRACER=y +CONFIG_DEBUG_USER=y +CONFIG_KEYS=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_UX500=y +CONFIG_CRYPTO_DEV_UX500_CRYP=y +CONFIG_CRYPTO_DEV_UX500_HASH=y +CONFIG_CRC7=y +CONFIG_LIBCRC32C=m diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index a4bf3199819..bbaeaef03b0 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -264,7 +264,7 @@ extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr * Harvard caches are synchronised for the user space address range. * This is used for the ARM private sys_cacheflush system call. */ -#define flush_cache_user_range(vma,start,end) \ +#define flush_cache_user_range(start,end) \ __cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end)) /* diff --git a/arch/arm/include/asm/fiq_debugger.h b/arch/arm/include/asm/fiq_debugger.h new file mode 100644 index 00000000000..e711b57b22f --- /dev/null +++ b/arch/arm/include/asm/fiq_debugger.h @@ -0,0 +1,46 @@ +/* + * arch/arm/include/asm/fiq_debugger.h + * + * Copyright (C) 2010 Google, Inc. + * Author: Colin Cross <ccross@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_ +#define _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_ + +#include <linux/serial_core.h> + +#define FIQ_DEBUGGER_NO_CHAR NO_POLL_CHAR +#define FIQ_DEBUGGER_BREAK 0x00ff0100 + +#define FIQ_DEBUGGER_FIQ_IRQ_NAME "fiq" +#define FIQ_DEBUGGER_SIGNAL_IRQ_NAME "signal" +#define FIQ_DEBUGGER_WAKEUP_IRQ_NAME "wakeup" + +struct fiq_debugger_pdata { + int (*uart_init)(struct platform_device *pdev); + void (*uart_free)(struct platform_device *pdev); + int (*uart_resume)(struct platform_device *pdev); + int (*uart_getc)(struct platform_device *pdev); + void (*uart_putc)(struct platform_device *pdev, unsigned int c); + void (*uart_flush)(struct platform_device *pdev); + + void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq, + bool enable); + void (*fiq_ack)(struct platform_device *pdev, unsigned int fiq); + + void (*force_irq)(struct platform_device *pdev, unsigned int irq); + void (*force_irq_ack)(struct platform_device *pdev, unsigned int irq); +}; + +#endif diff --git a/arch/arm/include/asm/fiq_glue.h b/arch/arm/include/asm/fiq_glue.h new file mode 100644 index 00000000000..d54c29db97a --- /dev/null +++ b/arch/arm/include/asm/fiq_glue.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_FIQ_GLUE_H +#define __ASM_FIQ_GLUE_H + +struct fiq_glue_handler { + void (*fiq)(struct fiq_glue_handler *h, void *regs, void *svc_sp); + void (*resume)(struct fiq_glue_handler *h); +}; + +int fiq_glue_register_handler(struct fiq_glue_handler *handler); + +#ifdef CONFIG_FIQ_GLUE +void fiq_glue_resume(void); +#else +static inline void fiq_glue_resume(void) {} +#endif + +#endif diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h index 7ecd793b8f5..6643d6c4f35 100644 --- a/arch/arm/include/asm/hardware/coresight.h +++ b/arch/arm/include/asm/hardware/coresight.h @@ -17,15 +17,17 @@ #define TRACER_ACCESSED_BIT 0 #define TRACER_RUNNING_BIT 1 #define TRACER_CYCLE_ACC_BIT 2 +#define TRACER_TRACE_DATA_BIT 3 #define TRACER_ACCESSED BIT(TRACER_ACCESSED_BIT) #define TRACER_RUNNING BIT(TRACER_RUNNING_BIT) #define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT) +#define TRACER_TRACE_DATA BIT(TRACER_TRACE_DATA_BIT) #define TRACER_TIMEOUT 10000 -#define etm_writel(t, v, x) \ - (__raw_writel((v), (t)->etm_regs + (x))) -#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x))) +#define etm_writel(t, id, v, x) \ + (__raw_writel((v), (t)->etm_regs[(id)] + (x))) +#define etm_readl(t, id, x) (__raw_readl((t)->etm_regs[(id)] + (x))) /* CoreSight Management Registers */ #define CSMR_LOCKACCESS 0xfb0 @@ -113,11 +115,19 @@ #define ETMR_TRACEENCTRL 0x24 #define ETMTE_INCLEXCL BIT(24) #define ETMR_TRACEENEVT 0x20 + +#define ETMR_VIEWDATAEVT 0x30 +#define ETMR_VIEWDATACTRL1 0x34 +#define ETMR_VIEWDATACTRL2 0x38 +#define ETMR_VIEWDATACTRL3 0x3c +#define ETMVDC3_EXCLONLY BIT(16) + #define ETMCTRL_OPTS (ETMCTRL_DO_CPRT | \ - ETMCTRL_DATA_DO_ADDR | \ ETMCTRL_BRANCH_OUTPUT | \ ETMCTRL_DO_CONTEXTID) +#define ETMR_TRACEIDR 0x200 + /* ETM management registers, "ETM Architecture", 3.5.24 */ #define ETMMR_OSLAR 0x300 #define ETMMR_OSLSR 0x304 @@ -140,14 +150,16 @@ #define ETBFF_TRIGIN BIT(8) #define ETBFF_TRIGEVT BIT(9) #define ETBFF_TRIGFL BIT(10) +#define ETBFF_STOPFL BIT(12) #define etb_writel(t, v, x) \ (__raw_writel((v), (t)->etb_regs + (x))) #define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x))) -#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0) -#define etm_unlock(t) \ - do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0) +#define etm_lock(t, id) \ + do { etm_writel((t), (id), 0, CSMR_LOCKACCESS); } while (0) +#define etm_unlock(t, id) \ + do { etm_writel((t), (id), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0) #define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0) #define etb_unlock(t) \ diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h new file mode 100644 index 00000000000..bca864ac945 --- /dev/null +++ b/arch/arm/include/asm/mach/mmc.h @@ -0,0 +1,28 @@ +/* + * arch/arm/include/asm/mach/mmc.h + */ +#ifndef ASMARM_MACH_MMC_H +#define ASMARM_MACH_MMC_H + +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/mmc/sdio_func.h> + +struct embedded_sdio_data { + struct sdio_cis cis; + struct sdio_cccr cccr; + struct sdio_embedded_func *funcs; + int num_funcs; +}; + +struct mmc_platform_data { + unsigned int ocr_mask; /* available voltages */ + int built_in; /* built-in device flag */ + int card_present; /* card detect state */ + u32 (*translate_vdd)(struct device *, unsigned int); + unsigned int (*status)(struct device *); + struct embedded_sdio_data *embedded_sdio; + int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); +}; + +#endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 8f9ab5c9015..a3fbdff58b2 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -496,7 +496,7 @@ __und_usr: blo __und_usr_unknown 3: ldrht r0, [r4] add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 - orr r0, r0, r5, lsl #16 + orr r0, r0, r5, lsl #16 #else b __und_usr_unknown #endif diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c index 1bec8b5f22f..496b8b84e45 100644 --- a/arch/arm/kernel/etm.c +++ b/arch/arm/kernel/etm.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/io.h> +#include <linux/slab.h> #include <linux/sysrq.h> #include <linux/device.h> #include <linux/clk.h> @@ -36,26 +37,36 @@ MODULE_AUTHOR("Alexander Shishkin"); struct tracectx { unsigned int etb_bufsz; void __iomem *etb_regs; - void __iomem *etm_regs; + void __iomem **etm_regs; + int etm_regs_count; unsigned long flags; int ncmppairs; int etm_portsz; + u32 etb_fc; + unsigned long range_start; + unsigned long range_end; + unsigned long data_range_start; + unsigned long data_range_end; + bool dump_initial_etb; struct device *dev; struct clk *emu_clk; struct mutex mutex; }; -static struct tracectx tracer; +static struct tracectx tracer = { + .range_start = (unsigned long)_stext, + .range_end = (unsigned long)_etext, +}; static inline bool trace_isrunning(struct tracectx *t) { return !!(t->flags & TRACER_RUNNING); } -static int etm_setup_address_range(struct tracectx *t, int n, +static int etm_setup_address_range(struct tracectx *t, int id, int n, unsigned long start, unsigned long end, int exclude, int data) { - u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \ + u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY | ETMAAT_NOVALCMP; if (n < 1 || n > t->ncmppairs) @@ -71,95 +82,155 @@ static int etm_setup_address_range(struct tracectx *t, int n, flags |= ETMAAT_IEXEC; /* first comparator for the range */ - etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2)); - etm_writel(t, start, ETMR_COMP_VAL(n * 2)); + etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2)); + etm_writel(t, id, start, ETMR_COMP_VAL(n * 2)); /* second comparator is right next to it */ - etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1)); - etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1)); - - flags = exclude ? ETMTE_INCLEXCL : 0; - etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL); + etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1)); + etm_writel(t, id, end, ETMR_COMP_VAL(n * 2 + 1)); + + if (data) { + flags = exclude ? ETMVDC3_EXCLONLY : 0; + if (exclude) + n += 8; + etm_writel(t, id, flags | BIT(n), ETMR_VIEWDATACTRL3); + } else { + flags = exclude ? ETMTE_INCLEXCL : 0; + etm_writel(t, id, flags | (1 << n), ETMR_TRACEENCTRL); + } return 0; } -static int trace_start(struct tracectx *t) +static int trace_start_etm(struct tracectx *t, int id) { u32 v; unsigned long timeout = TRACER_TIMEOUT; - etb_unlock(t); - - etb_writel(t, 0, ETBR_FORMATTERCTRL); - etb_writel(t, 1, ETBR_CTRL); - - etb_lock(t); - - /* configure etm */ v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz); if (t->flags & TRACER_CYCLE_ACC) v |= ETMCTRL_CYCLEACCURATE; - etm_unlock(t); + if (t->flags & TRACER_TRACE_DATA) + v |= ETMCTRL_DATA_DO_ADDR; + + etm_unlock(t, id); - etm_writel(t, v, ETMR_CTRL); + etm_writel(t, id, v, ETMR_CTRL); - while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) + while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) ; if (!timeout) { dev_dbg(t->dev, "Waiting for progbit to assert timed out\n"); - etm_lock(t); + etm_lock(t, id); return -EFAULT; } - etm_setup_address_range(t, 1, (unsigned long)_stext, - (unsigned long)_etext, 0, 0); - etm_writel(t, 0, ETMR_TRACEENCTRL2); - etm_writel(t, 0, ETMR_TRACESSCTRL); - etm_writel(t, 0x6f, ETMR_TRACEENEVT); + if (t->range_start || t->range_end) + etm_setup_address_range(t, id, 1, + t->range_start, t->range_end, 0, 0); + else + etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL); + + etm_writel(t, id, 0, ETMR_TRACEENCTRL2); + etm_writel(t, id, 0, ETMR_TRACESSCTRL); + etm_writel(t, id, 0x6f, ETMR_TRACEENEVT); + + etm_writel(t, id, 0, ETMR_VIEWDATACTRL1); + etm_writel(t, id, 0, ETMR_VIEWDATACTRL2); + + if (t->data_range_start || t->data_range_end) + etm_setup_address_range(t, id, 2, t->data_range_start, + t->data_range_end, 0, 1); + else + etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3); + + etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT); v &= ~ETMCTRL_PROGRAM; v |= ETMCTRL_PORTSEL; - etm_writel(t, v, ETMR_CTRL); + etm_writel(t, id, v, ETMR_CTRL); timeout = TRACER_TIMEOUT; - while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout) + while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout) ; if (!timeout) { dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n"); - etm_lock(t); + etm_lock(t, id); return -EFAULT; } - etm_lock(t); + etm_lock(t, id); + return 0; +} + +static int trace_start(struct tracectx *t) +{ + int ret; + int id; + u32 etb_fc = t->etb_fc; + + etb_unlock(t); + + t->dump_initial_etb = false; + etb_writel(t, 0, ETBR_WRITEADDR); + etb_writel(t, etb_fc, ETBR_FORMATTERCTRL); + etb_writel(t, 1, ETBR_CTRL); + + etb_lock(t); + + /* configure etm(s) */ + for (id = 0; id < t->etm_regs_count; id++) { + ret = trace_start_etm(t, id); + if (ret) + return ret; + } t->flags |= TRACER_RUNNING; return 0; } -static int trace_stop(struct tracectx *t) +static int trace_stop_etm(struct tracectx *t, int id) { unsigned long timeout = TRACER_TIMEOUT; - etm_unlock(t); + etm_unlock(t, id); - etm_writel(t, 0x440, ETMR_CTRL); - while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) + etm_writel(t, id, 0x441, ETMR_CTRL); + while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) ; if (!timeout) { dev_dbg(t->dev, "Waiting for progbit to assert timed out\n"); - etm_lock(t); + etm_lock(t, id); return -EFAULT; } - etm_lock(t); + etm_lock(t, id); + return 0; +} + +static int trace_stop(struct tracectx *t) +{ + int id; + int ret; + unsigned long timeout = TRACER_TIMEOUT; + u32 etb_fc = t->etb_fc; + + for (id = 0; id < t->etm_regs_count; id++) { + ret = trace_stop_etm(t, id); + if (ret) + return ret; + } etb_unlock(t); - etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL); + if (etb_fc) { + etb_fc |= ETBFF_STOPFL; + etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL); + } + etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL); timeout = TRACER_TIMEOUT; while (etb_readl(t, ETBR_FORMATTERCTRL) & @@ -184,24 +255,15 @@ static int trace_stop(struct tracectx *t) static int etb_getdatalen(struct tracectx *t) { u32 v; - int rp, wp; + int wp; v = etb_readl(t, ETBR_STATUS); if (v & 1) return t->etb_bufsz; - rp = etb_readl(t, ETBR_READADDR); wp = etb_readl(t, ETBR_WRITEADDR); - - if (rp > wp) { - etb_writel(t, 0, ETBR_READADDR); - etb_writel(t, 0, ETBR_WRITEADDR); - - return 0; - } - - return wp - rp; + return wp; } /* sysrq+v will always stop the running trace and leave it at that */ @@ -234,21 +296,18 @@ static void etm_dump(void) printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM))); printk(KERN_INFO "\n--- ETB buffer end ---\n"); - /* deassert the overflow bit */ - etb_writel(t, 1, ETBR_CTRL); - etb_writel(t, 0, ETBR_CTRL); - - etb_writel(t, 0, ETBR_TRIGGERCOUNT); - etb_writel(t, 0, ETBR_READADDR); - etb_writel(t, 0, ETBR_WRITEADDR); - etb_lock(t); } static void sysrq_etm_dump(int key) { + if (!mutex_trylock(&tracer.mutex)) { + printk(KERN_INFO "Tracing hardware busy\n"); + return; + } dev_dbg(tracer.dev, "Dumping ETB buffer\n"); etm_dump(); + mutex_unlock(&tracer.mutex); } static struct sysrq_key_op sysrq_etm_op = { @@ -275,6 +334,10 @@ static ssize_t etb_read(struct file *file, char __user *data, struct tracectx *t = file->private_data; u32 first = 0; u32 *buf; + int wpos; + int skip; + long wlength; + loff_t pos = *ppos; mutex_lock(&t->mutex); @@ -286,31 +349,39 @@ static ssize_t etb_read(struct file *file, char __user *data, etb_unlock(t); total = etb_getdatalen(t); + if (total == 0 && t->dump_initial_etb) + total = t->etb_bufsz; if (total == t->etb_bufsz) first = etb_readl(t, ETBR_WRITEADDR); + if (pos > total * 4) { + skip = 0; + wpos = total; + } else { + skip = (int)pos % 4; + wpos = (int)pos / 4; + } + total -= wpos; + first = (first + wpos) % t->etb_bufsz; + etb_writel(t, first, ETBR_READADDR); - length = min(total * 4, (int)len); - buf = vmalloc(length); + wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4)); + length = min(total * 4 - skip, (int)len); + buf = vmalloc(wlength * 4); - dev_dbg(t->dev, "ETB buffer length: %d\n", total); + dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n", + length, pos, wlength, first); + dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos); dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS)); - for (i = 0; i < length / 4; i++) + for (i = 0; i < wlength; i++) buf[i] = etb_readl(t, ETBR_READMEM); - /* the only way to deassert overflow bit in ETB status is this */ - etb_writel(t, 1, ETBR_CTRL); - etb_writel(t, 0, ETBR_CTRL); - - etb_writel(t, 0, ETBR_WRITEADDR); - etb_writel(t, 0, ETBR_READADDR); - etb_writel(t, 0, ETBR_TRIGGERCOUNT); - etb_lock(t); - length -= copy_to_user(data, buf, length); + length -= copy_to_user(data, (u8 *)buf + skip, length); vfree(buf); + *ppos = pos + length; out: mutex_unlock(&t->mutex); @@ -347,28 +418,17 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id if (ret) goto out; + mutex_lock(&t->mutex); t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res)); if (!t->etb_regs) { ret = -ENOMEM; goto out_release; } + t->dev = &dev->dev; + t->dump_initial_etb = true; amba_set_drvdata(dev, t); - etb_miscdev.parent = &dev->dev; - - ret = misc_register(&etb_miscdev); - if (ret) - goto out_unmap; - - t->emu_clk = clk_get(&dev->dev, "emu_src_ck"); - if (IS_ERR(t->emu_clk)) { - dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n"); - return -EFAULT; - } - - clk_enable(t->emu_clk); - etb_unlock(t); t->etb_bufsz = etb_readl(t, ETBR_DEPTH); dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz); @@ -377,6 +437,20 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id etb_writel(t, 0, ETBR_CTRL); etb_writel(t, 0x1000, ETBR_FORMATTERCTRL); etb_lock(t); + mutex_unlock(&t->mutex); + + etb_miscdev.parent = &dev->dev; + + ret = misc_register(&etb_miscdev); + if (ret) + goto out_unmap; + + /* Get optional clock. Currently used to select clock source on omap3 */ + t->emu_clk = clk_get(&dev->dev, "emu_src_ck"); + if (IS_ERR(t->emu_clk)) + dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n"); + else + clk_enable(t->emu_clk); dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n"); @@ -384,10 +458,13 @@ out: return ret; out_unmap: + mutex_lock(&t->mutex); amba_set_drvdata(dev, NULL); iounmap(t->etb_regs); + t->etb_regs = NULL; out_release: + mutex_unlock(&t->mutex); amba_release_regions(dev); return ret; @@ -402,8 +479,10 @@ static int etb_remove(struct amba_device *dev) iounmap(t->etb_regs); t->etb_regs = NULL; - clk_disable(t->emu_clk); - clk_put(t->emu_clk); + if (!IS_ERR(t->emu_clk)) { + clk_disable(t->emu_clk); + clk_put(t->emu_clk); + } amba_release_regions(dev); @@ -447,7 +526,10 @@ static ssize_t trace_running_store(struct kobject *kobj, return -EINVAL; mutex_lock(&tracer.mutex); - ret = value ? trace_start(&tracer) : trace_stop(&tracer); + if (!tracer.etb_regs) + ret = -ENODEV; + else + ret = value ? trace_start(&tracer) : trace_stop(&tracer); mutex_unlock(&tracer.mutex); return ret ? : n; @@ -462,36 +544,50 @@ static ssize_t trace_info_show(struct kobject *kobj, { u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st; int datalen; + int id; + int ret; - etb_unlock(&tracer); - datalen = etb_getdatalen(&tracer); - etb_wa = etb_readl(&tracer, ETBR_WRITEADDR); - etb_ra = etb_readl(&tracer, ETBR_READADDR); - etb_st = etb_readl(&tracer, ETBR_STATUS); - etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL); - etb_lock(&tracer); - - etm_unlock(&tracer); - etm_ctrl = etm_readl(&tracer, ETMR_CTRL); - etm_st = etm_readl(&tracer, ETMR_STATUS); - etm_lock(&tracer); + mutex_lock(&tracer.mutex); + if (tracer.etb_regs) { + etb_unlock(&tracer); + datalen = etb_getdatalen(&tracer); + etb_wa = etb_readl(&tracer, ETBR_WRITEADDR); + etb_ra = etb_readl(&tracer, ETBR_READADDR); + etb_st = etb_readl(&tracer, ETBR_STATUS); + etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL); + etb_lock(&tracer); + } else { + etb_wa = etb_ra = etb_st = etb_fc = ~0; + datalen = -1; + } - return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n" + ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n" "ETBR_WRITEADDR:\t%08x\n" "ETBR_READADDR:\t%08x\n" "ETBR_STATUS:\t%08x\n" - "ETBR_FORMATTERCTRL:\t%08x\n" - "ETMR_CTRL:\t%08x\n" - "ETMR_STATUS:\t%08x\n", + "ETBR_FORMATTERCTRL:\t%08x\n", datalen, tracer.ncmppairs, etb_wa, etb_ra, etb_st, - etb_fc, + etb_fc + ); + + for (id = 0; id < tracer.etm_regs_count; id++) { + etm_unlock(&tracer, id); + etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL); + etm_st = etm_readl(&tracer, id, ETMR_STATUS); + etm_lock(&tracer, id); + ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n" + "ETMR_STATUS:\t%08x\n", etm_ctrl, etm_st ); + } + mutex_unlock(&tracer.mutex); + + return ret; } static struct kobj_attribute trace_info_attr = @@ -530,42 +626,121 @@ static ssize_t trace_mode_store(struct kobject *kobj, static struct kobj_attribute trace_mode_attr = __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store); +static ssize_t trace_range_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%08lx %08lx\n", + tracer.range_start, tracer.range_end); +} + +static ssize_t trace_range_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long range_start, range_end; + + if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2) + return -EINVAL; + + mutex_lock(&tracer.mutex); + tracer.range_start = range_start; + tracer.range_end = range_end; + mutex_unlock(&tracer.mutex); + + return n; +} + + +static struct kobj_attribute trace_range_attr = + __ATTR(trace_range, 0644, trace_range_show, trace_range_store); + +static ssize_t trace_data_range_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + unsigned long range_start; + u64 range_end; + mutex_lock(&tracer.mutex); + range_start = tracer.data_range_start; + range_end = tracer.data_range_end; + if (!range_end && (tracer.flags & TRACER_TRACE_DATA)) + range_end = 0x100000000ULL; + mutex_unlock(&tracer.mutex); + return sprintf(buf, "%08lx %08llx\n", range_start, range_end); +} + +static ssize_t trace_data_range_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long range_start; + u64 range_end; + + if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2) + return -EINVAL; + + mutex_lock(&tracer.mutex); + tracer.data_range_start = range_start; + tracer.data_range_end = (unsigned long)range_end; + if (range_end) + tracer.flags |= TRACER_TRACE_DATA; + else + tracer.flags &= ~TRACER_TRACE_DATA; + mutex_unlock(&tracer.mutex); + + return n; +} + + +static struct kobj_attribute trace_data_range_attr = + __ATTR(trace_data_range, 0644, + trace_data_range_show, trace_data_range_store); + static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id) { struct tracectx *t = &tracer; int ret = 0; + void __iomem **new_regs; + int new_count; - if (t->etm_regs) { - dev_dbg(&dev->dev, "ETM already initialized\n"); - ret = -EBUSY; + mutex_lock(&t->mutex); + new_count = t->etm_regs_count + 1; + new_regs = krealloc(t->etm_regs, + sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL); + + if (!new_regs) { + dev_dbg(&dev->dev, "Failed to allocate ETM register array\n"); + ret = -ENOMEM; goto out; } + t->etm_regs = new_regs; ret = amba_request_regions(dev, NULL); if (ret) goto out; - t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res)); - if (!t->etm_regs) { + t->etm_regs[t->etm_regs_count] = + ioremap_nocache(dev->res.start, resource_size(&dev->res)); + if (!t->etm_regs[t->etm_regs_count]) { ret = -ENOMEM; goto out_release; } - amba_set_drvdata(dev, t); + amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]); - mutex_init(&t->mutex); - t->dev = &dev->dev; - t->flags = TRACER_CYCLE_ACC; + t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA; t->etm_portsz = 1; - etm_unlock(t); - (void)etm_readl(t, ETMMR_PDSR); + etm_unlock(t, t->etm_regs_count); + (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR); /* dummy first read */ - (void)etm_readl(&tracer, ETMMR_OSSRR); + (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR); - t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf; - etm_writel(t, 0x440, ETMR_CTRL); - etm_lock(t); + t->ncmppairs = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE) & 0xf; + etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL); + etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR); + etm_lock(t, t->etm_regs_count); ret = sysfs_create_file(&dev->dev.kobj, &trace_running_attr.attr); @@ -581,36 +756,68 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id if (ret) dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n"); - dev_dbg(t->dev, "ETM AMBA driver initialized.\n"); + ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr); + if (ret) + dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n"); + + ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr); + if (ret) + dev_dbg(&dev->dev, + "Failed to create trace_data_range in sysfs\n"); + + dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n"); + + /* Enable formatter if there are multiple trace sources */ + if (new_count > 1) + t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC; + + t->etm_regs_count = new_count; out: + mutex_unlock(&t->mutex); return ret; out_unmap: amba_set_drvdata(dev, NULL); - iounmap(t->etm_regs); + iounmap(t->etm_regs[t->etm_regs_count]); out_release: amba_release_regions(dev); + mutex_unlock(&t->mutex); return ret; } static int etm_remove(struct amba_device *dev) { - struct tracectx *t = amba_get_drvdata(dev); + int i; + struct tracectx *t = &tracer; + void __iomem *etm_regs = amba_get_drvdata(dev); + + sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr); + sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr); + sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr); + sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr); + sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr); amba_set_drvdata(dev, NULL); - iounmap(t->etm_regs); - t->etm_regs = NULL; + mutex_lock(&t->mutex); + for (i = 0; i < t->etm_regs_count; i++) + if (t->etm_regs[i] == etm_regs) + break; + for (; i < t->etm_regs_count - 1; i++) + t->etm_regs[i] = t->etm_regs[i + 1]; + t->etm_regs_count--; + if (!t->etm_regs_count) { + kfree(t->etm_regs); + t->etm_regs = NULL; + } + mutex_unlock(&t->mutex); + iounmap(etm_regs); amba_release_regions(dev); - sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr); - sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr); - sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr); - return 0; } @@ -619,6 +826,10 @@ static struct amba_id etm_ids[] = { .id = 0x0003b921, .mask = 0x0007ffff, }, + { + .id = 0x0003b950, + .mask = 0x0007ffff, + }, { 0, 0 }, }; @@ -636,6 +847,8 @@ static int __init etm_init(void) { int retval; + mutex_init(&tracer.mutex); + retval = amba_driver_register(&etb_driver); if (retval) { printk(KERN_ERR "Failed to register etb\n"); diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c index 0f107dcb034..136e8376a3e 100644 --- a/arch/arm/kernel/leds.c +++ b/arch/arm/kernel/leds.c @@ -9,6 +9,8 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/notifier.h> +#include <linux/cpu.h> #include <linux/sysdev.h> #include <linux/syscore_ops.h> @@ -101,6 +103,25 @@ static struct syscore_ops leds_syscore_ops = { .resume = leds_resume, }; +static int leds_idle_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + switch (val) { + case IDLE_START: + leds_event(led_idle_start); + break; + case IDLE_END: + leds_event(led_idle_end); + break; + } + + return 0; +} + +static struct notifier_block leds_idle_nb = { + .notifier_call = leds_idle_notifier, +}; + static int __init leds_init(void) { int ret; @@ -109,8 +130,12 @@ static int __init leds_init(void) ret = sysdev_register(&leds_device); if (ret == 0) ret = sysdev_create_file(&leds_device, &attr_event); - if (ret == 0) + + if (ret == 0) { register_syscore_ops(&leds_syscore_ops); + idle_notifier_register(&leds_idle_nb); + } + return ret; } diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 99c0d6b2cd4..ccc587dbb95 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -32,7 +32,6 @@ #include <linux/hw_breakpoint.h> #include <asm/cacheflush.h> -#include <asm/leds.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/thread_notify.h> @@ -183,7 +182,7 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { tick_nohz_stop_sched_tick(1); - leds_event(led_idle_start); + idle_notifier_call_chain(IDLE_START); while (!need_resched()) { #ifdef CONFIG_HOTPLUG_CPU if (cpu_is_offline(smp_processor_id())) { @@ -216,7 +215,7 @@ void cpu_idle(void) local_irq_enable(); } } - leds_event(led_idle_end); + idle_notifier_call_chain(IDLE_END); tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); @@ -260,6 +259,77 @@ void machine_restart(char *cmd) arm_pm_restart(reboot_mode, cmd); } +/* + * dump a block of kernel memory from around the given address + */ +static void show_data(unsigned long addr, int nbytes, const char *name) +{ + int i, j; + int nlines; + u32 *p; + + /* + * don't attempt to dump non-kernel addresses or + * values that are probably just small negative numbers + */ + if (addr < PAGE_OFFSET || addr > -256UL) + return; + + printk("\n%s: %#lx:\n", name, addr); + + /* + * round address down to a 32 bit boundary + * and always dump a multiple of 32 bytes + */ + p = (u32 *)(addr & ~(sizeof(u32) - 1)); + nbytes += (addr & (sizeof(u32) - 1)); + nlines = (nbytes + 31) / 32; + + + for (i = 0; i < nlines; i++) { + /* + * just display low 16 bits of address to keep + * each line of the dump < 80 characters + */ + printk("%04lx ", (unsigned long)p & 0xffff); + for (j = 0; j < 8; j++) { + u32 data; + if (probe_kernel_address(p, data)) { + printk(" ********"); + } else { + printk(" %08x", data); + } + ++p; + } + printk("\n"); + } +} + +static void show_extra_register_data(struct pt_regs *regs, int nbytes) +{ + mm_segment_t fs; + + fs = get_fs(); + set_fs(KERNEL_DS); + show_data(regs->ARM_pc - nbytes, nbytes * 2, "PC"); + show_data(regs->ARM_lr - nbytes, nbytes * 2, "LR"); + show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP"); + show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP"); + show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP"); + show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0"); + show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1"); + show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2"); + show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3"); + show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4"); + show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5"); + show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6"); + show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7"); + show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8"); + show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9"); + show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10"); + set_fs(fs); +} + void __show_regs(struct pt_regs *regs) { unsigned long flags; @@ -319,6 +389,8 @@ void __show_regs(struct pt_regs *regs) printk("Control: %08x%s\n", ctrl, buf); } #endif + + show_extra_register_data(regs, 128); } void show_regs(struct pt_regs * regs) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 2d3436e9f71..062b3f1205a 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -466,7 +466,9 @@ do_cache_op(unsigned long start, unsigned long end, int flags) if (end > vma->vm_end) end = vma->vm_end; - flush_cache_user_range(vma, start, end); + up_read(&mm->mmap_sem); + flush_cache_user_range(start, end); + return; } up_read(&mm->mmap_sem); } diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 3799909d247..6304c43a6d8 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \ board-mop500-msp.o board-mop500-bm.o \ board-pins-sleep-force.o \ board-mop500-wlan.o +obj-$(CONFIG_ANDROID_STE_TIMED_VIBRA) += board-mop500-vibra.o obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o \ board-u5500-mcde.o board-u5500-regulators.o \ board-u5500-pins.o diff --git a/arch/arm/mach-ux500/board-mop500-vibra.c b/arch/arm/mach-ux500/board-mop500-vibra.c new file mode 100644 index 00000000000..bb4ba28774f --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-vibra.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 ST-Ericsson SA + * + * License terms:GNU General Public License (GPL) version 2 + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <asm/mach-types.h> + +#include <linux/ste_timed_vibra.h> +#include <sound/ux500_ab8500_ext.h> + +/* For details check ste_timed_vibra docbook */ +static struct ste_timed_vibra_platform_data rotary_vibra_plat_data = { + .is_linear_vibra = false, + .boost_level = 100, + .boost_time = 60, + .on_level = 50, + .off_level = 50, + .off_time = 60, + .timed_vibra_control = ux500_ab8500_audio_pwm_vibra, +}; + +static struct ste_timed_vibra_platform_data linear_vibra_plat_data = { + .is_linear_vibra = true, + .boost_level = 80, + .boost_time = 40, + .on_level = 80, + .off_level = 80, + .off_time = 0, + .timed_vibra_control = ux500_ab8500_audio_pwm_vibra, +}; + +/* Timed output vibrator device */ +static struct platform_device ux500_vibra_device = { + .name = "ste_timed_output_vibra", +}; + +void __init mop500_vibra_init(void) +{ + int ret; + + if (machine_is_hrefv60()) + ux500_vibra_device.dev.platform_data = &linear_vibra_plat_data; + else + ux500_vibra_device.dev.platform_data = &rotary_vibra_plat_data; + + ret = platform_device_register(&ux500_vibra_device); + if (ret < 0) + pr_err("vibra dev register failed"); +} diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 4b3e8a062b4..46a6759cd83 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -55,6 +55,7 @@ #ifdef CONFIG_U8500_SIM_DETECT #include <mach/sim_detect.h> #endif +#include <mach/ste_audio_io_vibrator.h> #include <video/av8100.h> #include "pins-db8500.h" @@ -974,6 +975,10 @@ static void __init mop500_init_machine(void) mop500_uart_init(); mop500_wlan_init(); +#ifdef CONFIG_ANDROID_STE_TIMED_VIBRA + mop500_vibra_init(); +#endif + platform_device_register(&ab8500_device); i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index 143ce365643..7d25acde335 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h @@ -77,6 +77,7 @@ void __init mop500_u8500uib_init(void); void __init mop500_stuib_init(void); void __init mop500_msp_init(void); void __init mop500_pins_init(void); +void __init mop500_vibra_init(void); void mop500_uib_i2c_add(int busnum, struct i2c_board_info const *info, unsigned n); diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h index 50c51b5605e..4f6f2f0394c 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu-regs.h +++ b/arch/arm/mach-ux500/include/mach/prcmu-regs.h @@ -17,6 +17,7 @@ #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end)) +#define PRCM_ACLK_MGT_OFF 0x004 #define PRCM_SVACLK_MGT_OFF 0x008 #define PRCM_SIACLK_MGT_OFF 0x00C #define PRCM_SGACLK_MGT_OFF 0x014 diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h index 6c7584d69d8..92fd7f79a4d 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu.h +++ b/arch/arm/mach-ux500/include/mach/prcmu.h @@ -153,12 +153,14 @@ enum prcmu_clock { * @APE_NO_CHANGE: The APE operating point is unchanged * @APE_100_OPP: The new APE operating point is ape100opp * @APE_50_OPP: 50% + * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%. */ enum ape_opp { APE_OPP_INIT = 0x00, APE_NO_CHANGE = 0x01, APE_100_OPP = 0x02, - APE_50_OPP = 0x03 + APE_50_OPP = 0x03, + APE_50_PARTLY_25_OPP = 0xFF, }; /** @@ -492,6 +494,7 @@ static inline void prcmu_get_abb_event_buffer(void __iomem **buf) unsigned long prcmu_qos_get_cpufreq_opp_delay(void); void prcmu_qos_set_cpufreq_opp_delay(unsigned long); void prcmu_qos_force_opp(int, s32); +void prcmu_qos_voice_call_override(bool enable); int prcmu_qos_requirement(int pm_qos_class); int prcmu_qos_add_requirement(int pm_qos_class, char *name, s32 value); int prcmu_qos_update_requirement(int pm_qos_class, char *name, s32 new_value); @@ -512,6 +515,8 @@ static inline void prcmu_qos_set_cpufreq_opp_delay(unsigned long n) {} static inline void prcmu_qos_force_opp(int prcmu_qos_class, s32 i) {} +static inline void prcmu_qos_voice_call_override(bool enable) {} + static inline int prcmu_qos_requirement(int prcmu_qos_class) { return 0; diff --git a/arch/arm/mach-ux500/pm/Kconfig b/arch/arm/mach-ux500/pm/Kconfig index d070e0a669f..47727b60775 100644 --- a/arch/arm/mach-ux500/pm/Kconfig +++ b/arch/arm/mach-ux500/pm/Kconfig @@ -73,3 +73,12 @@ config UX500_CONTEXT depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && PM help This is needed for ApSleep and deeper sleep states. + +config UX500_USECASE_GOVERNOR + bool "UX500 use-case governor" + depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && \ + (CPU_FREQ && CPU_IDLE && HOTPLUG_CPU && \ + EARLYSUSPEND && UX500_L2X0_PREFETCH_CTRL && PM) + default y + help + Adjusts CPU_IDLE, CPU_FREQ, HOTPLUG_CPU and L2 cache parameters diff --git a/arch/arm/mach-ux500/pm/Makefile b/arch/arm/mach-ux500/pm/Makefile index d297ea7370b..b237ec6fa16 100644 --- a/arch/arm/mach-ux500/pm/Makefile +++ b/arch/arm/mach-ux500/pm/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_U8500_CPUIDLE_DEBUG) += cpuidle_dbg.o obj-$(CONFIG_UX500_CONTEXT) += context.o context_arm.o context-db8500.o context-db5500.o obj-$(CONFIG_UX500_SUSPEND) += suspend.o obj-$(CONFIG_UX500_SUSPEND_DBG) += suspend_dbg.o +obj-$(CONFIG_UX500_USECASE_GOVERNOR) += usecase_gov.o diff --git a/arch/arm/mach-ux500/pm/usecase_gov.c b/arch/arm/mach-ux500/pm/usecase_gov.c new file mode 100644 index 00000000000..78f157d7f60 --- /dev/null +++ b/arch/arm/mach-ux500/pm/usecase_gov.c @@ -0,0 +1,885 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Alexandre Torgue <alexandre.torgue@stericsson.com> for ST-Ericsson + * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/io.h> +#include <linux/earlysuspend.h> +#include <linux/cpu.h> +#include <linux/sched.h> +#include <linux/tick.h> +#include <linux/workqueue.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/kernel_stat.h> +#include <linux/ktime.h> +#include <linux/cpufreq.h> +#include <mach/prcmu.h> + +#define CPULOAD_MEAS_DELAY 3000 /* 3 secondes of delta */ + +/* debug */ +static unsigned long debug; + +#define hp_printk \ + if (debug) \ + printk \ + +enum ux500_uc { + UX500_UC_NORMAL = 0, + UX500_UC_AUTO, /* Add use case below this. */ + UX500_UC_VC, + UX500_UC_LPA, + UX500_UC_USER, /* Add use case above this. */ + UX500_UC_MAX, +}; + +/* cpu load monitor struct */ +#define LOAD_MONITOR 4 +struct hotplug_cpu_info { + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_io; + unsigned int load[LOAD_MONITOR]; + unsigned int io[LOAD_MONITOR]; + unsigned int idx; +}; + +static DEFINE_PER_CPU(struct hotplug_cpu_info, hotplug_info); + +/* Auto trigger criteria */ +/* loadavg threshold */ +static unsigned long lower_threshold = 175; +static unsigned long upper_threshold = 450; +/* load balancing */ +static unsigned long max_unbalance = 210; +/* trend load */ +static unsigned long trend_unbalance = 40; +static unsigned long min_trend = 5; +/* instant load */ +static unsigned long max_instant = 85; + +/* Number of interrupts per second before exiting auto mode */ +static u32 exit_irq_per_s = 1000; +static u64 old_num_irqs; + +static DEFINE_MUTEX(user_config_mutex); +static bool user_config_updated; +static enum ux500_uc current_uc = UX500_UC_MAX; +static bool is_work_scheduled; +static bool is_early_suspend; + +static unsigned int cpuidle_deepest_state; + +struct usecase_config { + char *name; + unsigned long max_freq; + unsigned long min_freq; /* if no requirement set 0 */ + unsigned long cpuidle_multiplier; + bool second_cpu_online; + bool l2_prefetch_en; + bool enable; + unsigned int forced_state; /* Forced cpu idle state. */ + bool vc_override; /* QOS override for voice-call. */ +}; + +static struct usecase_config usecase_conf[UX500_UC_MAX] = { + [UX500_UC_NORMAL] = { + .name = "normal", + .max_freq = 1000000, + .min_freq = 200000, + .cpuidle_multiplier = 1024, + .second_cpu_online = true, + .l2_prefetch_en = true, + .enable = true, + .forced_state = 0, + .vc_override = false, + }, + [UX500_UC_AUTO] = { + .name = "auto", + .max_freq = 400000, + .min_freq = 200000, + .cpuidle_multiplier = 0, + .second_cpu_online = false, + .l2_prefetch_en = true, + .enable = false, + .forced_state = 0, + .vc_override = false, + }, + [UX500_UC_VC] = { + .name = "voice-call", + .max_freq = 200000, + .min_freq = 200000, + .cpuidle_multiplier = 0, + .second_cpu_online = false, + .l2_prefetch_en = false, + .enable = false, + .forced_state = 0, + .vc_override = true, + }, + [UX500_UC_LPA] = { + .name = "low-power-audio", + .max_freq = 400000, + .min_freq = 400000, + .cpuidle_multiplier = 0, + .second_cpu_online = false, + .l2_prefetch_en = false, + .enable = false, + .forced_state = 0, /* Updated dynamically */ + .vc_override = false, + }, +}; + +/* daemon */ +static struct delayed_work work_usecase; +static struct early_suspend usecase_early_suspend; + +/* calculate loadavg */ +#define LOAD_INT(x) ((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + +extern int cpufreq_update_freq(int cpu, unsigned int min, unsigned int max); +extern int cpuidle_set_multiplier(unsigned int value); +extern int cpuidle_force_state(unsigned int state); + +static unsigned long determine_loadavg(void) +{ + unsigned long avg = 0; + unsigned long avnrun[3]; + + get_avenrun(avnrun, FIXED_1 / 200, 0); + avg += (LOAD_INT(avnrun[0]) * 100) + (LOAD_FRAC(avnrun[0]) % 100); + + return avg; +} + +static unsigned long determine_cpu_load(void) +{ + int i; + unsigned long total_load = 0; + + /* get cpu load of each cpu */ + for_each_online_cpu(i) { + unsigned int load, iowait; + unsigned int idle_time, iowait_time, wall_time; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + struct hotplug_cpu_info *info; + + info = &per_cpu(hotplug_info, i); + + /* update both cur_idle_time and cur_wall_time */ + cur_idle_time = get_cpu_idle_time_us(i, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time_us(i, &cur_wall_time); + + /* how much wall time has passed since last iteration? */ + wall_time = (unsigned int) cputime64_sub(cur_wall_time, + info->prev_cpu_wall); + info->prev_cpu_wall = cur_wall_time; + + /* how much idle time has passed since last iteration? */ + idle_time = (unsigned int) cputime64_sub(cur_idle_time, + info->prev_cpu_idle); + info->prev_cpu_idle = cur_idle_time; + + /* how much io wait time has passed since last iteration? */ + iowait_time = (unsigned int) cputime64_sub(cur_iowait_time, + info->prev_cpu_io); + info->prev_cpu_io = cur_iowait_time; + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + /* load is the percentage of time not spent in idle */ + load = 100 * (wall_time - idle_time) / wall_time; + info->load[info->idx] = load; + hp_printk("cpu %d load %u ", i, load); + + /* iowait is the percentage of time not spent in io wait */ + iowait = 100 * (iowait_time) / wall_time; + info->io[info->idx++] = load; + hp_printk("iowait %u\n", iowait); + + if (info->idx >= LOAD_MONITOR) + info->idx = 0; + + total_load += load; + } + + return total_load; +} + +static unsigned long determine_cpu_load_trend(void) +{ + int i, j, k; + unsigned long total_load = 0; + + /* Get cpu load of each cpu */ + for_each_online_cpu(i) { + unsigned int load = 0; + struct hotplug_cpu_info *info; + + info = &per_cpu(hotplug_info, i); + + for (k = 0, j = info->idx; k < LOAD_MONITOR; k++, j++) + load += info->load[j]; + + load /= LOAD_MONITOR; + + hp_printk("cpu %d load trend %u\n", i, load); + + total_load += load; + } + + return total_load; +} + +static unsigned long determine_cpu_balance_trend(void) +{ + int i, j, k; + unsigned long total_load = 0; + unsigned long min_load = (unsigned long) (-1); + + /* Get cpu load of each cpu */ + for_each_online_cpu(i) { + unsigned int load = 0; + struct hotplug_cpu_info *info; + + info = &per_cpu(hotplug_info, i); + + for (k = 0, j = info->idx; k < LOAD_MONITOR; k++, j++) + load += info->load[j]; + + load /= LOAD_MONITOR; + + if (min_load > load) + min_load = load; + total_load += load; + } + + if (min_load > min_trend) + total_load = (100 * total_load) / min_load; + else + total_load = 50 << num_online_cpus(); + + return total_load; +} + +static void init_cpu_load_trend(void) +{ + int i; + + for_each_possible_cpu(i) { + struct hotplug_cpu_info *info; + int j; + + info = &per_cpu(hotplug_info, i); + + info->prev_cpu_idle = get_cpu_idle_time_us(i, + &(info->prev_cpu_wall)); + info->prev_cpu_io = get_cpu_iowait_time_us(i, + &(info->prev_cpu_wall)); + + for (j = 0; j < LOAD_MONITOR; j++) { + info->load[j] = 100; + info->io[j] = 100; + } + info->idx = 0; + } +} + +static u32 get_num_interrupts_per_s(void) +{ + int cpu; + int i; + u64 num_irqs = 0; + ktime_t now; + static ktime_t last; + unsigned int delta; + u32 irqs = 0; + + now = ktime_get(); + + for_each_possible_cpu(cpu) { + for (i = 0; i < NR_IRQS; i++) + num_irqs += kstat_irqs_cpu(i, cpu); + } + pr_debug("%s: total num irqs: %lld, previous %lld\n", + __func__, num_irqs, old_num_irqs); + + if (old_num_irqs > 0) { + delta = (u32)ktime_to_ms(ktime_sub(now, last)) / 1000; + irqs = ((u32)(num_irqs - old_num_irqs)) / delta; + } + + old_num_irqs = num_irqs; + last = now; + + pr_debug("delta irqs per sec:%d\n", irqs); + + return irqs; +} + +static void set_cpu_config(enum ux500_uc new_uc) +{ + struct cpufreq_policy policy; + int err; + bool update = false; + u32 min_freq, max_freq; + + if (new_uc != current_uc) + update = true; + else if ((user_config_updated) && (new_uc == UX500_UC_USER)) + update = true; + + pr_debug("%s: new_usecase=%d, current_usecase=%d, update=%d\n", + __func__, new_uc, current_uc, update); + + if (!update) + goto exit; + + /* Cpu hotplug */ + if (!(usecase_conf[new_uc].second_cpu_online) && + (num_online_cpus() > 1)) + cpu_down(1); + else if ((usecase_conf[new_uc].second_cpu_online) && + (num_online_cpus() < 2)) + cpu_up(1); + + /* Cpu freq */ + err = cpufreq_get_policy(&policy, 0); + if (err) + pr_err("usecase-gov: get cpufreq policy failed\n"); + + /* If requirement is 0, use current policy value */ + min_freq = usecase_conf[new_uc].min_freq ? + usecase_conf[new_uc].min_freq : policy.min; + + max_freq = usecase_conf[new_uc].max_freq ? + usecase_conf[new_uc].max_freq : policy.max; + + /* + * cpufreq fw does not allow frequency change if + * "current min freq" > "new max freq" or + * "current max freq" < "new min freq". + * Thus the intermediate steps below. + */ + if (policy.min > max_freq) { + err = cpufreq_update_freq(0, min_freq, policy.max); + if (err) + pr_err("usecase-gov: update min cpufreq failed\n"); + } + if (policy.max < min_freq) { + err = cpufreq_update_freq(0, policy.min, max_freq); + if (err) + pr_err("usecase-gov: update max cpufreq failed\n"); + } + + err = cpufreq_update_freq(0, min_freq, max_freq); + if (err) + pr_err("usecase-gov: update min/max cpufreq failed\n"); + + /* Cpu idle */ + cpuidle_set_multiplier(usecase_conf[new_uc].cpuidle_multiplier); + + /* L2 prefetch */ + if (usecase_conf[new_uc].l2_prefetch_en) + outer_prefetch_enable(); + else + outer_prefetch_disable(); + + /* Force cpuidle state */ + cpuidle_force_state(usecase_conf[new_uc].forced_state); + + /* QOS override */ + prcmu_qos_voice_call_override(usecase_conf[new_uc].vc_override); + + current_uc = new_uc; + +exit: + /* Its ok to clear even if new_uc != UX500_UC_USER */ + user_config_updated = false; +} + +/* + * Start load measurment every 6 s in order detrmine if can unplug one CPU. + * In order to not corrupt measurment, the first load average is not done + * here call in early suspend. + */ +static void usecase_earlysuspend_callback(struct early_suspend *h) +{ + init_cpu_load_trend(); + + mutex_lock(&user_config_mutex); + + is_early_suspend = true; + + if (usecase_conf[UX500_UC_AUTO].enable || + usecase_conf[UX500_UC_USER].enable) { + + is_work_scheduled = true; + + schedule_delayed_work_on(0, &work_usecase, + msecs_to_jiffies(CPULOAD_MEAS_DELAY)); + } + + mutex_unlock(&user_config_mutex); +} + +/* Stop measurement, call LCD early resume */ +static void usecase_lateresume_callback(struct early_suspend *h) +{ + mutex_lock(&user_config_mutex); + + if (is_work_scheduled) { + cancel_delayed_work_sync(&work_usecase); + is_work_scheduled = false; + } + + is_early_suspend = false; + + set_cpu_config(UX500_UC_NORMAL); + + mutex_unlock(&user_config_mutex); +} + +static void delayed_usecase_work(struct work_struct *work) +{ + unsigned long avg, load, trend, balance; + bool inc_perf = false; + bool dec_perf = false; + u32 irqs_per_s; + + /* determine loadavg */ + avg = determine_loadavg(); + hp_printk("loadavg = %lu lower th %lu upper th %lu\n", + avg, lower_threshold, upper_threshold); + + /* determine instant load */ + load = determine_cpu_load(); + hp_printk("cpu instant load = %lu max %lu\n", load, max_instant); + + /* determine load trend */ + trend = determine_cpu_load_trend(); + hp_printk("cpu load trend = %lu min %lu unbal %lu\n", + trend, min_trend, trend_unbalance); + + /* determine load balancing */ + balance = determine_cpu_balance_trend(); + hp_printk("load balancing trend = %lu min %lu\n", + balance, max_unbalance); + + irqs_per_s = get_num_interrupts_per_s(); + + /* Dont let configuration change in the middle of our calculations. */ + mutex_lock(&user_config_mutex); + + /* detect "instant" load increase */ + if (load > max_instant || irqs_per_s > exit_irq_per_s) { + inc_perf = true; + } else if (!usecase_conf[UX500_UC_USER].enable && + usecase_conf[UX500_UC_AUTO].enable) { + /* detect high loadavg use case */ + if (avg > upper_threshold) + inc_perf = true; + /* detect idle use case */ + else if (trend < min_trend) + dec_perf = true; + /* detect unbalanced low cpu load use case */ + else if ((balance > max_unbalance) && (trend < trend_unbalance)) + dec_perf = true; + /* detect low loadavg use case */ + else if (avg < lower_threshold) + dec_perf = true; + /* All user use cases disabled, current load not triggering + * any change. + */ + else if (user_config_updated) + dec_perf = true; + } else { + dec_perf = true; + } + + /* + * set_cpu_config() will not update the config unless it has been + * changed. + */ + if (dec_perf) { + if (usecase_conf[UX500_UC_USER].enable) + set_cpu_config(UX500_UC_USER); + else if (usecase_conf[UX500_UC_AUTO].enable) + set_cpu_config(UX500_UC_AUTO); + } else if (inc_perf) { + set_cpu_config(UX500_UC_NORMAL); + } + + mutex_unlock(&user_config_mutex); + + /* reprogramm scheduled work */ + schedule_delayed_work_on(0, &work_usecase, + msecs_to_jiffies(CPULOAD_MEAS_DELAY)); + +} + +static struct dentry *usecase_dir; + +#ifdef CONFIG_DEBUG_FS +#define define_set(_name) \ +static ssize_t set_##_name(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + int err; \ + long unsigned i; \ + \ + err = kstrtoul_from_user(user_buf, count, 0, &i); \ + \ + if (err) \ + return err; \ + \ + _name = i; \ + hp_printk("New value : %lu\n", _name); \ + \ + return count; \ +} + +define_set(upper_threshold); +define_set(lower_threshold); +define_set(max_unbalance); +define_set(trend_unbalance); +define_set(min_trend); +define_set(max_instant); +define_set(debug); + +#define define_print(_name) \ +static ssize_t print_##_name(struct seq_file *s, void *p) \ +{ \ + return seq_printf(s, "%lu\n", _name); \ +} + +define_print(upper_threshold); +define_print(lower_threshold); +define_print(max_unbalance); +define_print(trend_unbalance); +define_print(min_trend); +define_print(max_instant); +define_print(debug); + +#define define_open(_name) \ +static ssize_t open_##_name(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, print_##_name, inode->i_private); \ +} + +define_open(upper_threshold); +define_open(lower_threshold); +define_open(max_unbalance); +define_open(trend_unbalance); +define_open(min_trend); +define_open(max_instant); +define_open(debug); + +#define define_dbg_file(_name) \ +static const struct file_operations fops_##_name = { \ + .open = open_##_name, \ + .write = set_##_name, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + .owner = THIS_MODULE, \ +}; \ +static struct dentry *file_##_name; + +define_dbg_file(upper_threshold); +define_dbg_file(lower_threshold); +define_dbg_file(max_unbalance); +define_dbg_file(trend_unbalance); +define_dbg_file(min_trend); +define_dbg_file(max_instant); +define_dbg_file(debug); + +struct dbg_file { + struct dentry **file; + const struct file_operations *fops; + const char *name; +}; + +#define define_dbg_entry(_name) \ +{ \ + .file = &file_##_name, \ + .fops = &fops_##_name, \ + .name = #_name \ +} + +static struct dbg_file debug_entry[] = { + define_dbg_entry(upper_threshold), + define_dbg_entry(lower_threshold), + define_dbg_entry(max_unbalance), + define_dbg_entry(trend_unbalance), + define_dbg_entry(min_trend), + define_dbg_entry(max_instant), + define_dbg_entry(debug), +}; + +static int setup_debugfs(void) +{ + int i; + usecase_dir = debugfs_create_dir("usecase", NULL); + + if (IS_ERR_OR_NULL(usecase_dir)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(debug_entry); i++) { + if (IS_ERR_OR_NULL(debugfs_create_file(debug_entry[i].name, + S_IWUGO | S_IRUGO, + usecase_dir, + NULL, + debug_entry[i].fops))) + goto fail; + } + + if (IS_ERR_OR_NULL(debugfs_create_u32("exit_irq_per_s", + S_IWUGO | S_IRUGO, usecase_dir, + &exit_irq_per_s))) + goto fail; + return 0; +fail: + debugfs_remove_recursive(usecase_dir); + return -EINVAL; +} +#else +static int setup_debugfs(void) +{ + return 0; +} +#endif + +static void usecase_update_user_config(void) +{ + int i; + bool config_enable = false; + struct usecase_config *user_conf = &usecase_conf[UX500_UC_USER]; + + mutex_lock(&user_config_mutex); + + user_conf->max_freq = 0; + user_conf->min_freq = 0; + user_conf->cpuidle_multiplier = 0; + user_conf->second_cpu_online = false; + user_conf->l2_prefetch_en = false; + user_conf->forced_state = cpuidle_deepest_state; + user_conf->vc_override = true; /* A single false will clear it. */ + + /* Dont include Auto and Normal modes in this */ + for (i = (UX500_UC_AUTO + 1); i < UX500_UC_USER; i++) { + if (!usecase_conf[i].enable) + continue; + + config_enable = true; + + if (usecase_conf[i].max_freq > user_conf->max_freq) + user_conf->max_freq = usecase_conf[i].max_freq; + /* It's the highest min freq requirement that should be used */ + if (usecase_conf[i].min_freq > user_conf->min_freq) + user_conf->min_freq = usecase_conf[i].min_freq; + + if (usecase_conf[i].cpuidle_multiplier > + user_conf->cpuidle_multiplier) + user_conf->cpuidle_multiplier = + usecase_conf[i].cpuidle_multiplier; + + user_conf->second_cpu_online |= + usecase_conf[i].second_cpu_online; + + user_conf->l2_prefetch_en |= + usecase_conf[i].l2_prefetch_en; + + /* Take the shallowest state. */ + if (usecase_conf[i].forced_state < user_conf->forced_state) + user_conf->forced_state = usecase_conf[i].forced_state; + + /* Only override QOS if all enabled configurations are + * requesting it. + */ + if (!usecase_conf[i].vc_override) + user_conf->vc_override = false; + } + + user_conf->enable = config_enable; + user_config_updated = true; + + mutex_unlock(&user_config_mutex); +} + +struct usecase_devclass_attr { + struct sysdev_class_attribute class_attr; + u32 index; +}; + +static struct usecase_devclass_attr usecase_dc_attr[UX500_UC_MAX]; + +static struct attribute *dbs_attributes[UX500_UC_MAX + 1] = {NULL}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "usecase", +}; + +static ssize_t show_current(struct sysdev_class *class, + struct sysdev_class_attribute *attr, char *buf) +{ + enum ux500_uc display_uc = (current_uc == UX500_UC_MAX) ? + UX500_UC_NORMAL : current_uc; + + return sprintf(buf, "max_freq: %ld\n" + "cpuidle_multiplier: %ld\n" + "second_cpu_online: %s\n" + "l2_prefetch_en: %s\n" + "forced_state: %d\n" + "vc_override: %s\n", + usecase_conf[display_uc].max_freq, + usecase_conf[display_uc].cpuidle_multiplier, + usecase_conf[display_uc].second_cpu_online ? "true" : "false", + usecase_conf[display_uc].l2_prefetch_en ? "true" : "false", + usecase_conf[display_uc].forced_state, + usecase_conf[display_uc].vc_override ? "true" : "false"); +} + +static ssize_t show_dc_attr(struct sysdev_class *class, + struct sysdev_class_attribute *attr, char *buf) +{ + struct usecase_devclass_attr *uattr = + container_of(attr, struct usecase_devclass_attr, class_attr); + + return sprintf(buf, "%u\n", + usecase_conf[uattr->index].enable); +} + +static ssize_t store_dc_attr(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + struct usecase_devclass_attr *uattr = + container_of(attr, struct usecase_devclass_attr, class_attr); + + ret = sscanf(buf, "%u", &input); + + /* Normal mode cant be changed. */ + if ((ret != 1) || (uattr->index == 0)) + return -EINVAL; + + usecase_conf[uattr->index].enable = (bool)input; + + usecase_update_user_config(); + + mutex_lock(&user_config_mutex); + + if (usecase_conf[UX500_UC_AUTO].enable || + usecase_conf[UX500_UC_USER].enable) { + if (is_early_suspend && !is_work_scheduled) { + schedule_delayed_work_on(0, &work_usecase, + msecs_to_jiffies(CPULOAD_MEAS_DELAY)); + is_work_scheduled = true; + } + } else if (is_work_scheduled) { + cancel_delayed_work_sync(&work_usecase); + is_work_scheduled = false; + set_cpu_config(UX500_UC_NORMAL); + } + + mutex_unlock(&user_config_mutex); + + return count; +} + +static int usecase_sysfs_init(void) +{ + int err; + int i; + + for (i = 0; i < (ARRAY_SIZE(usecase_conf) - 1); i++) { + usecase_dc_attr[i].class_attr.attr.name = usecase_conf[i].name; + usecase_dc_attr[i].class_attr.attr.mode = 0644; + usecase_dc_attr[i].class_attr.show = show_dc_attr; + usecase_dc_attr[i].class_attr.store = store_dc_attr; + usecase_dc_attr[i].index = i; + + dbs_attributes[i] = &(usecase_dc_attr[i].class_attr.attr); + } + usecase_dc_attr[UX500_UC_USER].class_attr.attr.name = "current"; + usecase_dc_attr[UX500_UC_USER].class_attr.attr.mode = 0644; + usecase_dc_attr[UX500_UC_USER].class_attr.show = show_current; + usecase_dc_attr[UX500_UC_USER].class_attr.store = NULL; + usecase_dc_attr[UX500_UC_USER].index = UX500_UC_USER; + dbs_attributes[UX500_UC_USER] = + &(usecase_dc_attr[UX500_UC_USER].class_attr.attr); + + err = sysfs_create_group(&(cpu_sysdev_class.kset.kobj), + &dbs_attr_group); + if (err) + pr_err("usecase-gov: sysfs_create_group" + " failed with error = %d\n", err); + + return err; +} + +#include "cpuidle.h" + +static void usecase_cpuidle_init(void) +{ + int max_states; + int i; + struct cstate *state = ux500_ci_get_cstates(&max_states); + + for (i = 0; i < max_states; i++) + if ((state[i].APE == APE_OFF) && (state[i].ARM == ARM_RET)) + break; + + usecase_conf[UX500_UC_LPA].forced_state = i; + + cpuidle_deepest_state = max_states - 1; +} + +/* initialize devices */ +static int __init init_usecase_devices(void) +{ + int err; + + pr_info("Use-case governor initialized\n"); + + /* add early_suspend callback */ + usecase_early_suspend.level = 200; + usecase_early_suspend.suspend = usecase_earlysuspend_callback; + usecase_early_suspend.resume = usecase_lateresume_callback; + register_early_suspend(&usecase_early_suspend); + + /* register delayed queuework */ + INIT_DELAYED_WORK_DEFERRABLE(&work_usecase, + delayed_usecase_work); + + init_cpu_load_trend(); + + err = setup_debugfs(); + if (err) + goto error; + err = usecase_sysfs_init(); + if (err) + goto error2; + + usecase_cpuidle_init(); + + return 0; +error2: + debugfs_remove_recursive(usecase_dir); +error: + unregister_early_suspend(&usecase_early_suspend); + return err; +} + +device_initcall(init_usecase_devices); diff --git a/arch/arm/mach-ux500/prcmu-qos-power.c b/arch/arm/mach-ux500/prcmu-qos-power.c index 050bcf2f7ad..082393bd7eb 100644 --- a/arch/arm/mach-ux500/prcmu-qos-power.c +++ b/arch/arm/mach-ux500/prcmu-qos-power.c @@ -96,8 +96,11 @@ static struct prcmu_qos_object *prcmu_qos_array[] = { &ddr_opp_qos }; +static DEFINE_MUTEX(prcmu_qos_mutex); static DEFINE_SPINLOCK(prcmu_qos_lock); +static bool ape_opp_forced_to_50_partly_25; + static unsigned long cpufreq_opp_delay = HZ / 5; unsigned long prcmu_qos_get_cpufreq_opp_delay(void) @@ -141,6 +144,8 @@ static void update_target(int target) int update = 0; u8 op; + mutex_lock(&prcmu_qos_mutex); + spin_lock_irqsave(&prcmu_qos_lock, flags); extreme_value = prcmu_qos_array[target]->default_value; @@ -188,7 +193,7 @@ static void update_target(int target) default: pr_err("prcmu qos: Incorrect ddr target value (%d)", extreme_value); - return; + goto unlock_and_return; } prcmu_debug_ddr_opp_log(op); prcmu_set_ddr_opp(op); @@ -205,12 +210,17 @@ static void update_target(int target) default: pr_err("prcmu qos: Incorrect ape target value (%d)", extreme_value); - return; + goto unlock_and_return; } - prcmu_set_ape_opp(op); + + if (!ape_opp_forced_to_50_partly_25) + (void)prcmu_set_ape_opp(op); + prcmu_debug_ape_opp_log(op); } } +unlock_and_return: + mutex_unlock(&prcmu_qos_mutex); } void prcmu_qos_force_opp(int prcmu_qos_class, s32 i) @@ -219,6 +229,38 @@ void prcmu_qos_force_opp(int prcmu_qos_class, s32 i) update_target(prcmu_qos_class); } +void prcmu_qos_voice_call_override(bool enable) +{ + u8 op; + + mutex_lock(&prcmu_qos_mutex); + + ape_opp_forced_to_50_partly_25 = enable; + + if (enable) { + (void)prcmu_set_ape_opp(APE_50_PARTLY_25_OPP); + goto unlock_and_return; + } + + /* Disable: set the OPP according to the current target value. */ + switch (atomic_read( + &prcmu_qos_array[PRCMU_QOS_APE_OPP]->target_value)) { + case 50: + op = APE_50_OPP; + break; + case 100: + op = APE_100_OPP; + break; + default: + goto unlock_and_return; + } + + (void)prcmu_set_ape_opp(op); + +unlock_and_return: + mutex_unlock(&prcmu_qos_mutex); +} + /** * prcmu_qos_requirement - returns current prcmu qos expectation * @prcmu_qos_class: identification of which qos value is requested diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index b88dd4ab038..7c278122887 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -272,6 +272,11 @@ v6_dma_clean_range: * - end - virtual end address of region */ ENTRY(v6_dma_flush_range) +#ifdef CONFIG_CACHE_FLUSH_RANGE_LIMIT + sub r2, r1, r0 + cmp r2, #CONFIG_CACHE_FLUSH_RANGE_LIMIT + bhi v6_dma_flush_dcache_all +#endif #ifdef CONFIG_DMA_CACHE_RWFO ldrb r2, [r0] @ read for ownership strb r2, [r0] @ write for ownership @@ -294,6 +299,18 @@ ENTRY(v6_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mov pc, lr +#ifdef CONFIG_CACHE_FLUSH_RANGE_LIMIT +v6_dma_flush_dcache_all: + mov r0, #0 +#ifdef HARVARD_CACHE + mcr p15, 0, r0, c7, c14, 0 @ D cache clean+invalidate +#else + mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mov pc, lr +#endif + /* * dma_map_area(start, size, dir) * - start - kernel virtual start address diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 4fa9903b83c..c1a97840258 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -10,7 +10,7 @@ * * Basic entry code, called from the kernel's undefined instruction trap. * r0 = faulted instruction - * r5 = faulted PC+4 + * r2 = faulted PC+4 * r9 = successful return * r10 = thread_info structure * lr = failure return @@ -26,6 +26,7 @@ ENTRY(do_vfp) str r11, [r10, #TI_PREEMPT] #endif enable_irq + str r2, [sp, #S_PC] @ update regs->ARM_pc for Thumb 2 case ldr r4, .LCvfp ldr r11, [r10, #TI_CPU] @ CPU number add r10, r10, #TI_VFPSTATE @ r10 = workspace diff --git a/arch/x86/include/asm/idle.h b/arch/x86/include/asm/idle.h index f49253d7571..f1e4268ef3c 100644 --- a/arch/x86/include/asm/idle.h +++ b/arch/x86/include/asm/idle.h @@ -1,13 +1,6 @@ #ifndef _ASM_X86_IDLE_H #define _ASM_X86_IDLE_H -#define IDLE_START 1 -#define IDLE_END 2 - -struct notifier_block; -void idle_notifier_register(struct notifier_block *n); -void idle_notifier_unregister(struct notifier_block *n); - #ifdef CONFIG_X86_64 void enter_idle(void); void exit_idle(void); diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index ca6f7ab8df3..63c8aedbe5b 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -56,31 +56,17 @@ asmlinkage extern void ret_from_fork(void); DEFINE_PER_CPU(unsigned long, old_rsp); static DEFINE_PER_CPU(unsigned char, is_idle); -static ATOMIC_NOTIFIER_HEAD(idle_notifier); - -void idle_notifier_register(struct notifier_block *n) -{ - atomic_notifier_chain_register(&idle_notifier, n); -} -EXPORT_SYMBOL_GPL(idle_notifier_register); - -void idle_notifier_unregister(struct notifier_block *n) -{ - atomic_notifier_chain_unregister(&idle_notifier, n); -} -EXPORT_SYMBOL_GPL(idle_notifier_unregister); - void enter_idle(void) { percpu_write(is_idle, 1); - atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); + idle_notifier_call_chain(IDLE_START); } static void __exit_idle(void) { if (x86_test_and_clear_bit_percpu(0, is_idle) == 0) return; - atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); + idle_notifier_call_chain(IDLE_END); } /* Called from interrupts to signify idle end */ |