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 2018, Joyent, Inc. 23 * Copyright (c) 2012 Gary Mills 24 * 25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 * 28 * Copyright 2021 Racktop Systems, Inc. 29 */ 30 31 /* 32 * ACPI enumerator 33 */ 34 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/sunndi.h> 38 #include <sys/note.h> 39 #include <sys/acpi/acpi.h> 40 #include <sys/acpica.h> 41 #include <util/sscanf.h> 42 #include <util/qsort.h> 43 44 /* 45 * Used to track the interrupts used by a resource, as well as the set of 46 * interrupts used overall. The IRQ values are ints for historical purposes 47 * (the "interrupts" property has traditionally been an array of ints) even 48 * though negative IRQ values do not make much sense. 49 */ 50 typedef struct intrs { 51 int *i_intrs; 52 uint_t i_num; 53 uint_t i_alloc; 54 } intrs_t; 55 56 static char keyboard_alias[] = "keyboard"; 57 static char mouse_alias[] = "mouse"; 58 #define ACPI_ENUM_DEBUG "acpi_enum_debug" 59 #define PARSE_RESOURCES_DEBUG 0x0001 60 #define MASTER_LOOKUP_DEBUG 0x0002 61 #define DEVICES_NOT_ENUMED 0x0004 62 #define PARSE_RES_IRQ 0x0008 63 #define PARSE_RES_DMA 0x0010 64 #define PARSE_RES_MEMORY 0x0020 65 #define PARSE_RES_IO 0x0040 66 #define PARSE_RES_ADDRESS 0x0080 67 #define ISA_DEVICE_ENUM 0x1000 68 #define PROCESS_CIDS 0x2000 69 static unsigned long acpi_enum_debug = 0x00; 70 71 static char USED_RESOURCES[] = "used-resources"; 72 static dev_info_t *usedrdip = NULL; 73 static intrs_t used_interrupts; 74 static unsigned short used_dmas = 0; 75 typedef struct used_io_mem { 76 unsigned int start_addr; 77 unsigned int length; 78 struct used_io_mem *next; 79 } used_io_mem_t; 80 static used_io_mem_t *used_io_head = NULL; 81 static used_io_mem_t *used_mem_head = NULL; 82 static int used_io_count = 0; 83 static int used_mem_count = 0; 84 85 #define MAX_PARSED_ACPI_RESOURCES 255 86 #define ACPI_ISA_LIMIT 16 87 static int dma[ACPI_ISA_LIMIT]; 88 #define ACPI_ELEMENT_PACKAGE_LIMIT 32 89 #define EISA_ID_SIZE 7 90 91 static void 92 add_interrupt(intrs_t *intrs, int irq) 93 { 94 /* We only want to add the value once */ 95 for (uint_t i = 0; i < intrs->i_num; i++) { 96 if (intrs->i_intrs[i] == irq) 97 return; 98 } 99 100 /* 101 * Initially, i_num and i_alloc will be 0, and we allocate 102 * i_intrs to hold ACPI_ISA_LIMIT values on the initial add attempt. 103 * Since ISA buses could only use at most ACPI_ISA_LIMIT (16) 104 * interrupts, this seems like a reasonable size. The extended IRQ 105 * resource however exists explicitly to support IRQ values beyond 106 * 16. That suggests it may be possible on some hardware to exceed 107 * the initial allocation. If we do exceed the initial allocation, we 108 * grow i_intrs in chunks of ACPI_ISA_LIMIT since that's as good an 109 * amount as any. 110 */ 111 if (intrs->i_num == intrs->i_alloc) { 112 uint_t newlen = intrs->i_alloc + ACPI_ISA_LIMIT; 113 size_t newsz = newlen * sizeof (int); 114 size_t oldsz = intrs->i_alloc * sizeof (int); 115 int *newar = kmem_alloc(newsz, KM_SLEEP); 116 117 if (intrs->i_num > 0) { 118 bcopy(intrs->i_intrs, newar, oldsz); 119 kmem_free(intrs->i_intrs, oldsz); 120 } 121 122 intrs->i_intrs = newar; 123 intrs->i_alloc = newlen; 124 } 125 126 intrs->i_intrs[intrs->i_num++] = irq; 127 } 128 129 /* 130 * insert used io/mem in increasing order 131 */ 132 static void 133 insert_used_resource(used_io_mem_t *used, int *used_count, used_io_mem_t **head) 134 { 135 used_io_mem_t *curr, *prev; 136 137 (*used_count)++; 138 if (*head == NULL) { 139 *head = used; 140 return; 141 } 142 curr = prev = *head; 143 /* find a place to insert */ 144 while ((curr != NULL) && 145 (curr->start_addr < used->start_addr)) { 146 prev = curr; 147 curr = curr->next; 148 } 149 if (prev == curr) { 150 /* head */ 151 *head = used; 152 used->next = curr; 153 return; 154 } else { 155 prev->next = used; 156 } 157 used->next = curr; 158 } 159 160 static void 161 add_used_io_mem(struct regspec *io, int io_count) 162 { 163 int i; 164 used_io_mem_t *used; 165 166 for (i = 0; i < io_count; i++) { 167 used = (used_io_mem_t *)kmem_zalloc(sizeof (used_io_mem_t), 168 KM_SLEEP); 169 used->start_addr = io[i].regspec_addr; 170 used->length = io[i].regspec_size; 171 if (io[i].regspec_bustype == 1) { 172 insert_used_resource(used, &used_io_count, 173 &used_io_head); 174 } else { 175 insert_used_resource(used, &used_mem_count, 176 &used_mem_head); 177 } 178 } 179 } 180 181 static void 182 parse_resources_irq(ACPI_RESOURCE *resource_ptr, intrs_t *intrs) 183 { 184 uint_t i; 185 186 for (i = 0; i < resource_ptr->Data.Irq.InterruptCount; i++) { 187 uint8_t irq = resource_ptr->Data.Irq.Interrupts[i]; 188 189 add_interrupt(intrs, irq); 190 add_interrupt(&used_interrupts, irq); 191 192 if (acpi_enum_debug & PARSE_RES_IRQ) { 193 cmn_err(CE_NOTE, "!%s() IRQ num %u, intr # = %u", 194 __func__, i, irq); 195 } 196 } 197 } 198 199 static void 200 parse_resources_extended_irq(ACPI_RESOURCE *resource_ptr, intrs_t *intrs) 201 { 202 uint_t i; 203 204 for (i = 0; i < resource_ptr->Data.ExtendedIrq.InterruptCount; i++) { 205 uint32_t irq = resource_ptr->Data.ExtendedIrq.Interrupts[i]; 206 207 /* 208 * As noted in the definition of intrs_t above, traditionally 209 * the "interrupts" property is an array of ints. This is 210 * more precautionary than anything since it seems unlikely 211 * that anything will have an irq value > 2^31 anytime soon. 212 */ 213 if (irq > INT32_MAX) { 214 if (acpi_enum_debug & PARSE_RES_IRQ) { 215 cmn_err(CE_NOTE, 216 "!%s() intr # = %u out of range", 217 __func__, irq); 218 } 219 continue; 220 } 221 222 add_interrupt(intrs, irq); 223 add_interrupt(&used_interrupts, irq); 224 225 if (acpi_enum_debug & PARSE_RES_IRQ) { 226 cmn_err(CE_NOTE, "!%s() IRQ num %u, intr # = %u", 227 __func__, i, irq); 228 } 229 } 230 } 231 232 static void 233 parse_resources_dma(ACPI_RESOURCE *resource_ptr, int *dma_count) 234 { 235 int i; 236 237 for (i = 0; i < resource_ptr->Data.Dma.ChannelCount; i++) { 238 dma[(*dma_count)++] = resource_ptr->Data.Dma.Channels[i]; 239 used_dmas |= 1 << resource_ptr->Data.Dma.Channels[i]; 240 if (acpi_enum_debug & PARSE_RES_DMA) { 241 cmn_err(CE_NOTE, "!parse_resources() "\ 242 "DMA num %u, channel # = %u", 243 i, resource_ptr->Data.Dma.Channels[i]); 244 } 245 } 246 } 247 248 static void 249 parse_resources_io(ACPI_RESOURCE *resource_ptr, struct regspec *io, 250 int *io_count) 251 { 252 ACPI_RESOURCE_IO acpi_io = resource_ptr->Data.Io; 253 254 if (acpi_io.AddressLength == 0) 255 return; 256 257 io[*io_count].regspec_bustype = 1; /* io */ 258 io[*io_count].regspec_size = acpi_io.AddressLength; 259 io[*io_count].regspec_addr = acpi_io.Minimum; 260 if (acpi_enum_debug & PARSE_RES_IO) { 261 cmn_err(CE_NOTE, "!parse_resources() "\ 262 "IO min 0x%X, max 0x%X, length: 0x%X", 263 acpi_io.Minimum, 264 acpi_io.Maximum, 265 acpi_io.AddressLength); 266 } 267 (*io_count)++; 268 } 269 270 static void 271 parse_resources_fixed_io(ACPI_RESOURCE *resource_ptr, struct regspec *io, 272 int *io_count) 273 { 274 ACPI_RESOURCE_FIXED_IO fixed_io = resource_ptr->Data.FixedIo; 275 276 if (fixed_io.AddressLength == 0) 277 return; 278 279 io[*io_count].regspec_bustype = 1; /* io */ 280 io[*io_count].regspec_addr = fixed_io.Address; 281 io[*io_count].regspec_size = fixed_io.AddressLength; 282 if (acpi_enum_debug & PARSE_RES_IO) { 283 cmn_err(CE_NOTE, "!parse_resources() "\ 284 "Fixed IO 0x%X, length: 0x%X", 285 fixed_io.Address, fixed_io.AddressLength); 286 } 287 (*io_count)++; 288 } 289 290 static void 291 parse_resources_fixed_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io, 292 int *io_count) 293 { 294 ACPI_RESOURCE_FIXED_MEMORY32 fixed_mem32 = 295 resource_ptr->Data.FixedMemory32; 296 297 if (fixed_mem32.AddressLength == 0) 298 return; 299 300 io[*io_count].regspec_bustype = 0; /* memory */ 301 io[*io_count].regspec_addr = fixed_mem32.Address; 302 io[*io_count].regspec_size = fixed_mem32.AddressLength; 303 if (acpi_enum_debug & PARSE_RES_MEMORY) { 304 cmn_err(CE_NOTE, "!parse_resources() "\ 305 "Fixed Mem 32 %ul, length: %ul", 306 fixed_mem32.Address, fixed_mem32.AddressLength); 307 } 308 (*io_count)++; 309 } 310 311 static void 312 parse_resources_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io, 313 int *io_count) 314 { 315 ACPI_RESOURCE_MEMORY32 mem32 = resource_ptr->Data.Memory32; 316 317 if (mem32.AddressLength == 0) 318 return; 319 320 if (resource_ptr->Data.Memory32.Minimum == 321 resource_ptr->Data.Memory32.Maximum) { 322 io[*io_count].regspec_bustype = 0; /* memory */ 323 io[*io_count].regspec_addr = mem32.Minimum; 324 io[*io_count].regspec_size = mem32.AddressLength; 325 (*io_count)++; 326 if (acpi_enum_debug & PARSE_RES_MEMORY) { 327 cmn_err(CE_NOTE, "!parse_resources() "\ 328 "Mem 32 0x%X, length: 0x%X", 329 mem32.Minimum, mem32.AddressLength); 330 } 331 return; 332 } 333 if (acpi_enum_debug & PARSE_RES_MEMORY) { 334 cmn_err(CE_NOTE, "!parse_resources() "\ 335 "MEM32 Min Max not equal!"); 336 cmn_err(CE_NOTE, "!parse_resources() "\ 337 "Mem 32 Minimum 0x%X, Maximum: 0x%X", 338 mem32.Minimum, mem32.Maximum); 339 } 340 } 341 342 static void 343 parse_resources_addr16(ACPI_RESOURCE *resource_ptr, struct regspec *io, 344 int *io_count) 345 { 346 ACPI_RESOURCE_ADDRESS16 addr16 = 347 resource_ptr->Data.Address16; 348 349 if (addr16.Address.AddressLength == 0) 350 return; 351 352 if (acpi_enum_debug & PARSE_RES_ADDRESS) { 353 if (addr16.ResourceType == ACPI_MEMORY_RANGE) { 354 cmn_err(CE_NOTE, "!parse_resources() "\ 355 "ADDRESS 16 MEMORY RANGE"); 356 } else 357 if (addr16.ResourceType == ACPI_IO_RANGE) { 358 cmn_err(CE_NOTE, "!parse_resources() "\ 359 "ADDRESS 16 IO RANGE"); 360 } else { 361 cmn_err(CE_NOTE, "!parse_resources() "\ 362 "ADDRESS 16 OTHER"); 363 } 364 cmn_err(CE_NOTE, "!parse_resources() "\ 365 "%s "\ 366 "MinAddressFixed 0x%X, "\ 367 "MaxAddressFixed 0x%X, "\ 368 "Minimum 0x%X, "\ 369 "Maximum 0x%X, "\ 370 "length: 0x%X\n", 371 addr16.ProducerConsumer == ACPI_CONSUMER ? 372 "CONSUMER" : "PRODUCER", 373 addr16.MinAddressFixed, 374 addr16.MaxAddressFixed, 375 addr16.Address.Minimum, 376 addr16.Address.Maximum, 377 addr16.Address.AddressLength); 378 } 379 if (addr16.ProducerConsumer == ACPI_PRODUCER || 380 (addr16.ResourceType != ACPI_MEMORY_RANGE && 381 addr16.ResourceType != ACPI_IO_RANGE)) { 382 return; 383 } 384 if (addr16.Address.AddressLength > 0) { 385 if (addr16.ResourceType == ACPI_MEMORY_RANGE) { 386 /* memory */ 387 io[*io_count].regspec_bustype = 0; 388 } else { 389 /* io */ 390 io[*io_count].regspec_bustype = 1; 391 } 392 io[*io_count].regspec_addr = addr16.Address.Minimum; 393 io[*io_count].regspec_size = addr16.Address.AddressLength; 394 (*io_count)++; 395 } 396 } 397 398 static void 399 parse_resources_addr32(ACPI_RESOURCE *resource_ptr, struct regspec *io, 400 int *io_count) 401 { 402 ACPI_RESOURCE_ADDRESS32 addr32 = 403 resource_ptr->Data.Address32; 404 405 if (addr32.Address.AddressLength == 0) 406 return; 407 408 if (acpi_enum_debug & PARSE_RES_ADDRESS) { 409 if (addr32.ResourceType == ACPI_MEMORY_RANGE) { 410 cmn_err(CE_NOTE, "!parse_resources() "\ 411 "ADDRESS 32 MEMORY RANGE"); 412 } else 413 if (addr32.ResourceType == ACPI_IO_RANGE) { 414 cmn_err(CE_NOTE, "!parse_resources() "\ 415 "ADDRESS 32 IO RANGE"); 416 } else { 417 cmn_err(CE_NOTE, "!parse_resources() "\ 418 "ADDRESS 32 OTHER"); 419 } 420 cmn_err(CE_NOTE, "!parse_resources() "\ 421 "%s "\ 422 "MinAddressFixed 0x%X, "\ 423 "MaxAddressFixed 0x%X, "\ 424 "Minimum 0x%X, "\ 425 "Maximum 0x%X, "\ 426 "length: 0x%X\n", 427 addr32.ProducerConsumer == ACPI_CONSUMER ? 428 "CONSUMER" : "PRODUCER", 429 addr32.MinAddressFixed, 430 addr32.MaxAddressFixed, 431 addr32.Address.Minimum, 432 addr32.Address.Maximum, 433 addr32.Address.AddressLength); 434 } 435 if (addr32.ProducerConsumer == ACPI_PRODUCER || 436 (addr32.ResourceType != ACPI_MEMORY_RANGE && 437 addr32.ResourceType != ACPI_IO_RANGE)) { 438 return; 439 } 440 if (addr32.Address.AddressLength > 0) { 441 if (addr32.ResourceType == ACPI_MEMORY_RANGE) { 442 /* memory */ 443 io[*io_count].regspec_bustype = 0; 444 } else { 445 /* io */ 446 io[*io_count].regspec_bustype = 1; 447 } 448 io[*io_count].regspec_addr = addr32.Address.Minimum; 449 io[*io_count].regspec_size = addr32.Address.AddressLength; 450 (*io_count)++; 451 } 452 } 453 454 static void 455 parse_resources_addr64(ACPI_RESOURCE *resource_ptr, struct regspec *io, 456 int *io_count) 457 { 458 ACPI_RESOURCE_ADDRESS64 addr64 = 459 resource_ptr->Data.Address64; 460 461 if (addr64.Address.AddressLength == 0) 462 return; 463 464 if (acpi_enum_debug & PARSE_RES_ADDRESS) { 465 if (addr64.ResourceType == ACPI_MEMORY_RANGE) { 466 cmn_err(CE_NOTE, "!parse_resources() "\ 467 "ADDRESS 64 MEMORY RANGE"); 468 } else 469 if (addr64.ResourceType == ACPI_IO_RANGE) { 470 cmn_err(CE_NOTE, "!parse_resources() "\ 471 "ADDRESS 64 IO RANGE"); 472 } else { 473 cmn_err(CE_NOTE, "!parse_resources() "\ 474 "ADDRESS 64 OTHER"); 475 } 476 #ifdef _LP64 477 cmn_err(CE_NOTE, "!parse_resources() "\ 478 "%s "\ 479 "MinAddressFixed 0x%X, "\ 480 "MaxAddressFixed 0x%X, "\ 481 "Minimum 0x%lX, "\ 482 "Maximum 0x%lX, "\ 483 "length: 0x%lX\n", 484 addr64.ProducerConsumer == ACPI_CONSUMER ? 485 "CONSUMER" : "PRODUCER", 486 addr64.MinAddressFixed, 487 addr64.MaxAddressFixed, 488 addr64.Address.Minimum, 489 addr64.Address.Maximum, 490 addr64.Address.AddressLength); 491 #else 492 cmn_err(CE_NOTE, "!parse_resources() "\ 493 "%s "\ 494 "MinAddressFixed 0x%X, "\ 495 "MaxAddressFixed 0x%X, "\ 496 "Minimum 0x%llX, "\ 497 "Maximum 0x%llX, "\ 498 "length: 0x%llX\n", 499 addr64.ProducerConsumer == ACPI_CONSUMER ? 500 "CONSUMER" : "PRODUCER", 501 addr64.MinAddressFixed, 502 addr64.MaxAddressFixed, 503 addr64.Address.Minimum, 504 addr64.Address.Maximum, 505 addr64.Address.AddressLength); 506 #endif 507 } 508 if (addr64.ProducerConsumer == ACPI_PRODUCER || 509 (addr64.ResourceType != ACPI_MEMORY_RANGE && 510 addr64.ResourceType != ACPI_IO_RANGE)) { 511 return; 512 } 513 if (addr64.Address.AddressLength > 0) { 514 if (addr64.ResourceType == ACPI_MEMORY_RANGE) { 515 /* memory */ 516 io[*io_count].regspec_bustype = 0; 517 } else { 518 /* io */ 519 io[*io_count].regspec_bustype = 1; 520 } 521 io[*io_count].regspec_addr = addr64.Address.Minimum; 522 io[*io_count].regspec_size = addr64.Address.AddressLength; 523 (*io_count)++; 524 } 525 } 526 527 static ACPI_STATUS 528 parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path) 529 { 530 ACPI_BUFFER buf; 531 ACPI_RESOURCE *resource_ptr; 532 ACPI_STATUS status; 533 char *current_ptr, *last_ptr; 534 struct regspec *io; 535 intrs_t intrs = { 0 }; 536 int io_count = 0, dma_count = 0; 537 int i; 538 539 buf.Length = ACPI_ALLOCATE_BUFFER; 540 status = AcpiGetCurrentResources(handle, &buf); 541 switch (status) { 542 case AE_OK: 543 break; 544 case AE_NOT_FOUND: 545 /* 546 * Workaround for faulty DSDT tables that omit the _CRS 547 * method for the UAR3 device but have a valid _PRS method 548 * for that device. 549 */ 550 status = AcpiGetPossibleResources(handle, &buf); 551 if (status != AE_OK) { 552 return (status); 553 } 554 break; 555 default: 556 cmn_err(CE_WARN, 557 "!AcpiGetCurrentResources failed for %s, exception: %s", 558 path, AcpiFormatException(status)); 559 return (status); 560 break; 561 } 562 io = (struct regspec *)kmem_zalloc(sizeof (struct regspec) * 563 MAX_PARSED_ACPI_RESOURCES, KM_SLEEP); 564 current_ptr = buf.Pointer; 565 last_ptr = (char *)buf.Pointer + buf.Length; 566 while (current_ptr < last_ptr) { 567 if (io_count >= MAX_PARSED_ACPI_RESOURCES) { 568 break; 569 } 570 resource_ptr = (ACPI_RESOURCE *)current_ptr; 571 current_ptr += resource_ptr->Length; 572 switch (resource_ptr->Type) { 573 case ACPI_RESOURCE_TYPE_END_TAG: 574 current_ptr = last_ptr; 575 break; 576 case ACPI_RESOURCE_TYPE_IO: 577 parse_resources_io(resource_ptr, io, &io_count); 578 break; 579 case ACPI_RESOURCE_TYPE_FIXED_IO: 580 parse_resources_fixed_io(resource_ptr, io, &io_count); 581 break; 582 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 583 parse_resources_fixed_mem32(resource_ptr, io, 584 &io_count); 585 break; 586 case ACPI_RESOURCE_TYPE_MEMORY32: 587 parse_resources_mem32(resource_ptr, io, &io_count); 588 break; 589 case ACPI_RESOURCE_TYPE_ADDRESS16: 590 parse_resources_addr16(resource_ptr, io, &io_count); 591 break; 592 case ACPI_RESOURCE_TYPE_ADDRESS32: 593 parse_resources_addr32(resource_ptr, io, &io_count); 594 break; 595 case ACPI_RESOURCE_TYPE_ADDRESS64: 596 parse_resources_addr64(resource_ptr, io, &io_count); 597 break; 598 case ACPI_RESOURCE_TYPE_IRQ: 599 parse_resources_irq(resource_ptr, &intrs); 600 break; 601 case ACPI_RESOURCE_TYPE_DMA: 602 parse_resources_dma(resource_ptr, &dma_count); 603 break; 604 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 605 cmn_err(CE_NOTE, 606 "!ACPI source type" 607 " ACPI_RESOURCE_TYPE_START_DEPENDENT" 608 " not supported"); 609 break; 610 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 611 cmn_err(CE_NOTE, 612 "!ACPI source type" 613 " ACPI_RESOURCE_TYPE_END_DEPENDENT" 614 " not supported"); 615 break; 616 case ACPI_RESOURCE_TYPE_VENDOR: 617 cmn_err(CE_NOTE, 618 "!ACPI source type" 619 " ACPI_RESOURCE_TYPE_VENDOR" 620 " not supported"); 621 break; 622 case ACPI_RESOURCE_TYPE_MEMORY24: 623 cmn_err(CE_NOTE, 624 "!ACPI source type" 625 " ACPI_RESOURCE_TYPE_MEMORY24" 626 " not supported"); 627 break; 628 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 629 parse_resources_extended_irq(resource_ptr, &intrs); 630 break; 631 default: 632 /* Some types are not yet implemented (See CA 6.4) */ 633 cmn_err(CE_NOTE, 634 "!ACPI resource type (0X%X) not yet supported", 635 resource_ptr->Type); 636 break; 637 } 638 } 639 640 if (io_count) { 641 /* 642 * on LX50, you get interrupts of mouse and keyboard 643 * from separate PNP id... 644 */ 645 if (io_count == 2) { 646 if ((io[0].regspec_addr == 0x60 && 647 io[1].regspec_addr == 0x64) || 648 (io[0].regspec_addr == 0x64 && 649 io[1].regspec_addr == 0x60)) { 650 intrs.i_num = 0; 651 add_interrupt(&intrs, 0x1); 652 add_interrupt(&intrs, 0xc); 653 add_interrupt(&used_interrupts, 0x1); 654 add_interrupt(&used_interrupts, 0xc); 655 } 656 } 657 add_used_io_mem(io, io_count); 658 if (xdip != NULL) { 659 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 660 "reg", (int *)io, 3*io_count); 661 } 662 } 663 if (intrs.i_num > 0) { 664 if (xdip != NULL) { 665 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 666 "interrupts", intrs.i_intrs, intrs.i_num); 667 } 668 kmem_free(intrs.i_intrs, intrs.i_alloc * sizeof (int)); 669 } 670 if (dma_count && (xdip != NULL)) { 671 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 672 "dma-channels", (int *)dma, dma_count); 673 } 674 AcpiOsFree(buf.Pointer); 675 kmem_free(io, sizeof (struct regspec) * MAX_PARSED_ACPI_RESOURCES); 676 return (status); 677 } 678 679 /* keyboard mouse is under i8042, everything else under isa */ 680 static dev_info_t * 681 get_bus_dip(char *nodename, dev_info_t *isa_dip) 682 { 683 static dev_info_t *i8042_dip = NULL; 684 struct regspec i8042_regs[] = { 685 {1, 0x60, 0x1}, 686 {1, 0x64, 0x1} 687 }; 688 int i8042_intrs[] = {0x1, 0xc}; 689 690 if (strcmp(nodename, keyboard_alias) != 0 && 691 strcmp(nodename, mouse_alias) != 0) 692 return (isa_dip); 693 694 if (i8042_dip) 695 return (i8042_dip); 696 697 ndi_devi_alloc_sleep(isa_dip, "i8042", (pnode_t)DEVI_SID_NODEID, 698 &i8042_dip); 699 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip, 700 "reg", (int *)i8042_regs, 6); 701 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip, 702 "interrupts", (int *)i8042_intrs, 2); 703 (void) ndi_prop_update_string(DDI_DEV_T_NONE, i8042_dip, 704 "unit-address", "1,60"); 705 (void) ndi_devi_bind_driver(i8042_dip, 0); 706 return (i8042_dip); 707 } 708 709 /* 710 * put content of properties (if any) to dev info tree at branch xdip 711 * return non-zero if a "compatible" property was processed, zero otherwise 712 * 713 */ 714 static int 715 process_properties(dev_info_t *xdip, property_t *properties) 716 { 717 int rv = 0; 718 719 while (properties != NULL) { 720 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 721 properties->name, properties->value); 722 if (strcmp(properties->name, "compatible") == 0) 723 rv = 1; 724 properties = properties->next; 725 } 726 727 return (rv); 728 } 729 730 void 731 eisa_to_str(ACPI_INTEGER id, char *np) 732 { 733 static const char hextab[] = "0123456789ABCDEF"; 734 735 /* 736 * Expand an EISA device name: 737 * 738 * This routine converts a 32-bit EISA device "id" to a 739 * 7-byte ASCII device name, which is stored at "np". 740 */ 741 742 *np++ = '@' + ((id >> 2) & 0x1F); 743 *np++ = '@' + ((id << 3) & 0x18) + ((id >> 13) & 0x07); 744 *np++ = '@' + ((id >> 8) & 0x1F); 745 *np++ = hextab[(id >> 20) & 0x0F]; 746 *np++ = hextab[(id >> 16) & 0x0F]; 747 *np++ = hextab[(id >> 28) & 0x0F]; 748 *np++ = hextab[(id >> 24) & 0x0F]; 749 *np = 0; 750 } 751 752 /* 753 * process_cids() -- process multiple CIDs in a package 754 */ 755 static void 756 process_cids(ACPI_OBJECT *rv, device_id_t **dd) 757 { 758 device_id_t *d; 759 char tmp_cidstr[8]; /* 7-character EISA ID */ 760 int i; 761 762 if ((rv->Package.Count == 0) || rv->Package.Elements == NULL) 763 return; /* empty package */ 764 765 /* 766 * Work the package 'backwards' so the resulting list is 767 * in original order of preference. 768 */ 769 for (i = rv->Package.Count - 1; i >= 0; i--) { 770 /* get the actual acpi_object */ 771 ACPI_OBJECT obj = rv->Package.Elements[i]; 772 switch (obj.Type) { 773 case ACPI_TYPE_INTEGER: 774 eisa_to_str(obj.Integer.Value, tmp_cidstr); 775 d = mf_alloc_device_id(); 776 d->id = strdup(tmp_cidstr); 777 d->next = *dd; 778 *dd = d; 779 break; 780 case ACPI_TYPE_STRING: 781 d = mf_alloc_device_id(); 782 d->id = strdup(obj.String.Pointer); 783 d->next = *dd; 784 *dd = d; 785 break; 786 default: 787 if (acpi_enum_debug & PROCESS_CIDS) { 788 cmn_err(CE_NOTE, "!unexpected CID type: %d", 789 obj.Type); 790 } 791 break; 792 } 793 } 794 } 795 796 /* 797 * Convert "raw" PNP and ACPI IDs to IEEE 1275-compliant form. 798 * Some liberty is taken here, treating "ACPI" as a special form 799 * of PNP vendor ID. strsize specifies size of buffer. 800 */ 801 static void 802 convert_to_pnp1275(char *pnpid, char *str, int strsize) 803 { 804 char vendor[5]; 805 uint_t id; 806 807 if (strncmp(pnpid, "ACPI", 4) == 0) { 808 /* Assume ACPI ID: ACPIxxxx */ 809 sscanf(pnpid, "%4s%x", vendor, &id); 810 } else { 811 /* Assume PNP ID: aaaxxxx */ 812 sscanf(pnpid, "%3s%x", vendor, &id); 813 } 814 815 snprintf(str, strsize, "pnp%s,%x", vendor, id); 816 } 817 818 /* 819 * Given a list of device ID elements in most-to-least-specific 820 * order, create a "compatible" property. 821 */ 822 static void 823 create_compatible_property(dev_info_t *dip, device_id_t *ids) 824 { 825 char **strs; 826 int list_len, i; 827 device_id_t *d; 828 829 /* count list length */ 830 list_len = 0; 831 d = ids; 832 while (d != NULL) { 833 list_len++; 834 d = d->next; 835 } 836 837 /* create string array */ 838 strs = (char **)kmem_zalloc(list_len * sizeof (char *), KM_SLEEP); 839 i = 0; 840 d = ids; 841 while (d != NULL) { 842 /* strlen("pnpXXXX,xxxx") + 1 = 13 */ 843 strs[i] = kmem_zalloc(13, KM_SLEEP); 844 convert_to_pnp1275(d->id, strs[i++], 13); 845 d = d->next; 846 } 847 848 /* update property */ 849 (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, 850 "compatible", strs, list_len); 851 852 853 /* free memory */ 854 for (i = 0; i < list_len; i++) 855 kmem_free(strs[i], 13); 856 857 kmem_free(strs, list_len * sizeof (char *)); 858 } 859 860 /* 861 * isa_acpi_callback() 862 */ 863 static ACPI_STATUS 864 isa_acpi_callback(ACPI_HANDLE ObjHandle, uint32_t NestingLevel, void *a, 865 void **b) 866 { 867 _NOTE(ARGUNUSED(NestingLevel, b)) 868 869 ACPI_BUFFER rb; 870 ACPI_DEVICE_INFO *info = NULL; 871 char *path = NULL; 872 char *hidstr = NULL; 873 char tmp_cidstr[8]; /* EISAID size */ 874 dev_info_t *dip = (dev_info_t *)a; 875 dev_info_t *xdip = NULL; 876 device_id_t *d, *device_ids = NULL; 877 const master_rec_t *m; 878 int compatible_present = 0; 879 int status; 880 881 /* 882 * get full ACPI pathname for object 883 */ 884 rb.Length = ACPI_ALLOCATE_BUFFER; 885 rb.Pointer = NULL; 886 if (AcpiGetName(ObjHandle, ACPI_FULL_PATHNAME, &rb) != AE_OK) { 887 cmn_err(CE_WARN, "!acpi_enum: could not get pathname"); 888 goto done; 889 } 890 path = (char *)rb.Pointer; 891 892 /* 893 * Get device info object 894 */ 895 if (AcpiGetObjectInfo(ObjHandle, &info) != AE_OK) { 896 cmn_err(CE_WARN, "!acpi_enum: could not get device" 897 " info for %s", path); 898 goto done; 899 } 900 901 /* 902 * If device isn't present, we don't enumerate 903 * NEEDSWORK: what about docking bays and the like? 904 */ 905 if (ACPI_FAILURE(acpica_get_object_status(ObjHandle, &status))) { 906 cmn_err(CE_WARN, "!acpi_enum: no _STA for %s", path); 907 goto done; 908 } 909 910 /* 911 * CA 6.3.6 _STA method 912 * Bit 0 -- device is present 913 * Bit 1 -- device is enabled 914 * Bit 2 -- device is shown in UI 915 */ 916 if ((status & 0x7) != 0x7) { 917 if (acpi_enum_debug & DEVICES_NOT_ENUMED) { 918 cmn_err(CE_NOTE, "!parse_resources() " 919 "Bad status 0x%x for %s", 920 status, path); 921 } 922 goto done; 923 } 924 925 /* 926 * Keep track of _HID value 927 */ 928 if (!(info->Valid & ACPI_VALID_HID)) { 929 /* No _HID, we skip this node */ 930 if (acpi_enum_debug & DEVICES_NOT_ENUMED) { 931 cmn_err(CE_NOTE, "!parse_resources() " 932 "No _HID for %s", path); 933 } 934 goto done; 935 } 936 hidstr = info->HardwareId.String; 937 938 /* 939 * Attempt to get _CID value 940 */ 941 rb.Length = ACPI_ALLOCATE_BUFFER; 942 rb.Pointer = NULL; 943 if (AcpiEvaluateObject(ObjHandle, "_CID", NULL, &rb) == AE_OK && 944 rb.Length != 0) { 945 ACPI_OBJECT *rv = rb.Pointer; 946 947 switch (rv->Type) { 948 case ACPI_TYPE_INTEGER: 949 eisa_to_str(rv->Integer.Value, tmp_cidstr); 950 d = mf_alloc_device_id(); 951 d->id = strdup(tmp_cidstr); 952 d->next = device_ids; 953 device_ids = d; 954 break; 955 case ACPI_TYPE_STRING: 956 d = mf_alloc_device_id(); 957 d->id = strdup(rv->String.Pointer); 958 d->next = device_ids; 959 device_ids = d; 960 break; 961 case ACPI_TYPE_PACKAGE: 962 process_cids(rv, &device_ids); 963 break; 964 default: 965 break; 966 } 967 AcpiOsFree(rb.Pointer); 968 } 969 970 /* 971 * Add _HID last so it's at the head of the list 972 */ 973 d = mf_alloc_device_id(); 974 d->id = strdup(hidstr); 975 d->next = device_ids; 976 device_ids = d; 977 978 /* 979 * master_file_lookup() expects _HID first in device_ids 980 */ 981 if ((m = master_file_lookup(device_ids)) != NULL) { 982 /* PNP description found in master table */ 983 if (!(strncmp(hidstr, "ACPI", 4))) { 984 dip = ddi_root_node(); 985 } else { 986 dip = get_bus_dip(m->name, dip); 987 } 988 ndi_devi_alloc_sleep(dip, m->name, 989 (pnode_t)DEVI_SID_NODEID, &xdip); 990 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 991 "model", m->description); 992 compatible_present = process_properties(xdip, m->properties); 993 } else { 994 /* for ISA devices not known to the master file */ 995 if (!(strncmp(hidstr, "PNP03", 5))) { 996 /* a keyboard device includes PNP03xx */ 997 dip = get_bus_dip(keyboard_alias, dip); 998 ndi_devi_alloc_sleep(dip, keyboard_alias, 999 (pnode_t)DEVI_SID_NODEID, &xdip); 1000 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1001 "compatible", "pnpPNP,303"); 1002 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1003 "model", "PNP03xx keyboard"); 1004 } else { 1005 if (!(strncmp(hidstr, "PNP0F", 5))) { 1006 /* a mouse device include PNP0Fxx */ 1007 dip = get_bus_dip(mouse_alias, dip); 1008 ndi_devi_alloc_sleep(dip, mouse_alias, 1009 (pnode_t)DEVI_SID_NODEID, &xdip); 1010 (void) ndi_prop_update_string(DDI_DEV_T_NONE, 1011 xdip, "compatible", "pnpPNP,f03"); 1012 (void) ndi_prop_update_string(DDI_DEV_T_NONE, 1013 xdip, "model", "PNP0Fxx mouse"); 1014 } else { 1015 (void) parse_resources(ObjHandle, xdip, path); 1016 goto done; 1017 } 1018 } 1019 } 1020 1021 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, "acpi-namespace", 1022 path); 1023 1024 (void) parse_resources(ObjHandle, xdip, path); 1025 1026 /* Special processing for mouse and keyboard devices per IEEE 1275 */ 1027 /* if master entry doesn't contain "compatible" then we add default */ 1028 if (strcmp(m->name, keyboard_alias) == 0) { 1029 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 0); 1030 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1031 "device-type", keyboard_alias); 1032 if (!compatible_present) 1033 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1034 "compatible", "pnpPNP,303"); 1035 } else if (strcmp(m->name, mouse_alias) == 0) { 1036 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 1); 1037 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1038 "device-type", mouse_alias); 1039 if (!compatible_present) 1040 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1041 "compatible", "pnpPNP,f03"); 1042 } 1043 1044 /* 1045 * Create default "compatible" property if required 1046 */ 1047 if (!ddi_prop_exists(DDI_DEV_T_ANY, xdip, 1048 DDI_PROP_DONTPASS, "compatible")) 1049 create_compatible_property(xdip, device_ids); 1050 1051 (void) ndi_devi_bind_driver(xdip, 0); 1052 1053 done: 1054 /* discard _HID/_CID list */ 1055 d = device_ids; 1056 while (d != NULL) { 1057 device_id_t *next; 1058 1059 next = d->next; 1060 mf_free_device_id(d); 1061 d = next; 1062 } 1063 1064 if (path != NULL) 1065 AcpiOsFree(path); 1066 if (info != NULL) 1067 AcpiOsFree(info); 1068 1069 return (AE_OK); 1070 } 1071 1072 static int 1073 irq_cmp(const void *a, const void *b) 1074 { 1075 const int *l = a; 1076 const int *r = b; 1077 1078 if (*l < *r) 1079 return (-1); 1080 if (*l > *r) 1081 return (1); 1082 return (0); 1083 } 1084 1085 static void 1086 used_res_interrupts(void) 1087 { 1088 if (used_interrupts.i_num == 0) 1089 return; 1090 1091 /* 1092 * add_known_used_resources() in usr/src/uts/i86pc.io/isa.c (used 1093 * when ACPI enumeration is disabled) states that the interrupt values 1094 * in the interrupts property of usedrdip should be in increasing order. 1095 * It does not state the reason for the requirement, however out of 1096 * an abundance of caution, we ensure the interrupt values are also 1097 * stored in the interrupts property in increasing order. 1098 */ 1099 qsort(used_interrupts.i_intrs, used_interrupts.i_num, sizeof (int), 1100 irq_cmp); 1101 1102 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1103 "interrupts", used_interrupts.i_intrs, used_interrupts.i_num); 1104 1105 kmem_free(used_interrupts.i_intrs, 1106 used_interrupts.i_alloc * sizeof (int)); 1107 bzero(&used_interrupts, sizeof (used_interrupts)); 1108 } 1109 1110 static void 1111 used_res_dmas(void) 1112 { 1113 int dma[ACPI_ISA_LIMIT]; 1114 int count = 0; 1115 int i; 1116 1117 for (i = 0; i < ACPI_ISA_LIMIT; i++) { 1118 if ((used_dmas >> i) & 1) { 1119 dma[count++] = i; 1120 } 1121 } 1122 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1123 "dma-channels", (int *)dma, count); 1124 } 1125 1126 static void 1127 used_res_io_mem(char *nodename, int *count, used_io_mem_t **head) 1128 { 1129 int *io; 1130 used_io_mem_t *used = *head; 1131 int i; 1132 1133 *count *= 2; 1134 io = (int *)kmem_zalloc(sizeof (int)*(*count), KM_SLEEP); 1135 for (i = 0; i < *count; i += 2) { 1136 used_io_mem_t *prev; 1137 if (used != NULL) { 1138 io[i] = used->start_addr; 1139 io[i+1] = used->length; 1140 prev = used; 1141 used = used->next; 1142 kmem_free(prev, sizeof (used_io_mem_t)); 1143 } 1144 } 1145 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1146 nodename, (int *)io, *count); 1147 kmem_free(io, sizeof (int)*(*count)); 1148 *head = NULL; 1149 } 1150 1151 /* 1152 * acpi_isa_device_enum() -- call from isa nexus driver 1153 * returns 1 if deviced enumeration is successful 1154 * 0 if deviced enumeration fails 1155 */ 1156 int 1157 acpi_isa_device_enum(dev_info_t *isa_dip) 1158 { 1159 char *acpi_prop; 1160 1161 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1162 DDI_PROP_DONTPASS, ACPI_ENUM_DEBUG, &acpi_prop) == 1163 DDI_PROP_SUCCESS) { 1164 long data; 1165 if (ddi_strtol(acpi_prop, NULL, 0, &data) == 0) { 1166 acpi_enum_debug = (unsigned long)data; 1167 e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 1168 ACPI_ENUM_DEBUG); 1169 e_ddi_prop_update_int(DDI_DEV_T_NONE, 1170 ddi_root_node(), ACPI_ENUM_DEBUG, data); 1171 } 1172 ddi_prop_free(acpi_prop); 1173 } 1174 1175 if (acpi_enum_debug & ISA_DEVICE_ENUM) { 1176 cmn_err(CE_NOTE, "!acpi_isa_device_enum() called"); 1177 } 1178 1179 if (acpica_init() != AE_OK) { 1180 cmn_err(CE_WARN, "!isa_enum: init failed"); 1181 /* Note, pickup by i8042 nexus */ 1182 (void) e_ddi_prop_update_string(DDI_DEV_T_NONE, 1183 ddi_root_node(), "acpi-enum", "off"); 1184 return (0); 1185 } 1186 1187 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0); 1188 if (usedrdip == NULL) { 1189 ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES, 1190 (pnode_t)DEVI_SID_NODEID, &usedrdip); 1191 1192 } 1193 1194 process_master_file(); 1195 1196 /* 1197 * Do the actual enumeration. Avoid AcpiGetDevices because it 1198 * has an unnecessary internal callback that duplicates 1199 * determining if the device is present. 1200 */ 1201 (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 1202 UINT32_MAX, isa_acpi_callback, NULL, isa_dip, NULL); 1203 1204 free_master_data(); 1205 used_res_interrupts(); 1206 used_res_dmas(); 1207 used_res_io_mem("device-memory", &used_mem_count, &used_mem_head); 1208 used_res_io_mem("io-space", &used_io_count, &used_io_head); 1209 (void) ndi_devi_bind_driver(usedrdip, 0); 1210 1211 return (1); 1212 } 1213