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