1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2020 Ruslan Bukin <br@bsdpad.com>
5 *
6 * This software was developed by SRI International and the University of
7 * Cambridge Computer Laboratory (Department of Computer Science and
8 * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
9 * DARPA SSITH research programme.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/rman.h>
37 #include <sys/kernel.h>
38 #include <sys/lock.h>
39 #include <sys/module.h>
40 #include <sys/mutex.h>
41 #include <sys/uuid.h>
42 #include <machine/bus.h>
43
44 #include <contrib/dev/acpica/include/acpi.h>
45 #include <dev/acpica/acpivar.h>
46
47 #include <arm64/coresight/coresight.h>
48
49 #define ACPI_CORESIGHT_LINK_OUTPUT 1
50 #define ACPI_CORESIGHT_LINK_INPUT 0
51
52 static const struct uuid acpi_graph_uuid = {
53 0xab02a46b, 0x74c7, 0x45a2, 0xbd, 0x68,
54 { 0xf7, 0xd3, 0x44, 0xef, 0x21, 0x53 },
55 };
56
57 static const struct uuid coresight_graph_uuid = {
58 0x3ecbc8b6, 0x1d0e, 0x4fb3, 0x81, 0x07,
59 { 0xe6, 0x27, 0xf8, 0x05, 0xc6, 0xcd },
60 };
61
62 static inline bool
cs_acpi_validate_dsd_graph(const union acpi_object * graph)63 cs_acpi_validate_dsd_graph(const union acpi_object *graph)
64 {
65 const union acpi_object *rev, *nr_graphs;
66 const union acpi_object *obj;
67 int i, n;
68
69 if (graph->Package.Count < 2)
70 return (false);
71
72 rev = &graph->Package.Elements[0];
73 nr_graphs = &graph->Package.Elements[1];
74
75 if (rev->Type != ACPI_TYPE_INTEGER ||
76 nr_graphs->Type != ACPI_TYPE_INTEGER)
77 return (false);
78
79 /* Revision 0 supported only. */
80 if (rev->Integer.Value != 0)
81 return (false);
82
83 /* We are looking for a single graph. */
84 n = nr_graphs->Integer.Value;
85 if (n != 1)
86 return (false);
87
88 /* Check the number of elements. */
89 if (graph->Package.Count != (n + 2))
90 return (false);
91
92 for (i = 2; i < n + 2; i++) {
93 obj = &graph->Package.Elements[i];
94 if (obj->Type != ACPI_TYPE_PACKAGE || obj->Package.Count < 3)
95 return (false);
96 }
97
98 return (true);
99 }
100
101 static inline bool
cs_is_acpi_guid(const union acpi_object * obj)102 cs_is_acpi_guid(const union acpi_object *obj)
103 {
104
105 return (obj->Type == ACPI_TYPE_BUFFER) && (obj->Buffer.Length == 16);
106 }
107
108 static inline bool
cs_guid_equal(const struct uuid * u1,const struct uuid * u2)109 cs_guid_equal(const struct uuid *u1, const struct uuid *u2)
110 {
111
112 if (memcmp(u1, u2, 16) == 0)
113 return (true);
114
115 return (false);
116 }
117
118 static inline bool
cs_acpi_guid_matches(const union acpi_object * obj,const struct uuid * guid)119 cs_acpi_guid_matches(const union acpi_object *obj, const struct uuid *guid)
120 {
121
122 if (cs_is_acpi_guid(obj) &&
123 cs_guid_equal((struct uuid *)obj->Buffer.Pointer, guid))
124 return (true);
125
126 return (false);
127 }
128
129 static inline bool
is_acpi_dsd_graph_guid(const union acpi_object * obj)130 is_acpi_dsd_graph_guid(const union acpi_object *obj)
131 {
132
133 return (cs_acpi_guid_matches(obj, &acpi_graph_uuid));
134 }
135
136 static inline bool
cs_is_acpi_coresight_graph_guid(const union acpi_object * obj)137 cs_is_acpi_coresight_graph_guid(const union acpi_object *obj)
138 {
139
140 return (cs_acpi_guid_matches(obj, &coresight_graph_uuid));
141 }
142
143 static inline bool
cs_is_acpi_coresight_graph(const union acpi_object * obj)144 cs_is_acpi_coresight_graph(const union acpi_object *obj)
145 {
146 const union acpi_object *graphid, *guid, *links;
147
148 if (obj->Type != ACPI_TYPE_PACKAGE ||
149 obj->Package.Count < 3)
150 return (false);
151
152 graphid = &obj->Package.Elements[0];
153 guid = &obj->Package.Elements[1];
154 links = &obj->Package.Elements[2];
155
156 if (graphid->Type != ACPI_TYPE_INTEGER ||
157 links->Type != ACPI_TYPE_INTEGER)
158 return (false);
159
160 if (cs_is_acpi_coresight_graph_guid(guid))
161 return (true);
162
163 return (false);
164 }
165
166 static const union acpi_object *
cs_get_dsd_graph(device_t dev)167 cs_get_dsd_graph(device_t dev)
168 {
169 const union acpi_object *guid, *package;
170 union acpi_object *dsd;
171 ACPI_STATUS status;
172 ACPI_BUFFER buf;
173 device_t bus;
174 int i;
175
176 buf.Length = PAGE_SIZE;
177 buf.Pointer = malloc(buf.Length, M_TEMP, M_NOWAIT | M_ZERO);
178 if (buf.Pointer == NULL) {
179 printf("Failed to allocate memory.\n");
180 return (NULL);
181 }
182
183 bus = device_get_parent(dev);
184 status = ACPI_EVALUATE_OBJECT(bus, dev, "_DSD", NULL, &buf);
185 if (ACPI_FAILURE(status)) {
186 printf("Failed to evaluate object.\n");
187 return (NULL);
188 }
189
190 dsd = buf.Pointer;
191
192 for (i = 0; i + 1 < dsd->Package.Count; i += 2) {
193 guid = &dsd->Package.Elements[i];
194 package = &dsd->Package.Elements[i + 1];
195
196 if (!cs_is_acpi_guid(guid) ||
197 package->Type != ACPI_TYPE_PACKAGE)
198 break;
199
200 if (!is_acpi_dsd_graph_guid(guid))
201 continue;
202
203 if (cs_acpi_validate_dsd_graph(package))
204 return (package);
205 }
206
207 return (NULL);
208 }
209
210 static inline bool
cs_acpi_validate_coresight_graph(const union acpi_object * cs_graph)211 cs_acpi_validate_coresight_graph(const union acpi_object *cs_graph)
212 {
213 int nlinks;
214
215 nlinks = cs_graph->Package.Elements[2].Integer.Value;
216 if (cs_graph->Package.Count != (nlinks + 3))
217 return (false);
218
219 return (true);
220 }
221
222 static const union acpi_object *
cs_get_coresight_graph(device_t dev)223 cs_get_coresight_graph(device_t dev)
224 {
225 const union acpi_object *graph_list, *graph;
226 int i, nr_graphs;
227
228 graph_list = cs_get_dsd_graph(dev);
229 if (!graph_list) {
230 printf("failed to get graph list\n");
231 return (NULL);
232 }
233
234 nr_graphs = graph_list->Package.Elements[1].Integer.Value;
235 for (i = 2; i < nr_graphs + 2; i++) {
236 graph = &graph_list->Package.Elements[i];
237 if (!cs_is_acpi_coresight_graph(graph))
238 continue;
239 if (cs_acpi_validate_coresight_graph(graph))
240 return (graph);
241 break;
242 }
243
244 return (NULL);
245 }
246
247 static int
cs_acpi_record_endpoint(device_t dev,struct coresight_platform_data * pdata,const union acpi_object * link)248 cs_acpi_record_endpoint(device_t dev,
249 struct coresight_platform_data *pdata,
250 const union acpi_object *link)
251 {
252 const union acpi_object *fields;
253 struct endpoint *endp;
254 ACPI_HANDLE handle;
255 int dir;
256
257 if (link->Type != ACPI_TYPE_PACKAGE ||
258 link->Package.Count != 4)
259 return (ENXIO);
260
261 fields = link->Package.Elements;
262 if (fields[0].Type != ACPI_TYPE_INTEGER ||
263 fields[1].Type != ACPI_TYPE_INTEGER ||
264 fields[2].Type != ACPI_TYPE_LOCAL_REFERENCE ||
265 fields[3].Type != ACPI_TYPE_INTEGER)
266 return (ENXIO);
267
268 handle = fields[2].Reference.Handle;
269 dir = fields[3].Integer.Value;
270
271 endp = malloc(sizeof(struct endpoint),
272 M_CORESIGHT, M_WAITOK | M_ZERO);
273 if (endp == NULL) {
274 device_printf(dev, "Failed to allocate memory.\n");
275 return (ENXIO);
276 }
277
278 endp->their_handle = handle;
279 endp->my_handle = acpi_get_handle(dev);
280
281 mtx_lock(&pdata->mtx_lock);
282 TAILQ_INSERT_TAIL(&pdata->endpoints, endp, link);
283 mtx_unlock(&pdata->mtx_lock);
284
285 if (dir == ACPI_CORESIGHT_LINK_OUTPUT) {
286 pdata->out_ports++;
287 } else {
288 endp->input = true;
289 pdata->in_ports++;
290 }
291
292 return (0);
293 }
294
295 static int
coresight_acpi_get_ports(device_t dev,struct coresight_platform_data * pdata)296 coresight_acpi_get_ports(device_t dev,
297 struct coresight_platform_data *pdata)
298 {
299 const union acpi_object *graph;
300 const union acpi_object *link;
301 int nlinks;
302 int error;
303 int i;
304
305 graph = cs_get_coresight_graph(dev);
306 if (graph == NULL) {
307 device_printf(dev, "Coresight graph not found.\n");
308 return (ENXIO);
309 }
310
311 nlinks = graph->Package.Elements[2].Integer.Value;
312 if (!nlinks)
313 return (0);
314
315 for (i = 0; i < nlinks; i++) {
316 link = &graph->Package.Elements[3 + i];
317 error = cs_acpi_record_endpoint(dev, pdata, link);
318 if (error < 0)
319 return (error);
320 }
321
322 return (0);
323 }
324
325 static int
coresight_acpi_get_cpu(device_t dev,struct coresight_platform_data * pdata)326 coresight_acpi_get_cpu(device_t dev, struct coresight_platform_data *pdata)
327 {
328 ACPI_HANDLE handle, parent;
329 ACPI_STATUS status;
330 int cpuid;
331
332 handle = acpi_get_handle(dev);
333
334 status = AcpiGetParent(handle, &parent);
335 if (!ACPI_SUCCESS(status))
336 return (ENXIO);
337
338 if (!acpi_MatchHid(parent, "ACPI0007"))
339 return (ENXIO);
340
341 status = acpi_GetInteger(parent, "_UID", &cpuid);
342 if (ACPI_SUCCESS(status)) {
343 pdata->cpu = cpuid;
344 return (0);
345 }
346
347 return (ENXIO);
348 }
349
350 struct coresight_platform_data *
coresight_acpi_get_platform_data(device_t dev)351 coresight_acpi_get_platform_data(device_t dev)
352 {
353 struct coresight_platform_data *pdata;
354
355 pdata = malloc(sizeof(struct coresight_platform_data),
356 M_CORESIGHT, M_WAITOK | M_ZERO);
357 pdata->bus_type = CORESIGHT_BUS_ACPI;
358
359 mtx_init(&pdata->mtx_lock, "Coresight Platform Data", NULL, MTX_DEF);
360 TAILQ_INIT(&pdata->endpoints);
361
362 coresight_acpi_get_cpu(dev, pdata);
363 coresight_acpi_get_ports(dev, pdata);
364
365 if (bootverbose)
366 printf("Total ports: in %d out %d\n",
367 pdata->in_ports, pdata->out_ports);
368
369 return (pdata);
370 }
371