debuggers.hg

changeset 21140:cd6c6c685015

cpuidle: mwait on softirq_pending & remove wakeup ipis

For cpu which enter deep C state via monitor/mwait, wakeup can be done
by writing to the monitored memory. So once monitor softirq_pending,
we can remove the redundant ipis.

Signed-off-by: Yu Ke <ke.yu@intel.com>
Signed-off-by: Wei Gang <gang.wei@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Apr 06 06:52:11 2010 +0100 (2010-04-06)
parents 4a3e131f7498
children fe30bd463e84
files xen/arch/x86/acpi/cpu_idle.c xen/arch/x86/hpet.c xen/include/xen/cpuidle.h
line diff
     1.1 --- a/xen/arch/x86/acpi/cpu_idle.c	Tue Apr 06 06:51:04 2010 +0100
     1.2 +++ b/xen/arch/x86/acpi/cpu_idle.c	Tue Apr 06 06:52:11 2010 +0100
     1.3 @@ -69,6 +69,14 @@ boolean_param("lapic_timer_c2_ok", local
     1.4  
     1.5  static struct acpi_processor_power *__read_mostly processor_powers[NR_CPUS];
     1.6  
     1.7 +static char* acpi_cstate_method_name[] =
     1.8 +{
     1.9 +    "NONE",
    1.10 +    "SYSIO",
    1.11 +    "FFH",
    1.12 +    "HALT"
    1.13 +};
    1.14 +
    1.15  static void print_acpi_power(uint32_t cpu, struct acpi_processor_power *power)
    1.16  {
    1.17      uint32_t i, idle_usage = 0;
    1.18 @@ -92,6 +100,7 @@ static void print_acpi_power(uint32_t cp
    1.19          printk("type[C%d] ", power->states[i].type);
    1.20          printk("latency[%03d] ", power->states[i].latency);
    1.21          printk("usage[%08d] ", power->states[i].usage);
    1.22 +        printk("method[%5s] ", acpi_cstate_method_name[power->states[i].entry_method]);
    1.23          printk("duration[%"PRId64"]\n", res);
    1.24      }
    1.25      printk("    C0:\tusage[%08d] duration[%"PRId64"]\n",
    1.26 @@ -140,11 +149,43 @@ static void acpi_safe_halt(void)
    1.27  
    1.28  #define MWAIT_ECX_INTERRUPT_BREAK   (0x1)
    1.29  
    1.30 +/*
    1.31 + * The bit is set iff cpu use monitor/mwait to enter C state
    1.32 + * with this flag set, CPU can be waken up from C state
    1.33 + * by writing to specific memory address, instead of sending IPI
    1.34 + */
    1.35 +static cpumask_t cpuidle_mwait_flags;
    1.36 +
    1.37 +void cpuidle_wakeup_mwait(cpumask_t *mask)
    1.38 +{
    1.39 +    cpumask_t target;
    1.40 +    int cpu;
    1.41 +
    1.42 +    cpus_and(target, *mask, cpuidle_mwait_flags);
    1.43 +
    1.44 +    /* cpu is 'mwait'ing at softirq_pending,
    1.45 +       writing to it will wake up CPU */
    1.46 +    for_each_cpu_mask(cpu, target)
    1.47 +        set_bit(TIMER_SOFTIRQ, &softirq_pending(cpu));
    1.48 +
    1.49 +    cpus_andnot(*mask, *mask, cpuidle_mwait_flags);
    1.50 +}
    1.51 +
    1.52  static void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
    1.53  {
    1.54 -    __monitor((void *)current, 0, 0);
    1.55 +    int cpu = smp_processor_id();
    1.56 +
    1.57 +    __monitor((void *)&softirq_pending(cpu), 0, 0);
    1.58 +
    1.59      smp_mb();
    1.60 -    __mwait(eax, ecx);
    1.61 +    if (!softirq_pending(cpu))
    1.62 +    {
    1.63 +        cpu_set(cpu, cpuidle_mwait_flags);
    1.64 +
    1.65 +        __mwait(eax, ecx);
    1.66 +
    1.67 +        cpu_clear(cpu, cpuidle_mwait_flags);
    1.68 +    }
    1.69  }
    1.70  
    1.71  static void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
     2.1 --- a/xen/arch/x86/hpet.c	Tue Apr 06 06:51:04 2010 +0100
     2.2 +++ b/xen/arch/x86/hpet.c	Tue Apr 06 06:52:11 2010 +0100
     2.3 @@ -166,6 +166,8 @@ static int evt_do_broadcast(cpumask_t ma
     2.4          ret = 1;
     2.5      }
     2.6  
     2.7 +    cpuidle_wakeup_mwait(&mask);
     2.8 +
     2.9      if ( !cpus_empty(mask) )
    2.10      {
    2.11         cpumask_raise_softirq(mask, TIMER_SOFTIRQ);
     3.1 --- a/xen/include/xen/cpuidle.h	Tue Apr 06 06:51:04 2010 +0100
     3.2 +++ b/xen/include/xen/cpuidle.h	Tue Apr 06 06:52:11 2010 +0100
     3.3 @@ -86,6 +86,8 @@ struct cpuidle_governor
     3.4  extern struct cpuidle_governor *cpuidle_current_governor;
     3.5  void cpuidle_disable_deep_cstate(void);
     3.6  
     3.7 +extern void cpuidle_wakeup_mwait(cpumask_t *mask);
     3.8 +
     3.9  #define CPUIDLE_DRIVER_STATE_START  1
    3.10  
    3.11  #endif /* _XEN_CPUIDLE_H */