[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] passthrough: fix MSI-X table fixmap allocation
Currently, msix table pages are allocated a fixmap page per vector, the available fixmap pages will be depleted when assigning devices with large number of vectors. This patch fixes it, and a bug that prevents cross-page MSI-X table from working properly Signed-off-by: Qing He <qing.he@xxxxxxxxx> --- arch/x86/msi.c | 109 +++++++++++++++++++++++++++++++++------------- drivers/passthrough/pci.c | 1 include/asm-x86/fixmap.h | 2 include/asm-x86/msi.h | 6 +- include/xen/pci.h | 6 ++ 5 files changed, 90 insertions(+), 34 deletions(-) diff -r c3b5e36248c9 xen/arch/x86/msi.c --- a/xen/arch/x86/msi.c Tue Feb 03 18:14:19 2009 +0000 +++ b/xen/arch/x86/msi.c Wed Feb 04 14:41:03 2009 +0800 @@ -29,17 +29,17 @@ /* bitmap indicate which fixed map is free */ DEFINE_SPINLOCK(msix_fixmap_lock); -DECLARE_BITMAP(msix_fixmap_pages, MAX_MSIX_PAGES); +DECLARE_BITMAP(msix_fixmap_pages, FIX_MSIX_MAX_PAGES); static int msix_fixmap_alloc(void) { - int i, rc = -1; + int i, rc = -ENOMEM; spin_lock(&msix_fixmap_lock); - for ( i = 0; i < MAX_MSIX_PAGES; i++ ) + for ( i = 0; i < FIX_MSIX_MAX_PAGES; i++ ) if ( !test_bit(i, &msix_fixmap_pages) ) break; - if ( i == MAX_MSIX_PAGES ) + if ( i == FIX_MSIX_MAX_PAGES ) goto out; rc = FIX_MSIX_IO_RESERV_BASE + i; set_bit(i, &msix_fixmap_pages); @@ -51,8 +51,66 @@ static int msix_fixmap_alloc(void) static void msix_fixmap_free(int idx) { + spin_lock(&msix_fixmap_lock); if ( idx >= FIX_MSIX_IO_RESERV_BASE ) clear_bit(idx - FIX_MSIX_IO_RESERV_BASE, &msix_fixmap_pages); + spin_unlock(&msix_fixmap_lock); +} + +static int msix_get_fixmap(struct pci_dev *dev, unsigned long table_paddr, + unsigned long entry_paddr) +{ + int nr_page, idx; + + nr_page = (entry_paddr >> PAGE_SHIFT) - (table_paddr >> PAGE_SHIFT); + + 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 ) + { + idx = msix_fixmap_alloc(); + if ( idx < 0 ) + { + dev->msix_table_refcnt[nr_page]--; + goto out; + } + set_fixmap_nocache(idx, entry_paddr); + dev->msix_table_idx[nr_page] = idx; + } + else + idx = dev->msix_table_idx[nr_page]; + + out: + spin_unlock(&dev->msix_table_lock); + return idx; +} + +static void msix_put_fixmap(struct pci_dev *dev, int idx) +{ + int i; + unsigned long start; + + spin_lock(&dev->msix_table_lock); + for ( i = 0; i < MAX_MSIX_TABLE_PAGES; i++ ) + { + if ( dev->msix_table_idx[i] == idx ) + break; + } + if ( i == MAX_MSIX_TABLE_PAGES ) + goto out; + + if ( --dev->msix_table_refcnt[i] == 0 ) + { + start = fix_to_virt(idx); + destroy_xen_mappings(start, start + PAGE_SIZE); + msix_fixmap_free(idx); + dev->msix_table_idx[i] = 0; + } + + out: + spin_unlock(&dev->msix_table_lock); } /* @@ -122,8 +180,7 @@ static void read_msi_msg(struct msi_desc case PCI_CAP_ID_MSIX: { void __iomem *base; - base = entry->mask_base + - entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; + base = entry->mask_base; msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); @@ -199,8 +256,7 @@ static void write_msi_msg(struct msi_des case PCI_CAP_ID_MSIX: { void __iomem *base; - base = entry->mask_base + - entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; + base = entry->mask_base; writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); @@ -288,8 +344,7 @@ static void msix_flush_writes(unsigned i break; case PCI_CAP_ID_MSIX: { - int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; + int offset = PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; readl(entry->mask_base + offset); break; } @@ -330,8 +385,7 @@ static void msi_set_mask_bit(unsigned in break; case PCI_CAP_ID_MSIX: { - int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; + int offset = PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; writel(flag, entry->mask_base + offset); readl(entry->mask_base + offset); break; @@ -392,13 +446,10 @@ int msi_free_vector(struct msi_desc *ent { unsigned long start; - writel(1, entry->mask_base + entry->msi_attrib.entry_nr - * PCI_MSIX_ENTRY_SIZE - + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + writel(1, entry->mask_base + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); start = (unsigned long)entry->mask_base & ~(PAGE_SIZE - 1); - msix_fixmap_free(virt_to_fix(start)); - destroy_xen_mappings(start, start + PAGE_SIZE); + msix_put_fixmap(entry->dev, virt_to_fix(start)); } list_del(&entry->list); xfree(entry); @@ -500,8 +551,8 @@ static int msix_capability_init(struct p struct msi_desc *entry; int pos; u16 control; - unsigned long phys_addr; - u32 table_offset; + unsigned long table_paddr, entry_paddr; + u32 table_offset, entry_offset; u8 bir; void __iomem *base; int idx; @@ -525,15 +576,17 @@ static int msix_capability_init(struct p 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 = msi->table_base + table_offset; - idx = msix_fixmap_alloc(); + entry_offset = msi->entry_nr * PCI_MSIX_ENTRY_SIZE; + + table_paddr = msi->table_base + table_offset; + entry_paddr = table_paddr + entry_offset; + idx = msix_get_fixmap(dev, table_paddr, entry_paddr); if ( idx < 0 ) { xfree(entry); - return -ENOMEM; + return idx; } - set_fixmap_nocache(idx, phys_addr); - base = (void *)(fix_to_virt(idx) + (phys_addr & ((1UL << PAGE_SHIFT) - 1))); + base = (void *)(fix_to_virt(idx) + (entry_paddr & ((1UL << PAGE_SHIFT) - 1))); entry->msi_attrib.type = PCI_CAP_ID_MSIX; entry->msi_attrib.is_64 = 1; @@ -548,9 +601,7 @@ static int msix_capability_init(struct p list_add_tail(&entry->list, &dev->msi_list); /* Mask interrupt here */ - writel(1, entry->mask_base + entry->msi_attrib.entry_nr - * PCI_MSIX_ENTRY_SIZE - + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + writel(1, entry->mask_base + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); *desc = entry; /* Restore MSI-X enabled bits */ @@ -675,9 +726,7 @@ static void __pci_disable_msix(struct ms BUG_ON(list_empty(&dev->msi_list)); - writel(1, entry->mask_base + entry->msi_attrib.entry_nr - * PCI_MSIX_ENTRY_SIZE - + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + writel(1, entry->mask_base + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); pci_conf_write16(bus, slot, func, msix_control_reg(pos), control); } diff -r c3b5e36248c9 xen/drivers/passthrough/pci.c --- a/xen/drivers/passthrough/pci.c Tue Feb 03 18:14:19 2009 +0000 +++ b/xen/drivers/passthrough/pci.c Wed Feb 04 14:41:03 2009 +0800 @@ -48,6 +48,7 @@ struct pci_dev *alloc_pdev(u8 bus, u8 de pdev->domain = NULL; INIT_LIST_HEAD(&pdev->msi_list); list_add(&pdev->alldevs_list, &alldevs_list); + spin_lock_init(&pdev->msix_table_lock); return pdev; } diff -r c3b5e36248c9 xen/include/asm-x86/fixmap.h --- a/xen/include/asm-x86/fixmap.h Tue Feb 03 18:14:19 2009 +0000 +++ b/xen/include/asm-x86/fixmap.h Wed Feb 04 14:41:03 2009 +0800 @@ -50,7 +50,7 @@ enum fixed_addresses { FIX_IOMMU_MMIO_END = FIX_IOMMU_MMIO_BASE_0 + IOMMU_PAGES -1, FIX_TBOOT_SHARED_BASE, FIX_MSIX_IO_RESERV_BASE, - FIX_MSIX_IO_RESERV_END = FIX_MSIX_IO_RESERV_BASE + MAX_MSIX_PAGES -1, + FIX_MSIX_IO_RESERV_END = FIX_MSIX_IO_RESERV_BASE + FIX_MSIX_MAX_PAGES -1, __end_of_fixed_addresses }; diff -r c3b5e36248c9 xen/include/asm-x86/msi.h --- a/xen/include/asm-x86/msi.h Tue Feb 03 18:14:19 2009 +0000 +++ b/xen/include/asm-x86/msi.h Wed Feb 04 14:41:03 2009 +0800 @@ -49,9 +49,9 @@ /* MAX fixed pages reserved for mapping MSIX tables. */ #if defined(__x86_64__) -#define MAX_MSIX_PAGES 512 +#define FIX_MSIX_MAX_PAGES 512 #else -#define MAX_MSIX_PAGES 32 +#define FIX_MSIX_MAX_PAGES 32 #endif struct msi_info { @@ -93,7 +93,7 @@ struct msi_desc { struct list_head list; - void __iomem *mask_base; + void __iomem *mask_base; /* va for the entry in mask table */ struct pci_dev *dev; int vector; diff -r c3b5e36248c9 xen/include/xen/pci.h --- a/xen/include/xen/pci.h Tue Feb 03 18:14:19 2009 +0000 +++ b/xen/include/xen/pci.h Wed Feb 04 14:41:03 2009 +0800 @@ -29,10 +29,16 @@ #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_PAGES 8 /* 2048 entries */ struct pci_dev { struct list_head alldevs_list; struct list_head domain_list; + struct list_head msi_list; + int msix_table_refcnt[MAX_MSIX_TABLE_PAGES]; + int msix_table_idx[MAX_MSIX_TABLE_PAGES]; + spinlock_t msix_table_lock; + struct domain *domain; const u8 bus; const u8 devfn; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |