File 5d80e857-x86-PCI-read-MSI-X-table-entry-count-early.patch of Package xen.15297
References: bsc#1135799
# Commit 27ddc58d42a7848dbe60ba9f127ddd052906d487
# Date 2019-09-17 16:06:15 +0200
# Author Jan Beulich <jbeulich@suse.com>
# Committer Jan Beulich <jbeulich@suse.com>
x86/PCI: read MSI-X table entry count early
Rather than doing this every time we set up interrupts for a device
anew (and then in two distinct places) fill this invariant field
right after allocating struct arch_msix.
While at it also obtain the MSI-X capability structure position just
once, in msix_capability_init(), rather than in each caller.
Furthermore take the opportunity and eliminate the multi_msix_capable()
alias of msix_table_size().
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
--- a/xen/arch/x86/msi.c
+++ b/xen/arch/x86/msi.c
@@ -839,10 +839,8 @@ static u64 read_pci_mem_bar(u16 seg, u8
* requested MSI-X entries with allocated irqs or non-zero for otherwise.
**/
static int msix_capability_init(struct pci_dev *dev,
- unsigned int pos,
struct msi_info *msi,
- struct msi_desc **desc,
- unsigned int nr_entries)
+ struct msi_desc **desc)
{
struct arch_msix *msix = dev->msix;
struct msi_desc *entry = NULL;
@@ -856,6 +854,11 @@ static int msix_capability_init(struct p
u8 slot = PCI_SLOT(dev->devfn);
u8 func = PCI_FUNC(dev->devfn);
bool maskall = msix->host_maskall;
+ unsigned int pos = pci_find_cap_offset(seg, bus, slot, func,
+ PCI_CAP_ID_MSIX);
+
+ if ( !pos )
+ return -ENODEV;
ASSERT(pcidevs_locked());
@@ -931,10 +934,9 @@ static int msix_capability_init(struct p
u64 pba_paddr;
u32 pba_offset;
- 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);
+ msix->nr_entries * PCI_MSIX_ENTRY_SIZE - 1);
WARN_ON(rangeset_overlaps_range(mmio_ro_ranges, msix->table.first,
msix->table.last));
@@ -947,7 +949,7 @@ static int msix_capability_init(struct p
msix->pba.first = PFN_DOWN(pba_paddr);
msix->pba.last = PFN_DOWN(pba_paddr +
- BITS_TO_LONGS(nr_entries) - 1);
+ BITS_TO_LONGS(msix->nr_entries) - 1);
WARN_ON(rangeset_overlaps_range(mmio_ro_ranges, msix->pba.first,
msix->pba.last));
}
@@ -1019,7 +1021,6 @@ static int msix_capability_init(struct p
/* XXX How to deal with existing mappings? */
}
}
- WARN_ON(msix->nr_entries != nr_entries);
WARN_ON(msix->table.first != (table_paddr >> PAGE_SHIFT));
++msix->used_entries;
@@ -1113,23 +1114,17 @@ static void __pci_disable_msi(struct msi
**/
static int __pci_enable_msix(struct msi_info *msi, struct msi_desc **desc)
{
- int pos, nr_entries;
struct pci_dev *pdev;
- u16 control;
u8 slot = PCI_SLOT(msi->devfn);
u8 func = PCI_FUNC(msi->devfn);
struct msi_desc *old_desc;
ASSERT(pcidevs_locked());
pdev = pci_get_pdev(msi->seg, msi->bus, msi->devfn);
- pos = pci_find_cap_offset(msi->seg, msi->bus, slot, func, PCI_CAP_ID_MSIX);
- if ( !pdev || !pos )
+ if ( !pdev || !pdev->msix )
return -ENODEV;
- control = pci_conf_read16(msi->seg, msi->bus, slot, func,
- msix_control_reg(pos));
- nr_entries = multi_msix_capable(control);
- if ( msi->entry_nr >= nr_entries )
+ if ( msi->entry_nr >= pdev->msix->nr_entries )
return -EINVAL;
old_desc = find_msi_entry(pdev, msi->irq, PCI_CAP_ID_MSIX);
@@ -1148,7 +1143,7 @@ static int __pci_enable_msix(struct msi_
__pci_disable_msi(old_desc);
}
- return msix_capability_init(pdev, pos, msi, desc, nr_entries);
+ return msix_capability_init(pdev, msi, desc);
}
static void _pci_cleanup_msix(struct arch_msix *msix)
@@ -1208,16 +1203,10 @@ int pci_prepare_msix(u16 seg, u8 bus, u8
{
int rc;
struct pci_dev *pdev;
- u8 slot = PCI_SLOT(devfn), func = PCI_FUNC(devfn);
- unsigned int pos = pci_find_cap_offset(seg, bus, slot, func,
- PCI_CAP_ID_MSIX);
if ( !use_msi )
return 0;
- if ( !pos )
- return -ENODEV;
-
pcidevs_lock();
pdev = pci_get_pdev(seg, bus, devfn);
if ( !pdev )
@@ -1230,13 +1219,7 @@ int pci_prepare_msix(u16 seg, u8 bus, u8
rc = 0;
}
else
- {
- u16 control = pci_conf_read16(seg, bus, slot, func,
- msix_control_reg(pos));
-
- rc = msix_capability_init(pdev, pos, NULL, NULL,
- multi_msix_capable(control));
- }
+ rc = msix_capability_init(pdev, NULL, NULL);
pcidevs_unlock();
return rc;
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -330,6 +330,7 @@ static void apply_quirks(struct pci_dev
static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn)
{
struct pci_dev *pdev;
+ unsigned int pos;
list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list )
if ( pdev->bus == bus && pdev->devfn == devfn )
@@ -345,10 +346,12 @@ static struct pci_dev *alloc_pdev(struct
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) )
+ pos = pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ PCI_CAP_ID_MSIX);
+ if ( pos )
{
struct arch_msix *msix = xzalloc(struct arch_msix);
+ uint16_t ctrl;
if ( !msix )
{
@@ -356,6 +359,11 @@ static struct pci_dev *alloc_pdev(struct
return NULL;
}
spin_lock_init(&msix->table_lock);
+
+ ctrl = pci_conf_read16(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ msix_control_reg(pos));
+ msix->nr_entries = msix_table_size(ctrl);
+
pdev->msix = msix;
}
@@ -364,7 +372,6 @@ static struct pci_dev *alloc_pdev(struct
/* update bus2bridge */
switch ( pdev->type = pdev_type(pseg->nr, bus, devfn) )
{
- int pos;
u16 cap;
u8 sec_bus, sub_bus;
--- a/xen/include/asm-x86/msi.h
+++ b/xen/include/asm-x86/msi.h
@@ -172,7 +172,6 @@ int msi_free_irq(struct msi_desc *entry)
#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE
#define msix_disable(control) control &= ~PCI_MSIX_FLAGS_ENABLE
#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1)
-#define multi_msix_capable msix_table_size
#define msix_unmask(address) (address & ~PCI_MSIX_VECTOR_BITMASK)
#define msix_mask(address) (address | PCI_MSIX_VECTOR_BITMASK)