cpu_fdt.c revision 1.4 1 1.4 skrll /* $NetBSD: cpu_fdt.c,v 1.4 2024/01/01 13:51:56 skrll Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.1 skrll * Copyright (c) 2017 Jared McNeill <jmcneill (at) invisible.ca>
5 1.1 skrll * All rights reserved.
6 1.1 skrll *
7 1.1 skrll * Redistribution and use in source and binary forms, with or without
8 1.1 skrll * modification, are permitted provided that the following conditions
9 1.1 skrll * are met:
10 1.1 skrll * 1. Redistributions of source code must retain the above copyright
11 1.1 skrll * notice, this list of conditions and the following disclaimer.
12 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 skrll * notice, this list of conditions and the following disclaimer in the
14 1.1 skrll * documentation and/or other materials provided with the distribution.
15 1.1 skrll *
16 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 skrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 skrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 skrll * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 skrll * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 1.1 skrll * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 1.1 skrll * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 1.1 skrll * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 1.1 skrll * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 skrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 skrll * SUCH DAMAGE.
27 1.1 skrll */
28 1.1 skrll
29 1.1 skrll #include "opt_multiprocessor.h"
30 1.1 skrll
31 1.1 skrll #include <sys/cdefs.h>
32 1.4 skrll __KERNEL_RCSID(0, "$NetBSD: cpu_fdt.c,v 1.4 2024/01/01 13:51:56 skrll Exp $");
33 1.1 skrll
34 1.1 skrll #include <sys/param.h>
35 1.2 skrll #include <sys/cpu.h>
36 1.1 skrll
37 1.1 skrll #include <dev/fdt/fdtvar.h>
38 1.1 skrll
39 1.2 skrll #include <riscv/cpufunc.h>
40 1.1 skrll #include <riscv/cpuvar.h>
41 1.2 skrll #include <riscv/machdep.h>
42 1.2 skrll #include <riscv/sbi.h>
43 1.2 skrll
44 1.2 skrll #include <riscv/fdt/riscv_fdtvar.h>
45 1.2 skrll
46 1.4 skrll bool
47 1.4 skrll riscv_fdt_cpu_okay(const int node)
48 1.2 skrll {
49 1.2 skrll const char *s;
50 1.2 skrll
51 1.4 skrll s = fdtbus_get_string(node, "device_type");
52 1.2 skrll if (!s || strcmp(s, "cpu") != 0)
53 1.2 skrll return false;
54 1.2 skrll
55 1.4 skrll s = fdtbus_get_string(node, "status");
56 1.2 skrll if (s) {
57 1.2 skrll if (strcmp(s, "okay") == 0)
58 1.2 skrll return true;
59 1.2 skrll if (strcmp(s, "disabled") == 0)
60 1.2 skrll return false;
61 1.2 skrll return false;
62 1.2 skrll } else {
63 1.2 skrll return true;
64 1.2 skrll }
65 1.2 skrll }
66 1.2 skrll
67 1.2 skrll void
68 1.2 skrll riscv_fdt_cpu_bootstrap(void)
69 1.2 skrll {
70 1.2 skrll const int cpus = OF_finddevice("/cpus");
71 1.2 skrll if (cpus == -1) {
72 1.2 skrll aprint_error("%s: no /cpus node found\n", __func__);
73 1.2 skrll return;
74 1.2 skrll }
75 1.2 skrll
76 1.3 skrll /* Count harts and add hart index numbers to the cpu_hartindex array */
77 1.3 skrll u_int cpuindex = 1;
78 1.2 skrll for (int child = OF_child(cpus); child; child = OF_peer(child)) {
79 1.2 skrll if (!riscv_fdt_cpu_okay(child))
80 1.2 skrll continue;
81 1.2 skrll
82 1.2 skrll uint64_t reg;
83 1.2 skrll if (fdtbus_get_reg64(child, 0, ®, NULL) != 0)
84 1.2 skrll continue;
85 1.2 skrll
86 1.2 skrll const cpuid_t hartid = reg;
87 1.3 skrll if (hartid > MAXCPUS) {
88 1.3 skrll aprint_error("hart id too big %lu (%u)", hartid,
89 1.3 skrll MAXCPUS);
90 1.3 skrll continue;
91 1.3 skrll }
92 1.2 skrll
93 1.2 skrll struct sbiret sbiret = sbi_hart_get_status(hartid);
94 1.2 skrll switch (sbiret.error) {
95 1.2 skrll case SBI_ERR_INVALID_PARAM:
96 1.2 skrll aprint_error("Unknown hart id %lx", hartid);
97 1.2 skrll continue;
98 1.2 skrll case SBI_SUCCESS:
99 1.2 skrll break;
100 1.2 skrll default:
101 1.2 skrll aprint_error("Unexpected error (%ld) from get_status",
102 1.2 skrll sbiret.error);
103 1.2 skrll }
104 1.2 skrll
105 1.2 skrll /* Assume the BP is the only one started. */
106 1.2 skrll if (sbiret.value == SBI_HART_STARTED) {
107 1.3 skrll if (cpu_bphartid != ~0UL) {
108 1.2 skrll panic("more than 1 hart started");
109 1.2 skrll }
110 1.3 skrll cpu_bphartid = hartid;
111 1.3 skrll cpu_hartindex[hartid] = 0;
112 1.2 skrll continue;
113 1.2 skrll }
114 1.2 skrll
115 1.2 skrll KASSERT(cpuindex < MAXCPUS);
116 1.3 skrll cpu_hartindex[hartid] = cpuindex++;
117 1.2 skrll }
118 1.2 skrll }
119 1.3 skrll
120 1.2 skrll int
121 1.2 skrll riscv_fdt_cpu_mpstart(void)
122 1.2 skrll {
123 1.2 skrll int ret = 0;
124 1.2 skrll #ifdef MULTIPROCESSOR
125 1.2 skrll const int cpus = OF_finddevice("/cpus");
126 1.2 skrll if (cpus == -1) {
127 1.2 skrll aprint_error("%s: no /cpus node found\n", __func__);
128 1.2 skrll return 0;
129 1.2 skrll }
130 1.2 skrll
131 1.2 skrll /* BootAPs */
132 1.3 skrll u_int cpuindex = 1;
133 1.2 skrll for (int child = OF_child(cpus); child; child = OF_peer(child)) {
134 1.2 skrll if (!riscv_fdt_cpu_okay(child))
135 1.2 skrll continue;
136 1.2 skrll
137 1.2 skrll uint64_t reg;
138 1.2 skrll if (fdtbus_get_reg64(child, 0, ®, NULL) != 0)
139 1.2 skrll continue;
140 1.2 skrll
141 1.3 skrll const cpuid_t hartid = reg;
142 1.3 skrll if (hartid == cpu_bphartid)
143 1.2 skrll continue; /* BP already started */
144 1.2 skrll
145 1.2 skrll const paddr_t entry = KERN_VTOPHYS(cpu_mpstart);
146 1.3 skrll struct sbiret sbiret = sbi_hart_start(hartid, entry, cpuindex);
147 1.2 skrll switch (sbiret.error) {
148 1.2 skrll case SBI_SUCCESS:
149 1.2 skrll break;
150 1.2 skrll case SBI_ERR_INVALID_ADDRESS:
151 1.2 skrll break;
152 1.2 skrll case SBI_ERR_INVALID_PARAM:
153 1.2 skrll break;
154 1.2 skrll case SBI_ERR_ALREADY_AVAILABLE:
155 1.2 skrll break;
156 1.2 skrll case SBI_ERR_FAILED:
157 1.2 skrll break;
158 1.2 skrll default:
159 1.2 skrll aprint_error("%s: failed to enable CPU %#lx\n",
160 1.2 skrll __func__, hartid);
161 1.2 skrll }
162 1.2 skrll
163 1.2 skrll size_t i;
164 1.2 skrll /* Wait for AP to start */
165 1.2 skrll for (i = 0x10000000; i > 0; i--) {
166 1.2 skrll if (cpu_hatched_p(cpuindex))
167 1.2 skrll break;
168 1.2 skrll }
169 1.2 skrll
170 1.2 skrll if (i == 0) {
171 1.2 skrll ret++;
172 1.3 skrll aprint_error("hart%ld: WARNING: AP %u failed to start\n",
173 1.3 skrll hartid, cpuindex);
174 1.2 skrll }
175 1.2 skrll
176 1.2 skrll cpuindex++;
177 1.2 skrll }
178 1.2 skrll #else
179 1.2 skrll aprint_normal("%s: kernel compiled without MULTIPROCESSOR\n", __func__);
180 1.2 skrll #endif /* MULTIPROCESSOR */
181 1.2 skrll return ret;
182 1.2 skrll }
183 1.1 skrll
184 1.1 skrll static int
185 1.1 skrll cpu_fdt_match(device_t parent, cfdata_t cf, void *aux)
186 1.1 skrll {
187 1.1 skrll struct fdt_attach_args * const faa = aux;
188 1.1 skrll const int phandle = faa->faa_phandle;
189 1.1 skrll const char *device_type;
190 1.1 skrll
191 1.1 skrll device_type = fdtbus_get_string(phandle, "device_type");
192 1.1 skrll return device_type != NULL && strcmp(device_type, "cpu") == 0;
193 1.1 skrll }
194 1.1 skrll
195 1.1 skrll static void
196 1.1 skrll cpu_fdt_attach(device_t parent, device_t self, void *aux)
197 1.1 skrll {
198 1.1 skrll struct fdt_attach_args * const faa = aux;
199 1.1 skrll const int phandle = faa->faa_phandle;
200 1.3 skrll bus_addr_t hartid;
201 1.3 skrll
202 1.1 skrll
203 1.3 skrll if (fdtbus_get_reg(phandle, 0, &hartid, NULL) != 0)
204 1.3 skrll hartid = 0;
205 1.1 skrll
206 1.1 skrll /* Attach the CPU */
207 1.3 skrll cpu_attach(self, hartid);
208 1.1 skrll
209 1.1 skrll fdt_add_bus(self, phandle, faa);
210 1.1 skrll }
211 1.1 skrll
212 1.1 skrll CFATTACH_DECL_NEW(cpu_fdt, 0, cpu_fdt_match, cpu_fdt_attach, NULL, NULL);
213