diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2013-10-16 18:42:19 -0400 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2014-01-14 13:19:55 -0500 |
commit | 6235153170db777296b6a47181056dd30a027d03 (patch) | |
tree | 0c9de2c18f640f558b1fdd5e4e229cb14773d260 /arch/xtensa | |
parent | 0fb4040e6ed69b62e64ec781694882309edbf33c (diff) |
xtensa: update clockevent setup for SMP
Provide per-cpu ccount_timer objects and use them appropriately.
Extract per-cpu clockevent setup function.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/kernel/time.c | 54 |
1 files changed, 29 insertions, 25 deletions
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 26eb6a9e8d4e..4ce7aae39e64 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c | |||
@@ -53,18 +53,12 @@ static int ccount_timer_set_next_event(unsigned long delta, | |||
53 | struct clock_event_device *dev); | 53 | struct clock_event_device *dev); |
54 | static void ccount_timer_set_mode(enum clock_event_mode mode, | 54 | static void ccount_timer_set_mode(enum clock_event_mode mode, |
55 | struct clock_event_device *evt); | 55 | struct clock_event_device *evt); |
56 | static struct ccount_timer_t { | 56 | struct ccount_timer { |
57 | struct clock_event_device evt; | 57 | struct clock_event_device evt; |
58 | int irq_enabled; | 58 | int irq_enabled; |
59 | } ccount_timer = { | 59 | char name[24]; |
60 | .evt = { | ||
61 | .name = "ccount_clockevent", | ||
62 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
63 | .rating = 300, | ||
64 | .set_next_event = ccount_timer_set_next_event, | ||
65 | .set_mode = ccount_timer_set_mode, | ||
66 | }, | ||
67 | }; | 60 | }; |
61 | static DEFINE_PER_CPU(struct ccount_timer, ccount_timer); | ||
68 | 62 | ||
69 | static int ccount_timer_set_next_event(unsigned long delta, | 63 | static int ccount_timer_set_next_event(unsigned long delta, |
70 | struct clock_event_device *dev) | 64 | struct clock_event_device *dev) |
@@ -85,8 +79,8 @@ static int ccount_timer_set_next_event(unsigned long delta, | |||
85 | static void ccount_timer_set_mode(enum clock_event_mode mode, | 79 | static void ccount_timer_set_mode(enum clock_event_mode mode, |
86 | struct clock_event_device *evt) | 80 | struct clock_event_device *evt) |
87 | { | 81 | { |
88 | struct ccount_timer_t *timer = | 82 | struct ccount_timer *timer = |
89 | container_of(evt, struct ccount_timer_t, evt); | 83 | container_of(evt, struct ccount_timer, evt); |
90 | 84 | ||
91 | /* | 85 | /* |
92 | * There is no way to disable the timer interrupt at the device level, | 86 | * There is no way to disable the timer interrupt at the device level, |
@@ -118,9 +112,28 @@ static struct irqaction timer_irqaction = { | |||
118 | .handler = timer_interrupt, | 112 | .handler = timer_interrupt, |
119 | .flags = IRQF_TIMER, | 113 | .flags = IRQF_TIMER, |
120 | .name = "timer", | 114 | .name = "timer", |
121 | .dev_id = &ccount_timer, | ||
122 | }; | 115 | }; |
123 | 116 | ||
117 | void local_timer_setup(unsigned cpu) | ||
118 | { | ||
119 | struct ccount_timer *timer = &per_cpu(ccount_timer, cpu); | ||
120 | struct clock_event_device *clockevent = &timer->evt; | ||
121 | |||
122 | timer->irq_enabled = 1; | ||
123 | clockevent->name = timer->name; | ||
124 | snprintf(timer->name, sizeof(timer->name), "ccount_clockevent_%u", cpu); | ||
125 | clockevent->features = CLOCK_EVT_FEAT_ONESHOT; | ||
126 | clockevent->rating = 300; | ||
127 | clockevent->set_next_event = ccount_timer_set_next_event; | ||
128 | clockevent->set_mode = ccount_timer_set_mode; | ||
129 | clockevent->cpumask = cpumask_of(cpu); | ||
130 | clockevent->irq = irq_create_mapping(NULL, LINUX_TIMER_INT); | ||
131 | if (WARN(!clockevent->irq, "error: can't map timer irq")) | ||
132 | return; | ||
133 | clockevents_config_and_register(clockevent, ccount_freq, | ||
134 | 0xf, 0xffffffff); | ||
135 | } | ||
136 | |||
124 | void __init time_init(void) | 137 | void __init time_init(void) |
125 | { | 138 | { |
126 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT | 139 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT |
@@ -132,16 +145,8 @@ void __init time_init(void) | |||
132 | ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL; | 145 | ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL; |
133 | #endif | 146 | #endif |
134 | clocksource_register_hz(&ccount_clocksource, ccount_freq); | 147 | clocksource_register_hz(&ccount_clocksource, ccount_freq); |
135 | 148 | local_timer_setup(0); | |
136 | ccount_timer.evt.cpumask = cpumask_of(0); | 149 | setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction); |
137 | ccount_timer.evt.irq = irq_create_mapping(NULL, LINUX_TIMER_INT); | ||
138 | if (WARN(!ccount_timer.evt.irq, "error: can't map timer irq")) | ||
139 | return; | ||
140 | clockevents_config_and_register(&ccount_timer.evt, ccount_freq, 0xf, | ||
141 | 0xffffffff); | ||
142 | setup_irq(ccount_timer.evt.irq, &timer_irqaction); | ||
143 | ccount_timer.irq_enabled = 1; | ||
144 | |||
145 | setup_sched_clock(ccount_sched_clock_read, 32, ccount_freq); | 150 | setup_sched_clock(ccount_sched_clock_read, 32, ccount_freq); |
146 | } | 151 | } |
147 | 152 | ||
@@ -149,10 +154,9 @@ void __init time_init(void) | |||
149 | * The timer interrupt is called HZ times per second. | 154 | * The timer interrupt is called HZ times per second. |
150 | */ | 155 | */ |
151 | 156 | ||
152 | irqreturn_t timer_interrupt (int irq, void *dev_id) | 157 | irqreturn_t timer_interrupt(int irq, void *dev_id) |
153 | { | 158 | { |
154 | struct ccount_timer_t *timer = dev_id; | 159 | struct clock_event_device *evt = &this_cpu_ptr(&ccount_timer)->evt; |
155 | struct clock_event_device *evt = &timer->evt; | ||
156 | 160 | ||
157 | evt->event_handler(evt); | 161 | evt->event_handler(evt); |
158 | 162 | ||