aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/clockevents.c88
-rw-r--r--kernel/time/timer_list.c32
2 files changed, 115 insertions, 5 deletions
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 55449909f114..489642b08d64 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -94,6 +94,57 @@ u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
94} 94}
95EXPORT_SYMBOL_GPL(clockevent_delta2ns); 95EXPORT_SYMBOL_GPL(clockevent_delta2ns);
96 96
97static int __clockevents_set_mode(struct clock_event_device *dev,
98 enum clock_event_mode mode)
99{
100 /* Transition with legacy set_mode() callback */
101 if (dev->set_mode) {
102 /* Legacy callback doesn't support new modes */
103 if (mode > CLOCK_EVT_MODE_RESUME)
104 return -ENOSYS;
105 dev->set_mode(mode, dev);
106 return 0;
107 }
108
109 if (dev->features & CLOCK_EVT_FEAT_DUMMY)
110 return 0;
111
112 /* Transition with new mode-specific callbacks */
113 switch (mode) {
114 case CLOCK_EVT_MODE_UNUSED:
115 /*
116 * This is an internal state, which is guaranteed to go from
117 * SHUTDOWN to UNUSED. No driver interaction required.
118 */
119 return 0;
120
121 case CLOCK_EVT_MODE_SHUTDOWN:
122 return dev->set_mode_shutdown(dev);
123
124 case CLOCK_EVT_MODE_PERIODIC:
125 /* Core internal bug */
126 if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC))
127 return -ENOSYS;
128 return dev->set_mode_periodic(dev);
129
130 case CLOCK_EVT_MODE_ONESHOT:
131 /* Core internal bug */
132 if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
133 return -ENOSYS;
134 return dev->set_mode_oneshot(dev);
135
136 case CLOCK_EVT_MODE_RESUME:
137 /* Optional callback */
138 if (dev->set_mode_resume)
139 return dev->set_mode_resume(dev);
140 else
141 return 0;
142
143 default:
144 return -ENOSYS;
145 }
146}
147
97/** 148/**
98 * clockevents_set_mode - set the operating mode of a clock event device 149 * clockevents_set_mode - set the operating mode of a clock event device
99 * @dev: device to modify 150 * @dev: device to modify
@@ -105,7 +156,9 @@ void clockevents_set_mode(struct clock_event_device *dev,
105 enum clock_event_mode mode) 156 enum clock_event_mode mode)
106{ 157{
107 if (dev->mode != mode) { 158 if (dev->mode != mode) {
108 dev->set_mode(mode, dev); 159 if (__clockevents_set_mode(dev, mode))
160 return;
161
109 dev->mode = mode; 162 dev->mode = mode;
110 163
111 /* 164 /*
@@ -373,6 +426,35 @@ int clockevents_unbind_device(struct clock_event_device *ced, int cpu)
373} 426}
374EXPORT_SYMBOL_GPL(clockevents_unbind); 427EXPORT_SYMBOL_GPL(clockevents_unbind);
375 428
429/* Sanity check of mode transition callbacks */
430static int clockevents_sanity_check(struct clock_event_device *dev)
431{
432 /* Legacy set_mode() callback */
433 if (dev->set_mode) {
434 /* We shouldn't be supporting new modes now */
435 WARN_ON(dev->set_mode_periodic || dev->set_mode_oneshot ||
436 dev->set_mode_shutdown || dev->set_mode_resume);
437 return 0;
438 }
439
440 if (dev->features & CLOCK_EVT_FEAT_DUMMY)
441 return 0;
442
443 /* New mode-specific callbacks */
444 if (!dev->set_mode_shutdown)
445 return -EINVAL;
446
447 if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
448 !dev->set_mode_periodic)
449 return -EINVAL;
450
451 if ((dev->features & CLOCK_EVT_FEAT_ONESHOT) &&
452 !dev->set_mode_oneshot)
453 return -EINVAL;
454
455 return 0;
456}
457
376/** 458/**
377 * clockevents_register_device - register a clock event device 459 * clockevents_register_device - register a clock event device
378 * @dev: device to register 460 * @dev: device to register
@@ -382,6 +464,8 @@ void clockevents_register_device(struct clock_event_device *dev)
382 unsigned long flags; 464 unsigned long flags;
383 465
384 BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED); 466 BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
467 BUG_ON(clockevents_sanity_check(dev));
468
385 if (!dev->cpumask) { 469 if (!dev->cpumask) {
386 WARN_ON(num_possible_cpus() > 1); 470 WARN_ON(num_possible_cpus() > 1);
387 dev->cpumask = cpumask_of(smp_processor_id()); 471 dev->cpumask = cpumask_of(smp_processor_id());
@@ -449,7 +533,7 @@ int __clockevents_update_freq(struct clock_event_device *dev, u32 freq)
449 return clockevents_program_event(dev, dev->next_event, false); 533 return clockevents_program_event(dev, dev->next_event, false);
450 534
451 if (dev->mode == CLOCK_EVT_MODE_PERIODIC) 535 if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
452 dev->set_mode(CLOCK_EVT_MODE_PERIODIC, dev); 536 return __clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
453 537
454 return 0; 538 return 0;
455} 539}
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 61ed862cdd37..2cfd19485824 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -228,9 +228,35 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
228 print_name_offset(m, dev->set_next_event); 228 print_name_offset(m, dev->set_next_event);
229 SEQ_printf(m, "\n"); 229 SEQ_printf(m, "\n");
230 230
231 SEQ_printf(m, " set_mode: "); 231 if (dev->set_mode) {
232 print_name_offset(m, dev->set_mode); 232 SEQ_printf(m, " set_mode: ");
233 SEQ_printf(m, "\n"); 233 print_name_offset(m, dev->set_mode);
234 SEQ_printf(m, "\n");
235 } else {
236 if (dev->set_mode_shutdown) {
237 SEQ_printf(m, " shutdown: ");
238 print_name_offset(m, dev->set_mode_shutdown);
239 SEQ_printf(m, "\n");
240 }
241
242 if (dev->set_mode_periodic) {
243 SEQ_printf(m, " periodic: ");
244 print_name_offset(m, dev->set_mode_periodic);
245 SEQ_printf(m, "\n");
246 }
247
248 if (dev->set_mode_oneshot) {
249 SEQ_printf(m, " oneshot: ");
250 print_name_offset(m, dev->set_mode_oneshot);
251 SEQ_printf(m, "\n");
252 }
253
254 if (dev->set_mode_resume) {
255 SEQ_printf(m, " resume: ");
256 print_name_offset(m, dev->set_mode_resume);
257 SEQ_printf(m, "\n");
258 }
259 }
234 260
235 SEQ_printf(m, " event_handler: "); 261 SEQ_printf(m, " event_handler: ");
236 print_name_offset(m, dev->event_handler); 262 print_name_offset(m, dev->event_handler);