From: jbeulich@novell.com Subject: use base kernel suspend/resume infrastructure Patch-mainline: obsolete ... rather than calling just a few functions explicitly. --- head-2010-05-12.orig/arch/x86/kernel/time-xen.c 2010-05-12 09:13:55.000000000 +0200 +++ head-2010-05-12/arch/x86/kernel/time-xen.c 2010-05-12 09:14:03.000000000 +0200 @@ -69,6 +69,10 @@ static DEFINE_PER_CPU(struct vcpu_runsta /* Must be signed, as it's compared with s64 quantities which can be -ve. */ #define NS_PER_TICK (1000000000LL/HZ) +static struct vcpu_set_periodic_timer xen_set_periodic_tick = { + .period_ns = NS_PER_TICK +}; + static void __clock_was_set(struct work_struct *unused) { clock_was_set(); @@ -561,6 +565,17 @@ void mark_tsc_unstable(char *reason) } EXPORT_SYMBOL_GPL(mark_tsc_unstable); +static void init_missing_ticks_accounting(unsigned int cpu) +{ + struct vcpu_runstate_info *runstate = setup_runstate_area(cpu); + + per_cpu(processed_blocked_time, cpu) = + runstate->time[RUNSTATE_blocked]; + per_cpu(processed_stolen_time, cpu) = + runstate->time[RUNSTATE_runnable] + + runstate->time[RUNSTATE_offline]; +} + static cycle_t cs_last; static cycle_t xen_clocksource_read(struct clocksource *cs) @@ -597,11 +612,32 @@ static cycle_t xen_clocksource_read(stru #endif } +/* No locking required. Interrupts are disabled on all CPUs. */ static void xen_clocksource_resume(struct clocksource *cs) { - extern void time_resume(void); + unsigned int cpu; + + init_cpu_khz(); + + for_each_online_cpu(cpu) { + switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, + &xen_set_periodic_tick)) { + case 0: +#if CONFIG_XEN_COMPAT <= 0x030004 + case -ENOSYS: +#endif + break; + default: + BUG(); + } + get_time_values_from_xen(cpu); + per_cpu(processed_system_time, cpu) = + per_cpu(shadow_time, 0).system_timestamp; + init_missing_ticks_accounting(cpu); + } + + processed_system_time = per_cpu(shadow_time, 0).system_timestamp; - time_resume(); cs_last = local_clock(); } @@ -633,17 +669,6 @@ struct vcpu_runstate_info *setup_runstat return rs; } -static void init_missing_ticks_accounting(unsigned int cpu) -{ - struct vcpu_runstate_info *runstate = setup_runstate_area(cpu); - - per_cpu(processed_blocked_time, cpu) = - runstate->time[RUNSTATE_blocked]; - per_cpu(processed_stolen_time, cpu) = - runstate->time[RUNSTATE_runnable] + - runstate->time[RUNSTATE_offline]; -} - void xen_read_persistent_clock(struct timespec *ts) { const shared_info_t *s = HYPERVISOR_shared_info; @@ -689,10 +714,6 @@ static void __init setup_cpu0_timer_irq( BUG_ON(per_cpu(timer_irq, 0) < 0); } -static struct vcpu_set_periodic_timer xen_set_periodic_tick = { - .period_ns = NS_PER_TICK -}; - void __init time_init(void) { init_cpu_khz(); @@ -830,35 +851,6 @@ void xen_halt(void) } EXPORT_SYMBOL(xen_halt); -/* No locking required. Interrupts are disabled on all CPUs. */ -void time_resume(void) -{ - unsigned int cpu; - - init_cpu_khz(); - - for_each_online_cpu(cpu) { - switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, - &xen_set_periodic_tick)) { - case 0: -#if CONFIG_XEN_COMPAT <= 0x030004 - case -ENOSYS: -#endif - break; - default: - BUG(); - } - get_time_values_from_xen(cpu); - per_cpu(processed_system_time, cpu) = - per_cpu(shadow_time, 0).system_timestamp; - init_missing_ticks_accounting(cpu); - } - - processed_system_time = per_cpu(shadow_time, 0).system_timestamp; - - update_wallclock(); -} - #ifdef CONFIG_SMP static char timer_name[NR_CPUS][15]; --- head-2010-05-12.orig/drivers/xen/core/evtchn.c 2010-04-15 11:03:28.000000000 +0200 +++ head-2010-05-12/drivers/xen/core/evtchn.c 2010-04-23 15:20:28.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1117,10 +1118,21 @@ static void restore_cpu_ipis(unsigned in } } -void irq_resume(void) +static int evtchn_resume(struct sys_device *dev) { unsigned int cpu, irq, evtchn; struct irq_cfg *cfg; + struct evtchn_status status; + + /* Avoid doing anything in the 'suspend cancelled' case. */ + status.dom = DOMID_SELF; + status.port = evtchn_from_irq(percpu_read(virq_to_irq[VIRQ_TIMER])); + if (HYPERVISOR_event_channel_op(EVTCHNOP_status, &status)) + BUG(); + if (status.status == EVTCHNSTAT_virq + && status.vcpu == smp_processor_id() + && status.u.virq == VIRQ_TIMER) + return 0; init_evtchn_cpu_bindings(); @@ -1156,7 +1168,32 @@ void irq_resume(void) restore_cpu_ipis(cpu); } + return 0; +} + +static struct sysdev_class evtchn_sysclass = { + .name = "evtchn", + .resume = evtchn_resume, +}; + +static struct sys_device device_evtchn = { + .id = 0, + .cls = &evtchn_sysclass, +}; + +static int __init evtchn_register(void) +{ + int err; + + if (is_initial_xendomain()) + return 0; + + err = sysdev_class_register(&evtchn_sysclass); + if (!err) + err = sysdev_register(&device_evtchn); + return err; } +core_initcall(evtchn_register); #endif int __init arch_early_irq_init(void) --- head-2010-05-12.orig/drivers/xen/core/gnttab.c 2010-04-15 11:04:07.000000000 +0200 +++ head-2010-05-12/drivers/xen/core/gnttab.c 2010-04-15 11:42:34.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -708,23 +709,37 @@ EXPORT_SYMBOL(gnttab_post_map_adjust); #endif /* __HAVE_ARCH_PTE_SPECIAL */ -int gnttab_resume(void) +static int gnttab_resume(struct sys_device *dev) { if (max_nr_grant_frames() < nr_grant_frames) return -ENOSYS; return gnttab_map(0, nr_grant_frames - 1); } +#define gnttab_resume() gnttab_resume(NULL) #ifdef CONFIG_PM_SLEEP -int gnttab_suspend(void) -{ #ifdef CONFIG_X86 +static int gnttab_suspend(struct sys_device *dev, pm_message_t state) +{ apply_to_page_range(&init_mm, (unsigned long)shared, PAGE_SIZE * nr_grant_frames, unmap_pte_fn, NULL); -#endif return 0; } +#else +#define gnttab_suspend NULL +#endif + +static struct sysdev_class gnttab_sysclass = { + .name = "gnttab", + .resume = gnttab_resume, + .suspend = gnttab_suspend, +}; + +static struct sys_device device_gnttab = { + .id = 0, + .cls = &gnttab_sysclass, +}; #endif #else /* !CONFIG_XEN */ @@ -804,6 +819,17 @@ int __devinit gnttab_init(void) if (!is_running_on_xen()) return -ENODEV; +#if defined(CONFIG_XEN) && defined(CONFIG_PM_SLEEP) + if (!is_initial_xendomain()) { + int err = sysdev_class_register(&gnttab_sysclass); + + if (!err) + err = sysdev_register(&device_gnttab); + if (err) + return err; + } +#endif + nr_grant_frames = 1; boot_max_nr_grant_frames = __max_nr_grant_frames(); --- head-2010-05-12.orig/drivers/xen/core/machine_reboot.c 2010-03-24 15:17:58.000000000 +0100 +++ head-2010-05-12/drivers/xen/core/machine_reboot.c 2009-12-18 14:19:13.000000000 +0100 @@ -17,6 +17,7 @@ #include #include #include +#include "../../base/base.h" #if defined(__i386__) || defined(__x86_64__) #include @@ -145,47 +146,28 @@ struct suspend { static int take_machine_down(void *_suspend) { struct suspend *suspend = _suspend; - int suspend_cancelled, err; - extern void time_resume(void); + int suspend_cancelled; - if (suspend->fast_suspend) { - BUG_ON(!irqs_disabled()); - } else { - BUG_ON(irqs_disabled()); - - for (;;) { - err = smp_suspend(); - if (err) - return err; - - xenbus_suspend(); - preempt_disable(); - - if (num_online_cpus() == 1) - break; - - preempt_enable(); - xenbus_suspend_cancel(); - } - - local_irq_disable(); - } + BUG_ON(!irqs_disabled()); mm_pin_all(); - gnttab_suspend(); - pre_suspend(); - - /* - * This hypercall returns 1 if suspend was cancelled or the domain was - * merely checkpointed, and 0 if it is resuming in a new domain. - */ - suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); + suspend_cancelled = sysdev_suspend(PMSG_SUSPEND); + if (!suspend_cancelled) { + pre_suspend(); + /* + * This hypercall returns 1 if suspend was cancelled or the domain was + * merely checkpointed, and 0 if it is resuming in a new domain. + */ + suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); + } else + BUG_ON(suspend_cancelled > 0); suspend->resume_notifier(suspend_cancelled); - post_suspend(suspend_cancelled); - gnttab_resume(); + if (suspend_cancelled >= 0) { + post_suspend(suspend_cancelled); + sysdev_resume(); + } if (!suspend_cancelled) { - irq_resume(); #ifdef __x86_64__ /* * Older versions of Xen do not save/restore the user %cr3. @@ -197,10 +179,6 @@ static int take_machine_down(void *_susp current->active_mm->pgd))); #endif } - time_resume(); - - if (!suspend->fast_suspend) - local_irq_enable(); return suspend_cancelled; } @@ -208,8 +186,14 @@ static int take_machine_down(void *_susp int __xen_suspend(int fast_suspend, void (*resume_notifier)(int)) { int err, suspend_cancelled; + const char *what; struct suspend suspend; +#define _check(fn, args...) ({ \ + what = #fn; \ + err = (fn)(args); \ +}) + BUG_ON(smp_processor_id() != 0); BUG_ON(in_interrupt()); @@ -225,41 +209,91 @@ int __xen_suspend(int fast_suspend, void if (num_possible_cpus() == 1) fast_suspend = 0; - if (fast_suspend) { - err = stop_machine_create(); - if (err) - return err; + if (fast_suspend && _check(stop_machine_create)) { + printk(KERN_ERR "%s() failed: %d\n", what, err); + return err; } suspend.fast_suspend = fast_suspend; suspend.resume_notifier = resume_notifier; + if (_check(dpm_suspend_start, PMSG_SUSPEND)) { + if (fast_suspend) + stop_machine_destroy(); + printk(KERN_ERR "%s() failed: %d\n", what, err); + return err; + } + if (fast_suspend) { xenbus_suspend(); + + if (_check(dpm_suspend_noirq, PMSG_SUSPEND)) { + xenbus_suspend_cancel(); + dpm_resume_end(PMSG_RESUME); + stop_machine_destroy(); + printk(KERN_ERR "%s() failed: %d\n", what, err); + return err; + } + err = stop_machine(take_machine_down, &suspend, &cpumask_of_cpu(0)); if (err < 0) xenbus_suspend_cancel(); } else { + BUG_ON(irqs_disabled()); + + for (;;) { + xenbus_suspend(); + + if (!_check(dpm_suspend_noirq, PMSG_SUSPEND) + && _check(smp_suspend)) + dpm_resume_noirq(PMSG_RESUME); + if (err) { + xenbus_suspend_cancel(); + dpm_resume_end(PMSG_RESUME); + printk(KERN_ERR "%s() failed: %d\n", + what, err); + return err; + } + + preempt_disable(); + + if (num_online_cpus() == 1) + break; + + preempt_enable(); + + dpm_resume_noirq(PMSG_RESUME); + + xenbus_suspend_cancel(); + } + + local_irq_disable(); err = take_machine_down(&suspend); + local_irq_enable(); } - if (err < 0) - return err; + dpm_resume_noirq(PMSG_RESUME); - suspend_cancelled = err; - if (!suspend_cancelled) { - xencons_resume(); - xenbus_resume(); - } else { - xenbus_suspend_cancel(); + if (err >= 0) { + suspend_cancelled = err; + if (!suspend_cancelled) { + xencons_resume(); + xenbus_resume(); + } else { + xenbus_suspend_cancel(); + err = 0; + } + + if (!fast_suspend) + smp_resume(); } - if (!fast_suspend) - smp_resume(); - else + dpm_resume_end(PMSG_RESUME); + + if (fast_suspend) stop_machine_destroy(); - return 0; + return err; } #endif --- head-2010-05-12.orig/include/xen/evtchn.h 2010-03-31 14:02:34.000000000 +0200 +++ head-2010-05-12/include/xen/evtchn.h 2010-03-31 14:10:36.000000000 +0200 @@ -108,7 +108,9 @@ int bind_ipi_to_irqhandler( */ void unbind_from_irqhandler(unsigned int irq, void *dev_id); +#ifndef CONFIG_XEN void irq_resume(void); +#endif /* Entry point for notifications into Linux subsystems. */ asmlinkage void evtchn_do_upcall(struct pt_regs *regs); --- head-2010-05-12.orig/include/xen/gnttab.h 2008-11-04 11:13:10.000000000 +0100 +++ head-2010-05-12/include/xen/gnttab.h 2009-11-06 11:10:15.000000000 +0100 @@ -110,8 +110,9 @@ static inline void __gnttab_dma_unmap_pa void gnttab_reset_grant_page(struct page *page); -int gnttab_suspend(void); +#ifndef CONFIG_XEN int gnttab_resume(void); +#endif void *arch_gnttab_alloc_shared(unsigned long *frames);