From 2acb947274b7e0b03cb2023587acd1c5f7ceee31 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 1 Oct 2008 17:33:17 -0700 Subject: [PATCH] timer fixes for .26 --- queue-2.6.26/series | 11 +++ queue-2.6.26/timer-fix-01.patch | 84 +++++++++++++++++++++ queue-2.6.26/timer-fix-02.patch | 52 +++++++++++++ queue-2.6.26/timer-fix-03.patch | 67 +++++++++++++++++ queue-2.6.26/timer-fix-04.patch | 74 ++++++++++++++++++ queue-2.6.26/timer-fix-05.patch | 129 ++++++++++++++++++++++++++++++++ queue-2.6.26/timer-fix-06.patch | 40 ++++++++++ queue-2.6.26/timer-fix-07.patch | 76 +++++++++++++++++++ queue-2.6.26/timer-fix-08.patch | 54 +++++++++++++ queue-2.6.26/timer-fix-09.patch | 38 ++++++++++ queue-2.6.26/timer-fix-10.patch | 57 ++++++++++++++ queue-2.6.26/timer-fix-11.patch | 57 ++++++++++++++ 12 files changed, 739 insertions(+) create mode 100644 queue-2.6.26/timer-fix-01.patch create mode 100644 queue-2.6.26/timer-fix-02.patch create mode 100644 queue-2.6.26/timer-fix-03.patch create mode 100644 queue-2.6.26/timer-fix-04.patch create mode 100644 queue-2.6.26/timer-fix-05.patch create mode 100644 queue-2.6.26/timer-fix-06.patch create mode 100644 queue-2.6.26/timer-fix-07.patch create mode 100644 queue-2.6.26/timer-fix-08.patch create mode 100644 queue-2.6.26/timer-fix-09.patch create mode 100644 queue-2.6.26/timer-fix-10.patch create mode 100644 queue-2.6.26/timer-fix-11.patch diff --git a/queue-2.6.26/series b/queue-2.6.26/series index bd4f093edac..41c7c28a807 100644 --- a/queue-2.6.26/series +++ b/queue-2.6.26/series @@ -37,3 +37,14 @@ x86-fix-smp-alternatives-use-mutex-instead-of-spinlock-text_poke-is-sleepable.pa acpi-avoid-bogus-ec-timeout-when-ec-is-in-polling-mode.patch x86-add-io-delay-quirk-for-presario-f700.patch x86-fix-memmap-exactmap-boot-argument.patch +timer-fix-01.patch +timer-fix-02.patch +timer-fix-03.patch +timer-fix-04.patch +timer-fix-05.patch +timer-fix-06.patch +timer-fix-07.patch +timer-fix-08.patch +timer-fix-09.patch +timer-fix-10.patch +timer-fix-11.patch diff --git a/queue-2.6.26/timer-fix-01.patch b/queue-2.6.26/timer-fix-01.patch new file mode 100644 index 00000000000..38290b0e176 --- /dev/null +++ b/queue-2.6.26/timer-fix-01.patch @@ -0,0 +1,84 @@ +From 7c1e76897492d92b6a1c2d6892494d39ded9680c Mon Sep 17 00:00:00 2001 +From: Venkatesh Pallipadi +Date: Wed, 3 Sep 2008 21:36:50 +0000 +Subject: clockevents: prevent clockevent event_handler ending up handler_noop + +From: Venkatesh Pallipadi + +commit 7c1e76897492d92b6a1c2d6892494d39ded9680c upstream + +There is a ordering related problem with clockevents code, due to which +clockevents_register_device() called after tickless/highres switch +will not work. The new clockevent ends up with clockevents_handle_noop as +event handler, resulting in no timer activity. + +The problematic path seems to be + +* old device already has hrtimer_interrupt as the event_handler +* new clockevent device registers with a higher rating +* tick_check_new_device() is called + * clockevents_exchange_device() gets called + * old->event_handler is set to clockevents_handle_noop + * tick_setup_device() is called for the new device + * which sets new->event_handler using the old->event_handler which is noop. + +Change the ordering so that new device inherits the proper handler. + +This does not have any issue in normal case as most likely all the clockevent +devices are setup before the highres switch. But, can potentially be affecting +some corner case where HPET force detect happens after the highres switch. +This was a problem with HPET in MSI mode code that we have been experimenting +with. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Shaohua Li +Signed-off-by: Thomas Gleixner +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/clockchips.h | 2 ++ + kernel/time/clockevents.c | 3 +-- + kernel/time/tick-common.c | 1 + + 3 files changed, 4 insertions(+), 2 deletions(-) + +--- a/include/linux/clockchips.h ++++ b/include/linux/clockchips.h +@@ -127,6 +127,8 @@ extern int clockevents_register_notifier + extern int clockevents_program_event(struct clock_event_device *dev, + ktime_t expires, ktime_t now); + ++extern void clockevents_handle_noop(struct clock_event_device *dev); ++ + #ifdef CONFIG_GENERIC_CLOCKEVENTS + extern void clockevents_notify(unsigned long reason, void *arg); + #else +--- a/kernel/time/clockevents.c ++++ b/kernel/time/clockevents.c +@@ -177,7 +177,7 @@ void clockevents_register_device(struct + /* + * Noop handler when we shut down an event device + */ +-static void clockevents_handle_noop(struct clock_event_device *dev) ++void clockevents_handle_noop(struct clock_event_device *dev) + { + } + +@@ -199,7 +199,6 @@ void clockevents_exchange_device(struct + * released list and do a notify add later. + */ + if (old) { +- old->event_handler = clockevents_handle_noop; + clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); + list_del(&old->list); + list_add(&old->list, &clockevents_released); +--- a/kernel/time/tick-common.c ++++ b/kernel/time/tick-common.c +@@ -161,6 +161,7 @@ static void tick_setup_device(struct tic + } else { + handler = td->evtdev->event_handler; + next_event = td->evtdev->next_event; ++ td->evtdev->event_handler = clockevents_handle_noop; + } + + td->evtdev = newdev; diff --git a/queue-2.6.26/timer-fix-02.patch b/queue-2.6.26/timer-fix-02.patch new file mode 100644 index 00000000000..316d4bf4a0e --- /dev/null +++ b/queue-2.6.26/timer-fix-02.patch @@ -0,0 +1,52 @@ +From d4496b39559c6d43f83e4c08b899984f8b8089b5 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Wed, 3 Sep 2008 21:36:57 +0000 +Subject: clockevents: prevent endless loop in periodic broadcast handler + +From: Thomas Gleixner + +commit d4496b39559c6d43f83e4c08b899984f8b8089b5 upstream + +The reprogramming of the periodic broadcast handler was broken, +when the first programming returned -ETIME. The clockevents code +stores the new expiry value in the clock events device next_event field +only when the programming time has not been elapsed yet. The loop in +question calculates the new expiry value from the next_event value +and therefor never increases. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/tick-broadcast.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/kernel/time/tick-broadcast.c ++++ b/kernel/time/tick-broadcast.c +@@ -174,6 +174,8 @@ static void tick_do_periodic_broadcast(v + */ + static void tick_handle_periodic_broadcast(struct clock_event_device *dev) + { ++ ktime_t next; ++ + tick_do_periodic_broadcast(); + + /* +@@ -184,10 +186,13 @@ static void tick_handle_periodic_broadca + + /* + * Setup the next period for devices, which do not have +- * periodic mode: ++ * periodic mode. We read dev->next_event first and add to it ++ * when the event alrady expired. clockevents_program_event() ++ * sets dev->next_event only when the event is really ++ * programmed to the device. + */ +- for (;;) { +- ktime_t next = ktime_add(dev->next_event, tick_period); ++ for (next = dev->next_event; ;) { ++ next = ktime_add(next, tick_period); + + if (!clockevents_program_event(dev, next, ktime_get())) + return; diff --git a/queue-2.6.26/timer-fix-03.patch b/queue-2.6.26/timer-fix-03.patch new file mode 100644 index 00000000000..e8d29b72fa3 --- /dev/null +++ b/queue-2.6.26/timer-fix-03.patch @@ -0,0 +1,67 @@ +From 7205656ab48da29a95d7f55e43a81db755d3cb3a Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Wed, 3 Sep 2008 21:37:03 +0000 +Subject: clockevents: enforce reprogram in oneshot setup + +From: Thomas Gleixner + +commit 7205656ab48da29a95d7f55e43a81db755d3cb3a upstream + +In tick_oneshot_setup we program the device to the given next_event, +but we do not check the return value. We need to make sure that the +device is programmed enforced so the interrupt handler engine starts +working. Split out the reprogramming function from tick_program_event() +and call it with the device, which was handed in to tick_setup_oneshot(). +Set the force argument, so the devices is firing an interrupt. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/tick-oneshot.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +--- a/kernel/time/tick-oneshot.c ++++ b/kernel/time/tick-oneshot.c +@@ -23,11 +23,11 @@ + #include "tick-internal.h" + + /** +- * tick_program_event ++ * tick_program_event internal worker function + */ +-int tick_program_event(ktime_t expires, int force) ++static int __tick_program_event(struct clock_event_device *dev, ++ ktime_t expires, int force) + { +- struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + ktime_t now = ktime_get(); + + while (1) { +@@ -41,6 +41,16 @@ int tick_program_event(ktime_t expires, + } + + /** ++ * tick_program_event ++ */ ++int tick_program_event(ktime_t expires, int force) ++{ ++ struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; ++ ++ return __tick_program_event(dev, expires, force); ++} ++ ++/** + * tick_resume_onshot - resume oneshot mode + */ + void tick_resume_oneshot(void) +@@ -61,7 +71,7 @@ void tick_setup_oneshot(struct clock_eve + { + newdev->event_handler = handler; + clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); +- clockevents_program_event(newdev, next_event, ktime_get()); ++ __tick_program_event(newdev, next_event, 1); + } + + /** diff --git a/queue-2.6.26/timer-fix-04.patch b/queue-2.6.26/timer-fix-04.patch new file mode 100644 index 00000000000..994ff0e63ca --- /dev/null +++ b/queue-2.6.26/timer-fix-04.patch @@ -0,0 +1,74 @@ +From 9c17bcda991000351cb2373f78be7e4b1c44caa3 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Wed, 3 Sep 2008 21:37:08 +0000 +Subject: clockevents: prevent multiple init/shutdown + +From: Thomas Gleixner + +commit 9c17bcda991000351cb2373f78be7e4b1c44caa3 upstream + +While chasing the C1E/HPET bugreports I went through the clock events +code inch by inch and found that the broadcast device can be initialized +and shutdown multiple times. Multiple shutdowns are not critical, but +useless waste of time. Multiple initializations are simply broken. Another +CPU might have the device in use already after the first initialization and +the second init could just render it unusable again. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/tick-broadcast.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +--- a/kernel/time/tick-broadcast.c ++++ b/kernel/time/tick-broadcast.c +@@ -209,7 +209,7 @@ static void tick_do_broadcast_on_off(voi + struct clock_event_device *bc, *dev; + struct tick_device *td; + unsigned long flags, *reason = why; +- int cpu; ++ int cpu, bc_stopped; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + +@@ -227,6 +227,8 @@ static void tick_do_broadcast_on_off(voi + if (!tick_device_is_functional(dev)) + goto out; + ++ bc_stopped = cpus_empty(tick_broadcast_mask); ++ + switch (*reason) { + case CLOCK_EVT_NOTIFY_BROADCAST_ON: + case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: +@@ -248,9 +250,10 @@ static void tick_do_broadcast_on_off(voi + break; + } + +- if (cpus_empty(tick_broadcast_mask)) +- clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); +- else { ++ if (cpus_empty(tick_broadcast_mask)) { ++ if (!bc_stopped) ++ clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); ++ } else if (bc_stopped) { + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) + tick_broadcast_start_periodic(bc); + else +@@ -500,9 +503,12 @@ static void tick_broadcast_clear_oneshot + */ + void tick_broadcast_setup_oneshot(struct clock_event_device *bc) + { +- bc->event_handler = tick_handle_oneshot_broadcast; +- clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); +- bc->next_event.tv64 = KTIME_MAX; ++ /* Set it up only once ! */ ++ if (bc->event_handler != tick_handle_oneshot_broadcast) { ++ bc->event_handler = tick_handle_oneshot_broadcast; ++ clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); ++ bc->next_event.tv64 = KTIME_MAX; ++ } + } + + /* diff --git a/queue-2.6.26/timer-fix-05.patch b/queue-2.6.26/timer-fix-05.patch new file mode 100644 index 00000000000..4fc45402033 --- /dev/null +++ b/queue-2.6.26/timer-fix-05.patch @@ -0,0 +1,129 @@ +From 1fb9b7d29d8e85ba3196eaa7ab871bf76fc98d36 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Wed, 3 Sep 2008 21:37:14 +0000 +Subject: [PATCH] clockevents: prevent endless loop lockup + +From: Thomas Gleixner + +commit 1fb9b7d29d8e85ba3196eaa7ab871bf76fc98d36 upstream + +The C1E/HPET bug reports on AMDX2/RS690 systems where tracked down to a +too small value of the HPET minumum delta for programming an event. + +The clockevents code needs to enforce an interrupt event on the clock event +device in some cases. The enforcement code was stupid and naive, as it just +added the minimum delta to the current time and tried to reprogram the device. +When the minimum delta is too small, then this loops forever. + +Add a sanity check. Allow reprogramming to fail 3 times, then print a warning +and double the minimum delta value to make sure, that this does not happen again. +Use the same function for both tick-oneshot and tick-broadcast code. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/tick-broadcast.c | 10 +--------- + kernel/time/tick-internal.h | 2 ++ + kernel/time/tick-oneshot.c | 36 ++++++++++++++++++++++++++++++------ + 3 files changed, 33 insertions(+), 15 deletions(-) + +--- a/kernel/time/tick-broadcast.c ++++ b/kernel/time/tick-broadcast.c +@@ -370,16 +370,8 @@ cpumask_t *tick_get_broadcast_oneshot_ma + static int tick_broadcast_set_event(ktime_t expires, int force) + { + struct clock_event_device *bc = tick_broadcast_device.evtdev; +- ktime_t now = ktime_get(); +- int res; + +- for(;;) { +- res = clockevents_program_event(bc, expires, now); +- if (!res || !force) +- return res; +- now = ktime_get(); +- expires = ktime_add(now, ktime_set(0, bc->min_delta_ns)); +- } ++ return tick_dev_program_event(bc, expires, force); + } + + int tick_resume_broadcast_oneshot(struct clock_event_device *bc) +--- a/kernel/time/tick-internal.h ++++ b/kernel/time/tick-internal.h +@@ -17,6 +17,8 @@ extern void tick_handle_periodic(struct + extern void tick_setup_oneshot(struct clock_event_device *newdev, + void (*handler)(struct clock_event_device *), + ktime_t nextevt); ++extern int tick_dev_program_event(struct clock_event_device *dev, ++ ktime_t expires, int force); + extern int tick_program_event(ktime_t expires, int force); + extern void tick_oneshot_notify(void); + extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); +--- a/kernel/time/tick-oneshot.c ++++ b/kernel/time/tick-oneshot.c +@@ -25,18 +25,42 @@ + /** + * tick_program_event internal worker function + */ +-static int __tick_program_event(struct clock_event_device *dev, +- ktime_t expires, int force) ++int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, ++ int force) + { + ktime_t now = ktime_get(); ++ int i; + +- while (1) { ++ for (i = 0;;) { + int ret = clockevents_program_event(dev, expires, now); + + if (!ret || !force) + return ret; ++ ++ /* ++ * We tried 2 times to program the device with the given ++ * min_delta_ns. If that's not working then we double it ++ * and emit a warning. ++ */ ++ if (++i > 2) { ++ printk(KERN_WARNING "CE: __tick_program_event of %s is " ++ "stuck %llx %llx\n", dev->name ? dev->name : "?", ++ now.tv64, expires.tv64); ++ printk(KERN_WARNING ++ "CE: increasing min_delta_ns %ld to %ld nsec\n", ++ dev->min_delta_ns, dev->min_delta_ns << 1); ++ WARN_ON(1); ++ ++ /* Double the min. delta and try again */ ++ if (!dev->min_delta_ns) ++ dev->min_delta_ns = 5000; ++ else ++ dev->min_delta_ns <<= 1; ++ i = 0; ++ } ++ + now = ktime_get(); +- expires = ktime_add(now, ktime_set(0, dev->min_delta_ns)); ++ expires = ktime_add_ns(now, dev->min_delta_ns); + } + } + +@@ -47,7 +71,7 @@ int tick_program_event(ktime_t expires, + { + struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + +- return __tick_program_event(dev, expires, force); ++ return tick_dev_program_event(dev, expires, force); + } + + /** +@@ -71,7 +95,7 @@ void tick_setup_oneshot(struct clock_eve + { + newdev->event_handler = handler; + clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); +- __tick_program_event(newdev, next_event, 1); ++ tick_dev_program_event(newdev, next_event, 1); + } + + /** diff --git a/queue-2.6.26/timer-fix-06.patch b/queue-2.6.26/timer-fix-06.patch new file mode 100644 index 00000000000..8739bdae986 --- /dev/null +++ b/queue-2.6.26/timer-fix-06.patch @@ -0,0 +1,40 @@ +From 7cfb0435330364f90f274a26ecdc5f47f738498c Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Wed, 3 Sep 2008 21:37:24 +0000 +Subject: HPET: make minimum reprogramming delta useful + +From: Thomas Gleixner + +commit 7cfb0435330364f90f274a26ecdc5f47f738498c upstream + +The minimum reprogramming delta was hardcoded in HPET ticks, +which is stupid as it does not work with faster running HPETs. +The C1E idle patches made this prominent on AMD/RS690 chipsets, +where the HPET runs with 25MHz. Set it to 5us which seems to be +a reasonable value and fixes the problems on the bug reporters +machines. We have a further sanity check now in the clock events, +which increases the delta when it is not sufficient. + +Signed-off-by: Thomas Gleixner +Tested-by: Luiz Fernando N. Capitulino +Tested-by: Dmitry Nezhevenko +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/hpet.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -223,8 +223,8 @@ static void hpet_legacy_clockevent_regis + /* Calculate the min / max delta */ + hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, + &hpet_clockevent); +- hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, +- &hpet_clockevent); ++ /* 5 usec minimum reprogramming delta. */ ++ hpet_clockevent.min_delta_ns = 5000; + + /* + * Start hpet with the boot cpu mask and make it diff --git a/queue-2.6.26/timer-fix-07.patch b/queue-2.6.26/timer-fix-07.patch new file mode 100644 index 00000000000..426e3fc2cae --- /dev/null +++ b/queue-2.6.26/timer-fix-07.patch @@ -0,0 +1,76 @@ +From 7300711e8c6824fcfbd42a126980ff50439d8dd0 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 6 Sep 2008 03:01:45 +0200 +Subject: clockevents: broadcast fixup possible waiters + +From: Thomas Gleixner + +commit 7300711e8c6824fcfbd42a126980ff50439d8dd0 upstream + +Until the C1E patches arrived there where no users of periodic broadcast +before switching to oneshot mode. Now we need to trigger a possible +waiter for a periodic broadcast when switching to oneshot mode. +Otherwise we can starve them for ever. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/tick-broadcast.c | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +--- a/kernel/time/tick-broadcast.c ++++ b/kernel/time/tick-broadcast.c +@@ -490,6 +490,18 @@ static void tick_broadcast_clear_oneshot + cpu_clear(cpu, tick_broadcast_oneshot_mask); + } + ++static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires) ++{ ++ struct tick_device *td; ++ int cpu; ++ ++ for_each_cpu_mask_nr(cpu, *mask) { ++ td = &per_cpu(tick_cpu_device, cpu); ++ if (td->evtdev) ++ td->evtdev->next_event = expires; ++ } ++} ++ + /** + * tick_broadcast_setup_oneshot - setup the broadcast device + */ +@@ -497,9 +509,32 @@ void tick_broadcast_setup_oneshot(struct + { + /* Set it up only once ! */ + if (bc->event_handler != tick_handle_oneshot_broadcast) { ++ int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC; ++ int cpu = smp_processor_id(); ++ cpumask_t mask; ++ + bc->event_handler = tick_handle_oneshot_broadcast; + clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); +- bc->next_event.tv64 = KTIME_MAX; ++ ++ /* Take the do_timer update */ ++ tick_do_timer_cpu = cpu; ++ ++ /* ++ * We must be careful here. There might be other CPUs ++ * waiting for periodic broadcast. We need to set the ++ * oneshot_mask bits for those and program the ++ * broadcast device to fire. ++ */ ++ mask = tick_broadcast_mask; ++ cpu_clear(cpu, mask); ++ cpus_or(tick_broadcast_oneshot_mask, ++ tick_broadcast_oneshot_mask, mask); ++ ++ if (was_periodic && !cpus_empty(mask)) { ++ tick_broadcast_init_next_event(&mask, tick_next_period); ++ tick_broadcast_set_event(tick_next_period, 1); ++ } else ++ bc->next_event.tv64 = KTIME_MAX; + } + } + diff --git a/queue-2.6.26/timer-fix-08.patch b/queue-2.6.26/timer-fix-08.patch new file mode 100644 index 00000000000..d9188eed02f --- /dev/null +++ b/queue-2.6.26/timer-fix-08.patch @@ -0,0 +1,54 @@ +From f7676254f179eac6b5244a80195ec8ae0e9d4606 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 6 Sep 2008 03:03:32 +0200 +Subject: x86: HPET fix moronic 32/64bit thinko + +From: Thomas Gleixner + +commit f7676254f179eac6b5244a80195ec8ae0e9d4606 upstream + +We use the HPET only in 32bit mode because: +1) some HPETs are 32bit only +2) on i386 there is no way to read/write the HPET atomic 64bit wide + +The HPET code unification done by the "moron of the year" did +not take into account that unsigned long is different on 32 and +64 bit. + +This thinko results in a possible endless loop in the clockevents +code, when the return comparison fails due to the 64bit/332bit +unawareness. + +unsigned long cnt = (u32) hpet_read() + delta can wrap over 32bit. +but the final compare will fail and return -ETIME causing endless +loops. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/hpet.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -283,15 +283,15 @@ static void hpet_legacy_set_mode(enum cl + } + + static int hpet_legacy_next_event(unsigned long delta, +- struct clock_event_device *evt) ++ struct clock_event_device *evt) + { +- unsigned long cnt; ++ u32 cnt; + + cnt = hpet_readl(HPET_COUNTER); +- cnt += delta; ++ cnt += (u32) delta; + hpet_writel(cnt, HPET_T0_CMP); + +- return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0; ++ return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; + } + + /* diff --git a/queue-2.6.26/timer-fix-09.patch b/queue-2.6.26/timer-fix-09.patch new file mode 100644 index 00000000000..6f4d1a427a1 --- /dev/null +++ b/queue-2.6.26/timer-fix-09.patch @@ -0,0 +1,38 @@ +From 72d43d9bc9210d24d09202eaf219eac09e17b339 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 6 Sep 2008 03:06:08 +0200 +Subject: x86: HPET: read back compare register before reading counter + +From: Thomas Gleixner + +commit 72d43d9bc9210d24d09202eaf219eac09e17b339 upstream + +After fixing the u32 thinko I sill had occasional hickups on ATI chipsets +with small deltas. There seems to be a delay between writing the compare +register and the transffer to the internal register which triggers the +interrupt. Reading back the value makes sure, that it hit the internal +match register befor we compare against the counter value. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/hpet.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -291,6 +291,13 @@ static int hpet_legacy_next_event(unsign + cnt += (u32) delta; + hpet_writel(cnt, HPET_T0_CMP); + ++ /* ++ * We need to read back the CMP register to make sure that ++ * what we wrote hit the chip before we compare it to the ++ * counter. ++ */ ++ WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt); ++ + return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; + } + diff --git a/queue-2.6.26/timer-fix-10.patch b/queue-2.6.26/timer-fix-10.patch new file mode 100644 index 00000000000..8f44c564565 --- /dev/null +++ b/queue-2.6.26/timer-fix-10.patch @@ -0,0 +1,57 @@ +From 4ff4b9e19a80b73959ebeb28d1df40176686f0a8 Mon Sep 17 00:00:00 2001 +From: Maciej W. Rozycki +Date: Fri, 5 Sep 2008 14:05:31 -0700 +Subject: ntp: fix calculation of the next jiffie to trigger RTC sync + +From: Maciej W. Rozycki + +commit 4ff4b9e19a80b73959ebeb28d1df40176686f0a8 upstream + +We have a bug in the calculation of the next jiffie to trigger the RTC +synchronisation. The aim here is to run sync_cmos_clock() as close as +possible to the middle of a second. Which means we want this function to +be called less than or equal to half a jiffie away from when now.tv_nsec +equals 5e8 (500000000). + +If this is not the case for a given call to the function, for this purpose +instead of updating the RTC we calculate the offset in nanoseconds to the +next point in time where now.tv_nsec will be equal 5e8. The calculated +offset is then converted to jiffies as these are the unit used by the +timer. + +Hovewer timespec_to_jiffies() used here uses a ceil()-type rounding mode, +where the resulting value is rounded up. As a result the range of +now.tv_nsec when the timer will trigger is from 5e8 to 5e8 + TICK_NSEC +rather than the desired 5e8 - TICK_NSEC / 2 to 5e8 + TICK_NSEC / 2. + +As a result if for example sync_cmos_clock() happens to be called at the +time when now.tv_nsec is between 5e8 + TICK_NSEC / 2 and 5e8 to 5e8 + +TICK_NSEC, it will simply be rescheduled HZ jiffies later, falling in the +same range of now.tv_nsec again. Similarly for cases offsetted by an +integer multiple of TICK_NSEC. + +This change addresses the problem by subtracting TICK_NSEC / 2 from the +nanosecond offset to the next point in time where now.tv_nsec will be +equal 5e8, effectively shifting the following rounding in +timespec_to_jiffies() so that it produces a rounded-to-nearest result. + +Signed-off-by: Maciej W. Rozycki +Signed-off-by: Andrew Morton +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/ntp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -245,7 +245,7 @@ static void sync_cmos_clock(unsigned lon + if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) + fail = update_persistent_clock(now); + +- next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec; ++ next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); + if (next.tv_nsec <= 0) + next.tv_nsec += NSEC_PER_SEC; + diff --git a/queue-2.6.26/timer-fix-11.patch b/queue-2.6.26/timer-fix-11.patch new file mode 100644 index 00000000000..860053c3231 --- /dev/null +++ b/queue-2.6.26/timer-fix-11.patch @@ -0,0 +1,57 @@ +From 61c22c34c6f80a8e89cff5ff717627c54cc14fd4 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 9 Sep 2008 21:38:57 +0200 +Subject: clockevents: remove WARN_ON which was used to gather information + +From: Thomas Gleixner + +commit 61c22c34c6f80a8e89cff5ff717627c54cc14fd4 upstream + +The issue of the endless reprogramming loop due to a too small +min_delta_ns was fixed with the previous updates of the clock events +code, but we had no information about the spread of this problem. I +added a WARN_ON to get automated information via kerneloops.org and to +get some direct reports, which allowed me to analyse the affected +machines. + +The WARN_ON has served its purpose and would be annoying for a release +kernel. Remove it and just keep the information about the increase of +the min_delta_ns value. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/tick-oneshot.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +--- a/kernel/time/tick-oneshot.c ++++ b/kernel/time/tick-oneshot.c +@@ -43,19 +43,17 @@ int tick_dev_program_event(struct clock_ + * and emit a warning. + */ + if (++i > 2) { +- printk(KERN_WARNING "CE: __tick_program_event of %s is " +- "stuck %llx %llx\n", dev->name ? dev->name : "?", +- now.tv64, expires.tv64); +- printk(KERN_WARNING +- "CE: increasing min_delta_ns %ld to %ld nsec\n", +- dev->min_delta_ns, dev->min_delta_ns << 1); +- WARN_ON(1); +- +- /* Double the min. delta and try again */ ++ /* Increase the min. delta and try again */ + if (!dev->min_delta_ns) + dev->min_delta_ns = 5000; + else +- dev->min_delta_ns <<= 1; ++ dev->min_delta_ns += dev->min_delta_ns >> 1; ++ ++ printk(KERN_WARNING ++ "CE: %s increasing min_delta_ns to %lu nsec\n", ++ dev->name ? dev->name : "?", ++ dev->min_delta_ns << 1); ++ + i = 0; + } + -- 2.47.3