diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-22 13:38:44 +0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-23 01:09:00 +0400 |
commit | d04533650f64fe3367e180f3e488d92205152cd3 (patch) | |
tree | 5f183668d97d9655a8517e61afd46bfa2f80b101 /arch/mips/sibyte/sb1250/time.c | |
parent | 06d428d719dece96c01532b62df4140f4e69a308 (diff) | |
download | linux-d04533650f64fe3367e180f3e488d92205152cd3.tar.xz |
[MIPS] time: SMP-proofing of Sibyte clockevent/clocksource code.
The BCM148 has 4 cores but there are also just 4 generic timers available
so use the ZBbus cycle counter instead of it. In addition the ZBbus
counter also offers a much higher resolution and 64-bit counting so I'm
considering a later complete conversion to it once I figure out if all
members of the Sibyte SOC family support it - the docs seem to agree but
the headers files seem to disagree ...
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/sibyte/sb1250/time.c')
-rw-r--r-- | arch/mips/sibyte/sb1250/time.c | 88 |
1 files changed, 44 insertions, 44 deletions
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 9ef54628bc9c..a41e908bc218 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -52,26 +52,6 @@ extern int sb1250_steal_irq(int irq); -static cycle_t sb1250_hpt_read(void); - -void __init sb1250_hpt_setup(void) -{ - int cpu = smp_processor_id(); - - if (!cpu) { - /* Setup hpt using timer #3 but do not enable irq for it */ - __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); - __raw_writeq(SB1250_HPT_VALUE, - IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT))); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); - - mips_hpt_frequency = V_SCD_TIMER_FREQ; - clocksource_mips.read = sb1250_hpt_read; - clocksource_mips.mask = M_SCD_TIMER_INIT; - } -} - /* * The general purpose timer ticks at 1 Mhz independent if * the rest of the system @@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt) return 0; } -struct clock_event_device sibyte_hpt_clockevent = { - .name = "sb1250-counter", - .features = CLOCK_EVT_FEAT_PERIODIC, - .set_mode = sibyte_set_mode, - .set_next_event = sibyte_next_event, - .shift = 32, - .irq = 0, -}; - static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) { - struct clock_event_device *cd = &sibyte_hpt_clockevent; + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd = dev_id; + + /* ACK interrupt */ + ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); cd->event_handler(cd); @@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = { .name = "timer", }; +static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); +static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction); +static DEFINE_PER_CPU(char [18], sibyte_hpt_name); + void __cpuinit sb1250_clockevent_init(void) { - struct clock_event_device *cd = &sibyte_hpt_clockevent; unsigned int cpu = smp_processor_id(); - int irq = K_INT_TIMER_0 + cpu; + unsigned int irq = K_INT_TIMER_0 + cpu; + struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu); + struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); + unsigned char *name = per_cpu(sibyte_hpt_name, cpu); /* Only have 4 general purpose timers, and we use last one as hpt */ BUG_ON(cpu > 2); + sprintf(name, "bcm1480-counter %d", cpu); + cd->name = name; + cd->features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_MODE_ONESHOT; + clockevent_set_clock(cd, V_SCD_TIMER_FREQ); + cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd); + cd->min_delta_ns = clockevent_delta2ns(1, cd); + cd->rating = 200; + cd->irq = irq; + cd->cpumask = cpumask_of_cpu(cpu); + cd->set_next_event = sibyte_next_event; + cd->set_mode = sibyte_set_mode; + clockevents_register_device(cd); + sb1250_mask_irq(cpu, irq); /* Map the timer interrupt to ip[4] of this cpu */ @@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void) sb1250_unmask_irq(cpu, irq); sb1250_steal_irq(irq); - /* - * This interrupt is "special" in that it doesn't use the request_irq - * way to hook the irq line. The timer interrupt is initialized early - * enough to make this a major pain, and it's also firing enough to - * warrant a bit of special case code. sb1250_timer_interrupt is - * called directly from irq_handler.S when IP[4] is set during an - * interrupt - */ + action->handler = sibyte_counter_handler; + action->flags = IRQF_DISABLED | IRQF_PERCPU; + action->name = name; + action->dev_id = cd; setup_irq(irq, &sibyte_irqaction); - - clockevents_register_device(cd); } /* @@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = { .name = "MIPS", .rating = 200, .read = sb1250_hpt_read, - .mask = CLOCKSOURCE_MASK(32), - .shift = 32, + .mask = CLOCKSOURCE_MASK(23), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void) { struct clocksource *cs = &bcm1250_clocksource; + /* Setup hpt using timer #3 but do not enable irq for it */ + __raw_writeq(0, + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, + R_SCD_TIMER_CFG))); + __raw_writeq(SB1250_HPT_VALUE, + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, + R_SCD_TIMER_INIT))); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, + R_SCD_TIMER_CFG))); + clocksource_set_clock(cs, V_SCD_TIMER_FREQ); clocksource_register(cs); } |