Commit 59d66ce2 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-x86

* git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-x86:
  x86: force timer broadcast on late AMD C1E detection
  x86: move local APIC timer init to the end of start_secondary()
  clockevents: introduce force broadcast notifier
  x86: fix missing include for vsyscall
parents 5c0d6b34 89039b37
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/vsyscall.h>
#define MAX_PATCH_LEN (255-1) #define MAX_PATCH_LEN (255-1)
......
...@@ -964,8 +964,34 @@ void __init setup_boot_APIC_clock (void) ...@@ -964,8 +964,34 @@ void __init setup_boot_APIC_clock (void)
setup_APIC_timer(); setup_APIC_timer();
} }
/*
* AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the
* C1E flag only in the secondary CPU, so when we detect the wreckage
* we already have enabled the boot CPU local apic timer. Check, if
* disable_apic_timer is set and the DUMMY flag is cleared. If yes,
* set the DUMMY flag again and force the broadcast mode in the
* clockevents layer.
*/
void __cpuinit check_boot_apic_timer_broadcast(void)
{
struct clock_event_device *levt = &per_cpu(lapic_events, boot_cpu_id);
if (!disable_apic_timer ||
(lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY))
return;
printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n");
lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;
levt->features |= CLOCK_EVT_FEAT_DUMMY;
local_irq_enable();
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, &boot_cpu_id);
local_irq_disable();
}
void __cpuinit setup_secondary_APIC_clock(void) void __cpuinit setup_secondary_APIC_clock(void)
{ {
check_boot_apic_timer_broadcast();
setup_APIC_timer(); setup_APIC_timer();
} }
......
...@@ -335,11 +335,6 @@ void __cpuinit start_secondary(void) ...@@ -335,11 +335,6 @@ void __cpuinit start_secondary(void)
*/ */
check_tsc_sync_target(); check_tsc_sync_target();
Dprintk("cpu %d: setting up apic clock\n", smp_processor_id());
setup_secondary_APIC_clock();
Dprintk("cpu %d: enabling apic timer\n", smp_processor_id());
if (nmi_watchdog == NMI_IO_APIC) { if (nmi_watchdog == NMI_IO_APIC) {
disable_8259A_irq(0); disable_8259A_irq(0);
enable_NMI_through_LVT0(NULL); enable_NMI_through_LVT0(NULL);
...@@ -374,6 +369,8 @@ void __cpuinit start_secondary(void) ...@@ -374,6 +369,8 @@ void __cpuinit start_secondary(void)
unlock_ipi_call_lock(); unlock_ipi_call_lock();
setup_secondary_APIC_clock();
cpu_idle(); cpu_idle();
} }
......
...@@ -31,6 +31,7 @@ enum clock_event_nofitiers { ...@@ -31,6 +31,7 @@ enum clock_event_nofitiers {
CLOCK_EVT_NOTIFY_ADD, CLOCK_EVT_NOTIFY_ADD,
CLOCK_EVT_NOTIFY_BROADCAST_ON, CLOCK_EVT_NOTIFY_BROADCAST_ON,
CLOCK_EVT_NOTIFY_BROADCAST_OFF, CLOCK_EVT_NOTIFY_BROADCAST_OFF,
CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
CLOCK_EVT_NOTIFY_BROADCAST_ENTER, CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
CLOCK_EVT_NOTIFY_BROADCAST_EXIT, CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
CLOCK_EVT_NOTIFY_SUSPEND, CLOCK_EVT_NOTIFY_SUSPEND,
......
...@@ -217,26 +217,43 @@ static void tick_do_broadcast_on_off(void *why) ...@@ -217,26 +217,43 @@ static void tick_do_broadcast_on_off(void *why)
bc = tick_broadcast_device.evtdev; bc = tick_broadcast_device.evtdev;
/* /*
* Is the device in broadcast mode forever or is it not * Is the device not affected by the powerstate ?
* affected by the powerstate ?
*/ */
if (!dev || !tick_device_is_functional(dev) || if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
!(dev->features & CLOCK_EVT_FEAT_C3STOP))
goto out; goto out;
if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_ON) { /*
* Defect device ?
*/
if (!tick_device_is_functional(dev)) {
/*
* AMD C1E wreckage fixup:
*
* Device was registered functional in the first
* place. Now the secondary CPU detected the C1E
* misfeature and notifies us to fix it up
*/
if (*reason != CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
goto out;
}
switch (*reason) {
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
if (!cpu_isset(cpu, tick_broadcast_mask)) { if (!cpu_isset(cpu, tick_broadcast_mask)) {
cpu_set(cpu, tick_broadcast_mask); cpu_set(cpu, tick_broadcast_mask);
if (td->mode == TICKDEV_MODE_PERIODIC) if (td->mode == TICKDEV_MODE_PERIODIC)
clockevents_set_mode(dev, clockevents_set_mode(dev,
CLOCK_EVT_MODE_SHUTDOWN); CLOCK_EVT_MODE_SHUTDOWN);
} }
} else { break;
case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
if (cpu_isset(cpu, tick_broadcast_mask)) { if (cpu_isset(cpu, tick_broadcast_mask)) {
cpu_clear(cpu, tick_broadcast_mask); cpu_clear(cpu, tick_broadcast_mask);
if (td->mode == TICKDEV_MODE_PERIODIC) if (td->mode == TICKDEV_MODE_PERIODIC)
tick_setup_periodic(dev, 0); tick_setup_periodic(dev, 0);
} }
break;
} }
if (cpus_empty(tick_broadcast_mask)) if (cpus_empty(tick_broadcast_mask))
......
...@@ -345,6 +345,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason, ...@@ -345,6 +345,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
case CLOCK_EVT_NOTIFY_BROADCAST_ON: case CLOCK_EVT_NOTIFY_BROADCAST_ON:
case CLOCK_EVT_NOTIFY_BROADCAST_OFF: case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
tick_broadcast_on_off(reason, dev); tick_broadcast_on_off(reason, dev);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment