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