xref: /illumos-gate/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_resource.c (revision f6da83d4178694e7113b71d1e452f15b296f73d8)
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 /*
26  * Copyright (c) 2009-2010, Intel Corporation.
27  * All rights reserved.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/cmn_err.h>
32 #include <sys/sysmacros.h>
33 #include <sys/sunddi.h>
34 #include <sys/sunndi.h>
35 #include <sys/acpi/acpi.h>
36 #include <sys/acpica.h>
37 #include <sys/acpidev.h>
38 #include <sys/acpidev_rsc.h>
39 #include <sys/acpidev_impl.h>
40 
41 #define	ACPIDEV_RES_INIT_ITEMS		8
42 #define	ACPIDEV_RES_INCR_ITEMS		8
43 
44 /* Data structure to hold parsed resources during walking. */
45 struct acpidev_resource_handle {
46 	boolean_t			acpidev_consumer;
47 	int				acpidev_reg_count;
48 	int				acpidev_reg_max;
49 	acpidev_phys_spec_t		*acpidev_regp;
50 	acpidev_phys_spec_t		acpidev_regs[ACPIDEV_RES_INIT_ITEMS];
51 	int				acpidev_range_count;
52 	int				acpidev_range_max;
53 	acpidev_ranges_t		*acpidev_rangep;
54 	acpidev_ranges_t		acpidev_ranges[ACPIDEV_RES_INIT_ITEMS];
55 	int				acpidev_bus_count;
56 	int				acpidev_bus_max;
57 	acpidev_bus_range_t		*acpidev_busp;
58 	acpidev_bus_range_t		acpidev_buses[ACPIDEV_RES_INIT_ITEMS];
59 	int				acpidev_irq_count;
60 	int				acpidev_irqp[ACPIDEV_RES_IRQ_MAX];
61 	int				acpidev_dma_count;
62 	int				acpidev_dmap[ACPIDEV_RES_DMA_MAX];
63 };
64 
65 acpidev_resource_handle_t
66 acpidev_resource_handle_alloc(boolean_t consumer)
67 {
68 	acpidev_resource_handle_t rhdl;
69 
70 	rhdl = kmem_zalloc(sizeof (*rhdl), KM_SLEEP);
71 	rhdl->acpidev_consumer = consumer;
72 	rhdl->acpidev_reg_max = ACPIDEV_RES_INIT_ITEMS;
73 	rhdl->acpidev_regp = rhdl->acpidev_regs;
74 	rhdl->acpidev_range_max = ACPIDEV_RES_INIT_ITEMS;
75 	rhdl->acpidev_rangep = rhdl->acpidev_ranges;
76 	rhdl->acpidev_bus_max = ACPIDEV_RES_INIT_ITEMS;
77 	rhdl->acpidev_busp = rhdl->acpidev_buses;
78 
79 	return (rhdl);
80 }
81 
82 void
83 acpidev_resource_handle_free(acpidev_resource_handle_t rhdl)
84 {
85 	size_t sz;
86 
87 	ASSERT(rhdl != NULL);
88 	if (rhdl != NULL) {
89 		if (rhdl->acpidev_regp != rhdl->acpidev_regs) {
90 			sz = sizeof (acpidev_phys_spec_t) *
91 			    rhdl->acpidev_reg_max;
92 			kmem_free(rhdl->acpidev_regp, sz);
93 		}
94 		if (rhdl->acpidev_rangep != rhdl->acpidev_ranges) {
95 			sz = sizeof (acpidev_ranges_t) *
96 			    rhdl->acpidev_range_max;
97 			kmem_free(rhdl->acpidev_rangep, sz);
98 		}
99 		if (rhdl->acpidev_busp != rhdl->acpidev_buses) {
100 			sz = sizeof (acpidev_bus_range_t) *
101 			    rhdl->acpidev_bus_max;
102 			kmem_free(rhdl->acpidev_busp, sz);
103 		}
104 		kmem_free(rhdl, sizeof (struct acpidev_resource_handle));
105 	}
106 }
107 
108 static void
109 acpidev_resource_handle_grow(acpidev_resource_handle_t rhdl)
110 {
111 	size_t sz;
112 
113 	if (rhdl->acpidev_reg_count == rhdl->acpidev_reg_max) {
114 		acpidev_phys_spec_t *regp;
115 
116 		/* Prefer linear incremental here. */
117 		rhdl->acpidev_reg_max += ACPIDEV_RES_INCR_ITEMS;
118 		sz = sizeof (*regp) * rhdl->acpidev_reg_max;
119 		regp = kmem_zalloc(sz, KM_SLEEP);
120 		sz = sizeof (*regp) * rhdl->acpidev_reg_count;
121 		bcopy(rhdl->acpidev_regp, regp, sz);
122 		if (rhdl->acpidev_regp != rhdl->acpidev_regs) {
123 			kmem_free(rhdl->acpidev_regp, sz);
124 		}
125 		rhdl->acpidev_regp = regp;
126 	}
127 
128 	if (rhdl->acpidev_range_count == rhdl->acpidev_range_max) {
129 		acpidev_ranges_t *rngp;
130 
131 		/* Prefer linear incremental here. */
132 		rhdl->acpidev_range_max += ACPIDEV_RES_INCR_ITEMS;
133 		sz = sizeof (*rngp) * rhdl->acpidev_range_max;
134 		rngp = kmem_zalloc(sz, KM_SLEEP);
135 		sz = sizeof (*rngp) * rhdl->acpidev_range_count;
136 		bcopy(rhdl->acpidev_rangep, rngp, sz);
137 		if (rhdl->acpidev_rangep != rhdl->acpidev_ranges) {
138 			kmem_free(rhdl->acpidev_rangep, sz);
139 		}
140 		rhdl->acpidev_rangep = rngp;
141 	}
142 
143 	if (rhdl->acpidev_bus_count == rhdl->acpidev_bus_max) {
144 		acpidev_bus_range_t *busp;
145 
146 		/* Prefer linear incremental here. */
147 		rhdl->acpidev_bus_max += ACPIDEV_RES_INCR_ITEMS;
148 		sz = sizeof (*busp) * rhdl->acpidev_bus_max;
149 		busp = kmem_zalloc(sz, KM_SLEEP);
150 		sz = sizeof (*busp) * rhdl->acpidev_bus_count;
151 		bcopy(rhdl->acpidev_busp, busp, sz);
152 		if (rhdl->acpidev_busp != rhdl->acpidev_buses) {
153 			kmem_free(rhdl->acpidev_busp, sz);
154 		}
155 		rhdl->acpidev_busp = busp;
156 	}
157 }
158 
159 ACPI_STATUS
160 acpidev_resource_insert_reg(acpidev_resource_handle_t rhdl,
161     acpidev_regspec_t *regp)
162 {
163 	ASSERT(rhdl != NULL);
164 	ASSERT(regp != NULL);
165 	if (rhdl->acpidev_reg_count >= rhdl->acpidev_reg_max) {
166 		acpidev_resource_handle_grow(rhdl);
167 	}
168 	ASSERT(rhdl->acpidev_reg_count < rhdl->acpidev_reg_max);
169 	rhdl->acpidev_regp[rhdl->acpidev_reg_count] = *regp;
170 	rhdl->acpidev_reg_count++;
171 
172 	return (AE_OK);
173 }
174 
175 ACPI_STATUS
176 acpidev_resource_get_regs(acpidev_resource_handle_t rhdl,
177     uint_t mask, uint_t value, acpidev_regspec_t *regp, uint_t *cntp)
178 {
179 	uint_t i, j;
180 
181 	ASSERT(rhdl != NULL);
182 	ASSERT(cntp != NULL);
183 	if (rhdl == NULL || cntp == NULL || (regp == NULL && *cntp != 0)) {
184 		return (AE_BAD_PARAMETER);
185 	}
186 	for (i = 0, j = 0; i < rhdl->acpidev_reg_count; i++) {
187 		if ((rhdl->acpidev_regp[i].phys_hi & mask) == value) {
188 			if (j < *cntp) {
189 				regp[j] = rhdl->acpidev_regp[i];
190 			}
191 			j++;
192 		}
193 	}
194 	if (j >= *cntp) {
195 		*cntp = j;
196 		return (AE_LIMIT);
197 	} else {
198 		*cntp = j;
199 		return (AE_OK);
200 	}
201 }
202 
203 uint_t
204 acpidev_resource_get_reg_count(acpidev_resource_handle_t rhdl,
205     uint_t mask, uint_t value)
206 {
207 	uint_t i, j;
208 
209 	ASSERT(rhdl != NULL);
210 	for (i = 0, j = 0; i < rhdl->acpidev_reg_count; i++) {
211 		if ((rhdl->acpidev_regp[i].phys_hi & mask) == value) {
212 			j++;
213 		}
214 	}
215 
216 	return (j);
217 }
218 
219 ACPI_STATUS
220 acpidev_resource_insert_range(acpidev_resource_handle_t rhdl,
221     acpidev_ranges_t *rangep)
222 {
223 	ASSERT(rhdl != NULL);
224 	ASSERT(rangep != NULL);
225 	if (rhdl->acpidev_range_count >= rhdl->acpidev_range_max) {
226 		acpidev_resource_handle_grow(rhdl);
227 	}
228 	ASSERT(rhdl->acpidev_range_count < rhdl->acpidev_range_max);
229 	rhdl->acpidev_rangep[rhdl->acpidev_range_count] = *rangep;
230 	rhdl->acpidev_range_count++;
231 
232 	return (AE_OK);
233 }
234 
235 ACPI_STATUS
236 acpidev_resource_get_ranges(acpidev_resource_handle_t rhdl,
237     uint_t mask, uint_t value, acpidev_ranges_t *rangep, uint_t *cntp)
238 {
239 	uint_t i, j;
240 
241 	ASSERT(rhdl != NULL);
242 	ASSERT(cntp != NULL);
243 	if (rhdl == NULL || cntp == NULL || (rangep == NULL && *cntp != 0)) {
244 		return (AE_BAD_PARAMETER);
245 	}
246 	for (i = 0, j = 0; i < rhdl->acpidev_range_count; i++) {
247 		if ((rhdl->acpidev_rangep[i].child_hi & mask) == value) {
248 			if (j < *cntp) {
249 				rangep[j] = rhdl->acpidev_rangep[i];
250 			}
251 			j++;
252 		}
253 	}
254 	if (j >= *cntp) {
255 		*cntp = j;
256 		return (AE_LIMIT);
257 	} else {
258 		*cntp = j;
259 		return (AE_OK);
260 	}
261 }
262 
263 uint_t
264 acpidev_resource_get_range_count(acpidev_resource_handle_t rhdl,
265     uint_t mask, uint_t value)
266 {
267 	uint_t i, j;
268 
269 	ASSERT(rhdl != NULL);
270 	for (i = 0, j = 0; i < rhdl->acpidev_range_count; i++) {
271 		if ((rhdl->acpidev_rangep[i].child_hi & mask) == value) {
272 			j++;
273 		}
274 	}
275 
276 	return (j);
277 }
278 
279 ACPI_STATUS
280 acpidev_resource_insert_bus(acpidev_resource_handle_t rhdl,
281     acpidev_bus_range_t *busp)
282 {
283 	ASSERT(rhdl != NULL);
284 	ASSERT(busp != NULL);
285 	if (rhdl->acpidev_bus_count >= rhdl->acpidev_bus_max) {
286 		acpidev_resource_handle_grow(rhdl);
287 	}
288 	ASSERT(rhdl->acpidev_bus_count < rhdl->acpidev_bus_max);
289 	rhdl->acpidev_busp[rhdl->acpidev_bus_count] = *busp;
290 	rhdl->acpidev_bus_count++;
291 
292 	return (AE_OK);
293 }
294 
295 ACPI_STATUS
296 acpidev_resource_get_buses(acpidev_resource_handle_t rhdl,
297     acpidev_bus_range_t *busp, uint_t *cntp)
298 {
299 	uint_t i, j;
300 
301 	ASSERT(rhdl != NULL);
302 	ASSERT(cntp != NULL);
303 	if (rhdl == NULL || cntp == NULL || (busp == NULL && *cntp != 0)) {
304 		return (AE_BAD_PARAMETER);
305 	}
306 	for (i = 0, j = 0; i < rhdl->acpidev_bus_count; i++) {
307 		if (j < *cntp) {
308 			busp[j] = rhdl->acpidev_busp[i];
309 		}
310 		j++;
311 	}
312 	if (j >= *cntp) {
313 		*cntp = j;
314 		return (AE_LIMIT);
315 	} else {
316 		*cntp = j;
317 		return (AE_OK);
318 	}
319 }
320 
321 uint_t
322 acpidev_resource_get_bus_count(acpidev_resource_handle_t rhdl)
323 {
324 	ASSERT(rhdl != NULL);
325 	return (rhdl->acpidev_bus_count);
326 }
327 
328 ACPI_STATUS
329 acpidev_resource_insert_dma(acpidev_resource_handle_t rhdl, int dma)
330 {
331 	ASSERT(rhdl != NULL);
332 	if (rhdl->acpidev_dma_count >= ACPIDEV_RES_DMA_MAX) {
333 		ACPIDEV_DEBUG(CE_WARN,
334 		    "!acpidev: too many DMA resources, max %u.",
335 		    ACPIDEV_RES_DMA_MAX);
336 		return (AE_LIMIT);
337 	}
338 	rhdl->acpidev_dmap[rhdl->acpidev_dma_count] = dma;
339 	rhdl->acpidev_dma_count++;
340 
341 	return (AE_OK);
342 }
343 
344 ACPI_STATUS
345 acpidev_resource_get_dmas(acpidev_resource_handle_t rhdl,
346     uint_t *dmap, uint_t *cntp)
347 {
348 	uint_t i, j;
349 
350 	ASSERT(rhdl != NULL);
351 	ASSERT(cntp != NULL);
352 	if (rhdl == NULL || cntp == NULL || (dmap == NULL && *cntp != 0)) {
353 		return (AE_BAD_PARAMETER);
354 	}
355 	for (i = 0, j = 0; i < rhdl->acpidev_dma_count; i++) {
356 		if (j < *cntp) {
357 			dmap[j] = rhdl->acpidev_dmap[i];
358 		}
359 		j++;
360 	}
361 	if (j >= *cntp) {
362 		*cntp = j;
363 		return (AE_LIMIT);
364 	} else {
365 		*cntp = j;
366 		return (AE_OK);
367 	}
368 }
369 
370 uint_t
371 acpidev_resource_get_dma_count(acpidev_resource_handle_t rhdl)
372 {
373 	ASSERT(rhdl != NULL);
374 	return (rhdl->acpidev_dma_count);
375 }
376 
377 ACPI_STATUS
378 acpidev_resource_insert_irq(acpidev_resource_handle_t rhdl, int irq)
379 {
380 	ASSERT(rhdl != NULL);
381 	if (rhdl->acpidev_irq_count >= ACPIDEV_RES_IRQ_MAX) {
382 		ACPIDEV_DEBUG(CE_WARN,
383 		    "!acpidev: too many IRQ resources, max %u.",
384 		    ACPIDEV_RES_IRQ_MAX);
385 		return (AE_LIMIT);
386 	}
387 	rhdl->acpidev_irqp[rhdl->acpidev_irq_count] = irq;
388 	rhdl->acpidev_irq_count++;
389 
390 	return (AE_OK);
391 }
392 
393 ACPI_STATUS
394 acpidev_resource_get_irqs(acpidev_resource_handle_t rhdl,
395     uint_t *irqp, uint_t *cntp)
396 {
397 	uint_t i, j;
398 
399 	ASSERT(rhdl != NULL);
400 	ASSERT(cntp != NULL);
401 	if (rhdl == NULL || cntp == NULL || (irqp == NULL && *cntp != 0)) {
402 		return (AE_BAD_PARAMETER);
403 	}
404 	for (i = 0, j = 0; i < rhdl->acpidev_irq_count; i++) {
405 		if (j < *cntp) {
406 			irqp[j] = rhdl->acpidev_irqp[i];
407 		}
408 		j++;
409 	}
410 	if (j >= *cntp) {
411 		*cntp = j;
412 		return (AE_LIMIT);
413 	} else {
414 		*cntp = j;
415 		return (AE_OK);
416 	}
417 }
418 
419 uint_t
420 acpidev_resource_get_irq_count(acpidev_resource_handle_t rhdl)
421 {
422 	ASSERT(rhdl != NULL);
423 	return (rhdl->acpidev_irq_count);
424 }
425 
426 static ACPI_STATUS
427 acpidev_resource_address64(acpidev_resource_handle_t rhdl,
428     ACPI_RESOURCE_ADDRESS64 *addrp)
429 {
430 	ACPI_STATUS rc = AE_OK;
431 	uint_t high;
432 
433 	ASSERT(addrp != NULL && rhdl != NULL);
434 	if (addrp->AddressLength == 0) {
435 		return (AE_OK);
436 	}
437 
438 	switch (addrp->ResourceType) {
439 	case ACPI_MEMORY_RANGE:
440 		high = ACPIDEV_REG_TYPE_MEMORY;
441 		if (addrp->Decode == ACPI_SUB_DECODE) {
442 			high |= ACPIDEV_REG_SUB_DEC;
443 		}
444 		if (addrp->Info.Mem.Translation) {
445 			high |= ACPIDEV_REG_TRANSLATED;
446 		}
447 		if (addrp->Info.Mem.Caching == ACPI_NON_CACHEABLE_MEMORY) {
448 			high |= ACPIDEV_REG_MEM_COHERENT_NC;
449 		} else if (addrp->Info.Mem.Caching == ACPI_CACHABLE_MEMORY) {
450 			high |= ACPIDEV_REG_MEM_COHERENT_CA;
451 		} else if (addrp->Info.Mem.Caching ==
452 		    ACPI_WRITE_COMBINING_MEMORY) {
453 			high |= ACPIDEV_REG_MEM_COHERENT_WC;
454 		} else if (addrp->Info.Mem.Caching ==
455 		    ACPI_PREFETCHABLE_MEMORY) {
456 			high |= ACPIDEV_REG_MEM_COHERENT_PF;
457 		} else {
458 			ACPIDEV_DEBUG(CE_WARN,
459 			    "!acpidev: unknown memory caching type %u.",
460 			    addrp->Info.Mem.Caching);
461 			rc = AE_ERROR;
462 			break;
463 		}
464 		if (addrp->Info.Mem.WriteProtect == ACPI_READ_WRITE_MEMORY) {
465 			high |= ACPIDEV_REG_MEM_WRITABLE;
466 		}
467 
468 		/* Generate 'reg' for producer. */
469 		if (addrp->ProducerConsumer == ACPI_CONSUMER &&
470 		    rhdl->acpidev_consumer == B_TRUE) {
471 			acpidev_regspec_t reg;
472 
473 			reg.phys_hi = high;
474 			reg.phys_mid = addrp->Minimum >> 32;
475 			reg.phys_low = addrp->Minimum & 0xFFFFFFFF;
476 			reg.size_hi = addrp->AddressLength >> 32;
477 			reg.size_low = addrp->AddressLength & 0xFFFFFFFF;
478 			rc = acpidev_resource_insert_reg(rhdl, &reg);
479 			if (ACPI_FAILURE(rc)) {
480 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
481 				    "insert regspec into resource handle.");
482 			}
483 		/* Generate 'ranges' for producer. */
484 		} else if (addrp->ProducerConsumer == ACPI_PRODUCER &&
485 		    rhdl->acpidev_consumer == B_FALSE) {
486 			uint64_t paddr;
487 			acpidev_ranges_t range;
488 
489 			range.child_hi = high;
490 			range.child_mid = addrp->Minimum >> 32;
491 			range.child_low = addrp->Minimum & 0xFFFFFFFF;
492 			/* It's IO on parent side if Translation is true. */
493 			if (addrp->Info.Mem.Translation) {
494 				range.parent_hi = ACPIDEV_REG_TYPE_IO;
495 			} else {
496 				range.parent_hi = high;
497 			}
498 			paddr = addrp->Minimum + addrp->TranslationOffset;
499 			range.parent_mid = paddr >> 32;
500 			range.parent_low = paddr & 0xFFFFFFFF;
501 			range.size_hi = addrp->AddressLength >> 32;
502 			range.size_low = addrp->AddressLength & 0xFFFFFFFF;
503 			rc = acpidev_resource_insert_range(rhdl, &range);
504 			if (ACPI_FAILURE(rc)) {
505 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
506 				    "insert range into resource handle.");
507 			}
508 		}
509 		break;
510 
511 	case ACPI_IO_RANGE:
512 		high = ACPIDEV_REG_TYPE_IO;
513 		if (addrp->Decode == ACPI_SUB_DECODE) {
514 			high |= ACPIDEV_REG_SUB_DEC;
515 		}
516 		if (addrp->Info.Io.Translation) {
517 			high |= ACPIDEV_REG_TRANSLATED;
518 		}
519 		if (addrp->Info.Io.RangeType == ACPI_NON_ISA_ONLY_RANGES) {
520 			high |= ACPIDEV_REG_IO_RANGE_NONISA;
521 		} else if (addrp->Info.Io.RangeType == ACPI_ISA_ONLY_RANGES) {
522 			high |= ACPIDEV_REG_IO_RANGE_ISA;
523 		} else if (addrp->Info.Io.RangeType == ACPI_ENTIRE_RANGE) {
524 			high |= ACPIDEV_REG_IO_RANGE_FULL;
525 		} else {
526 			ACPIDEV_DEBUG(CE_WARN,
527 			    "!acpidev: unknown IO range type %u.",
528 			    addrp->Info.Io.RangeType);
529 			rc = AE_ERROR;
530 			break;
531 		}
532 		if (addrp->Info.Io.TranslationType == ACPI_SPARSE_TRANSLATION) {
533 			high |= ACPIDEV_REG_IO_SPARSE;
534 		}
535 
536 		/* Generate 'reg' for producer. */
537 		if (addrp->ProducerConsumer == ACPI_CONSUMER &&
538 		    rhdl->acpidev_consumer == B_TRUE) {
539 			acpidev_regspec_t reg;
540 
541 			reg.phys_hi = high;
542 			reg.phys_mid = addrp->Minimum >> 32;
543 			reg.phys_low = addrp->Minimum & 0xFFFFFFFF;
544 			reg.size_hi = addrp->AddressLength >> 32;
545 			reg.size_low = addrp->AddressLength & 0xFFFFFFFF;
546 			rc = acpidev_resource_insert_reg(rhdl, &reg);
547 			if (ACPI_FAILURE(rc)) {
548 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
549 				    "insert regspec into resource handle.");
550 			}
551 		/* Generate 'ranges' for producer. */
552 		} else if (addrp->ProducerConsumer == ACPI_PRODUCER &&
553 		    rhdl->acpidev_consumer == B_FALSE) {
554 			uint64_t paddr;
555 			acpidev_ranges_t range;
556 
557 			range.child_hi = high;
558 			range.child_mid = addrp->Minimum >> 32;
559 			range.child_low = addrp->Minimum & 0xFFFFFFFF;
560 			/* It's Memory on parent side if Translation is true. */
561 			if (addrp->Info.Io.Translation) {
562 				range.parent_hi = ACPIDEV_REG_TYPE_MEMORY;
563 			} else {
564 				range.parent_hi = high;
565 			}
566 			paddr = addrp->Minimum + addrp->TranslationOffset;
567 			range.parent_mid = paddr >> 32;
568 			range.parent_low = paddr & 0xFFFFFFFF;
569 			range.size_hi = addrp->AddressLength >> 32;
570 			range.size_low = addrp->AddressLength & 0xFFFFFFFF;
571 			rc = acpidev_resource_insert_range(rhdl, &range);
572 			if (ACPI_FAILURE(rc)) {
573 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
574 				    "insert range into resource handle.");
575 			}
576 		}
577 		break;
578 
579 	case ACPI_BUS_NUMBER_RANGE:
580 		/* Only support producer of BUS. */
581 		if (addrp->ProducerConsumer == ACPI_PRODUCER &&
582 		    rhdl->acpidev_consumer == B_FALSE) {
583 			uint64_t end;
584 			acpidev_bus_range_t bus;
585 
586 			end = addrp->Minimum + addrp->AddressLength;
587 			if (end < addrp->Minimum || end > UINT_MAX) {
588 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: bus range "
589 				    "in ADDRESS64 is invalid.");
590 				rc = AE_ERROR;
591 				break;
592 			}
593 			bus.bus_start = addrp->Minimum & 0xFFFFFFFF;
594 			bus.bus_end = end & 0xFFFFFFFF;
595 			ASSERT(bus.bus_start <= bus.bus_end);
596 			rc = acpidev_resource_insert_bus(rhdl, &bus);
597 			if (ACPI_FAILURE(rc)) {
598 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
599 				    "insert bus range into resource handle.");
600 			}
601 		}
602 		break;
603 
604 	default:
605 		ACPIDEV_DEBUG(CE_WARN,
606 		    "!acpidev: unknown resource type %u in ADDRESS64.",
607 		    addrp->ResourceType);
608 		rc = AE_BAD_PARAMETER;
609 	}
610 
611 	return (rc);
612 }
613 
614 static ACPI_STATUS
615 acpidev_resource_walk_producer(ACPI_RESOURCE *rscp, void *ctxp)
616 {
617 	ACPI_STATUS rc = AE_OK;
618 	acpidev_resource_handle_t rhdl;
619 
620 	ASSERT(ctxp != NULL);
621 	rhdl = (acpidev_resource_handle_t)ctxp;
622 	ASSERT(rhdl->acpidev_consumer == B_FALSE);
623 
624 	switch (rscp->Type) {
625 	case ACPI_RESOURCE_TYPE_DMA:
626 	case ACPI_RESOURCE_TYPE_IRQ:
627 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
628 	case ACPI_RESOURCE_TYPE_FIXED_IO:
629 	case ACPI_RESOURCE_TYPE_MEMORY24:
630 	case ACPI_RESOURCE_TYPE_MEMORY32:
631 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
632 	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
633 	case ACPI_RESOURCE_TYPE_VENDOR:
634 		ACPIDEV_DEBUG(CE_NOTE,
635 		    "!acpidev: unsupported producer resource type %u, ignored.",
636 		    rscp->Type);
637 		break;
638 
639 	case ACPI_RESOURCE_TYPE_IO:
640 	{
641 		acpidev_ranges_t range;
642 
643 		range.child_hi = ACPIDEV_REG_TYPE_IO;
644 		range.child_hi |= ACPIDEV_REG_IO_RANGE_FULL;
645 		if (rscp->Data.Io.IoDecode == ACPI_DECODE_16) {
646 			range.child_hi |= ACPIDEV_REG_IO_DECODE16;
647 		}
648 		range.parent_hi = range.child_hi;
649 		range.parent_mid = range.child_mid = 0;
650 		range.parent_low = range.child_low = rscp->Data.Io.Minimum;
651 		range.size_hi = 0;
652 		range.size_low = rscp->Data.Io.AddressLength;
653 		if ((uint64_t)range.child_low + range.size_low > UINT16_MAX) {
654 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid IO record, "
655 			    "IO max is out of range.");
656 			rc = AE_ERROR;
657 		} else if (range.size_low != 0) {
658 			rc = acpidev_resource_insert_range(rhdl, &range);
659 			if (ACPI_FAILURE(rc)) {
660 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
661 				    "insert range into resource handle.");
662 			}
663 		}
664 		break;
665 	}
666 
667 	case ACPI_RESOURCE_TYPE_ADDRESS16:
668 	case ACPI_RESOURCE_TYPE_ADDRESS32:
669 	case ACPI_RESOURCE_TYPE_ADDRESS64:
670 	{
671 		ACPI_RESOURCE_ADDRESS64 addr64;
672 
673 		if (rscp->Data.Address.ProducerConsumer != ACPI_PRODUCER) {
674 			ACPIDEV_DEBUG(CE_NOTE, "!acpidev: producer encountered "
675 			    "a CONSUMER resource, ignored.");
676 		} else if (ACPI_FAILURE(AcpiResourceToAddress64(rscp,
677 		    &addr64))) {
678 			ACPIDEV_DEBUG(CE_WARN,
679 			    "!acpidev: failed to convert resource to ADDR64.");
680 		} else if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
681 		    &addr64))) {
682 			ACPIDEV_DEBUG(CE_WARN,
683 			    "!acpidev: failed to handle ADDRESS resource.");
684 		}
685 		break;
686 	}
687 
688 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
689 	{
690 		ACPI_RESOURCE_ADDRESS64 addr64;
691 
692 		if (rscp->Data.ExtAddress64.ProducerConsumer != ACPI_PRODUCER) {
693 			ACPIDEV_DEBUG(CE_NOTE, "!acpidev: producer encountered "
694 			    "a CONSUMER resource, ignored.");
695 			break;
696 		}
697 
698 		*(ACPI_RESOURCE_ADDRESS *)&addr64 = rscp->Data.Address;
699 		addr64.Granularity = rscp->Data.ExtAddress64.Granularity;
700 		addr64.Minimum = rscp->Data.ExtAddress64.Minimum;
701 		addr64.Maximum = rscp->Data.ExtAddress64.Maximum;
702 		addr64.TranslationOffset =
703 		    rscp->Data.ExtAddress64.TranslationOffset;
704 		addr64.AddressLength = rscp->Data.ExtAddress64.AddressLength;
705 		if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
706 		    &addr64))) {
707 			ACPIDEV_DEBUG(CE_WARN,
708 			    "!acpidev: failed to handle EXTADDRESS resource.");
709 		}
710 		break;
711 	}
712 
713 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
714 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
715 		ACPIDEV_DEBUG(CE_NOTE, "!acpidev: producer encountered "
716 		    "START_DEPENDENT or END_DEPENDENT tag, ignored.");
717 		break;
718 
719 	case ACPI_RESOURCE_TYPE_END_TAG:
720 		/* Finish walking when we encounter END_TAG. */
721 		rc = AE_CTRL_TERMINATE;
722 		break;
723 
724 	default:
725 		ACPIDEV_DEBUG(CE_NOTE,
726 		    "!acpidev: unknown ACPI resource type %u, ignored.",
727 		    rscp->Type);
728 		break;
729 	}
730 
731 	return (rc);
732 }
733 
734 static ACPI_STATUS
735 acpidev_resource_walk_consumer(ACPI_RESOURCE *rscp, void *ctxp)
736 {
737 	ACPI_STATUS rc = AE_OK;
738 	acpidev_resource_handle_t rhdl;
739 
740 	ASSERT(ctxp != NULL);
741 	rhdl = (acpidev_resource_handle_t)ctxp;
742 	ASSERT(rhdl->acpidev_consumer == B_TRUE);
743 
744 	switch (rscp->Type) {
745 	case ACPI_RESOURCE_TYPE_MEMORY24:
746 	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
747 	case ACPI_RESOURCE_TYPE_VENDOR:
748 		ACPIDEV_DEBUG(CE_NOTE,
749 		    "!acpidev: unsupported consumer resource type %u, ignored.",
750 		    rscp->Type);
751 		break;
752 
753 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
754 	{
755 		int i;
756 
757 		if (rscp->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
758 			ACPIDEV_DEBUG(CE_NOTE, "!acpidev: consumer encountered "
759 			    "a PRODUCER resource, ignored.");
760 			break;
761 		}
762 		for (i = 0; i < rscp->Data.ExtendedIrq.InterruptCount; i++) {
763 			if (ACPI_SUCCESS(acpidev_resource_insert_irq(rhdl,
764 			    rscp->Data.ExtendedIrq.Interrupts[i]))) {
765 				continue;
766 			}
767 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to insert"
768 			    "Extended IRQ into resource handle.");
769 			rc = AE_ERROR;
770 			break;
771 		}
772 		break;
773 	}
774 
775 	case ACPI_RESOURCE_TYPE_IRQ:
776 	{
777 		int i;
778 
779 		for (i = 0; i < rscp->Data.Irq.InterruptCount; i++) {
780 			if (ACPI_SUCCESS(acpidev_resource_insert_irq(rhdl,
781 			    rscp->Data.Irq.Interrupts[i]))) {
782 				continue;
783 			}
784 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to insert"
785 			    "IRQ into resource handle.");
786 			rc = AE_ERROR;
787 			break;
788 		}
789 		break;
790 	}
791 
792 	case ACPI_RESOURCE_TYPE_DMA:
793 	{
794 		int i;
795 
796 		for (i = 0; i < rscp->Data.Dma.ChannelCount; i++) {
797 			if (ACPI_SUCCESS(acpidev_resource_insert_dma(rhdl,
798 			    rscp->Data.Dma.Channels[i]))) {
799 				continue;
800 			}
801 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to insert"
802 			    "dma into resource handle.");
803 			rc = AE_ERROR;
804 			break;
805 		}
806 		break;
807 	}
808 
809 	case ACPI_RESOURCE_TYPE_IO:
810 	case ACPI_RESOURCE_TYPE_FIXED_IO:
811 	{
812 		acpidev_regspec_t reg;
813 
814 		reg.phys_hi = ACPIDEV_REG_TYPE_IO;
815 		reg.phys_hi |= ACPIDEV_REG_IO_RANGE_FULL;
816 		if (rscp->Type == ACPI_RESOURCE_TYPE_IO) {
817 			if (rscp->Data.Io.IoDecode == ACPI_DECODE_16) {
818 				reg.phys_hi |= ACPIDEV_REG_IO_DECODE16;
819 			}
820 			reg.phys_low = rscp->Data.Io.Minimum;
821 			reg.size_low = rscp->Data.Io.AddressLength;
822 		} else {
823 			reg.phys_hi |= ACPIDEV_REG_IO_DECODE16;
824 			reg.phys_low = rscp->Data.FixedIo.Address;
825 			reg.size_low = rscp->Data.FixedIo.AddressLength;
826 		}
827 		reg.phys_mid = 0;
828 		reg.size_hi = 0;
829 		if ((uint64_t)reg.phys_low + reg.size_low > UINT16_MAX) {
830 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid IO/FIXEDIO "
831 			    "record, IO max is out of range.");
832 			rc = AE_ERROR;
833 		} else if (reg.size_low != 0) {
834 			rc = acpidev_resource_insert_reg(rhdl, &reg);
835 			if (ACPI_FAILURE(rc)) {
836 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
837 				    "insert reg into resource handle.");
838 			}
839 		}
840 		break;
841 	}
842 
843 	case ACPI_RESOURCE_TYPE_MEMORY32:
844 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
845 	{
846 		acpidev_regspec_t reg;
847 
848 		reg.phys_hi = ACPIDEV_REG_TYPE_MEMORY;
849 		reg.phys_hi |= ACPIDEV_REG_MEM_COHERENT_CA;
850 		if (rscp->Type == ACPI_RESOURCE_TYPE_MEMORY32) {
851 			if (rscp->Data.Memory32.WriteProtect ==
852 			    ACPI_READ_WRITE_MEMORY) {
853 				reg.phys_hi |= ACPIDEV_REG_MEM_WRITABLE;
854 			}
855 			reg.phys_low = rscp->Data.Memory32.Minimum;
856 			reg.size_low = rscp->Data.Memory32.AddressLength;
857 		} else {
858 			if (rscp->Data.FixedMemory32.WriteProtect ==
859 			    ACPI_READ_WRITE_MEMORY) {
860 				reg.phys_hi |= ACPIDEV_REG_MEM_WRITABLE;
861 			}
862 			reg.phys_low = rscp->Data.FixedMemory32.Address;
863 			reg.size_low = rscp->Data.FixedMemory32.AddressLength;
864 		}
865 		reg.phys_mid = 0;
866 		reg.size_hi = 0;
867 		if ((uint64_t)reg.phys_low + reg.size_low > UINT32_MAX) {
868 			ACPIDEV_DEBUG(CE_WARN,
869 			    "!acpidev: invalid MEMORY32/FIXEDMEMORY32 record, "
870 			    "memory max is out of range.");
871 			rc = AE_ERROR;
872 		} else if (reg.size_low != 0) {
873 			rc = acpidev_resource_insert_reg(rhdl, &reg);
874 			if (ACPI_FAILURE(rc)) {
875 				ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
876 				    "insert reg into resource handle.");
877 			}
878 		}
879 		break;
880 	}
881 
882 	case ACPI_RESOURCE_TYPE_ADDRESS16:
883 	case ACPI_RESOURCE_TYPE_ADDRESS32:
884 	case ACPI_RESOURCE_TYPE_ADDRESS64:
885 	{
886 		ACPI_RESOURCE_ADDRESS64 addr64;
887 
888 		if (rscp->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
889 			ACPIDEV_DEBUG(CE_NOTE, "!acpidev: consumer encountered "
890 			    "a PRODUCER resource, ignored.");
891 		} else if (ACPI_FAILURE(AcpiResourceToAddress64(rscp,
892 		    &addr64))) {
893 			ACPIDEV_DEBUG(CE_WARN,
894 			    "!acpidev: failed to convert resource to ADDR64.");
895 		} else if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
896 		    &addr64))) {
897 			ACPIDEV_DEBUG(CE_WARN,
898 			    "!acpidev: failed to handle ADDRESS resource.");
899 		}
900 		break;
901 	}
902 
903 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
904 	{
905 		ACPI_RESOURCE_ADDRESS64 addr64;
906 
907 		if (rscp->Data.ExtAddress64.ProducerConsumer != ACPI_CONSUMER) {
908 			ACPIDEV_DEBUG(CE_NOTE, "!acpidev: consumer encountered "
909 			    "a PRODUCER resource, ignored.");
910 			break;
911 		}
912 
913 		*(ACPI_RESOURCE_ADDRESS *)&addr64 = rscp->Data.Address;
914 		addr64.Granularity = rscp->Data.ExtAddress64.Granularity;
915 		addr64.Minimum = rscp->Data.ExtAddress64.Minimum;
916 		addr64.Maximum = rscp->Data.ExtAddress64.Maximum;
917 		addr64.TranslationOffset =
918 		    rscp->Data.ExtAddress64.TranslationOffset;
919 		addr64.AddressLength = rscp->Data.ExtAddress64.AddressLength;
920 		if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
921 		    &addr64))) {
922 			ACPIDEV_DEBUG(CE_WARN,
923 			    "!acpidev: failed to handle EXTADDRESS resource.");
924 		}
925 		break;
926 	}
927 
928 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
929 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
930 		ACPIDEV_DEBUG(CE_NOTE, "!acpidev: consumer encountered "
931 		    "START_DEPENDENT or END_DEPENDENT tag, ignored.");
932 		break;
933 
934 	case ACPI_RESOURCE_TYPE_END_TAG:
935 		/* Finish walking when we encounter END_TAG. */
936 		rc = AE_CTRL_TERMINATE;
937 		break;
938 
939 	default:
940 		ACPIDEV_DEBUG(CE_NOTE,
941 		    "!acpidev: unknown ACPI resource type %u, ignored.",
942 		    rscp->Type);
943 		break;
944 	}
945 
946 	return (rc);
947 }
948 
949 ACPI_STATUS
950 acpidev_resource_walk(ACPI_HANDLE hdl, char *method,
951     boolean_t consumer, acpidev_resource_handle_t *rhdlp)
952 {
953 	ACPI_STATUS rc = AE_OK;
954 	ACPI_HANDLE mhdl = NULL;
955 	acpidev_resource_handle_t rhdl = NULL;
956 
957 	ASSERT(hdl != NULL);
958 	ASSERT(method != NULL);
959 	ASSERT(rhdlp != NULL);
960 	if (hdl == NULL) {
961 		ACPIDEV_DEBUG(CE_WARN,
962 		    "!acpidev: hdl is NULL in acpidev_resource_walk().");
963 		return (AE_BAD_PARAMETER);
964 	} else if (method == NULL) {
965 		ACPIDEV_DEBUG(CE_WARN,
966 		    "!acpidev: method is NULL in acpidev_resource_walk().");
967 		return (AE_BAD_PARAMETER);
968 	} else if (rhdlp == NULL) {
969 		ACPIDEV_DEBUG(CE_WARN, "!acpidev: resource handle ptr is NULL "
970 		    "in acpidev_resource_walk().");
971 		return (AE_BAD_PARAMETER);
972 	}
973 
974 	/* Check whether method exists under object. */
975 	if (ACPI_FAILURE(AcpiGetHandle(hdl, method, &mhdl))) {
976 		char *objname = acpidev_get_object_name(hdl);
977 		ACPIDEV_DEBUG(CE_NOTE,
978 		    "!acpidev: method %s doesn't exist under %s",
979 		    method, objname);
980 		acpidev_free_object_name(objname);
981 		return (AE_NOT_FOUND);
982 	}
983 
984 	/* Walk all resources. */
985 	rhdl = acpidev_resource_handle_alloc(consumer);
986 	if (consumer) {
987 		rc = AcpiWalkResources(hdl, method,
988 		    acpidev_resource_walk_consumer, rhdl);
989 	} else {
990 		rc = AcpiWalkResources(hdl, method,
991 		    acpidev_resource_walk_producer, rhdl);
992 	}
993 	if (ACPI_SUCCESS(rc)) {
994 		*rhdlp = rhdl;
995 	} else {
996 		acpidev_resource_handle_free(rhdl);
997 	}
998 	if (ACPI_FAILURE(rc)) {
999 		char *objname = acpidev_get_object_name(hdl);
1000 		ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to walk resource from "
1001 		    "method %s under %s.", method, objname);
1002 		acpidev_free_object_name(objname);
1003 	}
1004 
1005 	return (rc);
1006 }
1007 
1008 ACPI_STATUS
1009 acpidev_resource_process(acpidev_walk_info_t *infop, boolean_t consumer)
1010 {
1011 	ACPI_STATUS rc;
1012 	char path[MAXPATHLEN];
1013 	acpidev_resource_handle_t rhdl = NULL;
1014 
1015 	ASSERT(infop != NULL);
1016 	if (infop == NULL) {
1017 		ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameter "
1018 		    "in acpidev_resource_process().");
1019 		return (AE_BAD_PARAMETER);
1020 	}
1021 
1022 	/* Walk all resources. */
1023 	(void) ddi_pathname(infop->awi_dip, path);
1024 	rc = acpidev_resource_walk(infop->awi_hdl, METHOD_NAME__CRS,
1025 	    consumer, &rhdl);
1026 	if (ACPI_FAILURE(rc)) {
1027 		ACPIDEV_DEBUG(CE_WARN,
1028 		    "!acpidev: failed to walk ACPI resources of %s(%s).",
1029 		    path, infop->awi_name);
1030 		return (rc);
1031 	}
1032 
1033 	if (consumer) {
1034 		/* Create device properties for consumer. */
1035 
1036 		/* Create 'reg' and 'assigned-addresses' properties. */
1037 		if (rhdl->acpidev_reg_count > 0 &&
1038 		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
1039 		    "reg", (int *)rhdl->acpidev_regp,
1040 		    rhdl->acpidev_reg_count * sizeof (acpidev_regspec_t) /
1041 		    sizeof (int)) != NDI_SUCCESS) {
1042 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to set "
1043 			    "'reg' property for %s.", path);
1044 			rc = AE_ERROR;
1045 			goto out;
1046 		}
1047 		if (rhdl->acpidev_reg_count > 0 &&
1048 		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
1049 		    "assigned-addresses", (int *)rhdl->acpidev_regp,
1050 		    rhdl->acpidev_reg_count * sizeof (acpidev_regspec_t) /
1051 		    sizeof (int)) != NDI_SUCCESS) {
1052 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to set "
1053 			    "'assigned-addresses' property for %s.", path);
1054 			rc = AE_ERROR;
1055 			goto out;
1056 		}
1057 
1058 		/* Create 'interrupts' property. */
1059 		if (rhdl->acpidev_irq_count > 0 &&
1060 		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
1061 		    "interrupts", (int *)rhdl->acpidev_irqp,
1062 		    rhdl->acpidev_irq_count) != NDI_SUCCESS) {
1063 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to set "
1064 			    "'interrupts' property for %s.", path);
1065 			rc = AE_ERROR;
1066 			goto out;
1067 		}
1068 
1069 		/* Create 'dma-channels' property. */
1070 		if (rhdl->acpidev_dma_count > 0 &&
1071 		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
1072 		    "dma-channels", (int *)rhdl->acpidev_dmap,
1073 		    rhdl->acpidev_dma_count) != NDI_SUCCESS) {
1074 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to set "
1075 			    "'dma-channels' property for %s.", path);
1076 			rc = AE_ERROR;
1077 			goto out;
1078 		}
1079 
1080 	} else {
1081 		/* Create device properties for producer. */
1082 
1083 		/* Create 'ranges' property. */
1084 		if (rhdl->acpidev_range_count > 0 &&
1085 		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
1086 		    "ranges", (int *)rhdl->acpidev_rangep,
1087 		    rhdl->acpidev_range_count * sizeof (acpidev_ranges_t) /
1088 		    sizeof (int)) != NDI_SUCCESS) {
1089 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to set "
1090 			    "'ranges' property for %s.", path);
1091 			rc = AE_ERROR;
1092 			goto out;
1093 		}
1094 
1095 		/* Create 'bus-range' property. */
1096 		if (rhdl->acpidev_bus_count > 0 &&
1097 		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
1098 		    "bus-range", (int *)rhdl->acpidev_busp,
1099 		    rhdl->acpidev_bus_count * sizeof (acpidev_bus_range_t) /
1100 		    sizeof (int)) != NDI_SUCCESS) {
1101 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to set "
1102 			    "'bus-range' property for %s.", path);
1103 			rc = AE_ERROR;
1104 			goto out;
1105 		}
1106 	}
1107 
1108 out:
1109 	/* Free resources allocated by acpidev_resource_walk. */
1110 	acpidev_resource_handle_free(rhdl);
1111 
1112 	return (rc);
1113 }
1114