acpi_resource.c revision 1.44 1 /* $NetBSD: acpi_resource.c,v 1.44 2025/01/02 16:32:34 andvar Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*-
39 * Copyright (c) 2000 Michael Smith
40 * Copyright (c) 2000 BSDi
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 */
64
65 /*
66 * ACPI resource parsing.
67 */
68
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: acpi_resource.c,v 1.44 2025/01/02 16:32:34 andvar Exp $");
71
72 #include <sys/param.h>
73 #include <sys/device.h>
74 #include <sys/systm.h>
75
76 #include <dev/acpi/acpireg.h>
77 #include <dev/acpi/acpivar.h>
78
79 #define _COMPONENT ACPI_RESOURCE_COMPONENT
80 ACPI_MODULE_NAME("RESOURCE")
81
82 static ACPI_STATUS acpi_resource_parse_callback(ACPI_RESOURCE *, void *);
83
84 struct resource_parse_callback_arg {
85 const struct acpi_resource_parse_ops *ops;
86 bool include_producer;
87 device_t dev;
88 void *context;
89 };
90
91 static ACPI_STATUS
92 acpi_resource_parse_callback(ACPI_RESOURCE *res, void *context)
93 {
94 struct resource_parse_callback_arg *arg = context;
95 const struct acpi_resource_parse_ops *ops;
96 int i;
97
98 ACPI_FUNCTION_TRACE(__func__);
99
100 ops = arg->ops;
101
102 switch (res->Type) {
103 case ACPI_RESOURCE_TYPE_END_TAG:
104 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
105 break;
106 case ACPI_RESOURCE_TYPE_FIXED_IO:
107 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
108 "FixedIo 0x%x/%u\n",
109 res->Data.FixedIo.Address,
110 res->Data.FixedIo.AddressLength));
111 if (ops->ioport)
112 (*ops->ioport)(arg->dev, arg->context,
113 res->Data.FixedIo.Address,
114 res->Data.FixedIo.AddressLength);
115 break;
116
117 case ACPI_RESOURCE_TYPE_IO:
118 if (res->Data.Io.Minimum ==
119 res->Data.Io.Maximum) {
120 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
121 "Io 0x%x/%u\n",
122 res->Data.Io.Minimum,
123 res->Data.Io.AddressLength));
124 if (ops->ioport)
125 (*ops->ioport)(arg->dev, arg->context,
126 res->Data.Io.Minimum,
127 res->Data.Io.AddressLength);
128 } else {
129 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
130 "Io 0x%x-0x%x/%u\n",
131 res->Data.Io.Minimum,
132 res->Data.Io.Maximum,
133 res->Data.Io.AddressLength));
134 if (ops->iorange)
135 (*ops->iorange)(arg->dev, arg->context,
136 res->Data.Io.Minimum,
137 res->Data.Io.Maximum,
138 res->Data.Io.AddressLength,
139 res->Data.Io.Alignment);
140 }
141 break;
142
143 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
144 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
145 "FixedMemory32 0x%x/%u\n",
146 res->Data.FixedMemory32.Address,
147 res->Data.FixedMemory32.AddressLength));
148 if (ops->memory)
149 (*ops->memory)(arg->dev, arg->context,
150 res->Data.FixedMemory32.Address,
151 res->Data.FixedMemory32.AddressLength,
152 res->Data.FixedMemory32.Address);
153 break;
154
155 case ACPI_RESOURCE_TYPE_MEMORY32:
156 if (res->Data.Memory32.Minimum ==
157 res->Data.Memory32.Maximum) {
158 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
159 "Memory32 0x%x/%u\n",
160 res->Data.Memory32.Minimum,
161 res->Data.Memory32.AddressLength));
162 if (ops->memory)
163 (*ops->memory)(arg->dev, arg->context,
164 res->Data.Memory32.Minimum,
165 res->Data.Memory32.AddressLength,
166 res->Data.Memory32.Minimum);
167 } else {
168 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
169 "Memory32 0x%x-0x%x/%u\n",
170 res->Data.Memory32.Minimum,
171 res->Data.Memory32.Maximum,
172 res->Data.Memory32.AddressLength));
173 if (ops->memrange)
174 (*ops->memrange)(arg->dev, arg->context,
175 res->Data.Memory32.Minimum,
176 res->Data.Memory32.Maximum,
177 res->Data.Memory32.AddressLength,
178 res->Data.Memory32.Alignment);
179 }
180 break;
181
182 case ACPI_RESOURCE_TYPE_MEMORY24:
183 if (res->Data.Memory24.Minimum ==
184 res->Data.Memory24.Maximum) {
185 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
186 "Memory24 0x%x/%u\n",
187 res->Data.Memory24.Minimum,
188 res->Data.Memory24.AddressLength));
189 if (ops->memory)
190 (*ops->memory)(arg->dev, arg->context,
191 res->Data.Memory24.Minimum,
192 res->Data.Memory24.AddressLength,
193 res->Data.Memory24.Minimum);
194 } else {
195 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
196 "Memory24 0x%x-0x%x/%u\n",
197 res->Data.Memory24.Minimum,
198 res->Data.Memory24.Maximum,
199 res->Data.Memory24.AddressLength));
200 if (ops->memrange)
201 (*ops->memrange)(arg->dev, arg->context,
202 res->Data.Memory24.Minimum,
203 res->Data.Memory24.Maximum,
204 res->Data.Memory24.AddressLength,
205 res->Data.Memory24.Alignment);
206 }
207 break;
208
209 case ACPI_RESOURCE_TYPE_IRQ:
210 for (i = 0; i < res->Data.Irq.InterruptCount; i++) {
211 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
212 "IRQ %u\n",
213 res->Data.Irq.Interrupts[i]));
214 if (ops->irq)
215 (*ops->irq)(arg->dev, arg->context,
216 res->Data.Irq.Interrupts[i],
217 res->Data.Irq.Triggering);
218 }
219 break;
220
221 case ACPI_RESOURCE_TYPE_DMA:
222 for (i = 0; i < res->Data.Dma.ChannelCount; i++) {
223 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
224 "DRQ %u\n",
225 res->Data.Dma.Channels[i]));
226 if (ops->drq)
227 (*ops->drq)(arg->dev, arg->context,
228 res->Data.Dma.Channels[i]);
229 }
230 break;
231
232 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
233 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
234 "Start dependent functions: %u\n",
235 res->Data.StartDpf.CompatibilityPriority));
236 if (ops->start_dep)
237 (*ops->start_dep)(arg->dev, arg->context,
238 res->Data.StartDpf.CompatibilityPriority);
239 break;
240
241 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
242 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
243 "End dependent functions\n"));
244 if (ops->end_dep)
245 (*ops->end_dep)(arg->dev, arg->context);
246 break;
247
248 case ACPI_RESOURCE_TYPE_ADDRESS32:
249 /* XXX Only fixed size supported for now */
250 if (res->Data.Address32.Address.AddressLength == 0)
251 break;
252 #define ADDRESS32_FIXED2(r) \
253 ((r)->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && \
254 (r)->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)
255 switch (res->Data.Address32.ResourceType) {
256 case ACPI_MEMORY_RANGE:
257 if (ADDRESS32_FIXED2(res)) {
258 if (ops->memory)
259 (*ops->memory)(arg->dev, arg->context,
260 res->Data.Address32.Address.Minimum,
261 res->Data.Address32.Address.AddressLength,
262 res->Data.Address32.Address.Minimum +
263 res->Data.Address32.Address.TranslationOffset);
264 } else {
265 if (ops->memrange)
266 (*ops->memrange)(arg->dev, arg->context,
267 res->Data.Address32.Address.Minimum,
268 res->Data.Address32.Address.Maximum,
269 res->Data.Address32.Address.AddressLength,
270 res->Data.Address32.Address.Granularity);
271 }
272 break;
273 case ACPI_IO_RANGE:
274 if (ADDRESS32_FIXED2(res)) {
275 if (ops->ioport)
276 (*ops->ioport)(arg->dev, arg->context,
277 res->Data.Address32.Address.Minimum,
278 res->Data.Address32.Address.AddressLength);
279 } else {
280 if (ops->iorange)
281 (*ops->iorange)(arg->dev, arg->context,
282 res->Data.Address32.Address.Minimum,
283 res->Data.Address32.Address.Maximum,
284 res->Data.Address32.Address.AddressLength,
285 res->Data.Address32.Address.Granularity);
286 }
287 break;
288 case ACPI_BUS_NUMBER_RANGE:
289 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
290 "Address32/BusNumber unimplemented\n"));
291 break;
292 }
293 #undef ADDRESS32_FIXED2
294 break;
295
296 case ACPI_RESOURCE_TYPE_ADDRESS16:
297 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
298 "Address16 unimplemented\n"));
299 break;
300
301 case ACPI_RESOURCE_TYPE_ADDRESS64:
302 #ifdef _LP64
303 /* XXX Only fixed size supported for now */
304 if (res->Data.Address64.Address.AddressLength == 0)
305 break;
306 #define ADDRESS64_FIXED2(r) \
307 ((r)->Data.Address64.MinAddressFixed == ACPI_ADDRESS_FIXED && \
308 (r)->Data.Address64.MaxAddressFixed == ACPI_ADDRESS_FIXED)
309 switch (res->Data.Address64.ResourceType) {
310 case ACPI_MEMORY_RANGE:
311 if (ADDRESS64_FIXED2(res)) {
312 if (ops->memory)
313 (*ops->memory)(arg->dev, arg->context,
314 res->Data.Address64.Address.Minimum,
315 res->Data.Address64.Address.AddressLength,
316 res->Data.Address64.Address.Minimum +
317 res->Data.Address64.Address.TranslationOffset);
318 } else {
319 if (ops->memrange)
320 (*ops->memrange)(arg->dev, arg->context,
321 res->Data.Address64.Address.Minimum,
322 res->Data.Address64.Address.Maximum,
323 res->Data.Address64.Address.AddressLength,
324 res->Data.Address64.Address.Granularity);
325 }
326 break;
327 case ACPI_IO_RANGE:
328 if (ADDRESS64_FIXED2(res)) {
329 if (ops->ioport)
330 (*ops->ioport)(arg->dev, arg->context,
331 res->Data.Address64.Address.Minimum,
332 res->Data.Address64.Address.AddressLength);
333 } else {
334 if (ops->iorange)
335 (*ops->iorange)(arg->dev, arg->context,
336 res->Data.Address64.Address.Minimum,
337 res->Data.Address64.Address.Maximum,
338 res->Data.Address64.Address.AddressLength,
339 res->Data.Address64.Address.Granularity);
340 }
341 break;
342 case ACPI_BUS_NUMBER_RANGE:
343 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
344 "Address64/BusNumber unimplemented\n"));
345 break;
346 }
347 #undef ADDRESS64_FIXED2
348 #else
349 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
350 "Address64 unimplemented\n"));
351 #endif
352 break;
353 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
354 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
355 "Extended address64 unimplemented\n"));
356 break;
357
358 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
359 if (!arg->include_producer &&
360 res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
361 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
362 "ignored ExtIRQ producer\n"));
363 break;
364 }
365 for (i = 0; i < res->Data.ExtendedIrq.InterruptCount; i++) {
366 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
367 "ExtIRQ %u\n",
368 res->Data.ExtendedIrq.Interrupts[i]));
369 if (ops->irq)
370 (*ops->irq)(arg->dev, arg->context,
371 res->Data.ExtendedIrq.Interrupts[i],
372 res->Data.ExtendedIrq.Triggering);
373 }
374 break;
375
376 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
377 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
378 "GenericRegister unimplemented\n"));
379 break;
380
381 case ACPI_RESOURCE_TYPE_VENDOR:
382 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
383 "VendorSpecific unimplemented\n"));
384 break;
385
386 default:
387 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
388 "Unknown resource type: %u\n", res->Type));
389 break;
390 }
391
392 return_ACPI_STATUS(AE_OK);
393 }
394
395
396 /*
397 * acpi_resource_parse:
398 *
399 * Parse a device node's resources and fill them in for the
400 * client.
401 *
402 * This API supports _CRS (current resources) and
403 * _PRS (possible resources).
404 *
405 * Note that it might be nice to also locate ACPI-specific resource
406 * items, such as GPE bits.
407 */
408 ACPI_STATUS
409 acpi_resource_parse(device_t dev, ACPI_HANDLE handle, const char *path,
410 void *arg, const struct acpi_resource_parse_ops *ops)
411 {
412 struct resource_parse_callback_arg cbarg;
413 ACPI_STATUS rv;
414
415 ACPI_FUNCTION_TRACE(__func__);
416
417 if (ops->init)
418 (*ops->init)(dev, arg, &cbarg.context);
419 else
420 cbarg.context = arg;
421 cbarg.ops = ops;
422 cbarg.dev = dev;
423 cbarg.include_producer = false;
424
425 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
426 &cbarg);
427 if (ACPI_FAILURE(rv)) {
428 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
429 path, AcpiFormatException(rv));
430 return_ACPI_STATUS(rv);
431 }
432
433 if (ops->fini)
434 (*ops->fini)(dev, cbarg.context);
435
436 return_ACPI_STATUS(AE_OK);
437 }
438
439 /*
440 * acpi_resource_parse_any:
441 *
442 * Parse a device node's resources and fill them in for the
443 * client. Like acpi_resource_parse, but doesn't skip ResourceProducer
444 * type resources.
445 */
446 ACPI_STATUS
447 acpi_resource_parse_any(device_t dev, ACPI_HANDLE handle, const char *path,
448 void *arg, const struct acpi_resource_parse_ops *ops)
449 {
450 struct resource_parse_callback_arg cbarg;
451 ACPI_STATUS rv;
452
453 ACPI_FUNCTION_TRACE(__func__);
454
455 if (ops->init)
456 (*ops->init)(dev, arg, &cbarg.context);
457 else
458 cbarg.context = arg;
459 cbarg.ops = ops;
460 cbarg.dev = dev;
461 cbarg.include_producer = true;
462
463 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
464 &cbarg);
465 if (ACPI_FAILURE(rv)) {
466 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
467 path, AcpiFormatException(rv));
468 return_ACPI_STATUS(rv);
469 }
470
471 if (ops->fini)
472 (*ops->fini)(dev, cbarg.context);
473
474 return_ACPI_STATUS(AE_OK);
475 }
476
477
478 /*
479 * acpi_resource_print:
480 *
481 * Print the resources assigned to a device.
482 */
483 void
484 acpi_resource_print(device_t dev, struct acpi_resources *res)
485 {
486 const char *sep;
487
488 if (SIMPLEQ_EMPTY(&res->ar_io) &&
489 SIMPLEQ_EMPTY(&res->ar_iorange) &&
490 SIMPLEQ_EMPTY(&res->ar_mem) &&
491 SIMPLEQ_EMPTY(&res->ar_memrange) &&
492 SIMPLEQ_EMPTY(&res->ar_irq) &&
493 SIMPLEQ_EMPTY(&res->ar_drq))
494 return;
495
496 aprint_normal(":");
497
498 if (SIMPLEQ_EMPTY(&res->ar_io) == 0) {
499 struct acpi_io *ar;
500
501 sep = "";
502 aprint_normal(" io ");
503 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
504 aprint_normal("%s0x%x", sep, ar->ar_base);
505 if (ar->ar_length > 1)
506 aprint_normal("-0x%x", ar->ar_base +
507 ar->ar_length - 1);
508 sep = ",";
509 }
510 }
511
512 /* XXX iorange */
513
514 if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) {
515 struct acpi_mem *ar;
516
517 sep = "";
518 aprint_normal(" mem ");
519 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
520 aprint_normal("%s0x%" PRIx64, sep,
521 (uint64_t)ar->ar_base);
522 if (ar->ar_length > 1)
523 aprint_normal("-0x%" PRIx64,
524 (uint64_t)ar->ar_base +
525 ar->ar_length - 1);
526 sep = ",";
527 }
528 }
529
530 /* XXX memrange */
531
532 if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) {
533 struct acpi_irq *ar;
534
535 sep = "";
536 aprint_normal(" irq ");
537 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
538 aprint_normal("%s%d", sep, ar->ar_irq);
539 sep = ",";
540 }
541 }
542
543 if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) {
544 struct acpi_drq *ar;
545
546 sep = "";
547 aprint_normal(" drq ");
548 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
549 aprint_normal("%s%d", sep, ar->ar_drq);
550 sep = ",";
551 }
552 }
553
554 aprint_normal("\n");
555 aprint_naive("\n");
556 }
557
558 /*
559 * acpi_resource_cleanup:
560 *
561 * Free all allocated buffers
562 */
563 void
564 acpi_resource_cleanup(struct acpi_resources *res)
565 {
566 while (!SIMPLEQ_EMPTY(&res->ar_io)) {
567 struct acpi_io *ar;
568 ar = SIMPLEQ_FIRST(&res->ar_io);
569 SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list);
570 ACPI_FREE(ar);
571 }
572
573 while (!SIMPLEQ_EMPTY(&res->ar_iorange)) {
574 struct acpi_iorange *ar;
575 ar = SIMPLEQ_FIRST(&res->ar_iorange);
576 SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list);
577 ACPI_FREE(ar);
578 }
579
580 while (!SIMPLEQ_EMPTY(&res->ar_mem)) {
581 struct acpi_mem *ar;
582 ar = SIMPLEQ_FIRST(&res->ar_mem);
583 SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list);
584 ACPI_FREE(ar);
585 }
586
587 while (!SIMPLEQ_EMPTY(&res->ar_memrange)) {
588 struct acpi_memrange *ar;
589 ar = SIMPLEQ_FIRST(&res->ar_memrange);
590 SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list);
591 ACPI_FREE(ar);
592 }
593
594 while (!SIMPLEQ_EMPTY(&res->ar_irq)) {
595 struct acpi_irq *ar;
596 ar = SIMPLEQ_FIRST(&res->ar_irq);
597 SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list);
598 ACPI_FREE(ar);
599 }
600
601 while (!SIMPLEQ_EMPTY(&res->ar_drq)) {
602 struct acpi_drq *ar;
603 ar = SIMPLEQ_FIRST(&res->ar_drq);
604 SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list);
605 ACPI_FREE(ar);
606 }
607
608 res->ar_nio = res->ar_niorange = res->ar_nmem =
609 res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0;
610 }
611
612 struct acpi_io *
613 acpi_res_io(struct acpi_resources *res, int idx)
614 {
615 struct acpi_io *ar;
616
617 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
618 if (ar->ar_index == idx)
619 return ar;
620 }
621 return NULL;
622 }
623
624 struct acpi_iorange *
625 acpi_res_iorange(struct acpi_resources *res, int idx)
626 {
627 struct acpi_iorange *ar;
628
629 SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) {
630 if (ar->ar_index == idx)
631 return ar;
632 }
633 return NULL;
634 }
635
636 struct acpi_mem *
637 acpi_res_mem(struct acpi_resources *res, int idx)
638 {
639 struct acpi_mem *ar;
640
641 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
642 if (ar->ar_index == idx)
643 return ar;
644 }
645 return NULL;
646 }
647
648 struct acpi_memrange *
649 acpi_res_memrange(struct acpi_resources *res, int idx)
650 {
651 struct acpi_memrange *ar;
652
653 SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) {
654 if (ar->ar_index == idx)
655 return ar;
656 }
657 return NULL;
658 }
659
660 struct acpi_irq *
661 acpi_res_irq(struct acpi_resources *res, int idx)
662 {
663 struct acpi_irq *ar;
664
665 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
666 if (ar->ar_index == idx)
667 return ar;
668 }
669 return NULL;
670 }
671
672 struct acpi_drq *
673 acpi_res_drq(struct acpi_resources *res, int idx)
674 {
675 struct acpi_drq *ar;
676
677 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
678 if (ar->ar_index == idx)
679 return ar;
680 }
681 return NULL;
682 }
683
684 /*****************************************************************************
685 * Default ACPI resource parse operations.
686 *****************************************************************************/
687
688 static void acpi_res_parse_init(device_t, void *, void **);
689 static void acpi_res_parse_fini(device_t, void *);
690
691 static void acpi_res_parse_ioport(device_t, void *, uint32_t,
692 uint32_t);
693 static void acpi_res_parse_iorange(device_t, void *, uint32_t,
694 uint32_t, uint32_t, uint32_t);
695
696 static void acpi_res_parse_memory(device_t, void *, uint64_t,
697 uint64_t, uint64_t);
698 static void acpi_res_parse_memrange(device_t, void *, uint64_t,
699 uint64_t, uint64_t, uint64_t);
700
701 static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t);
702 static void acpi_res_parse_drq(device_t, void *, uint32_t);
703
704 static void acpi_res_parse_start_dep(device_t, void *, int);
705 static void acpi_res_parse_end_dep(device_t, void *);
706
707 const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = {
708 .init = acpi_res_parse_init,
709 .fini = acpi_res_parse_fini,
710
711 .ioport = acpi_res_parse_ioport,
712 .iorange = acpi_res_parse_iorange,
713
714 .memory = acpi_res_parse_memory,
715 .memrange = acpi_res_parse_memrange,
716
717 .irq = acpi_res_parse_irq,
718 .drq = acpi_res_parse_drq,
719
720 .start_dep = acpi_res_parse_start_dep,
721 .end_dep = acpi_res_parse_end_dep,
722 };
723
724 const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = {
725 .init = acpi_res_parse_init,
726 .fini = NULL,
727
728 .ioport = acpi_res_parse_ioport,
729 .iorange = acpi_res_parse_iorange,
730
731 .memory = acpi_res_parse_memory,
732 .memrange = acpi_res_parse_memrange,
733
734 .irq = acpi_res_parse_irq,
735 .drq = acpi_res_parse_drq,
736
737 .start_dep = acpi_res_parse_start_dep,
738 .end_dep = acpi_res_parse_end_dep,
739 };
740
741 static void
742 acpi_res_parse_init(device_t dev, void *arg, void **contextp)
743 {
744 struct acpi_resources *res = arg;
745
746 SIMPLEQ_INIT(&res->ar_io);
747 res->ar_nio = 0;
748
749 SIMPLEQ_INIT(&res->ar_iorange);
750 res->ar_niorange = 0;
751
752 SIMPLEQ_INIT(&res->ar_mem);
753 res->ar_nmem = 0;
754
755 SIMPLEQ_INIT(&res->ar_memrange);
756 res->ar_nmemrange = 0;
757
758 SIMPLEQ_INIT(&res->ar_irq);
759 res->ar_nirq = 0;
760
761 SIMPLEQ_INIT(&res->ar_drq);
762 res->ar_ndrq = 0;
763
764 *contextp = res;
765 }
766
767 static void
768 acpi_res_parse_fini(device_t dev, void *context)
769 {
770 struct acpi_resources *res = context;
771
772 /* Print the resources we're using. */
773 acpi_resource_print(dev, res);
774 }
775
776 static void
777 acpi_res_parse_ioport(device_t dev, void *context, uint32_t base,
778 uint32_t length)
779 {
780 struct acpi_resources *res = context;
781 struct acpi_io *ar;
782
783 /*
784 * Check if there is another I/O port directly below/under
785 * this one.
786 */
787 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
788 if (ar->ar_base == base + length ) {
789 /*
790 * Entry just below existing entry - adjust
791 * the entry and return.
792 */
793 ar->ar_base = base;
794 ar->ar_length += length;
795 return;
796 } else if (ar->ar_base + ar->ar_length == base) {
797 /*
798 * Entry just above existing entry - adjust
799 * the entry and return.
800 */
801 ar->ar_length += length;
802 return;
803 }
804 }
805
806 /* IO and FixedIO I/O resource addresses are limited to 10/16-bit. */
807 if (base + length - 1 > UINT16_MAX) {
808 aprint_error_dev(dev, "ACPI: invalid I/O register resource %d,"
809 " base 0x%x, length %d\n",
810 res->ar_nio, base, length);
811 res->ar_nio++;
812 return;
813 }
814
815 ar = ACPI_ALLOCATE(sizeof(*ar));
816 if (ar == NULL) {
817 aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n",
818 res->ar_nio);
819 res->ar_nio++;
820 return;
821 }
822
823 ar->ar_index = res->ar_nio++;
824 ar->ar_base = base;
825 ar->ar_length = length;
826
827 SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list);
828 }
829
830 static void
831 acpi_res_parse_iorange(device_t dev, void *context, uint32_t low,
832 uint32_t high, uint32_t length, uint32_t align)
833 {
834 struct acpi_resources *res = context;
835 struct acpi_iorange *ar;
836
837 ar = ACPI_ALLOCATE(sizeof(*ar));
838 if (ar == NULL) {
839 aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n",
840 res->ar_niorange);
841 res->ar_niorange++;
842 return;
843 }
844
845 ar->ar_index = res->ar_niorange++;
846 ar->ar_low = low;
847 ar->ar_high = high;
848 ar->ar_length = length;
849 ar->ar_align = align;
850
851 SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list);
852 }
853
854 static void
855 acpi_res_parse_memory(device_t dev, void *context, uint64_t base,
856 uint64_t length, uint64_t xbase)
857 {
858 struct acpi_resources *res = context;
859 struct acpi_mem *ar;
860
861 ar = ACPI_ALLOCATE(sizeof(*ar));
862 if (ar == NULL) {
863 aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n",
864 res->ar_nmem);
865 res->ar_nmem++;
866 return;
867 }
868
869 ar->ar_index = res->ar_nmem++;
870 ar->ar_base = base;
871 ar->ar_length = length;
872 ar->ar_xbase = xbase;
873
874 SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list);
875 }
876
877 static void
878 acpi_res_parse_memrange(device_t dev, void *context, uint64_t low,
879 uint64_t high, uint64_t length, uint64_t align)
880 {
881 struct acpi_resources *res = context;
882 struct acpi_memrange *ar;
883
884 ar = ACPI_ALLOCATE(sizeof(*ar));
885 if (ar == NULL) {
886 aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n",
887 res->ar_nmemrange);
888 res->ar_nmemrange++;
889 return;
890 }
891
892 ar->ar_index = res->ar_nmemrange++;
893 ar->ar_low = low;
894 ar->ar_high = high;
895 ar->ar_length = length;
896 ar->ar_align = align;
897
898 SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list);
899 }
900
901 static void
902 acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type)
903 {
904 struct acpi_resources *res = context;
905 struct acpi_irq *ar;
906
907 ar = ACPI_ALLOCATE(sizeof(*ar));
908 if (ar == NULL) {
909 aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n",
910 res->ar_nirq);
911 res->ar_nirq++;
912 return;
913 }
914
915 ar->ar_index = res->ar_nirq++;
916 ar->ar_irq = irq;
917 ar->ar_type = type;
918
919 SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list);
920 }
921
922 static void
923 acpi_res_parse_drq(device_t dev, void *context, uint32_t drq)
924 {
925 struct acpi_resources *res = context;
926 struct acpi_drq *ar;
927
928 ar = ACPI_ALLOCATE(sizeof(*ar));
929 if (ar == NULL) {
930 aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n",
931 res->ar_ndrq);
932 res->ar_ndrq++;
933 return;
934 }
935
936 ar->ar_index = res->ar_ndrq++;
937 ar->ar_drq = drq;
938
939 SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list);
940 }
941
942 static void
943 acpi_res_parse_start_dep(device_t dev, void *context,
944 int preference)
945 {
946
947 aprint_error_dev(dev, "ACPI: dependent functions not supported\n");
948 }
949
950 static void
951 acpi_res_parse_end_dep(device_t dev, void *context)
952 {
953
954 /* Nothing to do. */
955 }
956