From 3611553ef985ef7c5863c8a94641738addd04cff Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 5 Jul 2007 17:08:09 +0200 Subject: [AVR32] Drop GFP_COMP for DMA memory allocations dma_alloc_coherent wants to split pages after allocation in order to reduce the memory footprint. This does not work well with GFP_COMP pages, so drop this flag before allocation. This patch was forward-ported from BSP 2.0 Signed-off-by: Haavard Skinnemoen --- arch/avr32/mm/dma-coherent.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch') diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c index 177fea8f7b71..6d8c794c3b81 100644 --- a/arch/avr32/mm/dma-coherent.c +++ b/arch/avr32/mm/dma-coherent.c @@ -41,6 +41,13 @@ static struct page *__dma_alloc(struct device *dev, size_t size, struct page *page, *free, *end; int order; + /* Following is a work-around (a.k.a. hack) to prevent pages + * with __GFP_COMP being passed to split_page() which cannot + * handle them. The real problem is that this flag probably + * should be 0 on AVR32 as it is not supported on this + * platform--see CONFIG_HUGETLB_PAGE. */ + gfp &= ~(__GFP_COMP); + size = PAGE_ALIGN(size); order = get_order(size); -- cgit v1.2.1 From 7f0f616bb093823b70855685cf085d39a8784818 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 28 Nov 2007 14:51:44 +0100 Subject: [AVR32] Remove redundant try_to_freeze() call from do_signal() get_signal_to_deliver() will call try_to_freeze(), so there's no point in do_signal() doing it as well. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/signal.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'arch') diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 0ec14854a200..5616a00c10ba 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -270,19 +270,12 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall) if (!user_mode(regs)) return 0; - if (try_to_freeze()) { - signr = 0; - if (!signal_pending(current)) - goto no_signal; - } - if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else if (!oldset) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); -no_signal: if (syscall) { switch (regs->r12) { case -ERESTART_RESTARTBLOCK: -- cgit v1.2.1 From 13b54a50525a9685065684e1e11258d27dd27bdf Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Tue, 27 Nov 2007 13:50:45 +0100 Subject: [AVR32] Enable debugging only when needed Keep track of processes being debugged (including the kernel itself) and turn the OCD system on and off as appropriate. Since enabling debugging turns off some optimizations in the CPU core, this fixes the issue that enabling KProbes support or simply running a program under gdbserver will reduce system performance significantly until the next reboot. The CPU performance will still be reduced for all processes while a process is being debugged, but this is a lot better than reducing the performance forever. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/Makefile | 2 +- arch/avr32/kernel/kprobes.c | 5 +- arch/avr32/kernel/ocd.c | 163 ++++++++++++++++++++++++++++++++++++++++++++ arch/avr32/kernel/process.c | 5 +- arch/avr32/kernel/ptrace.c | 5 +- 5 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 arch/avr32/kernel/ocd.c (limited to 'arch') diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index 2d6d48f35f69..bc224a4e39fe 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o vmlinux.lds obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o obj-y += syscall_table.o syscall-stubs.o irq.o -obj-y += setup.o traps.o semaphore.o ptrace.o +obj-y += setup.o traps.o semaphore.o ocd.o ptrace.o obj-y += signal.o sys_avr32.o process.o time.o obj-y += init_task.o switch_to.o cpu.o obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c index 799ba89b07a8..f820e9f25520 100644 --- a/arch/avr32/kernel/kprobes.c +++ b/arch/avr32/kernel/kprobes.c @@ -48,6 +48,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) void __kprobes arch_arm_kprobe(struct kprobe *p) { pr_debug("arming kprobe at %p\n", p->addr); + ocd_enable(NULL); *p->addr = BREAKPOINT_INSTRUCTION; flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); @@ -56,6 +57,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) void __kprobes arch_disarm_kprobe(struct kprobe *p) { pr_debug("disarming kprobe at %p\n", p->addr); + ocd_disable(NULL); *p->addr = p->opcode; flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); @@ -260,9 +262,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) int __init arch_init_kprobes(void) { - printk("KPROBES: Enabling monitor mode (MM|DBE)...\n"); - ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT)); - /* TODO: Register kretprobe trampoline */ return 0; } diff --git a/arch/avr32/kernel/ocd.c b/arch/avr32/kernel/ocd.c new file mode 100644 index 000000000000..c4f023294d75 --- /dev/null +++ b/arch/avr32/kernel/ocd.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include + +static long ocd_count; +static spinlock_t ocd_lock; + +/** + * ocd_enable - enable on-chip debugging + * @child: task to be debugged + * + * If @child is non-NULL, ocd_enable() first checks if debugging has + * already been enabled for @child, and if it has, does nothing. + * + * If @child is NULL (e.g. when debugging the kernel), or debugging + * has not already been enabled for it, ocd_enable() increments the + * reference count and enables the debugging hardware. + */ +void ocd_enable(struct task_struct *child) +{ + u32 dc; + + if (child) + pr_debug("ocd_enable: child=%s [%u]\n", + child->comm, child->pid); + else + pr_debug("ocd_enable (no child)\n"); + + if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) { + spin_lock(&ocd_lock); + ocd_count++; + dc = ocd_read(DC); + dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT); + ocd_write(DC, dc); + spin_unlock(&ocd_lock); + } +} + +/** + * ocd_disable - disable on-chip debugging + * @child: task that was being debugged, but isn't anymore + * + * If @child is non-NULL, ocd_disable() checks if debugging is enabled + * for @child, and if it isn't, does nothing. + * + * If @child is NULL (e.g. when debugging the kernel), or debugging is + * enabled, ocd_disable() decrements the reference count, and if it + * reaches zero, disables the debugging hardware. + */ +void ocd_disable(struct task_struct *child) +{ + u32 dc; + + if (!child) + pr_debug("ocd_disable (no child)\n"); + else if (test_tsk_thread_flag(child, TIF_DEBUG)) + pr_debug("ocd_disable: child=%s [%u]\n", + child->comm, child->pid); + + if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) { + spin_lock(&ocd_lock); + ocd_count--; + + WARN_ON(ocd_count < 0); + + if (ocd_count <= 0) { + dc = ocd_read(DC); + dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT)); + ocd_write(DC, dc); + } + spin_unlock(&ocd_lock); + } +} + +#ifdef CONFIG_DEBUG_FS +#include +#include + +static struct dentry *ocd_debugfs_root; +static struct dentry *ocd_debugfs_DC; +static struct dentry *ocd_debugfs_DS; +static struct dentry *ocd_debugfs_count; + +static u64 ocd_DC_get(void *data) +{ + return ocd_read(DC); +} +static void ocd_DC_set(void *data, u64 val) +{ + ocd_write(DC, val); +} +DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n"); + +static u64 ocd_DS_get(void *data) +{ + return ocd_read(DS); +} +DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n"); + +static u64 ocd_count_get(void *data) +{ + return ocd_count; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n"); + +static void ocd_debugfs_init(void) +{ + struct dentry *root; + + root = debugfs_create_dir("ocd", NULL); + if (IS_ERR(root) || !root) + goto err_root; + ocd_debugfs_root = root; + + ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR, + root, NULL, &fops_DC); + if (!ocd_debugfs_DC) + goto err_DC; + + ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root, + NULL, &fops_DS); + if (!ocd_debugfs_DS) + goto err_DS; + + ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root, + NULL, &fops_count); + if (!ocd_debugfs_count) + goto err_count; + + return; + +err_count: + debugfs_remove(ocd_debugfs_DS); +err_DS: + debugfs_remove(ocd_debugfs_DC); +err_DC: + debugfs_remove(ocd_debugfs_root); +err_root: + printk(KERN_WARNING "OCD: Failed to create debugfs entries\n"); +} +#else +static inline void ocd_debugfs_init(void) +{ + +} +#endif + +static int __init ocd_init(void) +{ + spin_lock_init(&ocd_lock); + ocd_debugfs_init(); + return 0; +} +arch_initcall(ocd_init); diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index 9d6dac8af7a2..eaaa69bbdc38 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -103,7 +103,7 @@ EXPORT_SYMBOL(kernel_thread); */ void exit_thread(void) { - /* nothing to do */ + ocd_disable(current); } void flush_thread(void) @@ -345,6 +345,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, p->thread.cpu_context.ksp = (unsigned long)childregs; p->thread.cpu_context.pc = (unsigned long)ret_from_fork; + if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) + ocd_enable(p); + return 0; } diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c index 002369e44093..1fed38fcf594 100644 --- a/arch/avr32/kernel/ptrace.c +++ b/arch/avr32/kernel/ptrace.c @@ -58,6 +58,7 @@ void ptrace_disable(struct task_struct *child) { clear_tsk_thread_flag(child, TIF_SINGLE_STEP); clear_tsk_thread_flag(child, TIF_BREAKPOINT); + ocd_disable(child); } /* @@ -144,10 +145,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; - pr_debug("ptrace: Enabling monitor mode...\n"); - ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT) - | (1 << OCD_DC_DBE_BIT)); - switch (request) { /* Read the word at location addr in the child process */ case PTRACE_PEEKTEXT: -- cgit v1.2.1 From a7f5bf9b95ace39cd8b61e8c9ca1035966779ed1 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 31 Oct 2007 15:22:34 +0100 Subject: [AVR32] Include instrumentation menu Remove KPROBES option from Kconfig.debug and include kernel/Kconfig.instrumentation. Signed-off-by: Haavard Skinnemoen --- arch/avr32/Kconfig | 2 ++ arch/avr32/Kconfig.debug | 10 ---------- 2 files changed, 2 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index b77abce10c7a..bc08c7f0883f 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -219,6 +219,8 @@ source "drivers/Kconfig" source "fs/Kconfig" +source "kernel/Kconfig.instrumentation" + source "arch/avr32/Kconfig.debug" source "security/Kconfig" diff --git a/arch/avr32/Kconfig.debug b/arch/avr32/Kconfig.debug index 64ace00fe6cb..2283933a9a93 100644 --- a/arch/avr32/Kconfig.debug +++ b/arch/avr32/Kconfig.debug @@ -6,14 +6,4 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" -config KPROBES - bool "Kprobes" - depends on DEBUG_KERNEL - help - Kprobes allows you to trap at almost any kernel address and - execute a callback function. register_kprobe() establishes - a probepoint and specifies the callback. Kprobes is useful - for kernel debugging, non-intrusive instrumentation and testing. - If in doubt, say "N". - endmenu -- cgit v1.2.1 From 2853ce5ecefe9d9ca119f33db0c23a3f075e35d9 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Jan 2006 17:26:23 +0100 Subject: [AVR32] Oprofile support This adds the necessary architecture code to run oprofile on AVR32 using the performance counters documented by the AVR32 Architecture Manual. Signed-off-by: Haavard Skinnemoen Acked-by: Philippe Elie --- arch/avr32/Kconfig | 3 + arch/avr32/Makefile | 1 + arch/avr32/oprofile/Makefile | 8 ++ arch/avr32/oprofile/op_model_avr32.c | 235 +++++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 arch/avr32/oprofile/Makefile create mode 100644 arch/avr32/oprofile/op_model_avr32.c (limited to 'arch') diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index bc08c7f0883f..767a19cfa423 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -54,6 +54,9 @@ config ARCH_HAS_ILOG2_U32 config ARCH_HAS_ILOG2_U64 def_bool n +config ARCH_SUPPORTS_OPROFILE + def_bool y + config GENERIC_HWEIGHT def_bool y diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile index 87918647be6d..f75d52cd2a4c 100644 --- a/arch/avr32/Makefile +++ b/arch/avr32/Makefile @@ -31,6 +31,7 @@ core-$(CONFIG_BOARD_ATNGW100) += arch/avr32/boards/atngw100/ core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/ core-y += arch/avr32/kernel/ core-y += arch/avr32/mm/ +drivers-$(CONFIG_OPROFILE) += arch/avr32/oprofile/ libs-y += arch/avr32/lib/ archincdir-$(CONFIG_PLATFORM_AT32AP) := arch-at32ap diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile new file mode 100644 index 000000000000..1fe81c3c1e86 --- /dev/null +++ b/arch/avr32/oprofile/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +oprofile-y := $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o) +oprofile-y += op_model_avr32.o diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c new file mode 100644 index 000000000000..e2f876bfc86b --- /dev/null +++ b/arch/avr32/oprofile/op_model_avr32.c @@ -0,0 +1,235 @@ +/* + * AVR32 Performance Counter Driver + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Author: Ronny Pedersen + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define AVR32_PERFCTR_IRQ_GROUP 0 +#define AVR32_PERFCTR_IRQ_LINE 1 + +enum { PCCNT, PCNT0, PCNT1, NR_counter }; + +struct avr32_perf_counter { + unsigned long enabled; + unsigned long event; + unsigned long count; + unsigned long unit_mask; + unsigned long kernel; + unsigned long user; + + u32 ie_mask; + u32 flag_mask; +}; + +static struct avr32_perf_counter counter[NR_counter] = { + { + .ie_mask = SYSREG_BIT(IEC), + .flag_mask = SYSREG_BIT(FC), + }, { + .ie_mask = SYSREG_BIT(IE0), + .flag_mask = SYSREG_BIT(F0), + }, { + .ie_mask = SYSREG_BIT(IE1), + .flag_mask = SYSREG_BIT(F1), + }, +}; + +static void avr32_perf_counter_reset(void) +{ + /* Reset all counter and disable/clear all interrupts */ + sysreg_write(PCCR, (SYSREG_BIT(PCCR_R) + | SYSREG_BIT(PCCR_C) + | SYSREG_BIT(FC) + | SYSREG_BIT(F0) + | SYSREG_BIT(F1))); +} + +static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id) +{ + struct avr32_perf_counter *ctr = dev_id; + struct pt_regs *regs; + u32 pccr; + + if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP) + & (1 << AVR32_PERFCTR_IRQ_LINE)))) + return IRQ_NONE; + + regs = get_irq_regs(); + pccr = sysreg_read(PCCR); + + /* Clear the interrupt flags we're about to handle */ + sysreg_write(PCCR, pccr); + + /* PCCNT */ + if (ctr->enabled && (pccr & ctr->flag_mask)) { + sysreg_write(PCCNT, -ctr->count); + oprofile_add_sample(regs, PCCNT); + } + ctr++; + /* PCNT0 */ + if (ctr->enabled && (pccr & ctr->flag_mask)) { + sysreg_write(PCNT0, -ctr->count); + oprofile_add_sample(regs, PCNT0); + } + ctr++; + /* PCNT1 */ + if (ctr->enabled && (pccr & ctr->flag_mask)) { + sysreg_write(PCNT1, -ctr->count); + oprofile_add_sample(regs, PCNT1); + } + + return IRQ_HANDLED; +} + +static int avr32_perf_counter_create_files(struct super_block *sb, + struct dentry *root) +{ + struct dentry *dir; + unsigned int i; + char filename[4]; + + for (i = 0; i < NR_counter; i++) { + snprintf(filename, sizeof(filename), "%u", i); + dir = oprofilefs_mkdir(sb, root, filename); + + oprofilefs_create_ulong(sb, dir, "enabled", + &counter[i].enabled); + oprofilefs_create_ulong(sb, dir, "event", + &counter[i].event); + oprofilefs_create_ulong(sb, dir, "count", + &counter[i].count); + + /* Dummy entries */ + oprofilefs_create_ulong(sb, dir, "kernel", + &counter[i].kernel); + oprofilefs_create_ulong(sb, dir, "user", + &counter[i].user); + oprofilefs_create_ulong(sb, dir, "unit_mask", + &counter[i].unit_mask); + } + + return 0; +} + +static int avr32_perf_counter_setup(void) +{ + struct avr32_perf_counter *ctr; + u32 pccr; + int ret; + int i; + + pr_debug("avr32_perf_counter_setup\n"); + + if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) { + printk(KERN_ERR + "oprofile: setup: perf counter already enabled\n"); + return -EBUSY; + } + + ret = request_irq(AVR32_PERFCTR_IRQ_GROUP, + avr32_perf_counter_interrupt, IRQF_SHARED, + "oprofile", counter); + if (ret) + return ret; + + avr32_perf_counter_reset(); + + pccr = 0; + for (i = PCCNT; i < NR_counter; i++) { + ctr = &counter[i]; + if (!ctr->enabled) + continue; + + pr_debug("enabling counter %d...\n", i); + + pccr |= ctr->ie_mask; + + switch (i) { + case PCCNT: + /* PCCNT always counts cycles, so no events */ + sysreg_write(PCCNT, -ctr->count); + break; + case PCNT0: + pccr |= SYSREG_BF(CONF0, ctr->event); + sysreg_write(PCNT0, -ctr->count); + break; + case PCNT1: + pccr |= SYSREG_BF(CONF1, ctr->event); + sysreg_write(PCNT1, -ctr->count); + break; + } + } + + pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr); + + sysreg_write(PCCR, pccr); + + return 0; +} + +static void avr32_perf_counter_shutdown(void) +{ + pr_debug("avr32_perf_counter_shutdown\n"); + + avr32_perf_counter_reset(); + free_irq(AVR32_PERFCTR_IRQ_GROUP, counter); +} + +static int avr32_perf_counter_start(void) +{ + pr_debug("avr32_perf_counter_start\n"); + + sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E)); + + return 0; +} + +static void avr32_perf_counter_stop(void) +{ + pr_debug("avr32_perf_counter_stop\n"); + + sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E)); +} + +static struct oprofile_operations avr32_perf_counter_ops __initdata = { + .create_files = avr32_perf_counter_create_files, + .setup = avr32_perf_counter_setup, + .shutdown = avr32_perf_counter_shutdown, + .start = avr32_perf_counter_start, + .stop = avr32_perf_counter_stop, + .cpu_type = "avr32", +}; + +int __init oprofile_arch_init(struct oprofile_operations *ops) +{ + if (!(current_cpu_data.features & AVR32_FEATURE_PCTR)) + return -ENODEV; + + memcpy(ops, &avr32_perf_counter_ops, + sizeof(struct oprofile_operations)); + + printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n"); + + return 0; +} + +void oprofile_arch_exit(void) +{ + +} -- cgit v1.2.1 From 281ef58ccf62eaa6c4e4b7e4c0a3ee6b52e84e5b Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 7 Dec 2007 10:21:02 +0100 Subject: [AVR32] Provide more CPU information in /proc/cpuinfo and dmesg Add the following fields to /proc/cpuinfo: * chip type and revision (from the JTAG chip id) * cpu MHz (from clk_get_rate()) * features (from the CONFIG0 register) Also rename "cpu family" to "cpu arch" and "cpu type" to "cpu core" to remove some ambiguity. Show chip type and revision at bootup, and clarify that the other kinds of IDs that we're already printing are for the cpu core and architecture. Rename "AP7000" to "AP7" since that's the name of the core. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/cpu.c | 94 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 26 deletions(-) (limited to 'arch') diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c index 2714cf6452b5..14610019216e 100644 --- a/arch/avr32/kernel/cpu.c +++ b/arch/avr32/kernel/cpu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -187,9 +188,20 @@ static int __init topology_init(void) subsys_initcall(topology_init); +struct chip_id_map { + u16 mid; + u16 pn; + const char *name; +}; + +static const struct chip_id_map chip_names[] = { + { .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" }, +}; +#define NR_CHIP_NAMES ARRAY_SIZE(chip_names) + static const char *cpu_names[] = { "Morgan", - "AP7000", + "AP7", }; #define NR_CPU_NAMES ARRAY_SIZE(cpu_names) @@ -206,12 +218,32 @@ static const char *mmu_types[] = { "MPU" }; +static const char *cpu_feature_flags[] = { + "rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu", +}; + +static const char *get_chip_name(struct avr32_cpuinfo *cpu) +{ + unsigned int i; + unsigned int mid = avr32_get_manufacturer_id(cpu); + unsigned int pn = avr32_get_product_number(cpu); + + for (i = 0; i < NR_CHIP_NAMES; i++) { + if (chip_names[i].mid == mid && chip_names[i].pn == pn) + return chip_names[i].name; + } + + return "(unknown)"; +} + void __init setup_processor(void) { unsigned long config0, config1; unsigned long features; unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type; + unsigned device_id; unsigned tmp; + unsigned i; config0 = sysreg_read(CONFIG0); config1 = sysreg_read(CONFIG1); @@ -221,11 +253,14 @@ void __init setup_processor(void) arch_rev = SYSREG_BFEXT(AR, config0); mmu_type = SYSREG_BFEXT(MMUT, config0); + device_id = ocd_read(DID); + boot_cpu_data.arch_type = arch_id; boot_cpu_data.cpu_type = cpu_id; boot_cpu_data.arch_revision = arch_rev; boot_cpu_data.cpu_revision = cpu_rev; boot_cpu_data.tlb_config = mmu_type; + boot_cpu_data.device_id = device_id; tmp = SYSREG_BFEXT(ILSZ, config1); if (tmp) { @@ -247,41 +282,34 @@ void __init setup_processor(void) return; } - printk ("CPU: %s [%02x] revision %d (%s revision %d)\n", + printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data), + avr32_get_chip_revision(&boot_cpu_data) + 'A'); + printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n", cpu_names[cpu_id], cpu_id, cpu_rev, arch_names[arch_id], arch_rev); printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]); printk ("CPU: features:"); features = 0; - if (config0 & SYSREG_BIT(CONFIG0_R)) { + if (config0 & SYSREG_BIT(CONFIG0_R)) features |= AVR32_FEATURE_RMW; - printk(" rmw"); - } - if (config0 & SYSREG_BIT(CONFIG0_D)) { + if (config0 & SYSREG_BIT(CONFIG0_D)) features |= AVR32_FEATURE_DSP; - printk(" dsp"); - } - if (config0 & SYSREG_BIT(CONFIG0_S)) { + if (config0 & SYSREG_BIT(CONFIG0_S)) features |= AVR32_FEATURE_SIMD; - printk(" simd"); - } - if (config0 & SYSREG_BIT(CONFIG0_O)) { + if (config0 & SYSREG_BIT(CONFIG0_O)) features |= AVR32_FEATURE_OCD; - printk(" ocd"); - } - if (config0 & SYSREG_BIT(CONFIG0_P)) { + if (config0 & SYSREG_BIT(CONFIG0_P)) features |= AVR32_FEATURE_PCTR; - printk(" perfctr"); - } - if (config0 & SYSREG_BIT(CONFIG0_J)) { + if (config0 & SYSREG_BIT(CONFIG0_J)) features |= AVR32_FEATURE_JAVA; - printk(" java"); - } - if (config0 & SYSREG_BIT(CONFIG0_F)) { + if (config0 & SYSREG_BIT(CONFIG0_F)) features |= AVR32_FEATURE_FPU; - printk(" fpu"); - } + + for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++) + if (features & (1 << i)) + printk(" %s", cpu_feature_flags[i]); + printk("\n"); boot_cpu_data.features = features; } @@ -291,6 +319,8 @@ static int c_show(struct seq_file *m, void *v) { unsigned int icache_size, dcache_size; unsigned int cpu = smp_processor_id(); + unsigned int freq; + unsigned int i; icache_size = boot_cpu_data.icache.ways * boot_cpu_data.icache.sets * @@ -301,15 +331,21 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "processor\t: %d\n", cpu); + seq_printf(m, "chip type\t: %s revision %c\n", + get_chip_name(&boot_cpu_data), + avr32_get_chip_revision(&boot_cpu_data) + 'A'); if (boot_cpu_data.arch_type < NR_ARCH_NAMES) - seq_printf(m, "cpu family\t: %s revision %d\n", + seq_printf(m, "cpu arch\t: %s revision %d\n", arch_names[boot_cpu_data.arch_type], boot_cpu_data.arch_revision); if (boot_cpu_data.cpu_type < NR_CPU_NAMES) - seq_printf(m, "cpu type\t: %s revision %d\n", + seq_printf(m, "cpu core\t: %s revision %d\n", cpu_names[boot_cpu_data.cpu_type], boot_cpu_data.cpu_revision); + freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000; + seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000); + seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n", icache_size >> 10, boot_cpu_data.icache.ways, @@ -320,7 +356,13 @@ static int c_show(struct seq_file *m, void *v) boot_cpu_data.dcache.ways, boot_cpu_data.dcache.sets, boot_cpu_data.dcache.linesz); - seq_printf(m, "bogomips\t: %lu.%02lu\n", + + seq_printf(m, "features\t:"); + for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++) + if (boot_cpu_data.features & (1 << i)) + seq_printf(m, " %s", cpu_feature_flags[i]); + + seq_printf(m, "\nbogomips\t: %lu.%02lu\n", boot_cpu_data.loops_per_jiffy / (500000/HZ), (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100); -- cgit v1.2.1 From 438ff3f3cc33833206a48492e9d6674e4e82bed8 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Mon, 29 Oct 2007 15:28:07 +0100 Subject: [AVR32] Add support for AT32AP7001 and AT32AP7002 These are derivatives of the AT32AP7000 chip, which means that most of the code stays the same. Rename a few files, functions, definitions and config symbols to reflect that they apply to all AP700x chips, and exclude some platform devices from chips where they aren't present. Signed-off-by: Haavard Skinnemoen --- arch/avr32/Kconfig | 21 +- arch/avr32/Makefile | 2 +- arch/avr32/boards/atngw100/setup.c | 2 +- arch/avr32/configs/atngw100_defconfig | 9 +- arch/avr32/configs/atstk1002_defconfig | 8 +- arch/avr32/mach-at32ap/Kconfig | 12 +- arch/avr32/mach-at32ap/Makefile | 4 +- arch/avr32/mach-at32ap/at32ap7000.c | 1730 ------------------------------- arch/avr32/mach-at32ap/at32ap700x.c | 1742 ++++++++++++++++++++++++++++++++ 9 files changed, 1780 insertions(+), 1750 deletions(-) delete mode 100644 arch/avr32/mach-at32ap/at32ap7000.c create mode 100644 arch/avr32/mach-at32ap/at32ap700x.c (limited to 'arch') diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index 767a19cfa423..e37e6b92658d 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -84,13 +84,26 @@ config PLATFORM_AT32AP select MMU select PERFORMANCE_COUNTERS +config CPU_AT32AP700X + bool + select PLATFORM_AT32AP + choice prompt "AVR32 CPU type" default CPU_AT32AP7000 config CPU_AT32AP7000 bool "AT32AP7000" - select PLATFORM_AT32AP + select CPU_AT32AP700X + +config CPU_AT32AP7001 + bool "AT32AP7001" + select CPU_AT32AP700X + +config CPU_AT32AP7002 + bool "AT32AP7002" + select CPU_AT32AP700X + endchoice # @@ -126,15 +139,15 @@ source "arch/avr32/mach-at32ap/Kconfig" config LOAD_ADDRESS hex - default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y + default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y config ENTRY_ADDRESS hex - default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y + default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y config PHYS_OFFSET hex - default 0x10000000 if CPU_AT32AP7000=y + default 0x10000000 if CPU_AT32AP700X=y source "kernel/Kconfig.preempt" diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile index f75d52cd2a4c..17a3529341dd 100644 --- a/arch/avr32/Makefile +++ b/arch/avr32/Makefile @@ -16,7 +16,7 @@ KBUILD_AFLAGS += -mrelax -mno-pic CFLAGS_MODULE += -mno-relax LDFLAGS_vmlinux += --relax -cpuflags-$(CONFIG_CPU_AT32AP7000) += -mcpu=ap7000 +cpuflags-$(CONFIG_PLATFORM_AT32AP) += -march=ap KBUILD_CFLAGS += $(cpuflags-y) KBUILD_AFLAGS += $(cpuflags-y) diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index 52987c81d668..a398be284966 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig index b799a68ffd97..374c17bcc05e 100644 --- a/arch/avr32/configs/atngw100_defconfig +++ b/arch/avr32/configs/atngw100_defconfig @@ -111,7 +111,10 @@ CONFIG_SUBARCH_AVR32B=y CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y CONFIG_PLATFORM_AT32AP=y +CONFIG_CPU_AT32AP700X=y CONFIG_CPU_AT32AP7000=y +# CONFIG_CPU_AT32AP7001 is not set +# CONFIG_CPU_AT32AP7002 is not set # CONFIG_BOARD_ATSTK1000 is not set CONFIG_BOARD_ATNGW100=y CONFIG_LOADER_U_BOOT=y @@ -119,9 +122,9 @@ CONFIG_LOADER_U_BOOT=y # # Atmel AVR32 AP options # -# CONFIG_AP7000_32_BIT_SMC is not set -CONFIG_AP7000_16_BIT_SMC=y -# CONFIG_AP7000_8_BIT_SMC is not set +# CONFIG_AP700X_32_BIT_SMC is not set +CONFIG_AP700X_16_BIT_SMC=y +# CONFIG_AP700X_8_BIT_SMC is not set CONFIG_LOAD_ADDRESS=0x10000000 CONFIG_ENTRY_ADDRESS=0x90000000 CONFIG_PHYS_OFFSET=0x10000000 diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig index 3b977fdbaa78..7614c5465cd6 100644 --- a/arch/avr32/configs/atstk1002_defconfig +++ b/arch/avr32/configs/atstk1002_defconfig @@ -114,6 +114,8 @@ CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y CONFIG_PLATFORM_AT32AP=y CONFIG_CPU_AT32AP7000=y +# CONFIG_CPU_AT32AP7001 is not set +# CONFIG_CPU_AT32AP7002 is not set CONFIG_BOARD_ATSTK1002=y CONFIG_BOARD_ATSTK1000=y # CONFIG_BOARD_ATNGW100 is not set @@ -122,9 +124,9 @@ CONFIG_LOADER_U_BOOT=y # # Atmel AVR32 AP options # -# CONFIG_AP7000_32_BIT_SMC is not set -CONFIG_AP7000_16_BIT_SMC=y -# CONFIG_AP7000_8_BIT_SMC is not set +# CONFIG_AP700X_32_BIT_SMC is not set +CONFIG_AP700X_16_BIT_SMC=y +# CONFIG_AP700X_8_BIT_SMC is not set CONFIG_LOAD_ADDRESS=0x10000000 CONFIG_ENTRY_ADDRESS=0x90000000 CONFIG_PHYS_OFFSET=0x10000000 diff --git a/arch/avr32/mach-at32ap/Kconfig b/arch/avr32/mach-at32ap/Kconfig index eb307838457b..a7bbcc82058e 100644 --- a/arch/avr32/mach-at32ap/Kconfig +++ b/arch/avr32/mach-at32ap/Kconfig @@ -3,9 +3,9 @@ if PLATFORM_AT32AP menu "Atmel AVR32 AP options" choice - prompt "AT32AP7000 static memory bus width" - depends on CPU_AT32AP7000 - default AP7000_16_BIT_SMC + prompt "AT32AP700x static memory bus width" + depends on CPU_AT32AP700X + default AP700X_16_BIT_SMC help Define the width of the AP7000 external static memory interface. This is used to determine how to mangle the address and/or data @@ -15,13 +15,13 @@ choice width for all chip selects, excluding the flash (which is using raw access and is thus not affected by any of this.) -config AP7000_32_BIT_SMC +config AP700X_32_BIT_SMC bool "32 bit" -config AP7000_16_BIT_SMC +config AP700X_16_BIT_SMC bool "16 bit" -config AP7000_8_BIT_SMC +config AP700X_8_BIT_SMC bool "8 bit" endchoice diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile index a8b445046e3e..5e9f8217befc 100644 --- a/arch/avr32/mach-at32ap/Makefile +++ b/arch/avr32/mach-at32ap/Makefile @@ -1,4 +1,4 @@ obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o -obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o -obj-$(CONFIG_CPU_AT32AP7000) += time-tc.o +obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o +obj-$(CONFIG_CPU_AT32AP700X) += time-tc.o obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c deleted file mode 100644 index 7c4388f4f17f..000000000000 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ /dev/null @@ -1,1730 +0,0 @@ -/* - * Copyright (C) 2005-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include