0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/string.h>
0013 #include <linux/nodemask.h>
0014 #include <linux/memblock.h>
0015
0016 #include <asm/io.h>
0017 #include <linux/pci_ids.h>
0018 #include <linux/acpi.h>
0019 #include <asm/types.h>
0020 #include <asm/mmzone.h>
0021 #include <asm/proto.h>
0022 #include <asm/e820/api.h>
0023 #include <asm/pci-direct.h>
0024 #include <asm/numa.h>
0025 #include <asm/mpspec.h>
0026 #include <asm/apic.h>
0027 #include <asm/amd_nb.h>
0028
0029 static unsigned char __initdata nodeids[8];
0030
0031 static __init int find_northbridge(void)
0032 {
0033 int num;
0034
0035 for (num = 0; num < 32; num++) {
0036 u32 header;
0037
0038 header = read_pci_config(0, num, 0, 0x00);
0039 if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)) &&
0040 header != (PCI_VENDOR_ID_AMD | (0x1200<<16)) &&
0041 header != (PCI_VENDOR_ID_AMD | (0x1300<<16)))
0042 continue;
0043
0044 header = read_pci_config(0, num, 1, 0x00);
0045 if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)) &&
0046 header != (PCI_VENDOR_ID_AMD | (0x1201<<16)) &&
0047 header != (PCI_VENDOR_ID_AMD | (0x1301<<16)))
0048 continue;
0049 return num;
0050 }
0051
0052 return -ENOENT;
0053 }
0054
0055 int __init amd_numa_init(void)
0056 {
0057 u64 start = PFN_PHYS(0);
0058 u64 end = PFN_PHYS(max_pfn);
0059 unsigned numnodes;
0060 u64 prevbase;
0061 int i, j, nb;
0062 u32 nodeid, reg;
0063 unsigned int bits, cores, apicid_base;
0064
0065 if (!early_pci_allowed())
0066 return -EINVAL;
0067
0068 nb = find_northbridge();
0069 if (nb < 0)
0070 return nb;
0071
0072 pr_info("Scanning NUMA topology in Northbridge %d\n", nb);
0073
0074 reg = read_pci_config(0, nb, 0, 0x60);
0075 numnodes = ((reg >> 4) & 0xF) + 1;
0076 if (numnodes <= 1)
0077 return -ENOENT;
0078
0079 pr_info("Number of physical nodes %d\n", numnodes);
0080
0081 prevbase = 0;
0082 for (i = 0; i < 8; i++) {
0083 u64 base, limit;
0084
0085 base = read_pci_config(0, nb, 1, 0x40 + i*8);
0086 limit = read_pci_config(0, nb, 1, 0x44 + i*8);
0087
0088 nodeids[i] = nodeid = limit & 7;
0089 if ((base & 3) == 0) {
0090 if (i < numnodes)
0091 pr_info("Skipping disabled node %d\n", i);
0092 continue;
0093 }
0094 if (nodeid >= numnodes) {
0095 pr_info("Ignoring excess node %d (%Lx:%Lx)\n", nodeid,
0096 base, limit);
0097 continue;
0098 }
0099
0100 if (!limit) {
0101 pr_info("Skipping node entry %d (base %Lx)\n",
0102 i, base);
0103 continue;
0104 }
0105 if ((base >> 8) & 3 || (limit >> 8) & 3) {
0106 pr_err("Node %d using interleaving mode %Lx/%Lx\n",
0107 nodeid, (base >> 8) & 3, (limit >> 8) & 3);
0108 return -EINVAL;
0109 }
0110 if (node_isset(nodeid, numa_nodes_parsed)) {
0111 pr_info("Node %d already present, skipping\n",
0112 nodeid);
0113 continue;
0114 }
0115
0116 limit >>= 16;
0117 limit++;
0118 limit <<= 24;
0119
0120 if (limit > end)
0121 limit = end;
0122 if (limit <= base)
0123 continue;
0124
0125 base >>= 16;
0126 base <<= 24;
0127
0128 if (base < start)
0129 base = start;
0130 if (limit > end)
0131 limit = end;
0132 if (limit == base) {
0133 pr_err("Empty node %d\n", nodeid);
0134 continue;
0135 }
0136 if (limit < base) {
0137 pr_err("Node %d bogus settings %Lx-%Lx.\n",
0138 nodeid, base, limit);
0139 continue;
0140 }
0141
0142
0143 if (prevbase > base) {
0144 pr_err("Node map not sorted %Lx,%Lx\n",
0145 prevbase, base);
0146 return -EINVAL;
0147 }
0148
0149 pr_info("Node %d MemBase %016Lx Limit %016Lx\n",
0150 nodeid, base, limit);
0151
0152 prevbase = base;
0153 numa_add_memblk(nodeid, base, limit);
0154 node_set(nodeid, numa_nodes_parsed);
0155 }
0156
0157 if (nodes_empty(numa_nodes_parsed))
0158 return -ENOENT;
0159
0160
0161
0162
0163
0164 bits = boot_cpu_data.x86_coreid_bits;
0165 cores = 1 << bits;
0166 apicid_base = 0;
0167
0168
0169
0170
0171 early_get_smp_config();
0172
0173 if (boot_cpu_physical_apicid > 0) {
0174 pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
0175 apicid_base = boot_cpu_physical_apicid;
0176 }
0177
0178 for_each_node_mask(i, numa_nodes_parsed)
0179 for (j = apicid_base; j < cores + apicid_base; j++)
0180 set_apicid_to_node((i << bits) + j, i);
0181
0182 return 0;
0183 }