diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/mm/k8topology_64.c | 144 |
1 files changed, 72 insertions, 72 deletions
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c index 3695c9e8b9b6..32b963de9b8f 100644 --- a/arch/x86/mm/k8topology_64.c +++ b/arch/x86/mm/k8topology_64.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * AMD K8 NUMA support. | 2 | * AMD K8 NUMA support. |
3 | * Discover the memory map and associated nodes. | 3 | * Discover the memory map and associated nodes. |
4 | * | 4 | * |
5 | * This version reads it directly from the K8 northbridge. | 5 | * This version reads it directly from the K8 northbridge. |
6 | * | 6 | * |
7 | * Copyright 2002,2003 Andi Kleen, SuSE Labs. | 7 | * Copyright 2002,2003 Andi Kleen, SuSE Labs. |
8 | */ | 8 | */ |
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
@@ -22,26 +22,26 @@ | |||
22 | 22 | ||
23 | static __init int find_northbridge(void) | 23 | static __init int find_northbridge(void) |
24 | { | 24 | { |
25 | int num; | 25 | int num; |
26 | 26 | ||
27 | for (num = 0; num < 32; num++) { | 27 | for (num = 0; num < 32; num++) { |
28 | u32 header; | 28 | u32 header; |
29 | 29 | ||
30 | header = read_pci_config(0, num, 0, 0x00); | 30 | header = read_pci_config(0, num, 0, 0x00); |
31 | if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16))) | 31 | if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16))) |
32 | continue; | 32 | continue; |
33 | 33 | ||
34 | header = read_pci_config(0, num, 1, 0x00); | 34 | header = read_pci_config(0, num, 1, 0x00); |
35 | if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16))) | 35 | if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16))) |
36 | continue; | 36 | continue; |
37 | return num; | 37 | return num; |
38 | } | 38 | } |
39 | 39 | ||
40 | return -1; | 40 | return -1; |
41 | } | 41 | } |
42 | 42 | ||
43 | int __init k8_scan_nodes(unsigned long start, unsigned long end) | 43 | int __init k8_scan_nodes(unsigned long start, unsigned long end) |
44 | { | 44 | { |
45 | unsigned long prevbase; | 45 | unsigned long prevbase; |
46 | struct bootnode nodes[8]; | 46 | struct bootnode nodes[8]; |
47 | int nodeid, i, nb; | 47 | int nodeid, i, nb; |
@@ -56,97 +56,97 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) | |||
56 | if (!early_pci_allowed()) | 56 | if (!early_pci_allowed()) |
57 | return -1; | 57 | return -1; |
58 | 58 | ||
59 | nb = find_northbridge(); | 59 | nb = find_northbridge(); |
60 | if (nb < 0) | 60 | if (nb < 0) |
61 | return nb; | 61 | return nb; |
62 | 62 | ||
63 | printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); | 63 | printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); |
64 | 64 | ||
65 | reg = read_pci_config(0, nb, 0, 0x60); | 65 | reg = read_pci_config(0, nb, 0, 0x60); |
66 | numnodes = ((reg >> 4) & 0xF) + 1; | 66 | numnodes = ((reg >> 4) & 0xF) + 1; |
67 | if (numnodes <= 1) | 67 | if (numnodes <= 1) |
68 | return -1; | 68 | return -1; |
69 | 69 | ||
70 | printk(KERN_INFO "Number of nodes %d\n", numnodes); | 70 | printk(KERN_INFO "Number of nodes %d\n", numnodes); |
71 | 71 | ||
72 | memset(&nodes,0,sizeof(nodes)); | 72 | memset(&nodes, 0, sizeof(nodes)); |
73 | prevbase = 0; | 73 | prevbase = 0; |
74 | for (i = 0; i < 8; i++) { | 74 | for (i = 0; i < 8; i++) { |
75 | unsigned long base,limit; | 75 | unsigned long base, limit; |
76 | u32 nodeid; | 76 | u32 nodeid; |
77 | 77 | ||
78 | base = read_pci_config(0, nb, 1, 0x40 + i*8); | 78 | base = read_pci_config(0, nb, 1, 0x40 + i*8); |
79 | limit = read_pci_config(0, nb, 1, 0x44 + i*8); | 79 | limit = read_pci_config(0, nb, 1, 0x44 + i*8); |
80 | 80 | ||
81 | nodeid = limit & 7; | 81 | nodeid = limit & 7; |
82 | nodeids[i] = nodeid; | 82 | nodeids[i] = nodeid; |
83 | if ((base & 3) == 0) { | 83 | if ((base & 3) == 0) { |
84 | if (i < numnodes) | 84 | if (i < numnodes) |
85 | printk("Skipping disabled node %d\n", i); | 85 | printk("Skipping disabled node %d\n", i); |
86 | continue; | 86 | continue; |
87 | } | 87 | } |
88 | if (nodeid >= numnodes) { | 88 | if (nodeid >= numnodes) { |
89 | printk("Ignoring excess node %d (%lx:%lx)\n", nodeid, | 89 | printk("Ignoring excess node %d (%lx:%lx)\n", nodeid, |
90 | base, limit); | 90 | base, limit); |
91 | continue; | 91 | continue; |
92 | } | 92 | } |
93 | 93 | ||
94 | if (!limit) { | 94 | if (!limit) { |
95 | printk(KERN_INFO "Skipping node entry %d (base %lx)\n", i, | 95 | printk(KERN_INFO "Skipping node entry %d (base %lx)\n", |
96 | base); | 96 | i, base); |
97 | continue; | 97 | continue; |
98 | } | 98 | } |
99 | if ((base >> 8) & 3 || (limit >> 8) & 3) { | 99 | if ((base >> 8) & 3 || (limit >> 8) & 3) { |
100 | printk(KERN_ERR "Node %d using interleaving mode %lx/%lx\n", | 100 | printk(KERN_ERR "Node %d using interleaving mode %lx/%lx\n", |
101 | nodeid, (base>>8)&3, (limit>>8) & 3); | 101 | nodeid, (base>>8)&3, (limit>>8) & 3); |
102 | return -1; | 102 | return -1; |
103 | } | 103 | } |
104 | if (node_isset(nodeid, node_possible_map)) { | 104 | if (node_isset(nodeid, node_possible_map)) { |
105 | printk(KERN_INFO "Node %d already present. Skipping\n", | 105 | printk(KERN_INFO "Node %d already present. Skipping\n", |
106 | nodeid); | 106 | nodeid); |
107 | continue; | 107 | continue; |
108 | } | 108 | } |
109 | 109 | ||
110 | limit >>= 16; | 110 | limit >>= 16; |
111 | limit <<= 24; | 111 | limit <<= 24; |
112 | limit |= (1<<24)-1; | 112 | limit |= (1<<24)-1; |
113 | limit++; | 113 | limit++; |
114 | 114 | ||
115 | if (limit > end_pfn << PAGE_SHIFT) | 115 | if (limit > end_pfn << PAGE_SHIFT) |
116 | limit = end_pfn << PAGE_SHIFT; | 116 | limit = end_pfn << PAGE_SHIFT; |
117 | if (limit <= base) | 117 | if (limit <= base) |
118 | continue; | 118 | continue; |
119 | 119 | ||
120 | base >>= 16; | 120 | base >>= 16; |
121 | base <<= 24; | 121 | base <<= 24; |
122 | 122 | ||
123 | if (base < start) | 123 | if (base < start) |
124 | base = start; | 124 | base = start; |
125 | if (limit > end) | 125 | if (limit > end) |
126 | limit = end; | 126 | limit = end; |
127 | if (limit == base) { | 127 | if (limit == base) { |
128 | printk(KERN_ERR "Empty node %d\n", nodeid); | 128 | printk(KERN_ERR "Empty node %d\n", nodeid); |
129 | continue; | 129 | continue; |
130 | } | 130 | } |
131 | if (limit < base) { | 131 | if (limit < base) { |
132 | printk(KERN_ERR "Node %d bogus settings %lx-%lx.\n", | 132 | printk(KERN_ERR "Node %d bogus settings %lx-%lx.\n", |
133 | nodeid, base, limit); | 133 | nodeid, base, limit); |
134 | continue; | 134 | continue; |
135 | } | 135 | } |
136 | 136 | ||
137 | /* Could sort here, but pun for now. Should not happen anyroads. */ | 137 | /* Could sort here, but pun for now. Should not happen anyroads. */ |
138 | if (prevbase > base) { | 138 | if (prevbase > base) { |
139 | printk(KERN_ERR "Node map not sorted %lx,%lx\n", | 139 | printk(KERN_ERR "Node map not sorted %lx,%lx\n", |
140 | prevbase,base); | 140 | prevbase, base); |
141 | return -1; | 141 | return -1; |
142 | } | 142 | } |
143 | 143 | ||
144 | printk(KERN_INFO "Node %d MemBase %016lx Limit %016lx\n", | 144 | printk(KERN_INFO "Node %d MemBase %016lx Limit %016lx\n", |
145 | nodeid, base, limit); | 145 | nodeid, base, limit); |
146 | 146 | ||
147 | found++; | 147 | found++; |
148 | 148 | ||
149 | nodes[nodeid].start = base; | 149 | nodes[nodeid].start = base; |
150 | nodes[nodeid].end = limit; | 150 | nodes[nodeid].end = limit; |
151 | e820_register_active_regions(nodeid, | 151 | e820_register_active_regions(nodeid, |
152 | nodes[nodeid].start >> PAGE_SHIFT, | 152 | nodes[nodeid].start >> PAGE_SHIFT, |
@@ -155,31 +155,31 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) | |||
155 | prevbase = base; | 155 | prevbase = base; |
156 | 156 | ||
157 | node_set(nodeid, node_possible_map); | 157 | node_set(nodeid, node_possible_map); |
158 | } | 158 | } |
159 | 159 | ||
160 | if (!found) | 160 | if (!found) |
161 | return -1; | 161 | return -1; |
162 | 162 | ||
163 | memnode_shift = compute_hash_shift(nodes, 8); | 163 | memnode_shift = compute_hash_shift(nodes, 8); |
164 | if (memnode_shift < 0) { | 164 | if (memnode_shift < 0) { |
165 | printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n"); | 165 | printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n"); |
166 | return -1; | 166 | return -1; |
167 | } | 167 | } |
168 | printk(KERN_INFO "Using node hash shift of %d\n", memnode_shift); | 168 | printk(KERN_INFO "Using node hash shift of %d\n", memnode_shift); |
169 | 169 | ||
170 | /* use the coreid bits from early_identify_cpu */ | 170 | /* use the coreid bits from early_identify_cpu */ |
171 | bits = boot_cpu_data.x86_coreid_bits; | 171 | bits = boot_cpu_data.x86_coreid_bits; |
172 | cores = (1<<bits); | 172 | cores = (1<<bits); |
173 | 173 | ||
174 | for (i = 0; i < 8; i++) { | 174 | for (i = 0; i < 8; i++) { |
175 | if (nodes[i].start != nodes[i].end) { | 175 | if (nodes[i].start != nodes[i].end) { |
176 | nodeid = nodeids[i]; | 176 | nodeid = nodeids[i]; |
177 | for (j = 0; j < cores; j++) | 177 | for (j = 0; j < cores; j++) |
178 | apicid_to_node[(nodeid << bits) + j] = i; | 178 | apicid_to_node[(nodeid << bits) + j] = i; |
179 | setup_node_bootmem(i, nodes[i].start, nodes[i].end); | 179 | setup_node_bootmem(i, nodes[i].start, nodes[i].end); |
180 | } | 180 | } |
181 | } | 181 | } |
182 | 182 | ||
183 | numa_init_array(); | 183 | numa_init_array(); |
184 | return 0; | 184 | return 0; |
185 | } | 185 | } |