[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] PV-on-HVM: More save/restore fixes.
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1176279364 -3600 # Node ID 5d7fb634ec1a1c127316ccb2cacbf473c8c77377 # Parent 87e2174b8a0dddcfaad6963c4cb81f38953d2810 PV-on-HVM: More save/restore fixes. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- linux-2.6-xen-sparse/drivers/xen/core/gnttab.c | 27 -- unmodified_drivers/linux-2.6/platform-pci/evtchn.c | 150 ++++++++----- unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c | 73 +++++- unmodified_drivers/linux-2.6/platform-pci/platform-pci.c | 34 +- unmodified_drivers/linux-2.6/platform-pci/platform-pci.h | 11 5 files changed, 186 insertions(+), 109 deletions(-) diff -r 87e2174b8a0d -r 5d7fb634ec1a linux-2.6-xen-sparse/drivers/xen/core/gnttab.c --- a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c Tue Apr 10 20:00:45 2007 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c Wed Apr 11 09:16:04 2007 +0100 @@ -60,9 +60,6 @@ static DEFINE_SPINLOCK(gnttab_list_lock) static DEFINE_SPINLOCK(gnttab_list_lock); static struct grant_entry *shared; -#ifndef CONFIG_XEN -static unsigned long resume_frames; -#endif static struct gnttab_free_callback *gnttab_free_callback_list; @@ -514,6 +511,8 @@ int gnttab_suspend(void) #include <platform-pci.h> +static unsigned long resume_frames; + static int gnttab_map(unsigned int start_idx, unsigned int end_idx) { struct xen_add_to_physmap xatp; @@ -543,23 +542,17 @@ int gnttab_resume(void) if (max_nr_gframes < nr_gframes) return -ENOSYS; - resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); + if (!resume_frames) { + resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); + shared = ioremap(resume_frames, PAGE_SIZE * max_nr_gframes); + if (shared == NULL) { + printk("error to ioremap gnttab share frames\n"); + return -1; + } + } gnttab_map(0, nr_gframes - 1); - shared = ioremap(resume_frames, PAGE_SIZE * max_nr_gframes); - if (shared == NULL) { - printk("error to ioremap gnttab share frames\n"); - return -1; - } - - return 0; -} - -int gnttab_suspend(void) -{ - iounmap(shared); - resume_frames = 0; return 0; } diff -r 87e2174b8a0d -r 5d7fb634ec1a unmodified_drivers/linux-2.6/platform-pci/evtchn.c --- a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c Tue Apr 10 20:00:45 2007 +0100 +++ b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c Wed Apr 11 09:16:04 2007 +0100 @@ -28,8 +28,10 @@ * IN THE SOFTWARE. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/spinlock.h> #include <xen/evtchn.h> #include <xen/interface/hvm/ioreq.h> #include <xen/features.h> @@ -41,29 +43,37 @@ void *shared_info_area; -static DEFINE_MUTEX(irq_evtchn_mutex); - #define is_valid_evtchn(x) ((x) != 0) #define evtchn_from_irq(x) (irq_evtchn[irq].evtchn) static struct { + spinlock_t lock; irqreturn_t(*handler) (int, void *, struct pt_regs *); void *dev_id; int evtchn; int close:1; /* close on unbind_from_irqhandler()? */ int inuse:1; + int in_handler:1; } irq_evtchn[256]; static int evtchn_to_irq[NR_EVENT_CHANNELS] = { [0 ... NR_EVENT_CHANNELS-1] = -1 }; -static int find_unbound_irq(void) +static DEFINE_SPINLOCK(irq_alloc_lock); + +static int alloc_xen_irq(void) { static int warned; int irq; - for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++) - if (!irq_evtchn[irq].inuse) - return irq; + spin_lock(&irq_alloc_lock); + + for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++) { + if (irq_evtchn[irq].inuse) + continue; + irq_evtchn[irq].inuse = 1; + spin_unlock(&irq_alloc_lock); + return irq; + } if (!warned) { warned = 1; @@ -71,7 +81,16 @@ static int find_unbound_irq(void) "increase irq_evtchn[] size in evtchn.c.\n"); } + spin_unlock(&irq_alloc_lock); + return -ENOSPC; +} + +static void free_xen_irq(int irq) +{ + spin_lock(&irq_alloc_lock); + irq_evtchn[irq].inuse = 0; + spin_unlock(&irq_alloc_lock); } int irq_to_evtchn_port(int irq) @@ -93,8 +112,7 @@ void unmask_evtchn(int port) shared_info_t *s = shared_info_area; vcpu_info_t *vcpu_info; - preempt_disable(); - cpu = smp_processor_id(); + cpu = get_cpu(); vcpu_info = &s->vcpu_info[cpu]; /* Slow path (hypercall) if this is a non-local port. We only @@ -103,7 +121,7 @@ void unmask_evtchn(int port) evtchn_unmask_t op = { .port = port }; (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &op); - preempt_enable(); + put_cpu(); return; } @@ -121,7 +139,8 @@ void unmask_evtchn(int port) if (!vcpu_info->evtchn_upcall_mask) force_evtchn_callback(); } - preempt_enable(); + + put_cpu(); } EXPORT_SYMBOL(unmask_evtchn); @@ -135,20 +154,19 @@ int bind_listening_port_to_irqhandler( struct evtchn_alloc_unbound alloc_unbound; int err, irq; - mutex_lock(&irq_evtchn_mutex); - - irq = find_unbound_irq(); - if (irq < 0) { - mutex_unlock(&irq_evtchn_mutex); + irq = alloc_xen_irq(); + if (irq < 0) return irq; - } + + spin_lock_irq(&irq_evtchn[irq].lock); alloc_unbound.dom = DOMID_SELF; alloc_unbound.remote_dom = remote_domain; err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); if (err) { - mutex_unlock(&irq_evtchn_mutex); + spin_unlock_irq(&irq_evtchn[irq].lock); + free_xen_irq(irq); return err; } @@ -156,13 +174,13 @@ int bind_listening_port_to_irqhandler( irq_evtchn[irq].dev_id = dev_id; irq_evtchn[irq].evtchn = alloc_unbound.port; irq_evtchn[irq].close = 1; - irq_evtchn[irq].inuse = 1; evtchn_to_irq[alloc_unbound.port] = irq; unmask_evtchn(alloc_unbound.port); - mutex_unlock(&irq_evtchn_mutex); + spin_unlock_irq(&irq_evtchn[irq].lock); + return irq; } EXPORT_SYMBOL(bind_listening_port_to_irqhandler); @@ -176,34 +194,34 @@ int bind_caller_port_to_irqhandler( { int irq; - mutex_lock(&irq_evtchn_mutex); - - irq = find_unbound_irq(); - if (irq < 0) { - mutex_unlock(&irq_evtchn_mutex); + irq = alloc_xen_irq(); + if (irq < 0) return irq; - } + + spin_lock_irq(&irq_evtchn[irq].lock); irq_evtchn[irq].handler = handler; irq_evtchn[irq].dev_id = dev_id; irq_evtchn[irq].evtchn = caller_port; irq_evtchn[irq].close = 0; - irq_evtchn[irq].inuse = 1; evtchn_to_irq[caller_port] = irq; unmask_evtchn(caller_port); - mutex_unlock(&irq_evtchn_mutex); + spin_unlock_irq(&irq_evtchn[irq].lock); + return irq; } EXPORT_SYMBOL(bind_caller_port_to_irqhandler); void unbind_from_irqhandler(unsigned int irq, void *dev_id) { - int evtchn = evtchn_from_irq(irq); - - mutex_lock(&irq_evtchn_mutex); + int evtchn; + + spin_lock_irq(&irq_evtchn[irq].lock); + + evtchn = evtchn_from_irq(irq); if (is_valid_evtchn(evtchn)) { evtchn_to_irq[irq] = -1; @@ -216,21 +234,28 @@ void unbind_from_irqhandler(unsigned int irq_evtchn[irq].handler = NULL; irq_evtchn[irq].evtchn = 0; - irq_evtchn[irq].inuse = 0; - - mutex_unlock(&irq_evtchn_mutex); + + spin_unlock_irq(&irq_evtchn[irq].lock); + + while (irq_evtchn[irq].in_handler) + cpu_relax(); + + free_xen_irq(irq); } EXPORT_SYMBOL(unbind_from_irqhandler); void notify_remote_via_irq(int irq) { - int evtchn = evtchn_from_irq(irq); + int evtchn; + + evtchn = evtchn_from_irq(irq); if (is_valid_evtchn(evtchn)) notify_remote_via_evtchn(evtchn); } EXPORT_SYMBOL(notify_remote_via_irq); -irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t evtchn_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { unsigned int l1i, port; /* XXX: All events are bound to vcpu0 but irq may be redirected. */ @@ -249,13 +274,30 @@ irqreturn_t evtchn_interrupt(int irq, vo while ((l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i])) { port = (l1i * BITS_PER_LONG) + __ffs(l2); synch_clear_bit(port, &s->evtchn_pending[0]); + irq = evtchn_to_irq[port]; - if ((irq >= 0) && - ((handler = irq_evtchn[irq].handler) != NULL)) - handler(irq, irq_evtchn[irq].dev_id, regs); - else - printk(KERN_WARNING "unexpected event channel " - "upcall on port %d!\n", port); + if (irq < 0) + continue; + + spin_lock(&irq_evtchn[irq].lock); + handler = irq_evtchn[irq].handler; + dev_id = irq_evtchn[irq].dev_id; + if (unlikely(handler == NULL)) { + printk("Xen IRQ%d (port %d) has no handler!\n", + irq, port); + spin_unlock(&irq_evtchn[irq].lock); + continue; + } + irq_evtchn[irq].in_handler = 1; + spin_unlock(&irq_evtchn[irq].lock); + + local_irq_enable(); + handler(irq, irq_evtchn[irq].dev_id, regs); + local_irq_disable(); + + spin_lock(&irq_evtchn[irq].lock); + irq_evtchn[irq].in_handler = 0; + spin_unlock(&irq_evtchn[irq].lock); } } @@ -267,16 +309,6 @@ void force_evtchn_callback(void) (void)HYPERVISOR_xen_version(0, NULL); } EXPORT_SYMBOL(force_evtchn_callback); - -void irq_suspend(void) -{ - mutex_lock(&irq_evtchn_mutex); -} - -void irq_suspend_cancel(void) -{ - mutex_unlock(&irq_evtchn_mutex); -} void irq_resume(void) { @@ -289,6 +321,16 @@ void irq_resume(void) for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++) irq_evtchn[irq].evtchn = 0; - - mutex_unlock(&irq_evtchn_mutex); -} +} + +int xen_irq_init(struct pci_dev *pdev) +{ + int irq; + + for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++) + spin_lock_init(&irq_evtchn[irq].lock); + + return request_irq(pdev->irq, evtchn_interrupt, + SA_SHIRQ | SA_SAMPLE_RANDOM | SA_INTERRUPT, + "xen-platform-pci", pdev); +} diff -r 87e2174b8a0d -r 5d7fb634ec1a unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c --- a/unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c Tue Apr 10 20:00:45 2007 +0100 +++ b/unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c Wed Apr 11 09:16:04 2007 +0100 @@ -1,24 +1,81 @@ #include <linux/config.h> +#include <linux/stop_machine.h> +#include <xen/evtchn.h> +#include <xen/gnttab.h> #include <xen/xenbus.h> #include "platform-pci.h" #include <asm/hypervisor.h> -int __xen_suspend(int fast_suspend) +/* + * Spinning prevents, for example, APs touching grant table entries while + * the shared grant table is not mapped into the address space imemdiately + * after resume. + */ +static void ap_suspend(void *_ap_spin) +{ + int *ap_spin = _ap_spin; + + BUG_ON(!irqs_disabled()); + + while (*ap_spin) { + cpu_relax(); + HYPERVISOR_yield(); + } +} + +static int bp_suspend(void) { int suspend_cancelled; - xenbus_suspend(); - platform_pci_suspend(); + BUG_ON(!irqs_disabled()); suspend_cancelled = HYPERVISOR_shutdown(SHUTDOWN_suspend); - if (suspend_cancelled) { - platform_pci_suspend_cancel(); + if (!suspend_cancelled) { + platform_pci_resume(); + gnttab_resume(); + irq_resume(); + } + + return suspend_cancelled; +} + +int __xen_suspend(int fast_suspend) +{ + int err, suspend_cancelled, ap_spin; + + xenbus_suspend(); + + preempt_disable(); + + /* Prevent any races with evtchn_interrupt() handler. */ + disable_irq(xen_platform_pdev->irq); + + ap_spin = 1; + smp_mb(); + + err = smp_call_function(ap_suspend, &ap_spin, 0, 0); + if (err < 0) { + preempt_enable(); xenbus_suspend_cancel(); - } else { - platform_pci_resume(); + return err; + } + + local_irq_disable(); + suspend_cancelled = bp_suspend(); + local_irq_enable(); + + smp_mb(); + ap_spin = 0; + + enable_irq(xen_platform_pdev->irq); + + preempt_enable(); + + if (!suspend_cancelled) xenbus_resume(); - } + else + xenbus_suspend_cancel(); return 0; } diff -r 87e2174b8a0d -r 5d7fb634ec1a unmodified_drivers/linux-2.6/platform-pci/platform-pci.c --- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c Tue Apr 10 20:00:45 2007 +0100 +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c Wed Apr 11 09:16:04 2007 +0100 @@ -40,7 +40,6 @@ #include <xen/interface/hvm/params.h> #include <xen/features.h> #include <xen/evtchn.h> -#include <xen/gnttab.h> #ifdef __ia64__ #include <asm/xen/xencomm.h> #endif @@ -61,6 +60,8 @@ MODULE_AUTHOR("ssmith@xxxxxxxxxxxxx"); MODULE_AUTHOR("ssmith@xxxxxxxxxxxxx"); MODULE_DESCRIPTION("Xen platform PCI device"); MODULE_LICENSE("GPL"); + +struct pci_dev *xen_platform_pdev; static unsigned long shared_info_frame; static uint64_t callback_via; @@ -88,8 +89,6 @@ static int __devinit init_xen_info(void) ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE); if (shared_info_area == NULL) panic("can't map shared info\n"); - - gnttab_init(); return 0; } @@ -199,8 +198,10 @@ static int set_callback_via(uint64_t via return HYPERVISOR_hvm_op(HVMOP_set_param, &a); } +int xen_irq_init(struct pci_dev *pdev); int xenbus_init(void); int xen_reboot_init(void); +int gnttab_init(void); static int __devinit platform_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -208,6 +209,10 @@ static int __devinit platform_pci_init(s int i, ret; long ioaddr, iolen; long mmio_addr, mmio_len; + + if (xen_platform_pdev) + return -EBUSY; + xen_platform_pdev = pdev; i = pci_enable_device(pdev); if (i) @@ -249,9 +254,10 @@ static int __devinit platform_pci_init(s if ((ret = init_xen_info())) goto out; - if ((ret = request_irq(pdev->irq, evtchn_interrupt, - SA_SHIRQ | SA_SAMPLE_RANDOM, - "xen-platform-pci", pdev))) + if ((ret = gnttab_init())) + goto out; + + if ((ret = xen_irq_init(pdev))) goto out; if ((ret = set_callback_via(callback_via))) @@ -291,18 +297,6 @@ static struct pci_driver platform_driver }; static int pci_device_registered; - -void platform_pci_suspend(void) -{ - gnttab_suspend(); - irq_suspend(); -} - -void platform_pci_suspend_cancel(void) -{ - irq_suspend_cancel(); - gnttab_resume(); -} void platform_pci_resume(void) { @@ -319,12 +313,8 @@ void platform_pci_resume(void) if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) BUG(); - irq_resume(); - if (set_callback_via(callback_via)) printk("platform_pci_resume failure!\n"); - - gnttab_resume(); } static int __init platform_pci_module_init(void) diff -r 87e2174b8a0d -r 5d7fb634ec1a unmodified_drivers/linux-2.6/platform-pci/platform-pci.h --- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h Tue Apr 10 20:00:45 2007 +0100 +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h Wed Apr 11 09:16:04 2007 +0100 @@ -22,16 +22,11 @@ #ifndef _XEN_PLATFORM_PCI_H #define _XEN_PLATFORM_PCI_H -#include <linux/interrupt.h> +#include <linux/pci.h> unsigned long alloc_xen_mmio(unsigned long len); -int gnttab_init(void); -irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs); -void irq_suspend(void); -void irq_suspend_cancel(void); - -void platform_pci_suspend(void); -void platform_pci_suspend_cancel(void); void platform_pci_resume(void); +extern struct pci_dev *xen_platform_pdev; + #endif /* _XEN_PLATFORM_PCI_H */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |