xref: /netbsd-src/sys/dev/acpi/acpi_util.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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