1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2016, Joyent, Inc.
26 */
27 /*
28 * Copyright (c) 2009-2010, Intel Corporation.
29 * All rights reserved.
30 */
31
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>
42
43 #define ACPIDEV_RES_INIT_ITEMS 8
44 #define ACPIDEV_RES_INCR_ITEMS 8
45
46 /* Data structure to hold parsed resources during walking. */
47 struct acpidev_resource_handle {
48 boolean_t acpidev_consumer;
49 int acpidev_reg_count;
50 int acpidev_reg_max;
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;
58 int acpidev_bus_max;
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];
65 };
66
67 acpidev_resource_handle_t
acpidev_resource_handle_alloc(boolean_t consumer)68 acpidev_resource_handle_alloc(boolean_t consumer)
69 {
70 acpidev_resource_handle_t rhdl;
71
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;
80
81 return (rhdl);
82 }
83
84 void
acpidev_resource_handle_free(acpidev_resource_handle_t rhdl)85 acpidev_resource_handle_free(acpidev_resource_handle_t rhdl)
86 {
87 size_t sz;
88
89 ASSERT(rhdl != NULL);
90 if (rhdl != NULL) {
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);
95 }
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);
100 }
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);
105 }
106 kmem_free(rhdl, sizeof (struct acpidev_resource_handle));
107 }
108 }
109
110 static void
acpidev_resource_handle_grow(acpidev_resource_handle_t rhdl)111 acpidev_resource_handle_grow(acpidev_resource_handle_t rhdl)
112 {
113 size_t sz;
114
115 if (rhdl->acpidev_reg_count == rhdl->acpidev_reg_max) {
116 acpidev_phys_spec_t *regp;
117
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);
126 }
127 rhdl->acpidev_regp = regp;
128 }
129
130 if (rhdl->acpidev_range_count == rhdl->acpidev_range_max) {
131 acpidev_ranges_t *rngp;
132
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);
141 }
142 rhdl->acpidev_rangep = rngp;
143 }
144
145 if (rhdl->acpidev_bus_count == rhdl->acpidev_bus_max) {
146 acpidev_bus_range_t *busp;
147
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);
156 }
157 rhdl->acpidev_busp = busp;
158 }
159 }
160
161 ACPI_STATUS
acpidev_resource_insert_reg(acpidev_resource_handle_t rhdl,acpidev_regspec_t * regp)162 acpidev_resource_insert_reg(acpidev_resource_handle_t rhdl,
163 acpidev_regspec_t *regp)
164 {
165 ASSERT(rhdl != NULL);
166 ASSERT(regp != NULL);
167 if (rhdl->acpidev_reg_count >= rhdl->acpidev_reg_max) {
168 acpidev_resource_handle_grow(rhdl);
169 }
170 ASSERT(rhdl->acpidev_reg_count < rhdl->acpidev_reg_max);
171 rhdl->acpidev_regp[rhdl->acpidev_reg_count] = *regp;
172 rhdl->acpidev_reg_count++;
173
174 return (AE_OK);
175 }
176
177 ACPI_STATUS
acpidev_resource_get_regs(acpidev_resource_handle_t rhdl,uint_t mask,uint_t value,acpidev_regspec_t * regp,uint_t * cntp)178 acpidev_resource_get_regs(acpidev_resource_handle_t rhdl,
179 uint_t mask, uint_t value, acpidev_regspec_t *regp, uint_t *cntp)
180 {
181 uint_t i, j;
182
183 ASSERT(rhdl != NULL);
184 ASSERT(cntp != NULL);
185 if (rhdl == NULL || cntp == NULL || (regp == NULL && *cntp != 0)) {
186 return (AE_BAD_PARAMETER);
187 }
188 for (i = 0, j = 0; i < rhdl->acpidev_reg_count; i++) {
189 if ((rhdl->acpidev_regp[i].phys_hi & mask) == value) {
190 if (j < *cntp) {
191 regp[j] = rhdl->acpidev_regp[i];
192 }
193 j++;
194 }
195 }
196 if (j >= *cntp) {
197 *cntp = j;
198 return (AE_LIMIT);
199 } else {
200 *cntp = j;
201 return (AE_OK);
202 }
203 }
204
205 uint_t
acpidev_resource_get_reg_count(acpidev_resource_handle_t rhdl,uint_t mask,uint_t value)206 acpidev_resource_get_reg_count(acpidev_resource_handle_t rhdl,
207 uint_t mask, uint_t value)
208 {
209 uint_t i, j;
210
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) {
214 j++;
215 }
216 }
217
218 return (j);
219 }
220
221 ACPI_STATUS
acpidev_resource_insert_range(acpidev_resource_handle_t rhdl,acpidev_ranges_t * rangep)222 acpidev_resource_insert_range(acpidev_resource_handle_t rhdl,
223 acpidev_ranges_t *rangep)
224 {
225 ASSERT(rhdl != NULL);
226 ASSERT(rangep != NULL);
227 if (rhdl->acpidev_range_count >= rhdl->acpidev_range_max) {
228 acpidev_resource_handle_grow(rhdl);
229 }
230 ASSERT(rhdl->acpidev_range_count < rhdl->acpidev_range_max);
231 rhdl->acpidev_rangep[rhdl->acpidev_range_count] = *rangep;
232 rhdl->acpidev_range_count++;
233
234 return (AE_OK);
235 }
236
237 ACPI_STATUS
acpidev_resource_get_ranges(acpidev_resource_handle_t rhdl,uint_t mask,uint_t value,acpidev_ranges_t * rangep,uint_t * cntp)238 acpidev_resource_get_ranges(acpidev_resource_handle_t rhdl,
239 uint_t mask, uint_t value, acpidev_ranges_t *rangep, uint_t *cntp)
240 {
241 uint_t i, j;
242
243 ASSERT(rhdl != NULL);
244 ASSERT(cntp != NULL);
245 if (rhdl == NULL || cntp == NULL || (rangep == NULL && *cntp != 0)) {
246 return (AE_BAD_PARAMETER);
247 }
248 for (i = 0, j = 0; i < rhdl->acpidev_range_count; i++) {
249 if ((rhdl->acpidev_rangep[i].child_hi & mask) == value) {
250 if (j < *cntp) {
251 rangep[j] = rhdl->acpidev_rangep[i];
252 }
253 j++;
254 }
255 }
256 if (j >= *cntp) {
257 *cntp = j;
258 return (AE_LIMIT);
259 } else {
260 *cntp = j;
261 return (AE_OK);
262 }
263 }
264
265 uint_t
acpidev_resource_get_range_count(acpidev_resource_handle_t rhdl,uint_t mask,uint_t value)266 acpidev_resource_get_range_count(acpidev_resource_handle_t rhdl,
267 uint_t mask, uint_t value)
268 {
269 uint_t i, j;
270
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) {
274 j++;
275 }
276 }
277
278 return (j);
279 }
280
281 ACPI_STATUS
acpidev_resource_insert_bus(acpidev_resource_handle_t rhdl,acpidev_bus_range_t * busp)282 acpidev_resource_insert_bus(acpidev_resource_handle_t rhdl,
283 acpidev_bus_range_t *busp)
284 {
285 ASSERT(rhdl != NULL);
286 ASSERT(busp != NULL);
287 if (rhdl->acpidev_bus_count >= rhdl->acpidev_bus_max) {
288 acpidev_resource_handle_grow(rhdl);
289 }
290 ASSERT(rhdl->acpidev_bus_count < rhdl->acpidev_bus_max);
291 rhdl->acpidev_busp[rhdl->acpidev_bus_count] = *busp;
292 rhdl->acpidev_bus_count++;
293
294 return (AE_OK);
295 }
296
297 ACPI_STATUS
acpidev_resource_get_buses(acpidev_resource_handle_t rhdl,acpidev_bus_range_t * busp,uint_t * cntp)298 acpidev_resource_get_buses(acpidev_resource_handle_t rhdl,
299 acpidev_bus_range_t *busp, uint_t *cntp)
300 {
301 uint_t i, j;
302
303 ASSERT(rhdl != NULL);
304 ASSERT(cntp != NULL);
305 if (rhdl == NULL || cntp == NULL || (busp == NULL && *cntp != 0)) {
306 return (AE_BAD_PARAMETER);
307 }
308 for (i = 0, j = 0; i < rhdl->acpidev_bus_count; i++) {
309 if (j < *cntp) {
310 busp[j] = rhdl->acpidev_busp[i];
311 }
312 j++;
313 }
314 if (j >= *cntp) {
315 *cntp = j;
316 return (AE_LIMIT);
317 } else {
318 *cntp = j;
319 return (AE_OK);
320 }
321 }
322
323 uint_t
acpidev_resource_get_bus_count(acpidev_resource_handle_t rhdl)324 acpidev_resource_get_bus_count(acpidev_resource_handle_t rhdl)
325 {
326 ASSERT(rhdl != NULL);
327 return (rhdl->acpidev_bus_count);
328 }
329
330 ACPI_STATUS
acpidev_resource_insert_dma(acpidev_resource_handle_t rhdl,int dma)331 acpidev_resource_insert_dma(acpidev_resource_handle_t rhdl, int dma)
332 {
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);
338 return (AE_LIMIT);
339 }
340 rhdl->acpidev_dmap[rhdl->acpidev_dma_count] = dma;
341 rhdl->acpidev_dma_count++;
342
343 return (AE_OK);
344 }
345
346 ACPI_STATUS
acpidev_resource_get_dmas(acpidev_resource_handle_t rhdl,uint_t * dmap,uint_t * cntp)347 acpidev_resource_get_dmas(acpidev_resource_handle_t rhdl,
348 uint_t *dmap, uint_t *cntp)
349 {
350 uint_t i, j;
351
352 ASSERT(rhdl != NULL);
353 ASSERT(cntp != NULL);
354 if (rhdl == NULL || cntp == NULL || (dmap == NULL && *cntp != 0)) {
355 return (AE_BAD_PARAMETER);
356 }
357 for (i = 0, j = 0; i < rhdl->acpidev_dma_count; i++) {
358 if (j < *cntp) {
359 dmap[j] = rhdl->acpidev_dmap[i];
360 }
361 j++;
362 }
363 if (j >= *cntp) {
364 *cntp = j;
365 return (AE_LIMIT);
366 } else {
367 *cntp = j;
368 return (AE_OK);
369 }
370 }
371
372 uint_t
acpidev_resource_get_dma_count(acpidev_resource_handle_t rhdl)373 acpidev_resource_get_dma_count(acpidev_resource_handle_t rhdl)
374 {
375 ASSERT(rhdl != NULL);
376 return (rhdl->acpidev_dma_count);
377 }
378
379 ACPI_STATUS
acpidev_resource_insert_irq(acpidev_resource_handle_t rhdl,int irq)380 acpidev_resource_insert_irq(acpidev_resource_handle_t rhdl, int irq)
381 {
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);
387 return (AE_LIMIT);
388 }
389 rhdl->acpidev_irqp[rhdl->acpidev_irq_count] = irq;
390 rhdl->acpidev_irq_count++;
391
392 return (AE_OK);
393 }
394
395 ACPI_STATUS
acpidev_resource_get_irqs(acpidev_resource_handle_t rhdl,uint_t * irqp,uint_t * cntp)396 acpidev_resource_get_irqs(acpidev_resource_handle_t rhdl,
397 uint_t *irqp, uint_t *cntp)
398 {
399 uint_t i, j;
400
401 ASSERT(rhdl != NULL);
402 ASSERT(cntp != NULL);
403 if (rhdl == NULL || cntp == NULL || (irqp == NULL && *cntp != 0)) {
404 return (AE_BAD_PARAMETER);
405 }
406 for (i = 0, j = 0; i < rhdl->acpidev_irq_count; i++) {
407 if (j < *cntp) {
408 irqp[j] = rhdl->acpidev_irqp[i];
409 }
410 j++;
411 }
412 if (j >= *cntp) {
413 *cntp = j;
414 return (AE_LIMIT);
415 } else {
416 *cntp = j;
417 return (AE_OK);
418 }
419 }
420
421 uint_t
acpidev_resource_get_irq_count(acpidev_resource_handle_t rhdl)422 acpidev_resource_get_irq_count(acpidev_resource_handle_t rhdl)
423 {
424 ASSERT(rhdl != NULL);
425 return (rhdl->acpidev_irq_count);
426 }
427
428 static ACPI_STATUS
acpidev_resource_address64(acpidev_resource_handle_t rhdl,ACPI_RESOURCE_ADDRESS64 * addrp)429 acpidev_resource_address64(acpidev_resource_handle_t rhdl,
430 ACPI_RESOURCE_ADDRESS64 *addrp)
431 {
432 ACPI_STATUS rc = AE_OK;
433 uint_t high;
434
435 ASSERT(addrp != NULL && rhdl != NULL);
436 if (addrp->Address.AddressLength == 0) {
437 return (AE_OK);
438 }
439
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;
445 }
446 if (addrp->Info.Mem.Translation) {
447 high |= ACPIDEV_REG_TRANSLATED;
448 }
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;
459 } else {
460 ACPIDEV_DEBUG(CE_WARN,
461 "!acpidev: unknown memory caching type %u.",
462 addrp->Info.Mem.Caching);
463 rc = AE_ERROR;
464 break;
465 }
466 if (addrp->Info.Mem.WriteProtect == ACPI_READ_WRITE_MEMORY) {
467 high |= ACPIDEV_REG_MEM_WRITABLE;
468 }
469
470 /* Generate 'reg' for producer. */
471 if (addrp->ProducerConsumer == ACPI_CONSUMER &&
472 rhdl->acpidev_consumer == B_TRUE) {
473 acpidev_regspec_t reg;
474
475 reg.phys_hi = high;
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 &
480 0xFFFFFFFF;
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.");
485 }
486 /* Generate 'ranges' for producer. */
487 } else if (addrp->ProducerConsumer == ACPI_PRODUCER &&
488 rhdl->acpidev_consumer == B_FALSE) {
489 uint64_t paddr;
490 acpidev_ranges_t range;
491
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;
498 } else {
499 range.parent_hi = high;
500 }
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 &
507 0xFFFFFFFF;
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.");
512 }
513 }
514 break;
515
516 case ACPI_IO_RANGE:
517 high = ACPIDEV_REG_TYPE_IO;
518 if (addrp->Decode == ACPI_SUB_DECODE) {
519 high |= ACPIDEV_REG_SUB_DEC;
520 }
521 if (addrp->Info.Io.Translation) {
522 high |= ACPIDEV_REG_TRANSLATED;
523 }
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;
530 } else {
531 ACPIDEV_DEBUG(CE_WARN,
532 "!acpidev: unknown IO range type %u.",
533 addrp->Info.Io.RangeType);
534 rc = AE_ERROR;
535 break;
536 }
537 if (addrp->Info.Io.TranslationType == ACPI_SPARSE_TRANSLATION) {
538 high |= ACPIDEV_REG_IO_SPARSE;
539 }
540
541 /* Generate 'reg' for producer. */
542 if (addrp->ProducerConsumer == ACPI_CONSUMER &&
543 rhdl->acpidev_consumer == B_TRUE) {
544 acpidev_regspec_t reg;
545
546 reg.phys_hi = high;
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 &
551 0xFFFFFFFF;
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.");
556 }
557 /* Generate 'ranges' for producer. */
558 } else if (addrp->ProducerConsumer == ACPI_PRODUCER &&
559 rhdl->acpidev_consumer == B_FALSE) {
560 uint64_t paddr;
561 acpidev_ranges_t range;
562
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;
569 } else {
570 range.parent_hi = high;
571 }
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 &
578 0xFFFFFFFF;
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.");
583 }
584 }
585 break;
586
587 case ACPI_BUS_NUMBER_RANGE:
588 /* Only support producer of BUS. */
589 if (addrp->ProducerConsumer == ACPI_PRODUCER &&
590 rhdl->acpidev_consumer == B_FALSE) {
591 uint64_t end;
592 acpidev_bus_range_t bus;
593
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.");
599 rc = AE_ERROR;
600 break;
601 }
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.");
609 }
610 }
611 break;
612
613 default:
614 ACPIDEV_DEBUG(CE_WARN,
615 "!acpidev: unknown resource type %u in ADDRESS64.",
616 addrp->ResourceType);
617 rc = AE_BAD_PARAMETER;
618 }
619
620 return (rc);
621 }
622
623 static ACPI_STATUS
acpidev_resource_walk_producer(ACPI_RESOURCE * rscp,void * ctxp)624 acpidev_resource_walk_producer(ACPI_RESOURCE *rscp, void *ctxp)
625 {
626 ACPI_STATUS rc = AE_OK;
627 acpidev_resource_handle_t rhdl;
628
629 ASSERT(ctxp != NULL);
630 rhdl = (acpidev_resource_handle_t)ctxp;
631 ASSERT(rhdl->acpidev_consumer == B_FALSE);
632
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.",
645 rscp->Type);
646 break;
647
648 case ACPI_RESOURCE_TYPE_IO:
649 {
650 acpidev_ranges_t range;
651
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;
656 }
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;
660 range.size_hi = 0;
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.");
665 rc = AE_ERROR;
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.");
671 }
672 }
673 break;
674 }
675
676 case ACPI_RESOURCE_TYPE_ADDRESS16:
677 case ACPI_RESOURCE_TYPE_ADDRESS32:
678 case ACPI_RESOURCE_TYPE_ADDRESS64:
679 {
680 ACPI_RESOURCE_ADDRESS64 addr64;
681
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,
686 &addr64))) {
687 ACPIDEV_DEBUG(CE_WARN,
688 "!acpidev: failed to convert resource to ADDR64.");
689 } else if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
690 &addr64))) {
691 ACPIDEV_DEBUG(CE_WARN,
692 "!acpidev: failed to handle ADDRESS resource.");
693 }
694 break;
695 }
696
697 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
698 {
699 ACPI_RESOURCE_ADDRESS64 addr64;
700
701 if (rscp->Data.ExtAddress64.ProducerConsumer != ACPI_PRODUCER) {
702 ACPIDEV_DEBUG(CE_NOTE, "!acpidev: producer encountered "
703 "a CONSUMER resource, ignored.");
704 break;
705 }
706
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,
719 &addr64))) {
720 ACPIDEV_DEBUG(CE_WARN,
721 "!acpidev: failed to handle EXTADDRESS resource.");
722 }
723 break;
724 }
725
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.");
730 break;
731
732 case ACPI_RESOURCE_TYPE_END_TAG:
733 /* Finish walking when we encounter END_TAG. */
734 rc = AE_CTRL_TERMINATE;
735 break;
736
737 default:
738 ACPIDEV_DEBUG(CE_NOTE,
739 "!acpidev: unknown ACPI resource type %u, ignored.",
740 rscp->Type);
741 break;
742 }
743
744 return (rc);
745 }
746
747 static ACPI_STATUS
acpidev_resource_walk_consumer(ACPI_RESOURCE * rscp,void * ctxp)748 acpidev_resource_walk_consumer(ACPI_RESOURCE *rscp, void *ctxp)
749 {
750 ACPI_STATUS rc = AE_OK;
751 acpidev_resource_handle_t rhdl;
752
753 ASSERT(ctxp != NULL);
754 rhdl = (acpidev_resource_handle_t)ctxp;
755 ASSERT(rhdl->acpidev_consumer == B_TRUE);
756
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.",
763 rscp->Type);
764 break;
765
766 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
767 {
768 int i;
769
770 if (rscp->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
771 ACPIDEV_DEBUG(CE_NOTE, "!acpidev: consumer encountered "
772 "a PRODUCER resource, ignored.");
773 break;
774 }
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]))) {
778 continue;
779 }
780 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to insert"
781 "Extended IRQ into resource handle.");
782 rc = AE_ERROR;
783 break;
784 }
785 break;
786 }
787
788 case ACPI_RESOURCE_TYPE_IRQ:
789 {
790 int i;
791
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]))) {
795 continue;
796 }
797 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to insert"
798 "IRQ into resource handle.");
799 rc = AE_ERROR;
800 break;
801 }
802 break;
803 }
804
805 case ACPI_RESOURCE_TYPE_DMA:
806 {
807 int i;
808
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]))) {
812 continue;
813 }
814 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to insert"
815 "dma into resource handle.");
816 rc = AE_ERROR;
817 break;
818 }
819 break;
820 }
821
822 case ACPI_RESOURCE_TYPE_IO:
823 case ACPI_RESOURCE_TYPE_FIXED_IO:
824 {
825 acpidev_regspec_t reg;
826
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;
832 }
833 reg.phys_low = rscp->Data.Io.Minimum;
834 reg.size_low = rscp->Data.Io.AddressLength;
835 } else {
836 reg.phys_hi |= ACPIDEV_REG_IO_DECODE16;
837 reg.phys_low = rscp->Data.FixedIo.Address;
838 reg.size_low = rscp->Data.FixedIo.AddressLength;
839 }
840 reg.phys_mid = 0;
841 reg.size_hi = 0;
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.");
845 rc = AE_ERROR;
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.");
851 }
852 }
853 break;
854 }
855
856 case ACPI_RESOURCE_TYPE_MEMORY32:
857 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
858 {
859 acpidev_regspec_t reg;
860
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;
867 }
868 reg.phys_low = rscp->Data.Memory32.Minimum;
869 reg.size_low = rscp->Data.Memory32.AddressLength;
870 } else {
871 if (rscp->Data.FixedMemory32.WriteProtect ==
872 ACPI_READ_WRITE_MEMORY) {
873 reg.phys_hi |= ACPIDEV_REG_MEM_WRITABLE;
874 }
875 reg.phys_low = rscp->Data.FixedMemory32.Address;
876 reg.size_low = rscp->Data.FixedMemory32.AddressLength;
877 }
878 reg.phys_mid = 0;
879 reg.size_hi = 0;
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.");
884 rc = AE_ERROR;
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.");
890 }
891 }
892 break;
893 }
894
895 case ACPI_RESOURCE_TYPE_ADDRESS16:
896 case ACPI_RESOURCE_TYPE_ADDRESS32:
897 case ACPI_RESOURCE_TYPE_ADDRESS64:
898 {
899 ACPI_RESOURCE_ADDRESS64 addr64;
900
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,
905 &addr64))) {
906 ACPIDEV_DEBUG(CE_WARN,
907 "!acpidev: failed to convert resource to ADDR64.");
908 } else if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
909 &addr64))) {
910 ACPIDEV_DEBUG(CE_WARN,
911 "!acpidev: failed to handle ADDRESS resource.");
912 }
913 break;
914 }
915
916 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
917 {
918 ACPI_RESOURCE_ADDRESS64 addr64;
919
920 if (rscp->Data.ExtAddress64.ProducerConsumer != ACPI_CONSUMER) {
921 ACPIDEV_DEBUG(CE_NOTE, "!acpidev: consumer encountered "
922 "a PRODUCER resource, ignored.");
923 break;
924 }
925
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,
938 &addr64))) {
939 ACPIDEV_DEBUG(CE_WARN,
940 "!acpidev: failed to handle EXTADDRESS resource.");
941 }
942 break;
943 }
944
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.");
949 break;
950
951 case ACPI_RESOURCE_TYPE_END_TAG:
952 /* Finish walking when we encounter END_TAG. */
953 rc = AE_CTRL_TERMINATE;
954 break;
955
956 default:
957 ACPIDEV_DEBUG(CE_NOTE,
958 "!acpidev: unknown ACPI resource type %u, ignored.",
959 rscp->Type);
960 break;
961 }
962
963 return (rc);
964 }
965
966 ACPI_STATUS
acpidev_resource_walk(ACPI_HANDLE hdl,char * method,boolean_t consumer,acpidev_resource_handle_t * rhdlp)967 acpidev_resource_walk(ACPI_HANDLE hdl, char *method,
968 boolean_t consumer, acpidev_resource_handle_t *rhdlp)
969 {
970 ACPI_STATUS rc = AE_OK;
971 ACPI_HANDLE mhdl = NULL;
972 acpidev_resource_handle_t rhdl = NULL;
973
974 ASSERT(hdl != NULL);
975 ASSERT(method != NULL);
976 ASSERT(rhdlp != NULL);
977 if (hdl == 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);
989 }
990
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",
996 method, objname);
997 acpidev_free_object_name(objname);
998 return (AE_NOT_FOUND);
999 }
1000
1001 /* Walk all resources. */
1002 rhdl = acpidev_resource_handle_alloc(consumer);
1003 if (consumer) {
1004 rc = AcpiWalkResources(hdl, method,
1005 acpidev_resource_walk_consumer, rhdl);
1006 } else {
1007 rc = AcpiWalkResources(hdl, method,
1008 acpidev_resource_walk_producer, rhdl);
1009 }
1010 if (ACPI_SUCCESS(rc)) {
1011 *rhdlp = rhdl;
1012 } else {
1013 acpidev_resource_handle_free(rhdl);
1014 }
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);
1020 }
1021
1022 return (rc);
1023 }
1024
1025 ACPI_STATUS
acpidev_resource_process(acpidev_walk_info_t * infop,boolean_t consumer)1026 acpidev_resource_process(acpidev_walk_info_t *infop, boolean_t consumer)
1027 {
1028 ACPI_STATUS rc;
1029 char path[MAXPATHLEN];
1030 acpidev_resource_handle_t rhdl = NULL;
1031
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);
1037 }
1038
1039 /* Walk all resources. */
1040 (void) ddi_pathname(infop->awi_dip, path);
1041 rc = acpidev_resource_walk(infop->awi_hdl, METHOD_NAME__CRS,
1042 consumer, &rhdl);
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);
1047 return (rc);
1048 }
1049
1050 if (consumer) {
1051 /* Create device properties for consumer. */
1052
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);
1061 rc = AE_ERROR;
1062 goto out;
1063 }
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);
1071 rc = AE_ERROR;
1072 goto out;
1073 }
1074
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);
1082 rc = AE_ERROR;
1083 goto out;
1084 }
1085
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);
1093 rc = AE_ERROR;
1094 goto out;
1095 }
1096
1097 } else {
1098 /* Create device properties for producer. */
1099
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);
1108 rc = AE_ERROR;
1109 goto out;
1110 }
1111
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);
1120 rc = AE_ERROR;
1121 goto out;
1122 }
1123 }
1124
1125 out:
1126 /* Free resources allocated by acpidev_resource_walk. */
1127 acpidev_resource_handle_free(rhdl);
1128
1129 return (rc);
1130 }
1131