diff options
Diffstat (limited to 'arch/x86/kernel/numaq_32.c')
-rw-r--r-- | arch/x86/kernel/numaq_32.c | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/arch/x86/kernel/numaq_32.c b/arch/x86/kernel/numaq_32.c deleted file mode 100644 index f2191d4f271..00000000000 --- a/arch/x86/kernel/numaq_32.c +++ /dev/null | |||
@@ -1,293 +0,0 @@ | |||
1 | /* | ||
2 | * Written by: Patricia Gaughen, IBM Corporation | ||
3 | * | ||
4 | * Copyright (C) 2002, IBM Corp. | ||
5 | * | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
16 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | * Send feedback to <gone@us.ibm.com> | ||
24 | */ | ||
25 | |||
26 | #include <linux/mm.h> | ||
27 | #include <linux/bootmem.h> | ||
28 | #include <linux/mmzone.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/nodemask.h> | ||
31 | #include <asm/numaq.h> | ||
32 | #include <asm/topology.h> | ||
33 | #include <asm/processor.h> | ||
34 | #include <asm/genapic.h> | ||
35 | #include <asm/e820.h> | ||
36 | #include <asm/setup.h> | ||
37 | |||
38 | #define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT)) | ||
39 | |||
40 | /* | ||
41 | * Function: smp_dump_qct() | ||
42 | * | ||
43 | * Description: gets memory layout from the quad config table. This | ||
44 | * function also updates node_online_map with the nodes (quads) present. | ||
45 | */ | ||
46 | static void __init smp_dump_qct(void) | ||
47 | { | ||
48 | int node; | ||
49 | struct eachquadmem *eq; | ||
50 | struct sys_cfg_data *scd = | ||
51 | (struct sys_cfg_data *)__va(SYS_CFG_DATA_PRIV_ADDR); | ||
52 | |||
53 | nodes_clear(node_online_map); | ||
54 | for_each_node(node) { | ||
55 | if (scd->quads_present31_0 & (1 << node)) { | ||
56 | node_set_online(node); | ||
57 | eq = &scd->eq[node]; | ||
58 | /* Convert to pages */ | ||
59 | node_start_pfn[node] = MB_TO_PAGES( | ||
60 | eq->hi_shrd_mem_start - eq->priv_mem_size); | ||
61 | node_end_pfn[node] = MB_TO_PAGES( | ||
62 | eq->hi_shrd_mem_start + eq->hi_shrd_mem_size); | ||
63 | |||
64 | e820_register_active_regions(node, node_start_pfn[node], | ||
65 | node_end_pfn[node]); | ||
66 | memory_present(node, | ||
67 | node_start_pfn[node], node_end_pfn[node]); | ||
68 | node_remap_size[node] = node_memmap_size_bytes(node, | ||
69 | node_start_pfn[node], | ||
70 | node_end_pfn[node]); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | |||
76 | void __cpuinit numaq_tsc_disable(void) | ||
77 | { | ||
78 | if (!found_numaq) | ||
79 | return; | ||
80 | |||
81 | if (num_online_nodes() > 1) { | ||
82 | printk(KERN_DEBUG "NUMAQ: disabling TSC\n"); | ||
83 | setup_clear_cpu_cap(X86_FEATURE_TSC); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | static int __init numaq_pre_time_init(void) | ||
88 | { | ||
89 | numaq_tsc_disable(); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | int found_numaq; | ||
94 | /* | ||
95 | * Have to match translation table entries to main table entries by counter | ||
96 | * hence the mpc_record variable .... can't see a less disgusting way of | ||
97 | * doing this .... | ||
98 | */ | ||
99 | struct mpc_config_translation { | ||
100 | unsigned char mpc_type; | ||
101 | unsigned char trans_len; | ||
102 | unsigned char trans_type; | ||
103 | unsigned char trans_quad; | ||
104 | unsigned char trans_global; | ||
105 | unsigned char trans_local; | ||
106 | unsigned short trans_reserved; | ||
107 | }; | ||
108 | |||
109 | /* x86_quirks member */ | ||
110 | static int mpc_record; | ||
111 | static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] | ||
112 | __cpuinitdata; | ||
113 | |||
114 | static inline int generate_logical_apicid(int quad, int phys_apicid) | ||
115 | { | ||
116 | return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1); | ||
117 | } | ||
118 | |||
119 | /* x86_quirks member */ | ||
120 | static int mpc_apic_id(struct mpc_cpu *m) | ||
121 | { | ||
122 | int quad = translation_table[mpc_record]->trans_quad; | ||
123 | int logical_apicid = generate_logical_apicid(quad, m->apicid); | ||
124 | |||
125 | printk(KERN_DEBUG "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n", | ||
126 | m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8, | ||
127 | (m->cpufeature & CPU_MODEL_MASK) >> 4, | ||
128 | m->apicver, quad, logical_apicid); | ||
129 | return logical_apicid; | ||
130 | } | ||
131 | |||
132 | int mp_bus_id_to_node[MAX_MP_BUSSES]; | ||
133 | |||
134 | int mp_bus_id_to_local[MAX_MP_BUSSES]; | ||
135 | |||
136 | /* x86_quirks member */ | ||
137 | static void mpc_oem_bus_info(struct mpc_bus *m, char *name) | ||
138 | { | ||
139 | int quad = translation_table[mpc_record]->trans_quad; | ||
140 | int local = translation_table[mpc_record]->trans_local; | ||
141 | |||
142 | mp_bus_id_to_node[m->busid] = quad; | ||
143 | mp_bus_id_to_local[m->busid] = local; | ||
144 | printk(KERN_INFO "Bus #%d is %s (node %d)\n", | ||
145 | m->busid, name, quad); | ||
146 | } | ||
147 | |||
148 | int quad_local_to_mp_bus_id [NR_CPUS/4][4]; | ||
149 | |||
150 | /* x86_quirks member */ | ||
151 | static void mpc_oem_pci_bus(struct mpc_bus *m) | ||
152 | { | ||
153 | int quad = translation_table[mpc_record]->trans_quad; | ||
154 | int local = translation_table[mpc_record]->trans_local; | ||
155 | |||
156 | quad_local_to_mp_bus_id[quad][local] = m->busid; | ||
157 | } | ||
158 | |||
159 | static void __init MP_translation_info(struct mpc_config_translation *m) | ||
160 | { | ||
161 | printk(KERN_INFO | ||
162 | "Translation: record %d, type %d, quad %d, global %d, local %d\n", | ||
163 | mpc_record, m->trans_type, m->trans_quad, m->trans_global, | ||
164 | m->trans_local); | ||
165 | |||
166 | if (mpc_record >= MAX_MPC_ENTRY) | ||
167 | printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n"); | ||
168 | else | ||
169 | translation_table[mpc_record] = m; /* stash this for later */ | ||
170 | if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad)) | ||
171 | node_set_online(m->trans_quad); | ||
172 | } | ||
173 | |||
174 | static int __init mpf_checksum(unsigned char *mp, int len) | ||
175 | { | ||
176 | int sum = 0; | ||
177 | |||
178 | while (len--) | ||
179 | sum += *mp++; | ||
180 | |||
181 | return sum & 0xFF; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Read/parse the MPC oem tables | ||
186 | */ | ||
187 | |||
188 | static void __init smp_read_mpc_oem(struct mpc_oemtable *oemtable, | ||
189 | unsigned short oemsize) | ||
190 | { | ||
191 | int count = sizeof(*oemtable); /* the header size */ | ||
192 | unsigned char *oemptr = ((unsigned char *)oemtable) + count; | ||
193 | |||
194 | mpc_record = 0; | ||
195 | printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n", | ||
196 | oemtable); | ||
197 | if (memcmp(oemtable->signature, MPC_OEM_SIGNATURE, 4)) { | ||
198 | printk(KERN_WARNING | ||
199 | "SMP mpc oemtable: bad signature [%c%c%c%c]!\n", | ||
200 | oemtable->signature[0], oemtable->signature[1], | ||
201 | oemtable->signature[2], oemtable->signature[3]); | ||
202 | return; | ||
203 | } | ||
204 | if (mpf_checksum((unsigned char *)oemtable, oemtable->length)) { | ||
205 | printk(KERN_WARNING "SMP oem mptable: checksum error!\n"); | ||
206 | return; | ||
207 | } | ||
208 | while (count < oemtable->length) { | ||
209 | switch (*oemptr) { | ||
210 | case MP_TRANSLATION: | ||
211 | { | ||
212 | struct mpc_config_translation *m = | ||
213 | (struct mpc_config_translation *)oemptr; | ||
214 | MP_translation_info(m); | ||
215 | oemptr += sizeof(*m); | ||
216 | count += sizeof(*m); | ||
217 | ++mpc_record; | ||
218 | break; | ||
219 | } | ||
220 | default: | ||
221 | { | ||
222 | printk(KERN_WARNING | ||
223 | "Unrecognised OEM table entry type! - %d\n", | ||
224 | (int)*oemptr); | ||
225 | return; | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static int __init numaq_setup_ioapic_ids(void) | ||
232 | { | ||
233 | /* so can skip it */ | ||
234 | return 1; | ||
235 | } | ||
236 | |||
237 | static int __init numaq_update_genapic(void) | ||
238 | { | ||
239 | genapic->wakeup_cpu = wakeup_secondary_cpu_via_nmi; | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static struct x86_quirks numaq_x86_quirks __initdata = { | ||
245 | .arch_pre_time_init = numaq_pre_time_init, | ||
246 | .arch_time_init = NULL, | ||
247 | .arch_pre_intr_init = NULL, | ||
248 | .arch_memory_setup = NULL, | ||
249 | .arch_intr_init = NULL, | ||
250 | .arch_trap_init = NULL, | ||
251 | .mach_get_smp_config = NULL, | ||
252 | .mach_find_smp_config = NULL, | ||
253 | .mpc_record = &mpc_record, | ||
254 | .mpc_apic_id = mpc_apic_id, | ||
255 | .mpc_oem_bus_info = mpc_oem_bus_info, | ||
256 | .mpc_oem_pci_bus = mpc_oem_pci_bus, | ||
257 | .smp_read_mpc_oem = smp_read_mpc_oem, | ||
258 | .setup_ioapic_ids = numaq_setup_ioapic_ids, | ||
259 | .update_genapic = numaq_update_genapic, | ||
260 | }; | ||
261 | |||
262 | void numaq_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid) | ||
263 | { | ||
264 | if (strncmp(oem, "IBM NUMA", 8)) | ||
265 | printk("Warning! Not a NUMA-Q system!\n"); | ||
266 | else | ||
267 | found_numaq = 1; | ||
268 | } | ||
269 | |||
270 | static __init void early_check_numaq(void) | ||
271 | { | ||
272 | /* | ||
273 | * Find possible boot-time SMP configuration: | ||
274 | */ | ||
275 | early_find_smp_config(); | ||
276 | /* | ||
277 | * get boot-time SMP configuration: | ||
278 | */ | ||
279 | if (smp_found_config) | ||
280 | early_get_smp_config(); | ||
281 | |||
282 | if (found_numaq) | ||
283 | x86_quirks = &numaq_x86_quirks; | ||
284 | } | ||
285 | |||
286 | int __init get_memcfg_numaq(void) | ||
287 | { | ||
288 | early_check_numaq(); | ||
289 | if (!found_numaq) | ||
290 | return 0; | ||
291 | smp_dump_qct(); | ||
292 | return 1; | ||
293 | } | ||