xref: /aosp_15_r20/external/coreboot/src/drivers/intel/fsp2_0/ppi/mp_service_ppi.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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, &params,
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 			      &params, 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, &params,
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