[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] PCI multi-seg: introduce notion of PCI segments
# HG changeset patch # User Jan Beulich <jbeulich@xxxxxxxx> # Date 1316301003 -3600 # Node ID e5263921c85e2ec98946dc4e6aa6bfd94b1920e3 # Parent b78235de5c6407023759f9bbf723dd83887fedf0 PCI multi-seg: introduce notion of PCI segments Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> --- diff -r b78235de5c64 -r e5263921c85e xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c Sun Sep 18 00:01:58 2011 +0100 +++ b/xen/arch/x86/setup.c Sun Sep 18 00:10:03 2011 +0100 @@ -1246,6 +1246,8 @@ local_irq_enable(); + pt_pci_init(); + #ifdef CONFIG_X86_64 vesa_mtrr_init(); diff -r b78235de5c64 -r e5263921c85e xen/arch/x86/x86_64/acpi_mmcfg.c --- a/xen/arch/x86/x86_64/acpi_mmcfg.c Sun Sep 18 00:01:58 2011 +0100 +++ b/xen/arch/x86/x86_64/acpi_mmcfg.c Sun Sep 18 00:10:03 2011 +0100 @@ -111,6 +111,7 @@ pci_mmcfg_config_num = 0; return -ENODEV; } + pci_add_segment(pci_mmcfg_config[i].pci_segment); } return 0; diff -r b78235de5c64 -r e5263921c85e xen/arch/x86/x86_64/mmconfig-shared.c --- a/xen/arch/x86/x86_64/mmconfig-shared.c Sun Sep 18 00:01:58 2011 +0100 +++ b/xen/arch/x86/x86_64/mmconfig-shared.c Sun Sep 18 00:10:03 2011 +0100 @@ -171,6 +171,7 @@ pci_mmcfg_config[i].pci_segment = i; pci_mmcfg_config[i].start_bus_number = 0; pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1; + pci_add_segment(i); } return "AMD Family 10h NB"; diff -r b78235de5c64 -r e5263921c85e xen/drivers/passthrough/pci.c --- a/xen/drivers/passthrough/pci.c Sun Sep 18 00:01:58 2011 +0100 +++ b/xen/drivers/passthrough/pci.c Sun Sep 18 00:10:03 2011 +0100 @@ -26,29 +26,93 @@ #include <asm/hvm/irq.h> #include <xen/delay.h> #include <xen/keyhandler.h> +#include <xen/radix-tree.h> #include <xen/tasklet.h> #ifdef CONFIG_X86 #include <asm/msi.h> #endif -LIST_HEAD(alldevs_list); +struct pci_seg { + struct list_head alldevs_list; + u16 nr; + /* bus2bridge_lock protects bus2bridge array */ + spinlock_t bus2bridge_lock; +#define MAX_BUSES 256 + struct { + u8 map; + u8 bus; + u8 devfn; + } bus2bridge[MAX_BUSES]; +}; + spinlock_t pcidevs_lock = SPIN_LOCK_UNLOCKED; +static struct radix_tree_root pci_segments; -#define MAX_BUSES 256 -static struct { - u8 map; - u8 bus; - u8 devfn; -} bus2bridge[MAX_BUSES]; +static inline struct pci_seg *get_pseg(u16 seg) +{ + return radix_tree_lookup(&pci_segments, seg); +} -/* bus2bridge_lock protects bus2bridge array */ -static DEFINE_SPINLOCK(bus2bridge_lock); +static struct pci_seg *alloc_pseg(u16 seg) +{ + struct pci_seg *pseg = get_pseg(seg); -static struct pci_dev *alloc_pdev(u8 bus, u8 devfn) + if ( pseg ) + return pseg; + + pseg = xmalloc(struct pci_seg); + if ( !pseg ) + return NULL; + + pseg->nr = seg; + INIT_LIST_HEAD(&pseg->alldevs_list); + spin_lock_init(&pseg->bus2bridge_lock); + memset(pseg->bus2bridge, 0, sizeof(pseg->bus2bridge)); + + if ( radix_tree_insert(&pci_segments, seg, pseg) ) + { + xfree(pseg); + pseg = NULL; + } + + return pseg; +} + +static int pci_segments_iterate( + int (*handler)(struct pci_seg *, void *), void *arg) +{ + u16 seg = 0; + int rc = 0; + + do { + struct pci_seg *pseg; + + if ( !radix_tree_gang_lookup(&pci_segments, (void **)&pseg, seg, 1) ) + break; + rc = handler(pseg, arg); + seg = pseg->nr + 1; + } while (!rc && seg); + + return rc; +} + +void __init pt_pci_init(void) +{ + radix_tree_init(&pci_segments); + if ( !alloc_pseg(0) ) + panic("Could not initialize PCI segment 0\n"); +} + +int __init pci_add_segment(u16 seg) +{ + return alloc_pseg(seg) ? 0 : -ENOMEM; +} + +static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn) { struct pci_dev *pdev; - list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) if ( pdev->bus == bus && pdev->devfn == devfn ) return pdev; @@ -61,7 +125,7 @@ *((u8*) &pdev->devfn) = devfn; pdev->domain = NULL; INIT_LIST_HEAD(&pdev->msi_list); - list_add(&pdev->alldevs_list, &alldevs_list); + list_add(&pdev->alldevs_list, &pseg->alldevs_list); spin_lock_init(&pdev->msix_table_lock); return pdev; @@ -75,11 +139,15 @@ struct pci_dev *pci_get_pdev(int bus, int devfn) { + struct pci_seg *pseg = get_pseg(0); struct pci_dev *pdev = NULL; ASSERT(spin_is_locked(&pcidevs_lock)); - list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + if ( !pseg ) + return NULL; + + list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) if ( (pdev->bus == bus || bus == -1) && (pdev->devfn == devfn || devfn == -1) ) { @@ -91,9 +159,13 @@ struct pci_dev *pci_get_pdev_by_domain(struct domain *d, int bus, int devfn) { + struct pci_seg *pseg = get_pseg(0); struct pci_dev *pdev = NULL; - list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + if ( !pseg ) + return NULL; + + list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) if ( (pdev->bus == bus || bus == -1) && (pdev->devfn == devfn || devfn == -1) && (pdev->domain == d) ) @@ -145,6 +217,7 @@ int pci_add_device(u8 bus, u8 devfn, const struct pci_dev_info *info) { + struct pci_seg *pseg; struct pci_dev *pdev; unsigned int slot = PCI_SLOT(devfn), func = PCI_FUNC(devfn); const char *pdev_type; @@ -167,7 +240,10 @@ return -EINVAL; spin_lock(&pcidevs_lock); - pdev = alloc_pdev(bus, devfn); + pseg = alloc_pseg(0); + if ( !pseg ) + goto out; + pdev = alloc_pdev(pseg, bus, devfn); if ( !pdev ) goto out; @@ -262,11 +338,15 @@ int pci_remove_device(u8 bus, u8 devfn) { + struct pci_seg *pseg = get_pseg(0); struct pci_dev *pdev; int ret = -ENODEV; + if ( !pseg ) + return -ENODEV; + spin_lock(&pcidevs_lock); - list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) if ( pdev->bus == bus && pdev->devfn == devfn ) { ret = iommu_remove_device(pdev); @@ -384,22 +464,26 @@ */ int find_upstream_bridge(u8 *bus, u8 *devfn, u8 *secbus) { + struct pci_seg *pseg = get_pseg(0); int ret = 0; int cnt = 0; if ( *bus == 0 ) return 0; - if ( !bus2bridge[*bus].map ) + if ( !pseg ) + return -1; + + if ( !pseg->bus2bridge[*bus].map ) return 0; ret = 1; - spin_lock(&bus2bridge_lock); - while ( bus2bridge[*bus].map ) + spin_lock(&pseg->bus2bridge_lock); + while ( pseg->bus2bridge[*bus].map ) { *secbus = *bus; - *devfn = bus2bridge[*bus].devfn; - *bus = bus2bridge[*bus].bus; + *devfn = pseg->bus2bridge[*bus].devfn; + *bus = pseg->bus2bridge[*bus].bus; if ( cnt++ >= MAX_BUSES ) { ret = -1; @@ -408,7 +492,7 @@ } out: - spin_unlock(&bus2bridge_lock); + spin_unlock(&pseg->bus2bridge_lock); return ret; } @@ -431,14 +515,13 @@ * scan pci devices to add all existed PCI devices to alldevs_list, * and setup pci hierarchy in array bus2bridge. */ -int __init scan_pci_devices(void) +static int __init _scan_pci_devices(struct pci_seg *pseg, void *arg) { struct pci_dev *pdev; int bus, dev, func; u8 sec_bus, sub_bus; int type; - spin_lock(&pcidevs_lock); for ( bus = 0; bus < 256; bus++ ) { for ( dev = 0; dev < 32; dev++ ) @@ -448,11 +531,10 @@ if ( pci_device_detect(bus, dev, func) == 0 ) continue; - pdev = alloc_pdev(bus, PCI_DEVFN(dev, func)); + pdev = alloc_pdev(pseg, bus, PCI_DEVFN(dev, func)); if ( !pdev ) { printk("%s: alloc_pdev failed.\n", __func__); - spin_unlock(&pcidevs_lock); return -ENOMEM; } @@ -470,14 +552,15 @@ sub_bus = pci_conf_read8(bus, dev, func, PCI_SUBORDINATE_BUS); - spin_lock(&bus2bridge_lock); + spin_lock(&pseg->bus2bridge_lock); for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ ) { - bus2bridge[sec_bus].map = 1; - bus2bridge[sec_bus].bus = bus; - bus2bridge[sec_bus].devfn = PCI_DEVFN(dev, func); + pseg->bus2bridge[sec_bus].map = 1; + pseg->bus2bridge[sec_bus].bus = bus; + pseg->bus2bridge[sec_bus].devfn = + PCI_DEVFN(dev, func); } - spin_unlock(&bus2bridge_lock); + spin_unlock(&pseg->bus2bridge_lock); break; case DEV_TYPE_PCIe_ENDPOINT: @@ -487,7 +570,6 @@ default: printk("%s: unknown type: bdf = %x:%x.%x\n", __func__, bus, dev, func); - spin_unlock(&pcidevs_lock); return -EINVAL; } @@ -498,8 +580,18 @@ } } + return 0; +} + +int __init scan_pci_devices(void) +{ + int ret; + + spin_lock(&pcidevs_lock); + ret = pci_segments_iterate(_scan_pci_devices, NULL); spin_unlock(&pcidevs_lock); - return 0; + + return ret; } /* Disconnect all PCI devices from the PCI buses. From the PCI spec: @@ -508,29 +600,33 @@ * configuration accesses. All devices are required to support * this base level of functionality." */ -void disconnect_pci_devices(void) +static int _disconnect_pci_devices(struct pci_seg *pseg, void *arg) { struct pci_dev *pdev; - spin_lock(&pcidevs_lock); - - list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) pci_conf_write16(pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), PCI_COMMAND, 0); + return 0; +} + +void disconnect_pci_devices(void) +{ + spin_lock(&pcidevs_lock); + pci_segments_iterate(_disconnect_pci_devices, NULL); spin_unlock(&pcidevs_lock); } #ifdef SUPPORT_MSI_REMAPPING -static void dump_pci_devices(unsigned char ch) +static int _dump_pci_devices(struct pci_seg *pseg, void *arg) { struct pci_dev *pdev; struct msi_desc *msi; - printk("==== PCI devices ====\n"); - spin_lock(&pcidevs_lock); + printk("==== segment %04x ====\n", pseg->nr); - list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) { printk("%02x:%02x.%x - dom %-3d - MSIs < ", pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), @@ -540,6 +636,14 @@ printk(">\n"); } + return 0; +} + +static void dump_pci_devices(unsigned char ch) +{ + printk("==== PCI devices ====\n"); + spin_lock(&pcidevs_lock); + pci_segments_iterate(_dump_pci_devices, NULL); spin_unlock(&pcidevs_lock); } diff -r b78235de5c64 -r e5263921c85e xen/include/xen/iommu.h --- a/xen/include/xen/iommu.h Sun Sep 18 00:01:58 2011 +0100 +++ b/xen/include/xen/iommu.h Sun Sep 18 00:10:03 2011 +0100 @@ -92,6 +92,8 @@ void iommu_set_pgd(struct domain *d); void iommu_domain_teardown(struct domain *d); +void pt_pci_init(void); + struct pirq; int hvm_do_IRQ_dpci(struct domain *, struct pirq *); int dpci_ioport_intercept(ioreq_t *p); diff -r b78235de5c64 -r e5263921c85e xen/include/xen/pci.h --- a/xen/include/xen/pci.h Sun Sep 18 00:01:58 2011 +0100 +++ b/xen/include/xen/pci.h Sun Sep 18 00:10:03 2011 +0100 @@ -89,6 +89,7 @@ struct pci_dev *pci_lock_domain_pdev(struct domain *d, int bus, int devfn); void pci_release_devices(struct domain *d); +int pci_add_segment(u16 seg); int pci_add_device(u8 bus, u8 devfn, const struct pci_dev_info *); int pci_remove_device(u8 bus, u8 devfn); struct pci_dev *pci_get_pdev(int bus, int devfn); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |