# 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
|