1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <console/console.h>
4 #include <cpu/cpu.h>
5 #include <cpu/x86/mp.h>
6 #include <cpu/intel/microcode.h>
7 #include <fsp/api.h>
8 #include <fsp/ppi/mp_service_ppi.h>
9 #include <intelblocks/cpulib.h>
10 #include <intelblocks/mp_init.h>
11 #include <types.h>
12
13 #define BSP_CPU_SLOT 0
14
15 struct efi_ap_procedure_caller_params {
16 efi_ap_procedure procedure;
17 void *argument;
18 };
19
efi_ap_procedure_caller(void * arg)20 static void efi_ap_procedure_caller(void *arg)
21 {
22 struct efi_ap_procedure_caller_params *params =
23 (struct efi_ap_procedure_caller_params *)arg;
24 params->procedure(params->argument);
25 }
26
mp_get_number_of_processors(efi_uintn_t * number_of_processors,efi_uintn_t * number_of_enabled_processors)27 efi_return_status_t mp_get_number_of_processors(efi_uintn_t *number_of_processors,
28 efi_uintn_t *number_of_enabled_processors)
29 {
30 if (number_of_processors == NULL || number_of_enabled_processors ==
31 NULL)
32 return FSP_INVALID_PARAMETER;
33
34 *number_of_processors = get_cpu_count();
35 *number_of_enabled_processors = get_cpu_count();
36
37 return FSP_SUCCESS;
38 }
39
mp_get_processor_info(efi_uintn_t processor_number,efi_processor_information * processor_info_buffer)40 efi_return_status_t mp_get_processor_info(efi_uintn_t processor_number,
41 efi_processor_information *processor_info_buffer)
42 {
43 if (processor_number >= MIN(get_cpu_count(), CONFIG_MAX_CPUS))
44 return FSP_NOT_FOUND;
45
46 extern struct cpu_info cpu_infos[];
47 struct cpu_info *info = &cpu_infos[processor_number];
48 if (!info)
49 return FSP_DEVICE_ERROR;
50
51 struct device *dev = info->cpu;
52
53 if (processor_info_buffer == NULL)
54 return FSP_INVALID_PARAMETER;
55
56 processor_info_buffer->StatusFlag = PROCESSOR_HEALTH_STATUS_BIT
57 | PROCESSOR_ENABLED_BIT;
58
59 if (processor_number == BSP_CPU_SLOT)
60 processor_info_buffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
61
62 processor_info_buffer->ProcessorId = dev->path.apic.apic_id;
63 processor_info_buffer->Location.Package = dev->path.apic.package_id;
64 processor_info_buffer->Location.Core = dev->path.apic.core_id;
65 processor_info_buffer->Location.Thread = dev->path.apic.thread_id;
66
67 return FSP_SUCCESS;
68 }
69
mp_startup_all_aps(efi_ap_procedure procedure,bool run_serial,efi_uintn_t timeout_usec,void * argument)70 efi_return_status_t mp_startup_all_aps(efi_ap_procedure procedure,
71 bool run_serial, efi_uintn_t timeout_usec, void *argument)
72 {
73 struct efi_ap_procedure_caller_params params = {
74 .procedure = procedure,
75 .argument = argument
76 };
77
78 if (!cpu_info())
79 return FSP_DEVICE_ERROR;
80
81 if (procedure == NULL)
82 return FSP_INVALID_PARAMETER;
83
84 if (mp_run_on_all_aps((void *)efi_ap_procedure_caller, ¶ms,
85 timeout_usec, !run_serial) != CB_SUCCESS) {
86 printk(BIOS_DEBUG, "%s: Exit with Failure\n", __func__);
87 return FSP_NOT_STARTED;
88 }
89
90 return FSP_SUCCESS;
91 }
92
mp_startup_all_cpus(efi_ap_procedure procedure,efi_uintn_t timeout_usec,void * argument)93 efi_return_status_t mp_startup_all_cpus(efi_ap_procedure procedure,
94 efi_uintn_t timeout_usec, void *argument)
95 {
96 struct efi_ap_procedure_caller_params params = {
97 .procedure = procedure,
98 .argument = argument
99 };
100
101 if (!cpu_info())
102 return FSP_DEVICE_ERROR;
103
104 if (procedure == NULL)
105 return FSP_INVALID_PARAMETER;
106
107 /* Run on BSP */
108 procedure(argument);
109
110 /*
111 * Run on APs Serially
112 *
113 * FIXME: As per MP service specification, edk2 is allowed to specify the mode
114 * in which a 'func' routine should be executed on APs (i.e. execute serially
115 * or concurrently).
116 *
117 * MP service API `StartupAllCPUs` doesn't specify such requirement.
118 * Hence, running the `CpuCacheInfoCollectCoreAndCacheData`
119 * (UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c#194)
120 * simultaneously on APs results in a coherency issue (hang while executing `func`)
121 * due to lack of acquiring a spin lock while accessing common data structure in
122 * multiprocessor environment.
123 */
124 if (mp_run_on_all_aps((void *)efi_ap_procedure_caller,
125 ¶ms, timeout_usec, false) != CB_SUCCESS) {
126 printk(BIOS_DEBUG, "%s: Exit with Failure\n", __func__);
127 return FSP_NOT_STARTED;
128 }
129
130 return FSP_SUCCESS;
131 }
132
mp_startup_this_ap(efi_ap_procedure procedure,efi_uintn_t processor_number,efi_uintn_t timeout_usec,void * argument)133 efi_return_status_t mp_startup_this_ap(efi_ap_procedure procedure,
134 efi_uintn_t processor_number, efi_uintn_t timeout_usec, void *argument)
135 {
136 struct efi_ap_procedure_caller_params params = {
137 .procedure = procedure,
138 .argument = argument
139 };
140
141 if (!cpu_info())
142 return FSP_DEVICE_ERROR;
143
144 if (processor_number > get_cpu_count())
145 return FSP_NOT_FOUND;
146
147 if (processor_number == BSP_CPU_SLOT)
148 return FSP_INVALID_PARAMETER;
149
150 if (procedure == NULL)
151 return FSP_INVALID_PARAMETER;
152
153 if (mp_run_on_aps((void *)efi_ap_procedure_caller, ¶ms,
154 processor_number, timeout_usec) != CB_SUCCESS) {
155 printk(BIOS_DEBUG, "%s: Exit with Failure\n", __func__);
156 return FSP_NOT_STARTED;
157 }
158
159 return FSP_SUCCESS;
160 }
161
mp_identify_processor(efi_uintn_t * processor_number)162 efi_return_status_t mp_identify_processor(efi_uintn_t *processor_number)
163 {
164 int index;
165
166 if (processor_number == NULL)
167 return FSP_INVALID_PARAMETER;
168
169 index = cpu_index();
170
171 if (index < 0)
172 return FSP_DEVICE_ERROR;
173
174 *processor_number = index;
175
176 return FSP_SUCCESS;
177 }
178