1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public |
3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. |
5 | * |
6 | * Numascale NumaConnect-Specific APIC Code |
7 | * |
8 | * Copyright (C) 2011 Numascale AS. All rights reserved. |
9 | * |
10 | * Send feedback to <support@numascale.com> |
11 | * |
12 | */ |
13 | #include <linux/types.h> |
14 | #include <linux/init.h> |
15 | #include <linux/pgtable.h> |
16 | |
17 | #include <asm/numachip/numachip.h> |
18 | #include <asm/numachip/numachip_csr.h> |
19 | |
20 | |
21 | #include "local.h" |
22 | |
23 | u8 numachip_system __read_mostly; |
24 | static const struct apic apic_numachip1; |
25 | static const struct apic apic_numachip2; |
26 | static void (*numachip_apic_icr_write)(int apicid, unsigned int val) __read_mostly; |
27 | |
28 | static u32 numachip1_get_apic_id(u32 x) |
29 | { |
30 | unsigned long value; |
31 | unsigned int id = (x >> 24) & 0xff; |
32 | |
33 | if (static_cpu_has(X86_FEATURE_NODEID_MSR)) { |
34 | rdmsrl(MSR_FAM10H_NODE_ID, value); |
35 | id |= (value << 2) & 0xff00; |
36 | } |
37 | |
38 | return id; |
39 | } |
40 | |
41 | static u32 numachip1_set_apic_id(u32 id) |
42 | { |
43 | return (id & 0xff) << 24; |
44 | } |
45 | |
46 | static u32 numachip2_get_apic_id(u32 x) |
47 | { |
48 | u64 mcfg; |
49 | |
50 | rdmsrl(MSR_FAM10H_MMIO_CONF_BASE, mcfg); |
51 | return ((mcfg >> (28 - 8)) & 0xfff00) | (x >> 24); |
52 | } |
53 | |
54 | static u32 numachip2_set_apic_id(u32 id) |
55 | { |
56 | return id << 24; |
57 | } |
58 | |
59 | static u32 numachip_phys_pkg_id(u32 initial_apic_id, int index_msb) |
60 | { |
61 | return initial_apic_id >> index_msb; |
62 | } |
63 | |
64 | static void numachip1_apic_icr_write(int apicid, unsigned int val) |
65 | { |
66 | write_lcsr(CSR_G3_EXT_IRQ_GEN, val: (apicid << 16) | val); |
67 | } |
68 | |
69 | static void numachip2_apic_icr_write(int apicid, unsigned int val) |
70 | { |
71 | numachip2_write32_lcsr(NUMACHIP2_APIC_ICR, val: (apicid << 12) | val); |
72 | } |
73 | |
74 | static int numachip_wakeup_secondary(u32 phys_apicid, unsigned long start_rip) |
75 | { |
76 | numachip_apic_icr_write(phys_apicid, APIC_DM_INIT); |
77 | numachip_apic_icr_write(phys_apicid, APIC_DM_STARTUP | |
78 | (start_rip >> 12)); |
79 | |
80 | return 0; |
81 | } |
82 | |
83 | static void numachip_send_IPI_one(int cpu, int vector) |
84 | { |
85 | int local_apicid, apicid = per_cpu(x86_cpu_to_apicid, cpu); |
86 | unsigned int dmode; |
87 | |
88 | preempt_disable(); |
89 | local_apicid = __this_cpu_read(x86_cpu_to_apicid); |
90 | |
91 | /* Send via local APIC where non-local part matches */ |
92 | if (!((apicid ^ local_apicid) >> NUMACHIP_LAPIC_BITS)) { |
93 | unsigned long flags; |
94 | |
95 | local_irq_save(flags); |
96 | __default_send_IPI_dest_field(mask: apicid, vector, |
97 | APIC_DEST_PHYSICAL); |
98 | local_irq_restore(flags); |
99 | preempt_enable(); |
100 | return; |
101 | } |
102 | preempt_enable(); |
103 | |
104 | dmode = (vector == NMI_VECTOR) ? APIC_DM_NMI : APIC_DM_FIXED; |
105 | numachip_apic_icr_write(apicid, dmode | vector); |
106 | } |
107 | |
108 | static void numachip_send_IPI_mask(const struct cpumask *mask, int vector) |
109 | { |
110 | unsigned int cpu; |
111 | |
112 | for_each_cpu(cpu, mask) |
113 | numachip_send_IPI_one(cpu, vector); |
114 | } |
115 | |
116 | static void numachip_send_IPI_mask_allbutself(const struct cpumask *mask, |
117 | int vector) |
118 | { |
119 | unsigned int this_cpu = smp_processor_id(); |
120 | unsigned int cpu; |
121 | |
122 | for_each_cpu(cpu, mask) { |
123 | if (cpu != this_cpu) |
124 | numachip_send_IPI_one(cpu, vector); |
125 | } |
126 | } |
127 | |
128 | static void numachip_send_IPI_allbutself(int vector) |
129 | { |
130 | unsigned int this_cpu = smp_processor_id(); |
131 | unsigned int cpu; |
132 | |
133 | for_each_online_cpu(cpu) { |
134 | if (cpu != this_cpu) |
135 | numachip_send_IPI_one(cpu, vector); |
136 | } |
137 | } |
138 | |
139 | static void numachip_send_IPI_all(int vector) |
140 | { |
141 | numachip_send_IPI_mask(cpu_online_mask, vector); |
142 | } |
143 | |
144 | static void numachip_send_IPI_self(int vector) |
145 | { |
146 | apic_write(APIC_SELF_IPI, val: vector); |
147 | } |
148 | |
149 | static int __init numachip1_probe(void) |
150 | { |
151 | return apic == &apic_numachip1; |
152 | } |
153 | |
154 | static int __init numachip2_probe(void) |
155 | { |
156 | return apic == &apic_numachip2; |
157 | } |
158 | |
159 | static void fixup_cpu_id(struct cpuinfo_x86 *c, int node) |
160 | { |
161 | u64 val; |
162 | u32 nodes = 1; |
163 | |
164 | c->topo.llc_id = node; |
165 | |
166 | /* Account for nodes per socket in multi-core-module processors */ |
167 | if (boot_cpu_has(X86_FEATURE_NODEID_MSR)) { |
168 | rdmsrl(MSR_FAM10H_NODE_ID, val); |
169 | nodes = ((val >> 3) & 7) + 1; |
170 | } |
171 | |
172 | c->topo.pkg_id = node / nodes; |
173 | } |
174 | |
175 | static int __init numachip_system_init(void) |
176 | { |
177 | /* Map the LCSR area and set up the apic_icr_write function */ |
178 | switch (numachip_system) { |
179 | case 1: |
180 | init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE); |
181 | numachip_apic_icr_write = numachip1_apic_icr_write; |
182 | break; |
183 | case 2: |
184 | init_extra_mapping_uc(NUMACHIP2_LCSR_BASE, NUMACHIP2_LCSR_SIZE); |
185 | numachip_apic_icr_write = numachip2_apic_icr_write; |
186 | break; |
187 | default: |
188 | return 0; |
189 | } |
190 | |
191 | x86_cpuinit.fixup_cpu_id = fixup_cpu_id; |
192 | x86_init.pci.arch_init = pci_numachip_init; |
193 | |
194 | return 0; |
195 | } |
196 | early_initcall(numachip_system_init); |
197 | |
198 | static int numachip1_acpi_madt_oem_check(char *oem_id, char *oem_table_id) |
199 | { |
200 | if ((strncmp(oem_id, "NUMASC" , 6) != 0) || |
201 | (strncmp(oem_table_id, "NCONNECT" , 8) != 0)) |
202 | return 0; |
203 | |
204 | numachip_system = 1; |
205 | |
206 | return 1; |
207 | } |
208 | |
209 | static int numachip2_acpi_madt_oem_check(char *oem_id, char *oem_table_id) |
210 | { |
211 | if ((strncmp(oem_id, "NUMASC" , 6) != 0) || |
212 | (strncmp(oem_table_id, "NCONECT2" , 8) != 0)) |
213 | return 0; |
214 | |
215 | numachip_system = 2; |
216 | |
217 | return 1; |
218 | } |
219 | |
220 | static const struct apic apic_numachip1 __refconst = { |
221 | .name = "NumaConnect system" , |
222 | .probe = numachip1_probe, |
223 | .acpi_madt_oem_check = numachip1_acpi_madt_oem_check, |
224 | |
225 | .delivery_mode = APIC_DELIVERY_MODE_FIXED, |
226 | .dest_mode_logical = false, |
227 | |
228 | .disable_esr = 0, |
229 | |
230 | .cpu_present_to_apicid = default_cpu_present_to_apicid, |
231 | .phys_pkg_id = numachip_phys_pkg_id, |
232 | |
233 | .max_apic_id = UINT_MAX, |
234 | .get_apic_id = numachip1_get_apic_id, |
235 | .set_apic_id = numachip1_set_apic_id, |
236 | |
237 | .calc_dest_apicid = apic_default_calc_apicid, |
238 | |
239 | .send_IPI = numachip_send_IPI_one, |
240 | .send_IPI_mask = numachip_send_IPI_mask, |
241 | .send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself, |
242 | .send_IPI_allbutself = numachip_send_IPI_allbutself, |
243 | .send_IPI_all = numachip_send_IPI_all, |
244 | .send_IPI_self = numachip_send_IPI_self, |
245 | |
246 | .wakeup_secondary_cpu = numachip_wakeup_secondary, |
247 | |
248 | .read = native_apic_mem_read, |
249 | .write = native_apic_mem_write, |
250 | .eoi = native_apic_mem_eoi, |
251 | .icr_read = native_apic_icr_read, |
252 | .icr_write = native_apic_icr_write, |
253 | }; |
254 | |
255 | apic_driver(apic_numachip1); |
256 | |
257 | static const struct apic apic_numachip2 __refconst = { |
258 | .name = "NumaConnect2 system" , |
259 | .probe = numachip2_probe, |
260 | .acpi_madt_oem_check = numachip2_acpi_madt_oem_check, |
261 | |
262 | .delivery_mode = APIC_DELIVERY_MODE_FIXED, |
263 | .dest_mode_logical = false, |
264 | |
265 | .disable_esr = 0, |
266 | |
267 | .cpu_present_to_apicid = default_cpu_present_to_apicid, |
268 | .phys_pkg_id = numachip_phys_pkg_id, |
269 | |
270 | .max_apic_id = UINT_MAX, |
271 | .get_apic_id = numachip2_get_apic_id, |
272 | .set_apic_id = numachip2_set_apic_id, |
273 | |
274 | .calc_dest_apicid = apic_default_calc_apicid, |
275 | |
276 | .send_IPI = numachip_send_IPI_one, |
277 | .send_IPI_mask = numachip_send_IPI_mask, |
278 | .send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself, |
279 | .send_IPI_allbutself = numachip_send_IPI_allbutself, |
280 | .send_IPI_all = numachip_send_IPI_all, |
281 | .send_IPI_self = numachip_send_IPI_self, |
282 | |
283 | .wakeup_secondary_cpu = numachip_wakeup_secondary, |
284 | |
285 | .read = native_apic_mem_read, |
286 | .write = native_apic_mem_write, |
287 | .eoi = native_apic_mem_eoi, |
288 | .icr_read = native_apic_icr_read, |
289 | .icr_write = native_apic_icr_write, |
290 | }; |
291 | |
292 | apic_driver(apic_numachip2); |
293 | |