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 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 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 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 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 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 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 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 * 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 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 * 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 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 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 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 * 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