aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorTkhai Kirill <tkhai@yandex.ru>2012-04-04 15:49:26 -0400
committerDavid S. Miller <davem@davemloft.net>2012-04-15 13:28:50 -0400
commit62f082830d63cf753ed0dab16f8d3b2d0ffc7f43 (patch)
tree39770d13d3dbff835eb3500c6a913da5c784fec3 /arch/sparc
parent472bc4f2ad164a5aac2e85d891c4faecfc5d62c4 (diff)
sparc32: generic clockevent support
The kernel uses l14 timers as clockevents. l10 timer is used as clocksource if platform master_l10_counter isn't constantly zero. The clocksource is continuous, so it's possible to use high resolution timers. l10 timer is also used as clockevent on UP configurations. This realization is for sun4m, sun4d, sun4c, microsparc-IIep and LEON platforms. The appropriate LEON changes was made by Konrad Eisele. In case of sun4m's oneshot mode, profile irq is zeroed in smp4m_percpu_timer_interrupt(). It is maybe needless (double, triple etc overflow does nothing). sun4d is able to have oneshot mode too, but I haven't any way to test it. So code of its percpu timer handler is made as much equal to the current code as possible. The patch is tested on sun4m box in SMP mode by me, and tested by Konrad on leon in up mode (leon smp is broken atm - due to other reasons). Signed-off-by: Tkhai Kirill <tkhai@yandex.ru> Tested-by: Konrad Eisele <konrad@gaisler.com> [leon up] [sam: revised patch to provide generic support for leon] Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/Kconfig7
-rw-r--r--arch/sparc/include/asm/cpudata_32.h1
-rw-r--r--arch/sparc/include/asm/leon.h2
-rw-r--r--arch/sparc/include/asm/timer_32.h29
-rw-r--r--arch/sparc/include/asm/timex_32.h1
-rw-r--r--arch/sparc/kernel/irq.h19
-rw-r--r--arch/sparc/kernel/kernel.h2
-rw-r--r--arch/sparc/kernel/leon_kernel.c49
-rw-r--r--arch/sparc/kernel/leon_smp.c34
-rw-r--r--arch/sparc/kernel/pcic.c48
-rw-r--r--arch/sparc/kernel/smp_32.c21
-rw-r--r--arch/sparc/kernel/sun4c_irq.c11
-rw-r--r--arch/sparc/kernel/sun4d_irq.c18
-rw-r--r--arch/sparc/kernel/sun4d_smp.c34
-rw-r--r--arch/sparc/kernel/sun4m_irq.c22
-rw-r--r--arch/sparc/kernel/sun4m_smp.c38
-rw-r--r--arch/sparc/kernel/time_32.c215
17 files changed, 362 insertions, 189 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 6c0683d3fcba..db4e821b3ed0 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -73,17 +73,12 @@ config BITS
73 default 32 if SPARC32 73 default 32 if SPARC32
74 default 64 if SPARC64 74 default 64 if SPARC64
75 75
76config ARCH_USES_GETTIMEOFFSET
77 bool
78 default y if SPARC32
79
80config GENERIC_CMOS_UPDATE 76config GENERIC_CMOS_UPDATE
81 bool 77 bool
82 default y 78 default y
83 79
84config GENERIC_CLOCKEVENTS 80config GENERIC_CLOCKEVENTS
85 bool 81 def_bool y
86 default y if SPARC64
87 82
88config IOMMU_HELPER 83config IOMMU_HELPER
89 bool 84 bool
diff --git a/arch/sparc/include/asm/cpudata_32.h b/arch/sparc/include/asm/cpudata_32.h
index a4c5a938b936..0300d94c25b3 100644
--- a/arch/sparc/include/asm/cpudata_32.h
+++ b/arch/sparc/include/asm/cpudata_32.h
@@ -14,7 +14,6 @@
14typedef struct { 14typedef struct {
15 unsigned long udelay_val; 15 unsigned long udelay_val;
16 unsigned long clock_tick; 16 unsigned long clock_tick;
17 unsigned int multiplier;
18 unsigned int counter; 17 unsigned int counter;
19#ifdef CONFIG_SMP 18#ifdef CONFIG_SMP
20 unsigned int irq_resched_count; 19 unsigned int irq_resched_count;
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index a4e457f003ed..cf35a26454c8 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -323,7 +323,7 @@ extern void leon_update_virq_handling(unsigned int virq,
323 const char *name, int do_ack); 323 const char *name, int do_ack);
324extern void leon_clear_clock_irq(void); 324extern void leon_clear_clock_irq(void);
325extern void leon_load_profile_irq(int cpu, unsigned int limit); 325extern void leon_load_profile_irq(int cpu, unsigned int limit);
326extern void leon_init_timers(irq_handler_t counter_fn); 326extern void leon_init_timers(void);
327extern void leon_clear_clock_irq(void); 327extern void leon_clear_clock_irq(void);
328extern void leon_load_profile_irq(int cpu, unsigned int limit); 328extern void leon_load_profile_irq(int cpu, unsigned int limit);
329extern void leon_trans_init(struct device_node *dp); 329extern void leon_trans_init(struct device_node *dp);
diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h
index 1a91e11dd104..e6e66678f470 100644
--- a/arch/sparc/include/asm/timer_32.h
+++ b/arch/sparc/include/asm/timer_32.h
@@ -8,11 +8,40 @@
8#ifndef _SPARC_TIMER_H 8#ifndef _SPARC_TIMER_H
9#define _SPARC_TIMER_H 9#define _SPARC_TIMER_H
10 10
11#include <linux/clocksource.h>
12#include <linux/irqreturn.h>
13
14#include <asm-generic/percpu.h>
15
11#include <asm/cpu_type.h> /* For SUN4M_NCPUS */ 16#include <asm/cpu_type.h> /* For SUN4M_NCPUS */
12#include <asm/btfixup.h> 17#include <asm/btfixup.h>
13 18
19#define SBUS_CLOCK_RATE 2000000 /* 2MHz */
20#define TIMER_VALUE_SHIFT 9
21#define TIMER_VALUE_MASK 0x3fffff
22#define TIMER_LIMIT_BIT (1 << 31) /* Bit 31 in Counter-Timer register */
23
24/* The counter timer register has the value offset by 9 bits.
25 * From sun4m manual:
26 * When a counter reaches the value in the corresponding limit register,
27 * the Limit bit is set and the counter is set to 500 nS (i.e. 0x00000200).
28 *
29 * To compensate for this add one to the value.
30 */
31static inline unsigned int timer_value(unsigned int value)
32{
33 return (value + 1) << TIMER_VALUE_SHIFT;
34}
35
14extern __volatile__ unsigned int *master_l10_counter; 36extern __volatile__ unsigned int *master_l10_counter;
15 37
38extern irqreturn_t notrace timer_interrupt(int dummy, void *dev_id);
39
40#ifdef CONFIG_SMP
41DECLARE_PER_CPU(struct clock_event_device, sparc32_clockevent);
42extern void register_percpu_ce(int cpu);
43#endif
44
16/* FIXME: Make do_[gs]ettimeofday btfixup calls */ 45/* FIXME: Make do_[gs]ettimeofday btfixup calls */
17struct timespec; 46struct timespec;
18BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv) 47BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
diff --git a/arch/sparc/include/asm/timex_32.h b/arch/sparc/include/asm/timex_32.h
index a254750e4c03..b6ccdb0d6f7d 100644
--- a/arch/sparc/include/asm/timex_32.h
+++ b/arch/sparc/include/asm/timex_32.h
@@ -12,5 +12,4 @@
12typedef unsigned long cycles_t; 12typedef unsigned long cycles_t;
13#define get_cycles() (0) 13#define get_cycles() (0)
14 14
15extern u32 (*do_arch_gettimeoffset)(void);
16#endif 15#endif
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 3f6ca4d55dc4..8b946b1bc3b9 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -41,15 +41,32 @@ struct sun4m_irq_global {
41extern struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; 41extern struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
42extern struct sun4m_irq_global __iomem *sun4m_irq_global; 42extern struct sun4m_irq_global __iomem *sun4m_irq_global;
43 43
44/* The following definitions describe the individual platform features: */
45#define FEAT_L10_CLOCKSOURCE (1 << 0) /* L10 timer is used as a clocksource */
46#define FEAT_L10_CLOCKEVENT (1 << 1) /* L10 timer is used as a clockevent */
47#define FEAT_L14_ONESHOT (1 << 2) /* L14 timer clockevent can oneshot */
48
44/* 49/*
45 * Platform specific configuration 50 * Platform specific configuration
46 * The individual platforms assign their platform 51 * The individual platforms assign their platform
47 * specifics in their init functions. 52 * specifics in their init functions.
48 */ 53 */
49struct sparc_config { 54struct sparc_config {
50 void (*init_timers)(irq_handler_t); 55 void (*init_timers)(void);
51 unsigned int (*build_device_irq)(struct platform_device *op, 56 unsigned int (*build_device_irq)(struct platform_device *op,
52 unsigned int real_irq); 57 unsigned int real_irq);
58
59 /* generic clockevent features - see FEAT_* above */
60 int features;
61
62 /* clock rate used for clock event timer */
63 int clock_rate;
64
65 /* one period for clock source timer */
66 unsigned int cs_period;
67
68 /* function to obtain offsett for cs period */
69 unsigned int (*get_cycles_offset)(void);
53}; 70};
54extern struct sparc_config sparc_config; 71extern struct sparc_config sparc_config;
55 72
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index fd6c36b1df74..8abbad38e34e 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -47,8 +47,6 @@ extern void init_IRQ(void);
47extern void sun4c_init_IRQ(void); 47extern void sun4c_init_IRQ(void);
48 48
49/* sun4m_irq.c */ 49/* sun4m_irq.c */
50extern unsigned int lvl14_resolution;
51
52extern void sun4m_init_IRQ(void); 50extern void sun4m_init_IRQ(void);
53extern void sun4m_unmask_profile_irq(void); 51extern void sun4m_unmask_profile_irq(void);
54extern void sun4m_clear_profile_irq(int cpu); 52extern void sun4m_clear_profile_irq(int cpu);
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index a94122bc0c7b..722650ab83da 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -10,6 +10,8 @@
10#include <linux/of_platform.h> 10#include <linux/of_platform.h>
11#include <linux/interrupt.h> 11#include <linux/interrupt.h>
12#include <linux/of_device.h> 12#include <linux/of_device.h>
13#include <linux/clocksource.h>
14#include <linux/clockchips.h>
13 15
14#include <asm/oplib.h> 16#include <asm/oplib.h>
15#include <asm/timer.h> 17#include <asm/timer.h>
@@ -250,7 +252,38 @@ void leon_update_virq_handling(unsigned int virq,
250 irq_set_chip_data(virq, (void *)mask); 252 irq_set_chip_data(virq, (void *)mask);
251} 253}
252 254
253void __init leon_init_timers(irq_handler_t counter_fn) 255static u32 leon_cycles_offset(void)
256{
257 u32 rld, val, off;
258 rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld);
259 val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val);
260 off = rld - val;
261 return rld - val;
262}
263
264#ifdef CONFIG_SMP
265
266/* smp clockevent irq */
267irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused)
268{
269 struct clock_event_device *ce;
270 int cpu = smp_processor_id();
271
272 leon_clear_profile_irq(cpu);
273
274 ce = &per_cpu(sparc32_clockevent, cpu);
275
276 irq_enter();
277 if (ce->event_handler)
278 ce->event_handler(ce);
279 irq_exit();
280
281 return IRQ_HANDLED;
282}
283
284#endif /* CONFIG_SMP */
285
286void __init leon_init_timers(void)
254{ 287{
255 int irq, eirq; 288 int irq, eirq;
256 struct device_node *rootnp, *np, *nnp; 289 struct device_node *rootnp, *np, *nnp;
@@ -260,6 +293,14 @@ void __init leon_init_timers(irq_handler_t counter_fn)
260 int ampopts; 293 int ampopts;
261 int err; 294 int err;
262 295
296 sparc_config.get_cycles_offset = leon_cycles_offset;
297 sparc_config.cs_period = 1000000 / HZ;
298 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
299
300#ifndef CONFIG_SMP
301 sparc_config.features |= FEAT_L10_CLOCKEVENT;
302#endif
303
263 leondebug_irq_disable = 0; 304 leondebug_irq_disable = 0;
264 leon_debug_irqout = 0; 305 leon_debug_irqout = 0;
265 master_l10_counter = (unsigned int *)&dummy_master_l10_counter; 306 master_l10_counter = (unsigned int *)&dummy_master_l10_counter;
@@ -369,7 +410,7 @@ void __init leon_init_timers(irq_handler_t counter_fn)
369 leon_eirq_setup(eirq); 410 leon_eirq_setup(eirq);
370 411
371 irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx); 412 irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx);
372 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); 413 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
373 if (err) { 414 if (err) {
374 printk(KERN_ERR "unable to attach timer IRQ%d\n", irq); 415 printk(KERN_ERR "unable to attach timer IRQ%d\n", irq);
375 prom_halt(); 416 prom_halt();
@@ -401,7 +442,7 @@ void __init leon_init_timers(irq_handler_t counter_fn)
401 /* Install per-cpu IRQ handler for broadcasted ticker */ 442 /* Install per-cpu IRQ handler for broadcasted ticker */
402 irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, 443 irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq,
403 "per-cpu", 0); 444 "per-cpu", 0);
404 err = request_irq(irq, leon_percpu_timer_interrupt, 445 err = request_irq(irq, leon_percpu_timer_ce_interrupt,
405 IRQF_PERCPU | IRQF_TIMER, "ticker", 446 IRQF_PERCPU | IRQF_TIMER, "ticker",
406 NULL); 447 NULL);
407 if (err) { 448 if (err) {
@@ -428,7 +469,6 @@ void leon_clear_clock_irq(void)
428 469
429void leon_load_profile_irq(int cpu, unsigned int limit) 470void leon_load_profile_irq(int cpu, unsigned int limit)
430{ 471{
431 BUG();
432} 472}
433 473
434void __init leon_trans_init(struct device_node *dp) 474void __init leon_trans_init(struct device_node *dp)
@@ -496,6 +536,7 @@ void __init leon_init_IRQ(void)
496{ 536{
497 sparc_config.init_timers = leon_init_timers; 537 sparc_config.init_timers = leon_init_timers;
498 sparc_config.build_device_irq = _leon_build_device_irq; 538 sparc_config.build_device_irq = _leon_build_device_irq;
539 sparc_config.clock_rate = 1000000;
499 540
500 BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, 541 BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq,
501 BTFIXUPCALL_NORM); 542 BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
index 1210fde18740..6173f4d82ded 100644
--- a/arch/sparc/kernel/leon_smp.c
+++ b/arch/sparc/kernel/leon_smp.c
@@ -23,6 +23,8 @@
23#include <linux/pm.h> 23#include <linux/pm.h>
24#include <linux/delay.h> 24#include <linux/delay.h>
25#include <linux/gfp.h> 25#include <linux/gfp.h>
26#include <linux/cpu.h>
27#include <linux/clockchips.h>
26 28
27#include <asm/cacheflush.h> 29#include <asm/cacheflush.h>
28#include <asm/tlbflush.h> 30#include <asm/tlbflush.h>
@@ -42,6 +44,7 @@
42#include <asm/asi.h> 44#include <asm/asi.h>
43#include <asm/leon.h> 45#include <asm/leon.h>
44#include <asm/leon_amba.h> 46#include <asm/leon_amba.h>
47#include <asm/timer.h>
45 48
46#include "kernel.h" 49#include "kernel.h"
47 50
@@ -68,8 +71,6 @@ static inline unsigned long do_swap(volatile unsigned long *ptr,
68 return val; 71 return val;
69} 72}
70 73
71static void smp_setup_percpu_timer(void);
72
73void __cpuinit leon_callin(void) 74void __cpuinit leon_callin(void)
74{ 75{
75 int cpuid = hard_smpleon_processor_id(); 76 int cpuid = hard_smpleon_processor_id();
@@ -79,7 +80,7 @@ void __cpuinit leon_callin(void)
79 leon_configure_cache_smp(); 80 leon_configure_cache_smp();
80 81
81 /* Get our local ticker going. */ 82 /* Get our local ticker going. */
82 smp_setup_percpu_timer(); 83 register_percpu_ce(cpuid);
83 84
84 calibrate_delay(); 85 calibrate_delay();
85 smp_store_cpu_info(cpuid); 86 smp_store_cpu_info(cpuid);
@@ -196,7 +197,6 @@ void __init leon_boot_cpus(void)
196 leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER); 197 leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER);
197 198
198 leon_configure_cache_smp(); 199 leon_configure_cache_smp();
199 smp_setup_percpu_timer();
200 local_flush_cache_all(); 200 local_flush_cache_all();
201 201
202} 202}
@@ -489,32 +489,6 @@ void leon_cross_call_irq(void)
489 ccall_info.processors_out[i] = 1; 489 ccall_info.processors_out[i] = 1;
490} 490}
491 491
492irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused)
493{
494 int cpu = smp_processor_id();
495
496 leon_clear_profile_irq(cpu);
497
498 profile_tick(CPU_PROFILING);
499
500 if (!--prof_counter(cpu)) {
501 int user = user_mode(get_irq_regs());
502
503 update_process_times(user);
504
505 prof_counter(cpu) = prof_multiplier(cpu);
506 }
507
508 return IRQ_HANDLED;
509}
510
511static void __init smp_setup_percpu_timer(void)
512{
513 int cpu = smp_processor_id();
514
515 prof_counter(cpu) = prof_multiplier(cpu) = 1;
516}
517
518void __init leon_blackbox_id(unsigned *addr) 492void __init leon_blackbox_id(unsigned *addr)
519{ 493{
520 int rd = *addr & 0x3e000000; 494 int rd = *addr & 0x3e000000;
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 6edec801e46a..118a3f5806a8 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -703,31 +703,28 @@ static void pcic_clear_clock_irq(void)
703 pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT); 703 pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT);
704} 704}
705 705
706static irqreturn_t pcic_timer_handler (int irq, void *h) 706/* CPU frequency is 100 MHz, timer increments every 4 CPU clocks */
707#define USECS_PER_JIFFY (1000000 / HZ)
708#define TICK_TIMER_LIMIT ((100 * 1000000 / 4) / HZ)
709
710static unsigned int pcic_cycles_offset(void)
707{ 711{
708 pcic_clear_clock_irq(); 712 u32 value, count;
709 xtime_update(1);
710#ifndef CONFIG_SMP
711 update_process_times(user_mode(get_irq_regs()));
712#endif
713 return IRQ_HANDLED;
714}
715 713
716#define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */ 714 value = readl(pcic0.pcic_regs + PCI_SYS_COUNTER);
717#define TICK_TIMER_LIMIT ((100*1000000/4)/100) 715 count = value & ~PCI_SYS_COUNTER_OVERFLOW;
718 716
719u32 pci_gettimeoffset(void) 717 if (value & PCI_SYS_COUNTER_OVERFLOW)
720{ 718 count += TICK_TIMER_LIMIT;
721 /* 719 /*
722 * We divide all by 100 720 * We divide all by HZ
723 * to have microsecond resolution and to avoid overflow 721 * to have microsecond resolution and to avoid overflow
724 */ 722 */
725 unsigned long count = 723 count = ((count / HZ) * USECS_PER_JIFFY) / (TICK_TIMER_LIMIT / HZ);
726 readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
727 count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
728 return count * 1000;
729}
730 724
725 /* Coordinate with the fact that timer_cs rate is 2MHz */
726 return count * 2;
727}
731 728
732void __init pci_time_init(void) 729void __init pci_time_init(void)
733{ 730{
@@ -736,9 +733,16 @@ void __init pci_time_init(void)
736 int timer_irq, irq; 733 int timer_irq, irq;
737 int err; 734 int err;
738 735
739 do_arch_gettimeoffset = pci_gettimeoffset; 736#ifndef CONFIG_SMP
740 737 /*
741 btfixup(); 738 * It's in SBUS dimension, because timer_cs is in this dimension.
739 * We take into account this in pcic_cycles_offset()
740 */
741 timer_cs_period = SBUS_CLOCK_RATE / HZ;
742 sparc_config.features |= FEAT_L10_CLOCKEVENT;
743#endif
744 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
745 sparc_config.get_cycles_offset = pcic_cycles_offset;
742 746
743 writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT); 747 writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT);
744 /* PROM should set appropriate irq */ 748 /* PROM should set appropriate irq */
@@ -747,7 +751,7 @@ void __init pci_time_init(void)
747 writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), 751 writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),
748 pcic->pcic_regs+PCI_COUNTER_IRQ); 752 pcic->pcic_regs+PCI_COUNTER_IRQ);
749 irq = pcic_build_device_irq(NULL, timer_irq); 753 irq = pcic_build_device_irq(NULL, timer_irq);
750 err = request_irq(irq, pcic_timer_handler, 754 err = request_irq(irq, timer_interrupt,
751 IRQF_TIMER, "timer", NULL); 755 IRQF_TIMER, "timer", NULL);
752 if (err) { 756 if (err) {
753 prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); 757 prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
index f671e7fd6ddc..569a8a9d24a2 100644
--- a/arch/sparc/kernel/smp_32.c
+++ b/arch/sparc/kernel/smp_32.c
@@ -301,28 +301,9 @@ void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
301 local_flush_sig_insns(mm, insn_addr); 301 local_flush_sig_insns(mm, insn_addr);
302} 302}
303 303
304extern unsigned int lvl14_resolution;
305
306/* /proc/profile writes can call this, don't __init it please. */
307static DEFINE_SPINLOCK(prof_setup_lock);
308
309int setup_profiling_timer(unsigned int multiplier) 304int setup_profiling_timer(unsigned int multiplier)
310{ 305{
311 int i; 306 return -EINVAL;
312 unsigned long flags;
313
314 /* Prevent level14 ticker IRQ flooding. */
315 if((!multiplier) || (lvl14_resolution / multiplier) < 500)
316 return -EINVAL;
317
318 spin_lock_irqsave(&prof_setup_lock, flags);
319 for_each_possible_cpu(i) {
320 load_profile_irq(i, lvl14_resolution / multiplier);
321 prof_multiplier(i) = multiplier;
322 }
323 spin_unlock_irqrestore(&prof_setup_lock, flags);
324
325 return 0;
326} 307}
327 308
328void __init smp_prepare_cpus(unsigned int max_cpus) 309void __init smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index d4e3c832c341..39c64211b1b6 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -174,7 +174,7 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
174 /* Errm.. not sure how to do this.. */ 174 /* Errm.. not sure how to do this.. */
175} 175}
176 176
177static void __init sun4c_init_timers(irq_handler_t counter_fn) 177static void __init sun4c_init_timers(void)
178{ 178{
179 const struct linux_prom_irqs *prom_irqs; 179 const struct linux_prom_irqs *prom_irqs;
180 struct device_node *dp; 180 struct device_node *dp;
@@ -207,12 +207,16 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn)
207 * level 14 timer limit since we are letting the prom handle 207 * level 14 timer limit since we are letting the prom handle
208 * them until we have a real console driver so L1-A works. 208 * them until we have a real console driver so L1-A works.
209 */ 209 */
210 sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit); 210 sparc_config.cs_period = SBUS_CLOCK_RATE / HZ;
211 sparc_config.features |=
212 FEAT_L10_CLOCKSOURCE | FEAT_L10_CLOCKEVENT;
213 sbus_writel(timer_value(sparc_config.cs_period),
214 &sun4c_timers->l10_limit);
211 215
212 master_l10_counter = &sun4c_timers->l10_count; 216 master_l10_counter = &sun4c_timers->l10_count;
213 217
214 irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri); 218 irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri);
215 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); 219 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
216 if (err) { 220 if (err) {
217 prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); 221 prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
218 prom_halt(); 222 prom_halt();
@@ -253,6 +257,7 @@ void __init sun4c_init_IRQ(void)
253 257
254 sparc_config.init_timers = sun4c_init_timers; 258 sparc_config.init_timers = sun4c_init_timers;
255 sparc_config.build_device_irq = sun4c_build_device_irq; 259 sparc_config.build_device_irq = sun4c_build_device_irq;
260 sparc_config.clock_rate = SBUS_CLOCK_RATE;
256 261
257#ifdef CONFIG_SMP 262#ifdef CONFIG_SMP
258 BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); 263 BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 30119f662eff..abf52654a8bc 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -282,7 +282,8 @@ static void sun4d_clear_clock_irq(void)
282 282
283static void sun4d_load_profile_irq(int cpu, unsigned int limit) 283static void sun4d_load_profile_irq(int cpu, unsigned int limit)
284{ 284{
285 bw_set_prof_limit(cpu, limit); 285 unsigned int value = limit ? timer_value(limit) : 0;
286 bw_set_prof_limit(cpu, value);
286} 287}
287 288
288static void __init sun4d_load_profile_irqs(void) 289static void __init sun4d_load_profile_irqs(void)
@@ -423,7 +424,7 @@ static void __init sun4d_fixup_trap_table(void)
423#endif 424#endif
424} 425}
425 426
426static void __init sun4d_init_timers(irq_handler_t counter_fn) 427static void __init sun4d_init_timers(void)
427{ 428{
428 struct device_node *dp; 429 struct device_node *dp;
429 struct resource res; 430 struct resource res;
@@ -466,12 +467,20 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
466 prom_halt(); 467 prom_halt();
467 } 468 }
468 469
469 sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit); 470#ifdef CONFIG_SMP
471 sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */
472#else
473 sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */
474 sparc_config.features |= FEAT_L10_CLOCKEVENT;
475#endif
476 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
477 sbus_writel(timer_value(sparc_config.cs_period),
478 &sun4d_timers->l10_timer_limit);
470 479
471 master_l10_counter = &sun4d_timers->l10_cur_count; 480 master_l10_counter = &sun4d_timers->l10_cur_count;
472 481
473 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ); 482 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
474 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); 483 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
475 if (err) { 484 if (err) {
476 prom_printf("sun4d_init_timers: request_irq() failed with %d\n", 485 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
477 err); 486 err);
@@ -514,6 +523,7 @@ void __init sun4d_init_IRQ(void)
514 523
515 sparc_config.init_timers = sun4d_init_timers; 524 sparc_config.init_timers = sun4d_init_timers;
516 sparc_config.build_device_irq = sun4d_build_device_irq; 525 sparc_config.build_device_irq = sun4d_build_device_irq;
526 sparc_config.clock_rate = SBUS_CLOCK_RATE;
517 527
518#ifdef CONFIG_SMP 528#ifdef CONFIG_SMP
519 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM); 529 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 540b2fec09f0..576fe74d226b 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -6,16 +6,18 @@
6 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 6 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
7 */ 7 */
8 8
9#include <linux/clockchips.h>
9#include <linux/interrupt.h> 10#include <linux/interrupt.h>
10#include <linux/profile.h> 11#include <linux/profile.h>
11#include <linux/delay.h> 12#include <linux/delay.h>
12#include <linux/cpu.h> 13#include <linux/cpu.h>
13 14
15#include <asm/cacheflush.h>
16#include <asm/switch_to.h>
17#include <asm/tlbflush.h>
18#include <asm/timer.h>
14#include <asm/sbi.h> 19#include <asm/sbi.h>
15#include <asm/mmu.h> 20#include <asm/mmu.h>
16#include <asm/tlbflush.h>
17#include <asm/switch_to.h>
18#include <asm/cacheflush.h>
19 21
20#include "kernel.h" 22#include "kernel.h"
21#include "irq.h" 23#include "irq.h"
@@ -34,7 +36,6 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon
34} 36}
35 37
36static void smp4d_ipi_init(void); 38static void smp4d_ipi_init(void);
37static void smp_setup_percpu_timer(void);
38 39
39static unsigned char cpu_leds[32]; 40static unsigned char cpu_leds[32];
40 41
@@ -70,7 +71,7 @@ void __cpuinit smp4d_callin(void)
70 * to call the scheduler code. 71 * to call the scheduler code.
71 */ 72 */
72 /* Get our local ticker going. */ 73 /* Get our local ticker going. */
73 smp_setup_percpu_timer(); 74 register_percpu_ce(cpuid);
74 75
75 calibrate_delay(); 76 calibrate_delay();
76 smp_store_cpu_info(cpuid); 77 smp_store_cpu_info(cpuid);
@@ -123,7 +124,6 @@ void __init smp4d_boot_cpus(void)
123 smp4d_ipi_init(); 124 smp4d_ipi_init();
124 if (boot_cpu_id) 125 if (boot_cpu_id)
125 current_set[0] = NULL; 126 current_set[0] = NULL;
126 smp_setup_percpu_timer();
127 local_flush_cache_all(); 127 local_flush_cache_all();
128} 128}
129 129
@@ -364,6 +364,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
364{ 364{
365 struct pt_regs *old_regs; 365 struct pt_regs *old_regs;
366 int cpu = hard_smp4d_processor_id(); 366 int cpu = hard_smp4d_processor_id();
367 struct clock_event_device *ce;
367 static int cpu_tick[NR_CPUS]; 368 static int cpu_tick[NR_CPUS];
368 static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd }; 369 static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
369 370
@@ -379,28 +380,15 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
379 show_leds(cpu); 380 show_leds(cpu);
380 } 381 }
381 382
382 profile_tick(CPU_PROFILING); 383 ce = &per_cpu(sparc32_clockevent, cpu);
383
384 if (!--prof_counter(cpu)) {
385 int user = user_mode(regs);
386 384
387 irq_enter(); 385 irq_enter();
388 update_process_times(user); 386 ce->event_handler(ce);
389 irq_exit(); 387 irq_exit();
390 388
391 prof_counter(cpu) = prof_multiplier(cpu);
392 }
393 set_irq_regs(old_regs); 389 set_irq_regs(old_regs);
394} 390}
395 391
396static void __cpuinit smp_setup_percpu_timer(void)
397{
398 int cpu = hard_smp4d_processor_id();
399
400 prof_counter(cpu) = prof_multiplier(cpu) = 1;
401 load_profile_irq(cpu, lvl14_resolution);
402}
403
404void __init smp4d_blackbox_id(unsigned *addr) 392void __init smp4d_blackbox_id(unsigned *addr)
405{ 393{
406 int rd = *addr & 0x3e000000; 394 int rd = *addr & 0x3e000000;
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 0d3a2d8cb266..87908a5b1223 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -318,9 +318,6 @@ struct sun4m_timer_global {
318 318
319static struct sun4m_timer_global __iomem *timers_global; 319static struct sun4m_timer_global __iomem *timers_global;
320 320
321
322unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
323
324static void sun4m_clear_clock_irq(void) 321static void sun4m_clear_clock_irq(void)
325{ 322{
326 sbus_readl(&timers_global->l10_limit); 323 sbus_readl(&timers_global->l10_limit);
@@ -369,10 +366,11 @@ void sun4m_clear_profile_irq(int cpu)
369 366
370static void sun4m_load_profile_irq(int cpu, unsigned int limit) 367static void sun4m_load_profile_irq(int cpu, unsigned int limit)
371{ 368{
372 sbus_writel(limit, &timers_percpu[cpu]->l14_limit); 369 unsigned int value = limit ? timer_value(limit) : 0;
370 sbus_writel(value, &timers_percpu[cpu]->l14_limit);
373} 371}
374 372
375static void __init sun4m_init_timers(irq_handler_t counter_fn) 373static void __init sun4m_init_timers(void)
376{ 374{
377 struct device_node *dp = of_find_node_by_name(NULL, "counter"); 375 struct device_node *dp = of_find_node_by_name(NULL, "counter");
378 int i, err, len, num_cpu_timers; 376 int i, err, len, num_cpu_timers;
@@ -402,13 +400,22 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
402 /* Every per-cpu timer works in timer mode */ 400 /* Every per-cpu timer works in timer mode */
403 sbus_writel(0x00000000, &timers_global->timer_config); 401 sbus_writel(0x00000000, &timers_global->timer_config);
404 402
405 sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit); 403#ifdef CONFIG_SMP
404 sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */
405 sparc_config.features |= FEAT_L14_ONESHOT;
406#else
407 sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */
408 sparc_config.features |= FEAT_L10_CLOCKEVENT;
409#endif
410 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
411 sbus_writel(timer_value(sparc_config.cs_period),
412 &timers_global->l10_limit);
406 413
407 master_l10_counter = &timers_global->l10_count; 414 master_l10_counter = &timers_global->l10_count;
408 415
409 irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ); 416 irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ);
410 417
411 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); 418 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
412 if (err) { 419 if (err) {
413 printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", 420 printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
414 err); 421 err);
@@ -480,6 +487,7 @@ void __init sun4m_init_IRQ(void)
480 487
481 sparc_config.init_timers = sun4m_init_timers; 488 sparc_config.init_timers = sun4m_init_timers;
482 sparc_config.build_device_irq = sun4m_build_device_irq; 489 sparc_config.build_device_irq = sun4m_build_device_irq;
490 sparc_config.clock_rate = SBUS_CLOCK_RATE;
483 491
484#ifdef CONFIG_SMP 492#ifdef CONFIG_SMP
485 BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); 493 BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 02db9a0412ce..29f8ace10b59 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -4,6 +4,7 @@
4 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 4 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
5 */ 5 */
6 6
7#include <linux/clockchips.h>
7#include <linux/interrupt.h> 8#include <linux/interrupt.h>
8#include <linux/profile.h> 9#include <linux/profile.h>
9#include <linux/delay.h> 10#include <linux/delay.h>
@@ -12,6 +13,7 @@
12#include <asm/cacheflush.h> 13#include <asm/cacheflush.h>
13#include <asm/switch_to.h> 14#include <asm/switch_to.h>
14#include <asm/tlbflush.h> 15#include <asm/tlbflush.h>
16#include <asm/timer.h>
15 17
16#include "irq.h" 18#include "irq.h"
17#include "kernel.h" 19#include "kernel.h"
@@ -31,7 +33,6 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val)
31} 33}
32 34
33static void smp4m_ipi_init(void); 35static void smp4m_ipi_init(void);
34static void smp_setup_percpu_timer(void);
35 36
36void __cpuinit smp4m_callin(void) 37void __cpuinit smp4m_callin(void)
37{ 38{
@@ -42,8 +43,7 @@ void __cpuinit smp4m_callin(void)
42 43
43 notify_cpu_starting(cpuid); 44 notify_cpu_starting(cpuid);
44 45
45 /* Get our local ticker going. */ 46 register_percpu_ce(cpuid);
46 smp_setup_percpu_timer();
47 47
48 calibrate_delay(); 48 calibrate_delay();
49 smp_store_cpu_info(cpuid); 49 smp_store_cpu_info(cpuid);
@@ -87,7 +87,7 @@ void __cpuinit smp4m_callin(void)
87void __init smp4m_boot_cpus(void) 87void __init smp4m_boot_cpus(void)
88{ 88{
89 smp4m_ipi_init(); 89 smp4m_ipi_init();
90 smp_setup_percpu_timer(); 90 sun4m_unmask_profile_irq();
91 local_flush_cache_all(); 91 local_flush_cache_all();
92} 92}
93 93
@@ -260,37 +260,25 @@ void smp4m_cross_call_irq(void)
260void smp4m_percpu_timer_interrupt(struct pt_regs *regs) 260void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
261{ 261{
262 struct pt_regs *old_regs; 262 struct pt_regs *old_regs;
263 struct clock_event_device *ce;
263 int cpu = smp_processor_id(); 264 int cpu = smp_processor_id();
264 265
265 old_regs = set_irq_regs(regs); 266 old_regs = set_irq_regs(regs);
266 267
267 sun4m_clear_profile_irq(cpu); 268 ce = &per_cpu(sparc32_clockevent, cpu);
268 269
269 profile_tick(CPU_PROFILING); 270 if (ce->mode & CLOCK_EVT_MODE_PERIODIC)
271 sun4m_clear_profile_irq(cpu);
272 else
273 load_profile_irq(cpu, 0); /* Is this needless? */
270 274
271 if (!--prof_counter(cpu)) { 275 irq_enter();
272 int user = user_mode(regs); 276 ce->event_handler(ce);
277 irq_exit();
273 278
274 irq_enter();
275 update_process_times(user);
276 irq_exit();
277
278 prof_counter(cpu) = prof_multiplier(cpu);
279 }
280 set_irq_regs(old_regs); 279 set_irq_regs(old_regs);
281} 280}
282 281
283static void __cpuinit smp_setup_percpu_timer(void)
284{
285 int cpu = smp_processor_id();
286
287 prof_counter(cpu) = prof_multiplier(cpu) = 1;
288 load_profile_irq(cpu, lvl14_resolution);
289
290 if (cpu == boot_cpu_id)
291 sun4m_unmask_profile_irq();
292}
293
294static void __init smp4m_blackbox_id(unsigned *addr) 282static void __init smp4m_blackbox_id(unsigned *addr)
295{ 283{
296 int rd = *addr & 0x3e000000; 284 int rd = *addr & 0x3e000000;
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index 68e0284bf3f3..89e890bc0941 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -26,6 +26,8 @@
26#include <linux/rtc.h> 26#include <linux/rtc.h>
27#include <linux/rtc/m48t59.h> 27#include <linux/rtc/m48t59.h>
28#include <linux/timex.h> 28#include <linux/timex.h>
29#include <linux/clocksource.h>
30#include <linux/clockchips.h>
29#include <linux/init.h> 31#include <linux/init.h>
30#include <linux/pci.h> 32#include <linux/pci.h>
31#include <linux/ioport.h> 33#include <linux/ioport.h>
@@ -44,9 +46,21 @@
44#include <asm/page.h> 46#include <asm/page.h>
45#include <asm/pcic.h> 47#include <asm/pcic.h>
46#include <asm/irq_regs.h> 48#include <asm/irq_regs.h>
49#include <asm/setup.h>
47 50
48#include "irq.h" 51#include "irq.h"
49 52
53static __cacheline_aligned_in_smp DEFINE_SEQLOCK(timer_cs_lock);
54static __volatile__ u64 timer_cs_internal_counter = 0;
55static char timer_cs_enabled = 0;
56
57static struct clock_event_device timer_ce;
58static char timer_ce_enabled = 0;
59
60#ifdef CONFIG_SMP
61DEFINE_PER_CPU(struct clock_event_device, sparc32_clockevent);
62#endif
63
50DEFINE_SPINLOCK(rtc_lock); 64DEFINE_SPINLOCK(rtc_lock);
51EXPORT_SYMBOL(rtc_lock); 65EXPORT_SYMBOL(rtc_lock);
52 66
@@ -75,36 +89,167 @@ EXPORT_SYMBOL(profile_pc);
75 89
76__volatile__ unsigned int *master_l10_counter; 90__volatile__ unsigned int *master_l10_counter;
77 91
78u32 (*do_arch_gettimeoffset)(void);
79
80int update_persistent_clock(struct timespec now) 92int update_persistent_clock(struct timespec now)
81{ 93{
82 return set_rtc_mmss(now.tv_sec); 94 return set_rtc_mmss(now.tv_sec);
83} 95}
84 96
85/* 97irqreturn_t notrace timer_interrupt(int dummy, void *dev_id)
86 * timer_interrupt() needs to keep up the real-time clock, 98{
87 * as well as call the "xtime_update()" routine every clocktick 99 if (timer_cs_enabled) {
88 */ 100 write_seqlock(&timer_cs_lock);
101 timer_cs_internal_counter++;
102 clear_clock_irq();
103 write_sequnlock(&timer_cs_lock);
104 } else {
105 clear_clock_irq();
106 }
89 107
90#define TICK_SIZE (tick_nsec / 1000) 108 if (timer_ce_enabled)
109 timer_ce.event_handler(&timer_ce);
91 110
92static irqreturn_t timer_interrupt(int dummy, void *dev_id) 111 return IRQ_HANDLED;
112}
113
114static void timer_ce_set_mode(enum clock_event_mode mode,
115 struct clock_event_device *evt)
93{ 116{
94#ifndef CONFIG_SMP 117 switch (mode) {
95 profile_tick(CPU_PROFILING); 118 case CLOCK_EVT_MODE_PERIODIC:
96#endif 119 case CLOCK_EVT_MODE_RESUME:
120 timer_ce_enabled = 1;
121 break;
122 case CLOCK_EVT_MODE_SHUTDOWN:
123 timer_ce_enabled = 0;
124 break;
125 default:
126 break;
127 }
128 smp_mb();
129}
130
131static __init void setup_timer_ce(void)
132{
133 struct clock_event_device *ce = &timer_ce;
134
135 BUG_ON(smp_processor_id() != boot_cpu_id);
136
137 ce->name = "timer_ce";
138 ce->rating = 100;
139 ce->features = CLOCK_EVT_FEAT_PERIODIC;
140 ce->set_mode = timer_ce_set_mode;
141 ce->cpumask = cpu_possible_mask;
142 ce->shift = 32;
143 ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC,
144 ce->shift);
145 clockevents_register_device(ce);
146}
97 147
98 clear_clock_irq(); 148static unsigned int sbus_cycles_offset(void)
149{
150 unsigned int val, offset;
99 151
100 xtime_update(1); 152 val = *master_l10_counter;
153 offset = (val >> TIMER_VALUE_SHIFT) & TIMER_VALUE_MASK;
101 154
102#ifndef CONFIG_SMP 155 /* Limit hit? */
103 update_process_times(user_mode(get_irq_regs())); 156 if (val & TIMER_LIMIT_BIT)
104#endif 157 offset += sparc_config.cs_period;
105 return IRQ_HANDLED; 158
159 return offset;
106} 160}
107 161
162static cycle_t timer_cs_read(struct clocksource *cs)
163{
164 unsigned int seq, offset;
165 u64 cycles;
166
167 do {
168 seq = read_seqbegin(&timer_cs_lock);
169
170 cycles = timer_cs_internal_counter;
171 offset = sparc_config.get_cycles_offset();
172 } while (read_seqretry(&timer_cs_lock, seq));
173
174 /* Count absolute cycles */
175 cycles *= sparc_config.cs_period;
176 cycles += offset;
177
178 return cycles;
179}
180
181static struct clocksource timer_cs = {
182 .name = "timer_cs",
183 .rating = 100,
184 .read = timer_cs_read,
185 .mask = CLOCKSOURCE_MASK(64),
186 .shift = 2,
187 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
188};
189
190static __init int setup_timer_cs(void)
191{
192 timer_cs_enabled = 1;
193 timer_cs.mult = clocksource_hz2mult(sparc_config.clock_rate,
194 timer_cs.shift);
195
196 return clocksource_register(&timer_cs);
197}
198
199#ifdef CONFIG_SMP
200static void percpu_ce_setup(enum clock_event_mode mode,
201 struct clock_event_device *evt)
202{
203 int cpu = __first_cpu(evt->cpumask);
204
205 switch (mode) {
206 case CLOCK_EVT_MODE_PERIODIC:
207 load_profile_irq(cpu, SBUS_CLOCK_RATE / HZ);
208 break;
209 case CLOCK_EVT_MODE_ONESHOT:
210 case CLOCK_EVT_MODE_SHUTDOWN:
211 case CLOCK_EVT_MODE_UNUSED:
212 load_profile_irq(cpu, 0);
213 break;
214 default:
215 break;
216 }
217}
218
219static int percpu_ce_set_next_event(unsigned long delta,
220 struct clock_event_device *evt)
221{
222 int cpu = __first_cpu(evt->cpumask);
223 unsigned int next = (unsigned int)delta;
224
225 load_profile_irq(cpu, next);
226 return 0;
227}
228
229void register_percpu_ce(int cpu)
230{
231 struct clock_event_device *ce = &per_cpu(sparc32_clockevent, cpu);
232 unsigned int features = CLOCK_EVT_FEAT_PERIODIC;
233
234 if (sparc_config.features & FEAT_L14_ONESHOT)
235 features |= CLOCK_EVT_FEAT_ONESHOT;
236
237 ce->name = "percpu_ce";
238 ce->rating = 200;
239 ce->features = features;
240 ce->set_mode = percpu_ce_setup;
241 ce->set_next_event = percpu_ce_set_next_event;
242 ce->cpumask = cpumask_of(cpu);
243 ce->shift = 32;
244 ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC,
245 ce->shift);
246 ce->max_delta_ns = clockevent_delta2ns(sparc_config.clock_rate, ce);
247 ce->min_delta_ns = clockevent_delta2ns(100, ce);
248
249 clockevents_register_device(ce);
250}
251#endif
252
108static unsigned char mostek_read_byte(struct device *dev, u32 ofs) 253static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
109{ 254{
110 struct platform_device *pdev = to_platform_device(dev); 255 struct platform_device *pdev = to_platform_device(dev);
@@ -195,38 +340,30 @@ static int __init clock_init(void)
195 */ 340 */
196fs_initcall(clock_init); 341fs_initcall(clock_init);
197 342
198 343static void __init sparc32_late_time_init(void)
199u32 sbus_do_gettimeoffset(void)
200{ 344{
201 unsigned long val = *master_l10_counter; 345 if (sparc_config.features & FEAT_L10_CLOCKEVENT)
202 unsigned long usec = (val >> 10) & 0x1fffff; 346 setup_timer_ce();
203 347 if (sparc_config.features & FEAT_L10_CLOCKSOURCE)
204 /* Limit hit? */ 348 setup_timer_cs();
205 if (val & 0x80000000) 349#ifdef CONFIG_SMP
206 usec += 1000000 / HZ; 350 register_percpu_ce(smp_processor_id());
207 351#endif
208 return usec * 1000;
209} 352}
210 353
211 354static void __init sbus_time_init(void)
212u32 arch_gettimeoffset(void)
213{ 355{
214 if (unlikely(!do_arch_gettimeoffset)) 356 sparc_config.get_cycles_offset = sbus_cycles_offset;
215 return 0; 357 sparc_config.init_timers();
216 return do_arch_gettimeoffset();
217} 358}
218 359
219static void __init sbus_time_init(void) 360void __init time_init(void)
220{ 361{
221 do_arch_gettimeoffset = sbus_do_gettimeoffset;
222
223 btfixup(); 362 btfixup();
224 363
225 sparc_config.init_timers(timer_interrupt); 364 sparc_config.features = 0;
226} 365 late_time_init = sparc32_late_time_init;
227 366
228void __init time_init(void)
229{
230 if (pcic_present()) 367 if (pcic_present())
231 pci_time_init(); 368 pci_time_init();
232 else 369 else