acpi_util.c revision 1.9 1 /* $NetBSD: acpi_util.c,v 1.9 2017/12/10 16:51:30 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.9 2017/12/10 16:51:30 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)
521 {
522 ACPI_STATUS rv;
523 ACPI_HANDLE hdl = (void *)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(irq->ar_irq, intr, iarg);
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