acpi_util.c revision 1.11.2.1 1 /* $NetBSD: acpi_util.c,v 1.11.2.1 2019/06/10 22:07:05 christos 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.2.1 2019/06/10 22:07:05 christos 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
611 /*
612 * USB Device-Specific Data (_DSD) support
613 */
614
615 static UINT8 acpi_dsd_uuid[ACPI_UUID_LENGTH] = {
616 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
617 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
618 };
619
620 ACPI_STATUS
621 acpi_dsd_integer(ACPI_HANDLE handle, const char *prop, ACPI_INTEGER *val)
622 {
623 ACPI_OBJECT *obj, *uuid, *props, *pobj, *propkey, *propval;
624 ACPI_STATUS rv;
625 ACPI_BUFFER buf;
626 int n;
627
628 buf.Pointer = NULL;
629 buf.Length = ACPI_ALLOCATE_BUFFER;
630
631 rv = AcpiEvaluateObjectTyped(handle, "_DSD", NULL, &buf, ACPI_TYPE_PACKAGE);
632 if (ACPI_FAILURE(rv))
633 return rv;
634
635 props = NULL;
636 obj = (ACPI_OBJECT *)buf.Pointer;
637 for (n = 0; (n + 1) < obj->Package.Count; n += 2) {
638 uuid = &obj->Package.Elements[n];
639 if (uuid->Buffer.Length == ACPI_UUID_LENGTH &&
640 memcmp(uuid->Buffer.Pointer, acpi_dsd_uuid, ACPI_UUID_LENGTH) == 0) {
641 props = &obj->Package.Elements[n + 1];
642 break;
643 }
644 }
645 if (props == NULL) {
646 rv = AE_NOT_FOUND;
647 goto done;
648 }
649
650 for (n = 0; n < props->Package.Count; n++) {
651 pobj = &props->Package.Elements[n];
652 if (pobj->Type != ACPI_TYPE_PACKAGE || pobj->Package.Count != 2)
653 continue;
654 propkey = (ACPI_OBJECT *)&pobj->Package.Elements[0];
655 propval = (ACPI_OBJECT *)&pobj->Package.Elements[1];
656 if (propkey->Type != ACPI_TYPE_STRING)
657 continue;
658 if (strcmp(propkey->String.Pointer, prop) != 0)
659 continue;
660
661 if (propval->Type != ACPI_TYPE_INTEGER) {
662 rv = AE_TYPE;
663 } else {
664 *val = propval->Integer.Value;
665 rv = AE_OK;
666 }
667 break;
668 }
669
670 done:
671 ACPI_FREE(buf.Pointer);
672 return rv;
673 }
674