diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/boot/compressed/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/common/dmabounce.c | 22 | ||||
-rw-r--r-- | arch/arm/common/locomo.c | 2 | ||||
-rw-r--r-- | arch/arm/common/sa1111.c | 10 | ||||
-rw-r--r-- | arch/arm/common/scoop.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/kernel/armksyms.c | 5 | ||||
-rw-r--r-- | arch/arm/kernel/ecard.c | 5 | ||||
-rw-r--r-- | arch/arm/kernel/entry-common.S | 51 | ||||
-rw-r--r-- | arch/arm/kernel/ftrace.c | 116 | ||||
-rw-r--r-- | arch/arm/kernel/kgdb.c | 201 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 163 | ||||
-rw-r--r-- | arch/arm/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-integrator/impd1.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-integrator/lm.c | 6 | ||||
-rw-r--r-- | arch/arm/oprofile/op_model_mpcore.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 2 | ||||
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 2 |
23 files changed, 446 insertions, 180 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e57226e3afeb..d048f6887d0b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -12,8 +12,11 @@ config ARM select RTC_LIB select SYS_SUPPORTS_APM_EMULATION select HAVE_OPROFILE + select HAVE_ARCH_KGDB select HAVE_KPROBES if (!XIP_KERNEL) select HAVE_KRETPROBES if (HAVE_KPROBES) + select HAVE_FTRACE if (!XIP_KERNEL) + select HAVE_DYNAMIC_FTRACE if (HAVE_FTRACE) help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and @@ -699,6 +702,7 @@ source "kernel/time/Kconfig" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) + select USE_GENERIC_SMP_HELPERS help This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index de9d9ee50958..95baac4939e0 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -69,6 +69,12 @@ SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \ head.o misc.o $(OBJS) + +ifeq ($(CONFIG_FTRACE),y) +ORIG_CFLAGS := $(KBUILD_CFLAGS) +KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) +endif + EXTRA_CFLAGS := -fpic -fno-builtin EXTRA_AFLAGS := diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 2744673314b4..dd2947342604 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -554,9 +554,8 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC); if (!device_info) { - printk(KERN_ERR - "Could not allocated dmabounce_device_info for %s", - dev->bus_id); + dev_err(dev, + "Could not allocated dmabounce_device_info\n"); return -ENOMEM; } @@ -594,8 +593,7 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, dev->archdata.dmabounce = device_info; - printk(KERN_INFO "dmabounce: registered device %s on %s bus\n", - dev->bus_id, dev->bus->name); + dev_info(dev, "dmabounce: registered device\n"); return 0; @@ -614,16 +612,15 @@ dmabounce_unregister_dev(struct device *dev) dev->archdata.dmabounce = NULL; if (!device_info) { - printk(KERN_WARNING - "%s: Never registered with dmabounce but attempting" \ - "to unregister!\n", dev->bus_id); + dev_warn(dev, + "Never registered with dmabounce but attempting" + "to unregister!\n"); return; } if (!list_empty(&device_info->safe_buffers)) { - printk(KERN_ERR - "%s: Removing from dmabounce with pending buffers!\n", - dev->bus_id); + dev_err(dev, + "Removing from dmabounce with pending buffers!\n"); BUG(); } @@ -639,8 +636,7 @@ dmabounce_unregister_dev(struct device *dev) kfree(device_info); - printk(KERN_INFO "dmabounce: device %s on %s bus unregistered\n", - dev->bus_id, dev->bus->name); + dev_info(dev, "dmabounce: device unregistered\n"); } diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index d973c986f721..c3c3a3339049 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -543,7 +543,6 @@ locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) goto out; } - strncpy(dev->dev.bus_id, info->name, sizeof(dev->dev.bus_id)); /* * If the parent device has a DMA mask associated with it, * propagate it down to the children. @@ -553,6 +552,7 @@ locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) dev->dev.dma_mask = &dev->dma_mask; } + dev_set_name(&dev->dev, "%s", info->name); dev->devid = info->devid; dev->dev.parent = lchip->dev; dev->dev.bus = &locomo_bus_type; diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 79fa71d990b5..0a8e1ff2af8a 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -550,9 +550,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, goto out; } - snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), - "%4.4lx", info->offset); - + dev_set_name(&dev->dev, "%4.4lx", info->offset); dev->devid = info->devid; dev->dev.parent = sachip->dev; dev->dev.bus = &sa1111_bus_type; @@ -560,7 +558,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; dev->res.start = sachip->phys + info->offset; dev->res.end = dev->res.start + 511; - dev->res.name = dev->dev.bus_id; + dev->res.name = dev_name(&dev->dev); dev->res.flags = IORESOURCE_MEM; dev->mapbase = sachip->base + info->offset; dev->skpcr_mask = info->skpcr_mask; @@ -570,6 +568,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, if (ret) { printk("SA1111: failed to allocate resource for %s\n", dev->res.name); + dev_set_name(&dev->dev, NULL); kfree(dev); goto out; } @@ -593,7 +592,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, if (dev->dma_mask != 0xffffffffUL) { ret = dmabounce_register_dev(&dev->dev, 1024, 4096); if (ret) { - printk("SA1111: Failed to register %s with dmabounce", dev->dev.bus_id); + dev_err(&dev->dev, "SA1111: Failed to register" + " with dmabounce\n"); device_unregister(&dev->dev); } } diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index bc299b07a6fa..ae39553589dd 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -247,7 +247,7 @@ static int __devinit scoop_probe(struct platform_device *pdev) devptr->gpio.base = -1; if (inf->gpio_base != 0) { - devptr->gpio.label = pdev->dev.bus_id; + devptr->gpio.label = dev_name(&pdev->dev); devptr->gpio.base = inf->gpio_base; devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */ devptr->gpio.set = scoop_gpio_set; diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index ad455ff5aebe..1d296fc8494e 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -4,6 +4,10 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) +ifdef CONFIG_DYNAMIC_FTRACE +CFLAGS_REMOVE_ftrace.o = -pg +endif + # Object file lists. obj-y := compat.o entry-armv.o entry-common.o irq.o \ @@ -18,11 +22,13 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o obj-$(CONFIG_ATAGS_PROC) += atags.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o +obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 688b7b1ee416..cc7b246e9652 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -18,6 +18,7 @@ #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/ftrace.h> /* * libgcc functions - functions that are used internally by the @@ -181,3 +182,7 @@ EXPORT_SYMBOL(_find_next_bit_be); #endif EXPORT_SYMBOL(copy_page); + +#ifdef CONFIG_FTRACE +EXPORT_SYMBOL(mcount); +#endif diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 8bfd299bfe77..f5cfdabcb87d 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -783,7 +783,7 @@ static void ecard_proc_init(void) #define ec_set_resource(ec,nr,st,sz) \ do { \ - (ec)->resource[nr].name = ec->dev.bus_id; \ + (ec)->resource[nr].name = dev_name(&ec->dev); \ (ec)->resource[nr].start = st; \ (ec)->resource[nr].end = (st) + (sz) - 1; \ (ec)->resource[nr].flags = IORESOURCE_MEM; \ @@ -853,8 +853,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) for (i = 0; i < ECARD_NUM_RESOURCES; i++) { if (ec->resource[i].flags && request_resource(&iomem_resource, &ec->resource[i])) { - printk(KERN_ERR "%s: resource(s) not available\n", - ec->dev.bus_id); + dev_err(&ec->dev, "resource(s) not available\n"); ec->resource[i].end -= ec->resource[i].start; ec->resource[i].start = 0; ec->resource[i].flags = 0; diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 597ed00a08d8..84694e88b428 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -9,6 +9,7 @@ */ #include <asm/unistd.h> +#include <asm/ftrace.h> #include <asm/arch/entry-macro.S> #include "entry-header.S" @@ -99,6 +100,56 @@ ENTRY(ret_from_fork) #undef CALL #define CALL(x) .long x +#ifdef CONFIG_FTRACE +#ifdef CONFIG_DYNAMIC_FTRACE +ENTRY(mcount) + stmdb sp!, {r0-r3, lr} + mov r0, lr + sub r0, r0, #MCOUNT_INSN_SIZE + + .globl mcount_call +mcount_call: + bl ftrace_stub + ldmia sp!, {r0-r3, pc} + +ENTRY(ftrace_caller) + stmdb sp!, {r0-r3, lr} + ldr r1, [fp, #-4] + mov r0, lr + sub r0, r0, #MCOUNT_INSN_SIZE + + .globl ftrace_call +ftrace_call: + bl ftrace_stub + ldmia sp!, {r0-r3, pc} + +#else + +ENTRY(mcount) + stmdb sp!, {r0-r3, lr} + ldr r0, =ftrace_trace_function + ldr r2, [r0] + adr r0, ftrace_stub + cmp r0, r2 + bne trace + ldmia sp!, {r0-r3, pc} + +trace: + ldr r1, [fp, #-4] + mov r0, lr + sub r0, r0, #MCOUNT_INSN_SIZE + mov lr, pc + mov pc, r2 + ldmia sp!, {r0-r3, pc} + +#endif /* CONFIG_DYNAMIC_FTRACE */ + + .globl ftrace_stub +ftrace_stub: + mov pc, lr + +#endif /* CONFIG_FTRACE */ + /*============================================================================= * SWI handler *----------------------------------------------------------------------------- diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c new file mode 100644 index 000000000000..76d50e6091bc --- /dev/null +++ b/arch/arm/kernel/ftrace.c @@ -0,0 +1,116 @@ +/* + * Dynamic function tracing support. + * + * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com> + * + * For licencing details, see COPYING. + * + * Defines low-level handling of mcount calls when the kernel + * is compiled with the -pg flag. When using dynamic ftrace, the + * mcount call-sites get patched lazily with NOP till they are + * enabled. All code mutation routines here take effect atomically. + */ + +#include <linux/ftrace.h> + +#include <asm/cacheflush.h> +#include <asm/ftrace.h> + +#define PC_OFFSET 8 +#define BL_OPCODE 0xeb000000 +#define BL_OFFSET_MASK 0x00ffffff + +static unsigned long bl_insn; +static const unsigned long NOP = 0xe1a00000; /* mov r0, r0 */ + +unsigned char *ftrace_nop_replace(void) +{ + return (char *)&NOP; +} + +/* construct a branch (BL) instruction to addr */ +unsigned char *ftrace_call_replace(unsigned long pc, unsigned long addr) +{ + long offset; + + offset = (long)addr - (long)(pc + PC_OFFSET); + if (unlikely(offset < -33554432 || offset > 33554428)) { + /* Can't generate branches that far (from ARM ARM). Ftrace + * doesn't generate branches outside of kernel text. + */ + WARN_ON_ONCE(1); + return NULL; + } + offset = (offset >> 2) & BL_OFFSET_MASK; + bl_insn = BL_OPCODE | offset; + return (unsigned char *)&bl_insn; +} + +int ftrace_modify_code(unsigned long pc, unsigned char *old_code, + unsigned char *new_code) +{ + unsigned long err = 0, replaced = 0, old, new; + + old = *(unsigned long *)old_code; + new = *(unsigned long *)new_code; + + __asm__ __volatile__ ( + "1: ldr %1, [%2] \n" + " cmp %1, %4 \n" + "2: streq %3, [%2] \n" + " cmpne %1, %3 \n" + " movne %0, #2 \n" + "3:\n" + + ".section .fixup, \"ax\"\n" + "4: mov %0, #1 \n" + " b 3b \n" + ".previous\n" + + ".section __ex_table, \"a\"\n" + " .long 1b, 4b \n" + " .long 2b, 4b \n" + ".previous\n" + + : "=r"(err), "=r"(replaced) + : "r"(pc), "r"(new), "r"(old), "0"(err), "1"(replaced) + : "memory"); + + if (!err && (replaced == old)) + flush_icache_range(pc, pc + MCOUNT_INSN_SIZE); + + return err; +} + +int ftrace_update_ftrace_func(ftrace_func_t func) +{ + int ret; + unsigned long pc, old; + unsigned char *new; + + pc = (unsigned long)&ftrace_call; + memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE); + new = ftrace_call_replace(pc, (unsigned long)func); + ret = ftrace_modify_code(pc, (unsigned char *)&old, new); + return ret; +} + +int ftrace_mcount_set(unsigned long *data) +{ + unsigned long pc, old; + unsigned long *addr = data; + unsigned char *new; + + pc = (unsigned long)&mcount_call; + memcpy(&old, &mcount_call, MCOUNT_INSN_SIZE); + new = ftrace_call_replace(pc, *addr); + *addr = ftrace_modify_code(pc, (unsigned char *)&old, new); + return 0; +} + +/* run from kstop_machine */ +int __init ftrace_dyn_arch_init(void *data) +{ + ftrace_mcount_set(data); + return 0; +} diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c new file mode 100644 index 000000000000..aaffaecffcd1 --- /dev/null +++ b/arch/arm/kernel/kgdb.c @@ -0,0 +1,201 @@ +/* + * arch/arm/kernel/kgdb.c + * + * ARM KGDB support + * + * Copyright (c) 2002-2004 MontaVista Software, Inc + * Copyright (c) 2008 Wind River Systems, Inc. + * + * Authors: George Davis <davis_g@mvista.com> + * Deepak Saxena <dsaxena@plexity.net> + */ +#include <linux/kgdb.h> +#include <asm/traps.h> + +/* Make a local copy of the registers passed into the handler (bletch) */ +void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) +{ + int regno; + + /* Initialize all to zero. */ + for (regno = 0; regno < GDB_MAX_REGS; regno++) + gdb_regs[regno] = 0; + + gdb_regs[_R0] = kernel_regs->ARM_r0; + gdb_regs[_R1] = kernel_regs->ARM_r1; + gdb_regs[_R2] = kernel_regs->ARM_r2; + gdb_regs[_R3] = kernel_regs->ARM_r3; + gdb_regs[_R4] = kernel_regs->ARM_r4; + gdb_regs[_R5] = kernel_regs->ARM_r5; + gdb_regs[_R6] = kernel_regs->ARM_r6; + gdb_regs[_R7] = kernel_regs->ARM_r7; + gdb_regs[_R8] = kernel_regs->ARM_r8; + gdb_regs[_R9] = kernel_regs->ARM_r9; + gdb_regs[_R10] = kernel_regs->ARM_r10; + gdb_regs[_FP] = kernel_regs->ARM_fp; + gdb_regs[_IP] = kernel_regs->ARM_ip; + gdb_regs[_SPT] = kernel_regs->ARM_sp; + gdb_regs[_LR] = kernel_regs->ARM_lr; + gdb_regs[_PC] = kernel_regs->ARM_pc; + gdb_regs[_CPSR] = kernel_regs->ARM_cpsr; +} + +/* Copy local gdb registers back to kgdb regs, for later copy to kernel */ +void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) +{ + kernel_regs->ARM_r0 = gdb_regs[_R0]; + kernel_regs->ARM_r1 = gdb_regs[_R1]; + kernel_regs->ARM_r2 = gdb_regs[_R2]; + kernel_regs->ARM_r3 = gdb_regs[_R3]; + kernel_regs->ARM_r4 = gdb_regs[_R4]; + kernel_regs->ARM_r5 = gdb_regs[_R5]; + kernel_regs->ARM_r6 = gdb_regs[_R6]; + kernel_regs->ARM_r7 = gdb_regs[_R7]; + kernel_regs->ARM_r8 = gdb_regs[_R8]; + kernel_regs->ARM_r9 = gdb_regs[_R9]; + kernel_regs->ARM_r10 = gdb_regs[_R10]; + kernel_regs->ARM_fp = gdb_regs[_FP]; + kernel_regs->ARM_ip = gdb_regs[_IP]; + kernel_regs->ARM_sp = gdb_regs[_SPT]; + kernel_regs->ARM_lr = gdb_regs[_LR]; + kernel_regs->ARM_pc = gdb_regs[_PC]; + kernel_regs->ARM_cpsr = gdb_regs[_CPSR]; +} + +void +sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) +{ + struct pt_regs *thread_regs; + int regno; + + /* Just making sure... */ + if (task == NULL) + return; + + /* Initialize to zero */ + for (regno = 0; regno < GDB_MAX_REGS; regno++) + gdb_regs[regno] = 0; + + /* Otherwise, we have only some registers from switch_to() */ + thread_regs = task_pt_regs(task); + gdb_regs[_R0] = thread_regs->ARM_r0; + gdb_regs[_R1] = thread_regs->ARM_r1; + gdb_regs[_R2] = thread_regs->ARM_r2; + gdb_regs[_R3] = thread_regs->ARM_r3; + gdb_regs[_R4] = thread_regs->ARM_r4; + gdb_regs[_R5] = thread_regs->ARM_r5; + gdb_regs[_R6] = thread_regs->ARM_r6; + gdb_regs[_R7] = thread_regs->ARM_r7; + gdb_regs[_R8] = thread_regs->ARM_r8; + gdb_regs[_R9] = thread_regs->ARM_r9; + gdb_regs[_R10] = thread_regs->ARM_r10; + gdb_regs[_FP] = thread_regs->ARM_fp; + gdb_regs[_IP] = thread_regs->ARM_ip; + gdb_regs[_SPT] = thread_regs->ARM_sp; + gdb_regs[_LR] = thread_regs->ARM_lr; + gdb_regs[_PC] = thread_regs->ARM_pc; + gdb_regs[_CPSR] = thread_regs->ARM_cpsr; +} + +static int compiled_break; + +int kgdb_arch_handle_exception(int exception_vector, int signo, + int err_code, char *remcom_in_buffer, + char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + unsigned long addr; + char *ptr; + + switch (remcom_in_buffer[0]) { + case 'D': + case 'k': + case 'c': + kgdb_contthread = NULL; + + /* + * Try to read optional parameter, pc unchanged if no parm. + * If this was a compiled breakpoint, we need to move + * to the next instruction or we will just breakpoint + * over and over again. + */ + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr)) + linux_regs->ARM_pc = addr; + else if (compiled_break == 1) + linux_regs->ARM_pc += 4; + + compiled_break = 0; + + return 0; + } + + return -1; +} + +static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr) +{ + kgdb_handle_exception(1, SIGTRAP, 0, regs); + + return 0; +} + +static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr) +{ + compiled_break = 1; + kgdb_handle_exception(1, SIGTRAP, 0, regs); + + return 0; +} + +static struct undef_hook kgdb_brkpt_hook = { + .instr_mask = 0xffffffff, + .instr_val = KGDB_BREAKINST, + .fn = kgdb_brk_fn +}; + +static struct undef_hook kgdb_compiled_brkpt_hook = { + .instr_mask = 0xffffffff, + .instr_val = KGDB_COMPILED_BREAK, + .fn = kgdb_compiled_brk_fn +}; + +/** + * kgdb_arch_init - Perform any architecture specific initalization. + * + * This function will handle the initalization of any architecture + * specific callbacks. + */ +int kgdb_arch_init(void) +{ + register_undef_hook(&kgdb_brkpt_hook); + register_undef_hook(&kgdb_compiled_brkpt_hook); + + return 0; +} + +/** + * kgdb_arch_exit - Perform any architecture specific uninitalization. + * + * This function will handle the uninitalization of any architecture + * specific callbacks, for dynamic registration and unregistration. + */ +void kgdb_arch_exit(void) +{ + unregister_undef_hook(&kgdb_brkpt_hook); + unregister_undef_hook(&kgdb_compiled_brkpt_hook); +} + +/* + * Register our undef instruction hooks with ARM undef core. + * We regsiter a hook specifically looking for the KGB break inst + * and we handle the normal undef case within the do_undefinstr + * handler. + */ +struct kgdb_arch arch_kgdb_ops = { +#ifndef __ARMEB__ + .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7} +#else /* ! __ARMEB__ */ + .gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe} +#endif +}; diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 5593dd207216..5ee39e10c8d1 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -274,7 +274,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, * for kretprobe handlers which should normally be interested in r0 only * anyway. */ -static void __attribute__((naked)) __kprobes kretprobe_trampoline(void) +void __naked __kprobes kretprobe_trampoline(void) { __asm__ __volatile__ ( "stmdb sp!, {r0 - r11} \n\t" diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index b7b0720bc1bb..38f0e7940a13 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -36,6 +36,7 @@ #include <asm/mach/arch.h> #include <asm/mach/irq.h> #include <asm/mach/time.h> +#include <asm/traps.h> #include "compat.h" #include "atags.h" @@ -853,6 +854,7 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif #endif + early_trap_init(); } diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index eefae1de334c..5a7c09564d13 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -68,20 +68,10 @@ enum ipi_msg_type { IPI_TIMER, IPI_RESCHEDULE, IPI_CALL_FUNC, + IPI_CALL_FUNC_SINGLE, IPI_CPU_STOP, }; -struct smp_call_struct { - void (*func)(void *info); - void *info; - int wait; - cpumask_t pending; - cpumask_t unfinished; -}; - -static struct smp_call_struct * volatile smp_call_function_data; -static DEFINE_SPINLOCK(smp_call_function_lock); - int __cpuinit __cpu_up(unsigned int cpu) { struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); @@ -366,114 +356,15 @@ static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg) local_irq_restore(flags); } -/* - * You must not call this function with disabled interrupts, from a - * hardware interrupt handler, nor from a bottom half handler. - */ -static int smp_call_function_on_cpu(void (*func)(void *info), void *info, - int retry, int wait, cpumask_t callmap) -{ - struct smp_call_struct data; - unsigned long timeout; - int ret = 0; - - data.func = func; - data.info = info; - data.wait = wait; - - cpu_clear(smp_processor_id(), callmap); - if (cpus_empty(callmap)) - goto out; - - data.pending = callmap; - if (wait) - data.unfinished = callmap; - - /* - * try to get the mutex on smp_call_function_data - */ - spin_lock(&smp_call_function_lock); - smp_call_function_data = &data; - - send_ipi_message(callmap, IPI_CALL_FUNC); - - timeout = jiffies + HZ; - while (!cpus_empty(data.pending) && time_before(jiffies, timeout)) - barrier(); - - /* - * did we time out? - */ - if (!cpus_empty(data.pending)) { - /* - * this may be causing our panic - report it - */ - printk(KERN_CRIT - "CPU%u: smp_call_function timeout for %p(%p)\n" - " callmap %lx pending %lx, %swait\n", - smp_processor_id(), func, info, *cpus_addr(callmap), - *cpus_addr(data.pending), wait ? "" : "no "); - - /* - * TRACE - */ - timeout = jiffies + (5 * HZ); - while (!cpus_empty(data.pending) && time_before(jiffies, timeout)) - barrier(); - - if (cpus_empty(data.pending)) - printk(KERN_CRIT " RESOLVED\n"); - else - printk(KERN_CRIT " STILL STUCK\n"); - } - - /* - * whatever happened, we're done with the data, so release it - */ - smp_call_function_data = NULL; - spin_unlock(&smp_call_function_lock); - - if (!cpus_empty(data.pending)) { - ret = -ETIMEDOUT; - goto out; - } - - if (wait) - while (!cpus_empty(data.unfinished)) - barrier(); - out: - - return 0; -} - -int smp_call_function(void (*func)(void *info), void *info, int retry, - int wait) +void arch_send_call_function_ipi(cpumask_t mask) { - return smp_call_function_on_cpu(func, info, retry, wait, - cpu_online_map); + send_ipi_message(mask, IPI_CALL_FUNC); } -EXPORT_SYMBOL_GPL(smp_call_function); -int smp_call_function_single(int cpu, void (*func)(void *info), void *info, - int retry, int wait) +void arch_send_call_function_single_ipi(int cpu) { - /* prevent preemption and reschedule on another processor */ - int current_cpu = get_cpu(); - int ret = 0; - - if (cpu == current_cpu) { - local_irq_disable(); - func(info); - local_irq_enable(); - } else - ret = smp_call_function_on_cpu(func, info, retry, wait, - cpumask_of_cpu(cpu)); - - put_cpu(); - - return ret; + send_ipi_message(cpumask_of_cpu(cpu), IPI_CALL_FUNC_SINGLE); } -EXPORT_SYMBOL_GPL(smp_call_function_single); void show_ipi_list(struct seq_file *p) { @@ -521,27 +412,6 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) } #endif -/* - * ipi_call_function - handle IPI from smp_call_function() - * - * Note that we copy data out of the cross-call structure and then - * let the caller know that we're here and have done with their data - */ -static void ipi_call_function(unsigned int cpu) -{ - struct smp_call_struct *data = smp_call_function_data; - void (*func)(void *info) = data->func; - void *info = data->info; - int wait = data->wait; - - cpu_clear(cpu, data->pending); - - func(info); - - if (wait) - cpu_clear(cpu, data->unfinished); -} - static DEFINE_SPINLOCK(stop_lock); /* @@ -611,7 +481,11 @@ asmlinkage void __exception do_IPI(struct pt_regs *regs) break; case IPI_CALL_FUNC: - ipi_call_function(cpu); + generic_smp_call_function_interrupt(); + break; + + case IPI_CALL_FUNC_SINGLE: + generic_smp_call_function_single_interrupt(); break; case IPI_CPU_STOP: @@ -662,14 +536,13 @@ int setup_profiling_timer(unsigned int multiplier) } static int -on_each_cpu_mask(void (*func)(void *), void *info, int retry, int wait, - cpumask_t mask) +on_each_cpu_mask(void (*func)(void *), void *info, int wait, cpumask_t mask) { int ret = 0; preempt_disable(); - ret = smp_call_function_on_cpu(func, info, retry, wait, mask); + ret = smp_call_function_mask(mask, func, info, wait); if (cpu_isset(smp_processor_id(), mask)) func(info); @@ -731,14 +604,14 @@ static inline void ipi_flush_tlb_kernel_range(void *arg) void flush_tlb_all(void) { - on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1); + on_each_cpu(ipi_flush_tlb_all, NULL, 1); } void flush_tlb_mm(struct mm_struct *mm) { cpumask_t mask = mm->cpu_vm_mask; - on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, 1, mask); + on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mask); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) @@ -749,7 +622,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) ta.ta_vma = vma; ta.ta_start = uaddr; - on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, 1, mask); + on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mask); } void flush_tlb_kernel_page(unsigned long kaddr) @@ -758,7 +631,7 @@ void flush_tlb_kernel_page(unsigned long kaddr) ta.ta_start = kaddr; - on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1, 1); + on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); } void flush_tlb_range(struct vm_area_struct *vma, @@ -771,7 +644,7 @@ void flush_tlb_range(struct vm_area_struct *vma, ta.ta_start = start; ta.ta_end = end; - on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, 1, mask); + on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mask); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) @@ -781,5 +654,5 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) ta.ta_start = start; ta.ta_end = end; - on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1, 1); + on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); } diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 90e0c35ae60d..fc650f64df43 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -92,4 +92,5 @@ void save_stack_trace(struct stack_trace *trace) { save_stack_trace_tsk(current, trace); } +EXPORT_SYMBOL_GPL(save_stack_trace); #endif diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index cc5145b28e7f..368d171754cf 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -130,7 +130,9 @@ static const struct leds_evt_name evt_names[] = { { "red", led_red_on, led_red_off }, }; -static ssize_t leds_store(struct sys_device *dev, const char *buf, size_t size) +static ssize_t leds_store(struct sys_device *dev, + struct sysdev_attribute *attr, + const char *buf, size_t size) { int ret = -EINVAL, len = strcspn(buf, " "); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 5595fdd75e82..7277aef83098 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -708,6 +708,11 @@ EXPORT_SYMBOL(abort); void __init trap_init(void) { + return; +} + +void __init early_trap_init(void) +{ unsigned long vectors = CONFIG_VECTORS_BASE; extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 62e653a3ea1a..5a1588cf8242 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -393,9 +393,7 @@ static int impd1_probe(struct lm_device *dev) if (!d) continue; - snprintf(d->dev.bus_id, sizeof(d->dev.bus_id), - "lm%x:%5.5lx", dev->id, idev->offset >> 12); - + dev_set_name(&d->dev, "lm%x:%5.5lx", dev->id, idev->offset >> 12); d->dev.parent = &dev->dev; d->res.start = dev->resource.start + idev->offset; d->res.end = d->res.start + SZ_4K - 1; @@ -407,8 +405,7 @@ static int impd1_probe(struct lm_device *dev) ret = amba_device_register(d, &dev->resource); if (ret) { - printk("unable to register device %s: %d\n", - d->dev.bus_id, ret); + dev_err(&d->dev, "unable to register device: %d\n"); kfree(d); } } diff --git a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c index 622cdc4212dd..f939c5091405 100644 --- a/arch/arm/mach-integrator/lm.c +++ b/arch/arm/mach-integrator/lm.c @@ -81,8 +81,10 @@ int lm_device_register(struct lm_device *dev) dev->dev.release = lm_device_release; dev->dev.bus = &lm_bustype; - snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "lm%d", dev->id); - dev->resource.name = dev->dev.bus_id; + ret = dev_set_name(&dev->dev, "lm%d", dev->id); + if (ret) + return ret; + dev->resource.name = dev_name(&dev->dev); ret = request_resource(&iomem_resource, &dev->resource); if (ret == 0) { diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c index 74fae6045650..4458705021e0 100644 --- a/arch/arm/oprofile/op_model_mpcore.c +++ b/arch/arm/oprofile/op_model_mpcore.c @@ -201,7 +201,7 @@ static int em_call_function(int (*fn)(void)) data.ret = 0; preempt_disable(); - smp_call_function(em_func, &data, 1, 1); + smp_call_function(em_func, &data, 1); em_func(&data); preempt_enable(); diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 6f33f58bca45..ff1413eae0b8 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -334,7 +334,7 @@ static int omap_mbox_init(struct omap_mbox *mbox) } mbox->dev.class = &omap_mbox_class; - strlcpy(mbox->dev.bus_id, mbox->name, KOBJ_NAME_LEN); + dev_set_name(&mbox->dev, "%s", mbox->name); dev_set_drvdata(&mbox->dev, mbox); ret = device_register(&mbox->dev); diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 32455c633f1c..c0d2c9bb952b 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -352,7 +352,7 @@ static int __init vfp_init(void) else if (vfpsid & FPSID_NODOUBLE) { printk("no double precision support\n"); } else { - smp_call_function(vfp_enable, NULL, 1, 1); + smp_call_function(vfp_enable, NULL, 1); VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ printk("implementor %02x architecture %d part %02x variant %x rev %x\n", |