1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 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 #include <sys/mach_intr.h> 47 #include <sys/pci.h> 48 #include <sys/note.h> 49 #if defined(__xpv) 50 #include <sys/hypervisor.h> 51 #include <sys/evtchn_impl.h> 52 #endif 53 54 extern int pseudo_isa; 55 extern int isa_resource_setup(void); 56 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 57 psm_intr_op_t, int *); 58 extern void pci_remove_isa_resources(int, uint32_t, uint32_t); 59 static char USED_RESOURCES[] = "used-resources"; 60 static void isa_alloc_nodes(dev_info_t *); 61 static void enumerate_BIOS_serial(dev_info_t *); 62 static void isa_postattach(dev_info_t *); 63 64 /* 65 * The following typedef is used to represent an entry in the "ranges" 66 * property of a pci-isa bridge device node. 67 */ 68 typedef struct { 69 uint32_t child_high; 70 uint32_t child_low; 71 uint32_t parent_high; 72 uint32_t parent_mid; 73 uint32_t parent_low; 74 uint32_t size; 75 } pib_ranges_t; 76 77 typedef struct { 78 uint32_t base; 79 uint32_t len; 80 } used_ranges_t; 81 82 #define USED_CELL_SIZE 2 /* 1 byte addr, 1 byte size */ 83 #define ISA_ADDR_IO 1 /* IO address space */ 84 #define ISA_ADDR_MEM 0 /* memory adress space */ 85 #define BIOS_DATA_AREA 0x400 86 /* 87 * #define ISA_DEBUG 1 88 */ 89 90 /* 91 * Local data 92 */ 93 static ddi_dma_lim_t ISA_dma_limits = { 94 0, /* address low */ 95 0x00ffffff, /* address high */ 96 0, /* counter max */ 97 1, /* burstsize */ 98 DMA_UNIT_8, /* minimum xfer */ 99 0, /* dma speed */ 100 (uint_t)DMALIM_VER0, /* version */ 101 0x0000ffff, /* address register */ 102 0x0000ffff, /* counter register */ 103 1, /* sector size */ 104 0x00000001, /* scatter/gather list length */ 105 (uint_t)0xffffffff /* request size */ 106 }; 107 108 static ddi_dma_attr_t ISA_dma_attr = { 109 DMA_ATTR_V0, 110 (unsigned long long)0, 111 (unsigned long long)0x00ffffff, 112 0x0000ffff, 113 1, 114 1, 115 1, 116 (unsigned long long)0xffffffff, 117 (unsigned long long)0x0000ffff, 118 1, 119 1, 120 0 121 }; 122 123 124 /* 125 * Config information 126 */ 127 128 static int 129 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 130 off_t offset, off_t len, caddr_t *vaddrp); 131 132 static int 133 isa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *, 134 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *); 135 136 static int 137 isa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops, 138 off_t *, size_t *, caddr_t *, uint_t); 139 140 static int 141 isa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 142 143 static int 144 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 145 ddi_intr_handle_impl_t *hdlp, void *result); 146 147 struct bus_ops isa_bus_ops = { 148 BUSO_REV, 149 isa_bus_map, 150 NULL, 151 NULL, 152 NULL, 153 i_ddi_map_fault, 154 ddi_dma_map, 155 isa_dma_allochdl, 156 ddi_dma_freehdl, 157 ddi_dma_bindhdl, 158 ddi_dma_unbindhdl, 159 ddi_dma_flush, 160 ddi_dma_win, 161 isa_dma_mctl, 162 isa_ctlops, 163 ddi_bus_prop_op, 164 NULL, /* (*bus_get_eventcookie)(); */ 165 NULL, /* (*bus_add_eventcall)(); */ 166 NULL, /* (*bus_remove_eventcall)(); */ 167 NULL, /* (*bus_post_event)(); */ 168 NULL, /* (*bus_intr_ctl)(); */ 169 NULL, /* (*bus_config)(); */ 170 NULL, /* (*bus_unconfig)(); */ 171 NULL, /* (*bus_fm_init)(); */ 172 NULL, /* (*bus_fm_fini)(); */ 173 NULL, /* (*bus_fm_access_enter)(); */ 174 NULL, /* (*bus_fm_access_exit)(); */ 175 NULL, /* (*bus_power)(); */ 176 isa_intr_ops /* (*bus_intr_op)(); */ 177 }; 178 179 180 static int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 181 182 /* 183 * Internal isa ctlops support routines 184 */ 185 static int isa_initchild(dev_info_t *child); 186 187 struct dev_ops isa_ops = { 188 DEVO_REV, /* devo_rev, */ 189 0, /* refcnt */ 190 ddi_no_info, /* info */ 191 nulldev, /* identify */ 192 nulldev, /* probe */ 193 isa_attach, /* attach */ 194 nulldev, /* detach */ 195 nodev, /* reset */ 196 (struct cb_ops *)0, /* driver operations */ 197 &isa_bus_ops, /* bus operations */ 198 NULL, /* power */ 199 ddi_quiesce_not_needed, /* quiesce */ 200 }; 201 202 /* 203 * Module linkage information for the kernel. 204 */ 205 206 static struct modldrv modldrv = { 207 &mod_driverops, /* Type of module. This is ISA bus driver */ 208 "isa nexus driver for 'ISA'", 209 &isa_ops, /* driver ops */ 210 }; 211 212 static struct modlinkage modlinkage = { 213 MODREV_1, 214 &modldrv, 215 NULL 216 }; 217 218 int 219 _init(void) 220 { 221 return (mod_install(&modlinkage)); 222 } 223 224 int 225 _fini(void) 226 { 227 return (mod_remove(&modlinkage)); 228 } 229 230 int 231 _info(struct modinfo *modinfop) 232 { 233 return (mod_info(&modlinkage, modinfop)); 234 } 235 236 static int 237 isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 238 { 239 int rval; 240 241 #if defined(__xpv) 242 /* 243 * don't allow isa to attach in domU. this can happen if someone sets 244 * the console wrong, etc. ISA devices assume the H/W is there and 245 * will cause the domU to panic. 246 */ 247 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 248 return (DDI_FAILURE); 249 } 250 #endif 251 252 switch (cmd) { 253 case DDI_ATTACH: 254 break; 255 case DDI_RESUME: 256 return (DDI_SUCCESS); 257 default: 258 return (DDI_FAILURE); 259 } 260 261 if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) { 262 ddi_report_dev(devi); 263 /* 264 * Enumerate children -- invoking ACPICA 265 * This is normally in bus_config(), but we need this 266 * to happen earlier to boot. 267 */ 268 isa_alloc_nodes(devi); 269 } 270 271 if (!pseudo_isa) 272 isa_postattach(devi); 273 274 return (rval); 275 } 276 277 #define SET_RNGS(rng_p, used_p, ctyp, ptyp) do { \ 278 (rng_p)->child_high = (ctyp); \ 279 (rng_p)->child_low = (rng_p)->parent_low = (used_p)->base; \ 280 (rng_p)->parent_high = (ptyp); \ 281 (rng_p)->parent_mid = 0; \ 282 (rng_p)->size = (used_p)->len; \ 283 _NOTE(CONSTCOND) } while (0) 284 static uint_t 285 isa_used_to_ranges(int ctype, int *array, uint_t size, pib_ranges_t *ranges) 286 { 287 used_ranges_t *used_p; 288 pib_ranges_t *rng_p = ranges; 289 uint_t i, ptype; 290 291 ptype = (ctype == ISA_ADDR_IO) ? PCI_ADDR_IO : PCI_ADDR_MEM32; 292 ptype |= PCI_REG_REL_M; 293 size /= USED_CELL_SIZE; 294 used_p = (used_ranges_t *)array; 295 SET_RNGS(rng_p, used_p, ctype, ptype); 296 for (i = 1, used_p++; i < size; i++, used_p++) { 297 /* merge ranges record if applicable */ 298 if (rng_p->child_low + rng_p->size == used_p->base) 299 rng_p->size += used_p->len; 300 else { 301 rng_p++; 302 SET_RNGS(rng_p, used_p, ctype, ptype); 303 } 304 } 305 return (rng_p - ranges + 1); 306 } 307 308 void 309 isa_remove_res_from_pci(int type, int *array, uint_t size) 310 { 311 int i; 312 used_ranges_t *used_p; 313 314 size /= USED_CELL_SIZE; 315 used_p = (used_ranges_t *)array; 316 for (i = 0; i < size; i++, used_p++) 317 pci_remove_isa_resources(type, used_p->base, used_p->len); 318 } 319 320 static void 321 isa_postattach(dev_info_t *dip) 322 { 323 dev_info_t *used; 324 int *ioarray, *memarray, status; 325 uint_t nio = 0, nmem = 0, nrng = 0, n; 326 pib_ranges_t *ranges; 327 328 used = ddi_find_devinfo("used-resources", -1, 0); 329 if (used == NULL) { 330 cmn_err(CE_WARN, "Failed to find used-resources <%s>\n", 331 ddi_get_name(dip)); 332 return; 333 } 334 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used, 335 DDI_PROP_DONTPASS, "io-space", &ioarray, &nio); 336 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) { 337 cmn_err(CE_WARN, "io-space property failure for %s (%x)\n", 338 ddi_get_name(used), status); 339 return; 340 } 341 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used, 342 DDI_PROP_DONTPASS, "device-memory", &memarray, &nmem); 343 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) { 344 cmn_err(CE_WARN, "device-memory property failure for %s (%x)\n", 345 ddi_get_name(used), status); 346 return; 347 } 348 n = (nio + nmem) / USED_CELL_SIZE; 349 ranges = (pib_ranges_t *)kmem_zalloc(sizeof (pib_ranges_t) * n, 350 KM_SLEEP); 351 352 if (nio != 0) { 353 nrng = isa_used_to_ranges(ISA_ADDR_IO, ioarray, nio, ranges); 354 isa_remove_res_from_pci(ISA_ADDR_IO, ioarray, nio); 355 ddi_prop_free(ioarray); 356 } 357 if (nmem != 0) { 358 nrng += isa_used_to_ranges(ISA_ADDR_MEM, memarray, nmem, 359 ranges + nrng); 360 isa_remove_res_from_pci(ISA_ADDR_MEM, memarray, nmem); 361 ddi_prop_free(memarray); 362 } 363 364 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", 365 (int *)ranges, nrng * sizeof (pib_ranges_t) / sizeof (int)); 366 kmem_free(ranges, sizeof (pib_ranges_t) * n); 367 } 368 369 /*ARGSUSED*/ 370 static int 371 isa_apply_range(dev_info_t *dip, struct regspec *isa_reg_p, 372 pci_regspec_t *pci_reg_p) 373 { 374 pib_ranges_t *ranges, *rng_p; 375 int len, i, offset, nrange; 376 static char out_of_range[] = 377 "Out of range register specification from device node <%s>"; 378 379 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 380 "ranges", (caddr_t)&ranges, &len) != DDI_SUCCESS) { 381 cmn_err(CE_WARN, "Can't get %s ranges property", 382 ddi_get_name(dip)); 383 return (DDI_ME_REGSPEC_RANGE); 384 } 385 nrange = len / sizeof (pib_ranges_t); 386 rng_p = ranges; 387 for (i = 0; i < nrange; i++, rng_p++) { 388 /* Check for correct space */ 389 if (isa_reg_p->regspec_bustype != rng_p->child_high) 390 continue; 391 392 /* Detect whether request entirely fits within a range */ 393 if (isa_reg_p->regspec_addr < rng_p->child_low) 394 continue; 395 if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size) > 396 (rng_p->child_low + rng_p->size)) 397 continue; 398 399 offset = isa_reg_p->regspec_addr - rng_p->child_low; 400 401 pci_reg_p->pci_phys_hi = rng_p->parent_high; 402 pci_reg_p->pci_phys_mid = 0; 403 pci_reg_p->pci_phys_low = rng_p->parent_low + offset; 404 pci_reg_p->pci_size_hi = 0; 405 pci_reg_p->pci_size_low = isa_reg_p->regspec_size; 406 407 break; 408 } 409 kmem_free(ranges, len); 410 if (i == nrange) { 411 cmn_err(CE_WARN, out_of_range, ddi_get_name(dip)); 412 return (DDI_ME_REGSPEC_RANGE); 413 } 414 415 return (DDI_SUCCESS); 416 } 417 418 static int 419 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 420 off_t offset, off_t len, caddr_t *vaddrp) 421 { 422 struct regspec tmp_reg, *rp; 423 pci_regspec_t vreg; 424 ddi_map_req_t mr = *mp; /* Get private copy of request */ 425 int error; 426 427 if (pseudo_isa) 428 return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp)); 429 430 mp = &mr; 431 432 /* 433 * First, if given an rnumber, convert it to a regspec... 434 */ 435 if (mp->map_type == DDI_MT_RNUMBER) { 436 437 int rnumber = mp->map_obj.rnumber; 438 439 rp = i_ddi_rnumber_to_regspec(rdip, rnumber); 440 if (rp == (struct regspec *)0) 441 return (DDI_ME_RNUMBER_RANGE); 442 443 /* 444 * Convert the given ddi_map_req_t from rnumber to regspec... 445 */ 446 mp->map_type = DDI_MT_REGSPEC; 447 mp->map_obj.rp = rp; 448 } 449 450 /* 451 * Adjust offset and length correspnding to called values... 452 * XXX: A non-zero length means override the one in the regspec. 453 * XXX: (Regardless of what's in the parent's range) 454 */ 455 456 tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */ 457 rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */ 458 459 rp->regspec_addr += (uint_t)offset; 460 if (len != 0) 461 rp->regspec_size = (uint_t)len; 462 463 if ((error = isa_apply_range(dip, rp, &vreg)) != 0) 464 return (error); 465 mp->map_obj.rp = (struct regspec *)&vreg; 466 467 /* 468 * Call my parents bus_map function with modified values... 469 */ 470 471 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 472 } 473 474 static int 475 isa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr, 476 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 477 { 478 ddi_dma_attr_merge(dma_attr, &ISA_dma_attr); 479 return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep)); 480 } 481 482 static int 483 isa_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 484 ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 485 off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 486 { 487 int rval; 488 ddi_dma_lim_t defalt; 489 int arg = (int)(uintptr_t)objp; 490 491 switch (request) { 492 493 case DDI_DMA_E_PROG: 494 return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp, 495 (ddi_dma_cookie_t *)lenp, arg)); 496 497 case DDI_DMA_E_ACQUIRE: 498 return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp, 499 (caddr_t)lenp)); 500 501 case DDI_DMA_E_FREE: 502 return (i_dmae_free(rdip, arg)); 503 504 case DDI_DMA_E_STOP: 505 i_dmae_stop(rdip, arg); 506 return (DDI_SUCCESS); 507 508 case DDI_DMA_E_ENABLE: 509 i_dmae_enable(rdip, arg); 510 return (DDI_SUCCESS); 511 512 case DDI_DMA_E_DISABLE: 513 i_dmae_disable(rdip, arg); 514 return (DDI_SUCCESS); 515 516 case DDI_DMA_E_GETCNT: 517 i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp); 518 return (DDI_SUCCESS); 519 520 case DDI_DMA_E_SWSETUP: 521 return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp, 522 (ddi_dma_cookie_t *)lenp, arg)); 523 524 case DDI_DMA_E_SWSTART: 525 i_dmae_swstart(rdip, arg); 526 return (DDI_SUCCESS); 527 528 case DDI_DMA_E_GETLIM: 529 bcopy(&ISA_dma_limits, objp, sizeof (ddi_dma_lim_t)); 530 return (DDI_SUCCESS); 531 532 case DDI_DMA_E_GETATTR: 533 bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t)); 534 return (DDI_SUCCESS); 535 536 case DDI_DMA_E_1STPTY: 537 { 538 struct ddi_dmae_req req1stpty = 539 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 540 if (arg == 0) { 541 req1stpty.der_command = DMAE_CMD_TRAN; 542 req1stpty.der_trans = DMAE_TRANS_DMND; 543 } else { 544 req1stpty.der_trans = DMAE_TRANS_CSCD; 545 } 546 return (i_dmae_prog(rdip, &req1stpty, NULL, arg)); 547 } 548 549 case DDI_DMA_IOPB_ALLOC: /* get contiguous DMA-able memory */ 550 case DDI_DMA_SMEM_ALLOC: 551 if (!offp) { 552 defalt = ISA_dma_limits; 553 offp = (off_t *)&defalt; 554 } 555 /*FALLTHROUGH*/ 556 default: 557 rval = ddi_dma_mctl(dip, rdip, handle, request, offp, 558 lenp, objp, flags); 559 } 560 return (rval); 561 } 562 563 /* 564 * Check if driver should be treated as an old pre 2.6 driver 565 */ 566 static int 567 old_driver(dev_info_t *dip) 568 { 569 extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */ 570 571 if (ndi_dev_is_persistent_node(dip)) { 572 if (ignore_hardware_nodes) 573 return (1); 574 if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 575 "ignore-hardware-nodes", -1) != -1) 576 return (1); 577 } 578 return (0); 579 } 580 581 typedef struct { 582 uint32_t phys_hi; 583 uint32_t phys_lo; 584 uint32_t size; 585 } isa_regs_t; 586 587 /* 588 * Return non-zero if device in tree is a PnP isa device 589 */ 590 static int 591 is_pnpisa(dev_info_t *dip) 592 { 593 isa_regs_t *isa_regs; 594 int proplen, pnpisa; 595 596 if (ndi_dev_is_persistent_node(dip) == 0) 597 return (0); 598 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 599 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 600 return (0); 601 } 602 pnpisa = isa_regs[0].phys_hi & 0x80000000; 603 /* 604 * free the memory allocated by ddi_getlongprop(). 605 */ 606 kmem_free(isa_regs, proplen); 607 if (pnpisa) 608 return (1); 609 else 610 return (0); 611 } 612 613 /*ARGSUSED*/ 614 static int 615 isa_ctlops(dev_info_t *dip, dev_info_t *rdip, 616 ddi_ctl_enum_t ctlop, void *arg, void *result) 617 { 618 int rn; 619 struct ddi_parent_private_data *pdp; 620 621 switch (ctlop) { 622 case DDI_CTLOPS_REPORTDEV: 623 if (rdip == (dev_info_t *)0) 624 return (DDI_FAILURE); 625 cmn_err(CE_CONT, "?ISA-device: %s%d\n", 626 ddi_driver_name(rdip), ddi_get_instance(rdip)); 627 return (DDI_SUCCESS); 628 629 case DDI_CTLOPS_INITCHILD: 630 /* 631 * older drivers aren't expecting the "standard" device 632 * node format used by the hardware nodes. these drivers 633 * only expect their own properties set in their driver.conf 634 * files. so they tell us not to call them with hardware 635 * nodes by setting the property "ignore-hardware-nodes". 636 */ 637 if (old_driver((dev_info_t *)arg)) { 638 return (DDI_NOT_WELL_FORMED); 639 } 640 641 return (isa_initchild((dev_info_t *)arg)); 642 643 case DDI_CTLOPS_UNINITCHILD: 644 impl_ddi_sunbus_removechild((dev_info_t *)arg); 645 return (DDI_SUCCESS); 646 647 case DDI_CTLOPS_SIDDEV: 648 /* 649 * All ISA devices need to do confirming probes 650 * unless they are PnP ISA. 651 */ 652 if (is_pnpisa(dip)) 653 return (DDI_SUCCESS); 654 else 655 return (DDI_FAILURE); 656 657 case DDI_CTLOPS_REGSIZE: 658 case DDI_CTLOPS_NREGS: 659 if (rdip == (dev_info_t *)0) 660 return (DDI_FAILURE); 661 662 if ((pdp = ddi_get_parent_data(rdip)) == NULL) 663 return (DDI_FAILURE); 664 665 if (ctlop == DDI_CTLOPS_NREGS) { 666 *(int *)result = pdp->par_nreg; 667 } else { 668 rn = *(int *)arg; 669 if (rn >= pdp->par_nreg) 670 return (DDI_FAILURE); 671 *(off_t *)result = (off_t)pdp->par_reg[rn].regspec_size; 672 } 673 return (DDI_SUCCESS); 674 675 case DDI_CTLOPS_ATTACH: 676 case DDI_CTLOPS_DETACH: 677 case DDI_CTLOPS_PEEK: 678 case DDI_CTLOPS_POKE: 679 return (DDI_FAILURE); 680 681 default: 682 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 683 } 684 } 685 686 static struct intrspec * 687 isa_get_ispec(dev_info_t *rdip, int inum) 688 { 689 struct ddi_parent_private_data *pdp = ddi_get_parent_data(rdip); 690 691 /* Validate the interrupt number */ 692 if (inum >= pdp->par_nintr) 693 return (NULL); 694 695 /* Get the interrupt structure pointer and return that */ 696 return ((struct intrspec *)&pdp->par_intr[inum]); 697 } 698 699 static int 700 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 701 ddi_intr_handle_impl_t *hdlp, void *result) 702 { 703 struct intrspec *ispec; 704 705 if (pseudo_isa) 706 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 707 708 709 /* Process the interrupt operation */ 710 switch (intr_op) { 711 case DDI_INTROP_GETCAP: 712 /* First check with pcplusmp */ 713 if (psm_intr_ops == NULL) 714 return (DDI_FAILURE); 715 716 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) { 717 *(int *)result = 0; 718 return (DDI_FAILURE); 719 } 720 break; 721 case DDI_INTROP_SETCAP: 722 if (psm_intr_ops == NULL) 723 return (DDI_FAILURE); 724 725 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) 726 return (DDI_FAILURE); 727 break; 728 case DDI_INTROP_ALLOC: 729 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 730 return (DDI_FAILURE); 731 hdlp->ih_pri = ispec->intrspec_pri; 732 *(int *)result = hdlp->ih_scratch1; 733 break; 734 case DDI_INTROP_FREE: 735 break; 736 case DDI_INTROP_GETPRI: 737 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 738 return (DDI_FAILURE); 739 *(int *)result = ispec->intrspec_pri; 740 break; 741 case DDI_INTROP_SETPRI: 742 /* Validate the interrupt priority passed to us */ 743 if (*(int *)result > LOCK_LEVEL) 744 return (DDI_FAILURE); 745 746 /* Ensure that PSM is all initialized and ispec is ok */ 747 if ((psm_intr_ops == NULL) || 748 ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)) 749 return (DDI_FAILURE); 750 751 /* update the ispec with the new priority */ 752 ispec->intrspec_pri = *(int *)result; 753 break; 754 case DDI_INTROP_ADDISR: 755 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 756 return (DDI_FAILURE); 757 ispec->intrspec_func = hdlp->ih_cb_func; 758 break; 759 case DDI_INTROP_REMISR: 760 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 761 return (DDI_FAILURE); 762 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 763 return (DDI_FAILURE); 764 ispec->intrspec_func = (uint_t (*)()) 0; 765 break; 766 case DDI_INTROP_ENABLE: 767 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 768 return (DDI_FAILURE); 769 770 /* Call psmi to translate irq with the dip */ 771 if (psm_intr_ops == NULL) 772 return (DDI_FAILURE); 773 774 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 775 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, 776 (int *)&hdlp->ih_vector); 777 778 /* Add the interrupt handler */ 779 if (!add_avintr((void *)hdlp, ispec->intrspec_pri, 780 hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector, 781 hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, NULL, rdip)) 782 return (DDI_FAILURE); 783 break; 784 case DDI_INTROP_DISABLE: 785 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL) 786 return (DDI_FAILURE); 787 788 /* Call psm_ops() to translate irq with the dip */ 789 if (psm_intr_ops == NULL) 790 return (DDI_FAILURE); 791 792 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 793 (void) (*psm_intr_ops)(rdip, hdlp, 794 PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector); 795 796 /* Remove the interrupt handler */ 797 rem_avintr((void *)hdlp, ispec->intrspec_pri, 798 hdlp->ih_cb_func, hdlp->ih_vector); 799 break; 800 case DDI_INTROP_SETMASK: 801 if (psm_intr_ops == NULL) 802 return (DDI_FAILURE); 803 804 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL)) 805 return (DDI_FAILURE); 806 break; 807 case DDI_INTROP_CLRMASK: 808 if (psm_intr_ops == NULL) 809 return (DDI_FAILURE); 810 811 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL)) 812 return (DDI_FAILURE); 813 break; 814 case DDI_INTROP_GETPENDING: 815 if (psm_intr_ops == NULL) 816 return (DDI_FAILURE); 817 818 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING, 819 result)) { 820 *(int *)result = 0; 821 return (DDI_FAILURE); 822 } 823 break; 824 case DDI_INTROP_NAVAIL: 825 case DDI_INTROP_NINTRS: 826 *(int *)result = i_ddi_get_intx_nintrs(rdip); 827 if (*(int *)result == 0) { 828 return (DDI_FAILURE); 829 } 830 break; 831 case DDI_INTROP_SUPPORTED_TYPES: 832 *(int *)result = DDI_INTR_TYPE_FIXED; /* Always ... */ 833 break; 834 default: 835 return (DDI_FAILURE); 836 } 837 838 return (DDI_SUCCESS); 839 } 840 841 static void 842 isa_vendor(uint32_t id, char *vendor) 843 { 844 vendor[0] = '@' + ((id >> 26) & 0x1f); 845 vendor[1] = '@' + ((id >> 21) & 0x1f); 846 vendor[2] = '@' + ((id >> 16) & 0x1f); 847 vendor[3] = 0; 848 } 849 850 /* 851 * Name a child 852 */ 853 static int 854 isa_name_child(dev_info_t *child, char *name, int namelen) 855 { 856 char vendor[8]; 857 int device; 858 uint32_t serial; 859 int func; 860 int bustype; 861 uint32_t base; 862 int proplen; 863 int pnpisa = 0; 864 isa_regs_t *isa_regs; 865 866 void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **); 867 868 /* 869 * older drivers aren't expecting the "standard" device 870 * node format used by the hardware nodes. these drivers 871 * only expect their own properties set in their driver.conf 872 * files. so they tell us not to call them with hardware 873 * nodes by setting the property "ignore-hardware-nodes". 874 */ 875 if (old_driver(child)) 876 return (DDI_FAILURE); 877 878 /* 879 * Fill in parent-private data 880 */ 881 if (ddi_get_parent_data(child) == NULL) { 882 struct ddi_parent_private_data *pdptr; 883 make_ddi_ppd(child, &pdptr); 884 ddi_set_parent_data(child, pdptr); 885 } 886 887 if (ndi_dev_is_persistent_node(child) == 0) { 888 /* 889 * For .conf nodes, generate name from parent private data 890 */ 891 name[0] = '\0'; 892 if (sparc_pd_getnreg(child) > 0) { 893 (void) snprintf(name, namelen, "%x,%x", 894 (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype, 895 (uint_t)sparc_pd_getreg(child, 0)->regspec_addr); 896 } 897 return (DDI_SUCCESS); 898 } 899 900 /* 901 * For hw nodes, look up "reg" property 902 */ 903 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 904 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 905 return (DDI_FAILURE); 906 } 907 908 /* 909 * extract the device identifications 910 */ 911 pnpisa = isa_regs[0].phys_hi & 0x80000000; 912 if (pnpisa) { 913 isa_vendor(isa_regs[0].phys_hi, vendor); 914 device = isa_regs[0].phys_hi & 0xffff; 915 serial = isa_regs[0].phys_lo; 916 func = (isa_regs[0].size >> 24) & 0xff; 917 if (func != 0) 918 (void) snprintf(name, namelen, "pnp%s,%04x,%x,%x", 919 vendor, device, serial, func); 920 else 921 (void) snprintf(name, namelen, "pnp%s,%04x,%x", 922 vendor, device, serial); 923 } else { 924 bustype = isa_regs[0].phys_hi; 925 base = isa_regs[0].phys_lo; 926 (void) sprintf(name, "%x,%x", bustype, base); 927 } 928 929 /* 930 * free the memory allocated by ddi_getlongprop(). 931 */ 932 kmem_free(isa_regs, proplen); 933 934 return (DDI_SUCCESS); 935 } 936 937 static int 938 isa_initchild(dev_info_t *child) 939 { 940 char name[80]; 941 942 if (isa_name_child(child, name, 80) != DDI_SUCCESS) 943 return (DDI_FAILURE); 944 ddi_set_name_addr(child, name); 945 946 if (ndi_dev_is_persistent_node(child) != 0) 947 return (DDI_SUCCESS); 948 949 /* 950 * This is a .conf node, try merge properties onto a 951 * hw node with the same name. 952 */ 953 if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) { 954 /* 955 * Return failure to remove node 956 */ 957 impl_ddi_sunbus_removechild(child); 958 return (DDI_FAILURE); 959 } 960 /* 961 * Cannot merge node, permit pseudo children 962 */ 963 return (DDI_SUCCESS); 964 } 965 966 /* 967 * called when ACPI enumeration is not used 968 */ 969 static void 970 add_known_used_resources(void) 971 { 972 /* needs to be in increasing order */ 973 int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc}; 974 int dma[] = {0x2}; 975 int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10, 976 0x778, 0x4}; 977 dev_info_t *usedrdip; 978 979 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0); 980 981 if (usedrdip == NULL) { 982 (void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES, 983 (pnode_t)DEVI_SID_NODEID, &usedrdip); 984 } 985 986 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 987 "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int))); 988 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 989 "io-space", (int *)io, (int)(sizeof (io) / sizeof (int))); 990 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 991 "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int))); 992 (void) ndi_devi_bind_driver(usedrdip, 0); 993 994 } 995 996 static void 997 isa_alloc_nodes(dev_info_t *isa_dip) 998 { 999 static int alloced = 0; 1000 int circ, i; 1001 dev_info_t *xdip; 1002 1003 /* hard coded isa stuff */ 1004 struct regspec asy_regs[] = { 1005 {1, 0x3f8, 0x8}, 1006 {1, 0x2f8, 0x8} 1007 }; 1008 int asy_intrs[] = {0x4, 0x3}; 1009 1010 struct regspec i8042_regs[] = { 1011 {1, 0x60, 0x1}, 1012 {1, 0x64, 0x1} 1013 }; 1014 int i8042_intrs[] = {0x1, 0xc}; 1015 char *acpi_prop; 1016 int acpi_enum = 1; /* ACPI is default to be on */ 1017 1018 if (alloced) 1019 return; 1020 1021 ndi_devi_enter(isa_dip, &circ); 1022 if (alloced) { /* just in case we are multi-threaded */ 1023 ndi_devi_exit(isa_dip, circ); 1024 return; 1025 } 1026 alloced = 1; 1027 1028 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1029 DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { 1030 acpi_enum = strcmp("off", acpi_prop); 1031 ddi_prop_free(acpi_prop); 1032 } 1033 1034 if (acpi_enum) { 1035 if (acpi_isa_device_enum(isa_dip)) { 1036 ndi_devi_exit(isa_dip, circ); 1037 if (isa_resource_setup() != NDI_SUCCESS) { 1038 cmn_err(CE_WARN, "isa nexus: isa " 1039 "resource setup failed"); 1040 } 1041 1042 /* serial ports? */ 1043 enumerate_BIOS_serial(isa_dip); 1044 return; 1045 } 1046 cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS"); 1047 } 1048 cmn_err(CE_NOTE, "!ACPI is off"); 1049 1050 /* serial ports */ 1051 for (i = 0; i < 2; i++) { 1052 #if defined(__xpv) 1053 /* 1054 * the hypervisor may be reserving the serial ports for console 1055 * and/or debug use. Probe the irqs to see if they are 1056 * available. 1057 */ 1058 if (ec_probe_pirq(asy_intrs[i]) == 0) 1059 continue; /* in use */ 1060 #endif 1061 ndi_devi_alloc_sleep(isa_dip, "asy", 1062 (pnode_t)DEVI_SID_NODEID, &xdip); 1063 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1064 "reg", (int *)&asy_regs[i], 3); 1065 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1066 "interrupts", asy_intrs[i]); 1067 (void) ndi_devi_bind_driver(xdip, 0); 1068 } 1069 1070 /* i8042 node */ 1071 ndi_devi_alloc_sleep(isa_dip, "i8042", 1072 (pnode_t)DEVI_SID_NODEID, &xdip); 1073 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1074 "reg", (int *)i8042_regs, 6); 1075 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1076 "interrupts", (int *)i8042_intrs, 2); 1077 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1078 "unit-address", "1,60"); 1079 (void) ndi_devi_bind_driver(xdip, 0); 1080 1081 add_known_used_resources(); 1082 1083 ndi_devi_exit(isa_dip, circ); 1084 1085 } 1086 1087 /* 1088 * On some machines, serial port 2 isn't listed in the ACPI table. 1089 * This function goes through the BIOS data area and makes sure all 1090 * the serial ports there are in the dev_info tree. If any are missing, 1091 * this function will add them. 1092 */ 1093 1094 static int num_BIOS_serial = 2; /* number of BIOS serial ports to look at */ 1095 1096 static void 1097 enumerate_BIOS_serial(dev_info_t *isa_dip) 1098 { 1099 ushort_t *bios_data; 1100 int i; 1101 dev_info_t *xdip; 1102 int found; 1103 int ret; 1104 struct regspec *tmpregs; 1105 int tmpregs_len; 1106 static struct regspec tmp_asy_regs[] = { 1107 {1, 0x3f8, 0x8}, 1108 }; 1109 static int default_asy_intrs[] = { 4, 3, 4, 3 }; 1110 static size_t size = 4; 1111 1112 /* 1113 * The first four 2-byte quantities of the BIOS data area contain 1114 * the base I/O addresses of the first four serial ports. 1115 */ 1116 bios_data = (ushort_t *)psm_map_new((paddr_t)BIOS_DATA_AREA, size, 1117 PSM_PROT_READ); 1118 for (i = 0; i < num_BIOS_serial; i++) { 1119 if (bios_data[i] == 0) { 1120 /* no COM[i]: port */ 1121 continue; 1122 } 1123 1124 /* Look for it in the dev_info tree */ 1125 found = 0; 1126 for (xdip = ddi_get_child(isa_dip); xdip != NULL; 1127 xdip = ddi_get_next_sibling(xdip)) { 1128 if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) { 1129 /* skip non asy */ 1130 continue; 1131 } 1132 1133 /* Match by addr */ 1134 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip, 1135 DDI_PROP_DONTPASS, "reg", (int **)&tmpregs, 1136 (uint_t *)&tmpregs_len); 1137 if (ret != DDI_PROP_SUCCESS) { 1138 /* error */ 1139 continue; 1140 } 1141 1142 if (tmpregs->regspec_addr == bios_data[i]) 1143 found = 1; 1144 /* 1145 * Free the memory allocated by 1146 * ddi_prop_lookup_int_array(). 1147 */ 1148 ddi_prop_free(tmpregs); 1149 1150 } 1151 1152 /* If not found, then add it */ 1153 if (!found) { 1154 ndi_devi_alloc_sleep(isa_dip, "asy", 1155 (pnode_t)DEVI_SID_NODEID, &xdip); 1156 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1157 "compatible", "PNP0500"); 1158 /* This should be gotten from master file: */ 1159 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1160 "model", "Standard PC COM port"); 1161 tmp_asy_regs[0].regspec_addr = bios_data[i]; 1162 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 1163 "reg", (int *)&tmp_asy_regs[0], 3); 1164 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1165 "interrupts", default_asy_intrs[i]); 1166 (void) ndi_devi_bind_driver(xdip, 0); 1167 } 1168 } 1169 #if defined(__xpv) 1170 /* 1171 * Check each serial port to see if it is in use by the hypervisor. 1172 * If it is in use, then remove the node from the device tree. 1173 */ 1174 i = 0; 1175 for (xdip = ddi_get_child(isa_dip); xdip != NULL; ) { 1176 int asy_intr; 1177 dev_info_t *curdip; 1178 1179 curdip = xdip; 1180 xdip = ddi_get_next_sibling(xdip); 1181 if (strncmp(ddi_node_name(curdip), "asy", 3) != 0) { 1182 /* skip non asy */ 1183 continue; 1184 } 1185 /* 1186 * Check if the hypervisor is using the serial port by probing 1187 * the irq and if it is using it remove the node 1188 * from the device tree 1189 */ 1190 asy_intr = ddi_prop_get_int(DDI_DEV_T_ANY, curdip, 1191 DDI_PROP_DONTPASS, "interrupts", -1); 1192 if (asy_intr == -1) { 1193 /* error */ 1194 continue; 1195 } 1196 1197 if (ec_probe_pirq(asy_intr)) { 1198 continue; 1199 } 1200 ret = ndi_devi_free(curdip); 1201 if (ret != DDI_SUCCESS) 1202 cmn_err(CE_WARN, 1203 "could not remove asy%d node", i); 1204 else 1205 cmn_err(CE_NOTE, "!asy%d unavailable, reserved" 1206 " to hypervisor", i); 1207 i++; 1208 } 1209 #endif /* __xpv */ 1210 1211 psm_unmap((caddr_t)bios_data, size); 1212 } 1213