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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * Host to PCI-Express local bus driver 32 */ 33 34 #include <sys/conf.h> 35 #include <sys/modctl.h> 36 #include <sys/pcie.h> 37 #include <sys/pci_impl.h> 38 #include <sys/sysmacros.h> 39 #include <sys/ddi_intr.h> 40 #include <sys/sunndi.h> 41 #include <sys/hotplug/pci/pcihp.h> 42 #include <io/pci/pci_common.h> 43 #include <io/pci/pci_tools_ext.h> 44 #include <io/pciex/pcie_error.h> 45 46 /* 47 * Bus Operation functions 48 */ 49 static int npe_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 50 off_t, off_t, caddr_t *); 51 static int npe_map_legacy_pci(off_t, off_t, caddr_t *, ddi_acc_hdl_t *); 52 static int npe_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 53 void *, void *); 54 static int npe_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 55 ddi_intr_handle_impl_t *, void *); 56 57 struct bus_ops npe_bus_ops = { 58 BUSO_REV, 59 npe_bus_map, 60 NULL, 61 NULL, 62 NULL, 63 i_ddi_map_fault, 64 ddi_dma_map, 65 ddi_dma_allochdl, 66 ddi_dma_freehdl, 67 ddi_dma_bindhdl, 68 ddi_dma_unbindhdl, 69 ddi_dma_flush, 70 ddi_dma_win, 71 ddi_dma_mctl, 72 npe_ctlops, 73 ddi_bus_prop_op, 74 0, /* (*bus_get_eventcookie)(); */ 75 0, /* (*bus_add_eventcall)(); */ 76 0, /* (*bus_remove_eventcall)(); */ 77 0, /* (*bus_post_event)(); */ 78 0, /* (*bus_intr_ctl)(); */ 79 0, /* (*bus_config)(); */ 80 0, /* (*bus_unconfig)(); */ 81 NULL, /* (*bus_fm_init)(); */ 82 NULL, /* (*bus_fm_fini)(); */ 83 NULL, /* (*bus_fm_access_enter)(); */ 84 NULL, /* (*bus_fm_access_exit)(); */ 85 NULL, /* (*bus_power)(); */ 86 npe_intr_ops /* (*bus_intr_op)(); */ 87 }; 88 89 /* 90 * One goal here is to leverage off of the pcihp.c source without making 91 * changes to it. Call into it's cb_ops directly if needed, piggybacking 92 * anything else needed by the pci_tools.c module. Only pci_tools and pcihp 93 * will be using the PCI devctl node. 94 */ 95 static int npe_open(dev_t *, int, int, cred_t *); 96 static int npe_close(dev_t, int, int, cred_t *); 97 static int npe_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 98 static int npe_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 99 caddr_t, int *); 100 static int npe_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 101 102 struct cb_ops npe_cb_ops = { 103 npe_open, /* open */ 104 npe_close, /* close */ 105 nodev, /* strategy */ 106 nodev, /* print */ 107 nodev, /* dump */ 108 nodev, /* read */ 109 nodev, /* write */ 110 npe_ioctl, /* ioctl */ 111 nodev, /* devmap */ 112 nodev, /* mmap */ 113 nodev, /* segmap */ 114 nochpoll, /* poll */ 115 npe_prop_op, /* cb_prop_op */ 116 NULL, /* streamtab */ 117 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 118 CB_REV, /* rev */ 119 nodev, /* int (*cb_aread)() */ 120 nodev /* int (*cb_awrite)() */ 121 }; 122 123 124 /* 125 * Device Node Operation functions 126 */ 127 static int npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 128 static int npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 129 130 struct dev_ops npe_ops = { 131 DEVO_REV, /* devo_rev */ 132 0, /* refcnt */ 133 npe_info, /* info */ 134 nulldev, /* identify */ 135 nulldev, /* probe */ 136 npe_attach, /* attach */ 137 npe_detach, /* detach */ 138 nulldev, /* reset */ 139 &npe_cb_ops, /* driver operations */ 140 &npe_bus_ops /* bus operations */ 141 }; 142 143 /* 144 * Internal routines in support of particular npe_ctlops. 145 */ 146 static int npe_removechild(dev_info_t *child); 147 static int npe_initchild(dev_info_t *child); 148 static int npe_check_if_device_is_pci(dev_info_t *); 149 150 /* 151 * External support routine 152 */ 153 extern void npe_query_acpi_mcfg(dev_info_t *dip); 154 extern void npe_ck804_fix_aer_ptr(dev_info_t *child); 155 156 /* 157 * Module linkage information for the kernel. 158 */ 159 static struct modldrv modldrv = { 160 &mod_driverops, /* Type of module */ 161 "Host to PCIe nexus driver %I%", 162 &npe_ops, /* driver ops */ 163 }; 164 165 static struct modlinkage modlinkage = { 166 MODREV_1, 167 (void *)&modldrv, 168 NULL 169 }; 170 171 /* Save minimal state. */ 172 void *npe_statep; 173 174 175 int 176 _init(void) 177 { 178 int e; 179 180 /* 181 * Initialize per-pci bus soft state pointer. 182 */ 183 e = ddi_soft_state_init(&npe_statep, sizeof (pci_state_t), 1); 184 if (e != 0) 185 return (e); 186 187 if ((e = mod_install(&modlinkage)) != 0) 188 ddi_soft_state_fini(&npe_statep); 189 190 return (e); 191 } 192 193 194 int 195 _fini(void) 196 { 197 int rc; 198 199 rc = mod_remove(&modlinkage); 200 if (rc != 0) 201 return (rc); 202 203 ddi_soft_state_fini(&npe_statep); 204 return (rc); 205 } 206 207 208 int 209 _info(struct modinfo *modinfop) 210 { 211 return (mod_info(&modlinkage, modinfop)); 212 } 213 214 215 /*ARGSUSED*/ 216 static int 217 npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 218 { 219 /* 220 * Use the minor number as constructed by pcihp, as the index value to 221 * ddi_soft_state_zalloc. 222 */ 223 int instance = ddi_get_instance(devi); 224 pci_state_t *pcip = NULL; 225 226 if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", 227 "pciex") != DDI_PROP_SUCCESS) { 228 cmn_err(CE_WARN, "npe: 'device_type' prop create failed"); 229 } 230 231 if (ddi_soft_state_zalloc(npe_statep, instance) == DDI_SUCCESS) 232 pcip = ddi_get_soft_state(npe_statep, instance); 233 234 if (pcip == NULL) 235 return (DDI_FAILURE); 236 237 pcip->pci_dip = devi; 238 239 /* 240 * Initialize hotplug support on this bus. At minimum 241 * (for non hotplug bus) this would create ":devctl" minor 242 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 243 * to this bus. 244 */ 245 if (pcihp_init(devi) != DDI_SUCCESS) { 246 cmn_err(CE_WARN, "npe: Failed to setup hotplug framework"); 247 ddi_soft_state_free(npe_statep, instance); 248 return (DDI_FAILURE); 249 } 250 251 /* Second arg: initialize for pci_express root nexus */ 252 if (pcitool_init(devi, B_TRUE) != DDI_SUCCESS) { 253 (void) pcihp_uninit(devi); 254 ddi_soft_state_free(npe_statep, instance); 255 return (DDI_FAILURE); 256 } 257 258 npe_query_acpi_mcfg(devi); 259 ddi_report_dev(devi); 260 return (DDI_SUCCESS); 261 262 } 263 264 265 /*ARGSUSED*/ 266 static int 267 npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 268 { 269 int instance = ddi_get_instance(devi); 270 271 /* Uninitialize pcitool support. */ 272 pcitool_uninit(devi); 273 274 /* 275 * Uninitialize hotplug support on this bus. 276 */ 277 (void) pcihp_uninit(devi); 278 ddi_soft_state_free(npe_statep, instance); 279 return (DDI_SUCCESS); 280 } 281 282 283 static int 284 npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 285 off_t offset, off_t len, caddr_t *vaddrp) 286 { 287 int rnumber; 288 int length; 289 int space; 290 dev_info_t *parent; 291 ddi_acc_hdl_t *hp; 292 ddi_map_req_t mr; 293 pci_regspec_t pci_reg; 294 pci_regspec_t *pci_rp; 295 struct regspec reg; 296 pci_acc_cfblk_t *cfp; 297 298 299 mr = *mp; /* Get private copy of request */ 300 mp = &mr; 301 302 /* 303 * check for register number 304 */ 305 switch (mp->map_type) { 306 case DDI_MT_REGSPEC: 307 pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); 308 pci_rp = &pci_reg; 309 if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 310 return (DDI_FAILURE); 311 break; 312 case DDI_MT_RNUMBER: 313 rnumber = mp->map_obj.rnumber; 314 /* 315 * get ALL "reg" properties for dip, select the one of 316 * of interest. In x86, "assigned-addresses" property 317 * is identical to the "reg" property, so there is no 318 * need to cross check the two to determine the physical 319 * address of the registers. 320 * This routine still performs some validity checks to 321 * make sure that everything is okay. 322 */ 323 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 324 DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 325 (uint_t *)&length) != DDI_PROP_SUCCESS) 326 return (DDI_FAILURE); 327 328 /* 329 * validate the register number. 330 */ 331 length /= (sizeof (pci_regspec_t) / sizeof (int)); 332 if (rnumber >= length) { 333 ddi_prop_free(pci_rp); 334 return (DDI_FAILURE); 335 } 336 337 /* 338 * copy the required entry. 339 */ 340 pci_reg = pci_rp[rnumber]; 341 342 /* 343 * free the memory allocated by ddi_prop_lookup_int_array 344 */ 345 ddi_prop_free(pci_rp); 346 347 pci_rp = &pci_reg; 348 if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 349 return (DDI_FAILURE); 350 mp->map_type = DDI_MT_REGSPEC; 351 break; 352 default: 353 return (DDI_ME_INVAL); 354 } 355 356 space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; 357 358 /* 359 * check for unmap and unlock of address space 360 */ 361 if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { 362 /* 363 * Adjust offset and length 364 * A non-zero length means override the one in the regspec. 365 */ 366 pci_rp->pci_phys_low += (uint_t)offset; 367 if (len != 0) 368 pci_rp->pci_size_low = len; 369 370 switch (space) { 371 case PCI_ADDR_IO: 372 reg.regspec_bustype = 1; 373 break; 374 375 case PCI_ADDR_CONFIG: 376 /* Check for AMD's northbridges */ 377 if (is_amd_northbridge(rdip) == 0) 378 return (DDI_SUCCESS); 379 380 /* 381 * 382 * Next two checks are workarounds to fix 383 * AMD-8132's inability to handle MMCFG 384 * accesses on Galaxy's PE servers. 385 * 386 * Solution: Check if device_type is "pci" 387 * and for any such device do I/O based config space 388 * access. 389 * 390 * Leaf devices under AMD-8132 may not 391 * have a device_type of "pci". This was observed 392 * during testing. Hence, if first check fails 393 * then check if the parent has "device_type" 394 * of "pci" and allow I/O based config space access 395 */ 396 if (npe_check_if_device_is_pci(rdip)) 397 return (DDI_SUCCESS); 398 399 parent = ddi_get_parent(rdip); 400 if (parent && npe_check_if_device_is_pci(parent)) 401 return (DDI_SUCCESS); 402 403 /* FALLTHROUGH */ 404 case PCI_ADDR_MEM64: 405 /* 406 * MEM64 requires special treatment on map, to check 407 * that the device is below 4G. On unmap, however, 408 * we can assume that everything is OK... the map 409 * must have succeeded. 410 */ 411 /* FALLTHROUGH */ 412 case PCI_ADDR_MEM32: 413 reg.regspec_bustype = 0; 414 break; 415 416 default: 417 return (DDI_FAILURE); 418 } 419 reg.regspec_addr = pci_rp->pci_phys_low; 420 reg.regspec_size = pci_rp->pci_size_low; 421 422 mp->map_obj.rp = ® 423 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 424 425 } 426 427 /* check for user mapping request - not legal for Config */ 428 if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { 429 cmn_err(CE_NOTE, "npe: Config mapping request from user\n"); 430 return (DDI_FAILURE); 431 } 432 433 434 if (space == PCI_ADDR_CONFIG) { 435 /* Can't map config space without a handle */ 436 hp = (ddi_acc_hdl_t *)mp->map_handlep; 437 if (hp == NULL) 438 return (DDI_FAILURE); 439 440 /* record the device address for future reference */ 441 cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; 442 cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 443 cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 444 cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 445 446 /* Check for AMD's northbridges */ 447 if (is_amd_northbridge(rdip) == 0) 448 return (npe_map_legacy_pci(offset, len, vaddrp, hp)); 449 450 if (npe_check_if_device_is_pci(rdip)) 451 return (npe_map_legacy_pci(offset, len, vaddrp, hp)); 452 453 parent = ddi_get_parent(rdip); 454 if (parent && npe_check_if_device_is_pci(parent)) 455 return (npe_map_legacy_pci(offset, len, vaddrp, hp)); 456 457 pci_rp->pci_phys_low = ddi_prop_get_int64(DDI_DEV_T_ANY, 458 rdip, 0, "ecfga-base-address", 0); 459 460 pci_rp->pci_phys_low += ((cfp->c_busnum << 20) | 461 (cfp->c_devnum) << 15 | (cfp->c_funcnum << 12)); 462 463 pci_rp->pci_size_low = PCIE_CONF_HDR_SIZE; 464 } 465 466 length = pci_rp->pci_size_low; 467 468 /* 469 * range check 470 */ 471 if ((offset >= length) || (len > length) || (offset + len > length)) 472 return (DDI_FAILURE); 473 474 /* 475 * Adjust offset and length 476 * A non-zero length means override the one in the regspec. 477 */ 478 pci_rp->pci_phys_low += (uint_t)offset; 479 if (len != 0) 480 pci_rp->pci_size_low = len; 481 482 /* 483 * convert the pci regsec into the generic regspec used by the 484 * parent root nexus driver. 485 */ 486 switch (space) { 487 case PCI_ADDR_IO: 488 reg.regspec_bustype = 1; 489 break; 490 case PCI_ADDR_CONFIG: 491 case PCI_ADDR_MEM64: 492 /* 493 * We can't handle 64-bit devices that are mapped above 494 * 4G or that are larger than 4G. 495 */ 496 if (pci_rp->pci_phys_mid != 0 || pci_rp->pci_size_hi != 0) 497 return (DDI_FAILURE); 498 /* 499 * Other than that, we can treat them as 32-bit mappings 500 */ 501 /* FALLTHROUGH */ 502 case PCI_ADDR_MEM32: 503 reg.regspec_bustype = 0; 504 break; 505 default: 506 return (DDI_FAILURE); 507 } 508 509 reg.regspec_addr = pci_rp->pci_phys_low; 510 reg.regspec_size = pci_rp->pci_size_low; 511 512 mp->map_obj.rp = ® 513 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 514 } 515 516 517 static int 518 npe_map_legacy_pci(off_t offset, off_t len, caddr_t *vaddrp, ddi_acc_hdl_t *hp) 519 { 520 ddi_acc_impl_t *ap; 521 522 /* 523 * check for config space 524 * On x86, CONFIG is not mapped via MMU and there is 525 * no endian-ness issues. Set the attr field in the handle to 526 * indicate that the common routines to call the nexus driver. 527 */ 528 529 ap = (ddi_acc_impl_t *)hp->ah_platform_private; 530 531 /* endian-ness check */ 532 if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 533 return (DDI_FAILURE); 534 535 /* 536 * range check 537 */ 538 if ((offset >= PCI_CONF_HDR_SIZE) || 539 (len > PCI_CONF_HDR_SIZE) || 540 (offset + len > PCI_CONF_HDR_SIZE)) 541 return (DDI_FAILURE); 542 *vaddrp = (caddr_t)offset; 543 544 ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 545 ap->ahi_put8 = pci_config_wr8; 546 ap->ahi_get8 = pci_config_rd8; 547 ap->ahi_put64 = pci_config_wr64; 548 ap->ahi_get64 = pci_config_rd64; 549 ap->ahi_rep_put8 = pci_config_rep_wr8; 550 ap->ahi_rep_get8 = pci_config_rep_rd8; 551 ap->ahi_rep_put64 = pci_config_rep_wr64; 552 ap->ahi_rep_get64 = pci_config_rep_rd64; 553 ap->ahi_get16 = pci_config_rd16; 554 ap->ahi_get32 = pci_config_rd32; 555 ap->ahi_put16 = pci_config_wr16; 556 ap->ahi_put32 = pci_config_wr32; 557 ap->ahi_rep_get16 = pci_config_rep_rd16; 558 ap->ahi_rep_get32 = pci_config_rep_rd32; 559 ap->ahi_rep_put16 = pci_config_rep_wr16; 560 ap->ahi_rep_put32 = pci_config_rep_wr32; 561 562 /* Initialize to default check/notify functions */ 563 ap->ahi_fault_check = i_ddi_acc_fault_check; 564 ap->ahi_fault_notify = i_ddi_acc_fault_notify; 565 ap->ahi_fault = 0; 566 impl_acc_err_init(hp); 567 568 return (DDI_SUCCESS); 569 } 570 571 572 /*ARGSUSED*/ 573 static int 574 npe_ctlops(dev_info_t *dip, dev_info_t *rdip, 575 ddi_ctl_enum_t ctlop, void *arg, void *result) 576 { 577 int rn; 578 int totreg; 579 uint_t reglen; 580 pci_regspec_t *drv_regp; 581 582 switch (ctlop) { 583 case DDI_CTLOPS_REPORTDEV: 584 if (rdip == (dev_info_t *)0) 585 return (DDI_FAILURE); 586 cmn_err(CE_CONT, "?PCI Express-device: %s@%s, %s%d\n", 587 ddi_node_name(rdip), ddi_get_name_addr(rdip), 588 ddi_driver_name(rdip), ddi_get_instance(rdip)); 589 return (DDI_SUCCESS); 590 591 case DDI_CTLOPS_INITCHILD: 592 return (npe_initchild((dev_info_t *)arg)); 593 594 case DDI_CTLOPS_UNINITCHILD: 595 return (npe_removechild((dev_info_t *)arg)); 596 597 case DDI_CTLOPS_SIDDEV: 598 return (DDI_SUCCESS); 599 600 case DDI_CTLOPS_REGSIZE: 601 case DDI_CTLOPS_NREGS: 602 if (rdip == (dev_info_t *)0) 603 return (DDI_FAILURE); 604 605 *(int *)result = 0; 606 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 607 DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, 608 ®len) != DDI_PROP_SUCCESS) { 609 return (DDI_FAILURE); 610 } 611 612 totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); 613 if (ctlop == DDI_CTLOPS_NREGS) 614 *(int *)result = totreg; 615 else if (ctlop == DDI_CTLOPS_REGSIZE) { 616 rn = *(int *)arg; 617 if (rn >= totreg) { 618 ddi_prop_free(drv_regp); 619 return (DDI_FAILURE); 620 } 621 *(off_t *)result = drv_regp[rn].pci_size_low; 622 } 623 ddi_prop_free(drv_regp); 624 625 return (DDI_SUCCESS); 626 627 case DDI_CTLOPS_POWER: 628 { 629 power_req_t *reqp = (power_req_t *)arg; 630 /* 631 * We currently understand reporting of PCI_PM_IDLESPEED 632 * capability. Everything else is passed up. 633 */ 634 if ((reqp->request_type == PMR_REPORT_PMCAP) && 635 (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) 636 return (DDI_SUCCESS); 637 638 break; 639 } 640 641 default: 642 break; 643 } 644 645 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 646 647 } 648 649 650 /* 651 * npe_intr_ops 652 */ 653 static int 654 npe_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 655 ddi_intr_handle_impl_t *hdlp, void *result) 656 { 657 return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result)); 658 } 659 660 661 static int 662 npe_initchild(dev_info_t *child) 663 { 664 char name[80]; 665 666 if (pci_common_name_child(child, name, 80) != DDI_SUCCESS) 667 return (DDI_FAILURE); 668 669 ddi_set_name_addr(child, name); 670 671 /* 672 * Pseudo nodes indicate a prototype node with per-instance 673 * properties to be merged into the real h/w device node. 674 * The interpretation of the unit-address is DD[,F] 675 * where DD is the device id and F is the function. 676 */ 677 if (ndi_dev_is_persistent_node(child) == 0) { 678 extern int pci_allow_pseudo_children; 679 680 ddi_set_parent_data(child, NULL); 681 682 /* 683 * Try to merge the properties from this prototype 684 * node into real h/w nodes. 685 */ 686 if (ndi_merge_node(child, pci_common_name_child) == 687 DDI_SUCCESS) { 688 /* 689 * Merged ok - return failure to remove the node. 690 */ 691 ddi_set_name_addr(child, NULL); 692 return (DDI_FAILURE); 693 } 694 695 /* workaround for DDIVS to run under PCI Express */ 696 if (pci_allow_pseudo_children) { 697 /* 698 * If the "interrupts" property doesn't exist, 699 * this must be the ddivs no-intr case, and it returns 700 * DDI_SUCCESS instead of DDI_FAILURE. 701 */ 702 if (ddi_prop_get_int(DDI_DEV_T_ANY, child, 703 DDI_PROP_DONTPASS, "interrupts", -1) == -1) 704 return (DDI_SUCCESS); 705 /* 706 * Create the ddi_parent_private_data for a pseudo 707 * child. 708 */ 709 pci_common_set_parent_private_data(child); 710 return (DDI_SUCCESS); 711 } 712 713 /* 714 * The child was not merged into a h/w node, 715 * but there's not much we can do with it other 716 * than return failure to cause the node to be removed. 717 */ 718 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 719 ddi_get_name(child), ddi_get_name_addr(child), 720 ddi_get_name(child)); 721 ddi_set_name_addr(child, NULL); 722 return (DDI_NOT_WELL_FORMED); 723 } 724 725 if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 726 "interrupts", -1) != -1) 727 pci_common_set_parent_private_data(child); 728 else 729 ddi_set_parent_data(child, NULL); 730 731 /* 732 * Enable AER next pointer being displayed 733 */ 734 npe_ck804_fix_aer_ptr(child); 735 736 (void) pcie_error_init(child); 737 738 return (DDI_SUCCESS); 739 } 740 741 742 static int 743 npe_removechild(dev_info_t *dip) 744 { 745 struct ddi_parent_private_data *pdptr; 746 747 /* 748 * Do it way early. 749 * Otherwise ddi_map() call form pcie_error_fini crashes 750 */ 751 pcie_error_fini(dip); 752 753 if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 754 kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); 755 ddi_set_parent_data(dip, NULL); 756 } 757 ddi_set_name_addr(dip, NULL); 758 759 /* 760 * Strip the node to properly convert it back to prototype form 761 */ 762 ddi_remove_minor_node(dip, NULL); 763 764 ddi_prop_remove_all(dip); 765 766 return (DDI_SUCCESS); 767 } 768 769 770 /* 771 * When retrofitting this module for pci_tools, functions such as open, close, 772 * and ioctl are now pulled into this module. Before this, the functions in 773 * the pcihp module were referenced directly. Now they are called or 774 * referenced through the pcihp cb_ops structure from functions in this module. 775 */ 776 static int 777 npe_open(dev_t *devp, int flags, int otyp, cred_t *credp) 778 { 779 return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp)); 780 } 781 782 static int 783 npe_close(dev_t dev, int flags, int otyp, cred_t *credp) 784 { 785 return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp)); 786 } 787 788 static int 789 npe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 790 { 791 minor_t minor = getminor(dev); 792 int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 793 pci_state_t *pci_p = ddi_get_soft_state(npe_statep, instance); 794 dev_info_t *dip; 795 796 if (pci_p == NULL) 797 return (ENXIO); 798 799 dip = pci_p->pci_dip; 800 return (pci_common_ioctl(dip, dev, cmd, arg, mode, credp, rvalp)); 801 } 802 803 static int 804 npe_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 805 int flags, char *name, caddr_t valuep, int *lengthp) 806 { 807 return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, 808 name, valuep, lengthp)); 809 } 810 811 static int 812 npe_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 813 { 814 return (pcihp_info(dip, cmd, arg, result)); 815 } 816 817 static int 818 npe_check_if_device_is_pci(dev_info_t *child) 819 { 820 int ret = 0; 821 char *dev_type = NULL; 822 823 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 824 "device_type", &dev_type) == DDI_SUCCESS) { 825 if (strcmp(dev_type, "pci") == 0) 826 ret = 1; 827 ddi_prop_free(dev_type); 828 } 829 830 return (ret); 831 } 832