aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/vmsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'xen/arch/x86/hvm/vmsi.c')
-rw-r--r--xen/arch/x86/hvm/vmsi.c38
1 files changed, 24 insertions, 14 deletions
diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
index d9ec9fb0a4..87f3bd1396 100644
--- a/xen/arch/x86/hvm/vmsi.c
+++ b/xen/arch/x86/hvm/vmsi.c
@@ -157,7 +157,7 @@ struct msixtbl_entry
struct pci_dev *pdev;
unsigned long gtable; /* gpa of msix table */
unsigned long table_len;
- unsigned long table_flags[MAX_MSIX_TABLE_ENTRIES / BITS_PER_LONG + 1];
+ unsigned long table_flags[BITS_TO_LONGS(MAX_MSIX_TABLE_ENTRIES)];
struct rcu_head rcu;
};
@@ -179,17 +179,14 @@ static struct msixtbl_entry *msixtbl_find_entry(
static void __iomem *msixtbl_addr_to_virt(
struct msixtbl_entry *entry, unsigned long addr)
{
- int idx, nr_page;
+ unsigned int idx, nr_page;
- if ( !entry )
+ if ( !entry || !entry->pdev )
return NULL;
nr_page = (addr >> PAGE_SHIFT) -
(entry->gtable >> PAGE_SHIFT);
- if ( !entry->pdev )
- return NULL;
-
idx = entry->pdev->msix_table_idx[nr_page];
if ( !idx )
return NULL;
@@ -207,10 +204,10 @@ static int msixtbl_read(
void *virt;
int r = X86EMUL_UNHANDLEABLE;
- rcu_read_lock();
+ if ( len != 4 || (address & 3) )
+ return r;
- if ( len != 4 )
- goto out;
+ rcu_read_lock();
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET)
@@ -235,13 +232,13 @@ static int msixtbl_write(struct vcpu *v, unsigned long address,
unsigned long offset;
struct msixtbl_entry *entry;
void *virt;
- int nr_entry;
+ unsigned int nr_entry;
int r = X86EMUL_UNHANDLEABLE;
- rcu_read_lock();
+ if ( len != 4 || (address & 3) )
+ return r;
- if ( len != 4 )
- goto out;
+ rcu_read_lock();
entry = msixtbl_find_entry(v, address);
nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
@@ -261,9 +258,22 @@ static int msixtbl_write(struct vcpu *v, unsigned long address,
if ( !virt )
goto out;
+ /* Do not allow the mask bit to be changed. */
+#if 0 /* XXX
+ * As the mask bit is the only defined bit in the word, and as the
+ * host MSI-X code doesn't preserve the other bits anyway, doing
+ * this is pointless. So for now just discard the write (also
+ * saving us from having to determine the matching irq_desc).
+ */
+ spin_lock_irqsave(&desc->lock, flags);
+ orig = readl(virt);
+ val &= ~PCI_MSIX_VECTOR_BITMASK;
+ val |= orig & PCI_MSIX_VECTOR_BITMASK;
writel(val, virt);
- r = X86EMUL_OKAY;
+ spin_unlock_irqrestore(&desc->lock, flags);
+#endif
+ r = X86EMUL_OKAY;
out:
rcu_read_unlock();
return r;