From: Jeff Garzik <jgarzik@redhat.com> Date: Thu, 28 Aug 2008 17:53:07 -0400 Subject: [x86] PCI domain support Message-id: 20080828215307.GA31330@fokker.devel.redhat.com O-Subject: [RHEL5 PATCH] x86[-64] PCI domain support Bugzilla: 228290 RH-Acked-by: Prarit Bhargava <prarit@redhat.com> diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 8d050cf..5173059 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1109,6 +1109,11 @@ config XEN_PCIDEV_FE_DEBUG source "drivers/pci/pcie/Kconfig" +config PCI_DOMAINS + bool "Support multiple PCI domains" + depends on PCI + default y + source "drivers/pci/Kconfig" config ISA_DMA_API diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c index cae88fe..5bf20fa 100644 --- a/arch/i386/pci/acpi.c +++ b/arch/i386/pci/acpi.c @@ -190,22 +190,46 @@ res_alloc_fail: struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) { struct pci_bus *bus; - + struct pci_sysdata *sd; dmi_check_system(acpi_pciprobe_dmi_table); + int pxm; + + /* Allocate per-root-bus (not per bus) arch-specific data. + * TODO: leak; this memory is never freed. + * It's arguable whether it's worth the trouble to care. + */ + sd = (struct pci_sysdata *) kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) { + printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); + return NULL; + } + +#ifdef CONFIG_PCI_DOMAINS + sd->domain = domain; +#else if (domain != 0) { printk(KERN_WARNING "PCI: Multiple domains not supported\n"); return NULL; } +#endif /* CONFIG_PCI_DOMAINS */ + + sd->node = -1; + + pxm = acpi_get_pxm(device->handle); +#ifdef CONFIG_ACPI_NUMA + if (pxm >= 0) + sd->node = pxm_to_node(pxm); +#endif - bus = pcibios_scan_root(busnum); + bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); + if (!bus) + kfree(sd); #ifdef CONFIG_ACPI_NUMA if (bus != NULL) { - int pxm = acpi_get_pxm(device->handle); if (pxm >= 0) { - bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm); - printk("bus %d -> pxm %d -> node %ld\n", - busnum, pxm, (long)(bus->sysdata)); + printk("bus %d -> pxm %d -> node %d\n", + busnum, pxm, sd->node); } } #endif diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 95f9d14..a92da29 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -31,14 +31,18 @@ struct pci_raw_ops *raw_pci_ops; int pci_noseg = 0; #endif +struct pci_sysdata pci_default_sysdata = { .node = -1 }; + static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return raw_pci_ops->read(0, bus->number, devfn, where, size, value); + return raw_pci_ops->read(pci_domain_nr(bus), bus->number, + devfn, where, size, value); } static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return raw_pci_ops->write(0, bus->number, devfn, where, size, value); + return raw_pci_ops->write(pci_domain_nr(bus), bus->number, + devfn, where, size, value); } struct pci_ops pci_root_ops = { @@ -367,6 +371,7 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { struct pci_bus * __devinit pcibios_scan_root(int busnum) { struct pci_bus *bus = NULL; + struct pci_sysdata *sd; dmi_check_system(pciprobe_dmi_table); @@ -377,9 +382,19 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) } } + /* Allocate per-root-bus (not per bus) arch-specific data. + * TODO: leak; this memory is never freed. + * It's arguable whether it's worth the trouble to care. + */ + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) { + printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); + return NULL; + } + printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); - return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL); + return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); } extern u8 pci_cache_line_size; diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 8aec979..e1bfe98 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -664,6 +664,11 @@ config XEN_PCIDEV_FE_DEBUG source "drivers/pci/pcie/Kconfig" +config PCI_DOMAINS + bool "Support multiple PCI domains" + depends on PCI + default y + source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c index 3acf60d..9cc813e 100644 --- a/arch/x86_64/pci/k8-bus.c +++ b/arch/x86_64/pci/k8-bus.c @@ -59,6 +59,8 @@ fill_mp_bus_to_cpumask(void) j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus); j++) { struct pci_bus *bus; + struct pci_sysdata *sd; + long node = NODE_ID(nid); /* Algorithm a bit dumb, but it shouldn't matter here */ @@ -67,7 +69,9 @@ fill_mp_bus_to_cpumask(void) continue; if (!node_online(node)) node = 0; - bus->sysdata = (void *)node; + + sd = bus->sysdata; + sd->node = node; } } } diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index e9ae6f8..8bff0f8 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -36,6 +36,7 @@ #include <linux/acpi.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#include <asm/pci.h> #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_irq") diff --git a/include/asm-i386/mach-xen/asm/pci.h b/include/asm-i386/mach-xen/asm/pci.h index 584f65e..c991436 100644 --- a/include/asm-i386/mach-xen/asm/pci.h +++ b/include/asm-i386/mach-xen/asm/pci.h @@ -3,6 +3,26 @@ #ifdef __KERNEL__ + +struct pci_sysdata { + int domain; /* PCI domain */ + int node; /* NUMA node */ +}; + +#ifdef CONFIG_PCI_DOMAINS +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sysdata *sd = bus->sysdata; + return sd->domain; +} +extern struct pci_sysdata pci_default_sysdata; + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} +#endif /* CONFIG_PCI_DOMAINS */ + #include <linux/mm.h> /* for struct page */ /* Can be used to override the logic in pci_scan_bus for skipping diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h index 64b6d0b..d1c293b 100644 --- a/include/asm-i386/pci.h +++ b/include/asm-i386/pci.h @@ -3,6 +3,26 @@ #ifdef __KERNEL__ + +struct pci_sysdata { + int domain; /* PCI domain */ + int node; /* NUMA node */ +}; + +#ifdef CONFIG_PCI_DOMAINS +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sysdata *sd = bus->sysdata; + return sd->domain; +} +extern struct pci_sysdata pci_default_sysdata; + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} +#endif /* CONFIG_PCI_DOMAINS */ + #include <linux/mm.h> /* for struct page */ /* Can be used to override the logic in pci_scan_bus for skipping diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index 6adbd9b..9234497 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -67,7 +67,7 @@ static inline int node_to_first_cpu(int node) return first_cpu(mask); } -#define pcibus_to_node(bus) ((long) (bus)->sysdata) +#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus)) /* sched_domains SD_NODE_INIT for NUMAQ machines */ diff --git a/include/asm-x86_64/mach-xen/asm/pci.h b/include/asm-x86_64/mach-xen/asm/pci.h index 8ec15d9..6d88d4b 100644 --- a/include/asm-x86_64/mach-xen/asm/pci.h +++ b/include/asm-x86_64/mach-xen/asm/pci.h @@ -5,6 +5,25 @@ #ifdef __KERNEL__ +struct pci_sysdata { + int domain; /* PCI domain */ + int node; /* NUMA node */ +}; +extern struct pci_sysdata pci_default_sysdata; + +#ifdef CONFIG_PCI_DOMAINS +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sysdata *sd = bus->sysdata; + return sd->domain; +} + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} +#endif /* CONFIG_PCI_DOMAINS */ + #include <linux/mm.h> /* for struct page */ /* Can be used to override the logic in pci_scan_bus for skipping diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h index 49c5e92..f2ca179 100644 --- a/include/asm-x86_64/pci.h +++ b/include/asm-x86_64/pci.h @@ -5,6 +5,25 @@ #ifdef __KERNEL__ +struct pci_sysdata { + int domain; /* PCI domain */ + int node; /* NUMA node */ +}; +extern struct pci_sysdata pci_default_sysdata; + +#ifdef CONFIG_PCI_DOMAINS +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sysdata *sd = bus->sysdata; + return sd->domain; +} + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} +#endif /* CONFIG_PCI_DOMAINS */ + #include <linux/mm.h> /* for struct page */ /* Can be used to override the logic in pci_scan_bus for skipping diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index a9ddeeb..c38717c 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -22,7 +22,7 @@ extern int __node_distance(int, int); #define parent_node(node) (node) #define node_to_first_cpu(node) (first_cpu(node_to_cpumask[node])) #define node_to_cpumask(node) (node_to_cpumask[node]) -#define pcibus_to_node(bus) ((long)(bus->sysdata)) +#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus)); #define numa_node_id() read_pda(nodenumber) diff --git a/include/xen/pcifront.h b/include/xen/pcifront.h index 50d76fe..3a0fc87 100644 --- a/include/xen/pcifront.h +++ b/include/xen/pcifront.h @@ -33,18 +33,6 @@ static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain, sd->pdev = pdev; } -#if defined(CONFIG_PCI_DOMAINS) -static inline int pci_domain_nr(struct pci_bus *bus) -{ - struct pcifront_sd *sd = bus->sysdata; - return sd->domain; -} -static inline int pci_proc_domain(struct pci_bus *bus) -{ - return pci_domain_nr(bus); -} -#endif /* CONFIG_PCI_DOMAINS */ - #else /* __ia64__ */ #include <asm/pci.h>