diff options
Diffstat (limited to 'arch/arc/kernel')
-rw-r--r-- | arch/arc/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/arc/kernel/clk.c | 21 | ||||
-rw-r--r-- | arch/arc/kernel/ctx_sw.c | 13 | ||||
-rw-r--r-- | arch/arc/kernel/devtree.c | 13 | ||||
-rw-r--r-- | arch/arc/kernel/intc-arcv2.c | 17 | ||||
-rw-r--r-- | arch/arc/kernel/intc-compact.c | 17 | ||||
-rw-r--r-- | arch/arc/kernel/irq.c | 50 | ||||
-rw-r--r-- | arch/arc/kernel/mcip.c | 7 | ||||
-rw-r--r-- | arch/arc/kernel/process.c | 7 | ||||
-rw-r--r-- | arch/arc/kernel/setup.c | 17 | ||||
-rw-r--r-- | arch/arc/kernel/smp.c | 25 | ||||
-rw-r--r-- | arch/arc/kernel/time.c | 238 |
12 files changed, 230 insertions, 197 deletions
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index 1bc2036b19d7..cfcdedf52ff8 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -9,7 +9,7 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o -obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o +obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o obj-$(CONFIG_PCI) += pcibios.o diff --git a/arch/arc/kernel/clk.c b/arch/arc/kernel/clk.c deleted file mode 100644 index 10c7b0b5a079..000000000000 --- a/arch/arc/kernel/clk.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com) - * - * 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 <asm/clk.h> - -unsigned long core_freq = 80000000; - -/* - * As of now we default to device-tree provided clock - * In future we can determine this in early boot - */ -int arc_set_core_freq(unsigned long freq) -{ - core_freq = freq; - return 0; -} diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c index 5d446df2c413..6f4cb0dab1b9 100644 --- a/arch/arc/kernel/ctx_sw.c +++ b/arch/arc/kernel/ctx_sw.c @@ -16,6 +16,9 @@ #include <asm/asm-offsets.h> #include <linux/sched.h> +#ifdef CONFIG_ARC_PLAT_EZNPS +#include <plat/ctop.h> +#endif #define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4) @@ -67,9 +70,16 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task) #ifndef CONFIG_SMP "st %2, [@_current_task] \n\t" #else +#ifdef CONFIG_ARC_PLAT_EZNPS + "lr r24, [%4] \n\t" +#ifndef CONFIG_EZNPS_MTM_EXT + "lsr r24, r24, 4 \n\t" +#endif +#else "lr r24, [identity] \n\t" "lsr r24, r24, 8 \n\t" "bmsk r24, r24, 7 \n\t" +#endif "add2 r24, @_current_task, r24 \n\t" "st %2, [r24] \n\t" #endif @@ -107,6 +117,9 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task) : "=r"(tmp) : "n"(KSP_WORD_OFF), "r"(next), "r"(prev) +#ifdef CONFIG_ARC_PLAT_EZNPS + , "i"(CTOP_AUX_LOGIC_GLOBAL_ID) +#endif : "blink" ); diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c index 7e844fd8213f..f1e07c2344f8 100644 --- a/arch/arc/kernel/devtree.c +++ b/arch/arc/kernel/devtree.c @@ -14,7 +14,6 @@ #include <linux/memblock.h> #include <linux/of.h> #include <linux/of_fdt.h> -#include <asm/clk.h> #include <asm/mach_desc.h> #ifdef CONFIG_SERIAL_EARLYCON @@ -28,14 +27,12 @@ unsigned int __init arc_early_base_baud(void) static void __init arc_set_early_base_baud(unsigned long dt_root) { - unsigned int core_clk = arc_get_core_freq(); - if (of_flat_dt_is_compatible(dt_root, "abilis,arc-tb10x")) - arc_base_baud = core_clk/3; + arc_base_baud = 166666666; /* Fixed 166.6MHz clk (TB10x) */ else if (of_flat_dt_is_compatible(dt_root, "snps,arc-sdp")) arc_base_baud = 33333333; /* Fixed 33MHz clk (AXS10x) */ else - arc_base_baud = core_clk; + arc_base_baud = 50000000; /* Fixed default 50MHz */ } #else #define arc_set_early_base_baud(dt_root) @@ -65,8 +62,6 @@ const struct machine_desc * __init setup_machine_fdt(void *dt) { const struct machine_desc *mdesc; unsigned long dt_root; - const void *clk; - int len; if (!early_init_dt_scan(dt)) return NULL; @@ -76,10 +71,6 @@ const struct machine_desc * __init setup_machine_fdt(void *dt) machine_halt(); dt_root = of_get_flat_dt_root(); - clk = of_get_flat_dt_prop(dt_root, "clock-frequency", &len); - if (clk) - arc_set_core_freq(of_read_ulong(clk, len/4)); - arc_set_early_base_baud(dt_root); return mdesc; diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 942526322ae7..6c24faf48b16 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -137,23 +137,30 @@ static const struct irq_domain_ops arcv2_irq_ops = { .map = arcv2_irq_map, }; -static struct irq_domain *root_domain; static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { + struct irq_domain *root_domain; + if (parent) panic("DeviceTree incore intc not a root irq controller\n"); - root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, - &arcv2_irq_ops, NULL); - + root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS, &arcv2_irq_ops, NULL); if (!root_domain) panic("root irq domain not avail\n"); - /* with this we don't need to export root_domain */ + /* + * Needed for primary domain lookup to succeed + * This is a primary irqchip, and can never have a parent + */ irq_set_default_host(root_domain); +#ifdef CONFIG_SMP + irq_create_mapping(root_domain, IPI_IRQ); +#endif + irq_create_mapping(root_domain, SOFTIRQ_IRQ); + return 0; } diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c index 224d1c3aa9c4..c5cceca36118 100644 --- a/arch/arc/kernel/intc-compact.c +++ b/arch/arc/kernel/intc-compact.c @@ -14,6 +14,8 @@ #include <linux/irqchip.h> #include <asm/irq.h> +#define TIMER0_IRQ 3 /* Fixed by ISA */ + /* * Early Hardware specific Interrupt setup * -Platform independent, needed for each CPU (not foldable into init_IRQ) @@ -79,8 +81,9 @@ static struct irq_chip onchip_intc = { static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - switch (irq) { + switch (hw) { case TIMER0_IRQ: + irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &onchip_intc, handle_percpu_irq); break; default: @@ -94,21 +97,23 @@ static const struct irq_domain_ops arc_intc_domain_ops = { .map = arc_intc_domain_map, }; -static struct irq_domain *root_domain; - static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { + struct irq_domain *root_domain; + if (parent) panic("DeviceTree incore intc not a root irq controller\n"); - root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, + root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS, &arc_intc_domain_ops, NULL); - if (!root_domain) panic("root irq domain not avail\n"); - /* with this we don't need to export root_domain */ + /* + * Needed for primary domain lookup to succeed + * This is a primary irqchip, and can never have a parent + */ irq_set_default_host(root_domain); return 0; diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index ba17f85285cf..538b36afe89e 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -41,53 +41,7 @@ void __init init_IRQ(void) * "C" Entry point for any ARC ISR, called from low level vector handler * @irq is the vector number read from ICAUSE reg of on-chip intc */ -void arch_do_IRQ(unsigned int irq, struct pt_regs *regs) +void arch_do_IRQ(unsigned int hwirq, struct pt_regs *regs) { - struct pt_regs *old_regs = set_irq_regs(regs); - - irq_enter(); - generic_handle_irq(irq); - irq_exit(); - set_irq_regs(old_regs); -} - -/* - * API called for requesting percpu interrupts - called by each CPU - * - For boot CPU, actually request the IRQ with genirq core + enables - * - For subsequent callers only enable called locally - * - * Relies on being called by boot cpu first (i.e. request called ahead) of - * any enable as expected by genirq. Hence Suitable only for TIMER, IPI - * which are guaranteed to be setup on boot core first. - * Late probed peripherals such as perf can't use this as there no guarantee - * of being called on boot CPU first. - */ - -void arc_request_percpu_irq(int irq, int cpu, - irqreturn_t (*isr)(int irq, void *dev), - const char *irq_nm, - void *percpu_dev) -{ - /* Boot cpu calls request, all call enable */ - if (!cpu) { - int rc; - -#ifdef CONFIG_ISA_ARCOMPACT - /* - * A subsequent request_percpu_irq() fails if percpu_devid is - * not set. That in turns sets NOAUTOEN, meaning each core needs - * to call enable_percpu_irq() - * - * For ARCv2, this is done in irq map function since we know - * which irqs are strictly per cpu - */ - irq_set_percpu_devid(irq); -#endif - - rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev); - if (rc) - panic("Percpu IRQ request failed for %d\n", irq); - } - - enable_percpu_irq(irq, 0); + handle_domain_irq(NULL, hwirq, regs); } diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index c41c364b926c..72f9179b1a24 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -15,9 +15,6 @@ #include <asm/mcip.h> #include <asm/setup.h> -#define IPI_IRQ 19 -#define SOFTIRQ_IRQ 21 - static char smp_cpuinfo_buf[128]; static int idu_detected; @@ -116,15 +113,13 @@ static void mcip_probe_n_setup(void) IS_AVAIL1(mp.dbg, "DEBUG "), IS_AVAIL1(mp.gfrc, "GFRC")); + cpuinfo_arc700[0].extn.gfrc = mp.gfrc; idu_detected = mp.idu; if (mp.dbg) { __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); } - - if (IS_ENABLED(CONFIG_ARC_HAS_GFRC) && !mp.gfrc) - panic("kernel trying to use non-existent GFRC\n"); } struct plat_smp_ops plat_smp_ops = { diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index a3f750e76b68..b5db9e7fd649 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -183,13 +183,6 @@ void flush_thread(void) { } -/* - * Free any architecture-specific thread data structures, etc. - */ -void exit_thread(void) -{ -} - int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { return 0; diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 151acf0c9383..f63b8bfefb0c 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -13,7 +13,6 @@ #include <linux/console.h> #include <linux/module.h> #include <linux/cpu.h> -#include <linux/clk-provider.h> #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/cache.h> @@ -24,7 +23,6 @@ #include <asm/page.h> #include <asm/irq.h> #include <asm/unwind.h> -#include <asm/clk.h> #include <asm/mach_desc.h> #include <asm/smp.h> @@ -220,10 +218,6 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) if (tbl->info.id == 0) n += scnprintf(buf + n, len - n, "UNKNOWN ARC Processor\n"); - n += scnprintf(buf + n, len - n, "CPU speed\t: %u.%02u Mhz\n", - (unsigned int)(arc_get_core_freq() / 1000000), - (unsigned int)(arc_get_core_freq() / 10000) % 100); - n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ", IS_AVAIL1(cpu->extn.timer0, "Timer0 "), IS_AVAIL1(cpu->extn.timer1, "Timer1 "), @@ -314,9 +308,6 @@ static void arc_chk_core_config(void) if (!cpu->extn.timer1) panic("Timer1 is not present!\n"); - if (IS_ENABLED(CONFIG_ARC_HAS_RTC) && !cpu->extn.rtc) - panic("RTC is not present\n"); - #ifdef CONFIG_ARC_HAS_DCCM /* * DCCM can be arbit placed in hardware. @@ -444,7 +435,6 @@ void __init setup_arch(char **cmdline_p) static int __init customize_machine(void) { - of_clk_init(NULL); /* * Traverses flattened DeviceTree - registering platform devices * (if any) complete with their resources @@ -477,6 +467,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) { char *str; int cpu_id = ptr_to_cpu(v); + struct device_node *core_clk = of_find_node_by_name(NULL, "core_clk"); + u32 freq = 0; if (!cpu_online(cpu_id)) { seq_printf(m, "processor [%d]\t: Offline\n", cpu_id); @@ -489,6 +481,11 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, arc_cpu_mumbojumbo(cpu_id, str, PAGE_SIZE)); + of_property_read_u32(core_clk, "clock-frequency", &freq); + if (freq) + seq_printf(m, "CPU speed\t: %u.%02u Mhz\n", + freq / 1000000, (freq / 10000) % 100); + seq_printf(m, "Bogo MIPS\t: %lu.%02lu\n", loops_per_jiffy / (500000 / HZ), (loops_per_jiffy / (5000 / HZ)) % 100); diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 4cb3add77c75..f183cc648851 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -126,11 +126,6 @@ void start_kernel_secondary(void) current->active_mm = mm; cpumask_set_cpu(cpu, mm_cpumask(mm)); - notify_cpu_starting(cpu); - set_cpu_online(cpu, true); - - pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); - /* Some SMP H/w setup - for each cpu */ if (plat_smp_ops.init_per_cpu) plat_smp_ops.init_per_cpu(cpu); @@ -138,7 +133,10 @@ void start_kernel_secondary(void) if (machine_desc->init_per_cpu) machine_desc->init_per_cpu(cpu); - arc_local_timer_setup(); + notify_cpu_starting(cpu); + set_cpu_online(cpu, true); + + pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); local_irq_enable(); preempt_disable(); @@ -346,6 +344,10 @@ irqreturn_t do_IPI(int irq, void *dev_id) /* * API called by platform code to hookup arch-common ISR to their IPI IRQ + * + * Note: If IPI is provided by platform (vs. say ARC MCIP), their intc setup/map + * function needs to call call irq_set_percpu_devid() for IPI IRQ, otherwise + * request_percpu_irq() below will fail */ static DEFINE_PER_CPU(int, ipi_dev); @@ -353,7 +355,16 @@ int smp_ipi_irq_setup(int cpu, int irq) { int *dev = per_cpu_ptr(&ipi_dev, cpu); - arc_request_percpu_irq(irq, cpu, do_IPI, "IPI Interrupt", dev); + /* Boot cpu calls request, all call enable */ + if (!cpu) { + int rc; + + rc = request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev); + if (rc) + panic("Percpu IRQ request failed for %d\n", irq); + } + + enable_percpu_irq(irq, 0); return 0; } diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 7d9a736fc7e5..4549ab255dd1 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -29,21 +29,16 @@ * which however is currently broken */ -#include <linux/spinlock.h> #include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/time.h> -#include <linux/init.h> -#include <linux/timex.h> -#include <linux/profile.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/clocksource.h> #include <linux/clockchips.h> +#include <linux/cpu.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include <asm/irq.h> #include <asm/arcregs.h> -#include <asm/clk.h> -#include <asm/mach_desc.h> #include <asm/mcip.h> @@ -60,16 +55,35 @@ #define ARC_TIMER_MAX 0xFFFFFFFF -/********** Clock Source Device *********/ - -#ifdef CONFIG_ARC_HAS_GFRC +static unsigned long arc_timer_freq; -static int arc_counter_setup(void) +static int noinline arc_get_timer_clk(struct device_node *node) { - return 1; + struct clk *clk; + int ret; + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("timer missing clk"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("Couldn't enable parent clk\n"); + return ret; + } + + arc_timer_freq = clk_get_rate(clk); + + return 0; } -static cycle_t arc_counter_read(struct clocksource *cs) +/********** Clock Source Device *********/ + +#ifdef CONFIG_ARC_HAS_GFRC + +static cycle_t arc_read_gfrc(struct clocksource *cs) { unsigned long flags; union { @@ -94,15 +108,31 @@ static cycle_t arc_counter_read(struct clocksource *cs) return stamp.full; } -static struct clocksource arc_counter = { +static struct clocksource arc_counter_gfrc = { .name = "ARConnect GFRC", .rating = 400, - .read = arc_counter_read, + .read = arc_read_gfrc, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#else +static void __init arc_cs_setup_gfrc(struct device_node *node) +{ + int exists = cpuinfo_arc700[0].extn.gfrc; + int ret; + + if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected")) + return; + + ret = arc_get_timer_clk(node); + if (ret) + return; + + clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); +} +CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); + +#endif #ifdef CONFIG_ARC_HAS_RTC @@ -110,15 +140,7 @@ static struct clocksource arc_counter = { #define AUX_RTC_LOW 0x104 #define AUX_RTC_HIGH 0x105 -int arc_counter_setup(void) -{ - write_aux_reg(AUX_RTC_CTRL, 1); - - /* Not usable in SMP */ - return !IS_ENABLED(CONFIG_SMP); -} - -static cycle_t arc_counter_read(struct clocksource *cs) +static cycle_t arc_read_rtc(struct clocksource *cs) { unsigned long status; union { @@ -142,47 +164,78 @@ static cycle_t arc_counter_read(struct clocksource *cs) return stamp.full; } -static struct clocksource arc_counter = { +static struct clocksource arc_counter_rtc = { .name = "ARCv2 RTC", .rating = 350, - .read = arc_counter_read, + .read = arc_read_rtc, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#else /* !CONFIG_ARC_HAS_RTC */ - -/* - * set 32bit TIMER1 to keep counting monotonically and wraparound - */ -int arc_counter_setup(void) +static void __init arc_cs_setup_rtc(struct device_node *node) { - write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); - write_aux_reg(ARC_REG_TIMER1_CNT, 0); - write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); + int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc; + int ret; + + if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected")) + return; + + /* Local to CPU hence not usable in SMP */ + if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP")) + return; + + ret = arc_get_timer_clk(node); + if (ret) + return; + + write_aux_reg(AUX_RTC_CTRL, 1); - /* Not usable in SMP */ - return !IS_ENABLED(CONFIG_SMP); + clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); } +CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); -static cycle_t arc_counter_read(struct clocksource *cs) +#endif + +/* + * 32bit TIMER1 to keep counting monotonically and wraparound + */ + +static cycle_t arc_read_timer1(struct clocksource *cs) { return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT); } -static struct clocksource arc_counter = { +static struct clocksource arc_counter_timer1 = { .name = "ARC Timer1", .rating = 300, - .read = arc_counter_read, + .read = arc_read_timer1, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#endif -#endif +static void __init arc_cs_setup_timer1(struct device_node *node) +{ + int ret; + + /* Local to CPU hence not usable in SMP */ + if (IS_ENABLED(CONFIG_SMP)) + return; + + ret = arc_get_timer_clk(node); + if (ret) + return; + + write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); + write_aux_reg(ARC_REG_TIMER1_CNT, 0); + write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); + + clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); +} /********** Clock Event Device *********/ +static int arc_timer_irq; + /* * Arm the timer to interrupt after @cycles * The distinction for oneshot/periodic is done in arc_event_timer_ack() below @@ -209,7 +262,7 @@ static int arc_clkevent_set_periodic(struct clock_event_device *dev) * At X Hz, 1 sec = 1000ms -> X cycles; * 10ms -> X / 100 cycles */ - arc_timer_event_setup(arc_get_core_freq() / HZ); + arc_timer_event_setup(arc_timer_freq / HZ); return 0; } @@ -218,7 +271,6 @@ static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .rating = 300, - .irq = TIMER0_IRQ, /* hardwired, no need for resources */ .set_next_event = arc_clkevent_set_next_event, .set_state_periodic = arc_clkevent_set_periodic, }; @@ -244,45 +296,81 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int arc_timer_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); + + evt->cpumask = cpumask_of(smp_processor_id()); + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + clockevents_config_and_register(evt, arc_timer_freq, + 0, ULONG_MAX); + enable_percpu_irq(arc_timer_irq, 0); + break; + case CPU_DYING: + disable_percpu_irq(arc_timer_irq); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block arc_timer_cpu_nb = { + .notifier_call = arc_timer_cpu_notify, +}; + /* - * Setup the local event timer for @cpu + * clockevent setup for boot CPU */ -void arc_local_timer_setup() +static void __init arc_clockevent_setup(struct device_node *node) { struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - int cpu = smp_processor_id(); + int ret; + + register_cpu_notifier(&arc_timer_cpu_nb); - evt->cpumask = cpumask_of(cpu); - clockevents_config_and_register(evt, arc_get_core_freq(), + arc_timer_irq = irq_of_parse_and_map(node, 0); + if (arc_timer_irq <= 0) + panic("clockevent: missing irq"); + + ret = arc_get_timer_clk(node); + if (ret) + panic("clockevent: missing clk"); + + evt->irq = arc_timer_irq; + evt->cpumask = cpumask_of(smp_processor_id()); + clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMER_MAX); - /* setup the per-cpu timer IRQ handler - for all cpus */ - arc_request_percpu_irq(TIMER0_IRQ, cpu, timer_irq_handler, - "Timer0 (per-cpu-tick)", evt); + /* Needs apriori irq_set_percpu_devid() done in intc map function */ + ret = request_percpu_irq(arc_timer_irq, timer_irq_handler, + "Timer0 (per-cpu-tick)", evt); + if (ret) + panic("clockevent: unable to request irq\n"); + + enable_percpu_irq(arc_timer_irq, 0); } +static void __init arc_of_timer_init(struct device_node *np) +{ + static int init_count = 0; + + if (!init_count) { + init_count = 1; + arc_clockevent_setup(np); + } else { + arc_cs_setup_timer1(np); + } +} +CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); + /* * Called from start_kernel() - boot CPU only - * - * -Sets up h/w timers as applicable on boot cpu - * -Also sets up any global state needed for timer subsystem: - * - for "counting" timer, registers a clocksource, usable across CPUs - * (provided that underlying counter h/w is synchronized across cores) - * - for "event" timer, sets up TIMER0 IRQ (as that is platform agnostic) */ void __init time_init(void) { - /* - * sets up the timekeeping free-flowing counter which also returns - * whether the counter is usable as clocksource - */ - if (arc_counter_setup()) - /* - * CLK upto 4.29 GHz can be safely represented in 32 bits - * because Max 32 bit number is 4,294,967,295 - */ - clocksource_register_hz(&arc_counter, arc_get_core_freq()); - - /* sets up the periodic event timer */ - arc_local_timer_setup(); + of_clk_init(NULL); + clocksource_probe(); } |