From: jbeulich@novell.com Subject: use base kernel suspend/resume infrastructure Patch-mainline: obsolete ... rather than calling just a few functions explicitly. Index: head-2008-12-01/arch/x86/kernel/time_32-xen.c =================================================================== --- head-2008-12-01.orig/arch/x86/kernel/time_32-xen.c 2008-12-01 12:07:15.000000000 +0100 +++ head-2008-12-01/arch/x86/kernel/time_32-xen.c 2008-12-01 12:07:30.000000000 +0100 @@ -88,6 +88,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(); @@ -599,6 +603,25 @@ void mark_tsc_unstable(char *reason) } EXPORT_SYMBOL_GPL(mark_tsc_unstable); +static void init_missing_ticks_accounting(unsigned int cpu) +{ + struct vcpu_register_runstate_memory_area area; + struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); + int rc; + + memset(runstate, 0, sizeof(*runstate)); + + area.addr.v = runstate; + rc = HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area); + WARN_ON(rc && rc != -ENOSYS); + + 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(void) @@ -635,11 +658,34 @@ static cycle_t xen_clocksource_read(void #endif } +/* No locking required. Interrupts are disabled on all CPUs. */ static void xen_clocksource_resume(void) { - 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; + + update_wallclock(); - time_resume(); cs_last = local_clock(); } @@ -654,25 +700,6 @@ static struct clocksource clocksource_xe .resume = xen_clocksource_resume, }; -static void init_missing_ticks_accounting(unsigned int cpu) -{ - struct vcpu_register_runstate_memory_area area; - struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); - int rc; - - memset(runstate, 0, sizeof(*runstate)); - - area.addr.v = runstate; - rc = HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area); - WARN_ON(rc && rc != -ENOSYS); - - per_cpu(processed_blocked_time, cpu) = - runstate->time[RUNSTATE_blocked]; - per_cpu(processed_stolen_time, cpu) = - runstate->time[RUNSTATE_runnable] + - runstate->time[RUNSTATE_offline]; -} - unsigned long xen_read_persistent_clock(void) { const shared_info_t *s = HYPERVISOR_shared_info; @@ -717,10 +744,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(); @@ -844,35 +867,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]; Index: head-2008-12-01/drivers/xen/core/evtchn.c =================================================================== --- head-2008-12-01.orig/drivers/xen/core/evtchn.c 2008-12-02 09:11:31.000000000 +0100 +++ head-2008-12-01/drivers/xen/core/evtchn.c 2008-12-02 09:23:09.000000000 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1061,9 +1062,20 @@ 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 evtchn_status status; + + /* Avoid doing anything in the 'suspend cancelled' case. */ + status.dom = DOMID_SELF; + status.port = evtchn_from_irq(__get_cpu_var(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(); @@ -1094,7 +1106,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 #if defined(CONFIG_X86_IO_APIC) Index: head-2008-12-01/drivers/xen/core/gnttab.c =================================================================== --- head-2008-12-01.orig/drivers/xen/core/gnttab.c 2008-12-02 09:26:17.000000000 +0100 +++ head-2008-12-01/drivers/xen/core/gnttab.c 2008-12-02 09:26:51.000000000 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -704,23 +705,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 */ @@ -800,6 +815,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(); Index: head-2008-12-01/drivers/xen/core/machine_reboot.c =================================================================== --- head-2008-12-01.orig/drivers/xen/core/machine_reboot.c 2008-12-01 11:49:07.000000000 +0100 +++ head-2008-12-01/drivers/xen/core/machine_reboot.c 2008-12-01 12:07:30.000000000 +0100 @@ -17,6 +17,7 @@ #include #include #include +#include "../../base/base.h" #if defined(__i386__) || defined(__x86_64__) @@ -149,7 +150,6 @@ static int take_machine_down(void *_susp { struct suspend *suspend = _suspend; int suspend_cancelled, err; - extern void time_resume(void); if (suspend->fast_suspend) { BUG_ON(!irqs_disabled()); @@ -175,20 +175,23 @@ static int take_machine_down(void *_susp } 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_FREEZE); + 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. @@ -200,7 +203,6 @@ static int take_machine_down(void *_susp current->active_mm->pgd))); #endif } - time_resume(); if (!suspend->fast_suspend) local_irq_enable(); Index: head-2008-12-01/include/xen/evtchn.h =================================================================== --- head-2008-12-01.orig/include/xen/evtchn.h 2008-12-02 09:25:52.000000000 +0100 +++ head-2008-12-01/include/xen/evtchn.h 2008-12-01 12:07:30.000000000 +0100 @@ -93,7 +93,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); Index: head-2008-12-01/include/xen/gnttab.h =================================================================== --- head-2008-12-01.orig/include/xen/gnttab.h 2008-12-02 09:25:52.000000000 +0100 +++ head-2008-12-01/include/xen/gnttab.h 2008-12-01 12:07:30.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);