4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2016, Joyent, Inc.
28 * Copyright (c) 2009-2010, Intel Corporation.
29 * All rights reserved.
32 #include <sys/types.h>
33 #include <sys/cmn_err.h>
34 #include <sys/sysmacros.h>
35 #include <sys/sunddi.h>
36 #include <sys/sunndi.h>
37 #include <sys/acpi/acpi.h>
38 #include <sys/acpica.h>
39 #include <sys/acpidev.h>
40 #include <sys/acpidev_rsc.h>
41 #include <sys/acpidev_impl.h>
43 #define ACPIDEV_RES_INIT_ITEMS 8
44 #define ACPIDEV_RES_INCR_ITEMS 8
46 /* Data structure to hold parsed resources during walking. */
47 struct acpidev_resource_handle
{
48 boolean_t acpidev_consumer
;
49 int acpidev_reg_count
;
51 acpidev_phys_spec_t
*acpidev_regp
;
52 acpidev_phys_spec_t acpidev_regs
[ACPIDEV_RES_INIT_ITEMS
];
53 int acpidev_range_count
;
54 int acpidev_range_max
;
55 acpidev_ranges_t
*acpidev_rangep
;
56 acpidev_ranges_t acpidev_ranges
[ACPIDEV_RES_INIT_ITEMS
];
57 int acpidev_bus_count
;
59 acpidev_bus_range_t
*acpidev_busp
;
60 acpidev_bus_range_t acpidev_buses
[ACPIDEV_RES_INIT_ITEMS
];
61 int acpidev_irq_count
;
62 int acpidev_irqp
[ACPIDEV_RES_IRQ_MAX
];
63 int acpidev_dma_count
;
64 int acpidev_dmap
[ACPIDEV_RES_DMA_MAX
];
67 acpidev_resource_handle_t
68 acpidev_resource_handle_alloc(boolean_t consumer
)
70 acpidev_resource_handle_t rhdl
;
72 rhdl
= kmem_zalloc(sizeof (*rhdl
), KM_SLEEP
);
73 rhdl
->acpidev_consumer
= consumer
;
74 rhdl
->acpidev_reg_max
= ACPIDEV_RES_INIT_ITEMS
;
75 rhdl
->acpidev_regp
= rhdl
->acpidev_regs
;
76 rhdl
->acpidev_range_max
= ACPIDEV_RES_INIT_ITEMS
;
77 rhdl
->acpidev_rangep
= rhdl
->acpidev_ranges
;
78 rhdl
->acpidev_bus_max
= ACPIDEV_RES_INIT_ITEMS
;
79 rhdl
->acpidev_busp
= rhdl
->acpidev_buses
;
85 acpidev_resource_handle_free(acpidev_resource_handle_t rhdl
)
91 if (rhdl
->acpidev_regp
!= rhdl
->acpidev_regs
) {
92 sz
= sizeof (acpidev_phys_spec_t
) *
93 rhdl
->acpidev_reg_max
;
94 kmem_free(rhdl
->acpidev_regp
, sz
);
96 if (rhdl
->acpidev_rangep
!= rhdl
->acpidev_ranges
) {
97 sz
= sizeof (acpidev_ranges_t
) *
98 rhdl
->acpidev_range_max
;
99 kmem_free(rhdl
->acpidev_rangep
, sz
);
101 if (rhdl
->acpidev_busp
!= rhdl
->acpidev_buses
) {
102 sz
= sizeof (acpidev_bus_range_t
) *
103 rhdl
->acpidev_bus_max
;
104 kmem_free(rhdl
->acpidev_busp
, sz
);
106 kmem_free(rhdl
, sizeof (struct acpidev_resource_handle
));
111 acpidev_resource_handle_grow(acpidev_resource_handle_t rhdl
)
115 if (rhdl
->acpidev_reg_count
== rhdl
->acpidev_reg_max
) {
116 acpidev_phys_spec_t
*regp
;
118 /* Prefer linear incremental here. */
119 rhdl
->acpidev_reg_max
+= ACPIDEV_RES_INCR_ITEMS
;
120 sz
= sizeof (*regp
) * rhdl
->acpidev_reg_max
;
121 regp
= kmem_zalloc(sz
, KM_SLEEP
);
122 sz
= sizeof (*regp
) * rhdl
->acpidev_reg_count
;
123 bcopy(rhdl
->acpidev_regp
, regp
, sz
);
124 if (rhdl
->acpidev_regp
!= rhdl
->acpidev_regs
) {
125 kmem_free(rhdl
->acpidev_regp
, sz
);
127 rhdl
->acpidev_regp
= regp
;
130 if (rhdl
->acpidev_range_count
== rhdl
->acpidev_range_max
) {
131 acpidev_ranges_t
*rngp
;
133 /* Prefer linear incremental here. */
134 rhdl
->acpidev_range_max
+= ACPIDEV_RES_INCR_ITEMS
;
135 sz
= sizeof (*rngp
) * rhdl
->acpidev_range_max
;
136 rngp
= kmem_zalloc(sz
, KM_SLEEP
);
137 sz
= sizeof (*rngp
) * rhdl
->acpidev_range_count
;
138 bcopy(rhdl
->acpidev_rangep
, rngp
, sz
);
139 if (rhdl
->acpidev_rangep
!= rhdl
->acpidev_ranges
) {
140 kmem_free(rhdl
->acpidev_rangep
, sz
);
142 rhdl
->acpidev_rangep
= rngp
;
145 if (rhdl
->acpidev_bus_count
== rhdl
->acpidev_bus_max
) {
146 acpidev_bus_range_t
*busp
;
148 /* Prefer linear incremental here. */
149 rhdl
->acpidev_bus_max
+= ACPIDEV_RES_INCR_ITEMS
;
150 sz
= sizeof (*busp
) * rhdl
->acpidev_bus_max
;
151 busp
= kmem_zalloc(sz
, KM_SLEEP
);
152 sz
= sizeof (*busp
) * rhdl
->acpidev_bus_count
;
153 bcopy(rhdl
->acpidev_busp
, busp
, sz
);
154 if (rhdl
->acpidev_busp
!= rhdl
->acpidev_buses
) {
155 kmem_free(rhdl
->acpidev_busp
, sz
);
157 rhdl
->acpidev_busp
= busp
;
162 acpidev_resource_insert_reg(acpidev_resource_handle_t rhdl
,
163 acpidev_regspec_t
*regp
)
165 ASSERT(rhdl
!= NULL
);
166 ASSERT(regp
!= NULL
);
167 if (rhdl
->acpidev_reg_count
>= rhdl
->acpidev_reg_max
) {
168 acpidev_resource_handle_grow(rhdl
);
170 ASSERT(rhdl
->acpidev_reg_count
< rhdl
->acpidev_reg_max
);
171 rhdl
->acpidev_regp
[rhdl
->acpidev_reg_count
] = *regp
;
172 rhdl
->acpidev_reg_count
++;
178 acpidev_resource_get_regs(acpidev_resource_handle_t rhdl
,
179 uint_t mask
, uint_t value
, acpidev_regspec_t
*regp
, uint_t
*cntp
)
183 ASSERT(rhdl
!= NULL
);
184 ASSERT(cntp
!= NULL
);
185 if (rhdl
== NULL
|| cntp
== NULL
|| (regp
== NULL
&& *cntp
!= 0)) {
186 return (AE_BAD_PARAMETER
);
188 for (i
= 0, j
= 0; i
< rhdl
->acpidev_reg_count
; i
++) {
189 if ((rhdl
->acpidev_regp
[i
].phys_hi
& mask
) == value
) {
191 regp
[j
] = rhdl
->acpidev_regp
[i
];
206 acpidev_resource_get_reg_count(acpidev_resource_handle_t rhdl
,
207 uint_t mask
, uint_t value
)
211 ASSERT(rhdl
!= NULL
);
212 for (i
= 0, j
= 0; i
< rhdl
->acpidev_reg_count
; i
++) {
213 if ((rhdl
->acpidev_regp
[i
].phys_hi
& mask
) == value
) {
222 acpidev_resource_insert_range(acpidev_resource_handle_t rhdl
,
223 acpidev_ranges_t
*rangep
)
225 ASSERT(rhdl
!= NULL
);
226 ASSERT(rangep
!= NULL
);
227 if (rhdl
->acpidev_range_count
>= rhdl
->acpidev_range_max
) {
228 acpidev_resource_handle_grow(rhdl
);
230 ASSERT(rhdl
->acpidev_range_count
< rhdl
->acpidev_range_max
);
231 rhdl
->acpidev_rangep
[rhdl
->acpidev_range_count
] = *rangep
;
232 rhdl
->acpidev_range_count
++;
238 acpidev_resource_get_ranges(acpidev_resource_handle_t rhdl
,
239 uint_t mask
, uint_t value
, acpidev_ranges_t
*rangep
, uint_t
*cntp
)
243 ASSERT(rhdl
!= NULL
);
244 ASSERT(cntp
!= NULL
);
245 if (rhdl
== NULL
|| cntp
== NULL
|| (rangep
== NULL
&& *cntp
!= 0)) {
246 return (AE_BAD_PARAMETER
);
248 for (i
= 0, j
= 0; i
< rhdl
->acpidev_range_count
; i
++) {
249 if ((rhdl
->acpidev_rangep
[i
].child_hi
& mask
) == value
) {
251 rangep
[j
] = rhdl
->acpidev_rangep
[i
];
266 acpidev_resource_get_range_count(acpidev_resource_handle_t rhdl
,
267 uint_t mask
, uint_t value
)
271 ASSERT(rhdl
!= NULL
);
272 for (i
= 0, j
= 0; i
< rhdl
->acpidev_range_count
; i
++) {
273 if ((rhdl
->acpidev_rangep
[i
].child_hi
& mask
) == value
) {
282 acpidev_resource_insert_bus(acpidev_resource_handle_t rhdl
,
283 acpidev_bus_range_t
*busp
)
285 ASSERT(rhdl
!= NULL
);
286 ASSERT(busp
!= NULL
);
287 if (rhdl
->acpidev_bus_count
>= rhdl
->acpidev_bus_max
) {
288 acpidev_resource_handle_grow(rhdl
);
290 ASSERT(rhdl
->acpidev_bus_count
< rhdl
->acpidev_bus_max
);
291 rhdl
->acpidev_busp
[rhdl
->acpidev_bus_count
] = *busp
;
292 rhdl
->acpidev_bus_count
++;
298 acpidev_resource_get_buses(acpidev_resource_handle_t rhdl
,
299 acpidev_bus_range_t
*busp
, uint_t
*cntp
)
303 ASSERT(rhdl
!= NULL
);
304 ASSERT(cntp
!= NULL
);
305 if (rhdl
== NULL
|| cntp
== NULL
|| (busp
== NULL
&& *cntp
!= 0)) {
306 return (AE_BAD_PARAMETER
);
308 for (i
= 0, j
= 0; i
< rhdl
->acpidev_bus_count
; i
++) {
310 busp
[j
] = rhdl
->acpidev_busp
[i
];
324 acpidev_resource_get_bus_count(acpidev_resource_handle_t rhdl
)
326 ASSERT(rhdl
!= NULL
);
327 return (rhdl
->acpidev_bus_count
);
331 acpidev_resource_insert_dma(acpidev_resource_handle_t rhdl
, int dma
)
333 ASSERT(rhdl
!= NULL
);
334 if (rhdl
->acpidev_dma_count
>= ACPIDEV_RES_DMA_MAX
) {
335 ACPIDEV_DEBUG(CE_WARN
,
336 "!acpidev: too many DMA resources, max %u.",
337 ACPIDEV_RES_DMA_MAX
);
340 rhdl
->acpidev_dmap
[rhdl
->acpidev_dma_count
] = dma
;
341 rhdl
->acpidev_dma_count
++;
347 acpidev_resource_get_dmas(acpidev_resource_handle_t rhdl
,
348 uint_t
*dmap
, uint_t
*cntp
)
352 ASSERT(rhdl
!= NULL
);
353 ASSERT(cntp
!= NULL
);
354 if (rhdl
== NULL
|| cntp
== NULL
|| (dmap
== NULL
&& *cntp
!= 0)) {
355 return (AE_BAD_PARAMETER
);
357 for (i
= 0, j
= 0; i
< rhdl
->acpidev_dma_count
; i
++) {
359 dmap
[j
] = rhdl
->acpidev_dmap
[i
];
373 acpidev_resource_get_dma_count(acpidev_resource_handle_t rhdl
)
375 ASSERT(rhdl
!= NULL
);
376 return (rhdl
->acpidev_dma_count
);
380 acpidev_resource_insert_irq(acpidev_resource_handle_t rhdl
, int irq
)
382 ASSERT(rhdl
!= NULL
);
383 if (rhdl
->acpidev_irq_count
>= ACPIDEV_RES_IRQ_MAX
) {
384 ACPIDEV_DEBUG(CE_WARN
,
385 "!acpidev: too many IRQ resources, max %u.",
386 ACPIDEV_RES_IRQ_MAX
);
389 rhdl
->acpidev_irqp
[rhdl
->acpidev_irq_count
] = irq
;
390 rhdl
->acpidev_irq_count
++;
396 acpidev_resource_get_irqs(acpidev_resource_handle_t rhdl
,
397 uint_t
*irqp
, uint_t
*cntp
)
401 ASSERT(rhdl
!= NULL
);
402 ASSERT(cntp
!= NULL
);
403 if (rhdl
== NULL
|| cntp
== NULL
|| (irqp
== NULL
&& *cntp
!= 0)) {
404 return (AE_BAD_PARAMETER
);
406 for (i
= 0, j
= 0; i
< rhdl
->acpidev_irq_count
; i
++) {
408 irqp
[j
] = rhdl
->acpidev_irqp
[i
];
422 acpidev_resource_get_irq_count(acpidev_resource_handle_t rhdl
)
424 ASSERT(rhdl
!= NULL
);
425 return (rhdl
->acpidev_irq_count
);
429 acpidev_resource_address64(acpidev_resource_handle_t rhdl
,
430 ACPI_RESOURCE_ADDRESS64
*addrp
)
432 ACPI_STATUS rc
= AE_OK
;
435 ASSERT(addrp
!= NULL
&& rhdl
!= NULL
);
436 if (addrp
->Address
.AddressLength
== 0) {
440 switch (addrp
->ResourceType
) {
441 case ACPI_MEMORY_RANGE
:
442 high
= ACPIDEV_REG_TYPE_MEMORY
;
443 if (addrp
->Decode
== ACPI_SUB_DECODE
) {
444 high
|= ACPIDEV_REG_SUB_DEC
;
446 if (addrp
->Info
.Mem
.Translation
) {
447 high
|= ACPIDEV_REG_TRANSLATED
;
449 if (addrp
->Info
.Mem
.Caching
== ACPI_NON_CACHEABLE_MEMORY
) {
450 high
|= ACPIDEV_REG_MEM_COHERENT_NC
;
451 } else if (addrp
->Info
.Mem
.Caching
== ACPI_CACHABLE_MEMORY
) {
452 high
|= ACPIDEV_REG_MEM_COHERENT_CA
;
453 } else if (addrp
->Info
.Mem
.Caching
==
454 ACPI_WRITE_COMBINING_MEMORY
) {
455 high
|= ACPIDEV_REG_MEM_COHERENT_WC
;
456 } else if (addrp
->Info
.Mem
.Caching
==
457 ACPI_PREFETCHABLE_MEMORY
) {
458 high
|= ACPIDEV_REG_MEM_COHERENT_PF
;
460 ACPIDEV_DEBUG(CE_WARN
,
461 "!acpidev: unknown memory caching type %u.",
462 addrp
->Info
.Mem
.Caching
);
466 if (addrp
->Info
.Mem
.WriteProtect
== ACPI_READ_WRITE_MEMORY
) {
467 high
|= ACPIDEV_REG_MEM_WRITABLE
;
470 /* Generate 'reg' for producer. */
471 if (addrp
->ProducerConsumer
== ACPI_CONSUMER
&&
472 rhdl
->acpidev_consumer
== B_TRUE
) {
473 acpidev_regspec_t reg
;
476 reg
.phys_mid
= addrp
->Address
.Minimum
>> 32;
477 reg
.phys_low
= addrp
->Address
.Minimum
& 0xFFFFFFFF;
478 reg
.size_hi
= addrp
->Address
.AddressLength
>> 32;
479 reg
.size_low
= addrp
->Address
.AddressLength
&
481 rc
= acpidev_resource_insert_reg(rhdl
, ®
);
482 if (ACPI_FAILURE(rc
)) {
483 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
484 "insert regspec into resource handle.");
486 /* Generate 'ranges' for producer. */
487 } else if (addrp
->ProducerConsumer
== ACPI_PRODUCER
&&
488 rhdl
->acpidev_consumer
== B_FALSE
) {
490 acpidev_ranges_t range
;
492 range
.child_hi
= high
;
493 range
.child_mid
= addrp
->Address
.Minimum
>> 32;
494 range
.child_low
= addrp
->Address
.Minimum
& 0xFFFFFFFF;
495 /* It's IO on parent side if Translation is true. */
496 if (addrp
->Info
.Mem
.Translation
) {
497 range
.parent_hi
= ACPIDEV_REG_TYPE_IO
;
499 range
.parent_hi
= high
;
501 paddr
= addrp
->Address
.Minimum
+
502 addrp
->Address
.TranslationOffset
;
503 range
.parent_mid
= paddr
>> 32;
504 range
.parent_low
= paddr
& 0xFFFFFFFF;
505 range
.size_hi
= addrp
->Address
.AddressLength
>> 32;
506 range
.size_low
= addrp
->Address
.AddressLength
&
508 rc
= acpidev_resource_insert_range(rhdl
, &range
);
509 if (ACPI_FAILURE(rc
)) {
510 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
511 "insert range into resource handle.");
517 high
= ACPIDEV_REG_TYPE_IO
;
518 if (addrp
->Decode
== ACPI_SUB_DECODE
) {
519 high
|= ACPIDEV_REG_SUB_DEC
;
521 if (addrp
->Info
.Io
.Translation
) {
522 high
|= ACPIDEV_REG_TRANSLATED
;
524 if (addrp
->Info
.Io
.RangeType
== ACPI_NON_ISA_ONLY_RANGES
) {
525 high
|= ACPIDEV_REG_IO_RANGE_NONISA
;
526 } else if (addrp
->Info
.Io
.RangeType
== ACPI_ISA_ONLY_RANGES
) {
527 high
|= ACPIDEV_REG_IO_RANGE_ISA
;
528 } else if (addrp
->Info
.Io
.RangeType
== ACPI_ENTIRE_RANGE
) {
529 high
|= ACPIDEV_REG_IO_RANGE_FULL
;
531 ACPIDEV_DEBUG(CE_WARN
,
532 "!acpidev: unknown IO range type %u.",
533 addrp
->Info
.Io
.RangeType
);
537 if (addrp
->Info
.Io
.TranslationType
== ACPI_SPARSE_TRANSLATION
) {
538 high
|= ACPIDEV_REG_IO_SPARSE
;
541 /* Generate 'reg' for producer. */
542 if (addrp
->ProducerConsumer
== ACPI_CONSUMER
&&
543 rhdl
->acpidev_consumer
== B_TRUE
) {
544 acpidev_regspec_t reg
;
547 reg
.phys_mid
= addrp
->Address
.Minimum
>> 32;
548 reg
.phys_low
= addrp
->Address
.Minimum
& 0xFFFFFFFF;
549 reg
.size_hi
= addrp
->Address
.AddressLength
>> 32;
550 reg
.size_low
= addrp
->Address
.AddressLength
&
552 rc
= acpidev_resource_insert_reg(rhdl
, ®
);
553 if (ACPI_FAILURE(rc
)) {
554 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
555 "insert regspec into resource handle.");
557 /* Generate 'ranges' for producer. */
558 } else if (addrp
->ProducerConsumer
== ACPI_PRODUCER
&&
559 rhdl
->acpidev_consumer
== B_FALSE
) {
561 acpidev_ranges_t range
;
563 range
.child_hi
= high
;
564 range
.child_mid
= addrp
->Address
.Minimum
>> 32;
565 range
.child_low
= addrp
->Address
.Minimum
& 0xFFFFFFFF;
566 /* It's Memory on parent side if Translation is true. */
567 if (addrp
->Info
.Io
.Translation
) {
568 range
.parent_hi
= ACPIDEV_REG_TYPE_MEMORY
;
570 range
.parent_hi
= high
;
572 paddr
= addrp
->Address
.Minimum
+
573 addrp
->Address
.TranslationOffset
;
574 range
.parent_mid
= paddr
>> 32;
575 range
.parent_low
= paddr
& 0xFFFFFFFF;
576 range
.size_hi
= addrp
->Address
.AddressLength
>> 32;
577 range
.size_low
= addrp
->Address
.AddressLength
&
579 rc
= acpidev_resource_insert_range(rhdl
, &range
);
580 if (ACPI_FAILURE(rc
)) {
581 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
582 "insert range into resource handle.");
587 case ACPI_BUS_NUMBER_RANGE
:
588 /* Only support producer of BUS. */
589 if (addrp
->ProducerConsumer
== ACPI_PRODUCER
&&
590 rhdl
->acpidev_consumer
== B_FALSE
) {
592 acpidev_bus_range_t bus
;
594 end
= addrp
->Address
.Minimum
+
595 addrp
->Address
.AddressLength
;
596 if (end
< addrp
->Address
.Minimum
|| end
> UINT_MAX
) {
597 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: bus range "
598 "in ADDRESS64 is invalid.");
602 bus
.bus_start
= addrp
->Address
.Minimum
& 0xFFFFFFFF;
603 bus
.bus_end
= end
& 0xFFFFFFFF;
604 ASSERT(bus
.bus_start
<= bus
.bus_end
);
605 rc
= acpidev_resource_insert_bus(rhdl
, &bus
);
606 if (ACPI_FAILURE(rc
)) {
607 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
608 "insert bus range into resource handle.");
614 ACPIDEV_DEBUG(CE_WARN
,
615 "!acpidev: unknown resource type %u in ADDRESS64.",
616 addrp
->ResourceType
);
617 rc
= AE_BAD_PARAMETER
;
624 acpidev_resource_walk_producer(ACPI_RESOURCE
*rscp
, void *ctxp
)
626 ACPI_STATUS rc
= AE_OK
;
627 acpidev_resource_handle_t rhdl
;
629 ASSERT(ctxp
!= NULL
);
630 rhdl
= (acpidev_resource_handle_t
)ctxp
;
631 ASSERT(rhdl
->acpidev_consumer
== B_FALSE
);
633 switch (rscp
->Type
) {
634 case ACPI_RESOURCE_TYPE_DMA
:
635 case ACPI_RESOURCE_TYPE_IRQ
:
636 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
637 case ACPI_RESOURCE_TYPE_FIXED_IO
:
638 case ACPI_RESOURCE_TYPE_MEMORY24
:
639 case ACPI_RESOURCE_TYPE_MEMORY32
:
640 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32
:
641 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER
:
642 case ACPI_RESOURCE_TYPE_VENDOR
:
643 ACPIDEV_DEBUG(CE_NOTE
,
644 "!acpidev: unsupported producer resource type %u, ignored.",
648 case ACPI_RESOURCE_TYPE_IO
:
650 acpidev_ranges_t range
;
652 range
.child_hi
= ACPIDEV_REG_TYPE_IO
;
653 range
.child_hi
|= ACPIDEV_REG_IO_RANGE_FULL
;
654 if (rscp
->Data
.Io
.IoDecode
== ACPI_DECODE_16
) {
655 range
.child_hi
|= ACPIDEV_REG_IO_DECODE16
;
657 range
.parent_hi
= range
.child_hi
;
658 range
.parent_mid
= range
.child_mid
= 0;
659 range
.parent_low
= range
.child_low
= rscp
->Data
.Io
.Minimum
;
661 range
.size_low
= rscp
->Data
.Io
.AddressLength
;
662 if ((uint64_t)range
.child_low
+ range
.size_low
> UINT16_MAX
) {
663 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: invalid IO record, "
664 "IO max is out of range.");
666 } else if (range
.size_low
!= 0) {
667 rc
= acpidev_resource_insert_range(rhdl
, &range
);
668 if (ACPI_FAILURE(rc
)) {
669 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
670 "insert range into resource handle.");
676 case ACPI_RESOURCE_TYPE_ADDRESS16
:
677 case ACPI_RESOURCE_TYPE_ADDRESS32
:
678 case ACPI_RESOURCE_TYPE_ADDRESS64
:
680 ACPI_RESOURCE_ADDRESS64 addr64
;
682 if (rscp
->Data
.Address
.ProducerConsumer
!= ACPI_PRODUCER
) {
683 ACPIDEV_DEBUG(CE_NOTE
, "!acpidev: producer encountered "
684 "a CONSUMER resource, ignored.");
685 } else if (ACPI_FAILURE(AcpiResourceToAddress64(rscp
,
687 ACPIDEV_DEBUG(CE_WARN
,
688 "!acpidev: failed to convert resource to ADDR64.");
689 } else if (ACPI_FAILURE(rc
= acpidev_resource_address64(rhdl
,
691 ACPIDEV_DEBUG(CE_WARN
,
692 "!acpidev: failed to handle ADDRESS resource.");
697 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64
:
699 ACPI_RESOURCE_ADDRESS64 addr64
;
701 if (rscp
->Data
.ExtAddress64
.ProducerConsumer
!= ACPI_PRODUCER
) {
702 ACPIDEV_DEBUG(CE_NOTE
, "!acpidev: producer encountered "
703 "a CONSUMER resource, ignored.");
707 *(ACPI_RESOURCE_ADDRESS
*)&addr64
= rscp
->Data
.Address
;
708 addr64
.Address
.Granularity
=
709 rscp
->Data
.ExtAddress64
.Address
.Granularity
;
710 addr64
.Address
.Minimum
=
711 rscp
->Data
.ExtAddress64
.Address
.Minimum
;
712 addr64
.Address
.Maximum
=
713 rscp
->Data
.ExtAddress64
.Address
.Maximum
;
714 addr64
.Address
.TranslationOffset
=
715 rscp
->Data
.ExtAddress64
.Address
.TranslationOffset
;
716 addr64
.Address
.AddressLength
=
717 rscp
->Data
.ExtAddress64
.Address
.AddressLength
;
718 if (ACPI_FAILURE(rc
= acpidev_resource_address64(rhdl
,
720 ACPIDEV_DEBUG(CE_WARN
,
721 "!acpidev: failed to handle EXTADDRESS resource.");
726 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
727 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
728 ACPIDEV_DEBUG(CE_NOTE
, "!acpidev: producer encountered "
729 "START_DEPENDENT or END_DEPENDENT tag, ignored.");
732 case ACPI_RESOURCE_TYPE_END_TAG
:
733 /* Finish walking when we encounter END_TAG. */
734 rc
= AE_CTRL_TERMINATE
;
738 ACPIDEV_DEBUG(CE_NOTE
,
739 "!acpidev: unknown ACPI resource type %u, ignored.",
748 acpidev_resource_walk_consumer(ACPI_RESOURCE
*rscp
, void *ctxp
)
750 ACPI_STATUS rc
= AE_OK
;
751 acpidev_resource_handle_t rhdl
;
753 ASSERT(ctxp
!= NULL
);
754 rhdl
= (acpidev_resource_handle_t
)ctxp
;
755 ASSERT(rhdl
->acpidev_consumer
== B_TRUE
);
757 switch (rscp
->Type
) {
758 case ACPI_RESOURCE_TYPE_MEMORY24
:
759 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER
:
760 case ACPI_RESOURCE_TYPE_VENDOR
:
761 ACPIDEV_DEBUG(CE_NOTE
,
762 "!acpidev: unsupported consumer resource type %u, ignored.",
766 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
770 if (rscp
->Data
.ExtendedIrq
.ProducerConsumer
!= ACPI_CONSUMER
) {
771 ACPIDEV_DEBUG(CE_NOTE
, "!acpidev: consumer encountered "
772 "a PRODUCER resource, ignored.");
775 for (i
= 0; i
< rscp
->Data
.ExtendedIrq
.InterruptCount
; i
++) {
776 if (ACPI_SUCCESS(acpidev_resource_insert_irq(rhdl
,
777 rscp
->Data
.ExtendedIrq
.Interrupts
[i
]))) {
780 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to insert"
781 "Extended IRQ into resource handle.");
788 case ACPI_RESOURCE_TYPE_IRQ
:
792 for (i
= 0; i
< rscp
->Data
.Irq
.InterruptCount
; i
++) {
793 if (ACPI_SUCCESS(acpidev_resource_insert_irq(rhdl
,
794 rscp
->Data
.Irq
.Interrupts
[i
]))) {
797 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to insert"
798 "IRQ into resource handle.");
805 case ACPI_RESOURCE_TYPE_DMA
:
809 for (i
= 0; i
< rscp
->Data
.Dma
.ChannelCount
; i
++) {
810 if (ACPI_SUCCESS(acpidev_resource_insert_dma(rhdl
,
811 rscp
->Data
.Dma
.Channels
[i
]))) {
814 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to insert"
815 "dma into resource handle.");
822 case ACPI_RESOURCE_TYPE_IO
:
823 case ACPI_RESOURCE_TYPE_FIXED_IO
:
825 acpidev_regspec_t reg
;
827 reg
.phys_hi
= ACPIDEV_REG_TYPE_IO
;
828 reg
.phys_hi
|= ACPIDEV_REG_IO_RANGE_FULL
;
829 if (rscp
->Type
== ACPI_RESOURCE_TYPE_IO
) {
830 if (rscp
->Data
.Io
.IoDecode
== ACPI_DECODE_16
) {
831 reg
.phys_hi
|= ACPIDEV_REG_IO_DECODE16
;
833 reg
.phys_low
= rscp
->Data
.Io
.Minimum
;
834 reg
.size_low
= rscp
->Data
.Io
.AddressLength
;
836 reg
.phys_hi
|= ACPIDEV_REG_IO_DECODE16
;
837 reg
.phys_low
= rscp
->Data
.FixedIo
.Address
;
838 reg
.size_low
= rscp
->Data
.FixedIo
.AddressLength
;
842 if ((uint64_t)reg
.phys_low
+ reg
.size_low
> UINT16_MAX
) {
843 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: invalid IO/FIXEDIO "
844 "record, IO max is out of range.");
846 } else if (reg
.size_low
!= 0) {
847 rc
= acpidev_resource_insert_reg(rhdl
, ®
);
848 if (ACPI_FAILURE(rc
)) {
849 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
850 "insert reg into resource handle.");
856 case ACPI_RESOURCE_TYPE_MEMORY32
:
857 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32
:
859 acpidev_regspec_t reg
;
861 reg
.phys_hi
= ACPIDEV_REG_TYPE_MEMORY
;
862 reg
.phys_hi
|= ACPIDEV_REG_MEM_COHERENT_CA
;
863 if (rscp
->Type
== ACPI_RESOURCE_TYPE_MEMORY32
) {
864 if (rscp
->Data
.Memory32
.WriteProtect
==
865 ACPI_READ_WRITE_MEMORY
) {
866 reg
.phys_hi
|= ACPIDEV_REG_MEM_WRITABLE
;
868 reg
.phys_low
= rscp
->Data
.Memory32
.Minimum
;
869 reg
.size_low
= rscp
->Data
.Memory32
.AddressLength
;
871 if (rscp
->Data
.FixedMemory32
.WriteProtect
==
872 ACPI_READ_WRITE_MEMORY
) {
873 reg
.phys_hi
|= ACPIDEV_REG_MEM_WRITABLE
;
875 reg
.phys_low
= rscp
->Data
.FixedMemory32
.Address
;
876 reg
.size_low
= rscp
->Data
.FixedMemory32
.AddressLength
;
880 if ((uint64_t)reg
.phys_low
+ reg
.size_low
> UINT32_MAX
) {
881 ACPIDEV_DEBUG(CE_WARN
,
882 "!acpidev: invalid MEMORY32/FIXEDMEMORY32 record, "
883 "memory max is out of range.");
885 } else if (reg
.size_low
!= 0) {
886 rc
= acpidev_resource_insert_reg(rhdl
, ®
);
887 if (ACPI_FAILURE(rc
)) {
888 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to "
889 "insert reg into resource handle.");
895 case ACPI_RESOURCE_TYPE_ADDRESS16
:
896 case ACPI_RESOURCE_TYPE_ADDRESS32
:
897 case ACPI_RESOURCE_TYPE_ADDRESS64
:
899 ACPI_RESOURCE_ADDRESS64 addr64
;
901 if (rscp
->Data
.Address
.ProducerConsumer
!= ACPI_CONSUMER
) {
902 ACPIDEV_DEBUG(CE_NOTE
, "!acpidev: consumer encountered "
903 "a PRODUCER resource, ignored.");
904 } else if (ACPI_FAILURE(AcpiResourceToAddress64(rscp
,
906 ACPIDEV_DEBUG(CE_WARN
,
907 "!acpidev: failed to convert resource to ADDR64.");
908 } else if (ACPI_FAILURE(rc
= acpidev_resource_address64(rhdl
,
910 ACPIDEV_DEBUG(CE_WARN
,
911 "!acpidev: failed to handle ADDRESS resource.");
916 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64
:
918 ACPI_RESOURCE_ADDRESS64 addr64
;
920 if (rscp
->Data
.ExtAddress64
.ProducerConsumer
!= ACPI_CONSUMER
) {
921 ACPIDEV_DEBUG(CE_NOTE
, "!acpidev: consumer encountered "
922 "a PRODUCER resource, ignored.");
926 *(ACPI_RESOURCE_ADDRESS
*)&addr64
= rscp
->Data
.Address
;
927 addr64
.Address
.Granularity
=
928 rscp
->Data
.ExtAddress64
.Address
.Granularity
;
929 addr64
.Address
.Minimum
=
930 rscp
->Data
.ExtAddress64
.Address
.Minimum
;
931 addr64
.Address
.Maximum
=
932 rscp
->Data
.ExtAddress64
.Address
.Maximum
;
933 addr64
.Address
.TranslationOffset
=
934 rscp
->Data
.ExtAddress64
.Address
.TranslationOffset
;
935 addr64
.Address
.AddressLength
=
936 rscp
->Data
.ExtAddress64
.Address
.AddressLength
;
937 if (ACPI_FAILURE(rc
= acpidev_resource_address64(rhdl
,
939 ACPIDEV_DEBUG(CE_WARN
,
940 "!acpidev: failed to handle EXTADDRESS resource.");
945 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
946 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
947 ACPIDEV_DEBUG(CE_NOTE
, "!acpidev: consumer encountered "
948 "START_DEPENDENT or END_DEPENDENT tag, ignored.");
951 case ACPI_RESOURCE_TYPE_END_TAG
:
952 /* Finish walking when we encounter END_TAG. */
953 rc
= AE_CTRL_TERMINATE
;
957 ACPIDEV_DEBUG(CE_NOTE
,
958 "!acpidev: unknown ACPI resource type %u, ignored.",
967 acpidev_resource_walk(ACPI_HANDLE hdl
, char *method
,
968 boolean_t consumer
, acpidev_resource_handle_t
*rhdlp
)
970 ACPI_STATUS rc
= AE_OK
;
971 ACPI_HANDLE mhdl
= NULL
;
972 acpidev_resource_handle_t rhdl
= NULL
;
975 ASSERT(method
!= NULL
);
976 ASSERT(rhdlp
!= NULL
);
978 ACPIDEV_DEBUG(CE_WARN
,
979 "!acpidev: hdl is NULL in acpidev_resource_walk().");
980 return (AE_BAD_PARAMETER
);
981 } else if (method
== NULL
) {
982 ACPIDEV_DEBUG(CE_WARN
,
983 "!acpidev: method is NULL in acpidev_resource_walk().");
984 return (AE_BAD_PARAMETER
);
985 } else if (rhdlp
== NULL
) {
986 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: resource handle ptr is NULL "
987 "in acpidev_resource_walk().");
988 return (AE_BAD_PARAMETER
);
991 /* Check whether method exists under object. */
992 if (ACPI_FAILURE(AcpiGetHandle(hdl
, method
, &mhdl
))) {
993 char *objname
= acpidev_get_object_name(hdl
);
994 ACPIDEV_DEBUG(CE_NOTE
,
995 "!acpidev: method %s doesn't exist under %s",
997 acpidev_free_object_name(objname
);
998 return (AE_NOT_FOUND
);
1001 /* Walk all resources. */
1002 rhdl
= acpidev_resource_handle_alloc(consumer
);
1004 rc
= AcpiWalkResources(hdl
, method
,
1005 acpidev_resource_walk_consumer
, rhdl
);
1007 rc
= AcpiWalkResources(hdl
, method
,
1008 acpidev_resource_walk_producer
, rhdl
);
1010 if (ACPI_SUCCESS(rc
)) {
1013 acpidev_resource_handle_free(rhdl
);
1015 if (ACPI_FAILURE(rc
)) {
1016 char *objname
= acpidev_get_object_name(hdl
);
1017 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to walk resource from "
1018 "method %s under %s.", method
, objname
);
1019 acpidev_free_object_name(objname
);
1026 acpidev_resource_process(acpidev_walk_info_t
*infop
, boolean_t consumer
)
1029 char path
[MAXPATHLEN
];
1030 acpidev_resource_handle_t rhdl
= NULL
;
1032 ASSERT(infop
!= NULL
);
1033 if (infop
== NULL
) {
1034 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: invalid parameter "
1035 "in acpidev_resource_process().");
1036 return (AE_BAD_PARAMETER
);
1039 /* Walk all resources. */
1040 (void) ddi_pathname(infop
->awi_dip
, path
);
1041 rc
= acpidev_resource_walk(infop
->awi_hdl
, METHOD_NAME__CRS
,
1043 if (ACPI_FAILURE(rc
)) {
1044 ACPIDEV_DEBUG(CE_WARN
,
1045 "!acpidev: failed to walk ACPI resources of %s(%s).",
1046 path
, infop
->awi_name
);
1051 /* Create device properties for consumer. */
1053 /* Create 'reg' and 'assigned-addresses' properties. */
1054 if (rhdl
->acpidev_reg_count
> 0 &&
1055 ndi_prop_update_int_array(DDI_DEV_T_NONE
, infop
->awi_dip
,
1056 "reg", (int *)rhdl
->acpidev_regp
,
1057 rhdl
->acpidev_reg_count
* sizeof (acpidev_regspec_t
) /
1058 sizeof (int)) != NDI_SUCCESS
) {
1059 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to set "
1060 "'reg' property for %s.", path
);
1064 if (rhdl
->acpidev_reg_count
> 0 &&
1065 ndi_prop_update_int_array(DDI_DEV_T_NONE
, infop
->awi_dip
,
1066 "assigned-addresses", (int *)rhdl
->acpidev_regp
,
1067 rhdl
->acpidev_reg_count
* sizeof (acpidev_regspec_t
) /
1068 sizeof (int)) != NDI_SUCCESS
) {
1069 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to set "
1070 "'assigned-addresses' property for %s.", path
);
1075 /* Create 'interrupts' property. */
1076 if (rhdl
->acpidev_irq_count
> 0 &&
1077 ndi_prop_update_int_array(DDI_DEV_T_NONE
, infop
->awi_dip
,
1078 "interrupts", (int *)rhdl
->acpidev_irqp
,
1079 rhdl
->acpidev_irq_count
) != NDI_SUCCESS
) {
1080 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to set "
1081 "'interrupts' property for %s.", path
);
1086 /* Create 'dma-channels' property. */
1087 if (rhdl
->acpidev_dma_count
> 0 &&
1088 ndi_prop_update_int_array(DDI_DEV_T_NONE
, infop
->awi_dip
,
1089 "dma-channels", (int *)rhdl
->acpidev_dmap
,
1090 rhdl
->acpidev_dma_count
) != NDI_SUCCESS
) {
1091 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to set "
1092 "'dma-channels' property for %s.", path
);
1098 /* Create device properties for producer. */
1100 /* Create 'ranges' property. */
1101 if (rhdl
->acpidev_range_count
> 0 &&
1102 ndi_prop_update_int_array(DDI_DEV_T_NONE
, infop
->awi_dip
,
1103 "ranges", (int *)rhdl
->acpidev_rangep
,
1104 rhdl
->acpidev_range_count
* sizeof (acpidev_ranges_t
) /
1105 sizeof (int)) != NDI_SUCCESS
) {
1106 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to set "
1107 "'ranges' property for %s.", path
);
1112 /* Create 'bus-range' property. */
1113 if (rhdl
->acpidev_bus_count
> 0 &&
1114 ndi_prop_update_int_array(DDI_DEV_T_NONE
, infop
->awi_dip
,
1115 "bus-range", (int *)rhdl
->acpidev_busp
,
1116 rhdl
->acpidev_bus_count
* sizeof (acpidev_bus_range_t
) /
1117 sizeof (int)) != NDI_SUCCESS
) {
1118 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: failed to set "
1119 "'bus-range' property for %s.", path
);
1126 /* Free resources allocated by acpidev_resource_walk. */
1127 acpidev_resource_handle_free(rhdl
);