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