Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
authorDavid S. Miller <davem@davemloft.net>
Fri, 27 Apr 2012 03:00:35 +0000 (20:00 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 27 Apr 2012 03:00:35 +0000 (20:00 -0700)
Conflicts:
arch/sparc/kernel/leon_smp.c

Merge mainline to get the nobootmem.c bug fix, for the sake
of the sparc64 NO_BOOTMEM conversion.

Resolve a small include line conflict in leon_smp.c

Signed-off-by: David S. Miller <davem@davemloft.net>
23 files changed:
arch/sparc/Kconfig
arch/sparc/include/asm/cpudata_32.h
arch/sparc/include/asm/leon.h
arch/sparc/include/asm/timer_32.h
arch/sparc/include/asm/timex_32.h
arch/sparc/kernel/ds.c
arch/sparc/kernel/irq.h
arch/sparc/kernel/irq_32.c
arch/sparc/kernel/kernel.h
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/leon_smp.c
arch/sparc/kernel/of_device_32.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/rtrap_64.S
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/sun4c_irq.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/time_32.c
arch/sparc/kernel/unaligned_64.c
arch/sparc/mm/srmmu.c

index 6c0683d..db4e821 100644 (file)
@@ -73,17 +73,12 @@ config BITS
        default 32 if SPARC32
        default 64 if SPARC64
 
-config ARCH_USES_GETTIMEOFFSET
-       bool
-       default y if SPARC32
-
 config GENERIC_CMOS_UPDATE
        bool
        default y
 
 config GENERIC_CLOCKEVENTS
-       bool
-       default y if SPARC64
+       def_bool y
 
 config IOMMU_HELPER
        bool
index a4c5a93..0300d94 100644 (file)
@@ -14,7 +14,6 @@
 typedef struct {
        unsigned long udelay_val;
        unsigned long clock_tick;
-       unsigned int multiplier;
        unsigned int counter;
 #ifdef CONFIG_SMP
        unsigned int irq_resched_count;
index a4e457f..cf35a26 100644 (file)
@@ -323,7 +323,7 @@ extern void leon_update_virq_handling(unsigned int virq,
                              const char *name, int do_ack);
 extern void leon_clear_clock_irq(void);
 extern void leon_load_profile_irq(int cpu, unsigned int limit);
-extern void leon_init_timers(irq_handler_t counter_fn);
+extern void leon_init_timers(void);
 extern void leon_clear_clock_irq(void);
 extern void leon_load_profile_irq(int cpu, unsigned int limit);
 extern void leon_trans_init(struct device_node *dp);
index 1a91e11..e6e6667 100644 (file)
@@ -8,11 +8,40 @@
 #ifndef _SPARC_TIMER_H
 #define _SPARC_TIMER_H
 
+#include <linux/clocksource.h>
+#include <linux/irqreturn.h>
+
+#include <asm-generic/percpu.h>
+
 #include <asm/cpu_type.h>  /* For SUN4M_NCPUS */
 #include <asm/btfixup.h>
 
+#define SBUS_CLOCK_RATE   2000000 /* 2MHz */
+#define TIMER_VALUE_SHIFT 9
+#define TIMER_VALUE_MASK  0x3fffff
+#define TIMER_LIMIT_BIT   (1 << 31)  /* Bit 31 in Counter-Timer register */
+
+/* The counter timer register has the value offset by 9 bits.
+ * From sun4m manual:
+ * When a counter reaches the value in the corresponding limit register,
+ * the Limit bit is set and the counter is set to 500 nS (i.e. 0x00000200).
+ *
+ * To compensate for this add one to the value.
+ */
+static inline unsigned int timer_value(unsigned int value)
+{
+       return (value + 1) << TIMER_VALUE_SHIFT;
+}
+
 extern __volatile__ unsigned int *master_l10_counter;
 
+extern irqreturn_t notrace timer_interrupt(int dummy, void *dev_id);
+
+#ifdef CONFIG_SMP
+DECLARE_PER_CPU(struct clock_event_device, sparc32_clockevent);
+extern void register_percpu_ce(int cpu);
+#endif
+
 /* FIXME: Make do_[gs]ettimeofday btfixup calls */
 struct timespec;
 BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
index a254750..b6ccdb0 100644 (file)
@@ -12,5 +12,4 @@
 typedef unsigned long cycles_t;
 #define get_cycles()   (0)
 
-extern u32 (*do_arch_gettimeoffset)(void);
 #endif
index b93c2c9..f09257c 100644 (file)
@@ -868,7 +868,7 @@ void ldom_power_off(void)
 
 static void ds_conn_reset(struct ds_info *dp)
 {
-       printk(KERN_ERR "ds-%llu: ds_conn_reset() from %p\n",
+       printk(KERN_ERR "ds-%llu: ds_conn_reset() from %pf\n",
               dp->id, __builtin_return_address(0));
 }
 
index 5a021dd..8b946b1 100644 (file)
@@ -41,17 +41,34 @@ struct sun4m_irq_global {
 extern struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
 extern struct sun4m_irq_global __iomem *sun4m_irq_global;
 
+/* The following definitions describe the individual platform features: */
+#define FEAT_L10_CLOCKSOURCE (1 << 0) /* L10 timer is used as a clocksource */
+#define FEAT_L10_CLOCKEVENT  (1 << 1) /* L10 timer is used as a clockevent */
+#define FEAT_L14_ONESHOT     (1 << 2) /* L14 timer clockevent can oneshot */
+
 /*
- * Platform specific irq configuration
+ * Platform specific configuration
  * The individual platforms assign their platform
  * specifics in their init functions.
  */
-struct sparc_irq_config {
-       void (*init_timers)(irq_handler_t);
+struct sparc_config {
+       void (*init_timers)(void);
        unsigned int (*build_device_irq)(struct platform_device *op,
                                         unsigned int real_irq);
+
+       /* generic clockevent features - see FEAT_* above */
+       int features;
+
+       /* clock rate used for clock event timer */
+       int clock_rate;
+
+       /* one period for clock source timer */
+       unsigned int cs_period;
+
+       /* function to obtain offsett for cs period */
+       unsigned int (*get_cycles_offset)(void);
 };
-extern struct sparc_irq_config sparc_irq_config;
+extern struct sparc_config sparc_config;
 
 unsigned int irq_alloc(unsigned int real_irq, unsigned int pil);
 void irq_link(unsigned int irq);
index b2668af..4a2b801 100644 (file)
@@ -32,7 +32,7 @@
 #endif /* SMP */
 
 /* platform specific irq setup */
-struct sparc_irq_config sparc_irq_config;
+struct sparc_config sparc_config;
 
 unsigned long arch_local_irq_save(void)
 {
index fd6c36b..8abbad3 100644 (file)
@@ -47,8 +47,6 @@ extern void init_IRQ(void);
 extern void sun4c_init_IRQ(void);
 
 /* sun4m_irq.c */
-extern unsigned int lvl14_resolution;
-
 extern void sun4m_init_IRQ(void);
 extern void sun4m_unmask_profile_irq(void);
 extern void sun4m_clear_profile_irq(int cpu);
index 35e4367..722650a 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 
 #include <asm/oplib.h>
 #include <asm/timer.h>
@@ -250,7 +252,38 @@ void leon_update_virq_handling(unsigned int virq,
        irq_set_chip_data(virq, (void *)mask);
 }
 
-void __init leon_init_timers(irq_handler_t counter_fn)
+static u32 leon_cycles_offset(void)
+{
+       u32 rld, val, off;
+       rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld);
+       val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val);
+       off = rld - val;
+       return rld - val;
+}
+
+#ifdef CONFIG_SMP
+
+/* smp clockevent irq */
+irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused)
+{
+       struct clock_event_device *ce;
+       int cpu = smp_processor_id();
+
+       leon_clear_profile_irq(cpu);
+
+       ce = &per_cpu(sparc32_clockevent, cpu);
+
+       irq_enter();
+       if (ce->event_handler)
+               ce->event_handler(ce);
+       irq_exit();
+
+       return IRQ_HANDLED;
+}
+
+#endif /* CONFIG_SMP */
+
+void __init leon_init_timers(void)
 {
        int irq, eirq;
        struct device_node *rootnp, *np, *nnp;
@@ -260,6 +293,14 @@ void __init leon_init_timers(irq_handler_t counter_fn)
        int ampopts;
        int err;
 
+       sparc_config.get_cycles_offset = leon_cycles_offset;
+       sparc_config.cs_period = 1000000 / HZ;
+       sparc_config.features |= FEAT_L10_CLOCKSOURCE;
+
+#ifndef CONFIG_SMP
+       sparc_config.features |= FEAT_L10_CLOCKEVENT;
+#endif
+
        leondebug_irq_disable = 0;
        leon_debug_irqout = 0;
        master_l10_counter = (unsigned int *)&dummy_master_l10_counter;
@@ -369,7 +410,7 @@ void __init leon_init_timers(irq_handler_t counter_fn)
                leon_eirq_setup(eirq);
 
        irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx);
-       err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
+       err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
        if (err) {
                printk(KERN_ERR "unable to attach timer IRQ%d\n", irq);
                prom_halt();
@@ -401,7 +442,7 @@ void __init leon_init_timers(irq_handler_t counter_fn)
        /* Install per-cpu IRQ handler for broadcasted ticker */
        irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq,
                                    "per-cpu", 0);
-       err = request_irq(irq, leon_percpu_timer_interrupt,
+       err = request_irq(irq, leon_percpu_timer_ce_interrupt,
                          IRQF_PERCPU | IRQF_TIMER, "ticker",
                          NULL);
        if (err) {
@@ -428,7 +469,6 @@ void leon_clear_clock_irq(void)
 
 void leon_load_profile_irq(int cpu, unsigned int limit)
 {
-       BUG();
 }
 
 void __init leon_trans_init(struct device_node *dp)
@@ -494,8 +534,9 @@ void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu)
 
 void __init leon_init_IRQ(void)
 {
-       sparc_irq_config.init_timers      = leon_init_timers;
-       sparc_irq_config.build_device_irq = _leon_build_device_irq;
+       sparc_config.init_timers      = leon_init_timers;
+       sparc_config.build_device_irq = _leon_build_device_irq;
+       sparc_config.clock_rate = 1000000;
 
        BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq,
                        BTFIXUPCALL_NORM);
index 160cac9..356dfc4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/gfp.h>
 #include <linux/cpu.h>
+#include <linux/clockchips.h>
 
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
@@ -43,6 +44,7 @@
 #include <asm/asi.h>
 #include <asm/leon.h>
 #include <asm/leon_amba.h>
+#include <asm/timer.h>
 
 #include "kernel.h"
 
@@ -69,8 +71,6 @@ static inline unsigned long do_swap(volatile unsigned long *ptr,
        return val;
 }
 
-static void smp_setup_percpu_timer(void);
-
 void __cpuinit leon_callin(void)
 {
        int cpuid = hard_smpleon_processor_id();
@@ -82,7 +82,7 @@ void __cpuinit leon_callin(void)
        notify_cpu_starting(cpuid);
 
        /* Get our local ticker going. */
-       smp_setup_percpu_timer();
+       register_percpu_ce(cpuid);
 
        calibrate_delay();
        smp_store_cpu_info(cpuid);
@@ -199,7 +199,6 @@ void __init leon_boot_cpus(void)
        leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER);
 
        leon_configure_cache_smp();
-       smp_setup_percpu_timer();
        local_flush_cache_all();
 
 }
@@ -492,32 +491,6 @@ void leon_cross_call_irq(void)
        ccall_info.processors_out[i] = 1;
 }
 
-irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused)
-{
-       int cpu = smp_processor_id();
-
-       leon_clear_profile_irq(cpu);
-
-       profile_tick(CPU_PROFILING);
-
-       if (!--prof_counter(cpu)) {
-               int user = user_mode(get_irq_regs());
-
-               update_process_times(user);
-
-               prof_counter(cpu) = prof_multiplier(cpu);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static void __init smp_setup_percpu_timer(void)
-{
-       int cpu = smp_processor_id();
-
-       prof_counter(cpu) = prof_multiplier(cpu) = 1;
-}
-
 void __init leon_blackbox_id(unsigned *addr)
 {
        int rd = *addr & 0x3e000000;
index 4ee8ce0..185aa96 100644 (file)
@@ -356,7 +356,7 @@ static struct platform_device * __init scan_one_device(struct device_node *dp,
                op->archdata.num_irqs = len / sizeof(struct linux_prom_irqs);
                for (i = 0; i < op->archdata.num_irqs; i++)
                        op->archdata.irqs[i] =
-                           sparc_irq_config.build_device_irq(op, intr[i].pri);
+                           sparc_config.build_device_irq(op, intr[i].pri);
        } else {
                const unsigned int *irq =
                        of_get_property(dp, "interrupts", &len);
@@ -365,7 +365,7 @@ static struct platform_device * __init scan_one_device(struct device_node *dp,
                        op->archdata.num_irqs = len / sizeof(unsigned int);
                        for (i = 0; i < op->archdata.num_irqs; i++)
                                op->archdata.irqs[i] =
-                                   sparc_irq_config.build_device_irq(op, irq[i]);
+                                   sparc_config.build_device_irq(op, irq[i]);
                } else {
                        op->archdata.num_irqs = 0;
                }
index fcc148e..f0ec939 100644 (file)
@@ -703,31 +703,28 @@ static void pcic_clear_clock_irq(void)
        pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT);
 }
 
-static irqreturn_t pcic_timer_handler (int irq, void *h)
+/* CPU frequency is 100 MHz, timer increments every 4 CPU clocks */
+#define USECS_PER_JIFFY  (1000000 / HZ)
+#define TICK_TIMER_LIMIT ((100 * 1000000 / 4) / HZ)
+
+static unsigned int pcic_cycles_offset(void)
 {
-       pcic_clear_clock_irq();
-       xtime_update(1);
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-       return IRQ_HANDLED;
-}
+       u32 value, count;
 
-#define USECS_PER_JIFFY  10000  /* We have 100HZ "standard" timer for sparc */
-#define TICK_TIMER_LIMIT ((100*1000000/4)/100)
+       value = readl(pcic0.pcic_regs + PCI_SYS_COUNTER);
+       count = value & ~PCI_SYS_COUNTER_OVERFLOW;
 
-u32 pci_gettimeoffset(void)
-{
+       if (value & PCI_SYS_COUNTER_OVERFLOW)
+               count += TICK_TIMER_LIMIT;
        /*
-        * We divide all by 100
+        * We divide all by HZ
         * to have microsecond resolution and to avoid overflow
         */
-       unsigned long count =
-           readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
-       count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
-       return count * 1000;
-}
+       count = ((count / HZ) * USECS_PER_JIFFY) / (TICK_TIMER_LIMIT / HZ);
 
+       /* Coordinate with the sparc_config.clock_rate setting */
+       return count * 2;
+}
 
 void __init pci_time_init(void)
 {
@@ -736,9 +733,16 @@ void __init pci_time_init(void)
        int timer_irq, irq;
        int err;
 
-       do_arch_gettimeoffset = pci_gettimeoffset;
-
-       btfixup();
+#ifndef CONFIG_SMP
+       /*
+        * The clock_rate is in SBUS dimension.
+        * We take into account this in pcic_cycles_offset()
+        */
+       sparc_config.clock_rate = SBUS_CLOCK_RATE / HZ;
+       sparc_config.features |= FEAT_L10_CLOCKEVENT;
+#endif
+       sparc_config.features |= FEAT_L10_CLOCKSOURCE;
+       sparc_config.get_cycles_offset = pcic_cycles_offset;
 
        writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT);
        /* PROM should set appropriate irq */
@@ -747,7 +751,7 @@ void __init pci_time_init(void)
        writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),
                pcic->pcic_regs+PCI_COUNTER_IRQ);
        irq = pcic_build_device_irq(NULL, timer_irq);
-       err = request_irq(irq, pcic_timer_handler,
+       err = request_irq(irq, timer_interrupt,
                          IRQF_TIMER, "timer", NULL);
        if (err) {
                prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);
@@ -875,7 +879,7 @@ static void pcic_load_profile_irq(int cpu, unsigned int limit)
 
 void __init sun4m_pci_init_IRQ(void)
 {
-       sparc_irq_config.build_device_irq = pcic_build_device_irq;
+       sparc_config.build_device_irq = pcic_build_device_irq;
 
        BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
index 9171fc2..afa2a9e 100644 (file)
@@ -73,18 +73,8 @@ rtrap_nmi:   ldx                     [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
                .globl                  rtrap_irq, rtrap, irqsz_patchme, rtrap_xcall
 rtrap_irq:
 rtrap:
-#ifndef CONFIG_SMP
-               sethi                   %hi(__cpu_data), %l0
-               lduw                    [%l0 + %lo(__cpu_data)], %l1
-#else
-               sethi                   %hi(__cpu_data), %l0
-               or                      %l0, %lo(__cpu_data), %l0
-               lduw                    [%l0 + %g5], %l1
-#endif
-               cmp                     %l1, 0
-
                /* mm/ultra.S:xcall_report_regs KNOWS about this load. */
-                ldx                    [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+               ldx                     [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 rtrap_xcall:
                sethi                   %hi(0xf << 20), %l4
                and                     %l1, %l4, %l4
index f671e7f..569a8a9 100644 (file)
@@ -301,28 +301,9 @@ void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
        local_flush_sig_insns(mm, insn_addr);
 }
 
-extern unsigned int lvl14_resolution;
-
-/* /proc/profile writes can call this, don't __init it please. */
-static DEFINE_SPINLOCK(prof_setup_lock);
-
 int setup_profiling_timer(unsigned int multiplier)
 {
-       int i;
-       unsigned long flags;
-
-       /* Prevent level14 ticker IRQ flooding. */
-       if((!multiplier) || (lvl14_resolution / multiplier) < 500)
-               return -EINVAL;
-
-       spin_lock_irqsave(&prof_setup_lock, flags);
-       for_each_possible_cpu(i) {
-               load_profile_irq(i, lvl14_resolution / multiplier);
-               prof_multiplier(i) = multiplier;
-       }
-       spin_unlock_irqrestore(&prof_setup_lock, flags);
-
-       return 0;
+       return -EINVAL;
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
index f6bf25a..39c6421 100644 (file)
@@ -174,7 +174,7 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
        /* Errm.. not sure how to do this.. */
 }
 
-static void __init sun4c_init_timers(irq_handler_t counter_fn)
+static void __init sun4c_init_timers(void)
 {
        const struct linux_prom_irqs *prom_irqs;
        struct device_node *dp;
@@ -207,12 +207,16 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn)
         * level 14 timer limit since we are letting the prom handle
         * them until we have a real console driver so L1-A works.
         */
-       sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit);
+       sparc_config.cs_period = SBUS_CLOCK_RATE / HZ;
+       sparc_config.features |=
+           FEAT_L10_CLOCKSOURCE | FEAT_L10_CLOCKEVENT;
+       sbus_writel(timer_value(sparc_config.cs_period),
+                   &sun4c_timers->l10_limit);
 
        master_l10_counter = &sun4c_timers->l10_count;
 
        irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri);
-       err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
+       err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
        if (err) {
                prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
                prom_halt();
@@ -251,8 +255,9 @@ void __init sun4c_init_IRQ(void)
        BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
 
-       sparc_irq_config.init_timers      = sun4c_init_timers;
-       sparc_irq_config.build_device_irq = sun4c_build_device_irq;
+       sparc_config.init_timers      = sun4c_init_timers;
+       sparc_config.build_device_irq = sun4c_build_device_irq;
+       sparc_config.clock_rate       = SBUS_CLOCK_RATE;
 
 #ifdef CONFIG_SMP
        BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
index 1d13c5b..abf5265 100644 (file)
@@ -282,7 +282,8 @@ static void sun4d_clear_clock_irq(void)
 
 static void sun4d_load_profile_irq(int cpu, unsigned int limit)
 {
-       bw_set_prof_limit(cpu, limit);
+       unsigned int value = limit ? timer_value(limit) : 0;
+       bw_set_prof_limit(cpu, value);
 }
 
 static void __init sun4d_load_profile_irqs(void)
@@ -423,7 +424,7 @@ static void __init sun4d_fixup_trap_table(void)
 #endif
 }
 
-static void __init sun4d_init_timers(irq_handler_t counter_fn)
+static void __init sun4d_init_timers(void)
 {
        struct device_node *dp;
        struct resource res;
@@ -466,12 +467,20 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
                prom_halt();
        }
 
-       sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
+#ifdef CONFIG_SMP
+       sparc_config.cs_period = SBUS_CLOCK_RATE * 2;  /* 2 seconds */
+#else
+       sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec  */
+       sparc_config.features |= FEAT_L10_CLOCKEVENT;
+#endif
+       sparc_config.features |= FEAT_L10_CLOCKSOURCE;
+       sbus_writel(timer_value(sparc_config.cs_period),
+                   &sun4d_timers->l10_timer_limit);
 
        master_l10_counter = &sun4d_timers->l10_cur_count;
 
        irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
-       err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
+       err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
        if (err) {
                prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
                             err);
@@ -512,8 +521,9 @@ void __init sun4d_init_IRQ(void)
        BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
 
-       sparc_irq_config.init_timers      = sun4d_init_timers;
-       sparc_irq_config.build_device_irq = sun4d_build_device_irq;
+       sparc_config.init_timers      = sun4d_init_timers;
+       sparc_config.build_device_irq = sun4d_build_device_irq;
+       sparc_config.clock_rate       = SBUS_CLOCK_RATE;
 
 #ifdef CONFIG_SMP
        BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
index 540b2fe..576fe74 100644 (file)
@@ -6,16 +6,18 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
 #include <linux/cpu.h>
 
+#include <asm/cacheflush.h>
+#include <asm/switch_to.h>
+#include <asm/tlbflush.h>
+#include <asm/timer.h>
 #include <asm/sbi.h>
 #include <asm/mmu.h>
-#include <asm/tlbflush.h>
-#include <asm/switch_to.h>
-#include <asm/cacheflush.h>
 
 #include "kernel.h"
 #include "irq.h"
@@ -34,7 +36,6 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon
 }
 
 static void smp4d_ipi_init(void);
-static void smp_setup_percpu_timer(void);
 
 static unsigned char cpu_leds[32];
 
@@ -70,7 +71,7 @@ void __cpuinit smp4d_callin(void)
         * to call the scheduler code.
         */
        /* Get our local ticker going. */
-       smp_setup_percpu_timer();
+       register_percpu_ce(cpuid);
 
        calibrate_delay();
        smp_store_cpu_info(cpuid);
@@ -123,7 +124,6 @@ void __init smp4d_boot_cpus(void)
        smp4d_ipi_init();
        if (boot_cpu_id)
                current_set[0] = NULL;
-       smp_setup_percpu_timer();
        local_flush_cache_all();
 }
 
@@ -364,6 +364,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
 {
        struct pt_regs *old_regs;
        int cpu = hard_smp4d_processor_id();
+       struct clock_event_device *ce;
        static int cpu_tick[NR_CPUS];
        static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
 
@@ -379,28 +380,15 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
                show_leds(cpu);
        }
 
-       profile_tick(CPU_PROFILING);
-
-       if (!--prof_counter(cpu)) {
-               int user = user_mode(regs);
+       ce = &per_cpu(sparc32_clockevent, cpu);
 
-               irq_enter();
-               update_process_times(user);
-               irq_exit();
+       irq_enter();
+       ce->event_handler(ce);
+       irq_exit();
 
-               prof_counter(cpu) = prof_multiplier(cpu);
-       }
        set_irq_regs(old_regs);
 }
 
-static void __cpuinit smp_setup_percpu_timer(void)
-{
-       int cpu = hard_smp4d_processor_id();
-
-       prof_counter(cpu) = prof_multiplier(cpu) = 1;
-       load_profile_irq(cpu, lvl14_resolution);
-}
-
 void __init smp4d_blackbox_id(unsigned *addr)
 {
        int rd = *addr & 0x3e000000;
index e611651..87908a5 100644 (file)
@@ -318,9 +318,6 @@ struct sun4m_timer_global {
 
 static struct sun4m_timer_global __iomem *timers_global;
 
-
-unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
-
 static void sun4m_clear_clock_irq(void)
 {
        sbus_readl(&timers_global->l10_limit);
@@ -369,10 +366,11 @@ void sun4m_clear_profile_irq(int cpu)
 
 static void sun4m_load_profile_irq(int cpu, unsigned int limit)
 {
-       sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
+       unsigned int value = limit ? timer_value(limit) : 0;
+       sbus_writel(value, &timers_percpu[cpu]->l14_limit);
 }
 
-static void __init sun4m_init_timers(irq_handler_t counter_fn)
+static void __init sun4m_init_timers(void)
 {
        struct device_node *dp = of_find_node_by_name(NULL, "counter");
        int i, err, len, num_cpu_timers;
@@ -402,13 +400,22 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
        /* Every per-cpu timer works in timer mode */
        sbus_writel(0x00000000, &timers_global->timer_config);
 
-       sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
+#ifdef CONFIG_SMP
+       sparc_config.cs_period = SBUS_CLOCK_RATE * 2;  /* 2 seconds */
+       sparc_config.features |= FEAT_L14_ONESHOT;
+#else
+       sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec  */
+       sparc_config.features |= FEAT_L10_CLOCKEVENT;
+#endif
+       sparc_config.features |= FEAT_L10_CLOCKSOURCE;
+       sbus_writel(timer_value(sparc_config.cs_period),
+                   &timers_global->l10_limit);
 
        master_l10_counter = &timers_global->l10_count;
 
        irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ);
 
-       err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
+       err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
        if (err) {
                printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
                        err);
@@ -478,8 +485,9 @@ void __init sun4m_init_IRQ(void)
        BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
 
-       sparc_irq_config.init_timers = sun4m_init_timers;
-       sparc_irq_config.build_device_irq = sun4m_build_device_irq;
+       sparc_config.init_timers = sun4m_init_timers;
+       sparc_config.build_device_irq = sun4m_build_device_irq;
+       sparc_config.clock_rate       = SBUS_CLOCK_RATE;
 
 #ifdef CONFIG_SMP
        BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
index 02db9a0..29f8ace 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
@@ -12,6 +13,7 @@
 #include <asm/cacheflush.h>
 #include <asm/switch_to.h>
 #include <asm/tlbflush.h>
+#include <asm/timer.h>
 
 #include "irq.h"
 #include "kernel.h"
@@ -31,7 +33,6 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val)
 }
 
 static void smp4m_ipi_init(void);
-static void smp_setup_percpu_timer(void);
 
 void __cpuinit smp4m_callin(void)
 {
@@ -42,8 +43,7 @@ void __cpuinit smp4m_callin(void)
 
        notify_cpu_starting(cpuid);
 
-       /* Get our local ticker going. */
-       smp_setup_percpu_timer();
+       register_percpu_ce(cpuid);
 
        calibrate_delay();
        smp_store_cpu_info(cpuid);
@@ -87,7 +87,7 @@ void __cpuinit smp4m_callin(void)
 void __init smp4m_boot_cpus(void)
 {
        smp4m_ipi_init();
-       smp_setup_percpu_timer();
+       sun4m_unmask_profile_irq();
        local_flush_cache_all();
 }
 
@@ -260,37 +260,25 @@ void smp4m_cross_call_irq(void)
 void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 {
        struct pt_regs *old_regs;
+       struct clock_event_device *ce;
        int cpu = smp_processor_id();
 
        old_regs = set_irq_regs(regs);
 
-       sun4m_clear_profile_irq(cpu);
+       ce = &per_cpu(sparc32_clockevent, cpu);
 
-       profile_tick(CPU_PROFILING);
+       if (ce->mode & CLOCK_EVT_MODE_PERIODIC)
+               sun4m_clear_profile_irq(cpu);
+       else
+               load_profile_irq(cpu, 0); /* Is this needless? */
 
-       if (!--prof_counter(cpu)) {
-               int user = user_mode(regs);
+       irq_enter();
+       ce->event_handler(ce);
+       irq_exit();
 
-               irq_enter();
-               update_process_times(user);
-               irq_exit();
-
-               prof_counter(cpu) = prof_multiplier(cpu);
-       }
        set_irq_regs(old_regs);
 }
 
-static void __cpuinit smp_setup_percpu_timer(void)
-{
-       int cpu = smp_processor_id();
-
-       prof_counter(cpu) = prof_multiplier(cpu) = 1;
-       load_profile_irq(cpu, lvl14_resolution);
-
-       if (cpu == boot_cpu_id)
-               sun4m_unmask_profile_irq();
-}
-
 static void __init smp4m_blackbox_id(unsigned *addr)
 {
        int rd = *addr & 0x3e000000;
index 7d0c088..89e890b 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/rtc.h>
 #include <linux/rtc/m48t59.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <asm/page.h>
 #include <asm/pcic.h>
 #include <asm/irq_regs.h>
+#include <asm/setup.h>
 
 #include "irq.h"
 
+static __cacheline_aligned_in_smp DEFINE_SEQLOCK(timer_cs_lock);
+static __volatile__ u64 timer_cs_internal_counter = 0;
+static char timer_cs_enabled = 0;
+
+static struct clock_event_device timer_ce;
+static char timer_ce_enabled = 0;
+
+#ifdef CONFIG_SMP
+DEFINE_PER_CPU(struct clock_event_device, sparc32_clockevent);
+#endif
+
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
@@ -75,36 +89,167 @@ EXPORT_SYMBOL(profile_pc);
 
 __volatile__ unsigned int *master_l10_counter;
 
-u32 (*do_arch_gettimeoffset)(void);
-
 int update_persistent_clock(struct timespec now)
 {
        return set_rtc_mmss(now.tv_sec);
 }
 
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "xtime_update()" routine every clocktick
- */
+irqreturn_t notrace timer_interrupt(int dummy, void *dev_id)
+{
+       if (timer_cs_enabled) {
+               write_seqlock(&timer_cs_lock);
+               timer_cs_internal_counter++;
+               clear_clock_irq();
+               write_sequnlock(&timer_cs_lock);
+       } else {
+               clear_clock_irq();
+       }
 
-#define TICK_SIZE (tick_nsec / 1000)
+       if (timer_ce_enabled)
+               timer_ce.event_handler(&timer_ce);
 
-static irqreturn_t timer_interrupt(int dummy, void *dev_id)
+       return IRQ_HANDLED;
+}
+
+static void timer_ce_set_mode(enum clock_event_mode mode,
+                             struct clock_event_device *evt)
 {
-#ifndef CONFIG_SMP
-       profile_tick(CPU_PROFILING);
-#endif
+       switch (mode) {
+               case CLOCK_EVT_MODE_PERIODIC:
+               case CLOCK_EVT_MODE_RESUME:
+                       timer_ce_enabled = 1;
+                       break;
+               case CLOCK_EVT_MODE_SHUTDOWN:
+                       timer_ce_enabled = 0;
+                       break;
+               default:
+                       break;
+       }
+       smp_mb();
+}
+
+static __init void setup_timer_ce(void)
+{
+       struct clock_event_device *ce = &timer_ce;
+
+       BUG_ON(smp_processor_id() != boot_cpu_id);
+
+       ce->name     = "timer_ce";
+       ce->rating   = 100;
+       ce->features = CLOCK_EVT_FEAT_PERIODIC;
+       ce->set_mode = timer_ce_set_mode;
+       ce->cpumask  = cpu_possible_mask;
+       ce->shift    = 32;
+       ce->mult     = div_sc(sparc_config.clock_rate, NSEC_PER_SEC,
+                             ce->shift);
+       clockevents_register_device(ce);
+}
 
-       clear_clock_irq();
+static unsigned int sbus_cycles_offset(void)
+{
+       unsigned int val, offset;
 
-       xtime_update(1);
+       val = *master_l10_counter;
+       offset = (val >> TIMER_VALUE_SHIFT) & TIMER_VALUE_MASK;
 
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-       return IRQ_HANDLED;
+       /* Limit hit? */
+       if (val & TIMER_LIMIT_BIT)
+               offset += sparc_config.cs_period;
+
+       return offset;
 }
 
+static cycle_t timer_cs_read(struct clocksource *cs)
+{
+       unsigned int seq, offset;
+       u64 cycles;
+
+       do {
+               seq = read_seqbegin(&timer_cs_lock);
+
+               cycles = timer_cs_internal_counter;
+               offset = sparc_config.get_cycles_offset();
+       } while (read_seqretry(&timer_cs_lock, seq));
+
+       /* Count absolute cycles */
+       cycles *= sparc_config.cs_period;
+       cycles += offset;
+
+       return cycles;
+}
+
+static struct clocksource timer_cs = {
+       .name   = "timer_cs",
+       .rating = 100,
+       .read   = timer_cs_read,
+       .mask   = CLOCKSOURCE_MASK(64),
+       .shift  = 2,
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static __init int setup_timer_cs(void)
+{
+       timer_cs_enabled = 1;
+       timer_cs.mult = clocksource_hz2mult(sparc_config.clock_rate,
+                                           timer_cs.shift);
+
+       return clocksource_register(&timer_cs);
+}
+
+#ifdef CONFIG_SMP
+static void percpu_ce_setup(enum clock_event_mode mode,
+                       struct clock_event_device *evt)
+{
+       int cpu = __first_cpu(evt->cpumask);
+
+       switch (mode) {
+               case CLOCK_EVT_MODE_PERIODIC:
+                       load_profile_irq(cpu, SBUS_CLOCK_RATE / HZ);
+                       break;
+               case CLOCK_EVT_MODE_ONESHOT:
+               case CLOCK_EVT_MODE_SHUTDOWN:
+               case CLOCK_EVT_MODE_UNUSED:
+                       load_profile_irq(cpu, 0);
+                       break;
+               default:
+                       break;
+       }
+}
+
+static int percpu_ce_set_next_event(unsigned long delta,
+                                   struct clock_event_device *evt)
+{
+       int cpu = __first_cpu(evt->cpumask);
+       unsigned int next = (unsigned int)delta;
+
+       load_profile_irq(cpu, next);
+       return 0;
+}
+
+void register_percpu_ce(int cpu)
+{
+       struct clock_event_device *ce = &per_cpu(sparc32_clockevent, cpu);
+       unsigned int features = CLOCK_EVT_FEAT_PERIODIC;
+
+       if (sparc_config.features & FEAT_L14_ONESHOT)
+               features |= CLOCK_EVT_FEAT_ONESHOT;
+
+       ce->name           = "percpu_ce";
+       ce->rating         = 200;
+       ce->features       = features;
+       ce->set_mode       = percpu_ce_setup;
+       ce->set_next_event = percpu_ce_set_next_event;
+       ce->cpumask        = cpumask_of(cpu);
+       ce->shift          = 32;
+       ce->mult           = div_sc(sparc_config.clock_rate, NSEC_PER_SEC,
+                                   ce->shift);
+       ce->max_delta_ns   = clockevent_delta2ns(sparc_config.clock_rate, ce);
+       ce->min_delta_ns   = clockevent_delta2ns(100, ce);
+
+       clockevents_register_device(ce);
+}
+#endif
+
 static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -195,38 +340,30 @@ static int __init clock_init(void)
  */
 fs_initcall(clock_init);
 
-
-u32 sbus_do_gettimeoffset(void)
+static void __init sparc32_late_time_init(void)
 {
-       unsigned long val = *master_l10_counter;
-       unsigned long usec = (val >> 10) & 0x1fffff;
-
-       /* Limit hit?  */
-       if (val & 0x80000000)
-               usec += 1000000 / HZ;
-
-       return usec * 1000;
+       if (sparc_config.features & FEAT_L10_CLOCKEVENT)
+               setup_timer_ce();
+       if (sparc_config.features & FEAT_L10_CLOCKSOURCE)
+               setup_timer_cs();
+#ifdef CONFIG_SMP
+       register_percpu_ce(smp_processor_id());
+#endif
 }
 
-
-u32 arch_gettimeoffset(void)
+static void __init sbus_time_init(void)
 {
-       if (unlikely(!do_arch_gettimeoffset))
-               return 0;
-       return do_arch_gettimeoffset();
+       sparc_config.get_cycles_offset = sbus_cycles_offset;
+       sparc_config.init_timers();
 }
 
-static void __init sbus_time_init(void)
+void __init time_init(void)
 {
-       do_arch_gettimeoffset = sbus_do_gettimeoffset;
-
        btfixup();
 
-       sparc_irq_config.init_timers(timer_interrupt);
-}
+       sparc_config.features = 0;
+       late_time_init = sparc32_late_time_init;
 
-void __init time_init(void)
-{
        if (pcic_present())
                pci_time_init();
        else
index dae85bc..f81d038 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/bitops.h>
 #include <linux/perf_event.h>
 #include <linux/ratelimit.h>
-#include <linux/bitops.h>
 #include <asm/fpumacro.h>
 #include <asm/cacheflush.h>
 
index cbef74e..f37fbb2 100644 (file)
@@ -705,7 +705,7 @@ static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long ad
                val = srmmu_hwprobe(address);
                if (val != 0 && pte_val(*ptep) != val) {
                        printk("swift_update_mmu_cache: "
-                           "addr %lx put %08x probed %08x from %p\n",
+                           "addr %lx put %08x probed %08x from %pf\n",
                            address, pte_val(*ptep), val,
                            __builtin_return_address(0));
                        srmmu_flush_whole_tlb();