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/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/bus.h> 39 #include <sys/rman.h> 40 #include <sys/kernel.h> 41 #include <sys/lock.h> 42 #include <sys/module.h> 43 #include <sys/mutex.h> 44 #include <sys/uuid.h> 45 #include <machine/bus.h> 46 47 #include <contrib/dev/acpica/include/acpi.h> 48 #include <dev/acpica/acpivar.h> 49 50 #include <arm64/coresight/coresight.h> 51 52 #define ACPI_CORESIGHT_LINK_OUTPUT 1 53 #define ACPI_CORESIGHT_LINK_INPUT 0 54 55 static const struct uuid acpi_graph_uuid = { 56 0xab02a46b, 0x74c7, 0x45a2, 0xbd, 0x68, 57 { 0xf7, 0xd3, 0x44, 0xef, 0x21, 0x53 }, 58 }; 59 60 static const struct uuid coresight_graph_uuid = { 61 0x3ecbc8b6, 0x1d0e, 0x4fb3, 0x81, 0x07, 62 { 0xe6, 0x27, 0xf8, 0x05, 0xc6, 0xcd }, 63 }; 64 65 static inline bool 66 cs_acpi_validate_dsd_graph(const union acpi_object *graph) 67 { 68 const union acpi_object *rev, *nr_graphs; 69 const union acpi_object *obj; 70 int i, n; 71 72 if (graph->Package.Count < 2) 73 return (false); 74 75 rev = &graph->Package.Elements[0]; 76 nr_graphs = &graph->Package.Elements[1]; 77 78 if (rev->Type != ACPI_TYPE_INTEGER || 79 nr_graphs->Type != ACPI_TYPE_INTEGER) 80 return (false); 81 82 /* Revision 0 supported only. */ 83 if (rev->Integer.Value != 0) 84 return (false); 85 86 /* We are looking for a single graph. */ 87 n = nr_graphs->Integer.Value; 88 if (n != 1) 89 return (false); 90 91 /* Check the number of elements. */ 92 if (graph->Package.Count != (n + 2)) 93 return (false); 94 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) 98 return (false); 99 } 100 101 return (true); 102 } 103 104 static inline bool 105 cs_is_acpi_guid(const union acpi_object *obj) 106 { 107 108 return (obj->Type == ACPI_TYPE_BUFFER) && (obj->Buffer.Length == 16); 109 } 110 111 static inline bool 112 cs_guid_equal(const struct uuid *u1, const struct uuid *u2) 113 { 114 115 if (memcmp(u1, u2, 16) == 0) 116 return (true); 117 118 return (false); 119 } 120 121 static inline bool 122 cs_acpi_guid_matches(const union acpi_object *obj, const struct uuid *guid) 123 { 124 125 if (cs_is_acpi_guid(obj) && 126 cs_guid_equal((struct uuid *)obj->Buffer.Pointer, guid)) 127 return (true); 128 129 return (false); 130 } 131 132 static inline bool 133 is_acpi_dsd_graph_guid(const union acpi_object *obj) 134 { 135 136 return (cs_acpi_guid_matches(obj, &acpi_graph_uuid)); 137 } 138 139 static inline bool 140 cs_is_acpi_coresight_graph_guid(const union acpi_object *obj) 141 { 142 143 return (cs_acpi_guid_matches(obj, &coresight_graph_uuid)); 144 } 145 146 static inline bool 147 cs_is_acpi_coresight_graph(const union acpi_object *obj) 148 { 149 const union acpi_object *graphid, *guid, *links; 150 151 if (obj->Type != ACPI_TYPE_PACKAGE || 152 obj->Package.Count < 3) 153 return (false); 154 155 graphid = &obj->Package.Elements[0]; 156 guid = &obj->Package.Elements[1]; 157 links = &obj->Package.Elements[2]; 158 159 if (graphid->Type != ACPI_TYPE_INTEGER || 160 links->Type != ACPI_TYPE_INTEGER) 161 return (false); 162 163 if (cs_is_acpi_coresight_graph_guid(guid)) 164 return (true); 165 166 return (false); 167 } 168 169 static const union acpi_object * 170 cs_get_dsd_graph(device_t dev) 171 { 172 const union acpi_object *guid, *package; 173 union acpi_object *dsd; 174 ACPI_STATUS status; 175 ACPI_BUFFER buf; 176 device_t bus; 177 int i; 178 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"); 183 return (NULL); 184 } 185 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"); 190 return (NULL); 191 } 192 193 dsd = buf.Pointer; 194 195 for (i = 0; i + 1 < dsd->Package.Count; i += 2) { 196 guid = &dsd->Package.Elements[i]; 197 package = &dsd->Package.Elements[i + 1]; 198 199 if (!cs_is_acpi_guid(guid) || 200 package->Type != ACPI_TYPE_PACKAGE) 201 break; 202 203 if (!is_acpi_dsd_graph_guid(guid)) 204 continue; 205 206 if (cs_acpi_validate_dsd_graph(package)) 207 return (package); 208 } 209 210 return (NULL); 211 } 212 213 static inline bool 214 cs_acpi_validate_coresight_graph(const union acpi_object *cs_graph) 215 { 216 int nlinks; 217 218 nlinks = cs_graph->Package.Elements[2].Integer.Value; 219 if (cs_graph->Package.Count != (nlinks + 3)) 220 return (false); 221 222 return (true); 223 } 224 225 static const union acpi_object * 226 cs_get_coresight_graph(device_t dev) 227 { 228 const union acpi_object *graph_list, *graph; 229 int i, nr_graphs; 230 231 graph_list = cs_get_dsd_graph(dev); 232 if (!graph_list) { 233 printf("failed to get graph list\n"); 234 return (NULL); 235 } 236 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)) 241 continue; 242 if (cs_acpi_validate_coresight_graph(graph)) 243 return (graph); 244 break; 245 } 246 247 return (NULL); 248 } 249 250 static int 251 cs_acpi_record_endpoint(device_t dev, 252 struct coresight_platform_data *pdata, 253 const union acpi_object *link) 254 { 255 const union acpi_object *fields; 256 struct endpoint *endp; 257 ACPI_HANDLE handle; 258 int dir; 259 260 if (link->Type != ACPI_TYPE_PACKAGE || 261 link->Package.Count != 4) 262 return (ENXIO); 263 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) 269 return (ENXIO); 270 271 handle = fields[2].Reference.Handle; 272 dir = fields[3].Integer.Value; 273 274 endp = malloc(sizeof(struct endpoint), 275 M_CORESIGHT, M_WAITOK | M_ZERO); 276 if (endp == NULL) { 277 device_printf(dev, "Failed to allocate memory.\n"); 278 return (ENXIO); 279 } 280 281 endp->their_handle = handle; 282 endp->my_handle = acpi_get_handle(dev); 283 284 mtx_lock(&pdata->mtx_lock); 285 TAILQ_INSERT_TAIL(&pdata->endpoints, endp, link); 286 mtx_unlock(&pdata->mtx_lock); 287 288 if (dir == ACPI_CORESIGHT_LINK_OUTPUT) { 289 pdata->out_ports++; 290 } else { 291 endp->input = true; 292 pdata->in_ports++; 293 } 294 295 return (0); 296 } 297 298 static int 299 coresight_acpi_get_ports(device_t dev, 300 struct coresight_platform_data *pdata) 301 { 302 const union acpi_object *graph; 303 const union acpi_object *link; 304 int nlinks; 305 int error; 306 int i; 307 308 graph = cs_get_coresight_graph(dev); 309 if (graph == NULL) { 310 device_printf(dev, "Coresight graph not found.\n"); 311 return (ENXIO); 312 } 313 314 nlinks = graph->Package.Elements[2].Integer.Value; 315 if (!nlinks) 316 return (0); 317 318 for (i = 0; i < nlinks; i++) { 319 link = &graph->Package.Elements[3 + i]; 320 error = cs_acpi_record_endpoint(dev, pdata, link); 321 if (error < 0) 322 return (error); 323 } 324 325 return (0); 326 } 327 328 static int 329 coresight_acpi_get_cpu(device_t dev, struct coresight_platform_data *pdata) 330 { 331 ACPI_HANDLE handle, parent; 332 ACPI_STATUS status; 333 int cpuid; 334 335 handle = acpi_get_handle(dev); 336 337 status = AcpiGetParent(handle, &parent); 338 if (!ACPI_SUCCESS(status)) 339 return (ENXIO); 340 341 if (!acpi_MatchHid(parent, "ACPI0007")) 342 return (ENXIO); 343 344 status = acpi_GetInteger(parent, "_UID", &cpuid); 345 if (ACPI_SUCCESS(status)) { 346 pdata->cpu = cpuid; 347 return (0); 348 } 349 350 return (ENXIO); 351 } 352 353 struct coresight_platform_data * 354 coresight_acpi_get_platform_data(device_t dev) 355 { 356 struct coresight_platform_data *pdata; 357 358 pdata = malloc(sizeof(struct coresight_platform_data), 359 M_CORESIGHT, M_WAITOK | M_ZERO); 360 pdata->bus_type = CORESIGHT_BUS_ACPI; 361 362 mtx_init(&pdata->mtx_lock, "Coresight Platform Data", NULL, MTX_DEF); 363 TAILQ_INIT(&pdata->endpoints); 364 365 coresight_acpi_get_cpu(dev, pdata); 366 coresight_acpi_get_ports(dev, pdata); 367 368 if (bootverbose) 369 printf("Total ports: in %d out %d\n", 370 pdata->in_ports, pdata->out_ports); 371 372 return (pdata); 373 } 374