aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/hvm/vmsi.c2
-rw-r--r--xen/arch/x86/msi.c101
-rw-r--r--xen/drivers/passthrough/pci.c17
-rw-r--r--xen/include/asm-x86/msi.h16
-rw-r--r--xen/include/xen/pci.h14
5 files changed, 86 insertions, 64 deletions
diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
index 0244b133fe..e36c1f0d94 100644
--- a/xen/arch/x86/hvm/vmsi.c
+++ b/xen/arch/x86/hvm/vmsi.c
@@ -199,7 +199,7 @@ static void __iomem *msixtbl_addr_to_virt(
nr_page = (addr >> PAGE_SHIFT) -
(entry->gtable >> PAGE_SHIFT);
- idx = entry->pdev->msix_table_idx[nr_page];
+ idx = entry->pdev->msix->table_idx[nr_page];
if ( !idx )
return NULL;
diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c
index 3a8956aa3e..e17e5b2817 100644
--- a/xen/arch/x86/msi.c
+++ b/xen/arch/x86/msi.c
@@ -66,7 +66,7 @@ static void msix_fixmap_free(int idx)
spin_unlock(&msix_fixmap_lock);
}
-static int msix_get_fixmap(struct pci_dev *dev, u64 table_paddr,
+static int msix_get_fixmap(struct arch_msix *msix, u64 table_paddr,
u64 entry_paddr)
{
long nr_page;
@@ -77,48 +77,48 @@ static int msix_get_fixmap(struct pci_dev *dev, u64 table_paddr,
if ( nr_page < 0 || nr_page >= MAX_MSIX_TABLE_PAGES )
return -EINVAL;
- spin_lock(&dev->msix_table_lock);
- if ( dev->msix_table_refcnt[nr_page]++ == 0 )
+ spin_lock(&msix->table_lock);
+ if ( msix->table_refcnt[nr_page]++ == 0 )
{
idx = msix_fixmap_alloc();
if ( idx < 0 )
{
- dev->msix_table_refcnt[nr_page]--;
+ msix->table_refcnt[nr_page]--;
goto out;
}
set_fixmap_nocache(idx, entry_paddr);
- dev->msix_table_idx[nr_page] = idx;
+ msix->table_idx[nr_page] = idx;
}
else
- idx = dev->msix_table_idx[nr_page];
+ idx = msix->table_idx[nr_page];
out:
- spin_unlock(&dev->msix_table_lock);
+ spin_unlock(&msix->table_lock);
return idx;
}
-static void msix_put_fixmap(struct pci_dev *dev, int idx)
+static void msix_put_fixmap(struct arch_msix *msix, int idx)
{
int i;
- spin_lock(&dev->msix_table_lock);
+ spin_lock(&msix->table_lock);
for ( i = 0; i < MAX_MSIX_TABLE_PAGES; i++ )
{
- if ( dev->msix_table_idx[i] == idx )
+ if ( msix->table_idx[i] == idx )
break;
}
if ( i == MAX_MSIX_TABLE_PAGES )
goto out;
- if ( --dev->msix_table_refcnt[i] == 0 )
+ if ( --msix->table_refcnt[i] == 0 )
{
__set_fixmap(idx, 0, 0);
msix_fixmap_free(idx);
- dev->msix_table_idx[i] = 0;
+ msix->table_idx[i] = 0;
}
out:
- spin_unlock(&dev->msix_table_lock);
+ spin_unlock(&msix->table_lock);
}
/*
@@ -503,7 +503,7 @@ int msi_free_irq(struct msi_desc *entry)
{
unsigned long start;
start = (unsigned long)entry->mask_base & ~(PAGE_SIZE - 1);
- msix_put_fixmap(entry->dev, virt_to_fix(start));
+ msix_put_fixmap(entry->dev->msix, virt_to_fix(start));
nr = 1;
}
@@ -698,6 +698,7 @@ static int msix_capability_init(struct pci_dev *dev,
struct msi_desc **desc,
unsigned int nr_entries)
{
+ struct arch_msix *msix = dev->msix;
struct msi_desc *entry = NULL;
int pos, vf;
u16 control;
@@ -757,17 +758,17 @@ static int msix_capability_init(struct pci_dev *dev,
}
table_paddr += table_offset;
- if ( !dev->msix_used_entries )
+ if ( !msix->used_entries )
{
u64 pba_paddr;
u32 pba_offset;
- dev->msix_nr_entries = nr_entries;
- dev->msix_table.first = PFN_DOWN(table_paddr);
- dev->msix_table.last = PFN_DOWN(table_paddr +
- nr_entries * PCI_MSIX_ENTRY_SIZE - 1);
- WARN_ON(rangeset_overlaps_range(mmio_ro_ranges, dev->msix_table.first,
- dev->msix_table.last));
+ msix->nr_entries = nr_entries;
+ msix->table.first = PFN_DOWN(table_paddr);
+ msix->table.last = PFN_DOWN(table_paddr +
+ nr_entries * PCI_MSIX_ENTRY_SIZE - 1);
+ WARN_ON(rangeset_overlaps_range(mmio_ro_ranges, msix->table.first,
+ msix->table.last));
pba_offset = pci_conf_read32(seg, bus, slot, func,
msix_pba_offset_reg(pos));
@@ -776,18 +777,18 @@ static int msix_capability_init(struct pci_dev *dev,
WARN_ON(!pba_paddr);
pba_paddr += pba_offset & ~PCI_MSIX_BIRMASK;
- dev->msix_pba.first = PFN_DOWN(pba_paddr);
- dev->msix_pba.last = PFN_DOWN(pba_paddr +
- BITS_TO_LONGS(nr_entries) - 1);
- WARN_ON(rangeset_overlaps_range(mmio_ro_ranges, dev->msix_pba.first,
- dev->msix_pba.last));
+ msix->pba.first = PFN_DOWN(pba_paddr);
+ msix->pba.last = PFN_DOWN(pba_paddr +
+ BITS_TO_LONGS(nr_entries) - 1);
+ WARN_ON(rangeset_overlaps_range(mmio_ro_ranges, msix->pba.first,
+ msix->pba.last));
}
if ( entry )
{
/* Map MSI-X table region */
u64 entry_paddr = table_paddr + msi->entry_nr * PCI_MSIX_ENTRY_SIZE;
- int idx = msix_get_fixmap(dev, table_paddr, entry_paddr);
+ int idx = msix_get_fixmap(msix, table_paddr, entry_paddr);
void __iomem *base;
if ( idx < 0 )
@@ -815,13 +816,13 @@ static int msix_capability_init(struct pci_dev *dev,
*desc = entry;
}
- if ( !dev->msix_used_entries )
+ if ( !msix->used_entries )
{
- if ( rangeset_add_range(mmio_ro_ranges, dev->msix_table.first,
- dev->msix_table.last) )
+ if ( rangeset_add_range(mmio_ro_ranges, msix->table.first,
+ msix->table.last) )
WARN();
- if ( rangeset_add_range(mmio_ro_ranges, dev->msix_pba.first,
- dev->msix_pba.last) )
+ if ( rangeset_add_range(mmio_ro_ranges, msix->pba.first,
+ msix->pba.last) )
WARN();
if ( dev->domain )
@@ -834,16 +835,16 @@ static int msix_capability_init(struct pci_dev *dev,
if ( !d )
for_each_domain(d)
if ( !paging_mode_translate(d) &&
- (iomem_access_permitted(d, dev->msix_table.first,
- dev->msix_table.last) ||
- iomem_access_permitted(d, dev->msix_pba.first,
- dev->msix_pba.last)) )
+ (iomem_access_permitted(d, msix->table.first,
+ msix->table.last) ||
+ iomem_access_permitted(d, msix->pba.first,
+ msix->pba.last)) )
break;
if ( d )
{
- if ( !is_hardware_domain(d) && dev->msix_warned != d->domain_id )
+ if ( !is_hardware_domain(d) && msix->warned != d->domain_id )
{
- dev->msix_warned = d->domain_id;
+ msix->warned = d->domain_id;
printk(XENLOG_ERR
"Potentially insecure use of MSI-X on %04x:%02x:%02x.%u by Dom%d\n",
seg, bus, slot, func, d->domain_id);
@@ -852,9 +853,9 @@ static int msix_capability_init(struct pci_dev *dev,
}
}
}
- WARN_ON(dev->msix_nr_entries != nr_entries);
- WARN_ON(dev->msix_table.first != (table_paddr >> PAGE_SHIFT));
- ++dev->msix_used_entries;
+ WARN_ON(msix->nr_entries != nr_entries);
+ WARN_ON(msix->table.first != (table_paddr >> PAGE_SHIFT));
+ ++msix->used_entries;
/* Restore MSI-X enabled bits */
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos), control);
@@ -978,15 +979,15 @@ static int __pci_enable_msix(struct msi_info *msi, struct msi_desc **desc)
return status;
}
-static void _pci_cleanup_msix(struct pci_dev *dev)
+static void _pci_cleanup_msix(struct arch_msix *msix)
{
- if ( !--dev->msix_used_entries )
+ if ( !--msix->used_entries )
{
- if ( rangeset_remove_range(mmio_ro_ranges, dev->msix_table.first,
- dev->msix_table.last) )
+ if ( rangeset_remove_range(mmio_ro_ranges, msix->table.first,
+ msix->table.last) )
WARN();
- if ( rangeset_remove_range(mmio_ro_ranges, dev->msix_pba.first,
- dev->msix_pba.last) )
+ if ( rangeset_remove_range(mmio_ro_ranges, msix->pba.first,
+ msix->pba.last) )
WARN();
}
}
@@ -1014,7 +1015,7 @@ static void __pci_disable_msix(struct msi_desc *entry)
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos), control);
- _pci_cleanup_msix(dev);
+ _pci_cleanup_msix(dev->msix);
}
int pci_prepare_msix(u16 seg, u8 bus, u8 devfn, bool_t off)
@@ -1035,11 +1036,11 @@ int pci_prepare_msix(u16 seg, u8 bus, u8 devfn, bool_t off)
pdev = pci_get_pdev(seg, bus, devfn);
if ( !pdev )
rc = -ENODEV;
- else if ( pdev->msix_used_entries != !!off )
+ else if ( pdev->msix->used_entries != !!off )
rc = -EBUSY;
else if ( off )
{
- _pci_cleanup_msix(pdev);
+ _pci_cleanup_msix(pdev->msix);
rc = 0;
}
else
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index f2756c954a..b488e2ae18 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -179,8 +179,22 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn)
*((u8*) &pdev->devfn) = devfn;
pdev->domain = NULL;
INIT_LIST_HEAD(&pdev->msi_list);
+
+ if ( pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ PCI_CAP_ID_MSIX) )
+ {
+ struct arch_msix *msix = xzalloc(struct arch_msix);
+
+ if ( !msix )
+ {
+ xfree(pdev);
+ return NULL;
+ }
+ spin_lock_init(&msix->table_lock);
+ pdev->msix = msix;
+ }
+
list_add(&pdev->alldevs_list, &pseg->alldevs_list);
- spin_lock_init(&pdev->msix_table_lock);
/* update bus2bridge */
switch ( pdev->type = pdev_type(pseg->nr, bus, devfn) )
@@ -277,6 +291,7 @@ static void free_pdev(struct pci_seg *pseg, struct pci_dev *pdev)
}
list_del(&pdev->alldevs_list);
+ xfree(pdev->msix);
xfree(pdev);
}
diff --git a/xen/include/asm-x86/msi.h b/xen/include/asm-x86/msi.h
index 06e68533d3..9eeef63935 100644
--- a/xen/include/asm-x86/msi.h
+++ b/xen/include/asm-x86/msi.h
@@ -214,6 +214,22 @@ struct msg_address {
__u32 hi_address;
} __attribute__ ((packed));
+#define MAX_MSIX_TABLE_ENTRIES (PCI_MSIX_FLAGS_QSIZE + 1)
+#define MAX_MSIX_TABLE_PAGES PFN_UP(MAX_MSIX_TABLE_ENTRIES * \
+ PCI_MSIX_ENTRY_SIZE + \
+ (~PCI_MSIX_BIRMASK & (PAGE_SIZE - 1)))
+
+struct arch_msix {
+ unsigned int nr_entries, used_entries;
+ struct {
+ unsigned long first, last;
+ } table, pba;
+ int table_refcnt[MAX_MSIX_TABLE_PAGES];
+ int table_idx[MAX_MSIX_TABLE_PAGES];
+ spinlock_t table_lock;
+ domid_t warned;
+};
+
void early_msi_init(void);
void msi_compose_msg(struct irq_desc *, struct msi_msg *);
void __msi_set_enable(u16 seg, u8 bus, u8 slot, u8 func, int pos, int enable);
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index ca72a99434..c367736b21 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -32,10 +32,6 @@
#define PCI_BDF(b,d,f) ((((b) & 0xff) << 8) | PCI_DEVFN(d,f))
#define PCI_BDF2(b,df) ((((b) & 0xff) << 8) | ((df) & 0xff))
-#define MAX_MSIX_TABLE_ENTRIES (PCI_MSIX_FLAGS_QSIZE + 1)
-#define MAX_MSIX_TABLE_PAGES PFN_UP(MAX_MSIX_TABLE_ENTRIES * \
- PCI_MSIX_ENTRY_SIZE + \
- (~PCI_MSIX_BIRMASK & (PAGE_SIZE - 1)))
struct pci_dev_info {
bool_t is_extfn;
bool_t is_virtfn;
@@ -50,14 +46,8 @@ struct pci_dev {
struct list_head domain_list;
struct list_head msi_list;
- unsigned int msix_nr_entries, msix_used_entries;
- struct {
- unsigned long first, last;
- } msix_table, msix_pba;
- int msix_table_refcnt[MAX_MSIX_TABLE_PAGES];
- int msix_table_idx[MAX_MSIX_TABLE_PAGES];
- spinlock_t msix_table_lock;
- domid_t msix_warned;
+
+ struct arch_msix *msix;
struct domain *domain;
const u16 seg;