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 2007 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 switch (cmd) { 225 case DDI_ATTACH: 226 break; 227 228 case DDI_RESUME: 229 return (DDI_SUCCESS); 230 231 default: 232 return (DDI_FAILURE); 233 } 234 235 if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci") 236 != DDI_PROP_SUCCESS) { 237 cmn_err(CE_WARN, "pci: 'device_type' prop create failed"); 238 } 239 240 if (ddi_soft_state_zalloc(pci_statep, instance) == DDI_SUCCESS) { 241 pcip = ddi_get_soft_state(pci_statep, instance); 242 } 243 244 if (pcip == NULL) { 245 goto bad_soft_state; 246 } 247 248 pcip->pci_dip = devi; 249 250 /* 251 * Initialize hotplug support on this bus. At minimum 252 * (for non hotplug bus) this would create ":devctl" minor 253 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 254 * to this bus. 255 */ 256 if (pcihp_init(devi) != DDI_SUCCESS) { 257 cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); 258 goto bad_pcihp_init; 259 } 260 261 /* Second arg: initialize for pci, not pci_express */ 262 if (pcitool_init(devi, B_FALSE) != DDI_SUCCESS) { 263 goto bad_pcitool_init; 264 } 265 266 pcip->pci_fmcap = DDI_FM_ERRCB_CAPABLE | 267 DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; 268 ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc); 269 mutex_init(&pcip->pci_err_mutex, NULL, MUTEX_DRIVER, 270 (void *)pcip->pci_fm_ibc); 271 mutex_init(&pcip->pci_peek_poke_mutex, NULL, MUTEX_DRIVER, 272 (void *)pcip->pci_fm_ibc); 273 if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { 274 pci_ereport_setup(devi); 275 ddi_fm_handler_register(devi, pci_fm_callback, NULL); 276 } 277 278 ddi_report_dev(devi); 279 280 return (DDI_SUCCESS); 281 282 bad_pcitool_init: 283 (void) pcihp_uninit(devi); 284 bad_pcihp_init: 285 ddi_soft_state_free(pci_statep, instance); 286 bad_soft_state: 287 return (DDI_FAILURE); 288 } 289 290 /*ARGSUSED*/ 291 static int 292 pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 293 { 294 int instance = ddi_get_instance(devi); 295 pci_state_t *pcip; 296 297 pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(devi)); 298 299 300 switch (cmd) { 301 case DDI_DETACH: 302 if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { 303 ddi_fm_handler_unregister(devi); 304 pci_ereport_teardown(devi); 305 } 306 mutex_destroy(&pcip->pci_peek_poke_mutex); 307 mutex_destroy(&pcip->pci_err_mutex); 308 ddi_fm_fini(devi); /* Uninitialize pcitool support. */ 309 pcitool_uninit(devi); 310 311 /* Uninitialize hotplug support on this bus. */ 312 (void) pcihp_uninit(devi); 313 314 ddi_soft_state_free(pci_statep, instance); 315 316 return (DDI_SUCCESS); 317 case DDI_SUSPEND: 318 return (DDI_SUCCESS); 319 default: 320 return (DDI_FAILURE); 321 } 322 } 323 324 static int 325 pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 326 off_t offset, off_t len, caddr_t *vaddrp) 327 { 328 struct regspec reg; 329 ddi_map_req_t mr; 330 ddi_acc_hdl_t *hp; 331 pci_regspec_t pci_reg; 332 pci_regspec_t *pci_rp; 333 int rnumber; 334 int length; 335 pci_acc_cfblk_t *cfp; 336 int space; 337 338 339 mr = *mp; /* Get private copy of request */ 340 mp = &mr; 341 342 /* 343 * check for register number 344 */ 345 switch (mp->map_type) { 346 case DDI_MT_REGSPEC: 347 pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); 348 pci_rp = &pci_reg; 349 if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 350 return (DDI_FAILURE); 351 break; 352 case DDI_MT_RNUMBER: 353 rnumber = mp->map_obj.rnumber; 354 /* 355 * get ALL "reg" properties for dip, select the one of 356 * of interest. In x86, "assigned-addresses" property 357 * is identical to the "reg" property, so there is no 358 * need to cross check the two to determine the physical 359 * address of the registers. 360 * This routine still performs some validity checks to 361 * make sure that everything is okay. 362 */ 363 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 364 DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 365 (uint_t *)&length) != DDI_PROP_SUCCESS) 366 return (DDI_FAILURE); 367 368 /* 369 * validate the register number. 370 */ 371 length /= (sizeof (pci_regspec_t) / sizeof (int)); 372 if (rnumber >= length) { 373 ddi_prop_free(pci_rp); 374 return (DDI_FAILURE); 375 } 376 377 /* 378 * copy the required entry. 379 */ 380 pci_reg = pci_rp[rnumber]; 381 382 /* 383 * free the memory allocated by ddi_prop_lookup_int_array 384 */ 385 ddi_prop_free(pci_rp); 386 387 pci_rp = &pci_reg; 388 if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 389 return (DDI_FAILURE); 390 mp->map_type = DDI_MT_REGSPEC; 391 break; 392 default: 393 return (DDI_ME_INVAL); 394 } 395 396 space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; 397 398 /* 399 * check for unmap and unlock of address space 400 */ 401 if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { 402 /* 403 * Adjust offset and length 404 * A non-zero length means override the one in the regspec. 405 */ 406 pci_rp->pci_phys_low += (uint_t)offset; 407 if (len != 0) 408 pci_rp->pci_size_low = len; 409 410 switch (space) { 411 case PCI_ADDR_CONFIG: 412 /* No work required on unmap of Config space */ 413 return (DDI_SUCCESS); 414 415 case PCI_ADDR_IO: 416 reg.regspec_bustype = 1; 417 break; 418 419 case PCI_ADDR_MEM64: 420 /* 421 * MEM64 requires special treatment on map, to check 422 * that the device is below 4G. On unmap, however, 423 * we can assume that everything is OK... the map 424 * must have succeeded. 425 */ 426 /* FALLTHROUGH */ 427 case PCI_ADDR_MEM32: 428 reg.regspec_bustype = 0; 429 break; 430 431 default: 432 return (DDI_FAILURE); 433 } 434 reg.regspec_addr = pci_rp->pci_phys_low; 435 reg.regspec_size = pci_rp->pci_size_low; 436 437 mp->map_obj.rp = ® 438 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 439 440 } 441 442 /* check for user mapping request - not legal for Config */ 443 if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { 444 return (DDI_FAILURE); 445 } 446 447 /* 448 * check for config space 449 * On x86, CONFIG is not mapped via MMU and there is 450 * no endian-ness issues. Set the attr field in the handle to 451 * indicate that the common routines to call the nexus driver. 452 */ 453 if (space == PCI_ADDR_CONFIG) { 454 /* Can't map config space without a handle */ 455 hp = (ddi_acc_hdl_t *)mp->map_handlep; 456 if (hp == NULL) 457 return (DDI_FAILURE); 458 459 /* record the device address for future reference */ 460 cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; 461 cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 462 cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 463 cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 464 465 *vaddrp = (caddr_t)offset; 466 return (pci_fm_acc_setup(hp, offset, len)); 467 } 468 469 /* 470 * range check 471 */ 472 if ((offset >= pci_rp->pci_size_low) || 473 (len > pci_rp->pci_size_low) || 474 (offset + len > pci_rp->pci_size_low)) { 475 return (DDI_FAILURE); 476 } 477 478 /* 479 * Adjust offset and length 480 * A non-zero length means override the one in the regspec. 481 */ 482 pci_rp->pci_phys_low += (uint_t)offset; 483 if (len != 0) 484 pci_rp->pci_size_low = len; 485 486 /* 487 * convert the pci regsec into the generic regspec used by the 488 * parent root nexus driver. 489 */ 490 switch (space) { 491 case PCI_ADDR_IO: 492 reg.regspec_bustype = 1; 493 break; 494 case PCI_ADDR_MEM64: 495 /* 496 * We can't handle 64-bit devices that are mapped above 497 * 4G or that are larger than 4G. 498 */ 499 if (pci_rp->pci_phys_mid != 0 || 500 pci_rp->pci_size_hi != 0) 501 return (DDI_FAILURE); 502 /* 503 * Other than that, we can treat them as 32-bit mappings 504 */ 505 /* FALLTHROUGH */ 506 case PCI_ADDR_MEM32: 507 reg.regspec_bustype = 0; 508 break; 509 default: 510 return (DDI_FAILURE); 511 } 512 reg.regspec_addr = pci_rp->pci_phys_low; 513 reg.regspec_size = pci_rp->pci_size_low; 514 515 mp->map_obj.rp = ® 516 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 517 } 518 519 520 /*ARGSUSED*/ 521 static int 522 pci_ctlops(dev_info_t *dip, dev_info_t *rdip, 523 ddi_ctl_enum_t ctlop, void *arg, void *result) 524 { 525 pci_regspec_t *drv_regp; 526 uint_t reglen; 527 int rn; 528 int totreg; 529 pci_state_t *pcip; 530 struct attachspec *asp; 531 532 switch (ctlop) { 533 case DDI_CTLOPS_REPORTDEV: 534 if (rdip == (dev_info_t *)0) 535 return (DDI_FAILURE); 536 cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 537 ddi_node_name(rdip), ddi_get_name_addr(rdip), 538 ddi_driver_name(rdip), 539 ddi_get_instance(rdip)); 540 return (DDI_SUCCESS); 541 542 case DDI_CTLOPS_INITCHILD: 543 return (pci_initchild((dev_info_t *)arg)); 544 545 case DDI_CTLOPS_UNINITCHILD: 546 return (pci_removechild((dev_info_t *)arg)); 547 548 case DDI_CTLOPS_SIDDEV: 549 return (DDI_SUCCESS); 550 551 case DDI_CTLOPS_REGSIZE: 552 case DDI_CTLOPS_NREGS: 553 if (rdip == (dev_info_t *)0) 554 return (DDI_FAILURE); 555 556 *(int *)result = 0; 557 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 558 DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, 559 ®len) != DDI_PROP_SUCCESS) { 560 return (DDI_FAILURE); 561 } 562 563 totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); 564 if (ctlop == DDI_CTLOPS_NREGS) 565 *(int *)result = totreg; 566 else if (ctlop == DDI_CTLOPS_REGSIZE) { 567 rn = *(int *)arg; 568 if (rn >= totreg) { 569 ddi_prop_free(drv_regp); 570 return (DDI_FAILURE); 571 } 572 *(off_t *)result = drv_regp[rn].pci_size_low; 573 } 574 ddi_prop_free(drv_regp); 575 576 return (DDI_SUCCESS); 577 578 case DDI_CTLOPS_POWER: { 579 power_req_t *reqp = (power_req_t *)arg; 580 /* 581 * We currently understand reporting of PCI_PM_IDLESPEED 582 * capability. Everything else is passed up. 583 */ 584 if ((reqp->request_type == PMR_REPORT_PMCAP) && 585 (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) { 586 587 return (DDI_SUCCESS); 588 } 589 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 590 } 591 592 case DDI_CTLOPS_PEEK: 593 case DDI_CTLOPS_POKE: 594 pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); 595 return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, 596 pci_common_peekpoke, &pcip->pci_err_mutex, 597 &pcip->pci_peek_poke_mutex)); 598 599 /* for now only X86 systems support PME wakeup from suspended state */ 600 case DDI_CTLOPS_ATTACH: 601 asp = (struct attachspec *)arg; 602 if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE) 603 if (pci_pre_resume(rdip) != DDI_SUCCESS) 604 return (DDI_FAILURE); 605 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 606 607 case DDI_CTLOPS_DETACH: 608 asp = (struct attachspec *)arg; 609 if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST) 610 if (pci_post_suspend(rdip) != DDI_SUCCESS) 611 return (DDI_FAILURE); 612 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 613 614 default: 615 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 616 } 617 618 /* NOTREACHED */ 619 620 } 621 622 /* 623 * pci_intr_ops 624 */ 625 static int 626 pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 627 ddi_intr_handle_impl_t *hdlp, void *result) 628 { 629 return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result)); 630 } 631 632 633 static int 634 pci_initchild(dev_info_t *child) 635 { 636 char name[80]; 637 ddi_acc_handle_t config_handle; 638 ushort_t command_preserve, command; 639 640 if (pci_common_name_child(child, name, 80) != DDI_SUCCESS) { 641 return (DDI_FAILURE); 642 } 643 ddi_set_name_addr(child, name); 644 645 /* 646 * Pseudo nodes indicate a prototype node with per-instance 647 * properties to be merged into the real h/w device node. 648 * The interpretation of the unit-address is DD[,F] 649 * where DD is the device id and F is the function. 650 */ 651 if (ndi_dev_is_persistent_node(child) == 0) { 652 extern int pci_allow_pseudo_children; 653 654 ddi_set_parent_data(child, NULL); 655 656 /* 657 * Try to merge the properties from this prototype 658 * node into real h/w nodes. 659 */ 660 if (ndi_merge_node(child, pci_common_name_child) == 661 DDI_SUCCESS) { 662 /* 663 * Merged ok - return failure to remove the node. 664 */ 665 ddi_set_name_addr(child, NULL); 666 return (DDI_FAILURE); 667 } 668 669 /* workaround for ddivs to run under PCI */ 670 if (pci_allow_pseudo_children) { 671 /* 672 * If the "interrupts" property doesn't exist, 673 * this must be the ddivs no-intr case, and it returns 674 * DDI_SUCCESS instead of DDI_FAILURE. 675 */ 676 if (ddi_prop_get_int(DDI_DEV_T_ANY, child, 677 DDI_PROP_DONTPASS, "interrupts", -1) == -1) 678 return (DDI_SUCCESS); 679 /* 680 * Create the ddi_parent_private_data for a pseudo 681 * child. 682 */ 683 pci_common_set_parent_private_data(child); 684 return (DDI_SUCCESS); 685 } 686 687 /* 688 * The child was not merged into a h/w node, 689 * but there's not much we can do with it other 690 * than return failure to cause the node to be removed. 691 */ 692 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 693 ddi_get_name(child), ddi_get_name_addr(child), 694 ddi_get_name(child)); 695 ddi_set_name_addr(child, NULL); 696 return (DDI_NOT_WELL_FORMED); 697 } 698 699 if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 700 "interrupts", -1) != -1) 701 pci_common_set_parent_private_data(child); 702 else 703 ddi_set_parent_data(child, NULL); 704 705 /* 706 * initialize command register 707 */ 708 if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) 709 return (DDI_FAILURE); 710 711 /* 712 * Support for the "command-preserve" property. 713 */ 714 command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, 715 DDI_PROP_DONTPASS, "command-preserve", 0); 716 command = pci_config_get16(config_handle, PCI_CONF_COMM); 717 command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 718 command |= (pci_command_default & ~command_preserve); 719 pci_config_put16(config_handle, PCI_CONF_COMM, command); 720 721 pci_config_teardown(&config_handle); 722 return (DDI_SUCCESS); 723 } 724 725 static int 726 pci_removechild(dev_info_t *dip) 727 { 728 struct ddi_parent_private_data *pdptr; 729 730 if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 731 kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); 732 ddi_set_parent_data(dip, NULL); 733 } 734 ddi_set_name_addr(dip, NULL); 735 736 /* 737 * Strip the node to properly convert it back to prototype form 738 */ 739 ddi_remove_minor_node(dip, NULL); 740 741 impl_rem_dev_props(dip); 742 743 return (DDI_SUCCESS); 744 } 745 746 747 /* 748 * When retrofitting this module for pci_tools, functions such as open, close, 749 * and ioctl are now pulled into this module. Before this, the functions in 750 * the pcihp module were referenced directly. Now they are called or 751 * referenced through the pcihp cb_ops structure from functions in this module. 752 */ 753 754 static int 755 pci_open(dev_t *devp, int flags, int otyp, cred_t *credp) 756 { 757 return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp)); 758 } 759 760 static int 761 pci_close(dev_t dev, int flags, int otyp, cred_t *credp) 762 { 763 return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp)); 764 } 765 766 static int 767 pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 768 { 769 minor_t minor = getminor(dev); 770 int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 771 pci_state_t *pci_p = ddi_get_soft_state(pci_statep, instance); 772 773 if (pci_p == NULL) 774 return (ENXIO); 775 776 return (pci_common_ioctl(pci_p->pci_dip, 777 dev, cmd, arg, mode, credp, rvalp)); 778 } 779 780 781 static int 782 pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 783 int flags, char *name, caddr_t valuep, int *lengthp) 784 { 785 return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, 786 name, valuep, lengthp)); 787 } 788 789 static int 790 pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 791 { 792 return (pcihp_info(dip, cmd, arg, result)); 793 } 794 795 /*ARGSUSED*/ 796 static int 797 pci_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap, 798 ddi_iblock_cookie_t *ibc) 799 { 800 pci_state_t *pcip = ddi_get_soft_state(pci_statep, 801 ddi_get_instance(dip)); 802 803 ASSERT(ibc != NULL); 804 *ibc = pcip->pci_fm_ibc; 805 806 return (pcip->pci_fmcap); 807 } 808 809 /*ARGSUSED*/ 810 static int 811 pci_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used) 812 { 813 pci_state_t *pcip = ddi_get_soft_state(pci_statep, 814 ddi_get_instance(dip)); 815 816 mutex_enter(&pcip->pci_err_mutex); 817 pci_ereport_post(dip, derr, NULL); 818 mutex_exit(&pcip->pci_err_mutex); 819 return (derr->fme_status); 820 } 821