Subject: [PATCH] PCI, X86: busnum/node boot command line for pci dev node setting. Some intel new sandybridge or newer two sockets system do support support numa for pci devices. But BIOS does not provide _PXM under those root bus in DSDT. Add boot command line, so user could have chance to input node info before BIOS guys figure out to add _PXM. Fold fix from Ulrich to use ";" instead of ",". | The problem is the pci= parameter | handling uses ',' to separate parameters and therefore the second PCI | root information, separated by a comma, is interpreted as a new pci= | parameter. -v3: According to Bjorn and Ingo, change to use "user input first" policy so it could cover wrong _PXM case. -v5: revert back to -v3, and change to use saved_command_line. Reported-by: Ulrich Drepper Signed-off-by: Yinghai Lu --- Documentation/kernel-parameters.txt | 5 +++++ arch/x86/include/asm/pci_x86.h | 3 +++ arch/x86/pci/acpi.c | 22 +++++++++++++--------- arch/x86/pci/common.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 9 deletions(-) Index: linux-2.6/Documentation/kernel-parameters.txt =================================================================== --- linux-2.6.orig/Documentation/kernel-parameters.txt +++ linux-2.6/Documentation/kernel-parameters.txt @@ -2195,6 +2195,11 @@ bytes respectively. Such letter suffixes only look for one device below a PCIe downstream port. + busnum_node= [X86] Set node for root bus. + Format: + :[; ...] + Specifies node for bus, will override bios _PXM + or probed value from hostbridge. pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power Management. off Disable ASPM. Index: linux-2.6/arch/x86/pci/common.c =================================================================== --- linux-2.6.orig/arch/x86/pci/common.c +++ linux-2.6/arch/x86/pci/common.c @@ -494,6 +494,34 @@ int __init pcibios_init(void) return 0; } +int get_user_busnum_node(int busnum) +{ + int bus, node, count; + char *p; + + p = strstr(saved_command_line, "busnum_node="); + if (!p) + return -1; + + p += 12; /* strlen("busnum_node=") */ + while (*p) { + count = 0; + if (sscanf(p, "%x:%x%n", &bus, &node, &count) != 2) { + printk(KERN_ERR "PCI: Can't parse busnum_node input: %s\n", + p); + break; + } + if (bus == busnum) + return node; + p += count; + if (*p != ';') + break; + p++; + } + + return -1; +} + char * __devinit pcibios_setup(char *str) { if (!strcmp(str, "off")) { Index: linux-2.6/arch/x86/include/asm/pci_x86.h =================================================================== --- linux-2.6.orig/arch/x86/include/asm/pci_x86.h +++ linux-2.6/arch/x86/include/asm/pci_x86.h @@ -46,6 +46,9 @@ enum pci_bf_sort_state { pci_dmi_bf, }; +/* pci-common.c */ +int get_user_busnum_node(int busnum); + /* pci-i386.c */ void pcibios_resource_survey(void); Index: linux-2.6/arch/x86/pci/acpi.c =================================================================== --- linux-2.6.orig/arch/x86/pci/acpi.c +++ linux-2.6/arch/x86/pci/acpi.c @@ -433,7 +433,7 @@ struct pci_bus * __devinit pci_acpi_scan struct pci_sysdata *sd; int node; #ifdef CONFIG_ACPI_NUMA - int pxm; + int pxm = -1; #endif if (domain && !pci_domains_supported) { @@ -443,16 +443,20 @@ struct pci_bus * __devinit pci_acpi_scan return NULL; } - node = -1; + node = get_user_busnum_node(busnum); + if (node == -1) { #ifdef CONFIG_ACPI_NUMA - pxm = acpi_get_pxm(device->handle); - if (pxm >= 0) - node = pxm_to_node(pxm); - if (node != -1) - set_mp_bus_to_node(busnum, node); - else -#endif + pxm = acpi_get_pxm(device->handle); + if (pxm >= 0) + node = pxm_to_node(pxm); + if (node != -1) + set_mp_bus_to_node(busnum, node); + else + node = get_mp_bus_to_node(busnum); +#else node = get_mp_bus_to_node(busnum); +#endif + } if (node != -1 && !node_online(node)) node = -1;