diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-22 05:38:44 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-22 17:09:00 -0400 |
commit | d04533650f64fe3367e180f3e488d92205152cd3 (patch) | |
tree | 5f183668d97d9655a8517e61afd46bfa2f80b101 /arch/mips/sibyte/sb1250/time.c | |
parent | 06d428d719dece96c01532b62df4140f4e69a308 (diff) |
[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 @@ | |||
52 | 52 | ||
53 | extern int sb1250_steal_irq(int irq); | 53 | extern int sb1250_steal_irq(int irq); |
54 | 54 | ||
55 | static cycle_t sb1250_hpt_read(void); | ||
56 | |||
57 | void __init sb1250_hpt_setup(void) | ||
58 | { | ||
59 | int cpu = smp_processor_id(); | ||
60 | |||
61 | if (!cpu) { | ||
62 | /* Setup hpt using timer #3 but do not enable irq for it */ | ||
63 | __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); | ||
64 | __raw_writeq(SB1250_HPT_VALUE, | ||
65 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT))); | ||
66 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | ||
67 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); | ||
68 | |||
69 | mips_hpt_frequency = V_SCD_TIMER_FREQ; | ||
70 | clocksource_mips.read = sb1250_hpt_read; | ||
71 | clocksource_mips.mask = M_SCD_TIMER_INIT; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | /* | 55 | /* |
76 | * The general purpose timer ticks at 1 Mhz independent if | 56 | * The general purpose timer ticks at 1 Mhz independent if |
77 | * the rest of the system | 57 | * the rest of the system |
@@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt) | |||
121 | return 0; | 101 | return 0; |
122 | } | 102 | } |
123 | 103 | ||
124 | struct clock_event_device sibyte_hpt_clockevent = { | ||
125 | .name = "sb1250-counter", | ||
126 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
127 | .set_mode = sibyte_set_mode, | ||
128 | .set_next_event = sibyte_next_event, | ||
129 | .shift = 32, | ||
130 | .irq = 0, | ||
131 | }; | ||
132 | |||
133 | static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) | 104 | static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) |
134 | { | 105 | { |
135 | struct clock_event_device *cd = &sibyte_hpt_clockevent; | 106 | unsigned int cpu = smp_processor_id(); |
107 | struct clock_event_device *cd = dev_id; | ||
108 | |||
109 | /* ACK interrupt */ | ||
110 | ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | ||
111 | IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); | ||
136 | 112 | ||
137 | cd->event_handler(cd); | 113 | cd->event_handler(cd); |
138 | 114 | ||
@@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = { | |||
145 | .name = "timer", | 121 | .name = "timer", |
146 | }; | 122 | }; |
147 | 123 | ||
124 | static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); | ||
125 | static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction); | ||
126 | static DEFINE_PER_CPU(char [18], sibyte_hpt_name); | ||
127 | |||
148 | void __cpuinit sb1250_clockevent_init(void) | 128 | void __cpuinit sb1250_clockevent_init(void) |
149 | { | 129 | { |
150 | struct clock_event_device *cd = &sibyte_hpt_clockevent; | ||
151 | unsigned int cpu = smp_processor_id(); | 130 | unsigned int cpu = smp_processor_id(); |
152 | int irq = K_INT_TIMER_0 + cpu; | 131 | unsigned int irq = K_INT_TIMER_0 + cpu; |
132 | struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu); | ||
133 | struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); | ||
134 | unsigned char *name = per_cpu(sibyte_hpt_name, cpu); | ||
153 | 135 | ||
154 | /* Only have 4 general purpose timers, and we use last one as hpt */ | 136 | /* Only have 4 general purpose timers, and we use last one as hpt */ |
155 | BUG_ON(cpu > 2); | 137 | BUG_ON(cpu > 2); |
156 | 138 | ||
139 | sprintf(name, "bcm1480-counter %d", cpu); | ||
140 | cd->name = name; | ||
141 | cd->features = CLOCK_EVT_FEAT_PERIODIC | | ||
142 | CLOCK_EVT_MODE_ONESHOT; | ||
143 | clockevent_set_clock(cd, V_SCD_TIMER_FREQ); | ||
144 | cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd); | ||
145 | cd->min_delta_ns = clockevent_delta2ns(1, cd); | ||
146 | cd->rating = 200; | ||
147 | cd->irq = irq; | ||
148 | cd->cpumask = cpumask_of_cpu(cpu); | ||
149 | cd->set_next_event = sibyte_next_event; | ||
150 | cd->set_mode = sibyte_set_mode; | ||
151 | clockevents_register_device(cd); | ||
152 | |||
157 | sb1250_mask_irq(cpu, irq); | 153 | sb1250_mask_irq(cpu, irq); |
158 | 154 | ||
159 | /* Map the timer interrupt to ip[4] of this cpu */ | 155 | /* Map the timer interrupt to ip[4] of this cpu */ |
@@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void) | |||
165 | sb1250_unmask_irq(cpu, irq); | 161 | sb1250_unmask_irq(cpu, irq); |
166 | sb1250_steal_irq(irq); | 162 | sb1250_steal_irq(irq); |
167 | 163 | ||
168 | /* | 164 | action->handler = sibyte_counter_handler; |
169 | * This interrupt is "special" in that it doesn't use the request_irq | 165 | action->flags = IRQF_DISABLED | IRQF_PERCPU; |
170 | * way to hook the irq line. The timer interrupt is initialized early | 166 | action->name = name; |
171 | * enough to make this a major pain, and it's also firing enough to | 167 | action->dev_id = cd; |
172 | * warrant a bit of special case code. sb1250_timer_interrupt is | ||
173 | * called directly from irq_handler.S when IP[4] is set during an | ||
174 | * interrupt | ||
175 | */ | ||
176 | setup_irq(irq, &sibyte_irqaction); | 168 | setup_irq(irq, &sibyte_irqaction); |
177 | |||
178 | clockevents_register_device(cd); | ||
179 | } | 169 | } |
180 | 170 | ||
181 | /* | 171 | /* |
@@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = { | |||
195 | .name = "MIPS", | 185 | .name = "MIPS", |
196 | .rating = 200, | 186 | .rating = 200, |
197 | .read = sb1250_hpt_read, | 187 | .read = sb1250_hpt_read, |
198 | .mask = CLOCKSOURCE_MASK(32), | 188 | .mask = CLOCKSOURCE_MASK(23), |
199 | .shift = 32, | ||
200 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 189 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
201 | }; | 190 | }; |
202 | 191 | ||
@@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void) | |||
204 | { | 193 | { |
205 | struct clocksource *cs = &bcm1250_clocksource; | 194 | struct clocksource *cs = &bcm1250_clocksource; |
206 | 195 | ||
196 | /* Setup hpt using timer #3 but do not enable irq for it */ | ||
197 | __raw_writeq(0, | ||
198 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, | ||
199 | R_SCD_TIMER_CFG))); | ||
200 | __raw_writeq(SB1250_HPT_VALUE, | ||
201 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, | ||
202 | R_SCD_TIMER_INIT))); | ||
203 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | ||
204 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, | ||
205 | R_SCD_TIMER_CFG))); | ||
206 | |||
207 | clocksource_set_clock(cs, V_SCD_TIMER_FREQ); | 207 | clocksource_set_clock(cs, V_SCD_TIMER_FREQ); |
208 | clocksource_register(cs); | 208 | clocksource_register(cs); |
209 | } | 209 | } |