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, &reg);
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, &reg);
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, &reg);
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, &reg);
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