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>
This commit is contained in:
@@ -18,10 +18,26 @@
|
|||||||
#define TWD_TIMER_CONTROL_PERIODIC (1 << 1)
|
#define TWD_TIMER_CONTROL_PERIODIC (1 << 1)
|
||||||
#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2)
|
#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2)
|
||||||
|
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
|
||||||
struct clock_event_device;
|
struct clock_event_device;
|
||||||
|
|
||||||
extern void __iomem *twd_base;
|
extern void __iomem *twd_base;
|
||||||
|
|
||||||
void twd_timer_setup(struct clock_event_device *);
|
int twd_timer_setup(struct clock_event_device *);
|
||||||
|
|
||||||
|
struct twd_local_timer {
|
||||||
|
struct resource res[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFINE_TWD_LOCAL_TIMER(name,base,irq) \
|
||||||
|
struct twd_local_timer name __initdata = { \
|
||||||
|
.res = { \
|
||||||
|
DEFINE_RES_MEM(base, 0x10), \
|
||||||
|
DEFINE_RES_IRQ(irq), \
|
||||||
|
}, \
|
||||||
|
};
|
||||||
|
|
||||||
|
int twd_local_timer_register(struct twd_local_timer *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -32,6 +32,7 @@ static struct clk *twd_clk;
|
|||||||
static unsigned long twd_timer_rate;
|
static unsigned long twd_timer_rate;
|
||||||
|
|
||||||
static struct clock_event_device __percpu **twd_evt;
|
static struct clock_event_device __percpu **twd_evt;
|
||||||
|
static int twd_ppi;
|
||||||
|
|
||||||
static void twd_set_mode(enum clock_event_mode mode,
|
static void twd_set_mode(enum clock_event_mode mode,
|
||||||
struct clock_event_device *clk)
|
struct clock_event_device *clk)
|
||||||
@@ -227,7 +228,7 @@ static struct clk *twd_get_clock(void)
|
|||||||
/*
|
/*
|
||||||
* Setup the local clock events for a CPU.
|
* Setup the local clock events for a CPU.
|
||||||
*/
|
*/
|
||||||
void __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
int __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
||||||
{
|
{
|
||||||
struct clock_event_device **this_cpu_clk;
|
struct clock_event_device **this_cpu_clk;
|
||||||
|
|
||||||
@@ -237,7 +238,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
|||||||
twd_evt = alloc_percpu(struct clock_event_device *);
|
twd_evt = alloc_percpu(struct clock_event_device *);
|
||||||
if (!twd_evt) {
|
if (!twd_evt) {
|
||||||
pr_err("twd: can't allocate memory\n");
|
pr_err("twd: can't allocate memory\n");
|
||||||
return;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = request_percpu_irq(clk->irq, twd_handler,
|
err = request_percpu_irq(clk->irq, twd_handler,
|
||||||
@@ -245,7 +246,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
|||||||
if (err) {
|
if (err) {
|
||||||
pr_err("twd: can't register interrupt %d (%d)\n",
|
pr_err("twd: can't register interrupt %d (%d)\n",
|
||||||
clk->irq, err);
|
clk->irq, err);
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,6 +266,8 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
|||||||
clk->rating = 350;
|
clk->rating = 350;
|
||||||
clk->set_mode = twd_set_mode;
|
clk->set_mode = twd_set_mode;
|
||||||
clk->set_next_event = twd_set_next_event;
|
clk->set_next_event = twd_set_next_event;
|
||||||
|
if (!clk->irq)
|
||||||
|
clk->irq = twd_ppi;
|
||||||
|
|
||||||
this_cpu_clk = __this_cpu_ptr(twd_evt);
|
this_cpu_clk = __this_cpu_ptr(twd_evt);
|
||||||
*this_cpu_clk = clk;
|
*this_cpu_clk = clk;
|
||||||
@@ -272,4 +275,46 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
|||||||
clockevents_config_and_register(clk, twd_timer_rate,
|
clockevents_config_and_register(clk, twd_timer_rate,
|
||||||
0xf, 0xffffffff);
|
0xf, 0xffffffff);
|
||||||
enable_percpu_irq(clk->irq, 0);
|
enable_percpu_irq(clk->irq, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct local_timer_ops twd_lt_ops __cpuinitdata = {
|
||||||
|
.setup = twd_timer_setup,
|
||||||
|
.stop = twd_timer_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
int __init twd_local_timer_register(struct twd_local_timer *tlt)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (twd_base || twd_evt)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
twd_ppi = tlt->res[1].start;
|
||||||
|
|
||||||
|
twd_evt = alloc_percpu(struct clock_event_device *);
|
||||||
|
twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
|
||||||
|
if (!twd_base || !twd_evt) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
|
||||||
|
if (err) {
|
||||||
|
pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = local_timer_register(&twd_lt_ops);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
iounmap(twd_base);
|
||||||
|
free_percpu(twd_evt);
|
||||||
|
twd_base = twd_evt = NULL;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user