blob: 3cf73aedde8073ae80f26e1c970a3576ea72fc30 [file] [log] [blame]
Furquan Shaikh2af76f42014-04-28 16:39:40 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2013 Google Inc.
5 *
Aaron Durbin0b0a1e32014-09-06 01:28:54 -05006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
Furquan Shaikh2af76f42014-04-28 16:39:40 -07009 *
Aaron Durbin0b0a1e32014-09-06 01:28:54 -050010 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Furquan Shaikh2af76f42014-04-28 16:39:40 -070014 *
Aaron Durbin0b0a1e32014-09-06 01:28:54 -050015 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Patrick Georgib890a122015-03-26 15:17:45 +010017 * Foundation, Inc.
Furquan Shaikh2af76f42014-04-28 16:39:40 -070018 */
Aaron Durbin0b0a1e32014-09-06 01:28:54 -050019
Aaron Durbin9fd4dc72014-09-06 02:31:30 -050020#include <stdint.h>
Furquan Shaikh2af76f42014-04-28 16:39:40 -070021#include <stdlib.h>
Aaron Durbin9fd4dc72014-09-06 02:31:30 -050022#include <arch/lib_helpers.h>
23#include <cpu/cpu.h>
24#include <console/console.h>
Aaron Durbin168eda52015-05-01 16:48:54 -050025#include <smp/node.h>
Aaron Durbin9fd4dc72014-09-06 02:31:30 -050026#include "cpu-internal.h"
Furquan Shaikh2af76f42014-04-28 16:39:40 -070027
Aaron Durbinb30c9b12014-09-18 11:52:16 -050028struct cpu_info cpu_infos[CONFIG_MAX_CPUS];
Aaron Durbin74ff69f2014-09-17 11:51:41 -050029struct cpu_info *bsp_cpu_info;
Aaron Durbin1b315d02014-08-27 10:30:39 -050030
Furquan Shaikh2af76f42014-04-28 16:39:40 -070031struct cpu_info *cpu_info(void)
32{
Aaron Durbin9fd4dc72014-09-06 02:31:30 -050033 return cpu_info_for_cpu(smp_processor_id());
34}
35
Aaron Durbin931a2182014-11-05 11:19:21 -060036size_t cpus_online(void)
37{
38 int i;
39 size_t num = 0;
40
41 for (i = 0; i < ARRAY_SIZE(cpu_infos); i++) {
42 if (cpu_online(cpu_info_for_cpu(i)))
43 num++;
44 }
45
46 return num;
47}
48
Aaron Durbin9fd4dc72014-09-06 02:31:30 -050049static inline int action_queue_empty(struct cpu_action_queue *q)
50{
51 return load_acquire_exclusive(&q->todo) == NULL;
52}
53
54static inline int action_completed(struct cpu_action_queue *q,
55 struct cpu_action *action)
56{
57 return load_acquire(&q->completed) == action;
58}
59
60static inline void wait_for_action_queue_slot(struct cpu_action_queue *q)
61{
62 while (!action_queue_empty(q))
63 wfe();
64}
65
66static void wait_for_action_complete(struct cpu_action_queue *q,
67 struct cpu_action *a)
68{
69 while (!action_completed(q, a))
70 wfe();
71}
72
73static struct cpu_action *wait_for_action(struct cpu_action_queue *q,
74 struct cpu_action *local)
75{
76 struct cpu_action *action;
77
78 while (action_queue_empty(q))
79 wfe();
80
81 /*
82 * Keep original address, but use a local copy for async processing.
83 */
84 do {
85 action = load_acquire_exclusive(&q->todo);
86 *local = *action;
87 } while (!store_release_exclusive(&q->todo, NULL));
88
89 return action;
90}
91
92static void queue_action(struct cpu_action_queue *q, struct cpu_action *action)
93{
94 do {
95 wait_for_action_queue_slot(q);
96 if (load_acquire_exclusive(&q->todo) != NULL)
97 continue;
98 } while (!store_release_exclusive(&q->todo, action));
99}
100
101static void action_queue_complete(struct cpu_action_queue *q,
102 struct cpu_action *action)
103{
104 /* Mark completion and send events to waiters. */
105 store_release(&q->completed, action);
106 sev();
107}
108
109static void action_run(struct cpu_action *action)
110{
111 action->run(action->arg);
112}
113
114static void action_run_on_cpu(struct cpu_info *ci, struct cpu_action *action,
115 int sync)
116{
117 struct cpu_action_queue *q = &ci->action_queue;
118
Aaron Durbinb30c9b12014-09-18 11:52:16 -0500119 /* Don't run actions on non-online cpus. */
120 if (!cpu_online(ci))
Aaron Durbin9fd4dc72014-09-06 02:31:30 -0500121 return;
122
123 if (ci->id == smp_processor_id()) {
124 action->run(action->arg);
125 return;
126 }
127
128 queue_action(q, action);
129 /* Wait for CPU to pick it up. Empty slot means it was picked up. */
130 wait_for_action_queue_slot(q);
131 /* Wait for completion if requested. */
132 if (sync)
133 wait_for_action_complete(q, action);
134}
135
136static int __arch_run_on_cpu(unsigned int cpu, struct cpu_action *action,
137 int sync)
138{
139 struct cpu_info *ci;
140
141 if (cpu >= CONFIG_MAX_CPUS)
142 return -1;
143
144 ci = cpu_info_for_cpu(cpu);
145
146 action_run_on_cpu(ci, action, sync);
147
148 return 0;
149}
150
151int arch_run_on_cpu(unsigned int cpu, struct cpu_action *action)
152{
153 return __arch_run_on_cpu(cpu, action, 1);
154}
155
156int arch_run_on_cpu_async(unsigned int cpu, struct cpu_action *action)
157{
158 return __arch_run_on_cpu(cpu, action, 0);
159}
160
161static int __arch_run_on_all_cpus(struct cpu_action *action, int sync)
162{
163 int i;
164
165 for (i = 0; i < CONFIG_MAX_CPUS; i++)
166 action_run_on_cpu(cpu_info_for_cpu(i), action, sync);
167
168 return 0;
169}
170
Aaron Durbincf5b6272014-09-17 12:00:57 -0500171static int __arch_run_on_all_cpus_but_self(struct cpu_action *action, int sync)
172{
173 int i;
174 struct cpu_info *me = cpu_info();
175
176 for (i = 0; i < CONFIG_MAX_CPUS; i++) {
177 struct cpu_info *ci = cpu_info_for_cpu(i);
178 if (ci == me)
179 continue;
180 action_run_on_cpu(ci, action, sync);
181 }
182
183 return 0;
184}
185
Aaron Durbin9fd4dc72014-09-06 02:31:30 -0500186int arch_run_on_all_cpus(struct cpu_action *action)
187{
188 return __arch_run_on_all_cpus(action, 1);
189}
190
191int arch_run_on_all_cpus_async(struct cpu_action *action)
192{
193 return __arch_run_on_all_cpus(action, 0);
194}
195
Aaron Durbincf5b6272014-09-17 12:00:57 -0500196int arch_run_on_all_cpus_but_self(struct cpu_action *action)
197{
198 return __arch_run_on_all_cpus_but_self(action, 1);
199}
200
201int arch_run_on_all_cpus_but_self_async(struct cpu_action *action)
202{
203 return __arch_run_on_all_cpus_but_self(action, 0);
204}
205
Aaron Durbinb30c9b12014-09-18 11:52:16 -0500206
207void arch_cpu_wait_for_action(void)
Aaron Durbin9fd4dc72014-09-06 02:31:30 -0500208{
209 struct cpu_info *ci = cpu_info();
210 struct cpu_action_queue *q = &ci->action_queue;
211
Aaron Durbin9fd4dc72014-09-06 02:31:30 -0500212 while (1) {
213 struct cpu_action *orig;
214 struct cpu_action action;
215
216 orig = wait_for_action(q, &action);
217
218 action_run(&action);
219 action_queue_complete(q, orig);
220 }
221}
Aaron Durbin168eda52015-05-01 16:48:54 -0500222
223int boot_cpu(void)
224{
225 return cpu_is_bsp();
226}