Blame view

arch/x86/mm/amdtopology.c 4.28 KB
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
1
  /*
eec1d4fa0   Hans Rosenfeld   x86, amd-nb: Comp...
2
   * AMD NUMA support.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   * Discover the memory map and associated nodes.
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
4
   *
eec1d4fa0   Hans Rosenfeld   x86, amd-nb: Comp...
5
   * This version reads it directly from the AMD northbridge.
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
6
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
   * Copyright 2002,2003 Andi Kleen, SuSE Labs.
   */
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/string.h>
  #include <linux/module.h>
  #include <linux/nodemask.h>
a9ce6bc15   Yinghai Lu   x86, memblock: Re...
14
  #include <linux/memblock.h>
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
15
  #include <linux/bootmem.h>
a9ce6bc15   Yinghai Lu   x86, memblock: Re...
16

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <asm/io.h>
  #include <linux/pci_ids.h>
cbf9bd603   Yinghai Lu   acpi: get boot_cp...
19
  #include <linux/acpi.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
  #include <asm/types.h>
  #include <asm/mmzone.h>
  #include <asm/proto.h>
  #include <asm/e820.h>
  #include <asm/pci-direct.h>
  #include <asm/numa.h>
cbf9bd603   Yinghai Lu   acpi: get boot_cp...
26
27
  #include <asm/mpspec.h>
  #include <asm/apic.h>
23ac4ae82   Andreas Herrmann   x86, k8: Rename k...
28
  #include <asm/amd_nb.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

f51bf3073   David Rientjes   x86, numa: Fake a...
30
  static unsigned char __initdata nodeids[8];
8ee2debce   David Rientjes   x86: Export k8 ph...
31

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  static __init int find_northbridge(void)
  {
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
34
  	int num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
36
  	for (num = 0; num < 32; num++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  		u32 header;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
38
39
  
  		header = read_pci_config(0, num, 0, 0x00);
bb4a1d644   Joachim Deguara   x86: add PCI IDs ...
40
41
42
  		if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)) &&
  			header != (PCI_VENDOR_ID_AMD | (0x1200<<16)) &&
  			header != (PCI_VENDOR_ID_AMD | (0x1300<<16)))
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
43
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
45
  		header = read_pci_config(0, num, 1, 0x00);
bb4a1d644   Joachim Deguara   x86: add PCI IDs ...
46
47
48
  		if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)) &&
  			header != (PCI_VENDOR_ID_AMD | (0x1201<<16)) &&
  			header != (PCI_VENDOR_ID_AMD | (0x1301<<16)))
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
49
50
51
  			continue;
  		return num;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
53
  	return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  }
cbf9bd603   Yinghai Lu   acpi: get boot_cp...
55
56
57
  static __init void early_get_boot_cpu_id(void)
  {
  	/*
f6e9456c9   Robert Richter   x86, cleanup: Rem...
58
  	 * need to get the APIC ID of the BSP so can use that to
eec1d4fa0   Hans Rosenfeld   x86, amd-nb: Comp...
59
  	 * create apicid_to_node in amd_scan_nodes()
cbf9bd603   Yinghai Lu   acpi: get boot_cp...
60
  	 */
a4caa18ef   Yinghai Lu   x86: fix compilin...
61
  #ifdef CONFIG_X86_MPPARSE
cbf9bd603   Yinghai Lu   acpi: get boot_cp...
62
63
64
65
66
  	/*
  	 * get boot-time SMP configuration:
  	 */
  	if (smp_found_config)
  		early_get_smp_config();
a4caa18ef   Yinghai Lu   x86: fix compilin...
67
  #endif
8ee2debce   David Rientjes   x86: Export k8 ph...
68
  }
940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
69
  int __init amd_numa_init(void)
8ee2debce   David Rientjes   x86: Export k8 ph...
70
  {
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
71
72
  	u64 start = PFN_PHYS(0);
  	u64 end = PFN_PHYS(max_pfn);
8ee2debce   David Rientjes   x86: Export k8 ph...
73
  	unsigned numnodes;
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
74
  	u64 prevbase;
45fe6c78c   Tejun Heo   x86-64, NUMA: Mov...
75
  	int i, j, nb;
d34c08958   Thomas Gleixner   x86: k8topology f...
76
  	u32 nodeid, reg;
45fe6c78c   Tejun Heo   x86-64, NUMA: Mov...
77
  	unsigned int bits, cores, apicid_base;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

0637a70a5   Andi Kleen   [PATCH] x86: Allo...
79
  	if (!early_pci_allowed())
940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
80
  		return -EINVAL;
0637a70a5   Andi Kleen   [PATCH] x86: Allo...
81

3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
82
83
  	nb = find_northbridge();
  	if (nb < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  		return nb;
1af5ba514   David Rientjes   x86: Clean up and...
85
86
  	pr_info("Scanning NUMA topology in Northbridge %d
  ", nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87

3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
88
  	reg = read_pci_config(0, nb, 0, 0x60);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	numnodes = ((reg >> 4) & 0xF) + 1;
3bea9c979   Andi Kleen   [PATCH] x86-64: D...
90
  	if (numnodes <= 1)
940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
91
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

8ee2debce   David Rientjes   x86: Export k8 ph...
93
94
  	pr_info("Number of physical nodes %d
  ", numnodes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  	prevbase = 0;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
97
  	for (i = 0; i < 8; i++) {
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
98
  		u64 base, limit;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
99

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  		base = read_pci_config(0, nb, 1, 0x40 + i*8);
  		limit = read_pci_config(0, nb, 1, 0x44 + i*8);
f51bf3073   David Rientjes   x86, numa: Fake a...
102
  		nodeids[i] = nodeid = limit & 7;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
103
  		if ((base & 3) == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  			if (i < numnodes)
1af5ba514   David Rientjes   x86: Clean up and...
105
106
  				pr_info("Skipping disabled node %d
  ", i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  			continue;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
108
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  		if (nodeid >= numnodes) {
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
110
111
  			pr_info("Ignoring excess node %d (%Lx:%Lx)
  ", nodeid,
1af5ba514   David Rientjes   x86: Clean up and...
112
  				base, limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  			continue;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
114
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115

3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
116
  		if (!limit) {
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
117
118
  			pr_info("Skipping node entry %d (base %Lx)
  ",
1af5ba514   David Rientjes   x86: Clean up and...
119
  				i, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  			continue;
  		}
  		if ((base >> 8) & 3 || (limit >> 8) & 3) {
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
123
124
  			pr_err("Node %d using interleaving mode %Lx/%Lx
  ",
1af5ba514   David Rientjes   x86: Clean up and...
125
  			       nodeid, (base >> 8) & 3, (limit >> 8) & 3);
940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
126
  			return -EINVAL;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
127
  		}
4697bdcc9   Tejun Heo   x86-64, NUMA: Kil...
128
  		if (node_isset(nodeid, numa_nodes_parsed)) {
1af5ba514   David Rientjes   x86: Clean up and...
129
130
131
  			pr_info("Node %d already present, skipping
  ",
  				nodeid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
  			continue;
  		}
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
134
135
  		limit >>= 16;
  		limit <<= 24;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  		limit |= (1<<24)-1;
ffd10a2b7   Magnus Damm   [PATCH] x86_64: M...
137
  		limit++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138

8ee2debce   David Rientjes   x86: Export k8 ph...
139
140
  		if (limit > end)
  			limit = end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  		if (limit <= base)
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
142
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  		base >>= 16;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
144
145
146
147
148
149
150
  		base <<= 24;
  
  		if (base < start)
  			base = start;
  		if (limit > end)
  			limit = end;
  		if (limit == base) {
1af5ba514   David Rientjes   x86: Clean up and...
151
152
  			pr_err("Empty node %d
  ", nodeid);
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
153
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  		}
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
155
  		if (limit < base) {
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
156
157
  			pr_err("Node %d bogus settings %Lx-%Lx.
  ",
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
158
  			       nodeid, base, limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  			continue;
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
160
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  		/* Could sort here, but pun for now. Should not happen anyroads. */
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
162
  		if (prevbase > base) {
2706a0bf7   Tejun Heo   x86, NUMA: Enable...
163
164
  			pr_err("Node map not sorted %Lx,%Lx
  ",
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
165
  			       prevbase, base);
940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
166
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  		}
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
168

2706a0bf7   Tejun Heo   x86, NUMA: Enable...
169
170
  		pr_info("Node %d MemBase %016Lx Limit %016Lx
  ",
1af5ba514   David Rientjes   x86: Clean up and...
171
  			nodeid, base, limit);
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
172

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  		prevbase = base;
91556237e   Tejun Heo   x86-64, NUMA: Kil...
174
  		numa_add_memblk(nodeid, base, limit);
92d4a4371   Tejun Heo   x86-64, NUMA: Ren...
175
  		node_set(nodeid, numa_nodes_parsed);
3aa88cdf6   Carlos R. Mafra   x86: clean up k8t...
176
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

4697bdcc9   Tejun Heo   x86-64, NUMA: Kil...
178
  	if (!nodes_weight(numa_nodes_parsed))
940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
179
  		return -ENOENT;
45fe6c78c   Tejun Heo   x86-64, NUMA: Mov...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  
  	/*
  	 * We seem to have valid NUMA configuration.  Map apicids to nodes
  	 * using the coreid bits from early_identify_cpu.
  	 */
  	bits = boot_cpu_data.x86_coreid_bits;
  	cores = 1 << bits;
  	apicid_base = 0;
  
  	/* get the APIC ID of the BSP early for systems with apicid lifting */
  	early_get_boot_cpu_id();
  	if (boot_cpu_physical_apicid > 0) {
  		pr_info("BSP APIC ID: %02x
  ", boot_cpu_physical_apicid);
  		apicid_base = boot_cpu_physical_apicid;
  	}
92d4a4371   Tejun Heo   x86-64, NUMA: Ren...
196
  	for_each_node_mask(i, numa_nodes_parsed)
45fe6c78c   Tejun Heo   x86-64, NUMA: Mov...
197
198
  		for (j = apicid_base; j < cores + apicid_base; j++)
  			set_apicid_to_node((i << bits) + j, i);
8ee2debce   David Rientjes   x86: Export k8 ph...
199
200
  	return 0;
  }