2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2020 Ruslan Bukin <br@bsdpad.com>
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
40 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/mutex.h>
45 #include <machine/bus.h>
47 #include <contrib/dev/acpica/include/acpi.h>
48 #include <dev/acpica/acpivar.h>
50 #include <arm64/coresight/coresight.h>
52 #define ACPI_CORESIGHT_LINK_OUTPUT 1
53 #define ACPI_CORESIGHT_LINK_INPUT 0
55 static const struct uuid acpi_graph_uuid = {
56 0xab02a46b, 0x74c7, 0x45a2, 0xbd, 0x68,
57 { 0xf7, 0xd3, 0x44, 0xef, 0x21, 0x53 },
60 static const struct uuid coresight_graph_uuid = {
61 0x3ecbc8b6, 0x1d0e, 0x4fb3, 0x81, 0x07,
62 { 0xe6, 0x27, 0xf8, 0x05, 0xc6, 0xcd },
66 cs_acpi_validate_dsd_graph(const union acpi_object *graph)
68 const union acpi_object *rev, *nr_graphs;
69 const union acpi_object *obj;
72 if (graph->Package.Count < 2)
75 rev = &graph->Package.Elements[0];
76 nr_graphs = &graph->Package.Elements[1];
78 if (rev->Type != ACPI_TYPE_INTEGER ||
79 nr_graphs->Type != ACPI_TYPE_INTEGER)
82 /* Revision 0 supported only. */
83 if (rev->Integer.Value != 0)
86 /* We are looking for a single graph. */
87 n = nr_graphs->Integer.Value;
91 /* Check the number of elements. */
92 if (graph->Package.Count != (n + 2))
95 for (i = 2; i < n + 2; i++) {
96 obj = &graph->Package.Elements[i];
97 if (obj->Type != ACPI_TYPE_PACKAGE || obj->Package.Count < 3)
105 cs_is_acpi_guid(const union acpi_object *obj)
108 return (obj->Type == ACPI_TYPE_BUFFER) && (obj->Buffer.Length == 16);
112 cs_guid_equal(const struct uuid *u1, const struct uuid *u2)
115 if (memcmp(u1, u2, 16) == 0)
122 cs_acpi_guid_matches(const union acpi_object *obj, const struct uuid *guid)
125 if (cs_is_acpi_guid(obj) &&
126 cs_guid_equal((struct uuid *)obj->Buffer.Pointer, guid))
133 is_acpi_dsd_graph_guid(const union acpi_object *obj)
136 return (cs_acpi_guid_matches(obj, &acpi_graph_uuid));
140 cs_is_acpi_coresight_graph_guid(const union acpi_object *obj)
143 return (cs_acpi_guid_matches(obj, &coresight_graph_uuid));
147 cs_is_acpi_coresight_graph(const union acpi_object *obj)
149 const union acpi_object *graphid, *guid, *links;
151 if (obj->Type != ACPI_TYPE_PACKAGE ||
152 obj->Package.Count < 3)
155 graphid = &obj->Package.Elements[0];
156 guid = &obj->Package.Elements[1];
157 links = &obj->Package.Elements[2];
159 if (graphid->Type != ACPI_TYPE_INTEGER ||
160 links->Type != ACPI_TYPE_INTEGER)
163 if (cs_is_acpi_coresight_graph_guid(guid))
169 static const union acpi_object *
170 cs_get_dsd_graph(device_t dev)
172 const union acpi_object *guid, *package;
173 union acpi_object *dsd;
179 buf.Length = PAGE_SIZE;
180 buf.Pointer = malloc(buf.Length, M_TEMP, M_NOWAIT | M_ZERO);
181 if (buf.Pointer == NULL) {
182 printf("Failed to allocate memory.\n");
186 bus = device_get_parent(dev);
187 status = ACPI_EVALUATE_OBJECT(bus, dev, "_DSD", NULL, &buf);
188 if (ACPI_FAILURE(status)) {
189 printf("Failed to evaluate object.\n");
195 for (i = 0; i + 1 < dsd->Package.Count; i += 2) {
196 guid = &dsd->Package.Elements[i];
197 package = &dsd->Package.Elements[i + 1];
199 if (!cs_is_acpi_guid(guid) ||
200 package->Type != ACPI_TYPE_PACKAGE)
203 if (!is_acpi_dsd_graph_guid(guid))
206 if (cs_acpi_validate_dsd_graph(package))
214 cs_acpi_validate_coresight_graph(const union acpi_object *cs_graph)
218 nlinks = cs_graph->Package.Elements[2].Integer.Value;
219 if (cs_graph->Package.Count != (nlinks + 3))
225 static const union acpi_object *
226 cs_get_coresight_graph(device_t dev)
228 const union acpi_object *graph_list, *graph;
231 graph_list = cs_get_dsd_graph(dev);
233 printf("failed to get graph list\n");
237 nr_graphs = graph_list->Package.Elements[1].Integer.Value;
238 for (i = 2; i < nr_graphs + 2; i++) {
239 graph = &graph_list->Package.Elements[i];
240 if (!cs_is_acpi_coresight_graph(graph))
242 if (cs_acpi_validate_coresight_graph(graph))
251 cs_acpi_record_endpoint(device_t dev,
252 struct coresight_platform_data *pdata,
253 const union acpi_object *link)
255 const union acpi_object *fields;
256 struct endpoint *endp;
260 if (link->Type != ACPI_TYPE_PACKAGE ||
261 link->Package.Count != 4)
264 fields = link->Package.Elements;
265 if (fields[0].Type != ACPI_TYPE_INTEGER ||
266 fields[1].Type != ACPI_TYPE_INTEGER ||
267 fields[2].Type != ACPI_TYPE_LOCAL_REFERENCE ||
268 fields[3].Type != ACPI_TYPE_INTEGER)
271 handle = fields[2].Reference.Handle;
272 dir = fields[3].Integer.Value;
274 endp = malloc(sizeof(struct endpoint),
275 M_CORESIGHT, M_WAITOK | M_ZERO);
277 device_printf(dev, "Failed to allocate memory.\n");
281 endp->their_handle = handle;
282 endp->my_handle = acpi_get_handle(dev);
284 mtx_lock(&pdata->mtx_lock);
285 TAILQ_INSERT_TAIL(&pdata->endpoints, endp, link);
286 mtx_unlock(&pdata->mtx_lock);
288 if (dir == ACPI_CORESIGHT_LINK_OUTPUT) {
299 coresight_acpi_get_ports(device_t dev,
300 struct coresight_platform_data *pdata)
302 const union acpi_object *graph;
303 const union acpi_object *link;
308 graph = cs_get_coresight_graph(dev);
310 device_printf(dev, "Coresight graph not found.\n");
314 nlinks = graph->Package.Elements[2].Integer.Value;
318 for (i = 0; i < nlinks; i++) {
319 link = &graph->Package.Elements[3 + i];
320 error = cs_acpi_record_endpoint(dev, pdata, link);
329 coresight_acpi_get_cpu(device_t dev, struct coresight_platform_data *pdata)
331 ACPI_HANDLE handle, parent;
335 handle = acpi_get_handle(dev);
337 status = AcpiGetParent(handle, &parent);
338 if (!ACPI_SUCCESS(status))
341 if (!acpi_MatchHid(parent, "ACPI0007"))
344 status = acpi_GetInteger(parent, "_UID", &cpuid);
345 if (ACPI_SUCCESS(status)) {
353 struct coresight_platform_data *
354 coresight_acpi_get_platform_data(device_t dev)
356 struct coresight_platform_data *pdata;
358 pdata = malloc(sizeof(struct coresight_platform_data),
359 M_CORESIGHT, M_WAITOK | M_ZERO);
360 pdata->bus_type = CORESIGHT_BUS_ACPI;
362 mtx_init(&pdata->mtx_lock, "Coresight Platform Data", NULL, MTX_DEF);
363 TAILQ_INIT(&pdata->endpoints);
365 coresight_acpi_get_cpu(dev, pdata);
366 coresight_acpi_get_ports(dev, pdata);
369 printf("Total ports: in %d out %d\n",
370 pdata->in_ports, pdata->out_ports);