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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * ISA bus nexus driver 30 */ 31 32 #include <sys/types.h> 33 #include <sys/cmn_err.h> 34 #include <sys/conf.h> 35 #include <sys/modctl.h> 36 #include <sys/autoconf.h> 37 #include <sys/errno.h> 38 #include <sys/debug.h> 39 #include <sys/kmem.h> 40 #include <sys/psm.h> 41 #include <sys/ddidmareq.h> 42 #include <sys/ddi_impldefs.h> 43 #include <sys/dma_engine.h> 44 #include <sys/ddi.h> 45 #include <sys/sunddi.h> 46 #include <sys/sunndi.h> 47 #include <sys/acpi/acpi_enum.h> 48 #if defined(__xpv) 49 #include <sys/hypervisor.h> 50 #include <sys/evtchn_impl.h> 51 #endif 52 53 54 extern int isa_resource_setup(void); 55 static char USED_RESOURCES[] = "used-resources"; 56 static void isa_alloc_nodes(dev_info_t *); 57 static void enumerate_BIOS_serial(dev_info_t *); 58 59 #define BIOS_DATA_AREA 0x400 60 /* 61 * #define ISA_DEBUG 1 62 */ 63 64 /* 65 * Local data 66 */ 67 static ddi_dma_lim_t ISA_dma_limits = { 68 0, /* address low */ 69 0x00ffffff, /* address high */ 70 0, /* counter max */ 71 1, /* burstsize */ 72 DMA_UNIT_8, /* minimum xfer */ 73 0, /* dma speed */ 74 (uint_t)DMALIM_VER0, /* version */ 75 0x0000ffff, /* address register */ 76 0x0000ffff, /* counter register */ 77 1, /* sector size */ 78 0x00000001, /* scatter/gather list length */ 79 (uint_t)0xffffffff /* request size */ 80 }; 81 82 static ddi_dma_attr_t ISA_dma_attr = { 83 DMA_ATTR_V0, 84 (unsigned long long)0, 85 (unsigned long long)0x00ffffff, 86 0x0000ffff, 87 1, 88 1, 89 1, 90 (unsigned long long)0xffffffff, 91 (unsigned long long)0x0000ffff, 92 1, 93 1, 94 0 95 }; 96 97 98 /* 99 * Config information 100 */ 101 102 static int 103 isa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *, 104 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *); 105 106 static int 107 isa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops, 108 off_t *, size_t *, caddr_t *, uint_t); 109 110 static int 111 isa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 112 113 struct bus_ops isa_bus_ops = { 114 BUSO_REV, 115 i_ddi_bus_map, 116 NULL, 117 NULL, 118 NULL, 119 i_ddi_map_fault, 120 ddi_dma_map, 121 isa_dma_allochdl, 122 ddi_dma_freehdl, 123 ddi_dma_bindhdl, 124 ddi_dma_unbindhdl, 125 ddi_dma_flush, 126 ddi_dma_win, 127 isa_dma_mctl, 128 isa_ctlops, 129 ddi_bus_prop_op, 130 NULL, /* (*bus_get_eventcookie)(); */ 131 NULL, /* (*bus_add_eventcall)(); */ 132 NULL, /* (*bus_remove_eventcall)(); */ 133 NULL, /* (*bus_post_event)(); */ 134 NULL, /* (*bus_intr_ctl)(); */ 135 NULL, /* (*bus_config)(); */ 136 NULL, /* (*bus_unconfig)(); */ 137 NULL, /* (*bus_fm_init)(); */ 138 NULL, /* (*bus_fm_fini)(); */ 139 NULL, /* (*bus_fm_access_enter)(); */ 140 NULL, /* (*bus_fm_access_exit)(); */ 141 NULL, /* (*bus_power)(); */ 142 i_ddi_intr_ops /* (*bus_intr_op)(); */ 143 }; 144 145 146 static int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 147 148 /* 149 * Internal isa ctlops support routines 150 */ 151 static int isa_initchild(dev_info_t *child); 152 153 struct dev_ops isa_ops = { 154 DEVO_REV, /* devo_rev, */ 155 0, /* refcnt */ 156 ddi_no_info, /* info */ 157 nulldev, /* identify */ 158 nulldev, /* probe */ 159 isa_attach, /* attach */ 160 nodev, /* detach */ 161 nodev, /* reset */ 162 (struct cb_ops *)0, /* driver operations */ 163 &isa_bus_ops /* bus operations */ 164 165 }; 166 167 /* 168 * Module linkage information for the kernel. 169 */ 170 171 static struct modldrv modldrv = { 172 &mod_driverops, /* Type of module. This is ISA bus driver */ 173 "isa nexus driver for 'ISA' %I%", 174 &isa_ops, /* driver ops */ 175 }; 176 177 static struct modlinkage modlinkage = { 178 MODREV_1, 179 &modldrv, 180 NULL 181 }; 182 183 int 184 _init(void) 185 { 186 return (mod_install(&modlinkage)); 187 } 188 189 int 190 _fini(void) 191 { 192 return (mod_remove(&modlinkage)); 193 } 194 195 int 196 _info(struct modinfo *modinfop) 197 { 198 return (mod_info(&modlinkage, modinfop)); 199 } 200 201 static int 202 isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 203 { 204 int rval; 205 206 #if defined(__xpv) 207 /* 208 * don't allow isa to attach in domU. this can happen if someone sets 209 * the console wrong, etc. ISA devices assume the H/W is there and 210 * will cause the domU to panic. 211 */ 212 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 213 return (DDI_FAILURE); 214 } 215 #endif 216 217 if (cmd != DDI_ATTACH) 218 return (DDI_FAILURE); 219 220 if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) { 221 ddi_report_dev(devi); 222 /* 223 * Enumerate children -- invoking ACPICA 224 * This is normally in bus_config(), but we need this 225 * to happen earlier to boot. 226 */ 227 isa_alloc_nodes(devi); 228 } 229 return (rval); 230 } 231 232 static int 233 isa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr, 234 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 235 { 236 ddi_dma_attr_merge(dma_attr, &ISA_dma_attr); 237 return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep)); 238 } 239 240 static int 241 isa_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 242 ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 243 off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 244 { 245 int rval; 246 ddi_dma_lim_t defalt; 247 int arg = (int)(uintptr_t)objp; 248 249 switch (request) { 250 251 case DDI_DMA_E_PROG: 252 return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp, 253 (ddi_dma_cookie_t *)lenp, arg)); 254 255 case DDI_DMA_E_ACQUIRE: 256 return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp, 257 (caddr_t)lenp)); 258 259 case DDI_DMA_E_FREE: 260 return (i_dmae_free(rdip, arg)); 261 262 case DDI_DMA_E_STOP: 263 i_dmae_stop(rdip, arg); 264 return (DDI_SUCCESS); 265 266 case DDI_DMA_E_ENABLE: 267 i_dmae_enable(rdip, arg); 268 return (DDI_SUCCESS); 269 270 case DDI_DMA_E_DISABLE: 271 i_dmae_disable(rdip, arg); 272 return (DDI_SUCCESS); 273 274 case DDI_DMA_E_GETCNT: 275 i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp); 276 return (DDI_SUCCESS); 277 278 case DDI_DMA_E_SWSETUP: 279 return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp, 280 (ddi_dma_cookie_t *)lenp, arg)); 281 282 case DDI_DMA_E_SWSTART: 283 i_dmae_swstart(rdip, arg); 284 return (DDI_SUCCESS); 285 286 case DDI_DMA_E_GETLIM: 287 bcopy(&ISA_dma_limits, objp, sizeof (ddi_dma_lim_t)); 288 return (DDI_SUCCESS); 289 290 case DDI_DMA_E_GETATTR: 291 bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t)); 292 return (DDI_SUCCESS); 293 294 case DDI_DMA_E_1STPTY: 295 { 296 struct ddi_dmae_req req1stpty = 297 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 298 if (arg == 0) { 299 req1stpty.der_command = DMAE_CMD_TRAN; 300 req1stpty.der_trans = DMAE_TRANS_DMND; 301 } else { 302 req1stpty.der_trans = DMAE_TRANS_CSCD; 303 } 304 return (i_dmae_prog(rdip, &req1stpty, NULL, arg)); 305 } 306 307 case DDI_DMA_IOPB_ALLOC: /* get contiguous DMA-able memory */ 308 case DDI_DMA_SMEM_ALLOC: 309 if (!offp) { 310 defalt = ISA_dma_limits; 311 offp = (off_t *)&defalt; 312 } 313 /*FALLTHROUGH*/ 314 default: 315 rval = ddi_dma_mctl(dip, rdip, handle, request, offp, 316 lenp, objp, flags); 317 } 318 return (rval); 319 } 320 321 /* 322 * Check if driver should be treated as an old pre 2.6 driver 323 */ 324 static int 325 old_driver(dev_info_t *dip) 326 { 327 extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */ 328 329 if (ndi_dev_is_persistent_node(dip)) { 330 if (ignore_hardware_nodes) 331 return (1); 332 if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 333 "ignore-hardware-nodes", -1) != -1) 334 return (1); 335 } 336 return (0); 337 } 338 339 typedef struct { 340 uint32_t phys_hi; 341 uint32_t phys_lo; 342 uint32_t size; 343 } isa_regs_t; 344 345 /* 346 * Return non-zero if device in tree is a PnP isa device 347 */ 348 static int 349 is_pnpisa(dev_info_t *dip) 350 { 351 isa_regs_t *isa_regs; 352 int proplen, pnpisa; 353 354 if (ndi_dev_is_persistent_node(dip) == 0) 355 return (0); 356 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 357 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 358 return (0); 359 } 360 pnpisa = isa_regs[0].phys_hi & 0x80000000; 361 /* 362 * free the memory allocated by ddi_getlongprop(). 363 */ 364 kmem_free(isa_regs, proplen); 365 if (pnpisa) 366 return (1); 367 else 368 return (0); 369 } 370 371 /*ARGSUSED*/ 372 static int 373 isa_ctlops(dev_info_t *dip, dev_info_t *rdip, 374 ddi_ctl_enum_t ctlop, void *arg, void *result) 375 { 376 switch (ctlop) { 377 case DDI_CTLOPS_REPORTDEV: 378 if (rdip == (dev_info_t *)0) 379 return (DDI_FAILURE); 380 cmn_err(CE_CONT, "?ISA-device: %s%d\n", 381 ddi_driver_name(rdip), ddi_get_instance(rdip)); 382 return (DDI_SUCCESS); 383 384 case DDI_CTLOPS_INITCHILD: 385 /* 386 * older drivers aren't expecting the "standard" device 387 * node format used by the hardware nodes. these drivers 388 * only expect their own properties set in their driver.conf 389 * files. so they tell us not to call them with hardware 390 * nodes by setting the property "ignore-hardware-nodes". 391 */ 392 if (old_driver((dev_info_t *)arg)) { 393 return (DDI_NOT_WELL_FORMED); 394 } 395 396 return (isa_initchild((dev_info_t *)arg)); 397 398 case DDI_CTLOPS_UNINITCHILD: 399 impl_ddi_sunbus_removechild((dev_info_t *)arg); 400 return (DDI_SUCCESS); 401 402 case DDI_CTLOPS_SIDDEV: 403 /* 404 * All ISA devices need to do confirming probes 405 * unless they are PnP ISA. 406 */ 407 if (is_pnpisa(dip)) 408 return (DDI_SUCCESS); 409 else 410 return (DDI_FAILURE); 411 412 default: 413 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 414 } 415 } 416 417 static void 418 isa_vendor(uint32_t id, char *vendor) 419 { 420 vendor[0] = '@' + ((id >> 26) & 0x1f); 421 vendor[1] = '@' + ((id >> 21) & 0x1f); 422 vendor[2] = '@' + ((id >> 16) & 0x1f); 423 vendor[3] = 0; 424 } 425 426 /* 427 * Name a child 428 */ 429 static int 430 isa_name_child(dev_info_t *child, char *name, int namelen) 431 { 432 char vendor[8]; 433 int device; 434 uint32_t serial; 435 int func; 436 int bustype; 437 uint32_t base; 438 int proplen; 439 int pnpisa = 0; 440 isa_regs_t *isa_regs; 441 442 void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **); 443 444 /* 445 * older drivers aren't expecting the "standard" device 446 * node format used by the hardware nodes. these drivers 447 * only expect their own properties set in their driver.conf 448 * files. so they tell us not to call them with hardware 449 * nodes by setting the property "ignore-hardware-nodes". 450 */ 451 if (old_driver(child)) 452 return (DDI_FAILURE); 453 454 /* 455 * Fill in parent-private data 456 */ 457 if (ddi_get_parent_data(child) == NULL) { 458 struct ddi_parent_private_data *pdptr; 459 make_ddi_ppd(child, &pdptr); 460 ddi_set_parent_data(child, pdptr); 461 } 462 463 if (ndi_dev_is_persistent_node(child) == 0) { 464 /* 465 * For .conf nodes, generate name from parent private data 466 */ 467 name[0] = '\0'; 468 if (sparc_pd_getnreg(child) > 0) { 469 (void) snprintf(name, namelen, "%x,%x", 470 (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype, 471 (uint_t)sparc_pd_getreg(child, 0)->regspec_addr); 472 } 473 return (DDI_SUCCESS); 474 } 475 476 /* 477 * For hw nodes, look up "reg" property 478 */ 479 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 480 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 481 return (DDI_FAILURE); 482 } 483 484 /* 485 * extract the device identifications 486 */ 487 pnpisa = isa_regs[0].phys_hi & 0x80000000; 488 if (pnpisa) { 489 isa_vendor(isa_regs[0].phys_hi, vendor); 490 device = isa_regs[0].phys_hi & 0xffff; 491 serial = isa_regs[0].phys_lo; 492 func = (isa_regs[0].size >> 24) & 0xff; 493 if (func != 0) 494 (void) snprintf(name, namelen, "pnp%s,%04x,%x,%x", 495 vendor, device, serial, func); 496 else 497 (void) snprintf(name, namelen, "pnp%s,%04x,%x", 498 vendor, device, serial); 499 } else { 500 bustype = isa_regs[0].phys_hi; 501 base = isa_regs[0].phys_lo; 502 (void) sprintf(name, "%x,%x", bustype, base); 503 } 504 505 /* 506 * free the memory allocated by ddi_getlongprop(). 507 */ 508 kmem_free(isa_regs, proplen); 509 510 return (DDI_SUCCESS); 511 } 512 513 static int 514 isa_initchild(dev_info_t *child) 515 { 516 char name[80]; 517 518 if (isa_name_child(child, name, 80) != DDI_SUCCESS) 519 return (DDI_FAILURE); 520 ddi_set_name_addr(child, name); 521 522 if (ndi_dev_is_persistent_node(child) != 0) 523 return (DDI_SUCCESS); 524 525 /* 526 * This is a .conf node, try merge properties onto a 527 * hw node with the same name. 528 */ 529 if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) { 530 /* 531 * Return failure to remove node 532 */ 533 impl_ddi_sunbus_removechild(child); 534 return (DDI_FAILURE); 535 } 536 /* 537 * Cannot merge node, permit pseudo children 538 */ 539 return (DDI_SUCCESS); 540 } 541 542 /* 543 * called when ACPI enumeration is not used 544 */ 545 static void 546 add_known_used_resources(void) 547 { 548 /* needs to be in increasing order */ 549 int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc}; 550 int dma[] = {0x2}; 551 int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10, 552 0x778, 0x4}; 553 dev_info_t *usedrdip; 554 555 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0); 556 557 if (usedrdip == NULL) { 558 (void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES, 559 (pnode_t)DEVI_SID_NODEID, &usedrdip); 560 } 561 562 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 563 "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int))); 564 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 565 "io-space", (int *)io, (int)(sizeof (io) / sizeof (int))); 566 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 567 "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int))); 568 (void) ndi_devi_bind_driver(usedrdip, 0); 569 570 } 571 572 static void 573 isa_alloc_nodes(dev_info_t *isa_dip) 574 { 575 static int alloced = 0; 576 int circ, i; 577 dev_info_t *xdip; 578 579 /* hard coded isa stuff */ 580 struct regspec asy_regs[] = { 581 {1, 0x3f8, 0x8}, 582 {1, 0x2f8, 0x8} 583 }; 584 int asy_intrs[] = {0x4, 0x3}; 585 586 struct regspec i8042_regs[] = { 587 {1, 0x60, 0x1}, 588 {1, 0x64, 0x1} 589 }; 590 int i8042_intrs[] = {0x1, 0xc}; 591 char *acpi_prop; 592 int acpi_enum = 1; /* ACPI is default to be on */ 593 594 if (alloced) 595 return; 596 597 ndi_devi_enter(isa_dip, &circ); 598 if (alloced) { /* just in case we are multi-threaded */ 599 ndi_devi_exit(isa_dip, circ); 600 return; 601 } 602 alloced = 1; 603 604 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 605 DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { 606 acpi_enum = strcmp("off", acpi_prop); 607 ddi_prop_free(acpi_prop); 608 } 609 610 if (acpi_enum) { 611 if (acpi_isa_device_enum(isa_dip)) { 612 ndi_devi_exit(isa_dip, circ); 613 if (isa_resource_setup() != NDI_SUCCESS) { 614 cmn_err(CE_WARN, "isa nexus: isa " 615 "resource setup failed"); 616 } 617 618 /* serial ports? */ 619 enumerate_BIOS_serial(isa_dip); 620 return; 621 } 622 cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS"); 623 } 624 cmn_err(CE_NOTE, "!ACPI is off"); 625 626 /* serial ports */ 627 for (i = 0; i < 2; i++) { 628 #if defined(__xpv) 629 /* 630 * the hypervisor may be reserving the serial ports for console 631 * and/or debug use. Probe the irqs to see if they are 632 * available. 633 */ 634 if (ec_probe_pirq(asy_intrs[i]) == 0) 635 continue; /* in use */ 636 #endif 637 ndi_devi_alloc_sleep(isa_dip, "asy", 638 (pnode_t)DEVI_SID_NODEID, &xdip); 639 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 640 "reg", (int *)&asy_regs[i], 3); 641 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 642 "interrupts", asy_intrs[i]); 643 (void) ndi_devi_bind_driver(xdip, 0); 644 } 645 646 /* i8042 node */ 647 ndi_devi_alloc_sleep(isa_dip, "i8042", 648 (pnode_t)DEVI_SID_NODEID, &xdip); 649 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 650 "reg", (int *)i8042_regs, 6); 651 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 652 "interrupts", (int *)i8042_intrs, 2); 653 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 654 "unit-address", "1,60"); 655 (void) ndi_devi_bind_driver(xdip, 0); 656 657 add_known_used_resources(); 658 659 ndi_devi_exit(isa_dip, circ); 660 661 } 662 663 /* 664 * On some machines, serial port 2 isn't listed in the ACPI table. 665 * This function goes through the BIOS data area and makes sure all 666 * the serial ports there are in the dev_info tree. If any are missing, 667 * this function will add them. 668 */ 669 670 static int num_BIOS_serial = 2; /* number of BIOS serial ports to look at */ 671 672 static void 673 enumerate_BIOS_serial(dev_info_t *isa_dip) 674 { 675 ushort_t *bios_data; 676 int i; 677 dev_info_t *xdip; 678 int found; 679 int ret; 680 struct regspec *tmpregs; 681 int tmpregs_len; 682 static struct regspec tmp_asy_regs[] = { 683 {1, 0x3f8, 0x8}, 684 }; 685 static int default_asy_intrs[] = { 4, 3, 4, 3 }; 686 static size_t size = 4; 687 688 /* 689 * The first four 2-byte quantities of the BIOS data area contain 690 * the base I/O addresses of the first four serial ports. 691 */ 692 bios_data = (ushort_t *)psm_map_new((paddr_t)BIOS_DATA_AREA, size, 693 PSM_PROT_READ); 694 for (i = 0; i < num_BIOS_serial; i++) { 695 if (bios_data[i] == 0) { 696 /* no COM[i]: port */ 697 continue; 698 } 699 700 /* Look for it in the dev_info tree */ 701 found = 0; 702 for (xdip = ddi_get_child(isa_dip); xdip != NULL; 703 xdip = ddi_get_next_sibling(xdip)) { 704 if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) { 705 /* skip non asy */ 706 continue; 707 } 708 709 /* Match by addr */ 710 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip, 711 DDI_PROP_DONTPASS, "reg", (int **)&tmpregs, 712 (uint_t *)&tmpregs_len); 713 if (ret != DDI_PROP_SUCCESS) { 714 /* error */ 715 continue; 716 } 717 718 if (tmpregs->regspec_addr == bios_data[i]) 719 found = 1; 720 /* 721 * Free the memory allocated by 722 * ddi_prop_lookup_int_array(). 723 */ 724 ddi_prop_free(tmpregs); 725 726 } 727 728 /* If not found, then add it */ 729 if (!found) { 730 ndi_devi_alloc_sleep(isa_dip, "asy", 731 (pnode_t)DEVI_SID_NODEID, &xdip); 732 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 733 "compatible", "PNP0500"); 734 /* This should be gotten from master file: */ 735 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 736 "model", "Standard PC COM port"); 737 tmp_asy_regs[0].regspec_addr = bios_data[i]; 738 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 739 "reg", (int *)&tmp_asy_regs[0], 3); 740 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 741 "interrupts", default_asy_intrs[i]); 742 (void) ndi_devi_bind_driver(xdip, 0); 743 } 744 } 745 #if defined(__xpv) 746 /* 747 * Check each serial port to see if it is in use by the hypervisor. 748 * If it is in use, then remove the node from the device tree. 749 */ 750 i = 0; 751 for (xdip = ddi_get_child(isa_dip); xdip != NULL; ) { 752 int asy_intr; 753 dev_info_t *curdip; 754 755 curdip = xdip; 756 xdip = ddi_get_next_sibling(xdip); 757 if (strncmp(ddi_node_name(curdip), "asy", 3) != 0) { 758 /* skip non asy */ 759 continue; 760 } 761 /* 762 * Check if the hypervisor is using the serial port by probing 763 * the irq and if it is using it remove the node 764 * from the device tree 765 */ 766 asy_intr = ddi_prop_get_int(DDI_DEV_T_ANY, curdip, 767 DDI_PROP_DONTPASS, "interrupts", -1); 768 if (asy_intr == -1) { 769 /* error */ 770 continue; 771 } 772 773 if (ec_probe_pirq(asy_intr)) { 774 continue; 775 } 776 ret = ndi_devi_free(curdip); 777 if (ret != DDI_SUCCESS) 778 cmn_err(CE_WARN, 779 "could not remove asy%d node", i); 780 else 781 cmn_err(CE_NOTE, "!asy%d unavailable, reserved" 782 " to hypervisor", i); 783 i++; 784 } 785 #endif /* __xpv */ 786 787 psm_unmap((caddr_t)bios_data, size); 788 } 789