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 * PCI nexus driver interface 31 */ 32 33 #include <sys/types.h> 34 #include <sys/conf.h> /* nulldev */ 35 #include <sys/stat.h> /* devctl */ 36 #include <sys/kmem.h> 37 #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 38 #include <sys/sunddi.h> 39 #include <sys/sunndi.h> 40 #include <sys/ndifm.h> 41 #include <sys/ontrap.h> 42 #include <sys/ddi_impldefs.h> 43 #include <sys/ddi_subrdefs.h> 44 #include <sys/epm.h> 45 #include <sys/hotplug/pci/pcihp.h> 46 #include <sys/pci/pci_tools_ext.h> 47 #include <sys/spl.h> 48 #include <sys/pci/pci_obj.h> 49 50 /*LINTLIBRARY*/ 51 52 /* 53 * function prototype for hotplug routine: 54 */ 55 static void 56 pci_init_hotplug(struct pci *); 57 58 /* 59 * function prototypes for dev ops routines: 60 */ 61 static int pci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 62 static int pci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 63 static int pci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 64 void *arg, void **result); 65 static int pci_ctlops_poke(pci_t *pci_p, peekpoke_ctlops_t *in_args); 66 static int pci_ctlops_peek(pci_t *pci_p, peekpoke_ctlops_t *in_args, 67 void *result); 68 static off_t get_reg_set_size(dev_info_t *child, int rnumber); 69 70 /* 71 * bus ops and dev ops structures: 72 */ 73 static struct bus_ops pci_bus_ops = { 74 BUSO_REV, 75 pci_map, 76 0, 77 0, 78 0, 79 i_ddi_map_fault, 80 pci_dma_setup, 81 pci_dma_allochdl, 82 pci_dma_freehdl, 83 pci_dma_bindhdl, 84 pci_dma_unbindhdl, 85 pci_dma_sync, 86 pci_dma_win, 87 pci_dma_ctlops, 88 pci_ctlops, 89 ddi_bus_prop_op, 90 ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ 91 ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ 92 ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ 93 ndi_post_event, /* (*bus_post_event)(); */ 94 NULL, /* (*bus_intr_ctl)(); */ 95 NULL, /* (*bus_config)(); */ 96 NULL, /* (*bus_unconfig)(); */ 97 pci_fm_init_child, /* (*bus_fm_init)(); */ 98 NULL, /* (*bus_fm_fini)(); */ 99 pci_bus_enter, /* (*bus_fm_access_enter)(); */ 100 pci_bus_exit, /* (*bus_fm_access_fini)(); */ 101 NULL, /* (*bus_power)(); */ 102 pci_intr_ops /* (*bus_intr_op)(); */ 103 }; 104 105 extern struct cb_ops pci_cb_ops; 106 107 static struct dev_ops pci_ops = { 108 DEVO_REV, 109 0, 110 pci_info, 111 nulldev, 112 0, 113 pci_attach, 114 pci_detach, 115 nodev, 116 &pci_cb_ops, 117 &pci_bus_ops, 118 0 119 }; 120 121 /* 122 * module definitions: 123 */ 124 #include <sys/modctl.h> 125 extern struct mod_ops mod_driverops; 126 127 static struct modldrv modldrv = { 128 &mod_driverops, /* Type of module - driver */ 129 "PCI Bus nexus driver %I%", /* Name of module. */ 130 &pci_ops, /* driver ops */ 131 }; 132 133 static struct modlinkage modlinkage = { 134 MODREV_1, (void *)&modldrv, NULL 135 }; 136 137 /* 138 * driver global data: 139 */ 140 void *per_pci_state; /* per-pbm soft state pointer */ 141 void *per_pci_common_state; /* per-psycho soft state pointer */ 142 kmutex_t pci_global_mutex; /* attach/detach common struct lock */ 143 errorq_t *pci_ecc_queue = NULL; /* per-system ecc handling queue */ 144 errorq_t *pci_target_queue = NULL; /* per-system target handling queue */ 145 struct cb_ops *pcihp_ops = NULL; /* hotplug module cb ops */ 146 147 148 extern void pci_child_cfg_save(dev_info_t *dip); 149 extern void pci_child_cfg_restore(dev_info_t *dip); 150 151 int 152 _init(void) 153 { 154 int e; 155 156 /* 157 * Initialize per-pci bus soft state pointer. 158 */ 159 e = ddi_soft_state_init(&per_pci_state, sizeof (pci_t), 1); 160 if (e != 0) 161 return (e); 162 163 /* 164 * Initialize per-psycho soft state pointer. 165 */ 166 e = ddi_soft_state_init(&per_pci_common_state, 167 sizeof (pci_common_t), 1); 168 if (e != 0) { 169 ddi_soft_state_fini(&per_pci_state); 170 return (e); 171 } 172 173 /* 174 * Initialize global mutexes. 175 */ 176 mutex_init(&pci_global_mutex, NULL, MUTEX_DRIVER, NULL); 177 pci_reloc_init(); 178 179 /* 180 * Create the performance kstats. 181 */ 182 pci_kstat_init(); 183 184 /* 185 * Install the module. 186 */ 187 e = mod_install(&modlinkage); 188 if (e != 0) { 189 ddi_soft_state_fini(&per_pci_state); 190 ddi_soft_state_fini(&per_pci_common_state); 191 mutex_destroy(&pci_global_mutex); 192 } 193 return (e); 194 } 195 196 int 197 _fini(void) 198 { 199 int e; 200 201 /* 202 * Remove the module. 203 */ 204 e = mod_remove(&modlinkage); 205 if (e != 0) 206 return (e); 207 208 /* 209 * Destroy pci_ecc_queue, and set it to NULL. 210 */ 211 if (pci_ecc_queue) 212 errorq_destroy(pci_ecc_queue); 213 214 pci_ecc_queue = NULL; 215 216 /* 217 * Destroy pci_target_queue, and set it to NULL. 218 */ 219 if (pci_target_queue) 220 errorq_destroy(pci_target_queue); 221 222 pci_target_queue = NULL; 223 224 /* 225 * Destroy the performance kstats. 226 */ 227 pci_kstat_fini(); 228 229 /* 230 * Free the per-pci and per-psycho soft state info and destroy 231 * mutex for per-psycho soft state. 232 */ 233 ddi_soft_state_fini(&per_pci_state); 234 ddi_soft_state_fini(&per_pci_common_state); 235 mutex_destroy(&pci_global_mutex); 236 pci_reloc_fini(); 237 return (e); 238 } 239 240 int 241 _info(struct modinfo *modinfop) 242 { 243 return (mod_info(&modlinkage, modinfop)); 244 } 245 246 /*ARGSUSED*/ 247 static int 248 pci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 249 { 250 int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(getminor((dev_t)arg)); 251 pci_t *pci_p = get_pci_soft_state(instance); 252 253 /* allow hotplug to deal with ones it manages */ 254 if (pci_p && (pci_p->hotplug_capable == B_TRUE)) 255 return (pcihp_info(dip, infocmd, arg, result)); 256 257 /* non-hotplug or not attached */ 258 switch (infocmd) { 259 case DDI_INFO_DEVT2INSTANCE: 260 *result = (void *)instance; 261 return (DDI_SUCCESS); 262 263 case DDI_INFO_DEVT2DEVINFO: 264 if (pci_p == NULL) 265 return (DDI_FAILURE); 266 *result = (void *)pci_p->pci_dip; 267 return (DDI_SUCCESS); 268 269 default: 270 return (DDI_FAILURE); 271 } 272 } 273 274 275 /* device driver entry points */ 276 /* 277 * attach entry point: 278 */ 279 static int 280 pci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 281 { 282 pci_t *pci_p; /* per bus state pointer */ 283 int instance = ddi_get_instance(dip); 284 285 switch (cmd) { 286 case DDI_ATTACH: 287 DEBUG0(DBG_ATTACH, dip, "DDI_ATTACH\n"); 288 289 /* 290 * Allocate and get the per-pci soft state structure. 291 */ 292 if (alloc_pci_soft_state(instance) != DDI_SUCCESS) { 293 cmn_err(CE_WARN, "%s%d: can't allocate pci state", 294 ddi_driver_name(dip), instance); 295 goto err_bad_pci_softstate; 296 } 297 pci_p = get_pci_soft_state(instance); 298 pci_p->pci_dip = dip; 299 mutex_init(&pci_p->pci_mutex, NULL, MUTEX_DRIVER, NULL); 300 pci_p->pci_soft_state = PCI_SOFT_STATE_CLOSED; 301 pci_p->pci_open_count = 0; 302 303 /* 304 * Get key properties of the pci bridge node and 305 * determine it's type (psycho, schizo, etc ...). 306 */ 307 if (get_pci_properties(pci_p, dip) == DDI_FAILURE) 308 goto err_bad_pci_prop; 309 310 /* 311 * Map in the registers. 312 */ 313 if (map_pci_registers(pci_p, dip) == DDI_FAILURE) 314 goto err_bad_reg_prop; 315 316 if (pci_obj_setup(pci_p) != DDI_SUCCESS) 317 goto err_bad_objs; 318 319 /* 320 * If this PCI leaf has hotplug and this platform 321 * loads hotplug modules then initialize the 322 * hotplug framework. 323 */ 324 pci_init_hotplug(pci_p); 325 326 /* 327 * Create the "devctl" node for hotplug support. 328 * For non-hotplug bus, we still need ":devctl" to 329 * support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls. 330 */ 331 if (pci_p->hotplug_capable == B_FALSE) { 332 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, 333 PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR), 334 DDI_NT_NEXUS, 0) != DDI_SUCCESS) 335 goto err_bad_devctl_node; 336 } 337 338 /* 339 * Create pcitool nodes for register access and interrupt 340 * routing. 341 */ 342 if (pcitool_init(dip) != DDI_SUCCESS) { 343 goto err_bad_pcitool_nodes; 344 } 345 346 /* 347 * Due to unresolved hardware issues, disable PCIPM until 348 * the problem is fully understood. 349 * 350 * pci_pwr_setup(pci_p, dip); 351 */ 352 353 ddi_report_dev(dip); 354 355 pci_p->pci_state = PCI_ATTACHED; 356 DEBUG0(DBG_ATTACH, dip, "attach success\n"); 357 break; 358 359 err_bad_pcitool_nodes: 360 if (pci_p->hotplug_capable == B_FALSE) 361 ddi_remove_minor_node(dip, "devctl"); 362 else 363 (void) pcihp_uninit(dip); 364 err_bad_devctl_node: 365 pci_obj_destroy(pci_p); 366 err_bad_objs: 367 unmap_pci_registers(pci_p); 368 err_bad_reg_prop: 369 free_pci_properties(pci_p); 370 err_bad_pci_prop: 371 mutex_destroy(&pci_p->pci_mutex); 372 free_pci_soft_state(instance); 373 err_bad_pci_softstate: 374 return (DDI_FAILURE); 375 376 case DDI_RESUME: 377 DEBUG0(DBG_ATTACH, dip, "DDI_RESUME\n"); 378 379 /* 380 * Make sure the Psycho control registers and IOMMU 381 * are configured properly. 382 */ 383 pci_p = get_pci_soft_state(instance); 384 mutex_enter(&pci_p->pci_mutex); 385 386 /* 387 * Make sure this instance has been suspended. 388 */ 389 if (pci_p->pci_state != PCI_SUSPENDED) { 390 DEBUG0(DBG_ATTACH, dip, "instance NOT suspended\n"); 391 mutex_exit(&pci_p->pci_mutex); 392 return (DDI_FAILURE); 393 } 394 pci_obj_resume(pci_p); 395 pci_p->pci_state = PCI_ATTACHED; 396 397 pci_child_cfg_restore(dip); 398 399 mutex_exit(&pci_p->pci_mutex); 400 break; 401 402 default: 403 DEBUG0(DBG_ATTACH, dip, "unsupported attach op\n"); 404 return (DDI_FAILURE); 405 } 406 407 return (DDI_SUCCESS); 408 } 409 410 /* 411 * detach entry point: 412 */ 413 static int 414 pci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 415 { 416 int instance = ddi_get_instance(dip); 417 pci_t *pci_p = get_pci_soft_state(instance); 418 419 /* 420 * Make sure we are currently attached 421 */ 422 if (pci_p->pci_state != PCI_ATTACHED) { 423 DEBUG0(DBG_ATTACH, dip, "failed - instance not attached\n"); 424 return (DDI_FAILURE); 425 } 426 427 mutex_enter(&pci_p->pci_mutex); 428 429 switch (cmd) { 430 case DDI_DETACH: 431 DEBUG0(DBG_DETACH, dip, "DDI_DETACH\n"); 432 433 if (pci_p->hotplug_capable == B_TRUE) 434 if (pcihp_uninit(dip) == DDI_FAILURE) { 435 mutex_exit(&pci_p->pci_mutex); 436 return (DDI_FAILURE); 437 } 438 439 pcitool_uninit(dip); 440 441 pci_obj_destroy(pci_p); 442 443 /* 444 * Free the pci soft state structure and the rest of the 445 * resources it's using. 446 */ 447 free_pci_properties(pci_p); 448 unmap_pci_registers(pci_p); 449 mutex_exit(&pci_p->pci_mutex); 450 mutex_destroy(&pci_p->pci_mutex); 451 free_pci_soft_state(instance); 452 453 /* Free the interrupt-priorities prop if we created it. */ { 454 int len; 455 456 if (ddi_getproplen(DDI_DEV_T_ANY, dip, 457 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 458 "interrupt-priorities", &len) == DDI_PROP_SUCCESS) 459 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 460 "interrupt-priorities"); 461 } 462 return (DDI_SUCCESS); 463 464 case DDI_SUSPEND: 465 pci_child_cfg_save(dip); 466 pci_obj_suspend(pci_p); 467 pci_p->pci_state = PCI_SUSPENDED; 468 469 mutex_exit(&pci_p->pci_mutex); 470 return (DDI_SUCCESS); 471 472 default: 473 DEBUG0(DBG_DETACH, dip, "unsupported detach op\n"); 474 mutex_exit(&pci_p->pci_mutex); 475 return (DDI_FAILURE); 476 } 477 } 478 479 480 /* bus driver entry points */ 481 482 /* 483 * bus map entry point: 484 * 485 * if map request is for an rnumber 486 * get the corresponding regspec from device node 487 * build a new regspec in our parent's format 488 * build a new map_req with the new regspec 489 * call up the tree to complete the mapping 490 */ 491 int 492 pci_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 493 off_t off, off_t len, caddr_t *addrp) 494 { 495 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 496 struct regspec p_regspec; 497 ddi_map_req_t p_mapreq; 498 int reglen, rval, r_no; 499 pci_regspec_t reloc_reg, *rp = &reloc_reg; 500 501 DEBUG2(DBG_MAP, dip, "rdip=%s%d:", 502 ddi_driver_name(rdip), ddi_get_instance(rdip)); 503 504 if (mp->map_flags & DDI_MF_USER_MAPPING) 505 return (DDI_ME_UNIMPLEMENTED); 506 507 switch (mp->map_type) { 508 case DDI_MT_REGSPEC: 509 reloc_reg = *(pci_regspec_t *)mp->map_obj.rp; /* dup whole */ 510 break; 511 512 case DDI_MT_RNUMBER: 513 r_no = mp->map_obj.rnumber; 514 DEBUG1(DBG_MAP | DBG_CONT, dip, " r#=%x", r_no); 515 516 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 517 "reg", (caddr_t)&rp, ®len) != DDI_SUCCESS) 518 return (DDI_ME_RNUMBER_RANGE); 519 520 if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) { 521 kmem_free(rp, reglen); 522 return (DDI_ME_RNUMBER_RANGE); 523 } 524 rp += r_no; 525 break; 526 527 default: 528 return (DDI_ME_INVAL); 529 } 530 DEBUG0(DBG_MAP | DBG_CONT, dip, "\n"); 531 532 /* use "assigned-addresses" to relocate regspec within pci space */ 533 if (rval = pci_reloc_reg(dip, rdip, pci_p, rp)) 534 goto done; 535 536 if (len) /* adjust regspec according to mapping request */ 537 rp->pci_size_low = len; 538 rp->pci_phys_low += off; 539 540 /* use "ranges" to translate relocated pci regspec into parent space */ 541 if (rval = pci_xlate_reg(pci_p, rp, &p_regspec)) 542 goto done; 543 544 p_mapreq = *mp; /* dup the whole structure */ 545 p_mapreq.map_type = DDI_MT_REGSPEC; 546 p_mapreq.map_obj.rp = &p_regspec; 547 rval = ddi_map(dip, &p_mapreq, 0, 0, addrp); 548 549 if (rval == DDI_SUCCESS) { 550 /* 551 * Set-up access functions for FM access error capable drivers. 552 * The axq workaround prevents fault management support 553 */ 554 if (DDI_FM_ACC_ERR_CAP(pci_p->pci_fm_cap) && 555 DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) && 556 mp->map_handlep->ah_acc.devacc_attr_access != 557 DDI_DEFAULT_ACC) 558 pci_fm_acc_setup(mp, rdip); 559 pci_axq_setup(mp, pci_p->pci_pbm_p); 560 } 561 562 done: 563 if (mp->map_type == DDI_MT_RNUMBER) 564 kmem_free(rp - r_no, reglen); 565 566 return (rval); 567 } 568 569 /* 570 * bus dma map entry point 571 * return value: 572 * DDI_DMA_PARTIAL_MAP 1 573 * DDI_DMA_MAPOK 0 574 * DDI_DMA_MAPPED 0 575 * DDI_DMA_NORESOURCES -1 576 * DDI_DMA_NOMAPPING -2 577 * DDI_DMA_TOOBIG -3 578 */ 579 int 580 pci_dma_setup(dev_info_t *dip, dev_info_t *rdip, ddi_dma_req_t *dmareq, 581 ddi_dma_handle_t *handlep) 582 { 583 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 584 iommu_t *iommu_p = pci_p->pci_iommu_p; 585 ddi_dma_impl_t *mp; 586 int ret; 587 588 DEBUG3(DBG_DMA_MAP, dip, "mapping - rdip=%s%d type=%s\n", 589 ddi_driver_name(rdip), ddi_get_instance(rdip), 590 handlep ? "alloc" : "advisory"); 591 592 if (!(mp = pci_dma_lmts2hdl(dip, rdip, iommu_p, dmareq))) 593 return (DDI_DMA_NORESOURCES); 594 if (mp == (ddi_dma_impl_t *)DDI_DMA_NOMAPPING) 595 return (DDI_DMA_NOMAPPING); 596 if (ret = pci_dma_type(pci_p, dmareq, mp)) 597 goto freehandle; 598 if (ret = pci_dma_pfn(pci_p, dmareq, mp)) 599 goto freehandle; 600 601 switch (PCI_DMA_TYPE(mp)) { 602 case DMAI_FLAGS_DVMA: /* LINTED E_EQUALITY_NOT_ASSIGNMENT */ 603 if ((ret = pci_dvma_win(pci_p, dmareq, mp)) || !handlep) 604 goto freehandle; 605 if (!PCI_DMA_CANCACHE(mp)) { /* try fast track */ 606 if (PCI_DMA_CANFAST(mp)) { 607 if (!pci_dvma_map_fast(iommu_p, mp)) 608 break; 609 /* LINTED E_NOP_ELSE_STMT */ 610 } else { 611 PCI_DVMA_FASTTRAK_PROF(mp); 612 } 613 } 614 if (ret = pci_dvma_map(mp, dmareq, iommu_p)) 615 goto freehandle; 616 break; 617 case DMAI_FLAGS_PEER_TO_PEER: /* LINTED E_EQUALITY_NOT_ASSIGNMENT */ 618 if ((ret = pci_dma_physwin(pci_p, dmareq, mp)) || !handlep) 619 goto freehandle; 620 break; 621 case DMAI_FLAGS_BYPASS: 622 default: 623 panic("%s%d: pci_dma_setup: bad dma type 0x%x", 624 ddi_driver_name(rdip), ddi_get_instance(rdip), 625 PCI_DMA_TYPE(mp)); 626 /*NOTREACHED*/ 627 } 628 *handlep = (ddi_dma_handle_t)mp; 629 mp->dmai_flags |= (DMAI_FLAGS_INUSE | DMAI_FLAGS_MAPPED); 630 dump_dma_handle(DBG_DMA_MAP, dip, mp); 631 632 return ((mp->dmai_nwin == 1) ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP); 633 freehandle: 634 if (ret == DDI_DMA_NORESOURCES) 635 pci_dma_freemp(mp); /* don't run_callback() */ 636 else 637 (void) pci_dma_freehdl(dip, rdip, (ddi_dma_handle_t)mp); 638 return (ret); 639 } 640 641 642 /* 643 * bus dma alloc handle entry point: 644 */ 645 int 646 pci_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 647 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 648 { 649 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 650 ddi_dma_impl_t *mp; 651 int rval; 652 653 DEBUG2(DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", 654 ddi_driver_name(rdip), ddi_get_instance(rdip)); 655 656 if (attrp->dma_attr_version != DMA_ATTR_V0) 657 return (DDI_DMA_BADATTR); 658 659 if (!(mp = pci_dma_allocmp(dip, rdip, waitfp, arg))) 660 return (DDI_DMA_NORESOURCES); 661 662 /* 663 * Save requestor's information 664 */ 665 mp->dmai_attr = *attrp; /* whole object - augmented later */ 666 *DEV_ATTR(mp) = *attrp; /* whole object - device orig attr */ 667 DEBUG1(DBG_DMA_ALLOCH, dip, "mp=%p\n", mp); 668 669 /* check and convert dma attributes to handle parameters */ 670 if (rval = pci_dma_attr2hdl(pci_p, mp)) { 671 pci_dma_freehdl(dip, rdip, (ddi_dma_handle_t)mp); 672 *handlep = NULL; 673 return (rval); 674 } 675 *handlep = (ddi_dma_handle_t)mp; 676 return (DDI_SUCCESS); 677 } 678 679 680 /* 681 * bus dma free handle entry point: 682 */ 683 /*ARGSUSED*/ 684 int 685 pci_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 686 { 687 DEBUG3(DBG_DMA_FREEH, dip, "rdip=%s%d mp=%p\n", 688 ddi_driver_name(rdip), ddi_get_instance(rdip), handle); 689 pci_dma_freemp((ddi_dma_impl_t *)handle); 690 691 if (pci_kmem_clid) { 692 DEBUG0(DBG_DMA_FREEH, dip, "run handle callback\n"); 693 ddi_run_callback(&pci_kmem_clid); 694 } 695 return (DDI_SUCCESS); 696 } 697 698 699 /* 700 * bus dma bind handle entry point: 701 */ 702 int 703 pci_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 704 ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, 705 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 706 { 707 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 708 iommu_t *iommu_p = pci_p->pci_iommu_p; 709 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 710 int ret; 711 712 DEBUG4(DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n", 713 ddi_driver_name(rdip), ddi_get_instance(rdip), mp, dmareq); 714 715 if (mp->dmai_flags & DMAI_FLAGS_INUSE) 716 return (DDI_DMA_INUSE); 717 718 ASSERT((mp->dmai_flags & ~DMAI_FLAGS_PRESERVE) == 0); 719 mp->dmai_flags |= DMAI_FLAGS_INUSE; 720 721 if (ret = pci_dma_type(pci_p, dmareq, mp)) 722 goto err; 723 if (ret = pci_dma_pfn(pci_p, dmareq, mp)) 724 goto err; 725 726 switch (PCI_DMA_TYPE(mp)) { 727 case DMAI_FLAGS_DVMA: 728 if (ret = pci_dvma_win(pci_p, dmareq, mp)) 729 goto map_err; 730 if (!PCI_DMA_CANCACHE(mp)) { /* try fast track */ 731 if (PCI_DMA_CANFAST(mp)) { 732 if (!pci_dvma_map_fast(iommu_p, mp)) 733 goto mapped; /*LINTED E_NOP_ELSE_STMT*/ 734 } else { 735 PCI_DVMA_FASTTRAK_PROF(mp); 736 } 737 } 738 if (ret = pci_dvma_map(mp, dmareq, iommu_p)) 739 goto map_err; 740 mapped: 741 *ccountp = 1; 742 MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, mp->dmai_size); 743 break; 744 case DMAI_FLAGS_BYPASS: 745 case DMAI_FLAGS_PEER_TO_PEER: 746 if (ret = pci_dma_physwin(pci_p, dmareq, mp)) 747 goto map_err; 748 *ccountp = WINLST(mp)->win_ncookies; 749 *cookiep = *(ddi_dma_cookie_t *)(WINLST(mp) + 1); /* wholeobj */ 750 break; 751 default: 752 panic("%s%d: pci_dma_bindhdl(%p): bad dma type", 753 ddi_driver_name(rdip), ddi_get_instance(rdip), mp); 754 /*NOTREACHED*/ 755 } 756 DEBUG2(DBG_DMA_BINDH, dip, "cookie %x+%x\n", cookiep->dmac_address, 757 cookiep->dmac_size); 758 dump_dma_handle(DBG_DMA_MAP, dip, mp); 759 760 if (mp->dmai_attr.dma_attr_flags & DDI_DMA_FLAGERR) 761 (void) ndi_fmc_insert(rdip, DMA_HANDLE, mp, NULL); 762 763 mp->dmai_flags |= DMAI_FLAGS_MAPPED; 764 return (mp->dmai_nwin == 1 ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP); 765 map_err: 766 pci_dvma_unregister_callbacks(pci_p, mp); 767 pci_dma_freepfn(mp); 768 err: 769 mp->dmai_flags &= DMAI_FLAGS_PRESERVE; 770 return (ret); 771 } 772 773 /* 774 * bus dma unbind handle entry point: 775 */ 776 /*ARGSUSED*/ 777 int 778 pci_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 779 { 780 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 781 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 782 iommu_t *iommu_p = pci_p->pci_iommu_p; 783 784 DEBUG3(DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n", 785 ddi_driver_name(rdip), ddi_get_instance(rdip), handle); 786 if ((mp->dmai_flags & DMAI_FLAGS_INUSE) == 0) { 787 DEBUG0(DBG_DMA_UNBINDH, dip, "handle not in use\n"); 788 return (DDI_FAILURE); 789 } 790 791 mp->dmai_flags &= ~DMAI_FLAGS_MAPPED; 792 793 switch (PCI_DMA_TYPE(mp)) { 794 case DMAI_FLAGS_DVMA: 795 pci_dvma_unregister_callbacks(pci_p, mp); 796 pci_dma_sync_unmap(dip, rdip, mp); 797 pci_dvma_unmap(iommu_p, mp); 798 pci_dma_freepfn(mp); 799 break; 800 case DMAI_FLAGS_BYPASS: 801 case DMAI_FLAGS_PEER_TO_PEER: 802 pci_dma_freewin(mp); 803 break; 804 default: 805 panic("%s%d: pci_dma_unbindhdl:bad dma type %p", 806 ddi_driver_name(rdip), ddi_get_instance(rdip), mp); 807 /*NOTREACHED*/ 808 } 809 if (iommu_p->iommu_dvma_clid != 0) { 810 DEBUG0(DBG_DMA_UNBINDH, dip, "run dvma callback\n"); 811 ddi_run_callback(&iommu_p->iommu_dvma_clid); 812 } 813 if (pci_kmem_clid) { 814 DEBUG0(DBG_DMA_UNBINDH, dip, "run handle callback\n"); 815 ddi_run_callback(&pci_kmem_clid); 816 } 817 mp->dmai_flags &= DMAI_FLAGS_PRESERVE; 818 SYNC_BUF_PA(mp) = 0; 819 820 if (mp->dmai_attr.dma_attr_flags & DDI_DMA_FLAGERR) { 821 if (DEVI(rdip)->devi_fmhdl != NULL && 822 DDI_FM_DMA_ERR_CAP(DEVI(rdip)->devi_fmhdl->fh_cap)) { 823 (void) ndi_fmc_remove(rdip, DMA_HANDLE, mp); 824 } 825 } 826 827 return (DDI_SUCCESS); 828 } 829 830 831 /* 832 * bus dma win entry point: 833 */ 834 int 835 pci_dma_win(dev_info_t *dip, dev_info_t *rdip, 836 ddi_dma_handle_t handle, uint_t win, off_t *offp, 837 size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp) 838 { 839 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 840 DEBUG2(DBG_DMA_WIN, dip, "rdip=%s%d\n", 841 ddi_driver_name(rdip), ddi_get_instance(rdip)); 842 dump_dma_handle(DBG_DMA_WIN, dip, mp); 843 if (win >= mp->dmai_nwin) { 844 DEBUG1(DBG_DMA_WIN, dip, "%x out of range\n", win); 845 return (DDI_FAILURE); 846 } 847 848 switch (PCI_DMA_TYPE(mp)) { 849 case DMAI_FLAGS_DVMA: 850 if (win != PCI_DMA_CURWIN(mp)) { 851 pci_t *pci_p = 852 get_pci_soft_state(ddi_get_instance(dip)); 853 pci_dma_sync_unmap(dip, rdip, mp); 854 /* map_window sets dmai_mapping/size/offset */ 855 iommu_map_window(pci_p->pci_iommu_p, mp, win); 856 } 857 if (cookiep) 858 MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, 859 mp->dmai_size); 860 if (ccountp) 861 *ccountp = 1; 862 break; 863 case DMAI_FLAGS_PEER_TO_PEER: 864 case DMAI_FLAGS_BYPASS: { 865 int i; 866 ddi_dma_cookie_t *ck_p; 867 pci_dma_win_t *win_p = mp->dmai_winlst; 868 869 for (i = 0; i < win; win_p = win_p->win_next, i++); 870 ck_p = (ddi_dma_cookie_t *)(win_p + 1); 871 *cookiep = *ck_p; 872 mp->dmai_offset = win_p->win_offset; 873 mp->dmai_size = win_p->win_size; 874 mp->dmai_mapping = ck_p->dmac_laddress; 875 mp->dmai_cookie = ck_p + 1; 876 win_p->win_curseg = 0; 877 if (ccountp) 878 *ccountp = win_p->win_ncookies; 879 } 880 break; 881 default: 882 cmn_err(CE_WARN, "%s%d: pci_dma_win:bad dma type 0x%x", 883 ddi_driver_name(rdip), ddi_get_instance(rdip), 884 PCI_DMA_TYPE(mp)); 885 return (DDI_FAILURE); 886 } 887 if (cookiep) 888 DEBUG2(DBG_DMA_WIN, dip, 889 "cookie - dmac_address=%x dmac_size=%x\n", 890 cookiep->dmac_address, cookiep->dmac_size); 891 if (offp) 892 *offp = (off_t)mp->dmai_offset; 893 if (lenp) 894 *lenp = mp->dmai_size; 895 return (DDI_SUCCESS); 896 } 897 898 #ifdef DEBUG 899 static char *pci_dmactl_str[] = { 900 "DDI_DMA_FREE", 901 "DDI_DMA_SYNC", 902 "DDI_DMA_HTOC", 903 "DDI_DMA_KVADDR", 904 "DDI_DMA_MOVWIN", 905 "DDI_DMA_REPWIN", 906 "DDI_DMA_GETERR", 907 "DDI_DMA_COFF", 908 "DDI_DMA_NEXTWIN", 909 "DDI_DMA_NEXTSEG", 910 "DDI_DMA_SEGTOC", 911 "DDI_DMA_RESERVE", 912 "DDI_DMA_RELEASE", 913 "DDI_DMA_RESETH", 914 "DDI_DMA_CKSYNC", 915 "DDI_DMA_IOPB_ALLOC", 916 "DDI_DMA_IOPB_FREE", 917 "DDI_DMA_SMEM_ALLOC", 918 "DDI_DMA_SMEM_FREE", 919 "DDI_DMA_SET_SBUS64", 920 "DDI_DMA_REMAP" 921 }; 922 #endif 923 924 /* 925 * bus dma control entry point: 926 */ 927 int 928 pci_dma_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, 929 enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp, 930 uint_t cache_flags) 931 { 932 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 933 DEBUG3(DBG_DMA_CTL, dip, "%s: rdip=%s%d\n", pci_dmactl_str[cmd], 934 ddi_driver_name(rdip), ddi_get_instance(rdip)); 935 936 switch (cmd) { 937 case DDI_DMA_FREE: 938 (void) pci_dma_unbindhdl(dip, rdip, handle); 939 (void) pci_dma_freehdl(dip, rdip, handle); 940 return (DDI_SUCCESS); 941 case DDI_DMA_RESERVE: { 942 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 943 return (pci_fdvma_reserve(dip, rdip, pci_p, 944 (ddi_dma_req_t *)offp, (ddi_dma_handle_t *)objp)); 945 } 946 case DDI_DMA_RELEASE: { 947 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 948 return (pci_fdvma_release(dip, pci_p, mp)); 949 } 950 default: 951 break; 952 } 953 954 switch (PCI_DMA_TYPE(mp)) { 955 case DMAI_FLAGS_DVMA: 956 return (pci_dvma_ctl(dip, rdip, mp, cmd, offp, lenp, objp, 957 cache_flags)); 958 case DMAI_FLAGS_PEER_TO_PEER: 959 case DMAI_FLAGS_BYPASS: 960 return (pci_dma_ctl(dip, rdip, mp, cmd, offp, lenp, objp, 961 cache_flags)); 962 default: 963 panic("%s%d: pci_dma_ctlops(%x):bad dma type %x", 964 ddi_driver_name(rdip), ddi_get_instance(rdip), cmd, 965 mp->dmai_flags); 966 /*NOTREACHED*/ 967 } 968 } 969 970 #ifdef DEBUG 971 int pci_peekfault_cnt = 0; 972 int pci_pokefault_cnt = 0; 973 #endif /* DEBUG */ 974 975 static int 976 pci_do_poke(pci_t *pci_p, peekpoke_ctlops_t *in_args) 977 { 978 pbm_t *pbm_p = pci_p->pci_pbm_p; 979 int err = DDI_SUCCESS; 980 on_trap_data_t otd; 981 982 mutex_enter(&pbm_p->pbm_pokefault_mutex); 983 pbm_p->pbm_ontrap_data = &otd; 984 985 /* Set up protected environment. */ 986 if (!on_trap(&otd, OT_DATA_ACCESS)) { 987 uintptr_t tramp = otd.ot_trampoline; 988 989 otd.ot_trampoline = (uintptr_t)&poke_fault; 990 err = do_poke(in_args->size, (void *)in_args->dev_addr, 991 (void *)in_args->host_addr); 992 otd.ot_trampoline = tramp; 993 } else 994 err = DDI_FAILURE; 995 996 /* 997 * Read the async fault register for the PBM to see it sees 998 * a master-abort. 999 */ 1000 pbm_clear_error(pbm_p); 1001 1002 if (otd.ot_trap & OT_DATA_ACCESS) 1003 err = DDI_FAILURE; 1004 1005 /* Take down protected environment. */ 1006 no_trap(); 1007 1008 pbm_p->pbm_ontrap_data = NULL; 1009 mutex_exit(&pbm_p->pbm_pokefault_mutex); 1010 1011 #ifdef DEBUG 1012 if (err == DDI_FAILURE) 1013 pci_pokefault_cnt++; 1014 #endif 1015 return (err); 1016 } 1017 1018 1019 static int 1020 pci_do_caut_put(pci_t *pci_p, peekpoke_ctlops_t *cautacc_ctlops_arg) 1021 { 1022 size_t size = cautacc_ctlops_arg->size; 1023 uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 1024 uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 1025 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 1026 size_t repcount = cautacc_ctlops_arg->repcount; 1027 uint_t flags = cautacc_ctlops_arg->flags; 1028 1029 pbm_t *pbm_p = pci_p->pci_pbm_p; 1030 int err = DDI_SUCCESS; 1031 1032 /* Use ontrap data in handle set up by FMA */ 1033 pbm_p->pbm_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap; 1034 1035 hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 1036 1037 /* 1038 * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 1039 * mutex. 1040 */ 1041 i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 1042 1043 if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 1044 for (; repcount; repcount--) { 1045 switch (size) { 1046 1047 case sizeof (uint8_t): 1048 i_ddi_put8(hp, (uint8_t *)dev_addr, 1049 *(uint8_t *)host_addr); 1050 break; 1051 1052 case sizeof (uint16_t): 1053 i_ddi_put16(hp, (uint16_t *)dev_addr, 1054 *(uint16_t *)host_addr); 1055 break; 1056 1057 case sizeof (uint32_t): 1058 i_ddi_put32(hp, (uint32_t *)dev_addr, 1059 *(uint32_t *)host_addr); 1060 break; 1061 1062 case sizeof (uint64_t): 1063 i_ddi_put64(hp, (uint64_t *)dev_addr, 1064 *(uint64_t *)host_addr); 1065 break; 1066 } 1067 1068 host_addr += size; 1069 1070 if (flags == DDI_DEV_AUTOINCR) 1071 dev_addr += size; 1072 1073 /* 1074 * Read the async fault register for the PBM to see if 1075 * it sees a master-abort. 1076 */ 1077 pbm_clear_error(pbm_p); 1078 1079 if (pbm_p->pbm_ontrap_data->ot_trap & OT_DATA_ACCESS) { 1080 err = DDI_FAILURE; 1081 #ifdef DEBUG 1082 pci_pokefault_cnt++; 1083 #endif 1084 break; 1085 } 1086 } 1087 } 1088 1089 i_ddi_notrap((ddi_acc_handle_t)hp); 1090 pbm_p->pbm_ontrap_data = NULL; 1091 i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 1092 hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 1093 1094 return (err); 1095 } 1096 1097 1098 static int 1099 pci_ctlops_poke(pci_t *pci_p, peekpoke_ctlops_t *in_args) 1100 { 1101 return (in_args->handle ? pci_do_caut_put(pci_p, in_args) : 1102 pci_do_poke(pci_p, in_args)); 1103 } 1104 1105 1106 static int 1107 pci_do_peek(pci_t *pci_p, peekpoke_ctlops_t *in_args) 1108 { 1109 int err = DDI_SUCCESS; 1110 on_trap_data_t otd; 1111 1112 if (!on_trap(&otd, OT_DATA_ACCESS)) { 1113 uintptr_t tramp = otd.ot_trampoline; 1114 1115 otd.ot_trampoline = (uintptr_t)&peek_fault; 1116 err = do_peek(in_args->size, (void *)in_args->dev_addr, 1117 (void *)in_args->host_addr); 1118 otd.ot_trampoline = tramp; 1119 } else 1120 err = DDI_FAILURE; 1121 1122 no_trap(); 1123 1124 #ifdef DEBUG 1125 if (err == DDI_FAILURE) 1126 pci_peekfault_cnt++; 1127 #endif 1128 return (err); 1129 } 1130 1131 static int 1132 pci_do_caut_get(pci_t *pci_p, peekpoke_ctlops_t *cautacc_ctlops_arg) 1133 { 1134 size_t size = cautacc_ctlops_arg->size; 1135 uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 1136 uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 1137 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 1138 size_t repcount = cautacc_ctlops_arg->repcount; 1139 uint_t flags = cautacc_ctlops_arg->flags; 1140 1141 pbm_t *pbm_p = pci_p->pci_pbm_p; 1142 int err = DDI_SUCCESS; 1143 1144 hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 1145 i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 1146 1147 /* Can this code be optimized? */ 1148 1149 if (repcount == 1) { 1150 if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 1151 i_ddi_caut_get(size, (void *)dev_addr, 1152 (void *)host_addr); 1153 } else { 1154 int i; 1155 uint8_t *ff_addr = (uint8_t *)host_addr; 1156 for (i = 0; i < size; i++) 1157 *ff_addr++ = 0xff; 1158 1159 err = DDI_FAILURE; 1160 #ifdef DEBUG 1161 pci_peekfault_cnt++; 1162 #endif 1163 } 1164 } else { 1165 if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 1166 for (; repcount; repcount--) { 1167 i_ddi_caut_get(size, (void *)dev_addr, 1168 (void *)host_addr); 1169 1170 host_addr += size; 1171 1172 if (flags == DDI_DEV_AUTOINCR) 1173 dev_addr += size; 1174 } 1175 } else { 1176 err = DDI_FAILURE; 1177 #ifdef DEBUG 1178 pci_peekfault_cnt++; 1179 #endif 1180 } 1181 } 1182 1183 i_ddi_notrap((ddi_acc_handle_t)hp); 1184 pbm_p->pbm_ontrap_data = NULL; 1185 i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 1186 hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 1187 1188 return (err); 1189 } 1190 1191 1192 static int 1193 pci_ctlops_peek(pci_t *pci_p, peekpoke_ctlops_t *in_args, void *result) 1194 { 1195 result = (void *)in_args->host_addr; 1196 return (in_args->handle ? pci_do_caut_get(pci_p, in_args) : 1197 pci_do_peek(pci_p, in_args)); 1198 } 1199 1200 /* 1201 * get_reg_set_size 1202 * 1203 * Given a dev info pointer to a pci child and a register number, this 1204 * routine returns the size element of that reg set property. 1205 * return value: size of reg set on success, -1 on error 1206 */ 1207 static off_t 1208 get_reg_set_size(dev_info_t *child, int rnumber) 1209 { 1210 pci_regspec_t *pci_rp; 1211 off_t size; 1212 int i; 1213 1214 if (rnumber < 0) 1215 return (-1); 1216 1217 /* 1218 * Get the reg property for the device. 1219 */ 1220 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 1221 (caddr_t)&pci_rp, &i) != DDI_SUCCESS) 1222 return (-1); 1223 1224 if (rnumber >= (i / (int)sizeof (pci_regspec_t))) { 1225 kmem_free(pci_rp, i); 1226 return (-1); 1227 } 1228 1229 size = pci_rp[rnumber].pci_size_low | 1230 ((uint64_t)pci_rp[rnumber].pci_size_hi << 32); 1231 kmem_free(pci_rp, i); 1232 return (size); 1233 } 1234 1235 1236 /* 1237 * control ops entry point: 1238 * 1239 * Requests handled completely: 1240 * DDI_CTLOPS_INITCHILD see init_child() for details 1241 * DDI_CTLOPS_UNINITCHILD 1242 * DDI_CTLOPS_REPORTDEV see report_dev() for details 1243 * DDI_CTLOPS_IOMIN cache line size if streaming otherwise 1 1244 * DDI_CTLOPS_REGSIZE 1245 * DDI_CTLOPS_NREGS 1246 * DDI_CTLOPS_DVMAPAGESIZE 1247 * DDI_CTLOPS_POKE 1248 * DDI_CTLOPS_PEEK 1249 * DDI_CTLOPS_QUIESCE 1250 * DDI_CTLOPS_UNQUIESCE 1251 * 1252 * All others passed to parent. 1253 */ 1254 int 1255 pci_ctlops(dev_info_t *dip, dev_info_t *rdip, 1256 ddi_ctl_enum_t op, void *arg, void *result) 1257 { 1258 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 1259 1260 switch (op) { 1261 case DDI_CTLOPS_INITCHILD: 1262 return (init_child(pci_p, (dev_info_t *)arg)); 1263 1264 case DDI_CTLOPS_UNINITCHILD: 1265 return (uninit_child(pci_p, (dev_info_t *)arg)); 1266 1267 case DDI_CTLOPS_REPORTDEV: 1268 return (report_dev(rdip)); 1269 1270 case DDI_CTLOPS_IOMIN: 1271 1272 /* 1273 * If we are using the streaming cache, align at 1274 * least on a cache line boundary. Otherwise use 1275 * whatever alignment is passed in. 1276 */ 1277 1278 if ((int)arg) { 1279 int val = *((int *)result); 1280 1281 val = maxbit(val, PCI_SBUF_LINE_SIZE); 1282 *((int *)result) = val; 1283 } 1284 return (DDI_SUCCESS); 1285 1286 case DDI_CTLOPS_REGSIZE: 1287 *((off_t *)result) = get_reg_set_size(rdip, *((int *)arg)); 1288 return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS); 1289 1290 case DDI_CTLOPS_NREGS: 1291 *((uint_t *)result) = get_nreg_set(rdip); 1292 return (DDI_SUCCESS); 1293 1294 case DDI_CTLOPS_DVMAPAGESIZE: 1295 *((ulong_t *)result) = IOMMU_PAGE_SIZE; 1296 return (DDI_SUCCESS); 1297 1298 case DDI_CTLOPS_POKE: 1299 return (pci_ctlops_poke(pci_p, (peekpoke_ctlops_t *)arg)); 1300 1301 case DDI_CTLOPS_PEEK: 1302 return (pci_ctlops_peek(pci_p, (peekpoke_ctlops_t *)arg, 1303 result)); 1304 1305 case DDI_CTLOPS_AFFINITY: 1306 break; 1307 1308 case DDI_CTLOPS_QUIESCE: 1309 return (pci_bus_quiesce(pci_p, rdip, result)); 1310 1311 case DDI_CTLOPS_UNQUIESCE: 1312 return (pci_bus_unquiesce(pci_p, rdip, result)); 1313 1314 default: 1315 break; 1316 } 1317 1318 /* 1319 * Now pass the request up to our parent. 1320 */ 1321 DEBUG2(DBG_CTLOPS, dip, "passing request to parent: rdip=%s%d\n", 1322 ddi_driver_name(rdip), ddi_get_instance(rdip)); 1323 return (ddi_ctlops(dip, rdip, op, arg, result)); 1324 } 1325 1326 1327 /* ARGSUSED */ 1328 int 1329 pci_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 1330 ddi_intr_handle_impl_t *hdlp, void *result) 1331 { 1332 pci_t *pci_p = get_pci_soft_state( 1333 ddi_get_instance(dip)); 1334 int ret = DDI_SUCCESS; 1335 1336 switch (intr_op) { 1337 case DDI_INTROP_GETCAP: 1338 /* GetCap will always fail for all non PCI devices */ 1339 (void) pci_intx_get_cap(rdip, (int *)result); 1340 break; 1341 case DDI_INTROP_SETCAP: 1342 ret = DDI_ENOTSUP; 1343 break; 1344 case DDI_INTROP_ALLOC: 1345 *(int *)result = hdlp->ih_scratch1; 1346 break; 1347 case DDI_INTROP_FREE: 1348 break; 1349 case DDI_INTROP_GETPRI: 1350 *(int *)result = hdlp->ih_pri ? 1351 hdlp->ih_pri : pci_class_to_pil(rdip); 1352 break; 1353 case DDI_INTROP_SETPRI: 1354 break; 1355 case DDI_INTROP_ADDISR: 1356 ret = pci_add_intr(dip, rdip, hdlp); 1357 break; 1358 case DDI_INTROP_REMISR: 1359 ret = pci_remove_intr(dip, rdip, hdlp); 1360 break; 1361 case DDI_INTROP_ENABLE: 1362 ret = ib_update_intr_state(pci_p, rdip, hdlp, 1363 PCI_INTR_STATE_ENABLE); 1364 break; 1365 case DDI_INTROP_DISABLE: 1366 ret = ib_update_intr_state(pci_p, rdip, hdlp, 1367 PCI_INTR_STATE_DISABLE); 1368 break; 1369 case DDI_INTROP_SETMASK: 1370 ret = pci_intx_set_mask(rdip); 1371 break; 1372 case DDI_INTROP_CLRMASK: 1373 ret = pci_intx_clr_mask(rdip); 1374 break; 1375 case DDI_INTROP_GETPENDING: 1376 ret = pci_intx_get_pending(rdip, (int *)result); 1377 break; 1378 case DDI_INTROP_NINTRS: 1379 case DDI_INTROP_NAVAIL: 1380 *(int *)result = i_ddi_get_nintrs(rdip); 1381 break; 1382 case DDI_INTROP_SUPPORTED_TYPES: 1383 /* PCI nexus driver supports only fixed interrupts */ 1384 *(int *)result = i_ddi_get_nintrs(rdip) ? 1385 DDI_INTR_TYPE_FIXED : 0; 1386 break; 1387 default: 1388 ret = DDI_ENOTSUP; 1389 break; 1390 } 1391 1392 return (ret); 1393 } 1394 1395 static void 1396 pci_init_hotplug(struct pci *pci_p) 1397 { 1398 pci_bus_range_t bus_range; 1399 dev_info_t *dip; 1400 1401 /* 1402 * Before initializing hotplug - open up 1403 * bus range. The busra module will 1404 * initialize its pool of bus numbers from 1405 * this. "busra" will be the agent that keeps 1406 * track of them during hotplug. Also, note, 1407 * that busra will remove any bus numbers 1408 * already in use from boot time. 1409 */ 1410 bus_range.lo = 0x0; 1411 bus_range.hi = 0xff; 1412 dip = pci_p->pci_dip; 1413 pci_p->hotplug_capable = B_FALSE; 1414 1415 /* 1416 * If this property exists, this nexus has hot-plug 1417 * slots. 1418 */ 1419 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1420 "hotplug-capable")) { 1421 if (ndi_prop_update_int_array(DDI_DEV_T_NONE, 1422 dip, "bus-range", 1423 (int *)&bus_range, 1424 2) != DDI_PROP_SUCCESS) { 1425 return; 1426 } 1427 1428 if (pcihp_init(dip) != DDI_SUCCESS) { 1429 return; 1430 } 1431 1432 if ((pcihp_ops = pcihp_get_cb_ops()) != NULL) { 1433 DEBUG2(DBG_ATTACH, dip, "%s%d hotplug enabled", 1434 ddi_driver_name(dip), ddi_get_instance(dip)); 1435 pci_p->hotplug_capable = B_TRUE; 1436 } 1437 } 1438 } 1439