aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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