diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:26:51 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:26:51 -0400 |
| commit | 5f78e4d33945b291d12765cdd7e4304f437b9361 (patch) | |
| tree | 113cea729de15a98bb941cc4afb8d13301534ca7 /arch/x86 | |
| parent | 867a89e0b73af48838c7987e80899a1ff26dd6ff (diff) | |
| parent | 5f0b2976cb2b62668a076f54419c24b8ab677167 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci:
x86: add pci=check_enable_amd_mmconf and dmi check
x86: work around io allocation overlap of HT links
acpi: get boot_cpu_id as early for k8_scan_nodes
x86_64: don't need set default res if only have one root bus
x86: double check the multi root bus with fam10h mmconf
x86: multi pci root bus with different io resource range, on 64-bit
x86: use bus conf in NB conf fun1 to get bus range on, on 64-bit
x86: get mp_bus_to_node early
x86 pci: remove checking type for mmconfig probe
x86: remove unneeded check in mmconf reject
driver core: try parent numa_node at first before using default
x86: seperate mmconf for fam10h out from setup_64.c
x86: if acpi=off, force setting the mmconf for fam10h
x86_64: check MSR to get MMCONFIG for AMD Family 10h
x86_64: check and enable MMCONFIG for AMD Family 10h
x86_64: set cfg_size for AMD Family 10h in case MMCONFIG
x86: mmconf enable mcfg early
x86: clear pci_mmcfg_virt when mmcfg get rejected
x86: validate against acpi motherboard resources
Fixed up fairly trivial conflicts in arch/x86/pci/{init.c,pci.h} due to
OLPC support manually.
Diffstat (limited to 'arch/x86')
| -rw-r--r-- | arch/x86/kernel/Makefile | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/acpi/boot.c | 70 | ||||
| -rw-r--r-- | arch/x86/kernel/mmconf-fam10h_64.c | 243 | ||||
| -rw-r--r-- | arch/x86/kernel/setup_64.c | 20 | ||||
| -rw-r--r-- | arch/x86/mm/k8topology_64.c | 38 | ||||
| -rw-r--r-- | arch/x86/pci/Makefile_32 | 1 | ||||
| -rw-r--r-- | arch/x86/pci/Makefile_64 | 2 | ||||
| -rw-r--r-- | arch/x86/pci/acpi.c | 27 | ||||
| -rw-r--r-- | arch/x86/pci/common.c | 22 | ||||
| -rw-r--r-- | arch/x86/pci/direct.c | 8 | ||||
| -rw-r--r-- | arch/x86/pci/fixup.c | 17 | ||||
| -rw-r--r-- | arch/x86/pci/init.c | 14 | ||||
| -rw-r--r-- | arch/x86/pci/irq.c | 4 | ||||
| -rw-r--r-- | arch/x86/pci/k8-bus_64.c | 575 | ||||
| -rw-r--r-- | arch/x86/pci/legacy.c | 4 | ||||
| -rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 247 | ||||
| -rw-r--r-- | arch/x86/pci/mmconfig_32.c | 4 | ||||
| -rw-r--r-- | arch/x86/pci/mmconfig_64.c | 22 | ||||
| -rw-r--r-- | arch/x86/pci/mp_bus_to_node.c | 23 | ||||
| -rw-r--r-- | arch/x86/pci/pci.h | 3 |
20 files changed, 1219 insertions, 127 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 350eb1b2a2..30d54ed27e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
| @@ -103,4 +103,6 @@ ifeq ($(CONFIG_X86_64),y) | |||
| 103 | obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o | 103 | obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o |
| 104 | obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o | 104 | obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o |
| 105 | obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o | 105 | obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o |
| 106 | |||
| 107 | obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o | ||
| 106 | endif | 108 | endif |
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 977ed5cdea..c49ebcc6c4 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
| @@ -771,6 +771,32 @@ static void __init acpi_register_lapic_address(unsigned long address) | |||
| 771 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 771 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); |
| 772 | } | 772 | } |
| 773 | 773 | ||
| 774 | static int __init early_acpi_parse_madt_lapic_addr_ovr(void) | ||
| 775 | { | ||
| 776 | int count; | ||
| 777 | |||
| 778 | if (!cpu_has_apic) | ||
| 779 | return -ENODEV; | ||
| 780 | |||
| 781 | /* | ||
| 782 | * Note that the LAPIC address is obtained from the MADT (32-bit value) | ||
| 783 | * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). | ||
| 784 | */ | ||
| 785 | |||
| 786 | count = | ||
| 787 | acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, | ||
| 788 | acpi_parse_lapic_addr_ovr, 0); | ||
| 789 | if (count < 0) { | ||
| 790 | printk(KERN_ERR PREFIX | ||
| 791 | "Error parsing LAPIC address override entry\n"); | ||
| 792 | return count; | ||
| 793 | } | ||
| 794 | |||
| 795 | acpi_register_lapic_address(acpi_lapic_addr); | ||
| 796 | |||
| 797 | return count; | ||
| 798 | } | ||
| 799 | |||
| 774 | static int __init acpi_parse_madt_lapic_entries(void) | 800 | static int __init acpi_parse_madt_lapic_entries(void) |
| 775 | { | 801 | { |
| 776 | int count; | 802 | int count; |
| @@ -901,6 +927,33 @@ static inline int acpi_parse_madt_ioapic_entries(void) | |||
| 901 | } | 927 | } |
| 902 | #endif /* !CONFIG_X86_IO_APIC */ | 928 | #endif /* !CONFIG_X86_IO_APIC */ |
| 903 | 929 | ||
| 930 | static void __init early_acpi_process_madt(void) | ||
| 931 | { | ||
| 932 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 933 | int error; | ||
| 934 | |||
| 935 | if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) { | ||
| 936 | |||
| 937 | /* | ||
| 938 | * Parse MADT LAPIC entries | ||
| 939 | */ | ||
| 940 | error = early_acpi_parse_madt_lapic_addr_ovr(); | ||
| 941 | if (!error) { | ||
| 942 | acpi_lapic = 1; | ||
| 943 | smp_found_config = 1; | ||
| 944 | } | ||
| 945 | if (error == -EINVAL) { | ||
| 946 | /* | ||
| 947 | * Dell Precision Workstation 410, 610 come here. | ||
| 948 | */ | ||
| 949 | printk(KERN_ERR PREFIX | ||
| 950 | "Invalid BIOS MADT, disabling ACPI\n"); | ||
| 951 | disable_acpi(); | ||
| 952 | } | ||
| 953 | } | ||
| 954 | #endif | ||
| 955 | } | ||
| 956 | |||
| 904 | static void __init acpi_process_madt(void) | 957 | static void __init acpi_process_madt(void) |
| 905 | { | 958 | { |
| 906 | #ifdef CONFIG_X86_LOCAL_APIC | 959 | #ifdef CONFIG_X86_LOCAL_APIC |
| @@ -1233,6 +1286,23 @@ int __init acpi_boot_table_init(void) | |||
| 1233 | return 0; | 1286 | return 0; |
| 1234 | } | 1287 | } |
| 1235 | 1288 | ||
| 1289 | int __init early_acpi_boot_init(void) | ||
| 1290 | { | ||
| 1291 | /* | ||
| 1292 | * If acpi_disabled, bail out | ||
| 1293 | * One exception: acpi=ht continues far enough to enumerate LAPICs | ||
| 1294 | */ | ||
| 1295 | if (acpi_disabled && !acpi_ht) | ||
| 1296 | return 1; | ||
| 1297 | |||
| 1298 | /* | ||
| 1299 | * Process the Multiple APIC Description Table (MADT), if present | ||
| 1300 | */ | ||
| 1301 | early_acpi_process_madt(); | ||
| 1302 | |||
| 1303 | return 0; | ||
| 1304 | } | ||
| 1305 | |||
| 1236 | int __init acpi_boot_init(void) | 1306 | int __init acpi_boot_init(void) |
| 1237 | { | 1307 | { |
| 1238 | /* | 1308 | /* |
diff --git a/arch/x86/kernel/mmconf-fam10h_64.c b/arch/x86/kernel/mmconf-fam10h_64.c new file mode 100644 index 0000000000..edc5fbfe85 --- /dev/null +++ b/arch/x86/kernel/mmconf-fam10h_64.c | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | /* | ||
| 2 | * AMD Family 10h mmconfig enablement | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <linux/types.h> | ||
| 6 | #include <linux/mm.h> | ||
| 7 | #include <linux/string.h> | ||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/dmi.h> | ||
| 10 | #include <asm/pci-direct.h> | ||
| 11 | #include <linux/sort.h> | ||
| 12 | #include <asm/io.h> | ||
| 13 | #include <asm/msr.h> | ||
| 14 | #include <asm/acpi.h> | ||
| 15 | |||
| 16 | #include "../pci/pci.h" | ||
| 17 | |||
| 18 | struct pci_hostbridge_probe { | ||
| 19 | u32 bus; | ||
| 20 | u32 slot; | ||
| 21 | u32 vendor; | ||
| 22 | u32 device; | ||
| 23 | }; | ||
| 24 | |||
| 25 | static u64 __cpuinitdata fam10h_pci_mmconf_base; | ||
| 26 | static int __cpuinitdata fam10h_pci_mmconf_base_status; | ||
| 27 | |||
| 28 | static struct pci_hostbridge_probe pci_probes[] __cpuinitdata = { | ||
| 29 | { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 }, | ||
| 30 | { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 }, | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct range { | ||
| 34 | u64 start; | ||
| 35 | u64 end; | ||
| 36 | }; | ||
| 37 | |||
| 38 | static int __cpuinit cmp_range(const void *x1, const void *x2) | ||
| 39 | { | ||
| 40 | const struct range *r1 = x1; | ||
| 41 | const struct range *r2 = x2; | ||
| 42 | int start1, start2; | ||
| 43 | |||
| 44 | start1 = r1->start >> 32; | ||
| 45 | start2 = r2->start >> 32; | ||
| 46 | |||
| 47 | return start1 - start2; | ||
| 48 | } | ||
| 49 | |||
| 50 | /*[47:0] */ | ||
| 51 | /* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */ | ||
| 52 | #define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32) | ||
| 53 | #define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32))) | ||
| 54 | static void __cpuinit get_fam10h_pci_mmconf_base(void) | ||
| 55 | { | ||
| 56 | int i; | ||
| 57 | unsigned bus; | ||
| 58 | unsigned slot; | ||
| 59 | int found; | ||
| 60 | |||
| 61 | u64 val; | ||
| 62 | u32 address; | ||
| 63 | u64 tom2; | ||
| 64 | u64 base = FAM10H_PCI_MMCONF_BASE; | ||
| 65 | |||
| 66 | int hi_mmio_num; | ||
| 67 | struct range range[8]; | ||
| 68 | |||
| 69 | /* only try to get setting from BSP */ | ||
| 70 | /* -1 or 1 */ | ||
| 71 | if (fam10h_pci_mmconf_base_status) | ||
| 72 | return; | ||
| 73 | |||
| 74 | if (!early_pci_allowed()) | ||
| 75 | goto fail; | ||
| 76 | |||
| 77 | found = 0; | ||
| 78 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { | ||
| 79 | u32 id; | ||
| 80 | u16 device; | ||
| 81 | u16 vendor; | ||
| 82 | |||
| 83 | bus = pci_probes[i].bus; | ||
| 84 | slot = pci_probes[i].slot; | ||
| 85 | id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID); | ||
| 86 | |||
| 87 | vendor = id & 0xffff; | ||
| 88 | device = (id>>16) & 0xffff; | ||
| 89 | if (pci_probes[i].vendor == vendor && | ||
| 90 | pci_probes[i].device == device) { | ||
| 91 | found = 1; | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | if (!found) | ||
| 97 | goto fail; | ||
| 98 | |||
| 99 | /* SYS_CFG */ | ||
| 100 | address = MSR_K8_SYSCFG; | ||
| 101 | rdmsrl(address, val); | ||
| 102 | |||
| 103 | /* TOP_MEM2 is not enabled? */ | ||
| 104 | if (!(val & (1<<21))) { | ||
| 105 | tom2 = 0; | ||
| 106 | } else { | ||
| 107 | /* TOP_MEM2 */ | ||
| 108 | address = MSR_K8_TOP_MEM2; | ||
| 109 | rdmsrl(address, val); | ||
| 110 | tom2 = val & (0xffffULL<<32); | ||
| 111 | } | ||
| 112 | |||
| 113 | if (base <= tom2) | ||
| 114 | base = tom2 + (1ULL<<32); | ||
| 115 | |||
| 116 | /* | ||
| 117 | * need to check if the range is in the high mmio range that is | ||
| 118 | * above 4G | ||
| 119 | */ | ||
| 120 | hi_mmio_num = 0; | ||
| 121 | for (i = 0; i < 8; i++) { | ||
| 122 | u32 reg; | ||
| 123 | u64 start; | ||
| 124 | u64 end; | ||
| 125 | reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3)); | ||
| 126 | if (!(reg & 3)) | ||
| 127 | continue; | ||
| 128 | |||
| 129 | start = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/ | ||
| 130 | reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3)); | ||
| 131 | end = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/ | ||
| 132 | |||
| 133 | if (!end) | ||
| 134 | continue; | ||
| 135 | |||
| 136 | range[hi_mmio_num].start = start; | ||
| 137 | range[hi_mmio_num].end = end; | ||
| 138 | hi_mmio_num++; | ||
| 139 | } | ||
| 140 | |||
| 141 | if (!hi_mmio_num) | ||
| 142 | goto out; | ||
| 143 | |||
| 144 | /* sort the range */ | ||
| 145 | sort(range, hi_mmio_num, sizeof(struct range), cmp_range, NULL); | ||
| 146 | |||
| 147 | if (range[hi_mmio_num - 1].end < base) | ||
| 148 | goto out; | ||
| 149 | if (range[0].start > base) | ||
| 150 | goto out; | ||
| 151 | |||
| 152 | /* need to find one window */ | ||
| 153 | base = range[0].start - (1ULL << 32); | ||
| 154 | if ((base > tom2) && BASE_VALID(base)) | ||
| 155 | goto out; | ||
| 156 | base = range[hi_mmio_num - 1].end + (1ULL << 32); | ||
| 157 | if ((base > tom2) && BASE_VALID(base)) | ||
| 158 | goto out; | ||
| 159 | /* need to find window between ranges */ | ||
| 160 | if (hi_mmio_num > 1) | ||
| 161 | for (i = 0; i < hi_mmio_num - 1; i++) { | ||
| 162 | if (range[i + 1].start > (range[i].end + (1ULL << 32))) { | ||
| 163 | base = range[i].end + (1ULL << 32); | ||
| 164 | if ((base > tom2) && BASE_VALID(base)) | ||
| 165 | goto out; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | fail: | ||
| 170 | fam10h_pci_mmconf_base_status = -1; | ||
| 171 | return; | ||
| 172 | out: | ||
| 173 | fam10h_pci_mmconf_base = base; | ||
| 174 | fam10h_pci_mmconf_base_status = 1; | ||
| 175 | } | ||
| 176 | |||
| 177 | void __cpuinit fam10h_check_enable_mmcfg(void) | ||
| 178 | { | ||
| 179 | u64 val; | ||
| 180 | u32 address; | ||
| 181 | |||
| 182 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) | ||
| 183 | return; | ||
| 184 | |||
| 185 | address = MSR_FAM10H_MMIO_CONF_BASE; | ||
| 186 | rdmsrl(address, val); | ||
| 187 | |||
| 188 | /* try to make sure that AP's setting is identical to BSP setting */ | ||
| 189 | if (val & FAM10H_MMIO_CONF_ENABLE) { | ||
| 190 | unsigned busnbits; | ||
| 191 | busnbits = (val >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & | ||
| 192 | FAM10H_MMIO_CONF_BUSRANGE_MASK; | ||
| 193 | |||
| 194 | /* only trust the one handle 256 buses, if acpi=off */ | ||
| 195 | if (!acpi_pci_disabled || busnbits >= 8) { | ||
| 196 | u64 base; | ||
| 197 | base = val & (0xffffULL << 32); | ||
| 198 | if (fam10h_pci_mmconf_base_status <= 0) { | ||
| 199 | fam10h_pci_mmconf_base = base; | ||
| 200 | fam10h_pci_mmconf_base_status = 1; | ||
| 201 | return; | ||
| 202 | } else if (fam10h_pci_mmconf_base == base) | ||
| 203 | return; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /* | ||
| 208 | * if it is not enabled, try to enable it and assume only one segment | ||
| 209 | * with 256 buses | ||
| 210 | */ | ||
| 211 | get_fam10h_pci_mmconf_base(); | ||
| 212 | if (fam10h_pci_mmconf_base_status <= 0) | ||
| 213 | return; | ||
| 214 | |||
| 215 | printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n"); | ||
| 216 | val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) | | ||
| 217 | (FAM10H_MMIO_CONF_BUSRANGE_MASK<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT)); | ||
| 218 | val |= fam10h_pci_mmconf_base | (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT) | | ||
| 219 | FAM10H_MMIO_CONF_ENABLE; | ||
| 220 | wrmsrl(address, val); | ||
| 221 | } | ||
| 222 | |||
| 223 | static int __devinit set_check_enable_amd_mmconf(const struct dmi_system_id *d) | ||
| 224 | { | ||
| 225 | pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF; | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | static struct dmi_system_id __devinitdata mmconf_dmi_table[] = { | ||
| 230 | { | ||
| 231 | .callback = set_check_enable_amd_mmconf, | ||
| 232 | .ident = "Sun Microsystems Machine", | ||
| 233 | .matches = { | ||
| 234 | DMI_MATCH(DMI_SYS_VENDOR, "Sun Microsystems"), | ||
| 235 | }, | ||
| 236 | }, | ||
| 237 | {} | ||
| 238 | }; | ||
| 239 | |||
| 240 | void __init check_enable_amd_mmconf_dmi(void) | ||
| 241 | { | ||
| 242 | dmi_check_system(mmconf_dmi_table); | ||
| 243 | } | ||
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index a94fb959a8..22c14e21c9 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/crash_dump.h> | 29 | #include <linux/crash_dump.h> |
| 30 | #include <linux/root_dev.h> | 30 | #include <linux/root_dev.h> |
| 31 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
| 32 | #include <asm/pci-direct.h> | ||
| 32 | #include <linux/efi.h> | 33 | #include <linux/efi.h> |
| 33 | #include <linux/acpi.h> | 34 | #include <linux/acpi.h> |
| 34 | #include <linux/kallsyms.h> | 35 | #include <linux/kallsyms.h> |
| @@ -40,6 +41,7 @@ | |||
| 40 | #include <linux/dmi.h> | 41 | #include <linux/dmi.h> |
| 41 | #include <linux/dma-mapping.h> | 42 | #include <linux/dma-mapping.h> |
| 42 | #include <linux/ctype.h> | 43 | #include <linux/ctype.h> |
| 44 | #include <linux/sort.h> | ||
| 43 | #include <linux/uaccess.h> | 45 | #include <linux/uaccess.h> |
| 44 | #include <linux/init_ohci1394_dma.h> | 46 | #include <linux/init_ohci1394_dma.h> |
| 45 | #include <linux/kvm_para.h> | 47 | #include <linux/kvm_para.h> |
| @@ -288,6 +290,18 @@ static void __init parse_setup_data(void) | |||
| 288 | } | 290 | } |
| 289 | } | 291 | } |
| 290 | 292 | ||
| 293 | #ifdef CONFIG_PCI_MMCONFIG | ||
| 294 | extern void __cpuinit fam10h_check_enable_mmcfg(void); | ||
| 295 | extern void __init check_enable_amd_mmconf_dmi(void); | ||
| 296 | #else | ||
| 297 | void __cpuinit fam10h_check_enable_mmcfg(void) | ||
| 298 | { | ||
| 299 | } | ||
| 300 | void __init check_enable_amd_mmconf_dmi(void) | ||
| 301 | { | ||
| 302 | } | ||
| 303 | #endif | ||
| 304 | |||
| 291 | /* | 305 | /* |
| 292 | * setup_arch - architecture-specific boot-time initializations | 306 | * setup_arch - architecture-specific boot-time initializations |
| 293 | * | 307 | * |
| @@ -515,6 +529,9 @@ void __init setup_arch(char **cmdline_p) | |||
| 515 | conswitchp = &dummy_con; | 529 | conswitchp = &dummy_con; |
| 516 | #endif | 530 | #endif |
| 517 | #endif | 531 | #endif |
| 532 | |||
| 533 | /* do this before identify_cpu for boot cpu */ | ||
| 534 | check_enable_amd_mmconf_dmi(); | ||
| 518 | } | 535 | } |
| 519 | 536 | ||
| 520 | static int __cpuinit get_model_name(struct cpuinfo_x86 *c) | 537 | static int __cpuinit get_model_name(struct cpuinfo_x86 *c) |
| @@ -767,6 +784,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
| 767 | /* MFENCE stops RDTSC speculation */ | 784 | /* MFENCE stops RDTSC speculation */ |
| 768 | set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); | 785 | set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); |
| 769 | 786 | ||
| 787 | if (c->x86 == 0x10) | ||
| 788 | fam10h_check_enable_mmcfg(); | ||
| 789 | |||
| 770 | if (amd_apic_timer_broken()) | 790 | if (amd_apic_timer_broken()) |
| 771 | disable_apic_timer = 1; | 791 | disable_apic_timer = 1; |
| 772 | 792 | ||
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c index 86808e666f..1f476e4778 100644 --- a/arch/x86/mm/k8topology_64.c +++ b/arch/x86/mm/k8topology_64.c | |||
| @@ -13,12 +13,15 @@ | |||
| 13 | #include <linux/nodemask.h> | 13 | #include <linux/nodemask.h> |
| 14 | #include <asm/io.h> | 14 | #include <asm/io.h> |
| 15 | #include <linux/pci_ids.h> | 15 | #include <linux/pci_ids.h> |
| 16 | #include <linux/acpi.h> | ||
| 16 | #include <asm/types.h> | 17 | #include <asm/types.h> |
| 17 | #include <asm/mmzone.h> | 18 | #include <asm/mmzone.h> |
| 18 | #include <asm/proto.h> | 19 | #include <asm/proto.h> |
| 19 | #include <asm/e820.h> | 20 | #include <asm/e820.h> |
| 20 | #include <asm/pci-direct.h> | 21 | #include <asm/pci-direct.h> |
| 21 | #include <asm/numa.h> | 22 | #include <asm/numa.h> |
| 23 | #include <asm/mpspec.h> | ||
| 24 | #include <asm/apic.h> | ||
| 22 | 25 | ||
| 23 | static __init int find_northbridge(void) | 26 | static __init int find_northbridge(void) |
| 24 | { | 27 | { |
| @@ -44,6 +47,30 @@ static __init int find_northbridge(void) | |||
| 44 | return -1; | 47 | return -1; |
| 45 | } | 48 | } |
| 46 | 49 | ||
| 50 | static __init void early_get_boot_cpu_id(void) | ||
| 51 | { | ||
| 52 | /* | ||
| 53 | * need to get boot_cpu_id so can use that to create apicid_to_node | ||
| 54 | * in k8_scan_nodes() | ||
| 55 | */ | ||
| 56 | /* | ||
| 57 | * Find possible boot-time SMP configuration: | ||
| 58 | */ | ||
| 59 | early_find_smp_config(); | ||
| 60 | #ifdef CONFIG_ACPI | ||
| 61 | /* | ||
| 62 | * Read APIC information from ACPI tables. | ||
| 63 | */ | ||
| 64 | early_acpi_boot_init(); | ||
| 65 | #endif | ||
| 66 | /* | ||
| 67 | * get boot-time SMP configuration: | ||
| 68 | */ | ||
| 69 | if (smp_found_config) | ||
| 70 | early_get_smp_config(); | ||
| 71 | early_init_lapic_mapping(); | ||
| 72 | } | ||
| 73 | |||
| 47 | int __init k8_scan_nodes(unsigned long start, unsigned long end) | 74 | int __init k8_scan_nodes(unsigned long start, unsigned long end) |
| 48 | { | 75 | { |
| 49 | unsigned long prevbase; | 76 | unsigned long prevbase; |
| @@ -56,6 +83,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) | |||
| 56 | unsigned cores; | 83 | unsigned cores; |
| 57 | unsigned bits; | 84 | unsigned bits; |
| 58 | int j; | 85 | int j; |
| 86 | unsigned apicid_base; | ||
| 59 | 87 | ||
| 60 | if (!early_pci_allowed()) | 88 | if (!early_pci_allowed()) |
| 61 | return -1; | 89 | return -1; |
| @@ -174,11 +202,19 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) | |||
| 174 | /* use the coreid bits from early_identify_cpu */ | 202 | /* use the coreid bits from early_identify_cpu */ |
| 175 | bits = boot_cpu_data.x86_coreid_bits; | 203 | bits = boot_cpu_data.x86_coreid_bits; |
| 176 | cores = (1<<bits); | 204 | cores = (1<<bits); |
| 205 | apicid_base = 0; | ||
| 206 | /* need to get boot_cpu_id early for system with apicid lifting */ | ||
| 207 | early_get_boot_cpu_id(); | ||
| 208 | if (boot_cpu_physical_apicid > 0) { | ||
| 209 | printk(KERN_INFO "BSP APIC ID: %02x\n", | ||
| 210 | boot_cpu_physical_apicid); | ||
| 211 | apicid_base = boot_cpu_physical_apicid; | ||
| 212 | } | ||
| 177 | 213 | ||
| 178 | for (i = 0; i < 8; i++) { | 214 | for (i = 0; i < 8; i++) { |
| 179 | if (nodes[i].start != nodes[i].end) { | 215 | if (nodes[i].start != nodes[i].end) { |
| 180 | nodeid = nodeids[i]; | 216 | nodeid = nodeids[i]; |
| 181 | for (j = 0; j < cores; j++) | 217 | for (j = apicid_base; j < cores + apicid_base; j++) |
| 182 | apicid_to_node[(nodeid << bits) + j] = i; | 218 | apicid_to_node[(nodeid << bits) + j] = i; |
| 183 | setup_node_bootmem(i, nodes[i].start, nodes[i].end); | 219 | setup_node_bootmem(i, nodes[i].start, nodes[i].end); |
| 184 | } | 220 | } |
diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32 index b859047a63..2a1516efb5 100644 --- a/arch/x86/pci/Makefile_32 +++ b/arch/x86/pci/Makefile_32 | |||
| @@ -11,5 +11,6 @@ pci-y += legacy.o irq.o | |||
| 11 | 11 | ||
| 12 | pci-$(CONFIG_X86_VISWS) := visws.o fixup.o | 12 | pci-$(CONFIG_X86_VISWS) := visws.o fixup.o |
| 13 | pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o | 13 | pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o |
| 14 | pci-$(CONFIG_NUMA) += mp_bus_to_node.o | ||
| 14 | 15 | ||
| 15 | obj-y += $(pci-y) common.o early.o | 16 | obj-y += $(pci-y) common.o early.o |
diff --git a/arch/x86/pci/Makefile_64 b/arch/x86/pci/Makefile_64 index 7d8c467bf1..8fbd19832c 100644 --- a/arch/x86/pci/Makefile_64 +++ b/arch/x86/pci/Makefile_64 | |||
| @@ -13,5 +13,5 @@ obj-y += legacy.o irq.o common.o early.o | |||
| 13 | # mmconfig has a 64bit special | 13 | # mmconfig has a 64bit special |
| 14 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o | 14 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o |
| 15 | 15 | ||
| 16 | obj-$(CONFIG_NUMA) += k8-bus_64.o | 16 | obj-y += k8-bus_64.o |
| 17 | 17 | ||
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 2664cb3fc9..1a9c0c6a1a 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
| @@ -191,7 +191,10 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
| 191 | { | 191 | { |
| 192 | struct pci_bus *bus; | 192 | struct pci_bus *bus; |
| 193 | struct pci_sysdata *sd; | 193 | struct pci_sysdata *sd; |
| 194 | int node; | ||
| 195 | #ifdef CONFIG_ACPI_NUMA | ||
| 194 | int pxm; | 196 | int pxm; |
| 197 | #endif | ||
| 195 | 198 | ||
| 196 | dmi_check_system(acpi_pciprobe_dmi_table); | 199 | dmi_check_system(acpi_pciprobe_dmi_table); |
| 197 | 200 | ||
| @@ -201,6 +204,17 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
| 201 | return NULL; | 204 | return NULL; |
| 202 | } | 205 | } |
| 203 | 206 | ||
| 207 | node = -1; | ||
| 208 | #ifdef CONFIG_ACPI_NUMA | ||
| 209 | pxm = acpi_get_pxm(device->handle); | ||
| 210 | if (pxm >= 0) | ||
| 211 | node = pxm_to_node(pxm); | ||
| 212 | if (node != -1) | ||
| 213 | set_mp_bus_to_node(busnum, node); | ||
| 214 | else | ||
| 215 | node = get_mp_bus_to_node(busnum); | ||
| 216 | #endif | ||
| 217 | |||
| 204 | /* Allocate per-root-bus (not per bus) arch-specific data. | 218 | /* Allocate per-root-bus (not per bus) arch-specific data. |
| 205 | * TODO: leak; this memory is never freed. | 219 | * TODO: leak; this memory is never freed. |
| 206 | * It's arguable whether it's worth the trouble to care. | 220 | * It's arguable whether it's worth the trouble to care. |
| @@ -212,13 +226,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
| 212 | } | 226 | } |
| 213 | 227 | ||
| 214 | sd->domain = domain; | 228 | sd->domain = domain; |
| 215 | sd->node = -1; | 229 | sd->node = node; |
| 216 | |||
| 217 | pxm = acpi_get_pxm(device->handle); | ||
| 218 | #ifdef CONFIG_ACPI_NUMA | ||
| 219 | if (pxm >= 0) | ||
| 220 | sd->node = pxm_to_node(pxm); | ||
| 221 | #endif | ||
| 222 | /* | 230 | /* |
| 223 | * Maybe the desired pci bus has been already scanned. In such case | 231 | * Maybe the desired pci bus has been already scanned. In such case |
| 224 | * it is unnecessary to scan the pci bus with the given domain,busnum. | 232 | * it is unnecessary to scan the pci bus with the given domain,busnum. |
| @@ -238,9 +246,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
| 238 | kfree(sd); | 246 | kfree(sd); |
| 239 | 247 | ||
| 240 | #ifdef CONFIG_ACPI_NUMA | 248 | #ifdef CONFIG_ACPI_NUMA |
| 241 | if (bus != NULL) { | 249 | if (bus) { |
| 242 | if (pxm >= 0) { | 250 | if (pxm >= 0) { |
| 243 | printk("bus %d -> pxm %d -> node %d\n", | 251 | printk(KERN_DEBUG "bus %02x -> pxm %d -> node %d\n", |
| 244 | busnum, pxm, pxm_to_node(pxm)); | 252 | busnum, pxm, pxm_to_node(pxm)); |
| 245 | } | 253 | } |
| 246 | } | 254 | } |
| @@ -248,7 +256,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
| 248 | 256 | ||
| 249 | if (bus && (pci_probe & PCI_USE__CRS)) | 257 | if (bus && (pci_probe & PCI_USE__CRS)) |
| 250 | get_current_resources(device, busnum, domain, bus); | 258 | get_current_resources(device, busnum, domain, bus); |
| 251 | |||
| 252 | return bus; | 259 | return bus; |
| 253 | } | 260 | } |
| 254 | 261 | ||
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 75fcc29ecf..2a4d751818 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
| @@ -342,9 +342,14 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) | |||
| 342 | return NULL; | 342 | return NULL; |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | sd->node = get_mp_bus_to_node(busnum); | ||
| 346 | |||
| 345 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); | 347 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); |
| 348 | bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); | ||
| 349 | if (!bus) | ||
| 350 | kfree(sd); | ||
| 346 | 351 | ||
| 347 | return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); | 352 | return bus; |
| 348 | } | 353 | } |
| 349 | 354 | ||
| 350 | extern u8 pci_cache_line_size; | 355 | extern u8 pci_cache_line_size; |
| @@ -420,6 +425,10 @@ char * __devinit pcibios_setup(char *str) | |||
| 420 | pci_probe &= ~PCI_PROBE_MMCONF; | 425 | pci_probe &= ~PCI_PROBE_MMCONF; |
| 421 | return NULL; | 426 | return NULL; |
| 422 | } | 427 | } |
| 428 | else if (!strcmp(str, "check_enable_amd_mmconf")) { | ||
| 429 | pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF; | ||
| 430 | return NULL; | ||
| 431 | } | ||
| 423 | #endif | 432 | #endif |
| 424 | else if (!strcmp(str, "noacpi")) { | 433 | else if (!strcmp(str, "noacpi")) { |
| 425 | acpi_noirq_set(); | 434 | acpi_noirq_set(); |
| @@ -480,7 +489,7 @@ void pcibios_disable_device (struct pci_dev *dev) | |||
| 480 | pcibios_disable_irq(dev); | 489 | pcibios_disable_irq(dev); |
| 481 | } | 490 | } |
| 482 | 491 | ||
| 483 | struct pci_bus *__devinit pci_scan_bus_with_sysdata(int busno) | 492 | struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) |
| 484 | { | 493 | { |
| 485 | struct pci_bus *bus = NULL; | 494 | struct pci_bus *bus = NULL; |
| 486 | struct pci_sysdata *sd; | 495 | struct pci_sysdata *sd; |
| @@ -495,10 +504,15 @@ struct pci_bus *__devinit pci_scan_bus_with_sysdata(int busno) | |||
| 495 | printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); | 504 | printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); |
| 496 | return NULL; | 505 | return NULL; |
| 497 | } | 506 | } |
| 498 | sd->node = -1; | 507 | sd->node = node; |
| 499 | bus = pci_scan_bus(busno, &pci_root_ops, sd); | 508 | bus = pci_scan_bus(busno, ops, sd); |
| 500 | if (!bus) | 509 | if (!bus) |
| 501 | kfree(sd); | 510 | kfree(sd); |
| 502 | 511 | ||
| 503 | return bus; | 512 | return bus; |
| 504 | } | 513 | } |
| 514 | |||
| 515 | struct pci_bus *pci_scan_bus_with_sysdata(int busno) | ||
| 516 | { | ||
| 517 | return pci_scan_bus_on_node(busno, &pci_root_ops, -1); | ||
| 518 | } | ||
diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c index 42f3e4cad1..21d1e0e0d5 100644 --- a/arch/x86/pci/direct.c +++ b/arch/x86/pci/direct.c | |||
| @@ -258,7 +258,8 @@ void __init pci_direct_init(int type) | |||
| 258 | { | 258 | { |
| 259 | if (type == 0) | 259 | if (type == 0) |
| 260 | return; | 260 | return; |
| 261 | printk(KERN_INFO "PCI: Using configuration type %d\n", type); | 261 | printk(KERN_INFO "PCI: Using configuration type %d for base access\n", |
| 262 | type); | ||
| 262 | if (type == 1) | 263 | if (type == 1) |
| 263 | raw_pci_ops = &pci_direct_conf1; | 264 | raw_pci_ops = &pci_direct_conf1; |
| 264 | else | 265 | else |
| @@ -275,8 +276,10 @@ int __init pci_direct_probe(void) | |||
| 275 | if (!region) | 276 | if (!region) |
| 276 | goto type2; | 277 | goto type2; |
| 277 | 278 | ||
| 278 | if (pci_check_type1()) | 279 | if (pci_check_type1()) { |
| 280 | raw_pci_ops = &pci_direct_conf1; | ||
| 279 | return 1; | 281 | return 1; |
| 282 | } | ||
| 280 | release_resource(region); | 283 | release_resource(region); |
| 281 | 284 | ||
| 282 | type2: | 285 | type2: |
| @@ -290,7 +293,6 @@ int __init pci_direct_probe(void) | |||
| 290 | goto fail2; | 293 | goto fail2; |
| 291 | 294 | ||
| 292 | if (pci_check_type2()) { | 295 | if (pci_check_type2()) { |
| 293 | printk(KERN_INFO "PCI: Using configuration type 2\n"); | ||
| 294 | raw_pci_ops = &pci_direct_conf2; | 296 | raw_pci_ops = &pci_direct_conf2; |
| 295 | return 2; | 297 | return 2; |
| 296 | } | 298 | } |
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index a5ef5f5513..b60b2abd48 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c | |||
| @@ -493,3 +493,20 @@ static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) | |||
| 493 | } | 493 | } |
| 494 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, | 494 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, |
| 495 | pci_siemens_interrupt_controller); | 495 | pci_siemens_interrupt_controller); |
| 496 | |||
| 497 | /* | ||
| 498 | * Regular PCI devices have 256 bytes, but AMD Family 10h Opteron ext config | ||
| 499 | * have 4096 bytes. Even if the device is capable, that doesn't mean we can | ||
| 500 | * access it. Maybe we don't have a way to generate extended config space | ||
| 501 | * accesses. So check it | ||
| 502 | */ | ||
| 503 | static void fam10h_pci_cfg_space_size(struct pci_dev *dev) | ||
| 504 | { | ||
| 505 | dev->cfg_size = pci_cfg_space_size_ext(dev, 0); | ||
| 506 | } | ||
| 507 | |||
| 508 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, fam10h_pci_cfg_space_size); | ||
| 509 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size); | ||
| 510 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size); | ||
| 511 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size); | ||
| 512 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size); | ||
diff --git a/arch/x86/pci/init.c b/arch/x86/pci/init.c index 0f5f7dd2a6..dd30c6076b 100644 --- a/arch/x86/pci/init.c +++ b/arch/x86/pci/init.c | |||
| @@ -6,19 +6,17 @@ | |||
| 6 | in the right sequence from here. */ | 6 | in the right sequence from here. */ |
| 7 | static __init int pci_access_init(void) | 7 | static __init int pci_access_init(void) |
| 8 | { | 8 | { |
| 9 | int type __maybe_unused = 0; | ||
| 10 | |||
| 11 | #ifdef CONFIG_PCI_DIRECT | 9 | #ifdef CONFIG_PCI_DIRECT |
| 10 | int type = 0; | ||
| 11 | |||
| 12 | type = pci_direct_probe(); | 12 | type = pci_direct_probe(); |
| 13 | #endif | 13 | #endif |
| 14 | #ifdef CONFIG_PCI_MMCONFIG | 14 | |
| 15 | pci_mmcfg_init(type); | 15 | pci_mmcfg_early_init(); |
| 16 | #endif | 16 | |
| 17 | #ifdef CONFIG_PCI_OLPC | 17 | #ifdef CONFIG_PCI_OLPC |
| 18 | pci_olpc_init(); | 18 | pci_olpc_init(); |
| 19 | #endif | 19 | #endif |
| 20 | if (raw_pci_ops) | ||
| 21 | return 0; | ||
| 22 | #ifdef CONFIG_PCI_BIOS | 20 | #ifdef CONFIG_PCI_BIOS |
| 23 | pci_pcbios_init(); | 21 | pci_pcbios_init(); |
| 24 | #endif | 22 | #endif |
| @@ -31,7 +29,7 @@ static __init int pci_access_init(void) | |||
| 31 | #ifdef CONFIG_PCI_DIRECT | 29 | #ifdef CONFIG_PCI_DIRECT |
| 32 | pci_direct_init(type); | 30 | pci_direct_init(type); |
| 33 | #endif | 31 | #endif |
| 34 | if (!raw_pci_ops) | 32 | if (!raw_pci_ops && !raw_pci_ext_ops) |
| 35 | printk(KERN_ERR | 33 | printk(KERN_ERR |
| 36 | "PCI: Fatal: No config space access function found\n"); | 34 | "PCI: Fatal: No config space access function found\n"); |
| 37 | 35 | ||
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 579745ca6b..0908fca901 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c | |||
| @@ -136,9 +136,11 @@ static void __init pirq_peer_trick(void) | |||
| 136 | busmap[e->bus] = 1; | 136 | busmap[e->bus] = 1; |
| 137 | } | 137 | } |
| 138 | for(i = 1; i < 256; i++) { | 138 | for(i = 1; i < 256; i++) { |
| 139 | int node; | ||
| 139 | if (!busmap[i] || pci_find_bus(0, i)) | 140 | if (!busmap[i] || pci_find_bus(0, i)) |
| 140 | continue; | 141 | continue; |
| 141 | if (pci_scan_bus_with_sysdata(i)) | 142 | node = get_mp_bus_to_node(i); |
| 143 | if (pci_scan_bus_on_node(i, &pci_root_ops, node)) | ||
| 142 | printk(KERN_INFO "PCI: Discovered primary peer " | 144 | printk(KERN_INFO "PCI: Discovered primary peer " |
| 143 | "bus %02x [IRQ]\n", i); | 145 | "bus %02x [IRQ]\n", i); |
| 144 | } | 146 | } |
diff --git a/arch/x86/pci/k8-bus_64.c b/arch/x86/pci/k8-bus_64.c index 9cc813e297..ab6d4b18a8 100644 --- a/arch/x86/pci/k8-bus_64.c +++ b/arch/x86/pci/k8-bus_64.c | |||
| @@ -1,83 +1,536 @@ | |||
| 1 | #include <linux/init.h> | 1 | #include <linux/init.h> |
| 2 | #include <linux/pci.h> | 2 | #include <linux/pci.h> |
| 3 | #include <asm/pci-direct.h> | ||
| 3 | #include <asm/mpspec.h> | 4 | #include <asm/mpspec.h> |
| 4 | #include <linux/cpumask.h> | 5 | #include <linux/cpumask.h> |
| 6 | #include <linux/topology.h> | ||
| 5 | 7 | ||
| 6 | /* | 8 | /* |
| 7 | * This discovers the pcibus <-> node mapping on AMD K8. | 9 | * This discovers the pcibus <-> node mapping on AMD K8. |
| 8 | * | 10 | * also get peer root bus resource for io,mmio |
| 9 | * RED-PEN need to call this again on PCI hotplug | ||
| 10 | * RED-PEN empty cpus get reported wrong | ||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #define NODE_ID_REGISTER 0x60 | 13 | |
| 14 | #define NODE_ID(dword) (dword & 0x07) | 14 | /* |
| 15 | #define LDT_BUS_NUMBER_REGISTER_0 0x94 | 15 | * sub bus (transparent) will use entres from 3 to store extra from root, |
| 16 | #define LDT_BUS_NUMBER_REGISTER_1 0xB4 | 16 | * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES? |
| 17 | #define LDT_BUS_NUMBER_REGISTER_2 0xD4 | 17 | */ |
| 18 | #define NR_LDT_BUS_NUMBER_REGISTERS 3 | 18 | #define RES_NUM 16 |
| 19 | #define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF) | 19 | struct pci_root_info { |
| 20 | #define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF) | 20 | char name[12]; |
| 21 | #define PCI_DEVICE_ID_K8HTCONFIG 0x1100 | 21 | unsigned int res_num; |
| 22 | struct resource res[RES_NUM]; | ||
| 23 | int bus_min; | ||
| 24 | int bus_max; | ||
| 25 | int node; | ||
| 26 | int link; | ||
| 27 | }; | ||
| 28 | |||
| 29 | /* 4 at this time, it may become to 32 */ | ||
| 30 | #define PCI_ROOT_NR 4 | ||
| 31 | static int pci_root_num; | ||
| 32 | static struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
| 33 | |||
| 34 | #ifdef CONFIG_NUMA | ||
| 35 | |||
| 36 | #define BUS_NR 256 | ||
| 37 | |||
| 38 | static int mp_bus_to_node[BUS_NR]; | ||
| 39 | |||
| 40 | void set_mp_bus_to_node(int busnum, int node) | ||
| 41 | { | ||
| 42 | if (busnum >= 0 && busnum < BUS_NR) | ||
| 43 | mp_bus_to_node[busnum] = node; | ||
| 44 | } | ||
| 45 | |||
| 46 | int get_mp_bus_to_node(int busnum) | ||
| 47 | { | ||
| 48 | int node = -1; | ||
| 49 | |||
| 50 | if (busnum < 0 || busnum > (BUS_NR - 1)) | ||
| 51 | return node; | ||
| 52 | |||
| 53 | node = mp_bus_to_node[busnum]; | ||
| 54 | |||
| 55 | /* | ||
| 56 | * let numa_node_id to decide it later in dma_alloc_pages | ||
| 57 | * if there is no ram on that node | ||
| 58 | */ | ||
| 59 | if (node != -1 && !node_online(node)) | ||
| 60 | node = -1; | ||
| 61 | |||
| 62 | return node; | ||
| 63 | } | ||
| 64 | #endif | ||
| 65 | |||
| 66 | void set_pci_bus_resources_arch_default(struct pci_bus *b) | ||
| 67 | { | ||
| 68 | int i; | ||
| 69 | int j; | ||
| 70 | struct pci_root_info *info; | ||
| 71 | |||
| 72 | /* if only one root bus, don't need to anything */ | ||
| 73 | if (pci_root_num < 2) | ||
| 74 | return; | ||
| 75 | |||
| 76 | for (i = 0; i < pci_root_num; i++) { | ||
| 77 | if (pci_root_info[i].bus_min == b->number) | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | |||
| 81 | if (i == pci_root_num) | ||
| 82 | return; | ||
| 83 | |||
| 84 | info = &pci_root_info[i]; | ||
| 85 | for (j = 0; j < info->res_num; j++) { | ||
| 86 | struct resource *res; | ||
| 87 | struct resource *root; | ||
| 88 | |||
| 89 | res = &info->res[j]; | ||
| 90 | b->resource[j] = res; | ||
| 91 | if (res->flags & IORESOURCE_IO) | ||
| 92 | root = &ioport_resource; | ||
| 93 | else | ||
| 94 | root = &iomem_resource; | ||
| 95 | insert_resource(root, res); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | #define RANGE_NUM 16 | ||
| 100 | |||
| 101 | struct res_range { | ||
| 102 | size_t start; | ||
| 103 | size_t end; | ||
| 104 | }; | ||
| 105 | |||
| 106 | static void __init update_range(struct res_range *range, size_t start, | ||
| 107 | size_t end) | ||
| 108 | { | ||
| 109 | int i; | ||
| 110 | int j; | ||
| 111 | |||
| 112 | for (j = 0; j < RANGE_NUM; j++) { | ||
| 113 | if (!range[j].end) | ||
| 114 | continue; | ||
| 115 | |||
| 116 | if (start <= range[j].start && end >= range[j].end) { | ||
| 117 | range[j].start = 0; | ||
| 118 | range[j].end = 0; | ||
| 119 | continue; | ||
| 120 | } | ||
| 121 | |||
| 122 | if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) { | ||
| 123 | range[j].start = end + 1; | ||
| 124 | continue; | ||
| 125 | } | ||
| 126 | |||
| 127 | |||
| 128 | if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) { | ||
| 129 | range[j].end = start - 1; | ||
| 130 | continue; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (start > range[j].start && end < range[j].end) { | ||
| 134 | /* find the new spare */ | ||
| 135 | for (i = 0; i < RANGE_NUM; i++) { | ||
| 136 | if (range[i].end == 0) | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | if (i < RANGE_NUM) { | ||
| 140 | range[i].end = range[j].end; | ||
| 141 | range[i].start = end + 1; | ||
| 142 | } else { | ||
| 143 | printk(KERN_ERR "run of slot in ranges\n"); | ||
| 144 | } | ||
| 145 | range[j].end = start - 1; | ||
| 146 | continue; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | static void __init update_res(struct pci_root_info *info, size_t start, | ||
| 152 | size_t end, unsigned long flags, int merge) | ||
| 153 | { | ||
| 154 | int i; | ||
| 155 | struct resource *res; | ||
| 156 | |||
| 157 | if (!merge) | ||
| 158 | goto addit; | ||
| 159 | |||
| 160 | /* try to merge it with old one */ | ||
| 161 | for (i = 0; i < info->res_num; i++) { | ||
| 162 | size_t final_start, final_end; | ||
| 163 | size_t common_start, common_end; | ||
| 164 | |||
| 165 | res = &info->res[i]; | ||
| 166 | if (res->flags != flags) | ||
| 167 | continue; | ||
| 168 | |||
| 169 | common_start = max((size_t)res->start, start); | ||
| 170 | common_end = min((size_t)res->end, end); | ||
| 171 | if (common_start > common_end + 1) | ||
| 172 | continue; | ||
| 173 | |||
| 174 | final_start = min((size_t)res->start, start); | ||
| 175 | final_end = max((size_t)res->end, end); | ||
| 176 | |||
| 177 | res->start = final_start; | ||
| 178 | res->end = final_end; | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | addit: | ||
| 183 | |||
| 184 | /* need to add that */ | ||
| 185 | if (info->res_num >= RES_NUM) | ||
| 186 | return; | ||
| 187 | |||
| 188 | res = &info->res[info->res_num]; | ||
| 189 | res->name = info->name; | ||
| 190 | res->flags = flags; | ||
| 191 | res->start = start; | ||
| 192 | res->end = end; | ||
| 193 | res->child = NULL; | ||
| 194 | info->res_num++; | ||
| 195 | } | ||
| 196 | |||
| 197 | struct pci_hostbridge_probe { | ||
| 198 | u32 bus; | ||
| 199 | u32 slot; | ||
| 200 | u32 vendor; | ||
| 201 | u32 device; | ||
| 202 | }; | ||
| 203 | |||
| 204 | static struct pci_hostbridge_probe pci_probes[] __initdata = { | ||
| 205 | { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1100 }, | ||
| 206 | { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 }, | ||
| 207 | { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 }, | ||
| 208 | { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 }, | ||
| 209 | }; | ||
| 210 | |||
| 211 | static u64 __initdata fam10h_mmconf_start; | ||
| 212 | static u64 __initdata fam10h_mmconf_end; | ||
| 213 | static void __init get_pci_mmcfg_amd_fam10h_range(void) | ||
| 214 | { | ||
| 215 | u32 address; | ||
| 216 | u64 base, msr; | ||
| 217 | unsigned segn_busn_bits; | ||
| 218 | |||
| 219 | /* assume all cpus from fam10h have mmconf */ | ||
| 220 | if (boot_cpu_data.x86 < 0x10) | ||
| 221 | return; | ||
| 222 | |||
| 223 | address = MSR_FAM10H_MMIO_CONF_BASE; | ||
| 224 | rdmsrl(address, msr); | ||
| 225 | |||
| 226 | /* mmconfig is not enable */ | ||
| 227 | if (!(msr & FAM10H_MMIO_CONF_ENABLE)) | ||
| 228 | return; | ||
| 229 | |||
| 230 | base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); | ||
| 231 | |||
| 232 | segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & | ||
| 233 | FAM10H_MMIO_CONF_BUSRANGE_MASK; | ||
| 234 | |||
| 235 | fam10h_mmconf_start = base; | ||
| 236 | fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; | ||
| 237 | } | ||
| 22 | 238 | ||
| 23 | /** | 239 | /** |
| 24 | * fill_mp_bus_to_cpumask() | 240 | * early_fill_mp_bus_to_node() |
| 241 | * called before pcibios_scan_root and pci_scan_bus | ||
| 25 | * fills the mp_bus_to_cpumask array based according to the LDT Bus Number | 242 | * fills the mp_bus_to_cpumask array based according to the LDT Bus Number |
| 26 | * Registers found in the K8 northbridge | 243 | * Registers found in the K8 northbridge |
| 27 | */ | 244 | */ |
| 28 | __init static int | 245 | static int __init early_fill_mp_bus_info(void) |
| 29 | fill_mp_bus_to_cpumask(void) | ||
| 30 | { | 246 | { |
| 31 | struct pci_dev *nb_dev = NULL; | 247 | int i; |
| 32 | int i, j; | 248 | int j; |
| 33 | u32 ldtbus, nid; | 249 | unsigned bus; |
| 34 | static int lbnr[3] = { | 250 | unsigned slot; |
| 35 | LDT_BUS_NUMBER_REGISTER_0, | 251 | int found; |
| 36 | LDT_BUS_NUMBER_REGISTER_1, | 252 | int node; |
| 37 | LDT_BUS_NUMBER_REGISTER_2 | 253 | int link; |
| 38 | }; | 254 | int def_node; |
| 39 | 255 | int def_link; | |
| 40 | while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, | 256 | struct pci_root_info *info; |
| 41 | PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) { | 257 | u32 reg; |
| 42 | pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid); | 258 | struct resource *res; |
| 43 | 259 | size_t start; | |
| 44 | for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) { | 260 | size_t end; |
| 45 | pci_read_config_dword(nb_dev, lbnr[i], &ldtbus); | 261 | struct res_range range[RANGE_NUM]; |
| 46 | /* | 262 | u64 val; |
| 47 | * if there are no busses hanging off of the current | 263 | u32 address; |
| 48 | * ldt link then both the secondary and subordinate | 264 | |
| 49 | * bus number fields are set to 0. | 265 | #ifdef CONFIG_NUMA |
| 50 | * | 266 | for (i = 0; i < BUS_NR; i++) |
| 51 | * RED-PEN | 267 | mp_bus_to_node[i] = -1; |
| 52 | * This is slightly broken because it assumes | 268 | #endif |
| 53 | * HT node IDs == Linux node ids, which is not always | 269 | |
| 54 | * true. However it is probably mostly true. | 270 | if (!early_pci_allowed()) |
| 55 | */ | 271 | return -1; |
| 56 | if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0 | 272 | |
| 57 | && SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) { | 273 | found = 0; |
| 58 | for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus); | 274 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { |
| 59 | j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus); | 275 | u32 id; |
| 60 | j++) { | 276 | u16 device; |
| 61 | struct pci_bus *bus; | 277 | u16 vendor; |
| 62 | struct pci_sysdata *sd; | 278 | |
| 63 | 279 | bus = pci_probes[i].bus; | |
| 64 | long node = NODE_ID(nid); | 280 | slot = pci_probes[i].slot; |
| 65 | /* Algorithm a bit dumb, but | 281 | id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID); |
| 66 | it shouldn't matter here */ | 282 | |
| 67 | bus = pci_find_bus(0, j); | 283 | vendor = id & 0xffff; |
| 68 | if (!bus) | 284 | device = (id>>16) & 0xffff; |
| 69 | continue; | 285 | if (pci_probes[i].vendor == vendor && |
| 70 | if (!node_online(node)) | 286 | pci_probes[i].device == device) { |
| 71 | node = 0; | 287 | found = 1; |
| 72 | 288 | break; | |
| 73 | sd = bus->sysdata; | 289 | } |
| 74 | sd->node = node; | 290 | } |
| 75 | } | 291 | |
| 292 | if (!found) | ||
| 293 | return 0; | ||
| 294 | |||
| 295 | pci_root_num = 0; | ||
| 296 | for (i = 0; i < 4; i++) { | ||
| 297 | int min_bus; | ||
| 298 | int max_bus; | ||
| 299 | reg = read_pci_config(bus, slot, 1, 0xe0 + (i << 2)); | ||
| 300 | |||
| 301 | /* Check if that register is enabled for bus range */ | ||
| 302 | if ((reg & 7) != 3) | ||
| 303 | continue; | ||
| 304 | |||
| 305 | min_bus = (reg >> 16) & 0xff; | ||
| 306 | max_bus = (reg >> 24) & 0xff; | ||
| 307 | node = (reg >> 4) & 0x07; | ||
| 308 | #ifdef CONFIG_NUMA | ||
| 309 | for (j = min_bus; j <= max_bus; j++) | ||
| 310 | mp_bus_to_node[j] = (unsigned char) node; | ||
| 311 | #endif | ||
| 312 | link = (reg >> 8) & 0x03; | ||
| 313 | |||
| 314 | info = &pci_root_info[pci_root_num]; | ||
| 315 | info->bus_min = min_bus; | ||
| 316 | info->bus_max = max_bus; | ||
| 317 | info->node = node; | ||
| 318 | info->link = link; | ||
| 319 | sprintf(info->name, "PCI Bus #%02x", min_bus); | ||
| 320 | pci_root_num++; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* get the default node and link for left over res */ | ||
| 324 | reg = read_pci_config(bus, slot, 0, 0x60); | ||
| 325 | def_node = (reg >> 8) & 0x07; | ||
| 326 | reg = read_pci_config(bus, slot, 0, 0x64); | ||
| 327 | def_link = (reg >> 8) & 0x03; | ||
| 328 | |||
| 329 | memset(range, 0, sizeof(range)); | ||
| 330 | range[0].end = 0xffff; | ||
| 331 | /* io port resource */ | ||
| 332 | for (i = 0; i < 4; i++) { | ||
| 333 | reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); | ||
| 334 | if (!(reg & 3)) | ||
| 335 | continue; | ||
| 336 | |||
| 337 | start = reg & 0xfff000; | ||
| 338 | reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3)); | ||
| 339 | node = reg & 0x07; | ||
| 340 | link = (reg >> 4) & 0x03; | ||
| 341 | end = (reg & 0xfff000) | 0xfff; | ||
| 342 | |||
| 343 | /* find the position */ | ||
| 344 | for (j = 0; j < pci_root_num; j++) { | ||
| 345 | info = &pci_root_info[j]; | ||
| 346 | if (info->node == node && info->link == link) | ||
| 347 | break; | ||
| 348 | } | ||
| 349 | if (j == pci_root_num) | ||
| 350 | continue; /* not found */ | ||
| 351 | |||
| 352 | info = &pci_root_info[j]; | ||
| 353 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", | ||
| 354 | node, link, (u64)start, (u64)end); | ||
| 355 | |||
| 356 | /* kernel only handle 16 bit only */ | ||
| 357 | if (end > 0xffff) | ||
| 358 | end = 0xffff; | ||
| 359 | update_res(info, start, end, IORESOURCE_IO, 1); | ||
| 360 | update_range(range, start, end); | ||
| 361 | } | ||
| 362 | /* add left over io port range to def node/link, [0, 0xffff] */ | ||
| 363 | /* find the position */ | ||
| 364 | for (j = 0; j < pci_root_num; j++) { | ||
| 365 | info = &pci_root_info[j]; | ||
| 366 | if (info->node == def_node && info->link == def_link) | ||
| 367 | break; | ||
| 368 | } | ||
| 369 | if (j < pci_root_num) { | ||
| 370 | info = &pci_root_info[j]; | ||
| 371 | for (i = 0; i < RANGE_NUM; i++) { | ||
| 372 | if (!range[i].end) | ||
| 373 | continue; | ||
| 374 | |||
| 375 | update_res(info, range[i].start, range[i].end, | ||
| 376 | IORESOURCE_IO, 1); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | memset(range, 0, sizeof(range)); | ||
| 381 | /* 0xfd00000000-0xffffffffff for HT */ | ||
| 382 | range[0].end = (0xfdULL<<32) - 1; | ||
| 383 | |||
| 384 | /* need to take out [0, TOM) for RAM*/ | ||
| 385 | address = MSR_K8_TOP_MEM1; | ||
| 386 | rdmsrl(address, val); | ||
| 387 | end = (val & 0xffffff8000000ULL); | ||
| 388 | printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20); | ||
| 389 | if (end < (1ULL<<32)) | ||
| 390 | update_range(range, 0, end - 1); | ||
| 391 | |||
| 392 | /* get mmconfig */ | ||
| 393 | get_pci_mmcfg_amd_fam10h_range(); | ||
| 394 | /* need to take out mmconf range */ | ||
| 395 | if (fam10h_mmconf_end) { | ||
| 396 | printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); | ||
| 397 | update_range(range, fam10h_mmconf_start, fam10h_mmconf_end); | ||
| 398 | } | ||
| 399 | |||
| 400 | /* mmio resource */ | ||
| 401 | for (i = 0; i < 8; i++) { | ||
| 402 | reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3)); | ||
| 403 | if (!(reg & 3)) | ||
| 404 | continue; | ||
| 405 | |||
| 406 | start = reg & 0xffffff00; /* 39:16 on 31:8*/ | ||
| 407 | start <<= 8; | ||
| 408 | reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3)); | ||
| 409 | node = reg & 0x07; | ||
| 410 | link = (reg >> 4) & 0x03; | ||
| 411 | end = (reg & 0xffffff00); | ||
| 412 | end <<= 8; | ||
| 413 | end |= 0xffff; | ||
| 414 | |||
| 415 | /* find the position */ | ||
| 416 | for (j = 0; j < pci_root_num; j++) { | ||
| 417 | info = &pci_root_info[j]; | ||
| 418 | if (info->node == node && info->link == link) | ||
| 419 | break; | ||
| 420 | } | ||
| 421 | if (j == pci_root_num) | ||
| 422 | continue; /* not found */ | ||
| 423 | |||
| 424 | info = &pci_root_info[j]; | ||
| 425 | |||
| 426 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", | ||
| 427 | node, link, (u64)start, (u64)end); | ||
| 428 | /* | ||
| 429 | * some sick allocation would have range overlap with fam10h | ||
| 430 | * mmconf range, so need to update start and end. | ||
| 431 | */ | ||
| 432 | if (fam10h_mmconf_end) { | ||
| 433 | int changed = 0; | ||
| 434 | u64 endx = 0; | ||
| 435 | if (start >= fam10h_mmconf_start && | ||
| 436 | start <= fam10h_mmconf_end) { | ||
| 437 | start = fam10h_mmconf_end + 1; | ||
| 438 | changed = 1; | ||
| 439 | } | ||
| 440 | |||
| 441 | if (end >= fam10h_mmconf_start && | ||
| 442 | end <= fam10h_mmconf_end) { | ||
| 443 | end = fam10h_mmconf_start - 1; | ||
| 444 | changed = 1; | ||
| 445 | } | ||
| 446 | |||
| 447 | if (start < fam10h_mmconf_start && | ||
| 448 | end > fam10h_mmconf_end) { | ||
| 449 | /* we got a hole */ | ||
| 450 | endx = fam10h_mmconf_start - 1; | ||
| 451 | update_res(info, start, endx, IORESOURCE_MEM, 0); | ||
| 452 | update_range(range, start, endx); | ||
| 453 | printk(KERN_CONT " ==> [%llx, %llx]", (u64)start, endx); | ||
| 454 | start = fam10h_mmconf_end + 1; | ||
| 455 | changed = 1; | ||
| 456 | } | ||
| 457 | if (changed) { | ||
| 458 | if (start <= end) { | ||
| 459 | printk(KERN_CONT " %s [%llx, %llx]", endx?"and":"==>", (u64)start, (u64)end); | ||
| 460 | } else { | ||
| 461 | printk(KERN_CONT "%s\n", endx?"":" ==> none"); | ||
| 462 | continue; | ||
| 463 | } | ||
| 76 | } | 464 | } |
| 77 | } | 465 | } |
| 466 | |||
| 467 | update_res(info, start, end, IORESOURCE_MEM, 1); | ||
| 468 | update_range(range, start, end); | ||
| 469 | printk(KERN_CONT "\n"); | ||
| 470 | } | ||
| 471 | |||
| 472 | /* need to take out [4G, TOM2) for RAM*/ | ||
| 473 | /* SYS_CFG */ | ||
| 474 | address = MSR_K8_SYSCFG; | ||
| 475 | rdmsrl(address, val); | ||
| 476 | /* TOP_MEM2 is enabled? */ | ||
| 477 | if (val & (1<<21)) { | ||
| 478 | /* TOP_MEM2 */ | ||
| 479 | address = MSR_K8_TOP_MEM2; | ||
| 480 | rdmsrl(address, val); | ||
| 481 | end = (val & 0xffffff8000000ULL); | ||
| 482 | printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20); | ||
| 483 | update_range(range, 1ULL<<32, end - 1); | ||
| 484 | } | ||
| 485 | |||
| 486 | /* | ||
| 487 | * add left over mmio range to def node/link ? | ||
| 488 | * that is tricky, just record range in from start_min to 4G | ||
| 489 | */ | ||
| 490 | for (j = 0; j < pci_root_num; j++) { | ||
| 491 | info = &pci_root_info[j]; | ||
| 492 | if (info->node == def_node && info->link == def_link) | ||
| 493 | break; | ||
| 494 | } | ||
| 495 | if (j < pci_root_num) { | ||
| 496 | info = &pci_root_info[j]; | ||
| 497 | |||
| 498 | for (i = 0; i < RANGE_NUM; i++) { | ||
| 499 | if (!range[i].end) | ||
| 500 | continue; | ||
| 501 | |||
| 502 | update_res(info, range[i].start, range[i].end, | ||
| 503 | IORESOURCE_MEM, 1); | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 507 | #ifdef CONFIG_NUMA | ||
| 508 | for (i = 0; i < BUS_NR; i++) { | ||
| 509 | node = mp_bus_to_node[i]; | ||
| 510 | if (node >= 0) | ||
| 511 | printk(KERN_DEBUG "bus: %02x to node: %02x\n", i, node); | ||
| 512 | } | ||
| 513 | #endif | ||
| 514 | |||
| 515 | for (i = 0; i < pci_root_num; i++) { | ||
| 516 | int res_num; | ||
| 517 | int busnum; | ||
| 518 | |||
| 519 | info = &pci_root_info[i]; | ||
| 520 | res_num = info->res_num; | ||
| 521 | busnum = info->bus_min; | ||
| 522 | printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n", | ||
| 523 | info->bus_min, info->bus_max, info->node, info->link); | ||
| 524 | for (j = 0; j < res_num; j++) { | ||
| 525 | res = &info->res[j]; | ||
| 526 | printk(KERN_DEBUG "bus: %02x index %x %s: [%llx, %llx]\n", | ||
| 527 | busnum, j, | ||
| 528 | (res->flags & IORESOURCE_IO)?"io port":"mmio", | ||
| 529 | res->start, res->end); | ||
| 530 | } | ||
| 78 | } | 531 | } |
| 79 | 532 | ||
| 80 | return 0; | 533 | return 0; |
| 81 | } | 534 | } |
| 82 | 535 | ||
| 83 | fs_initcall(fill_mp_bus_to_cpumask); | 536 | postcore_initcall(early_fill_mp_bus_info); |
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index e041ced0ce..a67921ce60 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | static void __devinit pcibios_fixup_peer_bridges(void) | 12 | static void __devinit pcibios_fixup_peer_bridges(void) |
| 13 | { | 13 | { |
| 14 | int n, devfn; | 14 | int n, devfn; |
| 15 | long node; | ||
| 15 | 16 | ||
| 16 | if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) | 17 | if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) |
| 17 | return; | 18 | return; |
| @@ -21,12 +22,13 @@ static void __devinit pcibios_fixup_peer_bridges(void) | |||
| 21 | u32 l; | 22 | u32 l; |
| 22 | if (pci_find_bus(0, n)) | 23 | if (pci_find_bus(0, n)) |
| 23 | continue; | 24 | continue; |
| 25 | node = get_mp_bus_to_node(n); | ||
| 24 | for (devfn = 0; devfn < 256; devfn += 8) { | 26 | for (devfn = 0; devfn < 256; devfn += 8) { |
| 25 | if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && | 27 | if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && |
| 26 | l != 0x0000 && l != 0xffff) { | 28 | l != 0x0000 && l != 0xffff) { |
| 27 | DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); | 29 | DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); |
| 28 | printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); | 30 | printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); |
| 29 | pci_scan_bus_with_sysdata(n); | 31 | pci_scan_bus_on_node(n, &pci_root_ops, node); |
| 30 | break; | 32 | break; |
| 31 | } | 33 | } |
| 32 | } | 34 | } |
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 8d54df4dfa..0cfebecf2a 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
| @@ -28,7 +28,7 @@ static int __initdata pci_mmcfg_resources_inserted; | |||
| 28 | static const char __init *pci_mmcfg_e7520(void) | 28 | static const char __init *pci_mmcfg_e7520(void) |
| 29 | { | 29 | { |
| 30 | u32 win; | 30 | u32 win; |
| 31 | pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); | 31 | raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win); |
| 32 | 32 | ||
| 33 | win = win & 0xf000; | 33 | win = win & 0xf000; |
| 34 | if(win == 0x0000 || win == 0xf000) | 34 | if(win == 0x0000 || win == 0xf000) |
| @@ -53,7 +53,7 @@ static const char __init *pci_mmcfg_intel_945(void) | |||
| 53 | 53 | ||
| 54 | pci_mmcfg_config_num = 1; | 54 | pci_mmcfg_config_num = 1; |
| 55 | 55 | ||
| 56 | pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); | 56 | raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar); |
| 57 | 57 | ||
| 58 | /* Enable bit */ | 58 | /* Enable bit */ |
| 59 | if (!(pciexbar & 1)) | 59 | if (!(pciexbar & 1)) |
| @@ -100,33 +100,102 @@ static const char __init *pci_mmcfg_intel_945(void) | |||
| 100 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; | 100 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | static const char __init *pci_mmcfg_amd_fam10h(void) | ||
| 104 | { | ||
| 105 | u32 low, high, address; | ||
| 106 | u64 base, msr; | ||
| 107 | int i; | ||
| 108 | unsigned segnbits = 0, busnbits; | ||
| 109 | |||
| 110 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) | ||
| 111 | return NULL; | ||
| 112 | |||
| 113 | address = MSR_FAM10H_MMIO_CONF_BASE; | ||
| 114 | if (rdmsr_safe(address, &low, &high)) | ||
| 115 | return NULL; | ||
| 116 | |||
| 117 | msr = high; | ||
| 118 | msr <<= 32; | ||
| 119 | msr |= low; | ||
| 120 | |||
| 121 | /* mmconfig is not enable */ | ||
| 122 | if (!(msr & FAM10H_MMIO_CONF_ENABLE)) | ||
| 123 | return NULL; | ||
| 124 | |||
| 125 | base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); | ||
| 126 | |||
| 127 | busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & | ||
| 128 | FAM10H_MMIO_CONF_BUSRANGE_MASK; | ||
| 129 | |||
| 130 | /* | ||
| 131 | * only handle bus 0 ? | ||
| 132 | * need to skip it | ||
| 133 | */ | ||
| 134 | if (!busnbits) | ||
| 135 | return NULL; | ||
| 136 | |||
| 137 | if (busnbits > 8) { | ||
| 138 | segnbits = busnbits - 8; | ||
| 139 | busnbits = 8; | ||
| 140 | } | ||
| 141 | |||
| 142 | pci_mmcfg_config_num = (1 << segnbits); | ||
| 143 | pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) * | ||
| 144 | pci_mmcfg_config_num, GFP_KERNEL); | ||
| 145 | if (!pci_mmcfg_config) | ||
| 146 | return NULL; | ||
| 147 | |||
| 148 | for (i = 0; i < (1 << segnbits); i++) { | ||
| 149 | pci_mmcfg_config[i].address = base + (1<<28) * i; | ||
| 150 | pci_mmcfg_config[i].pci_segment = i; | ||
| 151 | pci_mmcfg_config[i].start_bus_number = 0; | ||
| 152 | pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1; | ||
| 153 | } | ||
| 154 | |||
| 155 | return "AMD Family 10h NB"; | ||
| 156 | } | ||
| 157 | |||
| 103 | struct pci_mmcfg_hostbridge_probe { | 158 | struct pci_mmcfg_hostbridge_probe { |
| 159 | u32 bus; | ||
| 160 | u32 devfn; | ||
| 104 | u32 vendor; | 161 | u32 vendor; |
| 105 | u32 device; | 162 | u32 device; |
| 106 | const char *(*probe)(void); | 163 | const char *(*probe)(void); |
| 107 | }; | 164 | }; |
| 108 | 165 | ||
| 109 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { | 166 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { |
| 110 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, | 167 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, |
| 111 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | 168 | PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, |
| 169 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, | ||
| 170 | PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | ||
| 171 | { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD, | ||
| 172 | 0x1200, pci_mmcfg_amd_fam10h }, | ||
| 173 | { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, | ||
| 174 | 0x1200, pci_mmcfg_amd_fam10h }, | ||
| 112 | }; | 175 | }; |
| 113 | 176 | ||
| 114 | static int __init pci_mmcfg_check_hostbridge(void) | 177 | static int __init pci_mmcfg_check_hostbridge(void) |
| 115 | { | 178 | { |
| 116 | u32 l; | 179 | u32 l; |
| 180 | u32 bus, devfn; | ||
| 117 | u16 vendor, device; | 181 | u16 vendor, device; |
| 118 | int i; | 182 | int i; |
| 119 | const char *name; | 183 | const char *name; |
| 120 | 184 | ||
| 121 | pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); | 185 | if (!raw_pci_ops) |
| 122 | vendor = l & 0xffff; | 186 | return 0; |
| 123 | device = (l >> 16) & 0xffff; | ||
| 124 | 187 | ||
| 125 | pci_mmcfg_config_num = 0; | 188 | pci_mmcfg_config_num = 0; |
| 126 | pci_mmcfg_config = NULL; | 189 | pci_mmcfg_config = NULL; |
| 127 | name = NULL; | 190 | name = NULL; |
| 128 | 191 | ||
| 129 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { | 192 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
| 193 | bus = pci_mmcfg_probes[i].bus; | ||
| 194 | devfn = pci_mmcfg_probes[i].devfn; | ||
| 195 | raw_pci_ops->read(0, bus, devfn, 0, 4, &l); | ||
| 196 | vendor = l & 0xffff; | ||
| 197 | device = (l >> 16) & 0xffff; | ||
| 198 | |||
| 130 | if (pci_mmcfg_probes[i].vendor == vendor && | 199 | if (pci_mmcfg_probes[i].vendor == vendor && |
| 131 | pci_mmcfg_probes[i].device == device) | 200 | pci_mmcfg_probes[i].device == device) |
| 132 | name = pci_mmcfg_probes[i].probe(); | 201 | name = pci_mmcfg_probes[i].probe(); |
| @@ -173,9 +242,78 @@ static void __init pci_mmcfg_insert_resources(unsigned long resource_flags) | |||
| 173 | pci_mmcfg_resources_inserted = 1; | 242 | pci_mmcfg_resources_inserted = 1; |
| 174 | } | 243 | } |
| 175 | 244 | ||
| 176 | static void __init pci_mmcfg_reject_broken(int type) | 245 | static acpi_status __init check_mcfg_resource(struct acpi_resource *res, |
| 246 | void *data) | ||
| 247 | { | ||
| 248 | struct resource *mcfg_res = data; | ||
| 249 | struct acpi_resource_address64 address; | ||
| 250 | acpi_status status; | ||
| 251 | |||
| 252 | if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { | ||
| 253 | struct acpi_resource_fixed_memory32 *fixmem32 = | ||
| 254 | &res->data.fixed_memory32; | ||
| 255 | if (!fixmem32) | ||
| 256 | return AE_OK; | ||
| 257 | if ((mcfg_res->start >= fixmem32->address) && | ||
| 258 | (mcfg_res->end < (fixmem32->address + | ||
| 259 | fixmem32->address_length))) { | ||
| 260 | mcfg_res->flags = 1; | ||
| 261 | return AE_CTRL_TERMINATE; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) && | ||
| 265 | (res->type != ACPI_RESOURCE_TYPE_ADDRESS64)) | ||
| 266 | return AE_OK; | ||
| 267 | |||
| 268 | status = acpi_resource_to_address64(res, &address); | ||
| 269 | if (ACPI_FAILURE(status) || | ||
| 270 | (address.address_length <= 0) || | ||
| 271 | (address.resource_type != ACPI_MEMORY_RANGE)) | ||
| 272 | return AE_OK; | ||
| 273 | |||
| 274 | if ((mcfg_res->start >= address.minimum) && | ||
| 275 | (mcfg_res->end < (address.minimum + address.address_length))) { | ||
| 276 | mcfg_res->flags = 1; | ||
| 277 | return AE_CTRL_TERMINATE; | ||
| 278 | } | ||
| 279 | return AE_OK; | ||
| 280 | } | ||
| 281 | |||
| 282 | static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl, | ||
| 283 | void *context, void **rv) | ||
| 284 | { | ||
| 285 | struct resource *mcfg_res = context; | ||
| 286 | |||
| 287 | acpi_walk_resources(handle, METHOD_NAME__CRS, | ||
| 288 | check_mcfg_resource, context); | ||
| 289 | |||
| 290 | if (mcfg_res->flags) | ||
| 291 | return AE_CTRL_TERMINATE; | ||
| 292 | |||
| 293 | return AE_OK; | ||
| 294 | } | ||
| 295 | |||
| 296 | static int __init is_acpi_reserved(unsigned long start, unsigned long end) | ||
| 297 | { | ||
| 298 | struct resource mcfg_res; | ||
| 299 | |||
| 300 | mcfg_res.start = start; | ||
| 301 | mcfg_res.end = end; | ||
| 302 | mcfg_res.flags = 0; | ||
| 303 | |||
| 304 | acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL); | ||
| 305 | |||
| 306 | if (!mcfg_res.flags) | ||
| 307 | acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res, | ||
| 308 | NULL); | ||
| 309 | |||
| 310 | return mcfg_res.flags; | ||
| 311 | } | ||
| 312 | |||
| 313 | static void __init pci_mmcfg_reject_broken(int early) | ||
| 177 | { | 314 | { |
| 178 | typeof(pci_mmcfg_config[0]) *cfg; | 315 | typeof(pci_mmcfg_config[0]) *cfg; |
| 316 | int i; | ||
| 179 | 317 | ||
| 180 | if ((pci_mmcfg_config_num == 0) || | 318 | if ((pci_mmcfg_config_num == 0) || |
| 181 | (pci_mmcfg_config == NULL) || | 319 | (pci_mmcfg_config == NULL) || |
| @@ -184,51 +322,80 @@ static void __init pci_mmcfg_reject_broken(int type) | |||
| 184 | 322 | ||
| 185 | cfg = &pci_mmcfg_config[0]; | 323 | cfg = &pci_mmcfg_config[0]; |
| 186 | 324 | ||
| 187 | /* | 325 | for (i = 0; i < pci_mmcfg_config_num; i++) { |
| 188 | * Handle more broken MCFG tables on Asus etc. | 326 | int valid = 0; |
| 189 | * They only contain a single entry for bus 0-0. | 327 | u32 size = (cfg->end_bus_number + 1) << 20; |
| 190 | */ | 328 | cfg = &pci_mmcfg_config[i]; |
| 191 | if (pci_mmcfg_config_num == 1 && | 329 | printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " |
| 192 | cfg->pci_segment == 0 && | 330 | "segment %hu buses %u - %u\n", |
| 193 | (cfg->start_bus_number | cfg->end_bus_number) == 0) { | 331 | i, (unsigned long)cfg->address, cfg->pci_segment, |
| 194 | printk(KERN_ERR "PCI: start and end of bus number is 0. " | 332 | (unsigned int)cfg->start_bus_number, |
| 195 | "Rejected as broken MCFG.\n"); | 333 | (unsigned int)cfg->end_bus_number); |
| 196 | goto reject; | 334 | |
| 335 | if (!early && | ||
| 336 | is_acpi_reserved(cfg->address, cfg->address + size - 1)) { | ||
| 337 | printk(KERN_NOTICE "PCI: MCFG area at %Lx reserved " | ||
| 338 | "in ACPI motherboard resources\n", | ||
| 339 | cfg->address); | ||
| 340 | valid = 1; | ||
| 341 | } | ||
| 342 | |||
| 343 | if (valid) | ||
| 344 | continue; | ||
| 345 | |||
| 346 | if (!early) | ||
| 347 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" | ||
| 348 | " reserved in ACPI motherboard resources\n", | ||
| 349 | cfg->address); | ||
| 350 | /* Don't try to do this check unless configuration | ||
| 351 | type 1 is available. how about type 2 ?*/ | ||
| 352 | if (raw_pci_ops && e820_all_mapped(cfg->address, | ||
| 353 | cfg->address + size - 1, | ||
| 354 | E820_RESERVED)) { | ||
| 355 | printk(KERN_NOTICE | ||
| 356 | "PCI: MCFG area at %Lx reserved in E820\n", | ||
| 357 | cfg->address); | ||
| 358 | valid = 1; | ||
| 359 | } | ||
| 360 | |||
| 361 | if (!valid) | ||
| 362 | goto reject; | ||
| 197 | } | 363 | } |
| 198 | 364 | ||
| 199 | /* | ||
| 200 | * Only do this check when type 1 works. If it doesn't work | ||
| 201 | * assume we run on a Mac and always use MCFG | ||
| 202 | */ | ||
| 203 | if (type == 1 && !e820_all_mapped(cfg->address, | ||
| 204 | cfg->address + MMCONFIG_APER_MIN, | ||
| 205 | E820_RESERVED)) { | ||
| 206 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" | ||
| 207 | " E820-reserved\n", cfg->address); | ||
| 208 | goto reject; | ||
| 209 | } | ||
| 210 | return; | 365 | return; |
| 211 | 366 | ||
| 212 | reject: | 367 | reject: |
| 213 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | 368 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); |
| 369 | pci_mmcfg_arch_free(); | ||
| 214 | kfree(pci_mmcfg_config); | 370 | kfree(pci_mmcfg_config); |
| 215 | pci_mmcfg_config = NULL; | 371 | pci_mmcfg_config = NULL; |
| 216 | pci_mmcfg_config_num = 0; | 372 | pci_mmcfg_config_num = 0; |
| 217 | } | 373 | } |
| 218 | 374 | ||
| 219 | void __init pci_mmcfg_init(int type) | 375 | static int __initdata known_bridge; |
| 220 | { | ||
| 221 | int known_bridge = 0; | ||
| 222 | 376 | ||
| 377 | void __init __pci_mmcfg_init(int early) | ||
| 378 | { | ||
| 379 | /* MMCONFIG disabled */ | ||
| 223 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) | 380 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
| 224 | return; | 381 | return; |
| 225 | 382 | ||
| 226 | if (type == 1 && pci_mmcfg_check_hostbridge()) | 383 | /* MMCONFIG already enabled */ |
| 227 | known_bridge = 1; | 384 | if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF)) |
| 385 | return; | ||
| 386 | |||
| 387 | /* for late to exit */ | ||
| 388 | if (known_bridge) | ||
| 389 | return; | ||
| 390 | |||
| 391 | if (early) { | ||
| 392 | if (pci_mmcfg_check_hostbridge()) | ||
| 393 | known_bridge = 1; | ||
| 394 | } | ||
| 228 | 395 | ||
| 229 | if (!known_bridge) { | 396 | if (!known_bridge) { |
| 230 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); | 397 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); |
| 231 | pci_mmcfg_reject_broken(type); | 398 | pci_mmcfg_reject_broken(early); |
| 232 | } | 399 | } |
| 233 | 400 | ||
| 234 | if ((pci_mmcfg_config_num == 0) || | 401 | if ((pci_mmcfg_config_num == 0) || |
| @@ -249,6 +416,16 @@ void __init pci_mmcfg_init(int type) | |||
| 249 | } | 416 | } |
| 250 | } | 417 | } |
| 251 | 418 | ||
| 419 | void __init pci_mmcfg_early_init(void) | ||
| 420 | { | ||
| 421 | __pci_mmcfg_init(1); | ||
| 422 | } | ||
| 423 | |||
| 424 | void __init pci_mmcfg_late_init(void) | ||
| 425 | { | ||
| 426 | __pci_mmcfg_init(0); | ||
| 427 | } | ||
| 428 | |||
| 252 | static int __init pci_mmcfg_late_insert_resources(void) | 429 | static int __init pci_mmcfg_late_insert_resources(void) |
| 253 | { | 430 | { |
| 254 | /* | 431 | /* |
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c index 081816ada0..f3c761dce6 100644 --- a/arch/x86/pci/mmconfig_32.c +++ b/arch/x86/pci/mmconfig_32.c | |||
| @@ -136,3 +136,7 @@ int __init pci_mmcfg_arch_init(void) | |||
| 136 | raw_pci_ext_ops = &pci_mmcfg; | 136 | raw_pci_ext_ops = &pci_mmcfg; |
| 137 | return 1; | 137 | return 1; |
| 138 | } | 138 | } |
| 139 | |||
| 140 | void __init pci_mmcfg_arch_free(void) | ||
| 141 | { | ||
| 142 | } | ||
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c index 9207fd4923..a1994163c9 100644 --- a/arch/x86/pci/mmconfig_64.c +++ b/arch/x86/pci/mmconfig_64.c | |||
| @@ -127,7 +127,7 @@ static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg) | |||
| 127 | int __init pci_mmcfg_arch_init(void) | 127 | int __init pci_mmcfg_arch_init(void) |
| 128 | { | 128 | { |
| 129 | int i; | 129 | int i; |
| 130 | pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * | 130 | pci_mmcfg_virt = kzalloc(sizeof(*pci_mmcfg_virt) * |
| 131 | pci_mmcfg_config_num, GFP_KERNEL); | 131 | pci_mmcfg_config_num, GFP_KERNEL); |
| 132 | if (pci_mmcfg_virt == NULL) { | 132 | if (pci_mmcfg_virt == NULL) { |
| 133 | printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n"); | 133 | printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n"); |
| @@ -141,9 +141,29 @@ int __init pci_mmcfg_arch_init(void) | |||
| 141 | printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " | 141 | printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " |
| 142 | "segment %d\n", | 142 | "segment %d\n", |
| 143 | pci_mmcfg_config[i].pci_segment); | 143 | pci_mmcfg_config[i].pci_segment); |
| 144 | pci_mmcfg_arch_free(); | ||
| 144 | return 0; | 145 | return 0; |
| 145 | } | 146 | } |
| 146 | } | 147 | } |
| 147 | raw_pci_ext_ops = &pci_mmcfg; | 148 | raw_pci_ext_ops = &pci_mmcfg; |
| 148 | return 1; | 149 | return 1; |
| 149 | } | 150 | } |
| 151 | |||
| 152 | void __init pci_mmcfg_arch_free(void) | ||
| 153 | { | ||
| 154 | int i; | ||
| 155 | |||
| 156 | if (pci_mmcfg_virt == NULL) | ||
| 157 | return; | ||
| 158 | |||
| 159 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | ||
| 160 | if (pci_mmcfg_virt[i].virt) { | ||
| 161 | iounmap(pci_mmcfg_virt[i].virt); | ||
| 162 | pci_mmcfg_virt[i].virt = NULL; | ||
| 163 | pci_mmcfg_virt[i].cfg = NULL; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | kfree(pci_mmcfg_virt); | ||
| 168 | pci_mmcfg_virt = NULL; | ||
| 169 | } | ||
diff --git a/arch/x86/pci/mp_bus_to_node.c b/arch/x86/pci/mp_bus_to_node.c new file mode 100644 index 0000000000..022943999b --- /dev/null +++ b/arch/x86/pci/mp_bus_to_node.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #include <linux/pci.h> | ||
| 2 | #include <linux/init.h> | ||
| 3 | #include <linux/topology.h> | ||
| 4 | |||
| 5 | #define BUS_NR 256 | ||
| 6 | |||
| 7 | static unsigned char mp_bus_to_node[BUS_NR]; | ||
| 8 | |||
| 9 | void set_mp_bus_to_node(int busnum, int node) | ||
| 10 | { | ||
| 11 | if (busnum >= 0 && busnum < BUS_NR) | ||
| 12 | mp_bus_to_node[busnum] = (unsigned char) node; | ||
| 13 | } | ||
| 14 | |||
| 15 | int get_mp_bus_to_node(int busnum) | ||
| 16 | { | ||
| 17 | int node; | ||
| 18 | |||
| 19 | if (busnum < 0 || busnum > (BUS_NR - 1)) | ||
| 20 | return 0; | ||
| 21 | node = mp_bus_to_node[busnum]; | ||
| 22 | return node; | ||
| 23 | } | ||
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 7d84e813e9..c58805a92d 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #define PCI_ASSIGN_ALL_BUSSES 0x4000 | 26 | #define PCI_ASSIGN_ALL_BUSSES 0x4000 |
| 27 | #define PCI_CAN_SKIP_ISA_ALIGN 0x8000 | 27 | #define PCI_CAN_SKIP_ISA_ALIGN 0x8000 |
| 28 | #define PCI_USE__CRS 0x10000 | 28 | #define PCI_USE__CRS 0x10000 |
| 29 | #define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000 | ||
| 29 | 30 | ||
| 30 | extern unsigned int pci_probe; | 31 | extern unsigned int pci_probe; |
| 31 | extern unsigned long pirq_table_addr; | 32 | extern unsigned long pirq_table_addr; |
| @@ -97,12 +98,12 @@ extern struct pci_raw_ops pci_direct_conf1; | |||
| 97 | extern int pci_direct_probe(void); | 98 | extern int pci_direct_probe(void); |
| 98 | extern void pci_direct_init(int type); | 99 | extern void pci_direct_init(int type); |
| 99 | extern void pci_pcbios_init(void); | 100 | extern void pci_pcbios_init(void); |
| 100 | extern void pci_mmcfg_init(int type); | ||
| 101 | extern void pci_olpc_init(void); | 101 | extern void pci_olpc_init(void); |
| 102 | 102 | ||
| 103 | /* pci-mmconfig.c */ | 103 | /* pci-mmconfig.c */ |
| 104 | 104 | ||
| 105 | extern int __init pci_mmcfg_arch_init(void); | 105 | extern int __init pci_mmcfg_arch_init(void); |
| 106 | extern void __init pci_mmcfg_arch_free(void); | ||
| 106 | 107 | ||
| 107 | /* | 108 | /* |
| 108 | * AMD Fam10h CPUs are buggy, and cannot access MMIO config space | 109 | * AMD Fam10h CPUs are buggy, and cannot access MMIO config space |
