1 /* $NetBSD: acpi_util.c,v 1.14 2018/11/16 23:05:50 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum of By Noon Software, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright 2001, 2003 Wasabi Systems, Inc. 34 * All rights reserved. 35 * 36 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed for the NetBSD Project by 49 * Wasabi Systems, Inc. 50 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 51 * or promote products derived from this software without specific prior 52 * written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 * POSSIBILITY OF SUCH DAMAGE. 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.14 2018/11/16 23:05:50 jmcneill Exp $"); 69 70 #include <sys/param.h> 71 #include <sys/kmem.h> 72 #include <sys/cpu.h> 73 74 #include <dev/acpi/acpireg.h> 75 #include <dev/acpi/acpivar.h> 76 #include <dev/acpi/acpi_intr.h> 77 78 #include <machine/acpi_machdep.h> 79 80 #define _COMPONENT ACPI_BUS_COMPONENT 81 ACPI_MODULE_NAME ("acpi_util") 82 83 static void acpi_clean_node(ACPI_HANDLE, void *); 84 85 static const char * const acpicpu_ids[] = { 86 "ACPI0007", 87 NULL 88 }; 89 90 /* 91 * Evaluate an integer object. 92 */ 93 ACPI_STATUS 94 acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp) 95 { 96 ACPI_OBJECT obj; 97 ACPI_BUFFER buf; 98 ACPI_STATUS rv; 99 100 if (handle == NULL) 101 handle = ACPI_ROOT_OBJECT; 102 103 (void)memset(&obj, 0, sizeof(obj)); 104 buf.Pointer = &obj; 105 buf.Length = sizeof(obj); 106 107 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 108 109 if (ACPI_FAILURE(rv)) 110 return rv; 111 112 /* Check that evaluation produced a return value. */ 113 if (buf.Length == 0) 114 return AE_NULL_OBJECT; 115 116 if (obj.Type != ACPI_TYPE_INTEGER) 117 return AE_TYPE; 118 119 if (valp != NULL) 120 *valp = obj.Integer.Value; 121 122 return AE_OK; 123 } 124 125 /* 126 * Evaluate an integer object with a single integer input parameter. 127 */ 128 ACPI_STATUS 129 acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val) 130 { 131 ACPI_OBJECT_LIST arg; 132 ACPI_OBJECT obj; 133 134 if (handle == NULL) 135 handle = ACPI_ROOT_OBJECT; 136 137 obj.Type = ACPI_TYPE_INTEGER; 138 obj.Integer.Value = val; 139 140 arg.Count = 1; 141 arg.Pointer = &obj; 142 143 return AcpiEvaluateObject(handle, path, &arg, NULL); 144 } 145 146 /* 147 * Evaluate a (Unicode) string object. 148 */ 149 ACPI_STATUS 150 acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp) 151 { 152 ACPI_OBJECT *obj; 153 ACPI_BUFFER buf; 154 ACPI_STATUS rv; 155 156 rv = acpi_eval_struct(handle, path, &buf); 157 158 if (ACPI_FAILURE(rv)) 159 return rv; 160 161 obj = buf.Pointer; 162 163 if (obj->Type != ACPI_TYPE_STRING) { 164 rv = AE_TYPE; 165 goto out; 166 } 167 168 if (obj->String.Length == 0) { 169 rv = AE_BAD_DATA; 170 goto out; 171 } 172 173 *stringp = ACPI_ALLOCATE(obj->String.Length + 1); 174 175 if (*stringp == NULL) { 176 rv = AE_NO_MEMORY; 177 goto out; 178 } 179 180 (void)memcpy(*stringp, obj->String.Pointer, obj->String.Length); 181 182 (*stringp)[obj->String.Length] = '\0'; 183 184 out: 185 ACPI_FREE(buf.Pointer); 186 187 return rv; 188 } 189 190 /* 191 * Evaluate a structure. Caller must free buf.Pointer by ACPI_FREE(). 192 */ 193 ACPI_STATUS 194 acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *buf) 195 { 196 197 if (handle == NULL) 198 handle = ACPI_ROOT_OBJECT; 199 200 buf->Pointer = NULL; 201 buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; 202 203 return AcpiEvaluateObject(handle, path, NULL, buf); 204 } 205 206 /* 207 * Evaluate a reference handle from an element in a package. 208 */ 209 ACPI_STATUS 210 acpi_eval_reference_handle(ACPI_OBJECT *elm, ACPI_HANDLE *handle) 211 { 212 213 if (elm == NULL || handle == NULL) 214 return AE_BAD_PARAMETER; 215 216 switch (elm->Type) { 217 218 case ACPI_TYPE_ANY: 219 case ACPI_TYPE_LOCAL_REFERENCE: 220 221 if (elm->Reference.Handle == NULL) 222 return AE_NULL_ENTRY; 223 224 *handle = elm->Reference.Handle; 225 226 return AE_OK; 227 228 case ACPI_TYPE_STRING: 229 return AcpiGetHandle(NULL, elm->String.Pointer, handle); 230 231 default: 232 return AE_TYPE; 233 } 234 } 235 236 /* 237 * Iterate over all objects in a package, and pass them all 238 * to a function. If the called function returns non-AE_OK, 239 * the iteration is stopped and that value is returned. 240 */ 241 ACPI_STATUS 242 acpi_foreach_package_object(ACPI_OBJECT *pkg, 243 ACPI_STATUS (*func)(ACPI_OBJECT *, void *), void *arg) 244 { 245 ACPI_STATUS rv = AE_OK; 246 uint32_t i; 247 248 if (pkg == NULL) 249 return AE_BAD_PARAMETER; 250 251 if (pkg->Type != ACPI_TYPE_PACKAGE) 252 return AE_TYPE; 253 254 for (i = 0; i < pkg->Package.Count; i++) { 255 256 rv = (*func)(&pkg->Package.Elements[i], arg); 257 258 if (ACPI_FAILURE(rv)) 259 break; 260 } 261 262 return rv; 263 } 264 265 /* 266 * Fetch data info the specified (empty) ACPI buffer. 267 * Caller must free buf.Pointer by ACPI_FREE(). 268 */ 269 ACPI_STATUS 270 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 271 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 272 { 273 274 buf->Pointer = NULL; 275 buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; 276 277 return (*getit)(handle, buf); 278 } 279 280 /* 281 * Return a complete pathname from a handle. 282 * 283 * Note that the function uses static data storage; 284 * if the data is needed for future use, it should be 285 * copied before any subsequent calls overwrite it. 286 */ 287 const char * 288 acpi_name(ACPI_HANDLE handle) 289 { 290 static char name[80]; 291 ACPI_BUFFER buf; 292 ACPI_STATUS rv; 293 294 if (handle == NULL) 295 handle = ACPI_ROOT_OBJECT; 296 297 buf.Pointer = name; 298 buf.Length = sizeof(name); 299 300 rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf); 301 302 if (ACPI_FAILURE(rv)) 303 return "UNKNOWN"; 304 305 return name; 306 } 307 308 /* 309 * Match given IDs against _HID and _CIDs. 310 */ 311 int 312 acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids) 313 { 314 uint32_t i, n; 315 char *id; 316 317 while (*ids) { 318 319 if ((ad->Valid & ACPI_VALID_HID) != 0) { 320 321 if (pmatch(ad->HardwareId.String, *ids, NULL) == 2) 322 return 1; 323 } 324 325 if ((ad->Valid & ACPI_VALID_CID) != 0) { 326 327 n = ad->CompatibleIdList.Count; 328 329 for (i = 0; i < n; i++) { 330 331 id = ad->CompatibleIdList.Ids[i].String; 332 333 if (pmatch(id, *ids, NULL) == 2) 334 return 1; 335 } 336 } 337 338 ids++; 339 } 340 341 return 0; 342 } 343 344 /* 345 * Match a PCI-defined bass-class, sub-class, and programming interface 346 * against a handle's _CLS object. 347 */ 348 int 349 acpi_match_class(ACPI_HANDLE handle, uint8_t pci_class, uint8_t pci_subclass, 350 uint8_t pci_interface) 351 { 352 ACPI_BUFFER buf; 353 ACPI_OBJECT *obj; 354 ACPI_STATUS rv; 355 int match = 0; 356 357 rv = acpi_eval_struct(handle, "_CLS", &buf); 358 if (ACPI_FAILURE(rv)) 359 goto done; 360 361 obj = buf.Pointer; 362 if (obj->Type != ACPI_TYPE_PACKAGE) 363 goto done; 364 if (obj->Package.Count != 3) 365 goto done; 366 if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER || 367 obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER || 368 obj->Package.Elements[2].Type != ACPI_TYPE_INTEGER) 369 goto done; 370 371 match = obj->Package.Elements[0].Integer.Value == pci_class && 372 obj->Package.Elements[1].Integer.Value == pci_subclass && 373 obj->Package.Elements[2].Integer.Value == pci_interface; 374 375 done: 376 if (buf.Pointer) 377 ACPI_FREE(buf.Pointer); 378 return match; 379 } 380 381 /* 382 * Match a device node from a handle. 383 */ 384 struct acpi_devnode * 385 acpi_match_node(ACPI_HANDLE handle) 386 { 387 struct acpi_devnode *ad; 388 ACPI_STATUS rv; 389 390 if (handle == NULL) 391 return NULL; 392 393 rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad); 394 395 if (ACPI_FAILURE(rv)) 396 return NULL; 397 398 return ad; 399 } 400 401 /* 402 * Permanently associate a device node with a handle. 403 */ 404 void 405 acpi_match_node_init(struct acpi_devnode *ad) 406 { 407 (void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad); 408 } 409 410 static void 411 acpi_clean_node(ACPI_HANDLE handle, void *aux) 412 { 413 /* Nothing. */ 414 } 415 416 /* 417 * Match a handle from a cpu_info. Returns NULL on failure. 418 * 419 * Note that acpi_match_node() can be used if the device node 420 * is also required. 421 */ 422 ACPI_HANDLE 423 acpi_match_cpu_info(struct cpu_info *ci) 424 { 425 struct acpi_softc *sc = acpi_softc; 426 struct acpi_devnode *ad; 427 ACPI_INTEGER val; 428 ACPI_OBJECT *obj; 429 ACPI_BUFFER buf; 430 ACPI_HANDLE hdl; 431 ACPI_STATUS rv; 432 433 if (sc == NULL || acpi_active == 0) 434 return NULL; 435 436 /* 437 * CPUs are declared in the ACPI namespace 438 * either as a Processor() or as a Device(). 439 * In both cases the MADT entries are used 440 * for the match (see ACPI 4.0, section 8.4). 441 */ 442 SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { 443 444 hdl = ad->ad_handle; 445 446 switch (ad->ad_type) { 447 448 case ACPI_TYPE_DEVICE: 449 450 if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0) 451 break; 452 453 rv = acpi_eval_integer(hdl, "_UID", &val); 454 455 if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid) 456 return hdl; 457 458 break; 459 460 case ACPI_TYPE_PROCESSOR: 461 462 rv = acpi_eval_struct(hdl, NULL, &buf); 463 464 if (ACPI_FAILURE(rv)) 465 break; 466 467 obj = buf.Pointer; 468 469 if (obj->Processor.ProcId == ci->ci_acpiid) { 470 ACPI_FREE(buf.Pointer); 471 return hdl; 472 } 473 474 ACPI_FREE(buf.Pointer); 475 break; 476 } 477 } 478 479 return NULL; 480 } 481 482 /* 483 * Match a CPU from a handle. Returns NULL on failure. 484 */ 485 struct cpu_info * 486 acpi_match_cpu_handle(ACPI_HANDLE hdl) 487 { 488 struct cpu_info *ci; 489 ACPI_DEVICE_INFO *di; 490 CPU_INFO_ITERATOR cii; 491 ACPI_INTEGER val; 492 ACPI_OBJECT *obj; 493 ACPI_BUFFER buf; 494 ACPI_STATUS rv; 495 496 ci = NULL; 497 di = NULL; 498 buf.Pointer = NULL; 499 500 rv = AcpiGetObjectInfo(hdl, &di); 501 502 if (ACPI_FAILURE(rv)) 503 return NULL; 504 505 switch (di->Type) { 506 507 case ACPI_TYPE_DEVICE: 508 509 if (acpi_match_hid(di, acpicpu_ids) == 0) 510 goto out; 511 512 rv = acpi_eval_integer(hdl, "_UID", &val); 513 514 if (ACPI_FAILURE(rv)) 515 goto out; 516 517 break; 518 519 case ACPI_TYPE_PROCESSOR: 520 521 rv = acpi_eval_struct(hdl, NULL, &buf); 522 523 if (ACPI_FAILURE(rv)) 524 goto out; 525 526 obj = buf.Pointer; 527 val = obj->Processor.ProcId; 528 break; 529 530 default: 531 goto out; 532 } 533 534 for (CPU_INFO_FOREACH(cii, ci)) { 535 536 if (ci->ci_acpiid == val) 537 goto out; 538 } 539 540 ci = NULL; 541 542 out: 543 if (di != NULL) 544 ACPI_FREE(di); 545 546 if (buf.Pointer != NULL) 547 ACPI_FREE(buf.Pointer); 548 549 return ci; 550 } 551 552 struct acpi_irq_handler { 553 ACPI_HANDLE aih_hdl; 554 uint32_t aih_irq; 555 void *aih_ih; 556 }; 557 558 void * 559 acpi_intr_establish(device_t dev, uint64_t c, int ipl, bool mpsafe, 560 int (*intr)(void *), void *iarg, const char *xname) 561 { 562 ACPI_STATUS rv; 563 ACPI_HANDLE hdl = (void *)(uintptr_t)c; 564 struct acpi_resources res; 565 struct acpi_irq *irq; 566 struct acpi_irq_handler *aih = NULL; 567 void *ih; 568 569 rv = acpi_resource_parse(dev, hdl, "_CRS", &res, 570 &acpi_resource_parse_ops_quiet); 571 if (ACPI_FAILURE(rv)) 572 return NULL; 573 574 irq = acpi_res_irq(&res, 0); 575 if (irq == NULL) 576 goto end; 577 578 const int type = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL; 579 ih = acpi_md_intr_establish(irq->ar_irq, ipl, type, intr, iarg, mpsafe, xname); 580 if (ih == NULL) 581 goto end; 582 583 aih = kmem_alloc(sizeof(struct acpi_irq_handler), KM_SLEEP); 584 aih->aih_hdl = hdl; 585 aih->aih_irq = irq->ar_irq; 586 aih->aih_ih = ih; 587 588 end: 589 acpi_resource_cleanup(&res); 590 return aih; 591 } 592 593 void 594 acpi_intr_disestablish(void *c) 595 { 596 struct acpi_irq_handler *aih = c; 597 598 acpi_md_intr_disestablish(aih->aih_ih); 599 kmem_free(aih, sizeof(struct acpi_irq_handler)); 600 } 601 602 const char * 603 acpi_intr_string(void *c, char *buf, size_t size) 604 { 605 struct acpi_irq_handler *aih = c; 606 intr_handle_t ih = aih->aih_irq; 607 608 return intr_string(ih, buf, size); 609 } 610