]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge branch 'for-rc1/xen/core' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2009 22:30:20 +0000 (15:30 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2009 22:30:20 +0000 (15:30 -0700)
* 'for-rc1/xen/core' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen:
  xen: add FIX_TEXT_POKE to fixmap
  xen: honour VCPU availability on boot
  xen: clean up gate trap/interrupt constants
  xen: set _PAGE_NX in __supported_pte_mask before pagetable construction
  xen: resume interrupts before system devices.
  xen/mmu: weaken flush_tlb_other test
  xen/mmu: some early pagetable cleanups
  Xen: Add virt_to_pfn helper function
  x86-64: remove PGE from must-have feature list
  xen: mask XSAVE from cpuid
  NULL noise: arch/x86/xen/smp.c
  xen: remove xen_load_gdt debug
  xen: make xen_load_gdt simpler
  xen: clean up xen_load_gdt
  xen: split construction of p2m mfn tables from registration
  xen: separate p2m allocation from setting
  xen: disable preempt for leave_lazy_mmu

arch/x86/include/asm/required-features.h
arch/x86/include/asm/xen/page.h
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/mmu.h
arch/x86/xen/smp.c
arch/x86/xen/xen-ops.h
drivers/xen/cpu_hotplug.c
drivers/xen/manage.c

index d5cd6c586881f89639d486a92033d3ce19442ca0..a4737dddfd5878da05d20fb819592fc58a117a47 100644 (file)
@@ -50,7 +50,7 @@
 #ifdef CONFIG_X86_64
 #define NEED_PSE       0
 #define NEED_MSR       (1<<(X86_FEATURE_MSR & 31))
-#define NEED_PGE       (1<<(X86_FEATURE_PGE & 31))
+#define NEED_PGE       0
 #define NEED_FXSR      (1<<(X86_FEATURE_FXSR & 31))
 #define NEED_XMM       (1<<(X86_FEATURE_XMM & 31))
 #define NEED_XMM2      (1<<(X86_FEATURE_XMM2 & 31))
index 1a918dde46b503272b26e6070d198460f825f0c0..018a0a400799c33bb85b866b63fd7a2dbb4d4e04 100644 (file)
@@ -124,7 +124,8 @@ static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
 
 /* VIRT <-> MACHINE conversion */
 #define virt_to_machine(v)     (phys_to_machine(XPADDR(__pa(v))))
-#define virt_to_mfn(v)         (pfn_to_mfn(PFN_DOWN(__pa(v))))
+#define virt_to_pfn(v)          (PFN_DOWN(__pa(v)))
+#define virt_to_mfn(v)         (pfn_to_mfn(virt_to_pfn(v)))
 #define mfn_to_virt(m)         (__va(mfn_to_pfn(m) << PAGE_SHIFT))
 
 static inline unsigned long pte_mfn(pte_t pte)
index 82cd39a6cbd3a116b83c5ce1cf30cae0214991f6..f09e8c36ee805d58ba0d6580397305744446cc42 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/fixmap.h>
 #include <asm/processor.h>
+#include <asm/proto.h>
 #include <asm/msr-index.h>
 #include <asm/setup.h>
 #include <asm/desc.h>
@@ -168,21 +169,23 @@ static void __init xen_banner(void)
               xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
 }
 
+static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
+static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
+
 static void xen_cpuid(unsigned int *ax, unsigned int *bx,
                      unsigned int *cx, unsigned int *dx)
 {
+       unsigned maskecx = ~0;
        unsigned maskedx = ~0;
 
        /*
         * Mask out inconvenient features, to try and disable as many
         * unsupported kernel subsystems as possible.
         */
-       if (*ax == 1)
-               maskedx = ~((1 << X86_FEATURE_APIC) |  /* disable APIC */
-                           (1 << X86_FEATURE_ACPI) |  /* disable ACPI */
-                           (1 << X86_FEATURE_MCE)  |  /* disable MCE */
-                           (1 << X86_FEATURE_MCA)  |  /* disable MCA */
-                           (1 << X86_FEATURE_ACC));   /* thermal monitoring */
+       if (*ax == 1) {
+               maskecx = cpuid_leaf1_ecx_mask;
+               maskedx = cpuid_leaf1_edx_mask;
+       }
 
        asm(XEN_EMULATE_PREFIX "cpuid"
                : "=a" (*ax),
@@ -190,9 +193,43 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
                  "=c" (*cx),
                  "=d" (*dx)
                : "0" (*ax), "2" (*cx));
+
+       *cx &= maskecx;
        *dx &= maskedx;
 }
 
+static __init void xen_init_cpuid_mask(void)
+{
+       unsigned int ax, bx, cx, dx;
+
+       cpuid_leaf1_edx_mask =
+               ~((1 << X86_FEATURE_MCE)  |  /* disable MCE */
+                 (1 << X86_FEATURE_MCA)  |  /* disable MCA */
+                 (1 << X86_FEATURE_ACC));   /* thermal monitoring */
+
+       if (!xen_initial_domain())
+               cpuid_leaf1_edx_mask &=
+                       ~((1 << X86_FEATURE_APIC) |  /* disable local APIC */
+                         (1 << X86_FEATURE_ACPI));  /* disable ACPI */
+
+       ax = 1;
+       xen_cpuid(&ax, &bx, &cx, &dx);
+
+       /* cpuid claims we support xsave; try enabling it to see what happens */
+       if (cx & (1 << (X86_FEATURE_XSAVE % 32))) {
+               unsigned long cr4;
+
+               set_in_cr4(X86_CR4_OSXSAVE);
+               
+               cr4 = read_cr4();
+
+               if ((cr4 & X86_CR4_OSXSAVE) == 0)
+                       cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32));
+
+               clear_in_cr4(X86_CR4_OSXSAVE);
+       }
+}
+
 static void xen_set_debugreg(int reg, unsigned long val)
 {
        HYPERVISOR_set_debugreg(reg, val);
@@ -284,12 +321,11 @@ static void xen_set_ldt(const void *addr, unsigned entries)
 
 static void xen_load_gdt(const struct desc_ptr *dtr)
 {
-       unsigned long *frames;
        unsigned long va = dtr->address;
        unsigned int size = dtr->size + 1;
        unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+       unsigned long frames[pages];
        int f;
-       struct multicall_space mcs;
 
        /* A GDT can be up to 64k in size, which corresponds to 8192
           8-byte entries, or 16 4k pages.. */
@@ -297,19 +333,26 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
        BUG_ON(size > 65536);
        BUG_ON(va & ~PAGE_MASK);
 
-       mcs = xen_mc_entry(sizeof(*frames) * pages);
-       frames = mcs.args;
-
        for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
-               frames[f] = arbitrary_virt_to_mfn((void *)va);
+               int level;
+               pte_t *ptep = lookup_address(va, &level);
+               unsigned long pfn, mfn;
+               void *virt;
+
+               BUG_ON(ptep == NULL);
+
+               pfn = pte_pfn(*ptep);
+               mfn = pfn_to_mfn(pfn);
+               virt = __va(PFN_PHYS(pfn));
+
+               frames[f] = mfn;
 
                make_lowmem_page_readonly((void *)va);
-               make_lowmem_page_readonly(mfn_to_virt(frames[f]));
+               make_lowmem_page_readonly(virt);
        }
 
-       MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct));
-
-       xen_mc_issue(PARAVIRT_LAZY_CPU);
+       if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct)))
+               BUG();
 }
 
 static void load_TLS_descriptor(struct thread_struct *t,
@@ -385,7 +428,7 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
 static int cvt_gate_to_trap(int vector, const gate_desc *val,
                            struct trap_info *info)
 {
-       if (val->type != 0xf && val->type != 0xe)
+       if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT)
                return 0;
 
        info->vector = vector;
@@ -393,8 +436,8 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
        info->cs = gate_segment(*val);
        info->flags = val->dpl;
        /* interrupt gates clear IF */
-       if (val->type == 0xe)
-               info->flags |= 4;
+       if (val->type == GATE_INTERRUPT)
+               info->flags |= 1 << 2;
 
        return 1;
 }
@@ -872,7 +915,6 @@ static const struct machine_ops __initdata xen_machine_ops = {
        .emergency_restart = xen_emergency_restart,
 };
 
-
 /* First C function to be called on Xen boot */
 asmlinkage void __init xen_start_kernel(void)
 {
@@ -897,6 +939,8 @@ asmlinkage void __init xen_start_kernel(void)
 
        xen_init_irq_ops();
 
+       xen_init_cpuid_mask();
+
 #ifdef CONFIG_X86_LOCAL_APIC
        /*
         * set up the basic apic ops.
@@ -938,6 +982,11 @@ asmlinkage void __init xen_start_kernel(void)
        if (!xen_initial_domain())
                __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
 
+#ifdef CONFIG_X86_64
+       /* Work out if we support NX */
+       check_efer();
+#endif
+
        /* Don't do the full vcpu_info placement stuff until we have a
           possible map and a non-dummy shared_info. */
        per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
index 2a81838a9ab729954b2e575205a576b58a083766..9842b12124078f9795413a31e784dd96a1fc28a0 100644 (file)
@@ -184,7 +184,7 @@ static inline unsigned p2m_index(unsigned long pfn)
 }
 
 /* Build the parallel p2m_top_mfn structures */
-void xen_setup_mfn_list_list(void)
+static void __init xen_build_mfn_list_list(void)
 {
        unsigned pfn, idx;
 
@@ -198,7 +198,10 @@ void xen_setup_mfn_list_list(void)
                unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
                p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
        }
+}
 
+void xen_setup_mfn_list_list(void)
+{
        BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
 
        HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
@@ -218,6 +221,8 @@ void __init xen_build_dynamic_phys_to_machine(void)
 
                p2m_top[topidx] = &mfn_list[pfn];
        }
+
+       xen_build_mfn_list_list();
 }
 
 unsigned long get_phys_to_machine(unsigned long pfn)
@@ -233,47 +238,74 @@ unsigned long get_phys_to_machine(unsigned long pfn)
 }
 EXPORT_SYMBOL_GPL(get_phys_to_machine);
 
-static void alloc_p2m(unsigned long **pp, unsigned long *mfnp)
+/* install a  new p2m_top page */
+bool install_p2mtop_page(unsigned long pfn, unsigned long *p)
 {
-       unsigned long *p;
+       unsigned topidx = p2m_top_index(pfn);
+       unsigned long **pfnp, *mfnp;
        unsigned i;
 
-       p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
-       BUG_ON(p == NULL);
+       pfnp = &p2m_top[topidx];
+       mfnp = &p2m_top_mfn[topidx];
 
        for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
                p[i] = INVALID_P2M_ENTRY;
 
-       if (cmpxchg(pp, p2m_missing, p) != p2m_missing)
-               free_page((unsigned long)p);
-       else
+       if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) {
                *mfnp = virt_to_mfn(p);
+               return true;
+       }
+
+       return false;
 }
 
-void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+static void alloc_p2m(unsigned long pfn)
 {
-       unsigned topidx, idx;
+       unsigned long *p;
 
-       if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
-               BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
-               return;
-       }
+       p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
+       BUG_ON(p == NULL);
+
+       if (!install_p2mtop_page(pfn, p))
+               free_page((unsigned long)p);
+}
+
+/* Try to install p2m mapping; fail if intermediate bits missing */
+bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+{
+       unsigned topidx, idx;
 
        if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
                BUG_ON(mfn != INVALID_P2M_ENTRY);
-               return;
+               return true;
        }
 
        topidx = p2m_top_index(pfn);
        if (p2m_top[topidx] == p2m_missing) {
-               /* no need to allocate a page to store an invalid entry */
                if (mfn == INVALID_P2M_ENTRY)
-                       return;
-               alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]);
+                       return true;
+               return false;
        }
 
        idx = p2m_index(pfn);
        p2m_top[topidx][idx] = mfn;
+
+       return true;
+}
+
+void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+{
+       if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
+               BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+               return;
+       }
+
+       if (unlikely(!__set_phys_to_machine(pfn, mfn)))  {
+               alloc_p2m(pfn);
+
+               if (!__set_phys_to_machine(pfn, mfn))
+                       BUG();
+       }
 }
 
 unsigned long arbitrary_virt_to_mfn(void *vaddr)
@@ -987,7 +1019,7 @@ static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
        return 0;
 }
 
-void __init xen_mark_init_mm_pinned(void)
+static void __init xen_mark_init_mm_pinned(void)
 {
        xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
 }
@@ -1270,8 +1302,8 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
        } *args;
        struct multicall_space mcs;
 
-       BUG_ON(cpumask_empty(cpus));
-       BUG_ON(!mm);
+       if (cpumask_empty(cpus))
+               return;         /* nothing to do */
 
        mcs = xen_mc_entry(sizeof(*args));
        args = mcs.args;
@@ -1438,10 +1470,29 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
 }
 #endif
 
+static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
+{
+       struct mmuext_op op;
+       op.cmd = cmd;
+       op.arg1.mfn = pfn_to_mfn(pfn);
+       if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
+               BUG();
+}
+
 /* Early in boot, while setting up the initial pagetable, assume
    everything is pinned. */
 static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
 {
+#ifdef CONFIG_FLATMEM
+       BUG_ON(mem_map);        /* should only be used early */
+#endif
+       make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+       pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
+}
+
+/* Used for pmd and pud */
+static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
+{
 #ifdef CONFIG_FLATMEM
        BUG_ON(mem_map);        /* should only be used early */
 #endif
@@ -1450,18 +1501,15 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
 
 /* Early release_pte assumes that all pts are pinned, since there's
    only init_mm and anything attached to that is pinned. */
-static void xen_release_pte_init(unsigned long pfn)
+static __init void xen_release_pte_init(unsigned long pfn)
 {
+       pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
        make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 }
 
-static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
+static __init void xen_release_pmd_init(unsigned long pfn)
 {
-       struct mmuext_op op;
-       op.cmd = cmd;
-       op.arg1.mfn = pfn_to_mfn(pfn);
-       if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
-               BUG();
+       make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 }
 
 /* This needs to make sure the new pte page is pinned iff its being
@@ -1773,6 +1821,9 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 #ifdef CONFIG_X86_LOCAL_APIC
        case FIX_APIC_BASE:     /* maps dummy local APIC */
 #endif
+       case FIX_TEXT_POKE0:
+       case FIX_TEXT_POKE1:
+               /* All local page mappings */
                pte = pfn_pte(phys, prot);
                break;
 
@@ -1819,7 +1870,6 @@ __init void xen_post_allocator_init(void)
        xen_mark_init_mm_pinned();
 }
 
-
 const struct pv_mmu_ops xen_mmu_ops __initdata = {
        .pagetable_setup_start = xen_pagetable_setup_start,
        .pagetable_setup_done = xen_pagetable_setup_done,
@@ -1843,9 +1893,9 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
 
        .alloc_pte = xen_alloc_pte_init,
        .release_pte = xen_release_pte_init,
-       .alloc_pmd = xen_alloc_pte_init,
+       .alloc_pmd = xen_alloc_pmd_init,
        .alloc_pmd_clone = paravirt_nop,
-       .release_pmd = xen_release_pte_init,
+       .release_pmd = xen_release_pmd_init,
 
 #ifdef CONFIG_HIGHPTE
        .kmap_atomic_pte = xen_kmap_atomic_pte,
@@ -1883,8 +1933,8 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
        .make_pud = PV_CALLEE_SAVE(xen_make_pud),
        .set_pgd = xen_set_pgd_hyper,
 
-       .alloc_pud = xen_alloc_pte_init,
-       .release_pud = xen_release_pte_init,
+       .alloc_pud = xen_alloc_pmd_init,
+       .release_pud = xen_release_pmd_init,
 #endif /* PAGETABLE_LEVELS == 4 */
 
        .activate_mm = xen_activate_mm,
index 24d1b44a337d6c3ad9ad1a0b274b07169e9837fd..da7302624897871bb4747ea4fdac50cfffba321e 100644 (file)
@@ -11,6 +11,9 @@ enum pt_level {
 };
 
 
+bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
+bool install_p2mtop_page(unsigned long pfn, unsigned long *p);
+
 void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 
 
index 585a6e330837ffb3a9e37d50be37f93e169832e1..429834ec1687d9b7de965027f3f8d1c862ea88cd 100644 (file)
@@ -317,7 +317,7 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
        BUG_ON(rc);
 
        while(per_cpu(cpu_state, cpu) != CPU_ONLINE) {
-               HYPERVISOR_sched_op(SCHEDOP_yield, 0);
+               HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
                barrier();
        }
 
@@ -422,7 +422,7 @@ static void xen_smp_send_call_function_ipi(const struct cpumask *mask)
        /* Make sure other vcpus get a chance to run if they need to. */
        for_each_cpu(cpu, mask) {
                if (xen_vcpu_stolen(cpu)) {
-                       HYPERVISOR_sched_op(SCHEDOP_yield, 0);
+                       HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
                        break;
                }
        }
index 2f5ef2632ea23bc29d698d043738c1d90545d467..20139464943c7fa6ee3e516c6ead3a6e7c15ef33 100644 (file)
@@ -57,8 +57,6 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
 
 bool xen_vcpu_stolen(int vcpu);
 
-void xen_mark_init_mm_pinned(void);
-
 void xen_setup_vcpu_info_placement(void);
 
 #ifdef CONFIG_SMP
index 5f54c01c156872100ab8e2bf9f1ad74e08152abc..bdfd584ad853ac379e0b3ed9975034e86faa27c4 100644 (file)
@@ -21,29 +21,41 @@ static void disable_hotplug_cpu(int cpu)
        set_cpu_present(cpu, false);
 }
 
-static void vcpu_hotplug(unsigned int cpu)
+static int vcpu_online(unsigned int cpu)
 {
        int err;
        char dir[32], state[32];
 
-       if (!cpu_possible(cpu))
-               return;
-
        sprintf(dir, "cpu/%u", cpu);
        err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
        if (err != 1) {
                printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
-               return;
+               return err;
        }
 
-       if (strcmp(state, "online") == 0) {
+       if (strcmp(state, "online") == 0)
+               return 1;
+       else if (strcmp(state, "offline") == 0)
+               return 0;
+
+       printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n", state, cpu);
+       return -EINVAL;
+}
+static void vcpu_hotplug(unsigned int cpu)
+{
+       if (!cpu_possible(cpu))
+               return;
+
+       switch (vcpu_online(cpu)) {
+       case 1:
                enable_hotplug_cpu(cpu);
-       } else if (strcmp(state, "offline") == 0) {
+               break;
+       case 0:
                (void)cpu_down(cpu);
                disable_hotplug_cpu(cpu);
-       } else {
-               printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
-                      state, cpu);
+               break;
+       default:
+               break;
        }
 }
 
@@ -64,12 +76,20 @@ static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
 static int setup_cpu_watcher(struct notifier_block *notifier,
                              unsigned long event, void *data)
 {
+       int cpu;
        static struct xenbus_watch cpu_watch = {
                .node = "cpu",
                .callback = handle_vcpu_hotplug_event};
 
        (void)register_xenbus_watch(&cpu_watch);
 
+       for_each_possible_cpu(cpu) {
+               if (vcpu_online(cpu) == 0) {
+                       (void)cpu_down(cpu);
+                       cpu_clear(cpu, cpu_present_map);
+               }
+       }
+
        return NOTIFY_DONE;
 }
 
index 0d61db1e7b49bc5f5fd095795e74001dadda1bc3..4b5b84837ee13c85fab14a73c7ab213f74af90e2 100644 (file)
@@ -62,14 +62,15 @@ static int xen_suspend(void *data)
        gnttab_resume();
        xen_mm_unpin_all();
 
-       sysdev_resume();
-
        if (!*cancelled) {
                xen_irq_resume();
                xen_console_resume();
                xen_timer_resume();
        }
 
+       sysdev_resume();
+       device_power_up(PMSG_RESUME);
+
        return 0;
 }