From: Matthew Garrett <mjg@redhat.com> Date: Wed, 27 Aug 2008 17:33:01 +0100 Subject: [acpi] increase deep idle state residency on platforms-2 Message-id: 20080827163301.GA10872@srcf.ucam.org O-Subject: [RHEL5 patch] BZ#455449 - FEAT: RHEL 5.3: (2/2) Increase deep idle state residency on idle platforms using Nehalem class processors Bugzilla: 455449 When using the local APIC timer, we currently send an IPI to each CPU in sequence. This patch changes behaviour to send a broadcast IPI, allowing the CPU to return to the idle state more rapidly. This version fixes the i386 build. From looking at how the bizarro architectures like Summit do their APIC setup, I /think/ this is safe - none of them actually seem to make use of the APIC abstraction for IPI stuff. It'd be appreciated if someone who actually knows those platforms could take a look, though. diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index e72a37a..9ed9c97 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -1253,20 +1253,26 @@ static void up_apic_timer_interrupt_call(struct pt_regs *regs) void smp_send_timer_broadcast_ipi(struct pt_regs *regs) { +#ifdef CONFIG_SMP cpumask_t mask; + if (cpus_equal(cpu_online_map, timer_bcast_ipi)) { + __send_IPI_shortcut(APIC_DEST_ALLINC, LOCAL_TIMER_VECTOR); + return; + } cpus_and(mask, cpu_online_map, timer_bcast_ipi); if (!cpus_empty(mask)) { -#ifdef CONFIG_SMP send_IPI_mask(mask, LOCAL_TIMER_VECTOR); + } #else + if (!cpus_empty(timer_bcast_ipi)) { /* * We can directly call the apic timer interrupt handler * in UP case. Minus all irq related functions */ up_apic_timer_interrupt_call(regs); -#endif } +#endif } int setup_profiling_timer(unsigned int multiplier) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 9798e8e..758fece 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -36,6 +36,7 @@ #include <asm/idle.h> #include <asm/proto.h> #include <asm/timex.h> +#include <asm/ipi.h> int apic_verbosity; int apic_runs_main_timer; @@ -896,6 +897,12 @@ void smp_send_timer_broadcast_ipi(void) { cpumask_t mask; + if (cpus_equal(cpu_online_map, timer_interrupt_broadcast_ipi_mask)) { + __send_IPI_shortcut(APIC_DEST_ALLINC, LOCAL_TIMER_VECTOR, + APIC_DEST_LOGICAL); + return; + } + cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask); if (!cpus_empty(mask)) { send_IPI_mask(mask, LOCAL_TIMER_VECTOR); diff --git a/include/asm-i386/mach-generic/mach_ipi.h b/include/asm-i386/mach-generic/mach_ipi.h index 441b0fe..09203be 100644 --- a/include/asm-i386/mach-generic/mach_ipi.h +++ b/include/asm-i386/mach-generic/mach_ipi.h @@ -3,6 +3,7 @@ #include <asm/genapic.h> +void __send_IPI_shortcut(unsigned int shortcut, int vector); #define send_IPI_mask (genapic->send_IPI_mask) #define send_IPI_allbutself (genapic->send_IPI_allbutself) #define send_IPI_all (genapic->send_IPI_all)