1 /* $NetBSD: acpi_util.c,v 1.11 2018/03/20 12:14:52 bouyer 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.11 2018/03/20 12:14:52 bouyer Exp $"); 69 70 #include <sys/param.h> 71 #include <sys/kmem.h> 72 73 #include <dev/acpi/acpireg.h> 74 #include <dev/acpi/acpivar.h> 75 #include <dev/acpi/acpi_intr.h> 76 77 #define _COMPONENT ACPI_BUS_COMPONENT 78 ACPI_MODULE_NAME ("acpi_util") 79 80 static void acpi_clean_node(ACPI_HANDLE, void *); 81 82 static const char * const acpicpu_ids[] = { 83 "ACPI0007", 84 NULL 85 }; 86 87 /* 88 * Evaluate an integer object. 89 */ 90 ACPI_STATUS 91 acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp) 92 { 93 ACPI_OBJECT obj; 94 ACPI_BUFFER buf; 95 ACPI_STATUS rv; 96 97 if (handle == NULL) 98 handle = ACPI_ROOT_OBJECT; 99 100 (void)memset(&obj, 0, sizeof(obj)); 101 buf.Pointer = &obj; 102 buf.Length = sizeof(obj); 103 104 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 105 106 if (ACPI_FAILURE(rv)) 107 return rv; 108 109 /* Check that evaluation produced a return value. */ 110 if (buf.Length == 0) 111 return AE_NULL_OBJECT; 112 113 if (obj.Type != ACPI_TYPE_INTEGER) 114 return AE_TYPE; 115 116 if (valp != NULL) 117 *valp = obj.Integer.Value; 118 119 return AE_OK; 120 } 121 122 /* 123 * Evaluate an integer object with a single integer input parameter. 124 */ 125 ACPI_STATUS 126 acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val) 127 { 128 ACPI_OBJECT_LIST arg; 129 ACPI_OBJECT obj; 130 131 if (handle == NULL) 132 handle = ACPI_ROOT_OBJECT; 133 134 obj.Type = ACPI_TYPE_INTEGER; 135 obj.Integer.Value = val; 136 137 arg.Count = 1; 138 arg.Pointer = &obj; 139 140 return AcpiEvaluateObject(handle, path, &arg, NULL); 141 } 142 143 /* 144 * Evaluate a (Unicode) string object. 145 */ 146 ACPI_STATUS 147 acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp) 148 { 149 ACPI_OBJECT *obj; 150 ACPI_BUFFER buf; 151 ACPI_STATUS rv; 152 153 rv = acpi_eval_struct(handle, path, &buf); 154 155 if (ACPI_FAILURE(rv)) 156 return rv; 157 158 obj = buf.Pointer; 159 160 if (obj->Type != ACPI_TYPE_STRING) { 161 rv = AE_TYPE; 162 goto out; 163 } 164 165 if (obj->String.Length == 0) { 166 rv = AE_BAD_DATA; 167 goto out; 168 } 169 170 *stringp = ACPI_ALLOCATE(obj->String.Length + 1); 171 172 if (*stringp == NULL) { 173 rv = AE_NO_MEMORY; 174 goto out; 175 } 176 177 (void)memcpy(*stringp, obj->String.Pointer, obj->String.Length); 178 179 (*stringp)[obj->String.Length] = '\0'; 180 181 out: 182 ACPI_FREE(buf.Pointer); 183 184 return rv; 185 } 186 187 /* 188 * Evaluate a structure. Caller must free buf.Pointer by ACPI_FREE(). 189 */ 190 ACPI_STATUS 191 acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *buf) 192 { 193 194 if (handle == NULL) 195 handle = ACPI_ROOT_OBJECT; 196 197 buf->Pointer = NULL; 198 buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; 199 200 return AcpiEvaluateObject(handle, path, NULL, buf); 201 } 202 203 /* 204 * Evaluate a reference handle from an element in a package. 205 */ 206 ACPI_STATUS 207 acpi_eval_reference_handle(ACPI_OBJECT *elm, ACPI_HANDLE *handle) 208 { 209 210 if (elm == NULL || handle == NULL) 211 return AE_BAD_PARAMETER; 212 213 switch (elm->Type) { 214 215 case ACPI_TYPE_ANY: 216 case ACPI_TYPE_LOCAL_REFERENCE: 217 218 if (elm->Reference.Handle == NULL) 219 return AE_NULL_ENTRY; 220 221 *handle = elm->Reference.Handle; 222 223 return AE_OK; 224 225 case ACPI_TYPE_STRING: 226 return AcpiGetHandle(NULL, elm->String.Pointer, handle); 227 228 default: 229 return AE_TYPE; 230 } 231 } 232 233 /* 234 * Iterate over all objects in a package, and pass them all 235 * to a function. If the called function returns non-AE_OK, 236 * the iteration is stopped and that value is returned. 237 */ 238 ACPI_STATUS 239 acpi_foreach_package_object(ACPI_OBJECT *pkg, 240 ACPI_STATUS (*func)(ACPI_OBJECT *, void *), void *arg) 241 { 242 ACPI_STATUS rv = AE_OK; 243 uint32_t i; 244 245 if (pkg == NULL) 246 return AE_BAD_PARAMETER; 247 248 if (pkg->Type != ACPI_TYPE_PACKAGE) 249 return AE_TYPE; 250 251 for (i = 0; i < pkg->Package.Count; i++) { 252 253 rv = (*func)(&pkg->Package.Elements[i], arg); 254 255 if (ACPI_FAILURE(rv)) 256 break; 257 } 258 259 return rv; 260 } 261 262 /* 263 * Fetch data info the specified (empty) ACPI buffer. 264 * Caller must free buf.Pointer by ACPI_FREE(). 265 */ 266 ACPI_STATUS 267 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 268 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 269 { 270 271 buf->Pointer = NULL; 272 buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; 273 274 return (*getit)(handle, buf); 275 } 276 277 /* 278 * Return a complete pathname from a handle. 279 * 280 * Note that the function uses static data storage; 281 * if the data is needed for future use, it should be 282 * copied before any subsequent calls overwrite it. 283 */ 284 const char * 285 acpi_name(ACPI_HANDLE handle) 286 { 287 static char name[80]; 288 ACPI_BUFFER buf; 289 ACPI_STATUS rv; 290 291 if (handle == NULL) 292 handle = ACPI_ROOT_OBJECT; 293 294 buf.Pointer = name; 295 buf.Length = sizeof(name); 296 297 rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf); 298 299 if (ACPI_FAILURE(rv)) 300 return "UNKNOWN"; 301 302 return name; 303 } 304 305 /* 306 * Match given IDs against _HID and _CIDs. 307 */ 308 int 309 acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids) 310 { 311 uint32_t i, n; 312 char *id; 313 314 while (*ids) { 315 316 if ((ad->Valid & ACPI_VALID_HID) != 0) { 317 318 if (pmatch(ad->HardwareId.String, *ids, NULL) == 2) 319 return 1; 320 } 321 322 if ((ad->Valid & ACPI_VALID_CID) != 0) { 323 324 n = ad->CompatibleIdList.Count; 325 326 for (i = 0; i < n; i++) { 327 328 id = ad->CompatibleIdList.Ids[i].String; 329 330 if (pmatch(id, *ids, NULL) == 2) 331 return 1; 332 } 333 } 334 335 ids++; 336 } 337 338 return 0; 339 } 340 341 /* 342 * Match a device node from a handle. 343 */ 344 struct acpi_devnode * 345 acpi_match_node(ACPI_HANDLE handle) 346 { 347 struct acpi_devnode *ad; 348 ACPI_STATUS rv; 349 350 if (handle == NULL) 351 return NULL; 352 353 rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad); 354 355 if (ACPI_FAILURE(rv)) 356 return NULL; 357 358 return ad; 359 } 360 361 /* 362 * Permanently associate a device node with a handle. 363 */ 364 void 365 acpi_match_node_init(struct acpi_devnode *ad) 366 { 367 (void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad); 368 } 369 370 static void 371 acpi_clean_node(ACPI_HANDLE handle, void *aux) 372 { 373 /* Nothing. */ 374 } 375 376 /* 377 * Match a handle from a cpu_info. Returns NULL on failure. 378 * 379 * Note that acpi_match_node() can be used if the device node 380 * is also required. 381 */ 382 ACPI_HANDLE 383 acpi_match_cpu_info(struct cpu_info *ci) 384 { 385 struct acpi_softc *sc = acpi_softc; 386 struct acpi_devnode *ad; 387 ACPI_INTEGER val; 388 ACPI_OBJECT *obj; 389 ACPI_BUFFER buf; 390 ACPI_HANDLE hdl; 391 ACPI_STATUS rv; 392 393 if (sc == NULL || acpi_active == 0) 394 return NULL; 395 396 /* 397 * CPUs are declared in the ACPI namespace 398 * either as a Processor() or as a Device(). 399 * In both cases the MADT entries are used 400 * for the match (see ACPI 4.0, section 8.4). 401 */ 402 SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { 403 404 hdl = ad->ad_handle; 405 406 switch (ad->ad_type) { 407 408 case ACPI_TYPE_DEVICE: 409 410 if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0) 411 break; 412 413 rv = acpi_eval_integer(hdl, "_UID", &val); 414 415 if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid) 416 return hdl; 417 418 break; 419 420 case ACPI_TYPE_PROCESSOR: 421 422 rv = acpi_eval_struct(hdl, NULL, &buf); 423 424 if (ACPI_FAILURE(rv)) 425 break; 426 427 obj = buf.Pointer; 428 429 if (obj->Processor.ProcId == ci->ci_acpiid) { 430 ACPI_FREE(buf.Pointer); 431 return hdl; 432 } 433 434 ACPI_FREE(buf.Pointer); 435 break; 436 } 437 } 438 439 return NULL; 440 } 441 442 /* 443 * Match a CPU from a handle. Returns NULL on failure. 444 */ 445 struct cpu_info * 446 acpi_match_cpu_handle(ACPI_HANDLE hdl) 447 { 448 struct cpu_info *ci; 449 ACPI_DEVICE_INFO *di; 450 CPU_INFO_ITERATOR cii; 451 ACPI_INTEGER val; 452 ACPI_OBJECT *obj; 453 ACPI_BUFFER buf; 454 ACPI_STATUS rv; 455 456 ci = NULL; 457 di = NULL; 458 buf.Pointer = NULL; 459 460 rv = AcpiGetObjectInfo(hdl, &di); 461 462 if (ACPI_FAILURE(rv)) 463 return NULL; 464 465 switch (di->Type) { 466 467 case ACPI_TYPE_DEVICE: 468 469 if (acpi_match_hid(di, acpicpu_ids) == 0) 470 goto out; 471 472 rv = acpi_eval_integer(hdl, "_UID", &val); 473 474 if (ACPI_FAILURE(rv)) 475 goto out; 476 477 break; 478 479 case ACPI_TYPE_PROCESSOR: 480 481 rv = acpi_eval_struct(hdl, NULL, &buf); 482 483 if (ACPI_FAILURE(rv)) 484 goto out; 485 486 obj = buf.Pointer; 487 val = obj->Processor.ProcId; 488 break; 489 490 default: 491 goto out; 492 } 493 494 for (CPU_INFO_FOREACH(cii, ci)) { 495 496 if (ci->ci_acpiid == val) 497 goto out; 498 } 499 500 ci = NULL; 501 502 out: 503 if (di != NULL) 504 ACPI_FREE(di); 505 506 if (buf.Pointer != NULL) 507 ACPI_FREE(buf.Pointer); 508 509 return ci; 510 } 511 512 struct acpi_irq_handler { 513 ACPI_HANDLE aih_hdl; 514 uint32_t aih_irq; 515 int (*aih_intr)(void *); 516 }; 517 518 void * 519 acpi_intr_establish(device_t dev, uint64_t c, 520 unsigned int (*intr)(void *), void *iarg, const char *xname) 521 { 522 ACPI_STATUS rv; 523 ACPI_HANDLE hdl = (void *)(uintptr_t)c; 524 struct acpi_resources res; 525 struct acpi_irq *irq; 526 struct acpi_irq_handler *aih = NULL; 527 528 rv = acpi_resource_parse(dev, hdl, "_CRS", &res, 529 &acpi_resource_parse_ops_quiet); 530 if (ACPI_FAILURE(rv)) 531 return NULL; 532 533 irq = acpi_res_irq(&res, 0); 534 if (irq == NULL) 535 goto end; 536 537 aih = kmem_alloc(sizeof(struct acpi_irq_handler), KM_NOSLEEP); 538 if (aih == NULL) 539 goto end; 540 541 aih->aih_hdl = hdl; 542 aih->aih_irq = irq->ar_irq; 543 rv = AcpiOsInstallInterruptHandler_xname(irq->ar_irq, intr, iarg, xname); 544 if (ACPI_FAILURE(rv)) { 545 kmem_free(aih, sizeof(struct acpi_irq_handler)); 546 aih = NULL; 547 } 548 end: 549 acpi_resource_cleanup(&res); 550 return aih; 551 } 552 553 void 554 acpi_intr_disestablish(void *c, unsigned int (*intr)(void *)) 555 { 556 struct acpi_irq_handler *aih = c; 557 558 AcpiOsRemoveInterruptHandler(aih->aih_irq, intr); 559 kmem_free(aih, sizeof(struct acpi_irq_handler)); 560 return; 561 } 562 563 const char * 564 acpi_intr_string(void *c, char *buf, size_t size) 565 { 566 struct acpi_irq_handler *aih = c; 567 intr_handle_t ih = aih->aih_irq; 568 569 return intr_string(ih, buf, size); 570 } 571