diff options
| -rw-r--r-- | arch/x86/kernel/hpet.c | 19 | ||||
| -rw-r--r-- | drivers/clocksource/acpi_pm.c | 54 | ||||
| -rw-r--r-- | include/linux/clockchips.h | 2 | ||||
| -rw-r--r-- | kernel/time/clockevents.c | 3 | ||||
| -rw-r--r-- | kernel/time/ntp.c | 2 | ||||
| -rw-r--r-- | kernel/time/tick-broadcast.c | 78 | ||||
| -rw-r--r-- | kernel/time/tick-common.c | 1 | ||||
| -rw-r--r-- | kernel/time/tick-internal.h | 2 | ||||
| -rw-r--r-- | kernel/time/tick-oneshot.c | 46 |
9 files changed, 151 insertions, 56 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 59fd3b6b1303..73deaffadd03 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
| @@ -210,8 +210,8 @@ static void hpet_legacy_clockevent_register(void) | |||
| 210 | /* Calculate the min / max delta */ | 210 | /* Calculate the min / max delta */ |
| 211 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | 211 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, |
| 212 | &hpet_clockevent); | 212 | &hpet_clockevent); |
| 213 | hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, | 213 | /* 5 usec minimum reprogramming delta. */ |
| 214 | &hpet_clockevent); | 214 | hpet_clockevent.min_delta_ns = 5000; |
| 215 | 215 | ||
| 216 | /* | 216 | /* |
| 217 | * Start hpet with the boot cpu mask and make it | 217 | * Start hpet with the boot cpu mask and make it |
| @@ -270,15 +270,22 @@ static void hpet_legacy_set_mode(enum clock_event_mode mode, | |||
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | static int hpet_legacy_next_event(unsigned long delta, | 272 | static int hpet_legacy_next_event(unsigned long delta, |
| 273 | struct clock_event_device *evt) | 273 | struct clock_event_device *evt) |
| 274 | { | 274 | { |
| 275 | unsigned long cnt; | 275 | u32 cnt; |
| 276 | 276 | ||
| 277 | cnt = hpet_readl(HPET_COUNTER); | 277 | cnt = hpet_readl(HPET_COUNTER); |
| 278 | cnt += delta; | 278 | cnt += (u32) delta; |
| 279 | hpet_writel(cnt, HPET_T0_CMP); | 279 | hpet_writel(cnt, HPET_T0_CMP); |
| 280 | 280 | ||
| 281 | return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0; | 281 | /* |
| 282 | * We need to read back the CMP register to make sure that | ||
| 283 | * what we wrote hit the chip before we compare it to the | ||
| 284 | * counter. | ||
| 285 | */ | ||
| 286 | WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt); | ||
| 287 | |||
| 288 | return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; | ||
| 282 | } | 289 | } |
| 283 | 290 | ||
| 284 | /* | 291 | /* |
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 5ca1d80de182..4eee533f3f4a 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
| 22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
| 24 | #include <linux/delay.h> | ||
| 24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
| 25 | 26 | ||
| 26 | /* | 27 | /* |
| @@ -151,13 +152,13 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, | |||
| 151 | */ | 152 | */ |
| 152 | static int verify_pmtmr_rate(void) | 153 | static int verify_pmtmr_rate(void) |
| 153 | { | 154 | { |
| 154 | u32 value1, value2; | 155 | cycle_t value1, value2; |
| 155 | unsigned long count, delta; | 156 | unsigned long count, delta; |
| 156 | 157 | ||
| 157 | mach_prepare_counter(); | 158 | mach_prepare_counter(); |
| 158 | value1 = read_pmtmr(); | 159 | value1 = clocksource_acpi_pm.read(); |
| 159 | mach_countup(&count); | 160 | mach_countup(&count); |
| 160 | value2 = read_pmtmr(); | 161 | value2 = clocksource_acpi_pm.read(); |
| 161 | delta = (value2 - value1) & ACPI_PM_MASK; | 162 | delta = (value2 - value1) & ACPI_PM_MASK; |
| 162 | 163 | ||
| 163 | /* Check that the PMTMR delta is within 5% of what we expect */ | 164 | /* Check that the PMTMR delta is within 5% of what we expect */ |
| @@ -175,10 +176,13 @@ static int verify_pmtmr_rate(void) | |||
| 175 | #define verify_pmtmr_rate() (0) | 176 | #define verify_pmtmr_rate() (0) |
| 176 | #endif | 177 | #endif |
| 177 | 178 | ||
| 179 | /* Number of monotonicity checks to perform during initialization */ | ||
| 180 | #define ACPI_PM_MONOTONICITY_CHECKS 10 | ||
| 181 | |||
| 178 | static int __init init_acpi_pm_clocksource(void) | 182 | static int __init init_acpi_pm_clocksource(void) |
| 179 | { | 183 | { |
| 180 | u32 value1, value2; | 184 | cycle_t value1, value2; |
| 181 | unsigned int i; | 185 | unsigned int i, j, good = 0; |
| 182 | 186 | ||
| 183 | if (!pmtmr_ioport) | 187 | if (!pmtmr_ioport) |
| 184 | return -ENODEV; | 188 | return -ENODEV; |
| @@ -187,24 +191,32 @@ static int __init init_acpi_pm_clocksource(void) | |||
| 187 | clocksource_acpi_pm.shift); | 191 | clocksource_acpi_pm.shift); |
| 188 | 192 | ||
| 189 | /* "verify" this timing source: */ | 193 | /* "verify" this timing source: */ |
| 190 | value1 = read_pmtmr(); | 194 | for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { |
| 191 | for (i = 0; i < 10000; i++) { | 195 | value1 = clocksource_acpi_pm.read(); |
| 192 | value2 = read_pmtmr(); | 196 | for (i = 0; i < 10000; i++) { |
| 193 | if (value2 == value1) | 197 | value2 = clocksource_acpi_pm.read(); |
| 194 | continue; | 198 | if (value2 == value1) |
| 195 | if (value2 > value1) | 199 | continue; |
| 196 | goto pm_good; | 200 | if (value2 > value1) |
| 197 | if ((value2 < value1) && ((value2) < 0xFFF)) | 201 | good++; |
| 198 | goto pm_good; | 202 | break; |
| 199 | printk(KERN_INFO "PM-Timer had inconsistent results:" | 203 | if ((value2 < value1) && ((value2) < 0xFFF)) |
| 200 | " 0x%#x, 0x%#x - aborting.\n", value1, value2); | 204 | good++; |
| 201 | return -EINVAL; | 205 | break; |
| 206 | printk(KERN_INFO "PM-Timer had inconsistent results:" | ||
| 207 | " 0x%#llx, 0x%#llx - aborting.\n", | ||
| 208 | value1, value2); | ||
| 209 | return -EINVAL; | ||
| 210 | } | ||
| 211 | udelay(300 * i); | ||
| 212 | } | ||
| 213 | |||
| 214 | if (good != ACPI_PM_MONOTONICITY_CHECKS) { | ||
| 215 | printk(KERN_INFO "PM-Timer failed consistency check " | ||
| 216 | " (0x%#llx) - aborting.\n", value1); | ||
| 217 | return -ENODEV; | ||
| 202 | } | 218 | } |
| 203 | printk(KERN_INFO "PM-Timer had no reasonable result:" | ||
| 204 | " 0x%#x - aborting.\n", value1); | ||
| 205 | return -ENODEV; | ||
| 206 | 219 | ||
| 207 | pm_good: | ||
| 208 | if (verify_pmtmr_rate() != 0) | 220 | if (verify_pmtmr_rate() != 0) |
| 209 | return -ENODEV; | 221 | return -ENODEV; |
| 210 | 222 | ||
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index c33b0dc28e4d..ed3a5d473e52 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
| @@ -127,6 +127,8 @@ extern int clockevents_register_notifier(struct notifier_block *nb); | |||
| 127 | extern int clockevents_program_event(struct clock_event_device *dev, | 127 | extern int clockevents_program_event(struct clock_event_device *dev, |
| 128 | ktime_t expires, ktime_t now); | 128 | ktime_t expires, ktime_t now); |
| 129 | 129 | ||
| 130 | extern void clockevents_handle_noop(struct clock_event_device *dev); | ||
| 131 | |||
| 130 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 132 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
| 131 | extern void clockevents_notify(unsigned long reason, void *arg); | 133 | extern void clockevents_notify(unsigned long reason, void *arg); |
| 132 | #else | 134 | #else |
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 3d1e3e1a1971..1876b526c778 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c | |||
| @@ -177,7 +177,7 @@ void clockevents_register_device(struct clock_event_device *dev) | |||
| 177 | /* | 177 | /* |
| 178 | * Noop handler when we shut down an event device | 178 | * Noop handler when we shut down an event device |
| 179 | */ | 179 | */ |
| 180 | static void clockevents_handle_noop(struct clock_event_device *dev) | 180 | void clockevents_handle_noop(struct clock_event_device *dev) |
| 181 | { | 181 | { |
| 182 | } | 182 | } |
| 183 | 183 | ||
| @@ -199,7 +199,6 @@ void clockevents_exchange_device(struct clock_event_device *old, | |||
| 199 | * released list and do a notify add later. | 199 | * released list and do a notify add later. |
| 200 | */ | 200 | */ |
| 201 | if (old) { | 201 | if (old) { |
| 202 | old->event_handler = clockevents_handle_noop; | ||
| 203 | clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); | 202 | clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); |
| 204 | list_del(&old->list); | 203 | list_del(&old->list); |
| 205 | list_add(&old->list, &clockevents_released); | 204 | list_add(&old->list, &clockevents_released); |
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 5125ddd8196b..1ad46f3df6e7 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
| @@ -245,7 +245,7 @@ static void sync_cmos_clock(unsigned long dummy) | |||
| 245 | if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) | 245 | if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) |
| 246 | fail = update_persistent_clock(now); | 246 | fail = update_persistent_clock(now); |
| 247 | 247 | ||
| 248 | next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec; | 248 | next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); |
| 249 | if (next.tv_nsec <= 0) | 249 | if (next.tv_nsec <= 0) |
| 250 | next.tv_nsec += NSEC_PER_SEC; | 250 | next.tv_nsec += NSEC_PER_SEC; |
| 251 | 251 | ||
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 31463d370b94..2f5a38294bf9 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
| @@ -175,6 +175,8 @@ static void tick_do_periodic_broadcast(void) | |||
| 175 | */ | 175 | */ |
| 176 | static void tick_handle_periodic_broadcast(struct clock_event_device *dev) | 176 | static void tick_handle_periodic_broadcast(struct clock_event_device *dev) |
| 177 | { | 177 | { |
| 178 | ktime_t next; | ||
| 179 | |||
| 178 | tick_do_periodic_broadcast(); | 180 | tick_do_periodic_broadcast(); |
| 179 | 181 | ||
| 180 | /* | 182 | /* |
| @@ -185,10 +187,13 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev) | |||
| 185 | 187 | ||
| 186 | /* | 188 | /* |
| 187 | * Setup the next period for devices, which do not have | 189 | * Setup the next period for devices, which do not have |
| 188 | * periodic mode: | 190 | * periodic mode. We read dev->next_event first and add to it |
| 191 | * when the event alrady expired. clockevents_program_event() | ||
| 192 | * sets dev->next_event only when the event is really | ||
| 193 | * programmed to the device. | ||
| 189 | */ | 194 | */ |
| 190 | for (;;) { | 195 | for (next = dev->next_event; ;) { |
| 191 | ktime_t next = ktime_add(dev->next_event, tick_period); | 196 | next = ktime_add(next, tick_period); |
| 192 | 197 | ||
| 193 | if (!clockevents_program_event(dev, next, ktime_get())) | 198 | if (!clockevents_program_event(dev, next, ktime_get())) |
| 194 | return; | 199 | return; |
| @@ -205,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why) | |||
| 205 | struct clock_event_device *bc, *dev; | 210 | struct clock_event_device *bc, *dev; |
| 206 | struct tick_device *td; | 211 | struct tick_device *td; |
| 207 | unsigned long flags, *reason = why; | 212 | unsigned long flags, *reason = why; |
| 208 | int cpu; | 213 | int cpu, bc_stopped; |
| 209 | 214 | ||
| 210 | spin_lock_irqsave(&tick_broadcast_lock, flags); | 215 | spin_lock_irqsave(&tick_broadcast_lock, flags); |
| 211 | 216 | ||
| @@ -223,6 +228,8 @@ static void tick_do_broadcast_on_off(void *why) | |||
| 223 | if (!tick_device_is_functional(dev)) | 228 | if (!tick_device_is_functional(dev)) |
| 224 | goto out; | 229 | goto out; |
| 225 | 230 | ||
| 231 | bc_stopped = cpus_empty(tick_broadcast_mask); | ||
| 232 | |||
| 226 | switch (*reason) { | 233 | switch (*reason) { |
| 227 | case CLOCK_EVT_NOTIFY_BROADCAST_ON: | 234 | case CLOCK_EVT_NOTIFY_BROADCAST_ON: |
| 228 | case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: | 235 | case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: |
| @@ -245,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why) | |||
| 245 | break; | 252 | break; |
| 246 | } | 253 | } |
| 247 | 254 | ||
| 248 | if (cpus_empty(tick_broadcast_mask)) | 255 | if (cpus_empty(tick_broadcast_mask)) { |
| 249 | clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); | 256 | if (!bc_stopped) |
| 250 | else { | 257 | clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); |
| 258 | } else if (bc_stopped) { | ||
| 251 | if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) | 259 | if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) |
| 252 | tick_broadcast_start_periodic(bc); | 260 | tick_broadcast_start_periodic(bc); |
| 253 | else | 261 | else |
| @@ -364,16 +372,8 @@ cpumask_t *tick_get_broadcast_oneshot_mask(void) | |||
| 364 | static int tick_broadcast_set_event(ktime_t expires, int force) | 372 | static int tick_broadcast_set_event(ktime_t expires, int force) |
| 365 | { | 373 | { |
| 366 | struct clock_event_device *bc = tick_broadcast_device.evtdev; | 374 | struct clock_event_device *bc = tick_broadcast_device.evtdev; |
| 367 | ktime_t now = ktime_get(); | 375 | |
| 368 | int res; | 376 | return tick_dev_program_event(bc, expires, force); |
| 369 | |||
| 370 | for(;;) { | ||
| 371 | res = clockevents_program_event(bc, expires, now); | ||
| 372 | if (!res || !force) | ||
| 373 | return res; | ||
| 374 | now = ktime_get(); | ||
| 375 | expires = ktime_add(now, ktime_set(0, bc->min_delta_ns)); | ||
| 376 | } | ||
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | int tick_resume_broadcast_oneshot(struct clock_event_device *bc) | 379 | int tick_resume_broadcast_oneshot(struct clock_event_device *bc) |
| @@ -491,14 +491,52 @@ static void tick_broadcast_clear_oneshot(int cpu) | |||
| 491 | cpu_clear(cpu, tick_broadcast_oneshot_mask); | 491 | cpu_clear(cpu, tick_broadcast_oneshot_mask); |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires) | ||
| 495 | { | ||
| 496 | struct tick_device *td; | ||
| 497 | int cpu; | ||
| 498 | |||
| 499 | for_each_cpu_mask_nr(cpu, *mask) { | ||
| 500 | td = &per_cpu(tick_cpu_device, cpu); | ||
| 501 | if (td->evtdev) | ||
| 502 | td->evtdev->next_event = expires; | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 494 | /** | 506 | /** |
| 495 | * tick_broadcast_setup_oneshot - setup the broadcast device | 507 | * tick_broadcast_setup_oneshot - setup the broadcast device |
| 496 | */ | 508 | */ |
| 497 | void tick_broadcast_setup_oneshot(struct clock_event_device *bc) | 509 | void tick_broadcast_setup_oneshot(struct clock_event_device *bc) |
| 498 | { | 510 | { |
| 499 | bc->event_handler = tick_handle_oneshot_broadcast; | 511 | /* Set it up only once ! */ |
| 500 | clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); | 512 | if (bc->event_handler != tick_handle_oneshot_broadcast) { |
| 501 | bc->next_event.tv64 = KTIME_MAX; | 513 | int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC; |
| 514 | int cpu = smp_processor_id(); | ||
| 515 | cpumask_t mask; | ||
| 516 | |||
| 517 | bc->event_handler = tick_handle_oneshot_broadcast; | ||
| 518 | clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); | ||
| 519 | |||
| 520 | /* Take the do_timer update */ | ||
| 521 | tick_do_timer_cpu = cpu; | ||
| 522 | |||
| 523 | /* | ||
| 524 | * We must be careful here. There might be other CPUs | ||
| 525 | * waiting for periodic broadcast. We need to set the | ||
| 526 | * oneshot_mask bits for those and program the | ||
| 527 | * broadcast device to fire. | ||
| 528 | */ | ||
| 529 | mask = tick_broadcast_mask; | ||
| 530 | cpu_clear(cpu, mask); | ||
| 531 | cpus_or(tick_broadcast_oneshot_mask, | ||
| 532 | tick_broadcast_oneshot_mask, mask); | ||
| 533 | |||
| 534 | if (was_periodic && !cpus_empty(mask)) { | ||
| 535 | tick_broadcast_init_next_event(&mask, tick_next_period); | ||
| 536 | tick_broadcast_set_event(tick_next_period, 1); | ||
| 537 | } else | ||
| 538 | bc->next_event.tv64 = KTIME_MAX; | ||
| 539 | } | ||
| 502 | } | 540 | } |
| 503 | 541 | ||
| 504 | /* | 542 | /* |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 80c4336f4188..c4777193d567 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
| @@ -161,6 +161,7 @@ static void tick_setup_device(struct tick_device *td, | |||
| 161 | } else { | 161 | } else { |
| 162 | handler = td->evtdev->event_handler; | 162 | handler = td->evtdev->event_handler; |
| 163 | next_event = td->evtdev->next_event; | 163 | next_event = td->evtdev->next_event; |
| 164 | td->evtdev->event_handler = clockevents_handle_noop; | ||
| 164 | } | 165 | } |
| 165 | 166 | ||
| 166 | td->evtdev = newdev; | 167 | td->evtdev = newdev; |
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index f13f2b7f4fd4..0ffc2918ea6f 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h | |||
| @@ -17,6 +17,8 @@ extern void tick_handle_periodic(struct clock_event_device *dev); | |||
| 17 | extern void tick_setup_oneshot(struct clock_event_device *newdev, | 17 | extern void tick_setup_oneshot(struct clock_event_device *newdev, |
| 18 | void (*handler)(struct clock_event_device *), | 18 | void (*handler)(struct clock_event_device *), |
| 19 | ktime_t nextevt); | 19 | ktime_t nextevt); |
| 20 | extern int tick_dev_program_event(struct clock_event_device *dev, | ||
| 21 | ktime_t expires, int force); | ||
| 20 | extern int tick_program_event(ktime_t expires, int force); | 22 | extern int tick_program_event(ktime_t expires, int force); |
| 21 | extern void tick_oneshot_notify(void); | 23 | extern void tick_oneshot_notify(void); |
| 22 | extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); | 24 | extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); |
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 450c04935b66..2e35501e61dd 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c | |||
| @@ -23,24 +23,58 @@ | |||
| 23 | #include "tick-internal.h" | 23 | #include "tick-internal.h" |
| 24 | 24 | ||
| 25 | /** | 25 | /** |
| 26 | * tick_program_event | 26 | * tick_program_event internal worker function |
| 27 | */ | 27 | */ |
| 28 | int tick_program_event(ktime_t expires, int force) | 28 | int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, |
| 29 | int force) | ||
| 29 | { | 30 | { |
| 30 | struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; | ||
| 31 | ktime_t now = ktime_get(); | 31 | ktime_t now = ktime_get(); |
| 32 | int i; | ||
| 32 | 33 | ||
| 33 | while (1) { | 34 | for (i = 0;;) { |
| 34 | int ret = clockevents_program_event(dev, expires, now); | 35 | int ret = clockevents_program_event(dev, expires, now); |
| 35 | 36 | ||
| 36 | if (!ret || !force) | 37 | if (!ret || !force) |
| 37 | return ret; | 38 | return ret; |
| 39 | |||
| 40 | /* | ||
| 41 | * We tried 2 times to program the device with the given | ||
| 42 | * min_delta_ns. If that's not working then we double it | ||
| 43 | * and emit a warning. | ||
| 44 | */ | ||
| 45 | if (++i > 2) { | ||
| 46 | printk(KERN_WARNING "CE: __tick_program_event of %s is " | ||
| 47 | "stuck %llx %llx\n", dev->name ? dev->name : "?", | ||
| 48 | now.tv64, expires.tv64); | ||
| 49 | printk(KERN_WARNING | ||
| 50 | "CE: increasing min_delta_ns %ld to %ld nsec\n", | ||
| 51 | dev->min_delta_ns, dev->min_delta_ns << 1); | ||
| 52 | WARN_ON(1); | ||
| 53 | |||
| 54 | /* Double the min. delta and try again */ | ||
| 55 | if (!dev->min_delta_ns) | ||
| 56 | dev->min_delta_ns = 5000; | ||
| 57 | else | ||
| 58 | dev->min_delta_ns <<= 1; | ||
| 59 | i = 0; | ||
| 60 | } | ||
| 61 | |||
| 38 | now = ktime_get(); | 62 | now = ktime_get(); |
| 39 | expires = ktime_add(now, ktime_set(0, dev->min_delta_ns)); | 63 | expires = ktime_add_ns(now, dev->min_delta_ns); |
| 40 | } | 64 | } |
| 41 | } | 65 | } |
| 42 | 66 | ||
| 43 | /** | 67 | /** |
| 68 | * tick_program_event | ||
| 69 | */ | ||
| 70 | int tick_program_event(ktime_t expires, int force) | ||
| 71 | { | ||
| 72 | struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; | ||
| 73 | |||
| 74 | return tick_dev_program_event(dev, expires, force); | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 44 | * tick_resume_onshot - resume oneshot mode | 78 | * tick_resume_onshot - resume oneshot mode |
| 45 | */ | 79 | */ |
| 46 | void tick_resume_oneshot(void) | 80 | void tick_resume_oneshot(void) |
| @@ -61,7 +95,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev, | |||
| 61 | { | 95 | { |
| 62 | newdev->event_handler = handler; | 96 | newdev->event_handler = handler; |
| 63 | clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); | 97 | clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); |
| 64 | clockevents_program_event(newdev, next_event, ktime_get()); | 98 | tick_dev_program_event(newdev, next_event, 1); |
| 65 | } | 99 | } |
| 66 | 100 | ||
| 67 | /** | 101 | /** |
