1 /* $NetBSD: acpi_resource.c,v 1.42 2021/08/07 18:39:40 jmcneill 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.42 2021/08/07 18:39:40 jmcneill 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
acpi_resource_parse_callback(ACPI_RESOURCE * res,void * context)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 (!arg->include_producer &&
252 res->Data.Address32.ProducerConsumer != ACPI_CONSUMER))
253 break;
254 #define ADDRESS32_FIXED2(r) \
255 ((r)->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && \
256 (r)->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)
257 switch (res->Data.Address32.ResourceType) {
258 case ACPI_MEMORY_RANGE:
259 if (ADDRESS32_FIXED2(res)) {
260 if (ops->memory)
261 (*ops->memory)(arg->dev, arg->context,
262 res->Data.Address32.Address.Minimum,
263 res->Data.Address32.Address.AddressLength,
264 res->Data.Address32.Address.Minimum +
265 res->Data.Address32.Address.TranslationOffset);
266 } else {
267 if (ops->memrange)
268 (*ops->memrange)(arg->dev, arg->context,
269 res->Data.Address32.Address.Minimum,
270 res->Data.Address32.Address.Maximum,
271 res->Data.Address32.Address.AddressLength,
272 res->Data.Address32.Address.Granularity);
273 }
274 break;
275 case ACPI_IO_RANGE:
276 if (ADDRESS32_FIXED2(res)) {
277 if (ops->ioport)
278 (*ops->ioport)(arg->dev, arg->context,
279 res->Data.Address32.Address.Minimum,
280 res->Data.Address32.Address.AddressLength);
281 } else {
282 if (ops->iorange)
283 (*ops->iorange)(arg->dev, arg->context,
284 res->Data.Address32.Address.Minimum,
285 res->Data.Address32.Address.Maximum,
286 res->Data.Address32.Address.AddressLength,
287 res->Data.Address32.Address.Granularity);
288 }
289 break;
290 case ACPI_BUS_NUMBER_RANGE:
291 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
292 "Address32/BusNumber unimplemented\n"));
293 break;
294 }
295 #undef ADDRESS32_FIXED2
296 break;
297
298 case ACPI_RESOURCE_TYPE_ADDRESS16:
299 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
300 "Address16 unimplemented\n"));
301 break;
302
303 case ACPI_RESOURCE_TYPE_ADDRESS64:
304 #ifdef _LP64
305 /* XXX Only fixed size supported for now */
306 if (res->Data.Address64.Address.AddressLength == 0 ||
307 (!arg->include_producer &&
308 res->Data.Address64.ProducerConsumer != ACPI_CONSUMER))
309 break;
310 #define ADDRESS64_FIXED2(r) \
311 ((r)->Data.Address64.MinAddressFixed == ACPI_ADDRESS_FIXED && \
312 (r)->Data.Address64.MaxAddressFixed == ACPI_ADDRESS_FIXED)
313 switch (res->Data.Address64.ResourceType) {
314 case ACPI_MEMORY_RANGE:
315 if (ADDRESS64_FIXED2(res)) {
316 if (ops->memory)
317 (*ops->memory)(arg->dev, arg->context,
318 res->Data.Address64.Address.Minimum,
319 res->Data.Address64.Address.AddressLength,
320 res->Data.Address64.Address.Minimum +
321 res->Data.Address64.Address.TranslationOffset);
322 } else {
323 if (ops->memrange)
324 (*ops->memrange)(arg->dev, arg->context,
325 res->Data.Address64.Address.Minimum,
326 res->Data.Address64.Address.Maximum,
327 res->Data.Address64.Address.AddressLength,
328 res->Data.Address64.Address.Granularity);
329 }
330 break;
331 case ACPI_IO_RANGE:
332 if (ADDRESS64_FIXED2(res)) {
333 if (ops->ioport)
334 (*ops->ioport)(arg->dev, arg->context,
335 res->Data.Address64.Address.Minimum,
336 res->Data.Address64.Address.AddressLength);
337 } else {
338 if (ops->iorange)
339 (*ops->iorange)(arg->dev, arg->context,
340 res->Data.Address64.Address.Minimum,
341 res->Data.Address64.Address.Maximum,
342 res->Data.Address64.Address.AddressLength,
343 res->Data.Address64.Address.Granularity);
344 }
345 break;
346 case ACPI_BUS_NUMBER_RANGE:
347 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
348 "Address64/BusNumber unimplemented\n"));
349 break;
350 }
351 #undef ADDRESS64_FIXED2
352 #else
353 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
354 "Address64 unimplemented\n"));
355 #endif
356 break;
357 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
358 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
359 "Extended address64 unimplemented\n"));
360 break;
361
362 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
363 if (!arg->include_producer &&
364 res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
365 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
366 "ignored ExtIRQ producer\n"));
367 break;
368 }
369 for (i = 0; i < res->Data.ExtendedIrq.InterruptCount; i++) {
370 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
371 "ExtIRQ %u\n",
372 res->Data.ExtendedIrq.Interrupts[i]));
373 if (ops->irq)
374 (*ops->irq)(arg->dev, arg->context,
375 res->Data.ExtendedIrq.Interrupts[i],
376 res->Data.ExtendedIrq.Triggering);
377 }
378 break;
379
380 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
381 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
382 "GenericRegister unimplemented\n"));
383 break;
384
385 case ACPI_RESOURCE_TYPE_VENDOR:
386 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
387 "VendorSpecific unimplemented\n"));
388 break;
389
390 default:
391 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
392 "Unknown resource type: %u\n", res->Type));
393 break;
394 }
395
396 return_ACPI_STATUS(AE_OK);
397 }
398
399
400 /*
401 * acpi_resource_parse:
402 *
403 * Parse a device node's resources and fill them in for the
404 * client.
405 *
406 * This API supports _CRS (current resources) and
407 * _PRS (possible resources).
408 *
409 * Note that it might be nice to also locate ACPI-specific resource
410 * items, such as GPE bits.
411 */
412 ACPI_STATUS
acpi_resource_parse(device_t dev,ACPI_HANDLE handle,const char * path,void * arg,const struct acpi_resource_parse_ops * ops)413 acpi_resource_parse(device_t dev, ACPI_HANDLE handle, const char *path,
414 void *arg, const struct acpi_resource_parse_ops *ops)
415 {
416 struct resource_parse_callback_arg cbarg;
417 ACPI_STATUS rv;
418
419 ACPI_FUNCTION_TRACE(__func__);
420
421 if (ops->init)
422 (*ops->init)(dev, arg, &cbarg.context);
423 else
424 cbarg.context = arg;
425 cbarg.ops = ops;
426 cbarg.dev = dev;
427 cbarg.include_producer = false;
428
429 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
430 &cbarg);
431 if (ACPI_FAILURE(rv)) {
432 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
433 path, AcpiFormatException(rv));
434 return_ACPI_STATUS(rv);
435 }
436
437 if (ops->fini)
438 (*ops->fini)(dev, cbarg.context);
439
440 return_ACPI_STATUS(AE_OK);
441 }
442
443 /*
444 * acpi_resource_parse_any:
445 *
446 * Parse a device node's resources and fill them in for the
447 * client. Like acpi_resource_parse, but doesn't skip ResourceProducer
448 * type resources.
449 */
450 ACPI_STATUS
acpi_resource_parse_any(device_t dev,ACPI_HANDLE handle,const char * path,void * arg,const struct acpi_resource_parse_ops * ops)451 acpi_resource_parse_any(device_t dev, ACPI_HANDLE handle, const char *path,
452 void *arg, const struct acpi_resource_parse_ops *ops)
453 {
454 struct resource_parse_callback_arg cbarg;
455 ACPI_STATUS rv;
456
457 ACPI_FUNCTION_TRACE(__func__);
458
459 if (ops->init)
460 (*ops->init)(dev, arg, &cbarg.context);
461 else
462 cbarg.context = arg;
463 cbarg.ops = ops;
464 cbarg.dev = dev;
465 cbarg.include_producer = true;
466
467 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
468 &cbarg);
469 if (ACPI_FAILURE(rv)) {
470 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
471 path, AcpiFormatException(rv));
472 return_ACPI_STATUS(rv);
473 }
474
475 if (ops->fini)
476 (*ops->fini)(dev, cbarg.context);
477
478 return_ACPI_STATUS(AE_OK);
479 }
480
481
482 /*
483 * acpi_resource_print:
484 *
485 * Print the resources assigned to a device.
486 */
487 void
acpi_resource_print(device_t dev,struct acpi_resources * res)488 acpi_resource_print(device_t dev, struct acpi_resources *res)
489 {
490 const char *sep;
491
492 if (SIMPLEQ_EMPTY(&res->ar_io) &&
493 SIMPLEQ_EMPTY(&res->ar_iorange) &&
494 SIMPLEQ_EMPTY(&res->ar_mem) &&
495 SIMPLEQ_EMPTY(&res->ar_memrange) &&
496 SIMPLEQ_EMPTY(&res->ar_irq) &&
497 SIMPLEQ_EMPTY(&res->ar_drq))
498 return;
499
500 aprint_normal(":");
501
502 if (SIMPLEQ_EMPTY(&res->ar_io) == 0) {
503 struct acpi_io *ar;
504
505 sep = "";
506 aprint_normal(" io ");
507 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
508 aprint_normal("%s0x%x", sep, ar->ar_base);
509 if (ar->ar_length > 1)
510 aprint_normal("-0x%x", ar->ar_base +
511 ar->ar_length - 1);
512 sep = ",";
513 }
514 }
515
516 /* XXX iorange */
517
518 if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) {
519 struct acpi_mem *ar;
520
521 sep = "";
522 aprint_normal(" mem ");
523 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
524 aprint_normal("%s0x%" PRIx64, sep,
525 (uint64_t)ar->ar_base);
526 if (ar->ar_length > 1)
527 aprint_normal("-0x%" PRIx64,
528 (uint64_t)ar->ar_base +
529 ar->ar_length - 1);
530 sep = ",";
531 }
532 }
533
534 /* XXX memrange */
535
536 if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) {
537 struct acpi_irq *ar;
538
539 sep = "";
540 aprint_normal(" irq ");
541 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
542 aprint_normal("%s%d", sep, ar->ar_irq);
543 sep = ",";
544 }
545 }
546
547 if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) {
548 struct acpi_drq *ar;
549
550 sep = "";
551 aprint_normal(" drq ");
552 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
553 aprint_normal("%s%d", sep, ar->ar_drq);
554 sep = ",";
555 }
556 }
557
558 aprint_normal("\n");
559 aprint_naive("\n");
560 }
561
562 /*
563 * acpi_resource_cleanup:
564 *
565 * Free all allocated buffers
566 */
567 void
acpi_resource_cleanup(struct acpi_resources * res)568 acpi_resource_cleanup(struct acpi_resources *res)
569 {
570 while (!SIMPLEQ_EMPTY(&res->ar_io)) {
571 struct acpi_io *ar;
572 ar = SIMPLEQ_FIRST(&res->ar_io);
573 SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list);
574 ACPI_FREE(ar);
575 }
576
577 while (!SIMPLEQ_EMPTY(&res->ar_iorange)) {
578 struct acpi_iorange *ar;
579 ar = SIMPLEQ_FIRST(&res->ar_iorange);
580 SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list);
581 ACPI_FREE(ar);
582 }
583
584 while (!SIMPLEQ_EMPTY(&res->ar_mem)) {
585 struct acpi_mem *ar;
586 ar = SIMPLEQ_FIRST(&res->ar_mem);
587 SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list);
588 ACPI_FREE(ar);
589 }
590
591 while (!SIMPLEQ_EMPTY(&res->ar_memrange)) {
592 struct acpi_memrange *ar;
593 ar = SIMPLEQ_FIRST(&res->ar_memrange);
594 SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list);
595 ACPI_FREE(ar);
596 }
597
598 while (!SIMPLEQ_EMPTY(&res->ar_irq)) {
599 struct acpi_irq *ar;
600 ar = SIMPLEQ_FIRST(&res->ar_irq);
601 SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list);
602 ACPI_FREE(ar);
603 }
604
605 while (!SIMPLEQ_EMPTY(&res->ar_drq)) {
606 struct acpi_drq *ar;
607 ar = SIMPLEQ_FIRST(&res->ar_drq);
608 SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list);
609 ACPI_FREE(ar);
610 }
611
612 res->ar_nio = res->ar_niorange = res->ar_nmem =
613 res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0;
614 }
615
616 struct acpi_io *
acpi_res_io(struct acpi_resources * res,int idx)617 acpi_res_io(struct acpi_resources *res, int idx)
618 {
619 struct acpi_io *ar;
620
621 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
622 if (ar->ar_index == idx)
623 return ar;
624 }
625 return NULL;
626 }
627
628 struct acpi_iorange *
acpi_res_iorange(struct acpi_resources * res,int idx)629 acpi_res_iorange(struct acpi_resources *res, int idx)
630 {
631 struct acpi_iorange *ar;
632
633 SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) {
634 if (ar->ar_index == idx)
635 return ar;
636 }
637 return NULL;
638 }
639
640 struct acpi_mem *
acpi_res_mem(struct acpi_resources * res,int idx)641 acpi_res_mem(struct acpi_resources *res, int idx)
642 {
643 struct acpi_mem *ar;
644
645 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
646 if (ar->ar_index == idx)
647 return ar;
648 }
649 return NULL;
650 }
651
652 struct acpi_memrange *
acpi_res_memrange(struct acpi_resources * res,int idx)653 acpi_res_memrange(struct acpi_resources *res, int idx)
654 {
655 struct acpi_memrange *ar;
656
657 SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) {
658 if (ar->ar_index == idx)
659 return ar;
660 }
661 return NULL;
662 }
663
664 struct acpi_irq *
acpi_res_irq(struct acpi_resources * res,int idx)665 acpi_res_irq(struct acpi_resources *res, int idx)
666 {
667 struct acpi_irq *ar;
668
669 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
670 if (ar->ar_index == idx)
671 return ar;
672 }
673 return NULL;
674 }
675
676 struct acpi_drq *
acpi_res_drq(struct acpi_resources * res,int idx)677 acpi_res_drq(struct acpi_resources *res, int idx)
678 {
679 struct acpi_drq *ar;
680
681 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
682 if (ar->ar_index == idx)
683 return ar;
684 }
685 return NULL;
686 }
687
688 /*****************************************************************************
689 * Default ACPI resource parse operations.
690 *****************************************************************************/
691
692 static void acpi_res_parse_init(device_t, void *, void **);
693 static void acpi_res_parse_fini(device_t, void *);
694
695 static void acpi_res_parse_ioport(device_t, void *, uint32_t,
696 uint32_t);
697 static void acpi_res_parse_iorange(device_t, void *, uint32_t,
698 uint32_t, uint32_t, uint32_t);
699
700 static void acpi_res_parse_memory(device_t, void *, uint64_t,
701 uint64_t, uint64_t);
702 static void acpi_res_parse_memrange(device_t, void *, uint64_t,
703 uint64_t, uint64_t, uint64_t);
704
705 static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t);
706 static void acpi_res_parse_drq(device_t, void *, uint32_t);
707
708 static void acpi_res_parse_start_dep(device_t, void *, int);
709 static void acpi_res_parse_end_dep(device_t, void *);
710
711 const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = {
712 .init = acpi_res_parse_init,
713 .fini = acpi_res_parse_fini,
714
715 .ioport = acpi_res_parse_ioport,
716 .iorange = acpi_res_parse_iorange,
717
718 .memory = acpi_res_parse_memory,
719 .memrange = acpi_res_parse_memrange,
720
721 .irq = acpi_res_parse_irq,
722 .drq = acpi_res_parse_drq,
723
724 .start_dep = acpi_res_parse_start_dep,
725 .end_dep = acpi_res_parse_end_dep,
726 };
727
728 const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = {
729 .init = acpi_res_parse_init,
730 .fini = NULL,
731
732 .ioport = acpi_res_parse_ioport,
733 .iorange = acpi_res_parse_iorange,
734
735 .memory = acpi_res_parse_memory,
736 .memrange = acpi_res_parse_memrange,
737
738 .irq = acpi_res_parse_irq,
739 .drq = acpi_res_parse_drq,
740
741 .start_dep = acpi_res_parse_start_dep,
742 .end_dep = acpi_res_parse_end_dep,
743 };
744
745 static void
acpi_res_parse_init(device_t dev,void * arg,void ** contextp)746 acpi_res_parse_init(device_t dev, void *arg, void **contextp)
747 {
748 struct acpi_resources *res = arg;
749
750 SIMPLEQ_INIT(&res->ar_io);
751 res->ar_nio = 0;
752
753 SIMPLEQ_INIT(&res->ar_iorange);
754 res->ar_niorange = 0;
755
756 SIMPLEQ_INIT(&res->ar_mem);
757 res->ar_nmem = 0;
758
759 SIMPLEQ_INIT(&res->ar_memrange);
760 res->ar_nmemrange = 0;
761
762 SIMPLEQ_INIT(&res->ar_irq);
763 res->ar_nirq = 0;
764
765 SIMPLEQ_INIT(&res->ar_drq);
766 res->ar_ndrq = 0;
767
768 *contextp = res;
769 }
770
771 static void
acpi_res_parse_fini(device_t dev,void * context)772 acpi_res_parse_fini(device_t dev, void *context)
773 {
774 struct acpi_resources *res = context;
775
776 /* Print the resources we're using. */
777 acpi_resource_print(dev, res);
778 }
779
780 static void
acpi_res_parse_ioport(device_t dev,void * context,uint32_t base,uint32_t length)781 acpi_res_parse_ioport(device_t dev, void *context, uint32_t base,
782 uint32_t length)
783 {
784 struct acpi_resources *res = context;
785 struct acpi_io *ar;
786
787 /*
788 * Check if there is another I/O port directly below/under
789 * this one.
790 */
791 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
792 if (ar->ar_base == base + length ) {
793 /*
794 * Entry just below existing entry - adjust
795 * the entry and return.
796 */
797 ar->ar_base = base;
798 ar->ar_length += length;
799 return;
800 } else if (ar->ar_base + ar->ar_length == base) {
801 /*
802 * Entry just above existing entry - adjust
803 * the entry and return.
804 */
805 ar->ar_length += length;
806 return;
807 }
808 }
809
810 ar = ACPI_ALLOCATE(sizeof(*ar));
811 if (ar == NULL) {
812 aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n",
813 res->ar_nio);
814 res->ar_nio++;
815 return;
816 }
817
818 ar->ar_index = res->ar_nio++;
819 ar->ar_base = base;
820 ar->ar_length = length;
821
822 SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list);
823 }
824
825 static void
acpi_res_parse_iorange(device_t dev,void * context,uint32_t low,uint32_t high,uint32_t length,uint32_t align)826 acpi_res_parse_iorange(device_t dev, void *context, uint32_t low,
827 uint32_t high, uint32_t length, uint32_t align)
828 {
829 struct acpi_resources *res = context;
830 struct acpi_iorange *ar;
831
832 ar = ACPI_ALLOCATE(sizeof(*ar));
833 if (ar == NULL) {
834 aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n",
835 res->ar_niorange);
836 res->ar_niorange++;
837 return;
838 }
839
840 ar->ar_index = res->ar_niorange++;
841 ar->ar_low = low;
842 ar->ar_high = high;
843 ar->ar_length = length;
844 ar->ar_align = align;
845
846 SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list);
847 }
848
849 static void
acpi_res_parse_memory(device_t dev,void * context,uint64_t base,uint64_t length,uint64_t xbase)850 acpi_res_parse_memory(device_t dev, void *context, uint64_t base,
851 uint64_t length, uint64_t xbase)
852 {
853 struct acpi_resources *res = context;
854 struct acpi_mem *ar;
855
856 ar = ACPI_ALLOCATE(sizeof(*ar));
857 if (ar == NULL) {
858 aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n",
859 res->ar_nmem);
860 res->ar_nmem++;
861 return;
862 }
863
864 ar->ar_index = res->ar_nmem++;
865 ar->ar_base = base;
866 ar->ar_length = length;
867 ar->ar_xbase = xbase;
868
869 SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list);
870 }
871
872 static void
acpi_res_parse_memrange(device_t dev,void * context,uint64_t low,uint64_t high,uint64_t length,uint64_t align)873 acpi_res_parse_memrange(device_t dev, void *context, uint64_t low,
874 uint64_t high, uint64_t length, uint64_t align)
875 {
876 struct acpi_resources *res = context;
877 struct acpi_memrange *ar;
878
879 ar = ACPI_ALLOCATE(sizeof(*ar));
880 if (ar == NULL) {
881 aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n",
882 res->ar_nmemrange);
883 res->ar_nmemrange++;
884 return;
885 }
886
887 ar->ar_index = res->ar_nmemrange++;
888 ar->ar_low = low;
889 ar->ar_high = high;
890 ar->ar_length = length;
891 ar->ar_align = align;
892
893 SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list);
894 }
895
896 static void
acpi_res_parse_irq(device_t dev,void * context,uint32_t irq,uint32_t type)897 acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type)
898 {
899 struct acpi_resources *res = context;
900 struct acpi_irq *ar;
901
902 ar = ACPI_ALLOCATE(sizeof(*ar));
903 if (ar == NULL) {
904 aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n",
905 res->ar_nirq);
906 res->ar_nirq++;
907 return;
908 }
909
910 ar->ar_index = res->ar_nirq++;
911 ar->ar_irq = irq;
912 ar->ar_type = type;
913
914 SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list);
915 }
916
917 static void
acpi_res_parse_drq(device_t dev,void * context,uint32_t drq)918 acpi_res_parse_drq(device_t dev, void *context, uint32_t drq)
919 {
920 struct acpi_resources *res = context;
921 struct acpi_drq *ar;
922
923 ar = ACPI_ALLOCATE(sizeof(*ar));
924 if (ar == NULL) {
925 aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n",
926 res->ar_ndrq);
927 res->ar_ndrq++;
928 return;
929 }
930
931 ar->ar_index = res->ar_ndrq++;
932 ar->ar_drq = drq;
933
934 SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list);
935 }
936
937 static void
acpi_res_parse_start_dep(device_t dev,void * context,int preference)938 acpi_res_parse_start_dep(device_t dev, void *context,
939 int preference)
940 {
941
942 aprint_error_dev(dev, "ACPI: dependent functions not supported\n");
943 }
944
945 static void
acpi_res_parse_end_dep(device_t dev,void * context)946 acpi_res_parse_end_dep(device_t dev, void *context)
947 {
948
949 /* Nothing to do. */
950 }
951