diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index f8302d1f54..40263873e8 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -195,6 +195,15 @@ static void acpi_processor_idle(void) int sleep_ticks = 0; u32 t1, t2 = 0; + sched_tick_suspend(); + /* + * sched_tick_suspend may raise TIMER_SOFTIRQ by __stop_timer, + * which will break the later assumption of no sofirq pending, + * so add do_softirq + */ + if ( softirq_pending(smp_processor_id()) ) + do_softirq(); + /* * Interrupts must be disabled during bus mastering calculations and * for C2/C3 transitions. @@ -204,6 +213,7 @@ static void acpi_processor_idle(void) if ( softirq_pending(smp_processor_id()) ) { local_irq_enable(); + sched_tick_resume(); return; } @@ -223,6 +233,7 @@ static void acpi_processor_idle(void) pm_idle_save(); else acpi_safe_halt(); + sched_tick_resume(); return; } @@ -329,6 +340,7 @@ static void acpi_processor_idle(void) default: local_irq_enable(); + sched_tick_resume(); return; } @@ -339,6 +351,8 @@ static void acpi_processor_idle(void) cx->time += sleep_ticks; } + sched_tick_resume(); + if ( cpuidle_current_governor->reflect ) cpuidle_current_governor->reflect(power); } diff --git a/xen/common/sched_credit.c b/xen/common/sched_credit.c index d724293bc1..c554c8b8b9 100644 --- a/xen/common/sched_credit.c +++ b/xen/common/sched_credit.c @@ -154,6 +154,7 @@ struct csched_private { spinlock_t lock; struct list_head active_sdom; uint32_t ncpus; + struct timer master_ticker; unsigned int master; cpumask_t idlers; uint32_t weight; @@ -757,7 +758,7 @@ csched_runq_sort(unsigned int cpu) } static void -csched_acct(void) +csched_acct(void* dummy) { unsigned long flags; struct list_head *iter_vcpu, *next_vcpu; @@ -792,7 +793,7 @@ csched_acct(void) csched_priv.credit_balance = 0; spin_unlock_irqrestore(&csched_priv.lock, flags); CSCHED_STAT_CRANK(acct_no_work); - return; + goto out; } CSCHED_STAT_CRANK(acct_run); @@ -950,6 +951,10 @@ csched_acct(void) /* Inform each CPU that its runq needs to be sorted */ csched_priv.runq_sort++; + +out: + set_timer( &csched_priv.master_ticker, NOW() + + MILLISECS(CSCHED_MSECS_PER_TICK) * CSCHED_TICKS_PER_ACCT ); } static void @@ -966,18 +971,6 @@ csched_tick(void *_cpu) if ( !is_idle_vcpu(current) ) csched_vcpu_acct(cpu); - /* - * Host-wide accounting duty - * - * Note: Currently, this is always done by the master boot CPU. Eventually, - * we could distribute or at the very least cycle the duty. - */ - if ( (csched_priv.master == cpu) && - (spc->tick % CSCHED_TICKS_PER_ACCT) == 0 ) - { - csched_acct(); - } - /* * Check if runq needs to be sorted * @@ -1310,10 +1303,35 @@ static __init int csched_start_tickers(void) set_timer(&spc->ticker, NOW() + MILLISECS(CSCHED_MSECS_PER_TICK)); } + init_timer( &csched_priv.master_ticker, csched_acct, NULL, + csched_priv.master); + + set_timer( &csched_priv.master_ticker, NOW() + + MILLISECS(CSCHED_MSECS_PER_TICK) * CSCHED_TICKS_PER_ACCT ); + return 0; } __initcall(csched_start_tickers); +static void csched_tick_suspend(void) +{ + struct csched_pcpu *spc; + + spc = CSCHED_PCPU(smp_processor_id()); + + stop_timer(&spc->ticker); +} + +static void csched_tick_resume(void) +{ + struct csched_pcpu *spc; + uint64_t now = NOW(); + + spc = CSCHED_PCPU(smp_processor_id()); + + set_timer(&spc->ticker, now + MILLISECS(CSCHED_MSECS_PER_TICK) + - now % MILLISECS(CSCHED_MSECS_PER_TICK) ); +} struct scheduler sched_credit_def = { .name = "SMP Credit Scheduler", @@ -1337,4 +1355,7 @@ struct scheduler sched_credit_def = { .dump_cpu_state = csched_dump_pcpu, .dump_settings = csched_dump, .init = csched_init, + + .tick_suspend = csched_tick_suspend, + .tick_resume = csched_tick_resume, }; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 5e91f6c85d..f1121938da 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -964,6 +964,16 @@ void dump_runq(unsigned char key) local_irq_restore(flags); } +void sched_tick_suspend(void) +{ + SCHED_OP(tick_suspend); +} + +void sched_tick_resume(void) +{ + SCHED_OP(tick_resume); +} + #ifdef CONFIG_COMPAT #include "compat/schedule.c" #endif diff --git a/xen/include/xen/sched-if.h b/xen/include/xen/sched-if.h index f6ba9faa5c..5caf8245d2 100644 --- a/xen/include/xen/sched-if.h +++ b/xen/include/xen/sched-if.h @@ -77,6 +77,9 @@ struct scheduler { struct xen_domctl_scheduler_op *); void (*dump_settings) (void); void (*dump_cpu_state) (int); + + void (*tick_suspend) (void); + void (*tick_resume) (void); }; #endif /* __XEN_SCHED_IF_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index efaec7e9b7..206bf6de4e 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -428,6 +428,8 @@ int sched_init_domain(struct domain *d); void sched_destroy_domain(struct domain *d); long sched_adjust(struct domain *, struct xen_domctl_scheduler_op *); int sched_id(void); +void sched_tick_suspend(void); +void sched_tick_resume(void); void vcpu_wake(struct vcpu *d); void vcpu_sleep_nosync(struct vcpu *d); void vcpu_sleep_sync(struct vcpu *d);