Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: smp_twd: add runtime registration support

Add support for the new registration interface to smp_twd.
Platforms can populate a struct twd_local_timer with MMIO
and IRQ resources, and then call twd_local_timer_register()
to have the timer registered with the core.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+65 -4
+17 -1
arch/arm/include/asm/smp_twd.h
··· 18 18 #define TWD_TIMER_CONTROL_PERIODIC (1 << 1) 19 19 #define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2) 20 20 21 + #include <linux/ioport.h> 22 + 21 23 struct clock_event_device; 22 24 23 25 extern void __iomem *twd_base; 24 26 25 - void twd_timer_setup(struct clock_event_device *); 27 + int twd_timer_setup(struct clock_event_device *); 28 + 29 + struct twd_local_timer { 30 + struct resource res[2]; 31 + }; 32 + 33 + #define DEFINE_TWD_LOCAL_TIMER(name,base,irq) \ 34 + struct twd_local_timer name __initdata = { \ 35 + .res = { \ 36 + DEFINE_RES_MEM(base, 0x10), \ 37 + DEFINE_RES_IRQ(irq), \ 38 + }, \ 39 + }; 40 + 41 + int twd_local_timer_register(struct twd_local_timer *); 26 42 27 43 #endif
+48 -3
arch/arm/kernel/smp_twd.c
··· 32 32 static unsigned long twd_timer_rate; 33 33 34 34 static struct clock_event_device __percpu **twd_evt; 35 + static int twd_ppi; 35 36 36 37 static void twd_set_mode(enum clock_event_mode mode, 37 38 struct clock_event_device *clk) ··· 228 227 /* 229 228 * Setup the local clock events for a CPU. 230 229 */ 231 - void __cpuinit twd_timer_setup(struct clock_event_device *clk) 230 + int __cpuinit twd_timer_setup(struct clock_event_device *clk) 232 231 { 233 232 struct clock_event_device **this_cpu_clk; 234 233 ··· 238 237 twd_evt = alloc_percpu(struct clock_event_device *); 239 238 if (!twd_evt) { 240 239 pr_err("twd: can't allocate memory\n"); 241 - return; 240 + return -ENOMEM; 242 241 } 243 242 244 243 err = request_percpu_irq(clk->irq, twd_handler, ··· 246 245 if (err) { 247 246 pr_err("twd: can't register interrupt %d (%d)\n", 248 247 clk->irq, err); 249 - return; 248 + return err; 250 249 } 251 250 } 252 251 ··· 266 265 clk->rating = 350; 267 266 clk->set_mode = twd_set_mode; 268 267 clk->set_next_event = twd_set_next_event; 268 + if (!clk->irq) 269 + clk->irq = twd_ppi; 269 270 270 271 this_cpu_clk = __this_cpu_ptr(twd_evt); 271 272 *this_cpu_clk = clk; ··· 275 272 clockevents_config_and_register(clk, twd_timer_rate, 276 273 0xf, 0xffffffff); 277 274 enable_percpu_irq(clk->irq, 0); 275 + 276 + return 0; 277 + } 278 + 279 + static struct local_timer_ops twd_lt_ops __cpuinitdata = { 280 + .setup = twd_timer_setup, 281 + .stop = twd_timer_stop, 282 + }; 283 + 284 + int __init twd_local_timer_register(struct twd_local_timer *tlt) 285 + { 286 + int err; 287 + 288 + if (twd_base || twd_evt) 289 + return -EBUSY; 290 + 291 + twd_ppi = tlt->res[1].start; 292 + 293 + twd_evt = alloc_percpu(struct clock_event_device *); 294 + twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); 295 + if (!twd_base || !twd_evt) { 296 + err = -ENOMEM; 297 + goto out; 298 + } 299 + 300 + err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt); 301 + if (err) { 302 + pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err); 303 + goto out; 304 + } 305 + 306 + err = local_timer_register(&twd_lt_ops); 307 + if (err) 308 + goto out; 309 + 310 + return 0; 311 + 312 + out: 313 + iounmap(twd_base); 314 + free_percpu(twd_evt); 315 + twd_base = twd_evt = NULL; 316 + return err; 278 317 }