blob: 7c08f7a1d5c05b28b588b595559d58037f70a87c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001/* SPDX-License-Identifier: GPL-2.0 */
Simon Glassa9a44262015-04-29 22:25:59 -06002/*
3 * Copyright (c) 2015 Google, Inc
4 *
Simon Glassa9a44262015-04-29 22:25:59 -06005 * Taken from coreboot file of the same name
6 */
7
8#ifndef _X86_MP_H_
9#define _X86_MP_H_
10
11#include <asm/atomic.h>
Simon Glass274e0b02020-05-10 11:39:56 -060012#include <asm/cache.h>
Simon Glass0b13e3c2021-06-27 17:51:02 -060013#include <linux/bitops.h>
Tom Rini412a0212024-04-27 08:10:56 -060014#include <linux/errno.h>
Simon Glassa9a44262015-04-29 22:25:59 -060015
Simon Glass3ba929a2020-10-30 21:38:53 -060016struct udevice;
17
Simon Glass4a30bbb2020-07-17 08:48:16 -060018enum {
Simon Glass0b13e3c2021-06-27 17:51:02 -060019 /*
20 * Indicates that the function should run on all CPUs. We use a large
21 * number, above the number of real CPUs we expect to find.
22 */
23 MP_SELECT_ALL = BIT(16),
Simon Glass4a30bbb2020-07-17 08:48:16 -060024
25 /* Run on boot CPUs */
Simon Glass0b13e3c2021-06-27 17:51:02 -060026 MP_SELECT_BSP,
Simon Glass4a30bbb2020-07-17 08:48:16 -060027
28 /* Run on non-boot CPUs */
Simon Glass0b13e3c2021-06-27 17:51:02 -060029 MP_SELECT_APS,
Simon Glass4a30bbb2020-07-17 08:48:16 -060030};
31
Simon Glassa9a44262015-04-29 22:25:59 -060032typedef int (*mp_callback_t)(struct udevice *cpu, void *arg);
33
34/*
35 * A mp_flight_record details a sequence of calls for the APs to perform
36 * along with the BSP to coordinate sequencing. Each flight record either
37 * provides a barrier for each AP before calling the callback or the APs
38 * are allowed to perform the callback without waiting. Regardless, each
39 * record has the cpus_entered field incremented for each record. When
40 * the BSP observes that the cpus_entered matches the number of APs
41 * the bsp_call is called with bsp_arg and upon returning releases the
42 * barrier allowing the APs to make further progress.
43 *
44 * Note that ap_call() and bsp_call() can be NULL. In the NULL case the
45 * callback will just not be called.
Simon Glass00906cb2020-07-17 08:48:30 -060046 *
47 * @barrier: Ensures that the BSP and AP don't run the flight record at the same
48 * time
49 * @cpus_entered: Counts the number of APs that have run this record
50 * @ap_call: Function for the APs to call
51 * @ap_arg: Argument to pass to @ap_call
52 * @bsp_call: Function for the BSP to call
53 * @bsp_arg: Argument to pass to @bsp_call
Simon Glassa9a44262015-04-29 22:25:59 -060054 */
55struct mp_flight_record {
56 atomic_t barrier;
57 atomic_t cpus_entered;
58 mp_callback_t ap_call;
59 void *ap_arg;
60 mp_callback_t bsp_call;
61 void *bsp_arg;
62} __attribute__((aligned(ARCH_DMA_MINALIGN)));
63
64#define MP_FLIGHT_RECORD(barrier_, ap_func_, ap_arg_, bsp_func_, bsp_arg_) \
65 { \
66 .barrier = ATOMIC_INIT(barrier_), \
67 .cpus_entered = ATOMIC_INIT(0), \
68 .ap_call = ap_func_, \
69 .ap_arg = ap_arg_, \
70 .bsp_call = bsp_func_, \
71 .bsp_arg = bsp_arg_, \
72 }
73
74#define MP_FR_BLOCK_APS(ap_func, ap_arg, bsp_func, bsp_arg) \
75 MP_FLIGHT_RECORD(0, ap_func, ap_arg, bsp_func, bsp_arg)
76
77#define MP_FR_NOBLOCK_APS(ap_func, ap_arg, bsp_func, bsp_arg) \
78 MP_FLIGHT_RECORD(1, ap_func, ap_arg, bsp_func, bsp_arg)
79
80/*
Simon Glassa9a44262015-04-29 22:25:59 -060081 * mp_init() will set up the SIPI vector and bring up the APs according to
82 * mp_params. Each flight record will be executed according to the plan. Note
83 * that the MP infrastructure uses SMM default area without saving it. It's
84 * up to the chipset or mainboard to either e820 reserve this area or save this
85 * region prior to calling mp_init() and restoring it after mp_init returns.
86 *
87 * At the time mp_init() is called the MTRR MSRs are mirrored into APs then
88 * caching is enabled before running the flight plan.
89 *
90 * The MP init has the following properties:
91 * 1. APs are brought up in parallel.
92 * 2. The ordering of cpu number and APIC ids is not deterministic.
93 * Therefore, one cannot rely on this property or the order of devices in
94 * the device tree unless the chipset or mainboard know the APIC ids
95 * a priori.
96 *
97 * mp_init() returns < 0 on error, 0 on success.
98 */
Simon Glasse40633d2020-07-17 08:48:08 -060099int mp_init(void);
Simon Glassa9a44262015-04-29 22:25:59 -0600100
Simon Glass00906cb2020-07-17 08:48:30 -0600101/**
102 * x86_mp_init() - Set up additional CPUs
103 *
104 * @returns < 0 on error, 0 on success.
105 */
Simon Glass16a624b2017-01-16 07:03:57 -0700106int x86_mp_init(void);
107
Simon Glass6871dff2020-07-17 08:48:19 -0600108/**
109 * mp_run_func() - Function to call on the AP
110 *
111 * @arg: Argument to pass
112 */
113typedef void (*mp_run_func)(void *arg);
114
Simon Glassa2c515c2020-07-17 08:48:23 -0600115#if CONFIG_IS_ENABLED(SMP) && !CONFIG_IS_ENABLED(X86_64)
Simon Glass6871dff2020-07-17 08:48:19 -0600116/**
117 * mp_run_on_cpus() - Run a function on one or all CPUs
118 *
119 * This does not return until all CPUs have completed the work
120 *
121 * Running on anything other than the boot CPU is only supported if
122 * CONFIG_SMP_AP_WORK is enabled
123 *
Simon Glass6feac812020-12-16 21:20:22 -0700124 * @cpu_select: CPU to run on (its dev_seq() value), or MP_SELECT_ALL for
Simon Glass6871dff2020-07-17 08:48:19 -0600125 * all, or MP_SELECT_BSP for BSP
126 * @func: Function to run
127 * @arg: Argument to pass to the function
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100128 * Return: 0 on success, -ve on error
Simon Glass6871dff2020-07-17 08:48:19 -0600129 */
130int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg);
Simon Glass32d56952020-07-17 08:48:20 -0600131
132/**
133 * mp_park_aps() - Park the APs ready for the OS
134 *
135 * This halts all CPUs except the main one, ready for the OS to use them
136 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100137 * Return: 0 if OK, -ve on error
Simon Glass32d56952020-07-17 08:48:20 -0600138 */
139int mp_park_aps(void);
Simon Glass44344f52020-07-17 08:48:21 -0600140
141/**
142 * mp_first_cpu() - Get the first CPU to process, from a selection
143 *
144 * This is used to iterate through selected CPUs. Call this function first, then
145 * call mp_next_cpu() repeatedly (with the same @cpu_select) until it returns
146 * -EFBIG.
147 *
148 * @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...)
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100149 * Return: next CPU number to run on (e.g. 0)
Simon Glass44344f52020-07-17 08:48:21 -0600150 */
151int mp_first_cpu(int cpu_select);
152
153/**
154 * mp_next_cpu() - Get the next CPU to process, from a selection
155 *
156 * This is used to iterate through selected CPUs. After first calling
157 * mp_first_cpu() once, call this function repeatedly until it returns -EFBIG.
158 *
159 * The value of @cpu_select must be the same for all calls and must match the
160 * value passed to mp_first_cpu(), otherwise the behaviour is undefined.
161 *
162 * @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...)
163 * @prev_cpu: Previous value returned by mp_first_cpu()/mp_next_cpu()
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100164 * Return: next CPU number to run on (e.g. 0)
Simon Glass44344f52020-07-17 08:48:21 -0600165 */
166int mp_next_cpu(int cpu_select, int prev_cpu);
Simon Glass6871dff2020-07-17 08:48:19 -0600167#else
168static inline int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg)
169{
170 /* There is only one CPU, so just call the function here */
171 func(arg);
172
173 return 0;
174}
Simon Glass32d56952020-07-17 08:48:20 -0600175
176static inline int mp_park_aps(void)
177{
178 /* No APs to park */
179
180 return 0;
181}
182
Simon Glass44344f52020-07-17 08:48:21 -0600183static inline int mp_first_cpu(int cpu_select)
184{
185 /* We cannot run on any APs, nor a selected CPU */
186 return cpu_select == MP_SELECT_APS ? -EFBIG : MP_SELECT_BSP;
187}
188
189static inline int mp_next_cpu(int cpu_select, int prev_cpu)
190{
191 /*
192 * When MP is not enabled, there is only one CPU and we did it in
193 * mp_first_cpu()
194 */
195 return -EFBIG;
196}
197
Simon Glass6871dff2020-07-17 08:48:19 -0600198#endif
199
Simon Glassa9a44262015-04-29 22:25:59 -0600200#endif /* _X86_MP_H_ */