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