aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-08-13 13:45:39 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-08-13 13:45:39 +0100
commitf9307cbb49b5a29a298b0154b651af60d7d08883 (patch)
tree7be96fa01613f675973e269e5ac083b322ddff09
parent68c053e8a96b009f9ba518ebbc01f4df16cbbe4e (diff)
downloadxen-f9307cbb49b5a29a298b0154b651af60d7d08883.tar.gz
xen-f9307cbb49b5a29a298b0154b651af60d7d08883.tar.bz2
xen-f9307cbb49b5a29a298b0154b651af60d7d08883.zip
MSI-X: enhancement
Signed-off-by: Yu Zhao <yu.zhao@intel.com>
-rw-r--r--tools/ioemu/hw/pass-through.h1
-rw-r--r--tools/ioemu/hw/pt-msi.c24
-rw-r--r--tools/libxc/xc_physdev.c10
-rw-r--r--tools/libxc/xenctrl.h2
-rw-r--r--xen/arch/x86/msi.c78
-rw-r--r--xen/arch/x86/physdev.c15
-rw-r--r--xen/drivers/passthrough/io.c3
-rw-r--r--xen/include/asm-x86/msi.h10
-rw-r--r--xen/include/public/physdev.h11
9 files changed, 74 insertions, 80 deletions
diff --git a/tools/ioemu/hw/pass-through.h b/tools/ioemu/hw/pass-through.h
index 43a27c5f77..fa5357e14b 100644
--- a/tools/ioemu/hw/pass-through.h
+++ b/tools/ioemu/hw/pass-through.h
@@ -120,6 +120,7 @@ struct pt_msix_info {
int enabled;
int total_entries;
int bar_index;
+ uint64_t table_base;
uint32_t table_off;
uint64_t mmio_base_addr;
int mmio_index;
diff --git a/tools/ioemu/hw/pt-msi.c b/tools/ioemu/hw/pt-msi.c
index 68a952f059..98e485e076 100644
--- a/tools/ioemu/hw/pt-msi.c
+++ b/tools/ioemu/hw/pt-msi.c
@@ -38,8 +38,8 @@ int pt_msi_setup(struct pt_dev *dev)
}
if ( xc_physdev_map_pirq_msi(xc_handle, domid, AUTO_ASSIGN, &pirq,
- dev->pci_dev->dev << 3 | dev->pci_dev->func,
- dev->pci_dev->bus, 0, 1) )
+ dev->pci_dev->dev << 3 | dev->pci_dev->func,
+ dev->pci_dev->bus, 0, 0) )
{
PT_LOG("error map msi\n");
return -1;
@@ -121,7 +121,8 @@ static int pt_msix_update_one(struct pt_dev *dev, int entry_nr)
{
ret = xc_physdev_map_pirq_msi(xc_handle, domid, AUTO_ASSIGN, &pirq,
dev->pci_dev->dev << 3 | dev->pci_dev->func,
- dev->pci_dev->bus, entry_nr, 0);
+ dev->pci_dev->bus, entry_nr,
+ dev->msix->table_base);
if ( ret )
{
PT_LOG("error map msix entry %x\n", entry_nr);
@@ -183,7 +184,7 @@ static void pci_msix_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
entry = &msix->msix_entry[entry_nr];
offset = ((addr - msix->mmio_base_addr) % 16) / 4;
- if ( offset != 3 && msix->enabled && entry->io_mem[3] & 0x1 )
+ if ( offset != 3 && msix->enabled && !(entry->io_mem[3] & 0x1) )
{
PT_LOG("can not update msix entry %d since MSI-X is already \
function now.\n", entry_nr);
@@ -196,7 +197,7 @@ static void pci_msix_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
if ( offset == 3 )
{
- if ( !(val & 0x1) )
+ if ( msix->enabled && !(val & 0x1) )
pt_msix_update_one(dev, entry_nr);
mask_physical_msix_entry(dev, entry_nr, entry->io_mem[3] & 0x1);
}
@@ -280,7 +281,6 @@ int pt_msix_init(struct pt_dev *dev, int pos)
uint8_t id;
uint16_t control;
int i, total_entries, table_off, bar_index;
- uint64_t bar_base;
struct pci_dev *pd = dev->pci_dev;
id = pci_read_byte(pd, pos + PCI_CAP_LIST_ID);
@@ -314,18 +314,14 @@ int pt_msix_init(struct pt_dev *dev, int pos)
table_off = pci_read_long(pd, pos + PCI_MSIX_TABLE);
bar_index = dev->msix->bar_index = table_off & PCI_MSIX_BIR;
table_off &= table_off & ~PCI_MSIX_BIR;
- bar_base = pci_read_long(pd, 0x10 + 4 * bar_index);
- if ( (bar_base & 0x6) == 0x4 )
- {
- bar_base &= ~0xf;
- bar_base += (uint64_t)pci_read_long(pd, 0x10 + 4 * (bar_index + 1)) << 32;
- }
- PT_LOG("get MSI-X table bar base %lx\n", bar_base);
+ dev->msix->table_base = dev->pci_dev->base_addr[bar_index];
+ PT_LOG("get MSI-X table bar base %llx\n",
+ (unsigned long long)dev->msix->table_base);
dev->msix->fd = open("/dev/mem", O_RDWR);
dev->msix->phys_iomem_base = mmap(0, total_entries * 16,
PROT_WRITE | PROT_READ, MAP_SHARED | MAP_LOCKED,
- dev->msix->fd, bar_base + table_off);
+ dev->msix->fd, dev->msix->table_base + table_off);
PT_LOG("mapping physical MSI-X table to %lx\n",
(unsigned long)dev->msix->phys_iomem_base);
return 0;
diff --git a/tools/libxc/xc_physdev.c b/tools/libxc/xc_physdev.c
index b320f19dc8..ec0ebbeb76 100644
--- a/tools/libxc/xc_physdev.c
+++ b/tools/libxc/xc_physdev.c
@@ -51,7 +51,7 @@ int xc_physdev_map_pirq_msi(int xc_handle,
int devfn,
int bus,
int entry_nr,
- int msi_type)
+ uint64_t table_base)
{
int rc;
struct physdev_map_pirq map;
@@ -63,10 +63,10 @@ int xc_physdev_map_pirq_msi(int xc_handle,
map.type = MAP_PIRQ_TYPE_MSI;
map.index = index;
map.pirq = *pirq;
- map.msi_info.devfn = devfn;
- map.msi_info.bus = bus;
- map.msi_info.entry_nr = entry_nr;
- map.msi_info.msi = msi_type;
+ map.bus = bus;
+ map.devfn = devfn;
+ map.entry_nr = entry_nr;
+ map.table_base = table_base;
rc = do_physdev_op(xc_handle, PHYSDEVOP_map_pirq, &map);
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 0639d3fd23..341d117695 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -917,7 +917,7 @@ int xc_physdev_map_pirq_msi(int xc_handle,
int devfn,
int bus,
int entry_nr,
- int msi_type);
+ uint64_t table_base);
int xc_physdev_unmap_pirq(int xc_handle,
int domid,
diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c
index 91e725049a..cf5339e8e5 100644
--- a/xen/arch/x86/msi.c
+++ b/xen/arch/x86/msi.c
@@ -490,28 +490,6 @@ static int msi_capability_init(struct pci_dev *dev, int vector)
return 0;
}
-static u64 pci_resource_start(struct pci_dev *dev, u8 bar_index)
-{
- u64 bar_base;
- u32 reg_val;
- u8 bus = dev->bus;
- u8 slot = PCI_SLOT(dev->devfn);
- u8 func = PCI_FUNC(dev->devfn);
-
- reg_val = pci_conf_read32(bus, slot, func,
- PCI_BASE_ADDRESS_0 + 4 * bar_index);
- bar_base = reg_val & PCI_BASE_ADDRESS_MEM_MASK;
- if ( ( reg_val & PCI_BASE_ADDRESS_MEM_TYPE_MASK ) ==
- PCI_BASE_ADDRESS_MEM_TYPE_64 )
- {
- reg_val = pci_conf_read32(bus, slot, func,
- PCI_BASE_ADDRESS_0 + 4 * (bar_index + 1));
- bar_base |= ((u64)reg_val) << 32;
- }
-
- return bar_base;
-}
-
/**
* msix_capability_init - configure device's MSI-X capability
* @dev: pointer to the pci_dev data structure of MSI-X device function
@@ -522,7 +500,7 @@ static u64 pci_resource_start(struct pci_dev *dev, u8 bar_index)
* single MSI-X irq. A return of zero indicates the successful setup of
* requested MSI-X entries with allocated irqs or non-zero for otherwise.
**/
-static int msix_capability_init(struct pci_dev *dev, int vector, int entry_nr)
+static int msix_capability_init(struct pci_dev *dev, struct msi_info *msi)
{
struct msi_desc *entry;
int pos;
@@ -549,7 +527,7 @@ static int msix_capability_init(struct pci_dev *dev, int vector, int entry_nr)
table_offset = pci_conf_read32(bus, slot, func, msix_table_offset_reg(pos));
bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
- phys_addr = pci_resource_start(dev, bir) + table_offset;
+ phys_addr = msi->table_base + table_offset;
idx = msix_fixmap_alloc();
if ( idx < 0 )
{
@@ -561,11 +539,11 @@ static int msix_capability_init(struct pci_dev *dev, int vector, int entry_nr)
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
entry->msi_attrib.is_64 = 1;
- entry->msi_attrib.entry_nr = entry_nr;
+ entry->msi_attrib.entry_nr = msi->entry_nr;
entry->msi_attrib.maskbit = 1;
entry->msi_attrib.masked = 1;
entry->msi_attrib.pos = pos;
- entry->vector = vector;
+ entry->vector = msi->vector;
entry->dev = dev;
entry->mask_base = base;
@@ -589,24 +567,25 @@ static int msix_capability_init(struct pci_dev *dev, int vector, int entry_nr)
* indicates the successful setup of an entry zero with the new MSI
* irq or non-zero for otherwise.
**/
-static int __pci_enable_msi(u8 bus, u8 devfn, int vector)
+static int __pci_enable_msi(struct msi_info *msi)
{
int status;
struct pci_dev *pdev;
- pdev = pci_lock_pdev(bus, devfn);
+ pdev = pci_lock_pdev(msi->bus, msi->devfn);
if ( !pdev )
return -ENODEV;
- if ( find_msi_entry(pdev, vector, PCI_CAP_ID_MSI) )
+ if ( find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSI) )
{
spin_unlock(&pdev->lock);
- dprintk(XENLOG_WARNING, "vector %d has already mapped to MSI on device \
- %02x:%02x.%01x.\n", vector, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ dprintk(XENLOG_WARNING, "vector %d has already mapped to MSI on "
+ "device %02x:%02x.%01x.\n", msi->vector, msi->bus,
+ PCI_SLOT(msi->devfn), PCI_FUNC(msi->devfn));
return 0;
}
- status = msi_capability_init(pdev, vector);
+ status = msi_capability_init(pdev, msi->vector);
spin_unlock(&pdev->lock);
return status;
}
@@ -659,37 +638,37 @@ static void __pci_disable_msi(int vector)
* of irqs available. Driver should use the returned value to re-send
* its request.
**/
-static int __pci_enable_msix(u8 bus, u8 devfn, int vector, int entry_nr)
+static int __pci_enable_msix(struct msi_info *msi)
{
int status, pos, nr_entries;
struct pci_dev *pdev;
u16 control;
- u8 slot = PCI_SLOT(devfn);
- u8 func = PCI_FUNC(devfn);
+ u8 slot = PCI_SLOT(msi->devfn);
+ u8 func = PCI_FUNC(msi->devfn);
- pdev = pci_lock_pdev(bus, devfn);
+ pdev = pci_lock_pdev(msi->bus, msi->devfn);
if ( !pdev )
return -ENODEV;
- pos = pci_find_cap_offset(bus, slot, func, PCI_CAP_ID_MSIX);
- control = pci_conf_read16(bus, slot, func, msi_control_reg(pos));
+ pos = pci_find_cap_offset(msi->bus, slot, func, PCI_CAP_ID_MSIX);
+ control = pci_conf_read16(msi->bus, slot, func, msi_control_reg(pos));
nr_entries = multi_msix_capable(control);
- if (entry_nr > nr_entries)
+ if (msi->entry_nr > nr_entries)
{
spin_unlock(&pdev->lock);
return -EINVAL;
}
- if ( find_msi_entry(pdev, vector, PCI_CAP_ID_MSIX) )
+ if ( find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSIX) )
{
spin_unlock(&pdev->lock);
- dprintk(XENLOG_WARNING, "vector %d has already mapped to MSIX on \
- device %02x:%02x.%01x.\n", vector, bus,
- PCI_SLOT(devfn), PCI_FUNC(devfn));
+ dprintk(XENLOG_WARNING, "vector %d has already mapped to MSIX on "
+ "device %02x:%02x.%01x.\n", msi->vector, msi->bus,
+ PCI_SLOT(msi->devfn), PCI_FUNC(msi->devfn));
return 0;
}
- status = msix_capability_init(pdev, vector, entry_nr);
+ status = msix_capability_init(pdev, msi);
spin_unlock(&pdev->lock);
return status;
}
@@ -727,13 +706,12 @@ static void __pci_disable_msix(int vector)
spin_unlock(&dev->lock);
}
-int pci_enable_msi(u8 bus, u8 devfn, int vector, int entry_nr, int msi)
+int pci_enable_msi(struct msi_info *msi)
{
- ASSERT(spin_is_locked(&irq_desc[vector].lock));
- if ( msi )
- return __pci_enable_msi(bus, devfn, vector);
- else
- return __pci_enable_msix(bus, devfn, vector, entry_nr);
+ ASSERT(spin_is_locked(&irq_desc[msi->vector].lock));
+
+ return msi->table_base ? __pci_enable_msix(msi) :
+ __pci_enable_msi(msi);
}
void pci_disable_msi(int vector)
diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c
index acb46cbac0..af7ed5adf1 100644
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -66,6 +66,7 @@ static int map_domain_pirq(struct domain *d, int pirq, int vector,
{
int ret = 0;
int old_vector, old_pirq;
+ struct msi_info msi;
if ( d == NULL )
return -EINVAL;
@@ -115,10 +116,14 @@ static int map_domain_pirq(struct domain *d, int pirq, int vector,
vector);
desc->handler = &pci_msi_type;
- ret = pci_enable_msi(map->msi_info.bus,
- map->msi_info.devfn, vector,
- map->msi_info.entry_nr,
- map->msi_info.msi);
+ msi.bus = map->bus;
+ msi.devfn = map->devfn;
+ msi.entry_nr = map->entry_nr;
+ msi.table_base = map->table_base;
+ msi.vector = vector;
+
+ ret = pci_enable_msi(&msi);
+
spin_unlock_irqrestore(&desc->lock, flags);
if ( ret )
goto done;
@@ -139,7 +144,7 @@ static int unmap_domain_pirq(struct domain *d, int pirq)
int ret = 0;
int vector;
- if ( d == NULL || pirq < 0 || pirq > NR_PIRQS )
+ if ( d == NULL || pirq < 0 || pirq >= NR_PIRQS )
return -EINVAL;
if ( !IS_PRIV(current->domain) )
diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c
index ba809fb051..c8d81bcefa 100644
--- a/xen/drivers/passthrough/io.c
+++ b/xen/drivers/passthrough/io.c
@@ -75,6 +75,9 @@ int pt_irq_create_bind_vtd(
{
int pirq = pt_irq_bind->machine_irq;
+ if ( pirq < 0 || pirq >= NR_IRQS )
+ return -EINVAL;
+
if ( !(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_VALID ) )
{
hvm_irq_dpci->mirq[pirq].flags |= HVM_IRQ_DPCI_VALID |
diff --git a/xen/include/asm-x86/msi.h b/xen/include/asm-x86/msi.h
index 776fd6ebde..6aaffc90d5 100644
--- a/xen/include/asm-x86/msi.h
+++ b/xen/include/asm-x86/msi.h
@@ -54,6 +54,14 @@
#define MAX_MSIX_PAGES 32
#endif
+struct msi_info {
+ int bus;
+ int devfn;
+ int vector;
+ int entry_nr;
+ uint64_t table_base;
+};
+
struct msi_msg {
u32 address_lo; /* low 32 bits of msi message address */
u32 address_hi; /* high 32 bits of msi message address */
@@ -64,7 +72,7 @@ struct msi_msg {
extern void mask_msi_irq(unsigned int irq);
extern void unmask_msi_irq(unsigned int irq);
extern void set_msi_irq_affinity(unsigned int irq, cpumask_t mask);
-extern int pci_enable_msi(u8 bus, u8 devfn, int vector, int entry_nr, int msi);
+extern int pci_enable_msi(struct msi_info *msi);
extern void pci_disable_msi(int vector);
extern void pci_cleanup_msi(struct pci_dev *pdev);
diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h
index 77aedf546c..8057277baa 100644
--- a/xen/include/public/physdev.h
+++ b/xen/include/public/physdev.h
@@ -136,10 +136,13 @@ struct physdev_map_pirq {
/* IN or OUT */
int pirq;
/* IN */
- struct {
- int bus, devfn, entry_nr;
- int msi; /* 0 - MSIX 1 - MSI */
- } msi_info;
+ 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);