blob: 7fde4ff7e16283e181af42197c6ba01b832edb45 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass45b5a372015-04-29 22:25:59 -06002/*
3 * Copyright (C) 2015 Google, Inc
4 *
Simon Glass45b5a372015-04-29 22:25:59 -06005 * Based on code from the coreboot file of the same name
6 */
7
8#include <common.h>
9#include <cpu.h>
10#include <dm.h>
11#include <errno.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060012#include <log.h>
Simon Glass45b5a372015-04-29 22:25:59 -060013#include <malloc.h>
Miao Yan18686592016-05-22 19:37:17 -070014#include <qfw.h>
Simon Glass45b5a372015-04-29 22:25:59 -060015#include <asm/atomic.h>
16#include <asm/cpu.h>
17#include <asm/interrupt.h>
18#include <asm/lapic.h>
Simon Glass6bcb6752016-03-11 22:07:09 -070019#include <asm/microcode.h>
Simon Glass45b5a372015-04-29 22:25:59 -060020#include <asm/mp.h>
Bin Menga2d73fd2015-06-23 12:18:50 +080021#include <asm/msr.h>
Simon Glass45b5a372015-04-29 22:25:59 -060022#include <asm/mtrr.h>
Bin Menga2d73fd2015-06-23 12:18:50 +080023#include <asm/processor.h>
Simon Glass45b5a372015-04-29 22:25:59 -060024#include <asm/sipi.h>
25#include <dm/device-internal.h>
26#include <dm/uclass-internal.h>
Miao Yande752c52016-01-07 01:32:04 -080027#include <dm/lists.h>
28#include <dm/root.h>
Simon Glassc05ed002020-05-10 11:40:11 -060029#include <linux/delay.h>
Simon Glass45b5a372015-04-29 22:25:59 -060030#include <linux/linkage.h>
31
Simon Glass8b097912015-07-31 09:31:31 -060032DECLARE_GLOBAL_DATA_PTR;
33
Bin Meng6e6f4ce2015-06-17 11:15:36 +080034/* Total CPUs include BSP */
35static int num_cpus;
36
Simon Glass45b5a372015-04-29 22:25:59 -060037/* This also needs to match the sipi.S assembly code for saved MSR encoding */
38struct saved_msr {
39 uint32_t index;
40 uint32_t lo;
41 uint32_t hi;
42} __packed;
43
44
45struct mp_flight_plan {
46 int num_records;
47 struct mp_flight_record *records;
48};
49
50static struct mp_flight_plan mp_info;
51
52struct cpu_map {
53 struct udevice *dev;
54 int apic_id;
55 int err_code;
56};
57
58static inline void barrier_wait(atomic_t *b)
59{
60 while (atomic_read(b) == 0)
61 asm("pause");
62 mfence();
63}
64
65static inline void release_barrier(atomic_t *b)
66{
67 mfence();
68 atomic_set(b, 1);
69}
70
Bin Menga2d73fd2015-06-23 12:18:50 +080071static inline void stop_this_cpu(void)
72{
73 /* Called by an AP when it is ready to halt and wait for a new task */
74 for (;;)
75 cpu_hlt();
76}
77
Simon Glass45b5a372015-04-29 22:25:59 -060078/* Returns 1 if timeout waiting for APs. 0 if target APs found */
79static int wait_for_aps(atomic_t *val, int target, int total_delay,
80 int delay_step)
81{
82 int timeout = 0;
83 int delayed = 0;
84
85 while (atomic_read(val) != target) {
86 udelay(delay_step);
87 delayed += delay_step;
88 if (delayed >= total_delay) {
89 timeout = 1;
90 break;
91 }
92 }
93
94 return timeout;
95}
96
97static void ap_do_flight_plan(struct udevice *cpu)
98{
99 int i;
100
101 for (i = 0; i < mp_info.num_records; i++) {
102 struct mp_flight_record *rec = &mp_info.records[i];
103
104 atomic_inc(&rec->cpus_entered);
105 barrier_wait(&rec->barrier);
106
107 if (rec->ap_call != NULL)
108 rec->ap_call(cpu, rec->ap_arg);
109 }
110}
111
Miao Yan24fb4902016-01-07 01:32:02 -0800112static int find_cpu_by_apic_id(int apic_id, struct udevice **devp)
Simon Glass45b5a372015-04-29 22:25:59 -0600113{
114 struct udevice *dev;
115
116 *devp = NULL;
117 for (uclass_find_first_device(UCLASS_CPU, &dev);
118 dev;
119 uclass_find_next_device(&dev)) {
120 struct cpu_platdata *plat = dev_get_parent_platdata(dev);
121
122 if (plat->cpu_id == apic_id) {
123 *devp = dev;
124 return 0;
125 }
126 }
127
128 return -ENOENT;
129}
130
131/*
132 * By the time APs call ap_init() caching has been setup, and microcode has
133 * been loaded
134 */
135static void ap_init(unsigned int cpu_index)
136{
137 struct udevice *dev;
138 int apic_id;
139 int ret;
140
141 /* Ensure the local apic is enabled */
142 enable_lapic();
143
144 apic_id = lapicid();
Miao Yan24fb4902016-01-07 01:32:02 -0800145 ret = find_cpu_by_apic_id(apic_id, &dev);
Simon Glass45b5a372015-04-29 22:25:59 -0600146 if (ret) {
147 debug("Unknown CPU apic_id %x\n", apic_id);
148 goto done;
149 }
150
151 debug("AP: slot %d apic_id %x, dev %s\n", cpu_index, apic_id,
152 dev ? dev->name : "(apic_id not found)");
153
154 /* Walk the flight plan */
155 ap_do_flight_plan(dev);
156
157 /* Park the AP */
158 debug("parking\n");
159done:
160 stop_this_cpu();
161}
162
163static const unsigned int fixed_mtrrs[NUM_FIXED_MTRRS] = {
164 MTRR_FIX_64K_00000_MSR, MTRR_FIX_16K_80000_MSR, MTRR_FIX_16K_A0000_MSR,
165 MTRR_FIX_4K_C0000_MSR, MTRR_FIX_4K_C8000_MSR, MTRR_FIX_4K_D0000_MSR,
166 MTRR_FIX_4K_D8000_MSR, MTRR_FIX_4K_E0000_MSR, MTRR_FIX_4K_E8000_MSR,
167 MTRR_FIX_4K_F0000_MSR, MTRR_FIX_4K_F8000_MSR,
168};
169
170static inline struct saved_msr *save_msr(int index, struct saved_msr *entry)
171{
172 msr_t msr;
173
174 msr = msr_read(index);
175 entry->index = index;
176 entry->lo = msr.lo;
177 entry->hi = msr.hi;
178
179 /* Return the next entry */
180 entry++;
181 return entry;
182}
183
184static int save_bsp_msrs(char *start, int size)
185{
186 int msr_count;
187 int num_var_mtrrs;
188 struct saved_msr *msr_entry;
189 int i;
190 msr_t msr;
191
192 /* Determine number of MTRRs need to be saved */
193 msr = msr_read(MTRR_CAP_MSR);
194 num_var_mtrrs = msr.lo & 0xff;
195
196 /* 2 * num_var_mtrrs for base and mask. +1 for IA32_MTRR_DEF_TYPE */
197 msr_count = 2 * num_var_mtrrs + NUM_FIXED_MTRRS + 1;
198
199 if ((msr_count * sizeof(struct saved_msr)) > size) {
Simon Glass2254e342016-03-06 19:28:22 -0700200 printf("Cannot mirror all %d msrs\n", msr_count);
Simon Glass45b5a372015-04-29 22:25:59 -0600201 return -ENOSPC;
202 }
203
204 msr_entry = (void *)start;
205 for (i = 0; i < NUM_FIXED_MTRRS; i++)
206 msr_entry = save_msr(fixed_mtrrs[i], msr_entry);
207
208 for (i = 0; i < num_var_mtrrs; i++) {
209 msr_entry = save_msr(MTRR_PHYS_BASE_MSR(i), msr_entry);
210 msr_entry = save_msr(MTRR_PHYS_MASK_MSR(i), msr_entry);
211 }
212
213 msr_entry = save_msr(MTRR_DEF_TYPE_MSR, msr_entry);
214
215 return msr_count;
216}
217
Miao Yanb28cecd2016-01-07 01:32:03 -0800218static int load_sipi_vector(atomic_t **ap_countp, int num_cpus)
Simon Glass45b5a372015-04-29 22:25:59 -0600219{
220 struct sipi_params_16bit *params16;
221 struct sipi_params *params;
222 static char msr_save[512];
223 char *stack;
224 ulong addr;
225 int code_len;
226 int size;
227 int ret;
228
229 /* Copy in the code */
230 code_len = ap_start16_code_end - ap_start16;
231 debug("Copying SIPI code to %x: %d bytes\n", AP_DEFAULT_BASE,
232 code_len);
233 memcpy((void *)AP_DEFAULT_BASE, ap_start16, code_len);
234
235 addr = AP_DEFAULT_BASE + (ulong)sipi_params_16bit - (ulong)ap_start16;
236 params16 = (struct sipi_params_16bit *)addr;
237 params16->ap_start = (uint32_t)ap_start;
238 params16->gdt = (uint32_t)gd->arch.gdt;
239 params16->gdt_limit = X86_GDT_SIZE - 1;
240 debug("gdt = %x, gdt_limit = %x\n", params16->gdt, params16->gdt_limit);
241
242 params = (struct sipi_params *)sipi_params;
243 debug("SIPI 32-bit params at %p\n", params);
244 params->idt_ptr = (uint32_t)x86_get_idt();
245
246 params->stack_size = CONFIG_AP_STACK_SIZE;
Miao Yanb28cecd2016-01-07 01:32:03 -0800247 size = params->stack_size * num_cpus;
Stephen Warren4fd64d02016-02-12 14:27:56 -0700248 stack = memalign(4096, size);
Simon Glass45b5a372015-04-29 22:25:59 -0600249 if (!stack)
250 return -ENOMEM;
251 params->stack_top = (u32)(stack + size);
Andy Shevchenko308c75e2017-02-17 16:49:00 +0300252#if !defined(CONFIG_QEMU) && !defined(CONFIG_HAVE_FSP) && \
253 !defined(CONFIG_INTEL_MID)
Simon Glasse77b62e2016-03-11 22:07:11 -0700254 params->microcode_ptr = ucode_base;
255 debug("Microcode at %x\n", params->microcode_ptr);
256#endif
Simon Glass45b5a372015-04-29 22:25:59 -0600257 params->msr_table_ptr = (u32)msr_save;
258 ret = save_bsp_msrs(msr_save, sizeof(msr_save));
259 if (ret < 0)
260 return ret;
261 params->msr_count = ret;
262
263 params->c_handler = (uint32_t)&ap_init;
264
265 *ap_countp = &params->ap_count;
266 atomic_set(*ap_countp, 0);
267 debug("SIPI vector is ready\n");
268
269 return 0;
270}
271
272static int check_cpu_devices(int expected_cpus)
273{
274 int i;
275
276 for (i = 0; i < expected_cpus; i++) {
277 struct udevice *dev;
278 int ret;
279
280 ret = uclass_find_device(UCLASS_CPU, i, &dev);
281 if (ret) {
282 debug("Cannot find CPU %d in device tree\n", i);
283 return ret;
284 }
285 }
286
287 return 0;
288}
289
290/* Returns 1 for timeout. 0 on success */
Simon Glass2254e342016-03-06 19:28:22 -0700291static int apic_wait_timeout(int total_delay, const char *msg)
Simon Glass45b5a372015-04-29 22:25:59 -0600292{
293 int total = 0;
Simon Glass45b5a372015-04-29 22:25:59 -0600294
Simon Glass2254e342016-03-06 19:28:22 -0700295 if (!(lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY))
296 return 0;
297
298 debug("Waiting for %s...", msg);
Simon Glass45b5a372015-04-29 22:25:59 -0600299 while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY) {
Simon Glass2254e342016-03-06 19:28:22 -0700300 udelay(50);
301 total += 50;
Simon Glass45b5a372015-04-29 22:25:59 -0600302 if (total >= total_delay) {
Simon Glass2254e342016-03-06 19:28:22 -0700303 debug("timed out: aborting\n");
304 return -ETIMEDOUT;
Simon Glass45b5a372015-04-29 22:25:59 -0600305 }
306 }
Simon Glass2254e342016-03-06 19:28:22 -0700307 debug("done\n");
Simon Glass45b5a372015-04-29 22:25:59 -0600308
Simon Glass2254e342016-03-06 19:28:22 -0700309 return 0;
Simon Glass45b5a372015-04-29 22:25:59 -0600310}
311
312static int start_aps(int ap_count, atomic_t *num_aps)
313{
314 int sipi_vector;
315 /* Max location is 4KiB below 1MiB */
316 const int max_vector_loc = ((1 << 20) - (1 << 12)) >> 12;
317
318 if (ap_count == 0)
319 return 0;
320
321 /* The vector is sent as a 4k aligned address in one byte */
322 sipi_vector = AP_DEFAULT_BASE >> 12;
323
324 if (sipi_vector > max_vector_loc) {
325 printf("SIPI vector too large! 0x%08x\n",
326 sipi_vector);
Simon Glass7b140232019-04-25 21:58:41 -0600327 return -ENOSPC;
Simon Glass45b5a372015-04-29 22:25:59 -0600328 }
329
330 debug("Attempting to start %d APs\n", ap_count);
331
Simon Glass2254e342016-03-06 19:28:22 -0700332 if (apic_wait_timeout(1000, "ICR not to be busy"))
333 return -ETIMEDOUT;
Simon Glass45b5a372015-04-29 22:25:59 -0600334
335 /* Send INIT IPI to all but self */
Bin Menga2d73fd2015-06-23 12:18:50 +0800336 lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
337 lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
338 LAPIC_DM_INIT);
Simon Glass2254e342016-03-06 19:28:22 -0700339 debug("Waiting for 10ms after sending INIT\n");
Simon Glass45b5a372015-04-29 22:25:59 -0600340 mdelay(10);
341
342 /* Send 1st SIPI */
Simon Glass2254e342016-03-06 19:28:22 -0700343 if (apic_wait_timeout(1000, "ICR not to be busy"))
344 return -ETIMEDOUT;
Simon Glass45b5a372015-04-29 22:25:59 -0600345
Bin Menga2d73fd2015-06-23 12:18:50 +0800346 lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
347 lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
348 LAPIC_DM_STARTUP | sipi_vector);
Simon Glass2254e342016-03-06 19:28:22 -0700349 if (apic_wait_timeout(10000, "first SIPI to complete"))
350 return -ETIMEDOUT;
Simon Glass45b5a372015-04-29 22:25:59 -0600351
352 /* Wait for CPUs to check in up to 200 us */
353 wait_for_aps(num_aps, ap_count, 200, 15);
354
355 /* Send 2nd SIPI */
Simon Glass2254e342016-03-06 19:28:22 -0700356 if (apic_wait_timeout(1000, "ICR not to be busy"))
357 return -ETIMEDOUT;
Simon Glass45b5a372015-04-29 22:25:59 -0600358
Bin Menga2d73fd2015-06-23 12:18:50 +0800359 lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
360 lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
361 LAPIC_DM_STARTUP | sipi_vector);
Simon Glass2254e342016-03-06 19:28:22 -0700362 if (apic_wait_timeout(10000, "second SIPI to complete"))
363 return -ETIMEDOUT;
Simon Glass45b5a372015-04-29 22:25:59 -0600364
365 /* Wait for CPUs to check in */
366 if (wait_for_aps(num_aps, ap_count, 10000, 50)) {
Simon Glass2254e342016-03-06 19:28:22 -0700367 debug("Not all APs checked in: %d/%d\n",
Simon Glass45b5a372015-04-29 22:25:59 -0600368 atomic_read(num_aps), ap_count);
Simon Glass7b140232019-04-25 21:58:41 -0600369 return -EIO;
Simon Glass45b5a372015-04-29 22:25:59 -0600370 }
371
372 return 0;
373}
374
375static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params)
376{
377 int i;
378 int ret = 0;
379 const int timeout_us = 100000;
380 const int step_us = 100;
Bin Meng6e6f4ce2015-06-17 11:15:36 +0800381 int num_aps = num_cpus - 1;
Simon Glass45b5a372015-04-29 22:25:59 -0600382
383 for (i = 0; i < mp_params->num_records; i++) {
384 struct mp_flight_record *rec = &mp_params->flight_plan[i];
385
386 /* Wait for APs if the record is not released */
387 if (atomic_read(&rec->barrier) == 0) {
388 /* Wait for the APs to check in */
389 if (wait_for_aps(&rec->cpus_entered, num_aps,
390 timeout_us, step_us)) {
Simon Glass2254e342016-03-06 19:28:22 -0700391 debug("MP record %d timeout\n", i);
Simon Glass7b140232019-04-25 21:58:41 -0600392 ret = -ETIMEDOUT;
Simon Glass45b5a372015-04-29 22:25:59 -0600393 }
394 }
395
396 if (rec->bsp_call != NULL)
397 rec->bsp_call(cpu, rec->bsp_arg);
398
399 release_barrier(&rec->barrier);
400 }
401 return ret;
402}
403
404static int init_bsp(struct udevice **devp)
405{
406 char processor_name[CPU_MAX_NAME_LEN];
407 int apic_id;
408 int ret;
409
410 cpu_get_name(processor_name);
Simon Glass2254e342016-03-06 19:28:22 -0700411 debug("CPU: %s\n", processor_name);
Simon Glass45b5a372015-04-29 22:25:59 -0600412
Simon Glass45b5a372015-04-29 22:25:59 -0600413 apic_id = lapicid();
Miao Yan24fb4902016-01-07 01:32:02 -0800414 ret = find_cpu_by_apic_id(apic_id, devp);
Simon Glass45b5a372015-04-29 22:25:59 -0600415 if (ret) {
416 printf("Cannot find boot CPU, APIC ID %d\n", apic_id);
417 return ret;
418 }
419
420 return 0;
421}
422
423int mp_init(struct mp_params *p)
424{
425 int num_aps;
426 atomic_t *ap_count;
427 struct udevice *cpu;
428 int ret;
429
430 /* This will cause the CPUs devices to be bound */
431 struct uclass *uc;
432 ret = uclass_get(UCLASS_CPU, &uc);
433 if (ret)
434 return ret;
435
Simon Glassbaaeb922019-12-06 21:42:55 -0700436 if (IS_ENABLED(CONFIG_QFW)) {
437 ret = qemu_cpu_fixup();
438 if (ret)
439 return ret;
440 }
Miao Yande752c52016-01-07 01:32:04 -0800441
Simon Glass45b5a372015-04-29 22:25:59 -0600442 ret = init_bsp(&cpu);
443 if (ret) {
444 debug("Cannot init boot CPU: err=%d\n", ret);
445 return ret;
446 }
447
448 if (p == NULL || p->flight_plan == NULL || p->num_records < 1) {
449 printf("Invalid MP parameters\n");
Simon Glass7b140232019-04-25 21:58:41 -0600450 return -EINVAL;
Simon Glass45b5a372015-04-29 22:25:59 -0600451 }
452
Bin Meng6e6f4ce2015-06-17 11:15:36 +0800453 num_cpus = cpu_get_count(cpu);
454 if (num_cpus < 0) {
455 debug("Cannot get number of CPUs: err=%d\n", num_cpus);
456 return num_cpus;
457 }
458
459 if (num_cpus < 2)
460 debug("Warning: Only 1 CPU is detected\n");
461
462 ret = check_cpu_devices(num_cpus);
Simon Glass45b5a372015-04-29 22:25:59 -0600463 if (ret)
464 debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n");
465
466 /* Copy needed parameters so that APs have a reference to the plan */
467 mp_info.num_records = p->num_records;
468 mp_info.records = p->flight_plan;
469
470 /* Load the SIPI vector */
Miao Yanb28cecd2016-01-07 01:32:03 -0800471 ret = load_sipi_vector(&ap_count, num_cpus);
Simon Glass45b5a372015-04-29 22:25:59 -0600472 if (ap_count == NULL)
Simon Glass7b140232019-04-25 21:58:41 -0600473 return -ENOENT;
Simon Glass45b5a372015-04-29 22:25:59 -0600474
475 /*
476 * Make sure SIPI data hits RAM so the APs that come up will see
477 * the startup code even if the caches are disabled
478 */
479 wbinvd();
480
481 /* Start the APs providing number of APs and the cpus_entered field */
Bin Meng6e6f4ce2015-06-17 11:15:36 +0800482 num_aps = num_cpus - 1;
Simon Glass45b5a372015-04-29 22:25:59 -0600483 ret = start_aps(num_aps, ap_count);
484 if (ret) {
485 mdelay(1000);
486 debug("%d/%d eventually checked in?\n", atomic_read(ap_count),
487 num_aps);
488 return ret;
489 }
490
491 /* Walk the flight plan for the BSP */
492 ret = bsp_do_flight_plan(cpu, p);
493 if (ret) {
494 debug("CPU init failed: err=%d\n", ret);
495 return ret;
496 }
497
498 return 0;
499}
500
501int mp_init_cpu(struct udevice *cpu, void *unused)
502{
Simon Glass6bcb6752016-03-11 22:07:09 -0700503 struct cpu_platdata *plat = dev_get_parent_platdata(cpu);
504
Bin Mengecfeada2015-08-09 23:58:39 -0700505 /*
506 * Multiple APs are brought up simultaneously and they may get the same
507 * seq num in the uclass_resolve_seq() during device_probe(). To avoid
508 * this, set req_seq to the reg number in the device tree in advance.
509 */
Simon Glasse160f7d2017-01-17 16:52:55 -0700510 cpu->req_seq = fdtdec_get_int(gd->fdt_blob, dev_of_offset(cpu), "reg",
511 -1);
Simon Glass6bcb6752016-03-11 22:07:09 -0700512 plat->ucode_version = microcode_read_rev();
513 plat->device_id = gd->arch.x86_device;
Bin Mengecfeada2015-08-09 23:58:39 -0700514
Simon Glass45b5a372015-04-29 22:25:59 -0600515 return device_probe(cpu);
516}