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