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