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
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                               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
acpi_resource_parse(device_t dev,ACPI_HANDLE handle,const char * path,void * arg,const struct acpi_resource_parse_ops * ops)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
acpi_resource_parse_any(device_t dev,ACPI_HANDLE handle,const char * path,void * arg,const struct acpi_resource_parse_ops * ops)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
acpi_resource_print(device_t dev,struct acpi_resources * res)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
acpi_resource_cleanup(struct acpi_resources * res)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 *
acpi_res_io(struct acpi_resources * res,int idx)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 *
acpi_res_iorange(struct acpi_resources * res,int idx)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 *
acpi_res_mem(struct acpi_resources * res,int idx)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 *
acpi_res_memrange(struct acpi_resources * res,int idx)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 *
acpi_res_irq(struct acpi_resources * res,int idx)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 *
acpi_res_drq(struct acpi_resources * res,int idx)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
acpi_res_parse_init(device_t dev,void * arg,void ** contextp)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
acpi_res_parse_fini(device_t dev,void * context)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
acpi_res_parse_ioport(device_t dev,void * context,uint32_t base,uint32_t length)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
acpi_res_parse_iorange(device_t dev,void * context,uint32_t low,uint32_t high,uint32_t length,uint32_t align)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
acpi_res_parse_memory(device_t dev,void * context,uint64_t base,uint64_t length,uint64_t xbase)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
acpi_res_parse_memrange(device_t dev,void * context,uint64_t low,uint64_t high,uint64_t length,uint64_t align)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
acpi_res_parse_irq(device_t dev,void * context,uint32_t irq,uint32_t type)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
acpi_res_parse_drq(device_t dev,void * context,uint32_t drq)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
acpi_res_parse_start_dep(device_t dev,void * context,int preference)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
acpi_res_parse_end_dep(device_t dev,void * context)951 acpi_res_parse_end_dep(device_t dev, void *context)
952 {
953 
954           /* Nothing to do. */
955 }
956