cpu_fdt.c revision 1.2 1 1.2 skrll /* $NetBSD: cpu_fdt.c,v 1.2 2023/06/12 19:04:13 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.2 skrll __KERNEL_RCSID(0, "$NetBSD: cpu_fdt.c,v 1.2 2023/06/12 19:04:13 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.2 skrll
47 1.2 skrll #ifdef MULTIPROCESSOR
48 1.2 skrll static bool
49 1.2 skrll riscv_fdt_cpu_okay(const int child)
50 1.2 skrll {
51 1.2 skrll const char *s;
52 1.2 skrll
53 1.2 skrll s = fdtbus_get_string(child, "device_type");
54 1.2 skrll if (!s || strcmp(s, "cpu") != 0)
55 1.2 skrll return false;
56 1.2 skrll
57 1.2 skrll s = fdtbus_get_string(child, "status");
58 1.2 skrll if (s) {
59 1.2 skrll if (strcmp(s, "okay") == 0)
60 1.2 skrll return true;
61 1.2 skrll if (strcmp(s, "disabled") == 0)
62 1.2 skrll return false;
63 1.2 skrll return false;
64 1.2 skrll } else {
65 1.2 skrll return true;
66 1.2 skrll }
67 1.2 skrll }
68 1.2 skrll #endif /* MULTIPROCESSOR */
69 1.2 skrll
70 1.2 skrll void
71 1.2 skrll riscv_fdt_cpu_bootstrap(void)
72 1.2 skrll {
73 1.2 skrll #ifdef MULTIPROCESSOR
74 1.2 skrll
75 1.2 skrll const int cpus = OF_finddevice("/cpus");
76 1.2 skrll if (cpus == -1) {
77 1.2 skrll aprint_error("%s: no /cpus node found\n", __func__);
78 1.2 skrll riscv_cpu_max = 1;
79 1.2 skrll return;
80 1.2 skrll }
81 1.2 skrll
82 1.2 skrll /* Count harts and add hart IDs to to cpu_hartid array */
83 1.2 skrll size_t cpuindex = 1;
84 1.2 skrll for (int child = OF_child(cpus); child; child = OF_peer(child)) {
85 1.2 skrll if (!riscv_fdt_cpu_okay(child))
86 1.2 skrll continue;
87 1.2 skrll
88 1.2 skrll riscv_cpu_max++;
89 1.2 skrll
90 1.2 skrll uint64_t reg;
91 1.2 skrll if (fdtbus_get_reg64(child, 0, ®, NULL) != 0)
92 1.2 skrll continue;
93 1.2 skrll
94 1.2 skrll const cpuid_t hartid = reg;
95 1.2 skrll
96 1.2 skrll struct sbiret sbiret = sbi_hart_get_status(hartid);
97 1.2 skrll switch (sbiret.error) {
98 1.2 skrll case SBI_ERR_INVALID_PARAM:
99 1.2 skrll aprint_error("Unknown hart id %lx", hartid);
100 1.2 skrll continue;
101 1.2 skrll case SBI_SUCCESS:
102 1.2 skrll break;
103 1.2 skrll default:
104 1.2 skrll aprint_error("Unexpected error (%ld) from get_status",
105 1.2 skrll sbiret.error);
106 1.2 skrll }
107 1.2 skrll
108 1.2 skrll /* Assume the BP is the only one started. */
109 1.2 skrll if (sbiret.value == SBI_HART_STARTED) {
110 1.2 skrll if (cpu_hartid[0] != -1) {
111 1.2 skrll panic("more than 1 hart started");
112 1.2 skrll }
113 1.2 skrll cpu_hartid[0] = hartid;
114 1.2 skrll continue;
115 1.2 skrll }
116 1.2 skrll
117 1.2 skrll KASSERT(cpuindex < MAXCPUS);
118 1.2 skrll cpu_hartid[cpuindex] = hartid;
119 1.2 skrll cpu_dcache_wb_range((vaddr_t)&cpu_hartid[cpuindex],
120 1.2 skrll sizeof(cpu_hartid[cpuindex]));
121 1.2 skrll
122 1.2 skrll cpuindex++;
123 1.2 skrll }
124 1.2 skrll #endif
125 1.2 skrll }
126 1.2 skrll int
127 1.2 skrll riscv_fdt_cpu_mpstart(void)
128 1.2 skrll {
129 1.2 skrll int ret = 0;
130 1.2 skrll #ifdef MULTIPROCESSOR
131 1.2 skrll const int cpus = OF_finddevice("/cpus");
132 1.2 skrll if (cpus == -1) {
133 1.2 skrll aprint_error("%s: no /cpus node found\n", __func__);
134 1.2 skrll return 0;
135 1.2 skrll }
136 1.2 skrll
137 1.2 skrll // riscv_fdt_cpu_bootstrap put the boot hart id in cpu_hartid[0]
138 1.2 skrll const cpuid_t bp_hartid = cpu_hartid[0];
139 1.2 skrll
140 1.2 skrll /* BootAPs */
141 1.2 skrll size_t cpuindex = 1;
142 1.2 skrll for (int child = OF_child(cpus); child; child = OF_peer(child)) {
143 1.2 skrll if (!riscv_fdt_cpu_okay(child))
144 1.2 skrll continue;
145 1.2 skrll
146 1.2 skrll uint64_t reg;
147 1.2 skrll if (fdtbus_get_reg64(child, 0, ®, NULL) != 0)
148 1.2 skrll continue;
149 1.2 skrll
150 1.2 skrll cpuid_t hartid = reg;
151 1.2 skrll
152 1.2 skrll if (hartid == bp_hartid)
153 1.2 skrll continue; /* BP already started */
154 1.2 skrll
155 1.2 skrll const paddr_t entry = KERN_VTOPHYS(cpu_mpstart);
156 1.2 skrll struct sbiret sbiret = sbi_hart_start(hartid, entry, 0);
157 1.2 skrll switch (sbiret.error) {
158 1.2 skrll case SBI_SUCCESS:
159 1.2 skrll break;
160 1.2 skrll case SBI_ERR_INVALID_ADDRESS:
161 1.2 skrll break;
162 1.2 skrll case SBI_ERR_INVALID_PARAM:
163 1.2 skrll break;
164 1.2 skrll case SBI_ERR_ALREADY_AVAILABLE:
165 1.2 skrll break;
166 1.2 skrll case SBI_ERR_FAILED:
167 1.2 skrll break;
168 1.2 skrll default:
169 1.2 skrll aprint_error("%s: failed to enable CPU %#lx\n",
170 1.2 skrll __func__, hartid);
171 1.2 skrll }
172 1.2 skrll
173 1.2 skrll size_t i;
174 1.2 skrll /* Wait for AP to start */
175 1.2 skrll for (i = 0x10000000; i > 0; i--) {
176 1.2 skrll if (cpu_hatched_p(cpuindex))
177 1.2 skrll break;
178 1.2 skrll }
179 1.2 skrll
180 1.2 skrll if (i == 0) {
181 1.2 skrll ret++;
182 1.2 skrll aprint_error("cpu%zu: WARNING: AP failed to start\n",
183 1.2 skrll cpuindex);
184 1.2 skrll }
185 1.2 skrll
186 1.2 skrll cpuindex++;
187 1.2 skrll }
188 1.2 skrll #else
189 1.2 skrll aprint_normal("%s: kernel compiled without MULTIPROCESSOR\n", __func__);
190 1.2 skrll #endif /* MULTIPROCESSOR */
191 1.2 skrll return ret;
192 1.2 skrll }
193 1.1 skrll
194 1.1 skrll static int
195 1.1 skrll cpu_fdt_match(device_t parent, cfdata_t cf, void *aux)
196 1.1 skrll {
197 1.1 skrll struct fdt_attach_args * const faa = aux;
198 1.1 skrll const int phandle = faa->faa_phandle;
199 1.1 skrll const char *device_type;
200 1.1 skrll
201 1.1 skrll device_type = fdtbus_get_string(phandle, "device_type");
202 1.1 skrll return device_type != NULL && strcmp(device_type, "cpu") == 0;
203 1.1 skrll }
204 1.1 skrll
205 1.1 skrll static void
206 1.1 skrll cpu_fdt_attach(device_t parent, device_t self, void *aux)
207 1.1 skrll {
208 1.1 skrll struct fdt_attach_args * const faa = aux;
209 1.1 skrll const int phandle = faa->faa_phandle;
210 1.1 skrll bus_addr_t cpuid;
211 1.1 skrll
212 1.1 skrll if (fdtbus_get_reg(phandle, 0, &cpuid, NULL) != 0)
213 1.1 skrll cpuid = 0;
214 1.1 skrll
215 1.1 skrll /* Attach the CPU */
216 1.1 skrll cpu_attach(self, cpuid);
217 1.1 skrll
218 1.1 skrll fdt_add_bus(self, phandle, faa);
219 1.1 skrll }
220 1.1 skrll
221 1.1 skrll CFATTACH_DECL_NEW(cpu_fdt, 0, cpu_fdt_match, cpu_fdt_attach, NULL, NULL);
222