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 }