507 lines
12 KiB
Plaintext
507 lines
12 KiB
Plaintext
|
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 <linux/interrupt.h>
|
||
|
#include <linux/sched.h>
|
||
|
#include <linux/kernel_stat.h>
|
||
|
+#include <linux/sysdev.h>
|
||
|
#include <linux/ftrace.h>
|
||
|
#include <linux/version.h>
|
||
|
#include <asm/atomic.h>
|
||
|
@@ -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 <linux/sched.h>
|
||
|
#include <linux/mm.h>
|
||
|
#include <linux/seqlock.h>
|
||
|
+#include <linux/sysdev.h>
|
||
|
#include <xen/interface/xen.h>
|
||
|
#include <xen/gnttab.h>
|
||
|
#include <asm/pgtable.h>
|
||
|
@@ -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 <xen/xencons.h>
|
||
|
#include <xen/cpu_hotplug.h>
|
||
|
#include <xen/interface/vcpu.h>
|
||
|
+#include "../../base/base.h"
|
||
|
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
#include <asm/pci_x86.h>
|
||
|
@@ -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);
|
||
|
|