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