Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 2830

kernel-2.6.18-194.11.1.el5.src.rpm

From: ddugger@redhat.com <ddugger@redhat.com>
Date: Mon, 6 Apr 2009 15:51:41 -0600
Subject: [pci] xen: dom0/domU MSI support using PHSYDEV_map_irq
Message-id: 200904062151.n36Lpf95013502@sobek.n0ano.com
O-Subject: [RHEL5.4 PATCH 1/3] BZ484227: VTD: dom0/domU MSI support using PHSYDEV_map_irq
Bugzilla: 484227
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>

Add in MSI support (from changeset 525) and move Xen variable out
of the pci_dev struct (from changeset 790)

Moving the msi related variable irq_old out of struct pci_dev is
logically more consistent and has the additional benefit that xen
kernel and vanilla kernel now have the same pci_dev layout

Upstream Status: Accepted (CS 525, 790)

Signed-off-by: Qing He <qing.he@intel.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Qing He <qing.he@intel.com>
Signed-off-by: Don Dugger <donald.d.dugger@intel.com>

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 3c23973..14e6e02 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -5,7 +5,6 @@ config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
 	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC64
-	depends on !XEN
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 8b96bbf..6d93152 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -49,3 +49,8 @@ endif
 ifeq ($(CONFIG_PCI_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
+
+ifdef CONFIG_XEN
+include $(srctree)/scripts/Makefile.xen
+obj-y := $(call cherrypickxen, $(obj-y))
+endif
diff --git a/drivers/pci/msi-xen.c b/drivers/pci/msi-xen.c
new file mode 100644
index 0000000..afa83d4
--- /dev/null
+++ b/drivers/pci/msi-xen.c
@@ -0,0 +1,840 @@
+/*
+ * File:	msi.c
+ * Purpose:	PCI Message Signaled Interrupt (MSI)
+ *
+ * Copyright (C) 2003-2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+
+#include <xen/evtchn.h>
+
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+
+#include "pci.h"
+#include "msi.h"
+
+static int pci_msi_enable = 1;
+
+static struct msi_ops *msi_ops;
+
+int msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
+static LIST_HEAD(msi_dev_head);
+DEFINE_SPINLOCK(msi_dev_lock);
+
+struct msi_dev_list {
+	struct pci_dev *dev;
+	struct list_head list;
+	spinlock_t pirq_list_lock;
+	struct list_head pirq_list_head;
+	/* Used for saving/restoring MSI-X tables */
+	void __iomem *mask_base;
+	/* Store default pre-assigned irq */
+	unsigned int default_irq;
+};
+
+struct msi_pirq_entry {
+	struct list_head list;
+	int pirq;
+	int entry_nr;
+#ifdef CONFIG_PM
+	/* PM save area for MSIX address/data */
+	u32	address_hi_save;
+	u32	address_lo_save;
+	u32	data_save;
+#endif
+};
+
+static struct msi_dev_list *get_msi_dev_pirq_list(struct pci_dev *dev)
+{
+	struct msi_dev_list *msi_dev_list, *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_dev_lock, flags);
+
+	list_for_each_entry(msi_dev_list, &msi_dev_head, list)
+		if ( msi_dev_list->dev == dev )
+			ret = msi_dev_list;
+
+	if ( ret ) {
+		spin_unlock_irqrestore(&msi_dev_lock, flags);
+		return ret;
+	}
+
+	/* Has not allocate msi_dev until now. */
+	ret = kzalloc(sizeof(struct msi_dev_list), GFP_ATOMIC);
+
+	/* Failed to allocate msi_dev structure */
+	if ( !ret ) {
+		spin_unlock_irqrestore(&msi_dev_lock, flags);
+		return NULL;
+	}
+
+	ret->dev = dev;
+	spin_lock_init(&ret->pirq_list_lock);
+	INIT_LIST_HEAD(&ret->pirq_list_head);
+	list_add_tail(&ret->list, &msi_dev_head);
+	spin_unlock_irqrestore(&msi_dev_lock, flags);
+	return ret;
+}
+
+static int attach_pirq_entry(int pirq, int entry_nr,
+                             struct msi_dev_list *msi_dev_entry)
+{
+	struct msi_pirq_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	unsigned long flags;
+
+	if (!entry)
+		return -ENOMEM;
+	entry->pirq = pirq;
+	entry->entry_nr = entry_nr;
+	spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
+	list_add_tail(&entry->list, &msi_dev_entry->pirq_list_head);
+	spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
+	return 0;
+}
+
+static void detach_pirq_entry(int entry_nr,
+			      struct msi_dev_list *msi_dev_entry)
+{
+	unsigned long flags;
+	struct msi_pirq_entry *pirq_entry;
+
+	list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
+		if (pirq_entry->entry_nr == entry_nr) {
+			spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
+			list_del(&pirq_entry->list);
+			spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
+			kfree(pirq_entry);
+			return;
+		}
+	}
+}
+
+/*
+ * pciback will provide device's owner
+ */
+static int (*get_owner)(struct pci_dev *dev);
+
+int register_msi_get_owner(int (*func)(struct pci_dev *dev))
+{
+	if (get_owner) {
+		printk(KERN_WARNING "register msi_get_owner again\n");
+		return -EEXIST;
+	}
+	get_owner = func;
+	return 0;
+}
+
+int unregister_msi_get_owner(int (*func)(struct pci_dev *dev))
+{
+	if (get_owner != func)
+		return -EINVAL;
+	get_owner = NULL;
+	return 0;
+}
+
+static int msi_get_dev_owner(struct pci_dev *dev)
+{
+	int owner;
+
+	BUG_ON(!is_initial_xendomain());
+	if (get_owner && (owner = get_owner(dev)) >= 0) {
+		printk(KERN_INFO "get owner for dev %x get %x \n",
+		       dev->devfn, owner);
+		return owner;
+	}
+
+	return DOMID_SELF;
+}
+
+static int msi_unmap_pirq(struct pci_dev *dev, int pirq)
+{
+	struct physdev_unmap_pirq unmap;
+	int rc;
+
+	unmap.domid = msi_get_dev_owner(dev);
+	unmap.pirq = pirq;
+
+	if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap)))
+		printk(KERN_WARNING "unmap irq %x failed\n", pirq);
+
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static u64 find_table_base(struct pci_dev *dev, int pos)
+{
+	u8 bar;
+	u32 reg;
+	unsigned long flags;
+
+	pci_read_config_dword(dev, msix_table_offset_reg(pos), &reg);
+	bar = reg & PCI_MSIX_FLAGS_BIRMASK;
+
+	flags = pci_resource_flags(dev, bar);
+	if (flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET | IORESOURCE_BUSY))
+		return 0;
+
+	return pci_resource_start(dev, bar);
+}
+
+/*
+ * Protected by msi_lock
+ */
+static int msi_map_pirq_to_vector(struct pci_dev *dev, int pirq,
+				  int entry_nr, u64 table_base)
+{
+	struct physdev_map_pirq map_irq;
+	int rc;
+	domid_t domid = DOMID_SELF;
+
+	domid = msi_get_dev_owner(dev);
+
+	map_irq.domid = domid;
+	map_irq.type = MAP_PIRQ_TYPE_MSI;
+	map_irq.index = -1;
+	map_irq.pirq = pirq < 0 ? -1 : pirq;
+	map_irq.bus = dev->bus->number;
+	map_irq.devfn = dev->devfn;
+	map_irq.entry_nr = entry_nr;
+	map_irq.table_base = table_base;
+
+	if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq)))
+		printk(KERN_WARNING "map irq failed\n");
+
+	if (rc < 0)
+		return rc;
+	/* This happens when MSI support is not enabled in Xen. */
+	if (rc == 0 && map_irq.pirq < 0)
+		return -ENOSYS;
+
+	BUG_ON(map_irq.pirq <= 0);
+
+	return map_irq.pirq;
+}
+
+static int msi_map_vector(struct pci_dev *dev, int entry_nr, u64 table_base)
+{
+	return msi_map_pirq_to_vector(dev, -1, entry_nr, table_base);
+}
+
+static int msi_init(void)
+{
+	/* backport: checking pci_msi_quirk */
+	return 0;
+}
+
+void pci_scan_msi_device(struct pci_dev *dev) { }
+
+void disable_msi_mode(struct pci_dev *dev, int pos, int type)
+{
+	u16 control;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (type == PCI_CAP_ID_MSI) {
+		/* Set enabled bits to single MSI & enable MSI_enable bit */
+		msi_disable(control);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+		dev->msi_enabled = 0;
+	} else {
+		msix_disable(control);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+		dev->msix_enabled = 0;
+	}
+	if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
+		/* PCI Express Endpoint device detected */
+		pci_intx(dev, 1);  /* enable intx */
+	}
+}
+
+static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
+{
+	u16 control;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (type == PCI_CAP_ID_MSI) {
+		/* Set enabled bits to single MSI & enable MSI_enable bit */
+		msi_enable(control, 1);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+		dev->msi_enabled = 1;
+	} else {
+		msix_enable(control);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+		dev->msix_enabled = 1;
+	}
+	if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
+		/* PCI Express Endpoint device detected */
+		pci_intx(dev, 0);  /* disable intx */
+	}
+}
+
+#ifdef CONFIG_PM
+int pci_save_msi_state(struct pci_dev *dev)
+{
+	int pos, i = 0;
+	u16 control;
+	struct pci_cap_saved_state *save_state;
+	u32 *cap;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	if (pos <= 0 || dev->no_msi)
+		return 0;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (!(control & PCI_MSI_FLAGS_ENABLE))
+		return 0;
+
+	save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5,
+		GFP_KERNEL);
+	if (!save_state) {
+		printk(KERN_ERR "Out of memory in pci_save_msi_state\n");
+		return -ENOMEM;
+	}
+	cap = &save_state->data[0];
+
+	pci_read_config_dword(dev, pos, &cap[i++]);
+	control = cap[0] >> 16;
+	pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]);
+	if (control & PCI_MSI_FLAGS_64BIT) {
+		pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]);
+		pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]);
+	} else
+		pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]);
+	if (control & PCI_MSI_FLAGS_MASKBIT)
+		pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]);
+	save_state->cap_nr = PCI_CAP_ID_MSI;
+	pci_add_saved_cap(dev, save_state);
+	return 0;
+}
+
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+	int i = 0, pos;
+	u16 control;
+	struct pci_cap_saved_state *save_state;
+	u32 *cap;
+
+	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI);
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	if (!save_state || pos <= 0)
+		return;
+	cap = &save_state->data[0];
+
+	control = cap[i++] >> 16;
+	pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]);
+	if (control & PCI_MSI_FLAGS_64BIT) {
+		pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]);
+		pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]);
+	} else
+		pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]);
+	if (control & PCI_MSI_FLAGS_MASKBIT)
+		pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]);
+	pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+	enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+	pci_remove_saved_cap(save_state);
+	kfree(save_state);
+}
+EXPORT_SYMBOL_GPL(pci_restore_msi_state);
+
+int pci_save_msix_state(struct pci_dev *dev)
+{
+	int pos;
+	u16 control;
+	struct pci_cap_saved_state *save_state;
+	unsigned long flags;
+	struct msi_dev_list *msi_dev_entry;
+	struct msi_pirq_entry *pirq_entry;
+	void __iomem *base;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	if (pos <= 0 || dev->no_msi)
+		return 0;
+
+	/* save the capability */
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (!(control & PCI_MSIX_FLAGS_ENABLE))
+		return 0;
+
+	msi_dev_entry = get_msi_dev_pirq_list(dev);
+	/* If we failed to map the MSI-X table at pci_enable_msix,
+	 * We could not support saving them here.
+	 */
+	if (!(base = msi_dev_entry->mask_base))
+		return -ENOMEM;
+
+	save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16),
+		GFP_KERNEL);
+	if (!save_state) {
+		printk(KERN_ERR "Out of memory in pci_save_msix_state\n");
+		return -ENOMEM;
+	}
+	*((u16 *)&save_state->data[0]) = control;
+
+	spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
+	list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
+		int j;
+
+		/* save the table */
+		j = pirq_entry->entry_nr;
+		pirq_entry->address_lo_save =
+			readl(base + j * PCI_MSIX_ENTRY_SIZE +
+			      PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+		pirq_entry->address_hi_save =
+			readl(base + j * PCI_MSIX_ENTRY_SIZE +
+			      PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+		pirq_entry->data_save =
+			readl(base + j * PCI_MSIX_ENTRY_SIZE +
+			      PCI_MSIX_ENTRY_DATA_OFFSET);
+	}
+	spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
+
+	save_state->cap_nr = PCI_CAP_ID_MSIX;
+	pci_add_saved_cap(dev, save_state);
+	return 0;
+}
+
+void pci_restore_msix_state(struct pci_dev *dev)
+{
+	u16 save;
+	int pos, j;
+	void __iomem *base;
+	struct pci_cap_saved_state *save_state;
+	unsigned long flags;
+	struct msi_dev_list *msi_dev_entry;
+	struct msi_pirq_entry *pirq_entry;
+
+	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
+	if (!save_state)
+		return;
+
+	save = *((u16 *)&save_state->data[0]);
+	pci_remove_saved_cap(save_state);
+	kfree(save_state);
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	if (pos <= 0)
+		return;
+
+	msi_dev_entry = get_msi_dev_pirq_list(dev);
+	base = msi_dev_entry->mask_base;
+
+	spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
+	list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
+		/* route the table */
+		j = pirq_entry->entry_nr;
+		writel(pirq_entry->address_lo_save,
+			base + j * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+		writel(pirq_entry->address_hi_save,
+			base + j * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+		writel(pirq_entry->data_save,
+			base + j * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_DATA_OFFSET);
+	}
+	spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
+
+	pci_write_config_word(dev, msi_control_reg(pos), save);
+	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+}
+#endif
+
+/**
+ * msi_capability_init - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device function with a single
+ * MSI vector, regardless of device function is capable of handling
+ * multiple messages. A return of zero indicates the successful setup
+ * of an entry zero with the new MSI vector or non-zero for otherwise.
+ **/
+static int msi_capability_init(struct pci_dev *dev)
+{
+	int pos, pirq;
+	u16 control;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+
+	pirq = msi_map_vector(dev, 0, 0);
+	if (pirq < 0)
+		return -EBUSY;
+
+	dev->irq = pirq;
+	/* Set MSI enabled bits	 */
+	enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+	dev->msi_enabled = 1;
+
+	return 0;
+}
+
+/**
+ * msix_capability_init - configure device's MSI-X capability
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ * @entries: pointer to an array of struct msix_entry entries
+ * @nvec: number of @entries
+ *
+ * Setup the MSI-X capability structure of device function with a
+ * single MSI-X vector. A return of zero indicates the successful setup of
+ * requested MSI-X entries with allocated vectors or non-zero for otherwise.
+ **/
+static int msix_capability_init(struct pci_dev *dev,
+				struct msix_entry *entries, int nvec)
+{
+	u64 table_base;
+	u16 control;
+	int pirq, i, j, mapped, pos, nr_entries;
+	struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
+	struct msi_pirq_entry *pirq_entry;
+
+	if (!msi_dev_entry)
+		return -ENOMEM;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	table_base = find_table_base(dev, pos);
+	if (!table_base)
+		return -ENODEV;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	nr_entries = multi_msix_capable(control);
+	if (!msi_dev_entry->mask_base)
+		msi_dev_entry->mask_base =
+			ioremap_nocache(table_base, nr_entries * PCI_MSIX_ENTRY_SIZE);
+
+	/* MSI-X Table Initialization */
+	for (i = 0; i < nvec; i++) {
+		mapped = 0;
+		list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
+			if (pirq_entry->entry_nr == entries[i].entry) {
+				printk(KERN_WARNING "msix entry %d for dev %02x:%02x:%01x are \
+				       not freed before acquire again.\n", entries[i].entry,
+					   dev->bus->number, PCI_SLOT(dev->devfn),
+					   PCI_FUNC(dev->devfn));
+				(entries + i)->vector = pirq_entry->pirq;
+				mapped = 1;
+				break;
+			}
+		}
+		if (mapped)
+			continue;
+		pirq = msi_map_vector(dev, entries[i].entry, table_base);
+		if (pirq < 0)
+			break;
+		attach_pirq_entry(pirq, entries[i].entry, msi_dev_entry);
+		(entries + i)->vector = pirq;
+	}
+
+	if (i != nvec) {
+		for (j = --i; j >= 0; j--) {
+			msi_unmap_pirq(dev, entries[j].vector);
+			detach_pirq_entry(entries[j].entry, msi_dev_entry);
+			entries[j].vector = 0;
+		}
+		return -EBUSY;
+	}
+
+	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+	dev->msix_enabled = 1;
+
+	return 0;
+}
+
+/**
+ * pci_enable_msi - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device function with
+ * a single MSI vector upon its software driver call to request for
+ * MSI mode enabled on its hardware device function. A return of zero
+ * indicates the successful setup of an entry zero with the new MSI
+ * vector or non-zero for otherwise.
+ **/
+extern int pci_frontend_enable_msi(struct pci_dev *dev);
+int pci_enable_msi(struct pci_dev* dev)
+{
+	struct pci_bus *bus;
+	int pos, temp, status = -EINVAL;
+	struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
+
+	if (!pci_msi_enable || !dev)
+		return status;
+
+	if (dev->no_msi)
+		return status;
+
+	for (bus = dev->bus; bus; bus = bus->parent)
+		if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+			return -EINVAL;
+
+	status = msi_init();
+	if (status < 0)
+		return status;
+
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+	if (!is_initial_xendomain())
+	{
+		int ret;
+
+		temp = dev->irq;
+		ret = pci_frontend_enable_msi(dev);
+		if (ret)
+			return ret;
+
+		msi_dev_entry->default_irq = temp;
+
+		return ret;
+	}
+#endif
+
+	temp = dev->irq;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	if (!pos)
+		return -EINVAL;
+
+	/* Check whether driver already requested for MSI-X vectors */
+	if (dev->msix_enabled) {
+		printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
+			   "Device already has MSI-X vectors assigned\n",
+			   pci_name(dev));
+		dev->irq = temp;
+		return -EINVAL;
+	}
+
+	status = msi_capability_init(dev);
+	if ( !status )
+		msi_dev_entry->default_irq = temp;
+	else
+		dev->irq = temp;
+
+	return status;
+}
+
+extern void pci_frontend_disable_msi(struct pci_dev* dev);
+void pci_disable_msi(struct pci_dev* dev)
+{
+	int pos;
+	int pirq;
+	struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
+
+	if (!pci_msi_enable)
+		return;
+	if (!dev)
+		return;
+
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+	if (!is_initial_xendomain()) {
+		pci_frontend_disable_msi(dev);
+		dev->irq = msi_dev_entry->default_irq;
+		return;
+	}
+#endif
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	if (!pos)
+		return;
+
+	pirq = dev->irq;
+	/* Restore dev->irq to its default pin-assertion vector */
+	dev->irq = msi_dev_entry->default_irq;
+	msi_unmap_pirq(dev, pirq);
+
+	/* Disable MSI mode */
+	disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+}
+
+/**
+ * pci_enable_msix - configure device's MSI-X capability structure
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ * @entries: pointer to an array of MSI-X entries
+ * @nvec: number of MSI-X vectors requested for allocation by device driver
+ *
+ * Setup the MSI-X capability structure of device function with the number
+ * of requested vectors upon its software driver call to request for
+ * MSI-X mode enabled on its hardware device function. A return of zero
+ * indicates the successful configuration of MSI-X capability structure
+ * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
+ * Or a return of > 0 indicates that driver request is exceeding the number
+ * of vectors available. Driver should use the returned value to re-send
+ * its request.
+ **/
+extern int pci_frontend_enable_msix(struct pci_dev *dev,
+		struct msix_entry *entries, int nvec);
+int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
+{
+	struct pci_bus *bus;
+	int status, pos, nr_entries;
+	int i, j, temp;
+	u16 control;
+	struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
+
+	if (!pci_msi_enable || !dev || !entries)
+		return -EINVAL;
+
+	if (dev->no_msi)
+		return -EINVAL;
+
+	for (bus = dev->bus; bus; bus = bus->parent)
+		if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+			return -EINVAL;
+
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+	if (!is_initial_xendomain()) {
+		int ret;
+
+		temp = dev->irq;
+		ret = pci_frontend_enable_msix(dev, entries, nvec);
+		if (ret) {
+			printk("get %x from pci_frontend_enable_msix\n", ret);
+			return ret;
+		}
+		msi_dev_entry->default_irq = temp;
+
+		return 0;
+	}
+#endif
+
+	status = msi_init();
+	if (status < 0)
+		return status;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	if (!pos)
+		return -EINVAL;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	nr_entries = multi_msix_capable(control);
+	if (nvec > nr_entries)
+		return -EINVAL;
+
+	/* Check for any invalid entries */
+	for (i = 0; i < nvec; i++) {
+		if (entries[i].entry >= nr_entries)
+			return -EINVAL;		/* invalid entry */
+		for (j = i + 1; j < nvec; j++) {
+			if (entries[i].entry == entries[j].entry)
+				return -EINVAL;	/* duplicate entry */
+		}
+	}
+
+	temp = dev->irq;
+	/* Check whether driver already requested for MSI vector */
+	if (dev->msi_enabled) {
+		printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
+		       "Device already has an MSI vector assigned\n",
+		       pci_name(dev));
+		dev->irq = temp;
+		return -EINVAL;
+	}
+
+	status = msix_capability_init(dev, entries, nvec);
+
+	if ( !status )
+		msi_dev_entry->default_irq = temp;
+	else
+		dev->irq = temp;
+
+	return status;
+}
+
+extern void pci_frontend_disable_msix(struct pci_dev* dev);
+void pci_disable_msix(struct pci_dev* dev)
+{
+	int pos;
+	u16 control;
+	struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
+
+
+	if (!pci_msi_enable)
+		return;
+	if (!dev)
+		return;
+
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+	if (!is_initial_xendomain()) {
+		pci_frontend_disable_msix(dev);
+		dev->irq = msi_dev_entry->default_irq;
+		return;
+	}
+#endif
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	if (!pos)
+		return;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (!(control & PCI_MSIX_FLAGS_ENABLE))
+		return;
+
+	msi_remove_pci_irq_vectors(dev);
+
+	/* Disable MSI mode */
+	disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+}
+
+/**
+ * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
+ * @dev: pointer to the pci_dev data structure of MSI(X) device function
+ *
+ * Being called during hotplug remove, from which the device function
+ * is hot-removed. All previous assigned MSI/MSI-X vectors, if
+ * allocated for this device function, are reclaimed to unused state,
+ * which may be used later on.
+ **/
+void msi_remove_pci_irq_vectors(struct pci_dev* dev)
+{
+	unsigned long flags;
+	struct msi_dev_list *msi_dev_entry;
+	struct msi_pirq_entry *pirq_entry, *tmp;
+
+	if (!pci_msi_enable || !dev)
+		return;
+
+	msi_dev_entry = get_msi_dev_pirq_list(dev);
+
+	spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
+	if (!list_empty(&msi_dev_entry->pirq_list_head))
+		list_for_each_entry_safe(pirq_entry, tmp,
+		                         &msi_dev_entry->pirq_list_head, list) {
+			msi_unmap_pirq(dev, pirq_entry->pirq);
+			list_del(&pirq_entry->list);
+			kfree(pirq_entry);
+		}
+	spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
+	iounmap(msi_dev_entry->mask_base);
+	msi_dev_entry->mask_base = NULL;
+	dev->irq = msi_dev_entry->default_irq;
+}
+
+void pci_no_msi(void)
+{
+	pci_msi_enable = 0;
+}
+
+EXPORT_SYMBOL(pci_enable_msi);
+EXPORT_SYMBOL(pci_disable_msi);
+EXPORT_SYMBOL(pci_enable_msix);
+EXPORT_SYMBOL(pci_disable_msix);
+#ifdef CONFIG_XEN
+EXPORT_SYMBOL(register_msi_get_owner);
+EXPORT_SYMBOL(unregister_msi_get_owner);
+#endif
+
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 61cb569..ff97ba8 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -43,17 +43,19 @@ extern void pci_remove_legacy_files(struct pci_bus *bus);
 extern struct rw_semaphore pci_bus_sem;
 extern unsigned int pci_pm_d3_delay;
 
-#ifdef CONFIG_PCI_MSI
+#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
 void disable_msi_mode(struct pci_dev *dev, int pos, int type);
 void pci_no_msi(void);
 int pci_save_msi_state(struct pci_dev *dev);
 int pci_save_msix_state(struct pci_dev *dev);
+void pci_restore_msi_state(struct pci_dev *dev);
 void pci_restore_msix_state(struct pci_dev *dev);
 #else
 static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
 static inline void pci_no_msi(void) { }
 static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
 static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
+static inline void pci_restore_msi_state(struct pci_dev *dev) {}
 static inline void pci_restore_msix_state(struct pci_dev *dev) {}
 #endif
 
diff --git a/drivers/xen/pciback/Makefile b/drivers/xen/pciback/Makefile
index c7185fb..1aa5df2 100644
--- a/drivers/xen/pciback/Makefile
+++ b/drivers/xen/pciback/Makefile
@@ -6,6 +6,7 @@ pciback-y += conf_space.o conf_space_header.o \
 	     conf_space_capability_vpd.o \
 	     conf_space_capability_pm.o \
              conf_space_quirks.o
+pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
 pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
 pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
 pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
diff --git a/drivers/xen/pciback/conf_space_capability_msi.c b/drivers/xen/pciback/conf_space_capability_msi.c
new file mode 100644
index 0000000..762e396
--- /dev/null
+++ b/drivers/xen/pciback/conf_space_capability_msi.c
@@ -0,0 +1,79 @@
+/*
+ * PCI Backend -- Configuration overlay for MSI capability
+ */
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include "conf_space.h"
+#include "conf_space_capability.h"
+#include <xen/interface/io/pciif.h>
+#include "pciback.h"
+
+int pciback_enable_msi(struct pciback_device *pdev,
+		struct pci_dev *dev, struct xen_pci_op *op)
+{
+	int otherend = pdev->xdev->otherend_id;
+	int status;
+
+	status = pci_enable_msi(dev);
+
+	if (status) {
+		printk("error enable msi for guest %x status %x\n", otherend, status);
+		op->value = 0;
+		return XEN_PCI_ERR_op_failed;
+	}
+
+	op->value = dev->irq;
+	return 0;
+}
+
+int pciback_disable_msi(struct pciback_device *pdev,
+		struct pci_dev *dev, struct xen_pci_op *op)
+{
+	pci_disable_msi(dev);
+
+	op->value = dev->irq;
+	return 0;
+}
+
+int pciback_enable_msix(struct pciback_device *pdev,
+		struct pci_dev *dev, struct xen_pci_op *op)
+{
+	int i, result;
+	struct msix_entry *entries;
+
+	if (op->value > SH_INFO_MAX_VEC)
+		return -EINVAL;
+
+	entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL);
+	if (entries == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < op->value; i++) {
+		entries[i].entry = op->msix_entries[i].entry;
+		entries[i].vector = op->msix_entries[i].vector;
+	}
+
+	result = pci_enable_msix(dev, entries, op->value);
+
+	for (i = 0; i < op->value; i++) {
+		op->msix_entries[i].entry = entries[i].entry;
+		op->msix_entries[i].vector = entries[i].vector;
+	}
+
+	kfree(entries);
+
+	op->value = result;
+
+	return result;
+}
+
+int pciback_disable_msix(struct pciback_device *pdev,
+		struct pci_dev *dev, struct xen_pci_op *op)
+{
+
+	pci_disable_msix(dev);
+
+	op->value = dev->irq;
+	return 0;
+}
+
diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
index b338559..68fa0c4 100644
--- a/drivers/xen/pciback/pci_stub.c
+++ b/drivers/xen/pciback/pci_stub.c
@@ -809,6 +809,23 @@ static ssize_t permissive_show(struct device_driver *drv, char *buf)
 
 DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
 
+#ifdef CONFIG_PCI_MSI
+
+int pciback_get_owner(struct pci_dev *dev)
+{
+	struct pcistub_device *psdev;
+
+	psdev = pcistub_device_find(pci_domain_nr(dev->bus), dev->bus->number,
+			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	/* XXX will other domain has pciback support ??? */
+	if (!psdev || !psdev->pdev) {
+		printk(KERN_WARNING "no owner\n");
+		return -1;
+	}
+	return psdev->pdev->xdev->otherend_id;
+}
+#endif
+
 static int __init pcistub_init(void)
 {
 	int pos = 0;
@@ -856,6 +873,8 @@ static int __init pcistub_init(void)
 	driver_create_file(&pciback_pci_driver.driver, &driver_attr_quirks);
 	driver_create_file(&pciback_pci_driver.driver, &driver_attr_permissive);
 
+	err = register_msi_get_owner(pciback_get_owner);
+
       out:
 	return err;
 
@@ -908,6 +927,7 @@ static void __exit pciback_cleanup(void)
 	driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
 
 	pci_unregister_driver(&pciback_pci_driver);
+	WARN_ON(unregister_msi_get_owner(pciback_get_owner));
 }
 
 module_init(pciback_init);
diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
index 4b876e4..35e8f74 100644
--- a/drivers/xen/pciback/pciback.h
+++ b/drivers/xen/pciback/pciback.h
@@ -89,5 +89,19 @@ void pciback_do_op(void *data);
 int pciback_xenbus_register(void);
 void pciback_xenbus_unregister(void);
 
+#ifdef CONFIG_PCI_MSI
+int pciback_enable_msi(struct pciback_device *pdev,
+                       struct pci_dev *dev, struct xen_pci_op *op);
+
+int pciback_disable_msi(struct pciback_device *pdev,
+                         struct pci_dev *dev, struct xen_pci_op *op);
+
+
+int pciback_enable_msix(struct pciback_device *pdev,
+                        struct pci_dev *dev, struct xen_pci_op *op);
+
+int pciback_disable_msix(struct pciback_device *pdev,
+                        struct pci_dev *dev, struct xen_pci_op *op);
+#endif
 extern int verbose_request;
 #endif
diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
index 690941b..6c67a03 100644
--- a/drivers/xen/pciback/pciback_ops.c
+++ b/drivers/xen/pciback/pciback_ops.c
@@ -61,15 +61,37 @@ void pciback_do_op(void *data)
 
 	if (dev == NULL)
 		op->err = XEN_PCI_ERR_dev_not_found;
-	else if (op->cmd == XEN_PCI_OP_conf_read)
-		op->err = pciback_config_read(dev, op->offset, op->size,
-					      &op->value);
-	else if (op->cmd == XEN_PCI_OP_conf_write)
-		op->err = pciback_config_write(dev, op->offset, op->size,
-					       op->value);
 	else
-		op->err = XEN_PCI_ERR_not_implemented;
-
+	{
+		switch (op->cmd)
+		{
+			case XEN_PCI_OP_conf_read:
+				op->err = pciback_config_read(dev,
+					  op->offset, op->size, &op->value);
+				break;
+			case XEN_PCI_OP_conf_write:
+				op->err = pciback_config_write(dev,
+					  op->offset, op->size,	op->value);
+				break;
+#ifdef CONFIG_PCI_MSI
+			case XEN_PCI_OP_enable_msi:
+				op->err = pciback_enable_msi(pdev, dev, op);
+				break;
+			case XEN_PCI_OP_disable_msi:
+				op->err = pciback_disable_msi(pdev, dev, op);
+				break;
+			case XEN_PCI_OP_enable_msix:
+				op->err = pciback_enable_msix(pdev, dev, op);
+				break;
+			case XEN_PCI_OP_disable_msix:
+				op->err = pciback_disable_msix(pdev, dev, op);
+				break;
+#endif
+			default:
+				op->err = XEN_PCI_ERR_not_implemented;
+				break;
+		}
+	}
 	/* Tell the driver domain that we're done. */ 
 	wmb();
 	clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
diff --git a/drivers/xen/pcifront/pci_op.c b/drivers/xen/pcifront/pci_op.c
index 7619ccf..a1418c1 100644
--- a/drivers/xen/pcifront/pci_op.c
+++ b/drivers/xen/pcifront/pci_op.c
@@ -161,6 +161,122 @@ struct pci_ops pcifront_bus_ops = {
 	.write = pcifront_bus_write,
 };
 
+#ifdef CONFIG_PCI_MSI
+int pci_frontend_enable_msix(struct pci_dev *dev,
+		struct msix_entry *entries,
+		int nvec)
+{
+	int err;
+	int i;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_enable_msix,
+		.domain = pci_domain_nr(dev->bus),
+		.bus = dev->bus->number,
+		.devfn = dev->devfn,
+		.value = nvec,
+	};
+	struct pcifront_sd *sd = dev->bus->sysdata;
+	struct pcifront_device *pdev = pcifront_get_pdev(sd);
+
+	if (nvec > SH_INFO_MAX_VEC) {
+		printk("too much vector for pci frontend%x\n", nvec);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < nvec; i++) {
+		op.msix_entries[i].entry = entries[i].entry;
+		op.msix_entries[i].vector = entries[i].vector;
+	}
+
+	err = do_pci_op(pdev, &op);
+
+	if (!err) {
+		if (!op.value) {
+			/* we get the result */
+			for ( i = 0; i < nvec; i++)
+				entries[i].vector = op.msix_entries[i].vector;
+			return 0;
+		}
+		else {
+            printk("enable msix get value %x\n", op.value);
+			return op.value;
+		}
+	}
+	else {
+        printk("enable msix get err %x\n", err);
+		return err;
+	}
+}
+
+void pci_frontend_disable_msix(struct pci_dev* dev)
+{
+	int err;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_disable_msix,
+		.domain = pci_domain_nr(dev->bus),
+		.bus = dev->bus->number,
+		.devfn = dev->devfn,
+	};
+	struct pcifront_sd *sd = dev->bus->sysdata;
+	struct pcifront_device *pdev = pcifront_get_pdev(sd);
+
+	err = do_pci_op(pdev, &op);
+
+	/* What should do for error ? */
+	if (err)
+		printk("pci_disable_msix get err %x\n", err);
+}
+
+int pci_frontend_enable_msi(struct pci_dev *dev)
+{
+	int err;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_enable_msi,
+		.domain = pci_domain_nr(dev->bus),
+		.bus = dev->bus->number,
+		.devfn = dev->devfn,
+	};
+	struct pcifront_sd *sd = dev->bus->sysdata;
+	struct pcifront_device *pdev = pcifront_get_pdev(sd);
+
+	err = do_pci_op(pdev, &op);
+	if (likely(!err)) {
+		dev->irq = op.value;
+	}
+	else {
+		printk("pci frontend enable msi failed for dev %x:%x \n",
+				op.bus, op.devfn);
+		err = -EINVAL;
+	}
+	return err;
+}
+
+void pci_frontend_disable_msi(struct pci_dev* dev)
+{
+	int err;
+	struct xen_pci_op op = {
+		.cmd    = XEN_PCI_OP_disable_msi,
+		.domain = pci_domain_nr(dev->bus),
+		.bus = dev->bus->number,
+		.devfn = dev->devfn,
+	};
+	struct pcifront_sd *sd = dev->bus->sysdata;
+	struct pcifront_device *pdev = pcifront_get_pdev(sd);
+
+	err = do_pci_op(pdev, &op);
+	if (err == XEN_PCI_ERR_dev_not_found) {
+		/* XXX No response from backend, what shall we do? */
+		printk("get no response from backend for disable MSI\n");
+		return;
+	}
+	if (likely(!err))
+		dev->irq = op.value;
+	else
+		/* how can pciback notify us fail? */
+		printk("get fake response frombackend \n");
+}
+#endif /* CONFIG_PCI_MSI */
+
 /* Claim resources for the PCI frontend as-is, backend won't allow changes */
 static void pcifront_claim_resource(struct pci_dev *dev, void *data)
 {
diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h
index 5092e81..99f7e40 100644
--- a/include/asm-i386/io_apic.h
+++ b/include/asm-i386/io_apic.h
@@ -12,7 +12,7 @@
 
 #ifdef CONFIG_X86_IO_APIC
 
-#ifdef CONFIG_PCI_MSI
+#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN)
 static inline int use_pci_vector(void)	{return 1;}
 static inline void disable_edge_ioapic_vector(unsigned int vector) { }
 static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h
index b11c4b7..daef927 100644
--- a/include/asm-i386/msi.h
+++ b/include/asm-i386/msi.h
@@ -7,9 +7,17 @@
 #define ASM_MSI_H
 
 #include <asm/desc.h>
+#ifndef CONFIG_XEN
 #include <mach_apic.h>
+#endif
 
+#ifndef CONFIG_XEN
 #define LAST_DEVICE_VECTOR	(FIRST_SYSTEM_VECTOR - 1)
+#else
+#define LAST_DYNAMIC_VECTOR 0xdf
+#define LAST_DEVICE_VECTOR	(LAST_DYNAMIC_VECTOR)
+#endif
+
 #define MSI_TARGET_CPU_SHIFT	12
 
 extern struct msi_ops msi_apic_ops;
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
index 21fff71..9a81eaf 100644
--- a/include/asm-x86_64/io_apic.h
+++ b/include/asm-x86_64/io_apic.h
@@ -12,7 +12,7 @@
 
 #ifdef CONFIG_X86_IO_APIC
 
-#ifdef CONFIG_PCI_MSI
+#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN)
 static inline int use_pci_vector(void)	{return 1;}
 static inline void disable_edge_ioapic_vector(unsigned int vector) { }
 static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h
index 3ad2346..00a2016 100644
--- a/include/asm-x86_64/msi.h
+++ b/include/asm-x86_64/msi.h
@@ -7,10 +7,18 @@
 #define ASM_MSI_H
 
 #include <asm/desc.h>
+#ifndef CONFIG_XEN
 #include <asm/mach_apic.h>
+#endif
 #include <asm/smp.h>
 
+#ifndef CONFIG_XEN
 #define LAST_DEVICE_VECTOR	(FIRST_SYSTEM_VECTOR - 1)
+#else
+#define LAST_DYNAMIC_VECTOR 0xdf
+#define LAST_DEVICE_VECTOR	(LAST_DYNAMIC_VECTOR)
+#endif
+
 #define MSI_TARGET_CPU_SHIFT	12
 
 extern struct msi_ops msi_apic_ops;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 736aa36..5dccf2a 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -663,6 +663,10 @@ static inline int pci_enable_msix(struct pci_dev* dev,
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
 static inline void pci_restore_msi_state(struct pci_dev *dev) {}
+#ifdef CONFIG_XEN
+#define register_msi_get_owner(func) 0
+#define unregister_msi_get_owner(func) 0
+#endif
 #else
 extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
@@ -672,6 +676,10 @@ extern int pci_enable_msix(struct pci_dev* dev,
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
 extern void pci_restore_msi_state(struct pci_dev *dev);
+#ifdef CONFIG_XEN
+extern int register_msi_get_owner(int (*func)(struct pci_dev *dev));
+extern int unregister_msi_get_owner(int (*func)(struct pci_dev *dev));
+#endif
 #endif
 
 #ifndef CONFIG_EEH
diff --git a/include/xen/evtchn.h b/include/xen/evtchn.h
index 0889060..14de1ce 100644
--- a/include/xen/evtchn.h
+++ b/include/xen/evtchn.h
@@ -117,4 +117,18 @@ static inline void notify_remote_via_evtchn(int port)
  */
 extern void notify_remote_via_irq(int irq);
 
+#define PIRQ_SET_MAPPING 0x0
+#define PIRQ_CLEAR_MAPPING 0x1
+#define PIRQ_GET_MAPPING 0x3
+int pirq_mapstatus(int pirq, int action);
+int set_pirq_hw_action(int pirq, int (*action)(int pirq, int action));
+int clear_pirq_hw_action(int pirq);
+
+#define PIRQ_STARTUP 1
+#define PIRQ_SHUTDOWN 2
+#define PIRQ_ENABLE 3
+#define PIRQ_DISABLE 4
+#define PIRQ_END 5
+#define PIRQ_ACK 6
+
 #endif /* __ASM_EVTCHN_H__ */
diff --git a/include/xen/interface/io/pciif.h b/include/xen/interface/io/pciif.h
index a1c9ab7..2cd466a 100644
--- a/include/xen/interface/io/pciif.h
+++ b/include/xen/interface/io/pciif.h
@@ -16,6 +16,10 @@
 /* xen_pci_op commands */
 #define XEN_PCI_OP_conf_read    (0)
 #define XEN_PCI_OP_conf_write   (1)
+#define XEN_PCI_OP_enable_msi   (2)
+#define XEN_PCI_OP_enable_msix  (3)
+#define XEN_PCI_OP_disable_msi  (4)
+#define XEN_PCI_OP_disable_msix (5)
 
 /* xen_pci_op error numbers */
 #define XEN_PCI_ERR_success          (0)
@@ -26,6 +30,12 @@
 /* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
 #define XEN_PCI_ERR_op_failed       (-5)
 
+/*
+ * it should be PAGE_SIZE-sizeof(struct xen_pci_op))/sizeof(struct msix_entry))
+ * Should not exceed 128
+ */
+#define SH_INFO_MAX_VEC     128
+
 struct xen_pci_op {
 	/* IN: what action to perform: XEN_PCI_OP_* */
 	uint32_t cmd;
@@ -44,6 +54,11 @@ struct xen_pci_op {
 
 	/* IN/OUT: Contains the result after a READ or the value to WRITE */
 	uint32_t value;
+
+	/* IN: Contains extra infor for this operation */
+	uint32_t info;
+	/*IN:  param for msi-x */
+	struct msix_entry msix_entries[SH_INFO_MAX_VEC];
 };
 
 struct xen_pci_sharedinfo {
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
index 9b0baee..03e3413 100644
--- a/include/xen/interface/physdev.h
+++ b/include/xen/interface/physdev.h
@@ -98,6 +98,41 @@ struct physdev_irq {
 };
 typedef struct physdev_irq physdev_irq_t;
 DEFINE_XEN_GUEST_HANDLE(physdev_irq_t);
+ 
+#define MAP_PIRQ_TYPE_MSI               0x0
+#define MAP_PIRQ_TYPE_GSI               0x1
+#define MAP_PIRQ_TYPE_UNKNOWN           0x2
+
+#define PHYSDEVOP_map_pirq               13
+struct physdev_map_pirq {
+    domid_t domid;
+    /* IN */
+    int type;
+    /* IN */
+    int index;
+    /* IN or OUT */
+    int pirq;
+    /* IN */
+    int bus;
+    /* IN */
+    int devfn;
+    /* IN */
+    int entry_nr;
+    /* IN */
+    uint64_t table_base;
+};
+typedef struct physdev_map_pirq physdev_map_pirq_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t);
+
+#define PHYSDEVOP_unmap_pirq             14
+struct physdev_unmap_pirq {
+    domid_t domid;
+    /* IN */
+    int pirq;
+};
+
+typedef struct physdev_unmap_pirq physdev_unmap_pirq_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_unmap_pirq_t);
 
 /*
  * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
@@ -133,6 +168,7 @@ DEFINE_XEN_GUEST_HANDLE(physdev_op_t);
 #define PHYSDEVOP_APIC_READ              PHYSDEVOP_apic_read
 #define PHYSDEVOP_APIC_WRITE             PHYSDEVOP_apic_write
 #define PHYSDEVOP_ASSIGN_VECTOR          PHYSDEVOP_alloc_irq_vector
+#define PHYSDEVOP_FREE_VECTOR            PHYSDEVOP_free_irq_vector
 #define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi
 #define PHYSDEVOP_IRQ_SHARED             XENIRQSTAT_shared