Merge branch 'for-linus' of git://xenbits.xen.org/people/sstabellini/linux-pvhvm
* 'for-linus' of git://xenbits.xen.org/people/sstabellini/linux-pvhvm: xen: suspend: remove xen_hvm_suspend xen: suspend: pull pre/post suspend hooks out into suspend_info xen: suspend: move arch specific pre/post suspend hooks into generic hooks xen: suspend: refactor non-arch specific pre/post suspend hooks xen: suspend: add "arch" to pre/post suspend hooks xen: suspend: pass extra hypercall argument via suspend_info struct xen: suspend: refactor cancellation flag into a structure xen: suspend: use HYPERVISOR_suspend for PVHVM case instead of open coding xen: switch to new schedop hypercall by default. xen: use new schedop interface for suspend xen: do not respond to unknown xenstore control requests xen: fix compile issue if XEN is enabled but XEN_PVHVM is disabled xen: PV on HVM: support PV spinlocks and IPIs xen: make the ballon driver work for hvm domains xen-blkfront: handle Xen major numbers other than XENVBD xen: do not use xen_info on HVM, set pv_info name to "Xen HVM" xen: no need to delay xen_setup_shutdown_event for hvm guests anymore
This commit is contained in:
commit
76ca078328
13 changed files with 260 additions and 104 deletions
|
@ -37,19 +37,14 @@ xen_mm_unpin_all(void)
|
||||||
/* nothing */
|
/* nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
void xen_pre_device_suspend(void)
|
void
|
||||||
|
xen_arch_pre_suspend()
|
||||||
{
|
{
|
||||||
/* nothing */
|
/* nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xen_pre_suspend()
|
xen_arch_post_suspend(int suspend_cancelled)
|
||||||
{
|
|
||||||
/* nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
xen_post_suspend(int suspend_cancelled)
|
|
||||||
{
|
{
|
||||||
if (suspend_cancelled)
|
if (suspend_cancelled)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -287,7 +287,7 @@ HYPERVISOR_fpu_taskswitch(int set)
|
||||||
static inline int
|
static inline int
|
||||||
HYPERVISOR_sched_op(int cmd, void *arg)
|
HYPERVISOR_sched_op(int cmd, void *arg)
|
||||||
{
|
{
|
||||||
return _hypercall2(int, sched_op_new, cmd, arg);
|
return _hypercall2(int, sched_op, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline long
|
static inline long
|
||||||
|
@ -422,10 +422,17 @@ HYPERVISOR_set_segment_base(int reg, unsigned long value)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
HYPERVISOR_suspend(unsigned long srec)
|
HYPERVISOR_suspend(unsigned long start_info_mfn)
|
||||||
{
|
{
|
||||||
return _hypercall3(int, sched_op, SCHEDOP_shutdown,
|
struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
|
||||||
SHUTDOWN_suspend, srec);
|
|
||||||
|
/*
|
||||||
|
* For a PV guest the tools require that the start_info mfn be
|
||||||
|
* present in rdx/edx when the hypercall is made. Per the
|
||||||
|
* hypercall calling convention this is the third hypercall
|
||||||
|
* argument, which is start_info_mfn here.
|
||||||
|
*/
|
||||||
|
return _hypercall3(int, sched_op, SCHEDOP_shutdown, &r, start_info_mfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
|
|
@ -1284,8 +1284,7 @@ static int init_hvm_pv_info(int *major, int *minor)
|
||||||
|
|
||||||
xen_setup_features();
|
xen_setup_features();
|
||||||
|
|
||||||
pv_info = xen_info;
|
pv_info.name = "Xen HVM";
|
||||||
pv_info.kernel_rpl = 0;
|
|
||||||
|
|
||||||
xen_domain_type = XEN_HVM_DOMAIN;
|
xen_domain_type = XEN_HVM_DOMAIN;
|
||||||
|
|
||||||
|
@ -1331,6 +1330,8 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case CPU_UP_PREPARE:
|
case CPU_UP_PREPARE:
|
||||||
per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
|
per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
|
||||||
|
if (xen_have_vector_callback)
|
||||||
|
xen_init_lock_cpu(cpu);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1355,6 +1356,7 @@ static void __init xen_hvm_guest_init(void)
|
||||||
|
|
||||||
if (xen_feature(XENFEAT_hvm_callback_vector))
|
if (xen_feature(XENFEAT_hvm_callback_vector))
|
||||||
xen_have_vector_callback = 1;
|
xen_have_vector_callback = 1;
|
||||||
|
xen_hvm_smp_init();
|
||||||
register_cpu_notifier(&xen_hvm_cpu_notifier);
|
register_cpu_notifier(&xen_hvm_cpu_notifier);
|
||||||
xen_unplug_emulated_devices();
|
xen_unplug_emulated_devices();
|
||||||
have_vcpu_info_placement = 0;
|
have_vcpu_info_placement = 0;
|
||||||
|
|
|
@ -509,3 +509,41 @@ void __init xen_smp_init(void)
|
||||||
xen_fill_possible_map();
|
xen_fill_possible_map();
|
||||||
xen_init_spinlocks();
|
xen_init_spinlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
|
||||||
|
{
|
||||||
|
native_smp_prepare_cpus(max_cpus);
|
||||||
|
WARN_ON(xen_smp_intr_init(0));
|
||||||
|
|
||||||
|
if (!xen_have_vector_callback)
|
||||||
|
return;
|
||||||
|
xen_init_lock_cpu(0);
|
||||||
|
xen_init_spinlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __cpuinit xen_hvm_cpu_up(unsigned int cpu)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = native_cpu_up(cpu);
|
||||||
|
WARN_ON (xen_smp_intr_init(cpu));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xen_hvm_cpu_die(unsigned int cpu)
|
||||||
|
{
|
||||||
|
unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
|
||||||
|
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
|
||||||
|
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
|
||||||
|
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
|
||||||
|
native_cpu_die(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init xen_hvm_smp_init(void)
|
||||||
|
{
|
||||||
|
smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
|
||||||
|
smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
|
||||||
|
smp_ops.cpu_up = xen_hvm_cpu_up;
|
||||||
|
smp_ops.cpu_die = xen_hvm_cpu_die;
|
||||||
|
smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
|
||||||
|
smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi;
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "xen-ops.h"
|
#include "xen-ops.h"
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
|
|
||||||
void xen_pre_suspend(void)
|
void xen_arch_pre_suspend(void)
|
||||||
{
|
{
|
||||||
xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
|
xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
|
||||||
xen_start_info->console.domU.mfn =
|
xen_start_info->console.domU.mfn =
|
||||||
|
@ -26,8 +26,9 @@ void xen_pre_suspend(void)
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
void xen_hvm_post_suspend(int suspend_cancelled)
|
void xen_arch_hvm_post_suspend(int suspend_cancelled)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_XEN_PVHVM
|
||||||
int cpu;
|
int cpu;
|
||||||
xen_hvm_init_shared_info();
|
xen_hvm_init_shared_info();
|
||||||
xen_callback_vector();
|
xen_callback_vector();
|
||||||
|
@ -37,9 +38,10 @@ void xen_hvm_post_suspend(int suspend_cancelled)
|
||||||
xen_setup_runstate_info(cpu);
|
xen_setup_runstate_info(cpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void xen_post_suspend(int suspend_cancelled)
|
void xen_arch_post_suspend(int suspend_cancelled)
|
||||||
{
|
{
|
||||||
xen_build_mfn_list_list();
|
xen_build_mfn_list_list();
|
||||||
|
|
||||||
|
|
|
@ -64,10 +64,12 @@ void xen_setup_vcpu_info_placement(void);
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
void xen_smp_init(void);
|
void xen_smp_init(void);
|
||||||
|
void __init xen_hvm_smp_init(void);
|
||||||
|
|
||||||
extern cpumask_var_t xen_cpu_initialized_map;
|
extern cpumask_var_t xen_cpu_initialized_map;
|
||||||
#else
|
#else
|
||||||
static inline void xen_smp_init(void) {}
|
static inline void xen_smp_init(void) {}
|
||||||
|
static inline void xen_hvm_smp_init(void) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PARAVIRT_SPINLOCKS
|
#ifdef CONFIG_PARAVIRT_SPINLOCKS
|
||||||
|
|
|
@ -120,6 +120,10 @@ static DEFINE_SPINLOCK(minor_lock);
|
||||||
#define EXTENDED (1<<EXT_SHIFT)
|
#define EXTENDED (1<<EXT_SHIFT)
|
||||||
#define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
|
#define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
|
||||||
#define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
|
#define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
|
||||||
|
#define EMULATED_HD_DISK_MINOR_OFFSET (0)
|
||||||
|
#define EMULATED_HD_DISK_NAME_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET / 256)
|
||||||
|
#define EMULATED_SD_DISK_MINOR_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET + (4 * 16))
|
||||||
|
#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_HD_DISK_NAME_OFFSET + 4)
|
||||||
|
|
||||||
#define DEV_NAME "xvd" /* name in /dev */
|
#define DEV_NAME "xvd" /* name in /dev */
|
||||||
|
|
||||||
|
@ -434,6 +438,65 @@ static void xlvbd_flush(struct blkfront_info *info)
|
||||||
info->feature_flush ? "enabled" : "disabled");
|
info->feature_flush ? "enabled" : "disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
|
||||||
|
{
|
||||||
|
int major;
|
||||||
|
major = BLKIF_MAJOR(vdevice);
|
||||||
|
*minor = BLKIF_MINOR(vdevice);
|
||||||
|
switch (major) {
|
||||||
|
case XEN_IDE0_MAJOR:
|
||||||
|
*offset = (*minor / 64) + EMULATED_HD_DISK_NAME_OFFSET;
|
||||||
|
*minor = ((*minor / 64) * PARTS_PER_DISK) +
|
||||||
|
EMULATED_HD_DISK_MINOR_OFFSET;
|
||||||
|
break;
|
||||||
|
case XEN_IDE1_MAJOR:
|
||||||
|
*offset = (*minor / 64) + 2 + EMULATED_HD_DISK_NAME_OFFSET;
|
||||||
|
*minor = (((*minor / 64) + 2) * PARTS_PER_DISK) +
|
||||||
|
EMULATED_HD_DISK_MINOR_OFFSET;
|
||||||
|
break;
|
||||||
|
case XEN_SCSI_DISK0_MAJOR:
|
||||||
|
*offset = (*minor / PARTS_PER_DISK) + EMULATED_SD_DISK_NAME_OFFSET;
|
||||||
|
*minor = *minor + EMULATED_SD_DISK_MINOR_OFFSET;
|
||||||
|
break;
|
||||||
|
case XEN_SCSI_DISK1_MAJOR:
|
||||||
|
case XEN_SCSI_DISK2_MAJOR:
|
||||||
|
case XEN_SCSI_DISK3_MAJOR:
|
||||||
|
case XEN_SCSI_DISK4_MAJOR:
|
||||||
|
case XEN_SCSI_DISK5_MAJOR:
|
||||||
|
case XEN_SCSI_DISK6_MAJOR:
|
||||||
|
case XEN_SCSI_DISK7_MAJOR:
|
||||||
|
*offset = (*minor / PARTS_PER_DISK) +
|
||||||
|
((major - XEN_SCSI_DISK1_MAJOR + 1) * 16) +
|
||||||
|
EMULATED_SD_DISK_NAME_OFFSET;
|
||||||
|
*minor = *minor +
|
||||||
|
((major - XEN_SCSI_DISK1_MAJOR + 1) * 16 * PARTS_PER_DISK) +
|
||||||
|
EMULATED_SD_DISK_MINOR_OFFSET;
|
||||||
|
break;
|
||||||
|
case XEN_SCSI_DISK8_MAJOR:
|
||||||
|
case XEN_SCSI_DISK9_MAJOR:
|
||||||
|
case XEN_SCSI_DISK10_MAJOR:
|
||||||
|
case XEN_SCSI_DISK11_MAJOR:
|
||||||
|
case XEN_SCSI_DISK12_MAJOR:
|
||||||
|
case XEN_SCSI_DISK13_MAJOR:
|
||||||
|
case XEN_SCSI_DISK14_MAJOR:
|
||||||
|
case XEN_SCSI_DISK15_MAJOR:
|
||||||
|
*offset = (*minor / PARTS_PER_DISK) +
|
||||||
|
((major - XEN_SCSI_DISK8_MAJOR + 8) * 16) +
|
||||||
|
EMULATED_SD_DISK_NAME_OFFSET;
|
||||||
|
*minor = *minor +
|
||||||
|
((major - XEN_SCSI_DISK8_MAJOR + 8) * 16 * PARTS_PER_DISK) +
|
||||||
|
EMULATED_SD_DISK_MINOR_OFFSET;
|
||||||
|
break;
|
||||||
|
case XENVBD_MAJOR:
|
||||||
|
*offset = *minor / PARTS_PER_DISK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printk(KERN_WARNING "blkfront: your disk configuration is "
|
||||||
|
"incorrect, please use an xvd device instead\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
|
static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
|
||||||
struct blkfront_info *info,
|
struct blkfront_info *info,
|
||||||
|
@ -441,7 +504,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
|
||||||
{
|
{
|
||||||
struct gendisk *gd;
|
struct gendisk *gd;
|
||||||
int nr_minors = 1;
|
int nr_minors = 1;
|
||||||
int err = -ENODEV;
|
int err;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
int minor;
|
int minor;
|
||||||
int nr_parts;
|
int nr_parts;
|
||||||
|
@ -456,12 +519,20 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!VDEV_IS_EXTENDED(info->vdevice)) {
|
if (!VDEV_IS_EXTENDED(info->vdevice)) {
|
||||||
minor = BLKIF_MINOR(info->vdevice);
|
err = xen_translate_vdev(info->vdevice, &minor, &offset);
|
||||||
nr_parts = PARTS_PER_DISK;
|
if (err)
|
||||||
|
return err;
|
||||||
|
nr_parts = PARTS_PER_DISK;
|
||||||
} else {
|
} else {
|
||||||
minor = BLKIF_MINOR_EXT(info->vdevice);
|
minor = BLKIF_MINOR_EXT(info->vdevice);
|
||||||
nr_parts = PARTS_PER_EXT_DISK;
|
nr_parts = PARTS_PER_EXT_DISK;
|
||||||
|
offset = minor / nr_parts;
|
||||||
|
if (xen_hvm_domain() && offset <= EMULATED_HD_DISK_NAME_OFFSET + 4)
|
||||||
|
printk(KERN_WARNING "blkfront: vdevice 0x%x might conflict with "
|
||||||
|
"emulated IDE disks,\n\t choose an xvd device name"
|
||||||
|
"from xvde on\n", info->vdevice);
|
||||||
}
|
}
|
||||||
|
err = -ENODEV;
|
||||||
|
|
||||||
if ((minor % nr_parts) == 0)
|
if ((minor % nr_parts) == 0)
|
||||||
nr_minors = nr_parts;
|
nr_minors = nr_parts;
|
||||||
|
@ -475,8 +546,6 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
|
||||||
if (gd == NULL)
|
if (gd == NULL)
|
||||||
goto release;
|
goto release;
|
||||||
|
|
||||||
offset = minor / nr_parts;
|
|
||||||
|
|
||||||
if (nr_minors > 1) {
|
if (nr_minors > 1) {
|
||||||
if (offset < 26)
|
if (offset < 26)
|
||||||
sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset);
|
sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset);
|
||||||
|
|
|
@ -232,7 +232,7 @@ static int increase_reservation(unsigned long nr_pages)
|
||||||
set_phys_to_machine(pfn, frame_list[i]);
|
set_phys_to_machine(pfn, frame_list[i]);
|
||||||
|
|
||||||
/* Link back into the page tables if not highmem. */
|
/* Link back into the page tables if not highmem. */
|
||||||
if (pfn < max_low_pfn) {
|
if (!xen_hvm_domain() && pfn < max_low_pfn) {
|
||||||
int ret;
|
int ret;
|
||||||
ret = HYPERVISOR_update_va_mapping(
|
ret = HYPERVISOR_update_va_mapping(
|
||||||
(unsigned long)__va(pfn << PAGE_SHIFT),
|
(unsigned long)__va(pfn << PAGE_SHIFT),
|
||||||
|
@ -280,7 +280,7 @@ static int decrease_reservation(unsigned long nr_pages)
|
||||||
|
|
||||||
scrub_page(page);
|
scrub_page(page);
|
||||||
|
|
||||||
if (!PageHighMem(page)) {
|
if (!xen_hvm_domain() && !PageHighMem(page)) {
|
||||||
ret = HYPERVISOR_update_va_mapping(
|
ret = HYPERVISOR_update_va_mapping(
|
||||||
(unsigned long)__va(pfn << PAGE_SHIFT),
|
(unsigned long)__va(pfn << PAGE_SHIFT),
|
||||||
__pte_ma(0), 0);
|
__pte_ma(0), 0);
|
||||||
|
@ -392,15 +392,19 @@ static struct notifier_block xenstore_notifier;
|
||||||
|
|
||||||
static int __init balloon_init(void)
|
static int __init balloon_init(void)
|
||||||
{
|
{
|
||||||
unsigned long pfn, extra_pfn_end;
|
unsigned long pfn, nr_pages, extra_pfn_end;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
|
||||||
if (!xen_pv_domain())
|
if (!xen_domain())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
pr_info("xen_balloon: Initialising balloon driver.\n");
|
pr_info("xen_balloon: Initialising balloon driver.\n");
|
||||||
|
|
||||||
balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn);
|
if (xen_pv_domain())
|
||||||
|
nr_pages = xen_start_info->nr_pages;
|
||||||
|
else
|
||||||
|
nr_pages = max_pfn;
|
||||||
|
balloon_stats.current_pages = min(nr_pages, max_pfn);
|
||||||
balloon_stats.target_pages = balloon_stats.current_pages;
|
balloon_stats.target_pages = balloon_stats.current_pages;
|
||||||
balloon_stats.balloon_low = 0;
|
balloon_stats.balloon_low = 0;
|
||||||
balloon_stats.balloon_high = 0;
|
balloon_stats.balloon_high = 0;
|
||||||
|
|
|
@ -34,42 +34,38 @@ enum shutdown_state {
|
||||||
/* Ignore multiple shutdown requests. */
|
/* Ignore multiple shutdown requests. */
|
||||||
static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
|
static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
struct suspend_info {
|
||||||
static int xen_hvm_suspend(void *data)
|
int cancelled;
|
||||||
|
unsigned long arg; /* extra hypercall argument */
|
||||||
|
void (*pre)(void);
|
||||||
|
void (*post)(int cancelled);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void xen_hvm_post_suspend(int cancelled)
|
||||||
{
|
{
|
||||||
int err;
|
xen_arch_hvm_post_suspend(cancelled);
|
||||||
struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
|
|
||||||
int *cancelled = data;
|
|
||||||
|
|
||||||
BUG_ON(!irqs_disabled());
|
|
||||||
|
|
||||||
err = sysdev_suspend(PMSG_SUSPEND);
|
|
||||||
if (err) {
|
|
||||||
printk(KERN_ERR "xen_hvm_suspend: sysdev_suspend failed: %d\n",
|
|
||||||
err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
*cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
|
|
||||||
|
|
||||||
xen_hvm_post_suspend(*cancelled);
|
|
||||||
gnttab_resume();
|
gnttab_resume();
|
||||||
|
|
||||||
if (!*cancelled) {
|
|
||||||
xen_irq_resume();
|
|
||||||
xen_console_resume();
|
|
||||||
xen_timer_resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
sysdev_resume();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void xen_pre_suspend(void)
|
||||||
|
{
|
||||||
|
xen_mm_pin_all();
|
||||||
|
gnttab_suspend();
|
||||||
|
xen_arch_pre_suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xen_post_suspend(int cancelled)
|
||||||
|
{
|
||||||
|
xen_arch_post_suspend(cancelled);
|
||||||
|
gnttab_resume();
|
||||||
|
xen_mm_unpin_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static int xen_suspend(void *data)
|
static int xen_suspend(void *data)
|
||||||
{
|
{
|
||||||
|
struct suspend_info *si = data;
|
||||||
int err;
|
int err;
|
||||||
int *cancelled = data;
|
|
||||||
|
|
||||||
BUG_ON(!irqs_disabled());
|
BUG_ON(!irqs_disabled());
|
||||||
|
|
||||||
|
@ -80,22 +76,20 @@ static int xen_suspend(void *data)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
xen_mm_pin_all();
|
if (si->pre)
|
||||||
gnttab_suspend();
|
si->pre();
|
||||||
xen_pre_suspend();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This hypercall returns 1 if suspend was cancelled
|
* This hypercall returns 1 if suspend was cancelled
|
||||||
* or the domain was merely checkpointed, and 0 if it
|
* or the domain was merely checkpointed, and 0 if it
|
||||||
* is resuming in a new domain.
|
* is resuming in a new domain.
|
||||||
*/
|
*/
|
||||||
*cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
|
si->cancelled = HYPERVISOR_suspend(si->arg);
|
||||||
|
|
||||||
xen_post_suspend(*cancelled);
|
if (si->post)
|
||||||
gnttab_resume();
|
si->post(si->cancelled);
|
||||||
xen_mm_unpin_all();
|
|
||||||
|
|
||||||
if (!*cancelled) {
|
if (!si->cancelled) {
|
||||||
xen_irq_resume();
|
xen_irq_resume();
|
||||||
xen_console_resume();
|
xen_console_resume();
|
||||||
xen_timer_resume();
|
xen_timer_resume();
|
||||||
|
@ -109,7 +103,7 @@ static int xen_suspend(void *data)
|
||||||
static void do_suspend(void)
|
static void do_suspend(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
int cancelled = 1;
|
struct suspend_info si;
|
||||||
|
|
||||||
shutting_down = SHUTDOWN_SUSPEND;
|
shutting_down = SHUTDOWN_SUSPEND;
|
||||||
|
|
||||||
|
@ -139,20 +133,29 @@ static void do_suspend(void)
|
||||||
goto out_resume;
|
goto out_resume;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xen_hvm_domain())
|
si.cancelled = 1;
|
||||||
err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0));
|
|
||||||
else
|
if (xen_hvm_domain()) {
|
||||||
err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
|
si.arg = 0UL;
|
||||||
|
si.pre = NULL;
|
||||||
|
si.post = &xen_hvm_post_suspend;
|
||||||
|
} else {
|
||||||
|
si.arg = virt_to_mfn(xen_start_info);
|
||||||
|
si.pre = &xen_pre_suspend;
|
||||||
|
si.post = &xen_post_suspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stop_machine(xen_suspend, &si, cpumask_of(0));
|
||||||
|
|
||||||
dpm_resume_noirq(PMSG_RESUME);
|
dpm_resume_noirq(PMSG_RESUME);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
|
printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
|
||||||
cancelled = 1;
|
si.cancelled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_resume:
|
out_resume:
|
||||||
if (!cancelled) {
|
if (!si.cancelled) {
|
||||||
xen_arch_resume();
|
xen_arch_resume();
|
||||||
xs_resume();
|
xs_resume();
|
||||||
} else
|
} else
|
||||||
|
@ -172,12 +175,39 @@ static void do_suspend(void)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
|
struct shutdown_handler {
|
||||||
|
const char *command;
|
||||||
|
void (*cb)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void do_poweroff(void)
|
||||||
|
{
|
||||||
|
shutting_down = SHUTDOWN_POWEROFF;
|
||||||
|
orderly_poweroff(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_reboot(void)
|
||||||
|
{
|
||||||
|
shutting_down = SHUTDOWN_POWEROFF; /* ? */
|
||||||
|
ctrl_alt_del();
|
||||||
|
}
|
||||||
|
|
||||||
static void shutdown_handler(struct xenbus_watch *watch,
|
static void shutdown_handler(struct xenbus_watch *watch,
|
||||||
const char **vec, unsigned int len)
|
const char **vec, unsigned int len)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
struct xenbus_transaction xbt;
|
struct xenbus_transaction xbt;
|
||||||
int err;
|
int err;
|
||||||
|
static struct shutdown_handler handlers[] = {
|
||||||
|
{ "poweroff", do_poweroff },
|
||||||
|
{ "halt", do_poweroff },
|
||||||
|
{ "reboot", do_reboot },
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
{ "suspend", do_suspend },
|
||||||
|
#endif
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
||||||
|
static struct shutdown_handler *handler;
|
||||||
|
|
||||||
if (shutting_down != SHUTDOWN_INVALID)
|
if (shutting_down != SHUTDOWN_INVALID)
|
||||||
return;
|
return;
|
||||||
|
@ -194,7 +224,14 @@ static void shutdown_handler(struct xenbus_watch *watch,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
xenbus_write(xbt, "control", "shutdown", "");
|
for (handler = &handlers[0]; handler->command; handler++) {
|
||||||
|
if (strcmp(str, handler->command) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only acknowledge commands which we are prepared to handle. */
|
||||||
|
if (handler->cb)
|
||||||
|
xenbus_write(xbt, "control", "shutdown", "");
|
||||||
|
|
||||||
err = xenbus_transaction_end(xbt, 0);
|
err = xenbus_transaction_end(xbt, 0);
|
||||||
if (err == -EAGAIN) {
|
if (err == -EAGAIN) {
|
||||||
|
@ -202,17 +239,8 @@ static void shutdown_handler(struct xenbus_watch *watch,
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(str, "poweroff") == 0 ||
|
if (handler->cb) {
|
||||||
strcmp(str, "halt") == 0) {
|
handler->cb();
|
||||||
shutting_down = SHUTDOWN_POWEROFF;
|
|
||||||
orderly_poweroff(false);
|
|
||||||
} else if (strcmp(str, "reboot") == 0) {
|
|
||||||
shutting_down = SHUTDOWN_POWEROFF; /* ? */
|
|
||||||
ctrl_alt_del();
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
} else if (strcmp(str, "suspend") == 0) {
|
|
||||||
do_suspend();
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
|
printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
|
||||||
shutting_down = SHUTDOWN_INVALID;
|
shutting_down = SHUTDOWN_INVALID;
|
||||||
|
@ -291,27 +319,18 @@ static int shutdown_event(struct notifier_block *notifier,
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init __setup_shutdown_event(void)
|
|
||||||
{
|
|
||||||
/* Delay initialization in the PV on HVM case */
|
|
||||||
if (xen_hvm_domain())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!xen_pv_domain())
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return xen_setup_shutdown_event();
|
|
||||||
}
|
|
||||||
|
|
||||||
int xen_setup_shutdown_event(void)
|
int xen_setup_shutdown_event(void)
|
||||||
{
|
{
|
||||||
static struct notifier_block xenstore_notifier = {
|
static struct notifier_block xenstore_notifier = {
|
||||||
.notifier_call = shutdown_event
|
.notifier_call = shutdown_event
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!xen_domain())
|
||||||
|
return -ENODEV;
|
||||||
register_xenstore_notifier(&xenstore_notifier);
|
register_xenstore_notifier(&xenstore_notifier);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
|
EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
|
||||||
|
|
||||||
subsys_initcall(__setup_shutdown_event);
|
subsys_initcall(xen_setup_shutdown_event);
|
||||||
|
|
|
@ -156,9 +156,6 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
xenbus_probe(NULL);
|
xenbus_probe(NULL);
|
||||||
ret = xen_setup_shutdown_event();
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -97,4 +97,25 @@ DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response);
|
||||||
#define VDISK_REMOVABLE 0x2
|
#define VDISK_REMOVABLE 0x2
|
||||||
#define VDISK_READONLY 0x4
|
#define VDISK_READONLY 0x4
|
||||||
|
|
||||||
|
/* Xen-defined major numbers for virtual disks, they look strangely
|
||||||
|
* familiar */
|
||||||
|
#define XEN_IDE0_MAJOR 3
|
||||||
|
#define XEN_IDE1_MAJOR 22
|
||||||
|
#define XEN_SCSI_DISK0_MAJOR 8
|
||||||
|
#define XEN_SCSI_DISK1_MAJOR 65
|
||||||
|
#define XEN_SCSI_DISK2_MAJOR 66
|
||||||
|
#define XEN_SCSI_DISK3_MAJOR 67
|
||||||
|
#define XEN_SCSI_DISK4_MAJOR 68
|
||||||
|
#define XEN_SCSI_DISK5_MAJOR 69
|
||||||
|
#define XEN_SCSI_DISK6_MAJOR 70
|
||||||
|
#define XEN_SCSI_DISK7_MAJOR 71
|
||||||
|
#define XEN_SCSI_DISK8_MAJOR 128
|
||||||
|
#define XEN_SCSI_DISK9_MAJOR 129
|
||||||
|
#define XEN_SCSI_DISK10_MAJOR 130
|
||||||
|
#define XEN_SCSI_DISK11_MAJOR 131
|
||||||
|
#define XEN_SCSI_DISK12_MAJOR 132
|
||||||
|
#define XEN_SCSI_DISK13_MAJOR 133
|
||||||
|
#define XEN_SCSI_DISK14_MAJOR 134
|
||||||
|
#define XEN_SCSI_DISK15_MAJOR 135
|
||||||
|
|
||||||
#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
|
#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#define __HYPERVISOR_stack_switch 3
|
#define __HYPERVISOR_stack_switch 3
|
||||||
#define __HYPERVISOR_set_callbacks 4
|
#define __HYPERVISOR_set_callbacks 4
|
||||||
#define __HYPERVISOR_fpu_taskswitch 5
|
#define __HYPERVISOR_fpu_taskswitch 5
|
||||||
#define __HYPERVISOR_sched_op 6
|
#define __HYPERVISOR_sched_op_compat 6
|
||||||
#define __HYPERVISOR_dom0_op 7
|
#define __HYPERVISOR_dom0_op 7
|
||||||
#define __HYPERVISOR_set_debugreg 8
|
#define __HYPERVISOR_set_debugreg 8
|
||||||
#define __HYPERVISOR_get_debugreg 9
|
#define __HYPERVISOR_get_debugreg 9
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
#define __HYPERVISOR_mmuext_op 26
|
#define __HYPERVISOR_mmuext_op 26
|
||||||
#define __HYPERVISOR_acm_op 27
|
#define __HYPERVISOR_acm_op 27
|
||||||
#define __HYPERVISOR_nmi_op 28
|
#define __HYPERVISOR_nmi_op 28
|
||||||
#define __HYPERVISOR_sched_op_new 29
|
#define __HYPERVISOR_sched_op 29
|
||||||
#define __HYPERVISOR_callback_op 30
|
#define __HYPERVISOR_callback_op 30
|
||||||
#define __HYPERVISOR_xenoprof_op 31
|
#define __HYPERVISOR_xenoprof_op 31
|
||||||
#define __HYPERVISOR_event_channel_op 32
|
#define __HYPERVISOR_event_channel_op 32
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
|
|
||||||
DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
|
DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
|
||||||
|
|
||||||
void xen_pre_suspend(void);
|
void xen_arch_pre_suspend(void);
|
||||||
void xen_post_suspend(int suspend_cancelled);
|
void xen_arch_post_suspend(int suspend_cancelled);
|
||||||
void xen_hvm_post_suspend(int suspend_cancelled);
|
void xen_arch_hvm_post_suspend(int suspend_cancelled);
|
||||||
|
|
||||||
void xen_mm_pin_all(void);
|
void xen_mm_pin_all(void);
|
||||||
void xen_mm_unpin_all(void);
|
void xen_mm_unpin_all(void);
|
||||||
|
|
Loading…
Reference in a new issue