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 * PCI to PCI bus bridge nexus driver 30 */ 31 32 #include <sys/conf.h> 33 #include <sys/kmem.h> 34 #include <sys/debug.h> 35 #include <sys/modctl.h> 36 #include <sys/autoconf.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/pci.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/sunndi.h> 42 #include <sys/ddifm.h> 43 #include <sys/ndifm.h> 44 #include <sys/fm/protocol.h> 45 #include <sys/hotplug/pci/pcihp.h> 46 #include <sys/pci_intr_lib.h> 47 #include <sys/psm.h> 48 49 /* 50 * The variable controls the default setting of the command register 51 * for pci devices. See ppb_initchild() for details. 52 */ 53 static ushort_t ppb_command_default = PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO; 54 55 56 static int ppb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 57 off_t, off_t, caddr_t *); 58 static int ppb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 59 void *, void *); 60 static int ppb_fm_init(dev_info_t *, dev_info_t *, int, 61 ddi_iblock_cookie_t *); 62 static int ppb_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *); 63 static int ppb_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 64 ddi_intr_handle_impl_t *, void *); 65 66 /* 67 * ppb_support_msi: Flag that controls MSI support across P2P Bridges. 68 * By default, MSI is not supported except for special cases like HT 69 * bridges/tunnels that have HT MSI mapping enabled. 70 * 71 * However, MSI support behavior can be patched on a system by changing 72 * the value of this flag as shown below:- 73 * 0 = default value, MSI is allowed by this driver for special cases 74 * 1 = MSI supported without any checks for this driver 75 * -1 = MSI not supported at all 76 */ 77 int ppb_support_msi = 0; 78 79 /* 80 * Controls the usage of the Hypertransport MSI mapping capability 81 * 0 = default value, leave hardware function as it is 82 * 1 = always enable HT MSI mapping 83 * -1 = always disable HT MSI mapping 84 */ 85 int ppb_support_ht_msimap = 0; 86 87 /* 88 * masks and values for the upper 16-bits of hypertransport cap headers 89 */ 90 #define PCI_CAP_HT_MSIMAP_TYPE 0xA800 91 #define PCI_CAP_HT_MSIMAP_TYPE_MASK 0xFF00 92 #define PCI_CAP_HT_MSIMAP_ENABLE 0x0001 93 #define PCI_CAP_HT_MSIMAP_ENABLE_MASK 0x0001 94 95 96 struct bus_ops ppb_bus_ops = { 97 BUSO_REV, 98 ppb_bus_map, 99 0, 100 0, 101 0, 102 i_ddi_map_fault, 103 ddi_dma_map, 104 ddi_dma_allochdl, 105 ddi_dma_freehdl, 106 ddi_dma_bindhdl, 107 ddi_dma_unbindhdl, 108 ddi_dma_flush, 109 ddi_dma_win, 110 ddi_dma_mctl, 111 ppb_ctlops, 112 ddi_bus_prop_op, 113 0, /* (*bus_get_eventcookie)(); */ 114 0, /* (*bus_add_eventcall)(); */ 115 0, /* (*bus_remove_eventcall)(); */ 116 0, /* (*bus_post_event)(); */ 117 0, /* (*bus_intr_ctl)(); */ 118 0, /* (*bus_config)(); */ 119 0, /* (*bus_unconfig)(); */ 120 ppb_fm_init, /* (*bus_fm_init)(); */ 121 NULL, /* (*bus_fm_fini)(); */ 122 NULL, /* (*bus_fm_access_enter)(); */ 123 NULL, /* (*bus_fm_access_exit)(); */ 124 NULL, /* (*bus_power)(); */ 125 ppb_intr_ops /* (*bus_intr_op)(); */ 126 }; 127 128 /* 129 * The goal here is to leverage off of the pcihp.c source without making 130 * changes to it. Call into it's cb_ops directly if needed. 131 */ 132 static int ppb_open(dev_t *, int, int, cred_t *); 133 static int ppb_close(dev_t, int, int, cred_t *); 134 static int ppb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 135 static int ppb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 136 caddr_t, int *); 137 static int ppb_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 138 139 struct cb_ops ppb_cb_ops = { 140 ppb_open, /* open */ 141 ppb_close, /* close */ 142 nodev, /* strategy */ 143 nodev, /* print */ 144 nodev, /* dump */ 145 nodev, /* read */ 146 nodev, /* write */ 147 ppb_ioctl, /* ioctl */ 148 nodev, /* devmap */ 149 nodev, /* mmap */ 150 nodev, /* segmap */ 151 nochpoll, /* poll */ 152 ppb_prop_op, /* cb_prop_op */ 153 NULL, /* streamtab */ 154 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 155 CB_REV, /* rev */ 156 nodev, /* int (*cb_aread)() */ 157 nodev /* int (*cb_awrite)() */ 158 }; 159 160 161 static int ppb_probe(dev_info_t *); 162 static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 163 static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 164 165 struct dev_ops ppb_ops = { 166 DEVO_REV, /* devo_rev */ 167 0, /* refcnt */ 168 ppb_info, /* info */ 169 nulldev, /* identify */ 170 ppb_probe, /* probe */ 171 ppb_attach, /* attach */ 172 ppb_detach, /* detach */ 173 nulldev, /* reset */ 174 &ppb_cb_ops, /* driver operations */ 175 &ppb_bus_ops /* bus operations */ 176 }; 177 178 /* 179 * Module linkage information for the kernel. 180 */ 181 182 static struct modldrv modldrv = { 183 &mod_driverops, /* Type of module */ 184 "PCI to PCI bridge nexus driver %I%", 185 &ppb_ops, /* driver ops */ 186 }; 187 188 static struct modlinkage modlinkage = { 189 MODREV_1, 190 (void *)&modldrv, 191 NULL 192 }; 193 194 /* 195 * soft state pointer and structure template: 196 */ 197 static void *ppb_state; 198 199 typedef struct { 200 dev_info_t *dip; 201 int ppb_fmcap; 202 ddi_iblock_cookie_t ppb_fm_ibc; 203 kmutex_t ppb_peek_poke_mutex; 204 kmutex_t ppb_err_mutex; 205 206 /* 207 * cpr support: 208 */ 209 uint_t config_state_index; 210 struct { 211 dev_info_t *dip; 212 ushort_t command; 213 uchar_t cache_line_size; 214 uchar_t latency_timer; 215 uchar_t header_type; 216 uchar_t sec_latency_timer; 217 ushort_t bridge_control; 218 } config_state[PCI_MAX_CHILDREN]; 219 } ppb_devstate_t; 220 221 222 /* 223 * forward function declarations: 224 */ 225 static void ppb_removechild(dev_info_t *); 226 static int ppb_initchild(dev_info_t *child); 227 static void ppb_save_config_regs(ppb_devstate_t *ppb_p); 228 static void ppb_restore_config_regs(ppb_devstate_t *ppb_p); 229 static uint8_t ppb_find_ht_cap(ddi_acc_handle_t cfg_hdl, uint16_t reg_mask, 230 uint16_t reg_val); 231 static boolean_t ppb_ht_msimap_check(ddi_acc_handle_t cfg_hdl); 232 static int ppb_ht_msimap_set(ddi_acc_handle_t cfg_hdl, int cmd); 233 234 /* 235 * for <cmd> in ppb_ht_msimap_set 236 */ 237 #define HT_MSIMAP_ENABLE 1 238 #define HT_MSIMAP_DISABLE 0 239 240 241 int 242 _init(void) 243 { 244 int e; 245 246 if ((e = ddi_soft_state_init(&ppb_state, sizeof (ppb_devstate_t), 247 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 248 ddi_soft_state_fini(&ppb_state); 249 return (e); 250 } 251 252 int 253 _fini(void) 254 { 255 int e; 256 257 if ((e = mod_remove(&modlinkage)) == 0) 258 ddi_soft_state_fini(&ppb_state); 259 return (e); 260 } 261 262 int 263 _info(struct modinfo *modinfop) 264 { 265 return (mod_info(&modlinkage, modinfop)); 266 } 267 268 /*ARGSUSED*/ 269 static int 270 ppb_probe(dev_info_t *devi) 271 { 272 return (DDI_PROBE_SUCCESS); 273 } 274 275 /*ARGSUSED*/ 276 static int 277 ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 278 { 279 int instance; 280 ppb_devstate_t *ppb; 281 ddi_acc_handle_t config_handle; 282 283 switch (cmd) { 284 case DDI_ATTACH: 285 286 /* 287 * Make sure the "device_type" property exists. 288 */ 289 (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 290 "device_type", "pci"); 291 292 /* 293 * Allocate and get soft state structure. 294 */ 295 instance = ddi_get_instance(devi); 296 if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS) 297 return (DDI_FAILURE); 298 ppb = ddi_get_soft_state(ppb_state, instance); 299 ppb->dip = devi; 300 301 /* 302 * don't enable ereports if immediate child of npe 303 */ 304 if (strcmp(ddi_driver_name(ddi_get_parent(devi)), "npe") == 0) 305 ppb->ppb_fmcap = DDI_FM_ERRCB_CAPABLE | 306 DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; 307 else 308 ppb->ppb_fmcap = DDI_FM_EREPORT_CAPABLE | 309 DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 310 DDI_FM_DMACHK_CAPABLE; 311 312 ddi_fm_init(devi, &ppb->ppb_fmcap, &ppb->ppb_fm_ibc); 313 mutex_init(&ppb->ppb_err_mutex, NULL, MUTEX_DRIVER, 314 (void *)ppb->ppb_fm_ibc); 315 mutex_init(&ppb->ppb_peek_poke_mutex, NULL, MUTEX_DRIVER, 316 (void *)ppb->ppb_fm_ibc); 317 318 if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE | 319 DDI_FM_EREPORT_CAPABLE)) 320 pci_ereport_setup(devi); 321 if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE) 322 ddi_fm_handler_register(devi, ppb_fm_callback, NULL); 323 324 if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) { 325 if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE) 326 ddi_fm_handler_unregister(devi); 327 if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE | 328 DDI_FM_EREPORT_CAPABLE)) 329 pci_ereport_teardown(devi); 330 ddi_fm_fini(devi); 331 ddi_soft_state_free(ppb_state, instance); 332 return (DDI_FAILURE); 333 } 334 335 if (ppb_support_ht_msimap == 1) 336 (void) ppb_ht_msimap_set(config_handle, 337 HT_MSIMAP_ENABLE); 338 else if (ppb_support_ht_msimap == -1) 339 (void) ppb_ht_msimap_set(config_handle, 340 HT_MSIMAP_DISABLE); 341 342 pci_config_teardown(&config_handle); 343 344 /* 345 * Initialize hotplug support on this bus. At minimum 346 * (for non hotplug bus) this would create ":devctl" minor 347 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 348 * to this bus. 349 */ 350 if (pcihp_init(devi) != DDI_SUCCESS) 351 cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); 352 353 ddi_report_dev(devi); 354 return (DDI_SUCCESS); 355 356 case DDI_RESUME: 357 358 /* 359 * Get the soft state structure for the bridge. 360 */ 361 ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); 362 ppb_restore_config_regs(ppb); 363 return (DDI_SUCCESS); 364 365 default: 366 break; 367 } 368 return (DDI_FAILURE); 369 } 370 371 /*ARGSUSED*/ 372 static int 373 ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 374 { 375 ppb_devstate_t *ppb; 376 377 switch (cmd) { 378 case DDI_DETACH: 379 (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); 380 381 ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); 382 if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE) 383 ddi_fm_handler_unregister(devi); 384 if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE | 385 DDI_FM_EREPORT_CAPABLE)) 386 pci_ereport_teardown(devi); 387 mutex_destroy(&ppb->ppb_peek_poke_mutex); 388 mutex_destroy(&ppb->ppb_err_mutex); 389 ddi_fm_fini(devi); 390 391 /* 392 * And finally free the per-pci soft state. 393 */ 394 ddi_soft_state_free(ppb_state, ddi_get_instance(devi)); 395 396 /* 397 * Uninitialize hotplug support on this bus. 398 */ 399 (void) pcihp_uninit(devi); 400 return (DDI_SUCCESS); 401 402 case DDI_SUSPEND: 403 ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); 404 ppb_save_config_regs(ppb); 405 return (DDI_SUCCESS); 406 407 default: 408 break; 409 } 410 return (DDI_FAILURE); 411 } 412 413 /*ARGSUSED*/ 414 static int 415 ppb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 416 off_t offset, off_t len, caddr_t *vaddrp) 417 { 418 dev_info_t *pdip; 419 420 pdip = (dev_info_t *)DEVI(dip)->devi_parent; 421 return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip, 422 rdip, mp, offset, len, vaddrp)); 423 } 424 425 /*ARGSUSED*/ 426 static int 427 ppb_ctlops(dev_info_t *dip, dev_info_t *rdip, 428 ddi_ctl_enum_t ctlop, void *arg, void *result) 429 { 430 pci_regspec_t *drv_regp; 431 int reglen; 432 int rn; 433 int totreg; 434 ppb_devstate_t *ppb; 435 436 switch (ctlop) { 437 case DDI_CTLOPS_REPORTDEV: 438 if (rdip == (dev_info_t *)0) 439 return (DDI_FAILURE); 440 cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 441 ddi_node_name(rdip), ddi_get_name_addr(rdip), 442 ddi_driver_name(rdip), 443 ddi_get_instance(rdip)); 444 return (DDI_SUCCESS); 445 446 case DDI_CTLOPS_INITCHILD: 447 return (ppb_initchild((dev_info_t *)arg)); 448 449 case DDI_CTLOPS_UNINITCHILD: 450 ppb_removechild((dev_info_t *)arg); 451 return (DDI_SUCCESS); 452 453 case DDI_CTLOPS_SIDDEV: 454 return (DDI_SUCCESS); 455 456 case DDI_CTLOPS_REGSIZE: 457 case DDI_CTLOPS_NREGS: 458 if (rdip == (dev_info_t *)0) 459 return (DDI_FAILURE); 460 break; 461 462 case DDI_CTLOPS_PEEK: 463 case DDI_CTLOPS_POKE: 464 ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(dip)); 465 if (strcmp(ddi_driver_name(ddi_get_parent(dip)), "npe") != 0) 466 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 467 return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, 468 ddi_ctlops, &ppb->ppb_err_mutex, 469 &ppb->ppb_peek_poke_mutex)); 470 471 default: 472 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 473 } 474 475 *(int *)result = 0; 476 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, 477 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", 478 (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 479 return (DDI_FAILURE); 480 481 totreg = reglen / sizeof (pci_regspec_t); 482 if (ctlop == DDI_CTLOPS_NREGS) 483 *(int *)result = totreg; 484 else if (ctlop == DDI_CTLOPS_REGSIZE) { 485 rn = *(int *)arg; 486 if (rn >= totreg) { 487 kmem_free(drv_regp, reglen); 488 return (DDI_FAILURE); 489 } 490 *(off_t *)result = drv_regp[rn].pci_size_low; 491 } 492 493 kmem_free(drv_regp, reglen); 494 return (DDI_SUCCESS); 495 } 496 497 static int 498 ppb_name_child(dev_info_t *child, char *name, int namelen) 499 { 500 pci_regspec_t *pci_rp; 501 uint_t slot, func; 502 char **unit_addr; 503 uint_t n; 504 505 /* 506 * For .conf nodes, use unit-address property as name 507 */ 508 if (ndi_dev_is_persistent_node(child) == 0) { 509 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 510 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 511 DDI_PROP_SUCCESS) { 512 cmn_err(CE_WARN, 513 "cannot find unit-address in %s.conf", 514 ddi_driver_name(child)); 515 return (DDI_FAILURE); 516 } 517 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 518 cmn_err(CE_WARN, "unit-address property in %s.conf" 519 " not well-formed", ddi_driver_name(child)); 520 ddi_prop_free(unit_addr); 521 return (DDI_SUCCESS); 522 } 523 (void) snprintf(name, namelen, "%s", *unit_addr); 524 ddi_prop_free(unit_addr); 525 return (DDI_SUCCESS); 526 } 527 528 /* get child "reg" property */ 529 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 530 DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) { 531 return (DDI_FAILURE); 532 } 533 534 /* copy the device identifications */ 535 slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 536 func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 537 538 if (func != 0) 539 (void) snprintf(name, namelen, "%x,%x", slot, func); 540 else 541 (void) snprintf(name, namelen, "%x", slot); 542 543 ddi_prop_free(pci_rp); 544 return (DDI_SUCCESS); 545 } 546 547 static int 548 ppb_initchild(dev_info_t *child) 549 { 550 struct ddi_parent_private_data *pdptr; 551 char name[MAXNAMELEN]; 552 ddi_acc_handle_t config_handle; 553 ushort_t command_preserve, command; 554 555 if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 556 return (DDI_FAILURE); 557 ddi_set_name_addr(child, name); 558 559 /* 560 * Pseudo nodes indicate a prototype node with per-instance 561 * properties to be merged into the real h/w device node. 562 * The interpretation of the unit-address is DD[,F] 563 * where DD is the device id and F is the function. 564 */ 565 if (ndi_dev_is_persistent_node(child) == 0) { 566 extern int pci_allow_pseudo_children; 567 568 ddi_set_parent_data(child, NULL); 569 570 /* 571 * Try to merge the properties from this prototype 572 * node into real h/w nodes. 573 */ 574 if (ndi_merge_node(child, ppb_name_child) == DDI_SUCCESS) { 575 /* 576 * Merged ok - return failure to remove the node. 577 */ 578 ddi_set_name_addr(child, NULL); 579 return (DDI_FAILURE); 580 } 581 582 /* workaround for ddivs to run under PCI */ 583 if (pci_allow_pseudo_children) 584 return (DDI_SUCCESS); 585 586 /* 587 * The child was not merged into a h/w node, 588 * but there's not much we can do with it other 589 * than return failure to cause the node to be removed. 590 */ 591 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 592 ddi_driver_name(child), ddi_get_name_addr(child), 593 ddi_driver_name(child)); 594 ddi_set_name_addr(child, NULL); 595 return (DDI_NOT_WELL_FORMED); 596 } 597 598 /* transfer select properties from PROM to kernel */ 599 if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "interrupts", 600 -1) != -1) { 601 pdptr = kmem_zalloc((sizeof (struct ddi_parent_private_data) + 602 sizeof (struct intrspec)), KM_SLEEP); 603 pdptr->par_intr = (struct intrspec *)(pdptr + 1); 604 pdptr->par_nintr = 1; 605 ddi_set_parent_data(child, pdptr); 606 } else 607 ddi_set_parent_data(child, NULL); 608 609 if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) 610 return (DDI_FAILURE); 611 612 /* 613 * Support for the "command-preserve" property. 614 */ 615 command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, 616 DDI_PROP_DONTPASS, "command-preserve", 0); 617 command = pci_config_get16(config_handle, PCI_CONF_COMM); 618 command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 619 command |= (ppb_command_default & ~command_preserve); 620 pci_config_put16(config_handle, PCI_CONF_COMM, command); 621 622 pci_config_teardown(&config_handle); 623 return (DDI_SUCCESS); 624 } 625 626 static void 627 ppb_removechild(dev_info_t *dip) 628 { 629 struct ddi_parent_private_data *pdptr; 630 631 if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 632 kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); 633 ddi_set_parent_data(dip, NULL); 634 } 635 ddi_set_name_addr(dip, NULL); 636 637 /* 638 * Strip the node to properly convert it back to prototype form 639 */ 640 ddi_remove_minor_node(dip, NULL); 641 642 impl_rem_dev_props(dip); 643 } 644 645 /* 646 * ppb_save_config_regs 647 * 648 * This routine saves the state of the configuration registers of all 649 * the child nodes of each PBM. 650 * 651 * used by: ppb_detach() on suspends 652 * 653 * return value: none 654 */ 655 static void 656 ppb_save_config_regs(ppb_devstate_t *ppb_p) 657 { 658 int i; 659 dev_info_t *dip; 660 ddi_acc_handle_t config_handle; 661 662 for (i = 0, dip = ddi_get_child(ppb_p->dip); dip != NULL; 663 i++, dip = ddi_get_next_sibling(dip)) { 664 665 if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) { 666 cmn_err(CE_WARN, "%s%d: can't config space for %s%d\n", 667 ddi_driver_name(ppb_p->dip), 668 ddi_get_instance(ppb_p->dip), 669 ddi_driver_name(dip), 670 ddi_get_instance(dip)); 671 continue; 672 } 673 674 ppb_p->config_state[i].dip = dip; 675 ppb_p->config_state[i].command = 676 pci_config_get16(config_handle, PCI_CONF_COMM); 677 pci_config_teardown(&config_handle); 678 } 679 ppb_p->config_state_index = i; 680 } 681 682 683 /* 684 * ppb_restore_config_regs 685 * 686 * This routine restores the state of the configuration registers of all 687 * the child nodes of each PBM. 688 * 689 * used by: ppb_attach() on resume 690 * 691 * return value: none 692 */ 693 static void 694 ppb_restore_config_regs(ppb_devstate_t *ppb_p) 695 { 696 int i; 697 dev_info_t *dip; 698 ddi_acc_handle_t config_handle; 699 700 for (i = 0; i < ppb_p->config_state_index; i++) { 701 dip = ppb_p->config_state[i].dip; 702 if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) { 703 cmn_err(CE_WARN, "%s%d: can't config space for %s%d\n", 704 ddi_driver_name(ppb_p->dip), 705 ddi_get_instance(ppb_p->dip), 706 ddi_driver_name(dip), 707 ddi_get_instance(dip)); 708 continue; 709 } 710 pci_config_put16(config_handle, PCI_CONF_COMM, 711 ppb_p->config_state[i].command); 712 pci_config_teardown(&config_handle); 713 } 714 } 715 716 717 /* 718 * returns the location of a hypertransport capability whose upper 16-bit 719 * register of the cap header matches <reg_val> after masking the register 720 * with <reg_mask>; if both <reg_mask> and <reg_val> are 0, it will return the 721 * first HT cap found 722 */ 723 static uint8_t 724 ppb_find_ht_cap(ddi_acc_handle_t cfg_hdl, uint16_t reg_mask, uint16_t reg_val) 725 { 726 uint16_t status, reg; 727 uint8_t ptr, id; 728 729 status = pci_config_get16(cfg_hdl, PCI_CONF_STAT); 730 if (status == 0xffff || !((status & PCI_STAT_CAP))) 731 return (PCI_CAP_NEXT_PTR_NULL); 732 733 ptr = pci_config_get8(cfg_hdl, PCI_CONF_CAP_PTR); 734 while (ptr != 0xFF && 735 ptr != PCI_CAP_NEXT_PTR_NULL && 736 ptr >= PCI_CAP_PTR_OFF) { 737 738 ptr &= PCI_CAP_PTR_MASK; 739 id = pci_config_get8(cfg_hdl, ptr + PCI_CAP_ID); 740 741 if (id == PCI_CAP_ID_HT) { 742 reg = pci_config_get16(cfg_hdl, 743 ptr + PCI_CAP_ID_REGS_OFF); 744 if ((reg & reg_mask) == reg_val) 745 return (ptr); 746 } 747 ptr = pci_config_get8(cfg_hdl, ptr + PCI_CAP_NEXT_PTR); 748 } 749 750 return (PCI_CAP_NEXT_PTR_NULL); 751 } 752 753 754 static boolean_t 755 ppb_ht_msimap_check(ddi_acc_handle_t cfg_hdl) 756 { 757 uint8_t ptr; 758 759 ptr = ppb_find_ht_cap(cfg_hdl, 760 PCI_CAP_HT_MSIMAP_TYPE_MASK | PCI_CAP_HT_MSIMAP_ENABLE_MASK, 761 PCI_CAP_HT_MSIMAP_TYPE | PCI_CAP_HT_MSIMAP_ENABLE); 762 763 if (ptr == PCI_CAP_NEXT_PTR_NULL) 764 return (B_FALSE); 765 766 return (B_TRUE); 767 } 768 769 770 static int 771 ppb_ht_msimap_set(ddi_acc_handle_t cfg_hdl, int cmd) 772 { 773 uint8_t ptr; 774 uint16_t reg; 775 776 ptr = ppb_find_ht_cap(cfg_hdl, PCI_CAP_HT_MSIMAP_TYPE_MASK, 777 PCI_CAP_HT_MSIMAP_TYPE); 778 if (ptr == PCI_CAP_NEXT_PTR_NULL) 779 return (0); 780 781 reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF); 782 switch (cmd) { 783 case HT_MSIMAP_ENABLE: 784 reg |= PCI_CAP_HT_MSIMAP_ENABLE; 785 break; 786 case HT_MSIMAP_DISABLE: 787 default: 788 reg &= ~(uint16_t)PCI_CAP_HT_MSIMAP_ENABLE; 789 } 790 791 pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg); 792 return (1); 793 } 794 795 796 /* 797 * intercept certain interrupt services to handle special cases 798 */ 799 static int 800 ppb_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 801 ddi_intr_handle_impl_t *hdlp, void *result) 802 { 803 ddi_acc_handle_t cfg_hdl; 804 int rv = DDI_SUCCESS; 805 806 if (intr_op != DDI_INTROP_SUPPORTED_TYPES) 807 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 808 809 DDI_INTR_NEXDBG((CE_CONT, 810 "ppb_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 811 (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 812 813 /* Fixed interrupt is supported by default */ 814 *(int *)result = DDI_INTR_TYPE_FIXED; 815 816 if (ppb_support_msi == -1) { 817 DDI_INTR_NEXDBG((CE_CONT, 818 "ppb_intr_ops: MSI is not allowed\n")); 819 goto OUT; 820 } 821 822 if (ppb_support_msi == 1) { 823 DDI_INTR_NEXDBG((CE_CONT, 824 "ppb_intr_ops: MSI is always allowed\n")); 825 rv = i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result); 826 goto OUT; 827 } 828 829 if (pci_config_setup(pdip, &cfg_hdl) != DDI_SUCCESS) { 830 DDI_INTR_NEXDBG((CE_CONT, 831 "ppb_intr_ops: pci_config_setup() failed\n")); 832 goto OUT; 833 } 834 835 /* 836 * check for hypertransport msi mapping capability 837 */ 838 if (ppb_ht_msimap_check(cfg_hdl)) { 839 DDI_INTR_NEXDBG((CE_CONT, 840 "ppb_intr_ops: HT MSI mapping enabled\n")); 841 rv = i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result); 842 } 843 844 /* 845 * if we add failure conditions after pci_config_setup, move this to 846 * OUT and use an extra flag to indicate the need to teardown cfg_hdl 847 */ 848 pci_config_teardown(&cfg_hdl); 849 850 OUT: 851 DDI_INTR_NEXDBG((CE_CONT, 852 "ppb_intr_ops: rdip 0x%p, returns supported types: 0x%x\n", 853 (void *)rdip, *(int *)result)); 854 return (rv); 855 } 856 857 static int 858 ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp) 859 { 860 return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp)); 861 } 862 863 static int 864 ppb_close(dev_t dev, int flags, int otyp, cred_t *credp) 865 { 866 return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp)); 867 } 868 869 static int 870 ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 871 { 872 return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, credp, 873 rvalp)); 874 } 875 876 static int 877 ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 878 int flags, char *name, caddr_t valuep, int *lengthp) 879 { 880 return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, 881 name, valuep, lengthp)); 882 } 883 884 static int 885 ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 886 { 887 return (pcihp_info(dip, cmd, arg, result)); 888 } 889 890 /*ARGSUSED*/ 891 static int 892 ppb_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap, 893 ddi_iblock_cookie_t *ibc) 894 { 895 ppb_devstate_t *ppb = ddi_get_soft_state(ppb_state, 896 ddi_get_instance(dip)); 897 898 ASSERT(ibc != NULL); 899 *ibc = ppb->ppb_fm_ibc; 900 901 return (ppb->ppb_fmcap); 902 } 903 904 /*ARGSUSED*/ 905 static int 906 ppb_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used) 907 { 908 ppb_devstate_t *ppb = ddi_get_soft_state(ppb_state, 909 ddi_get_instance(dip)); 910 911 mutex_enter(&ppb->ppb_err_mutex); 912 pci_ereport_post(dip, derr, NULL); 913 mutex_exit(&ppb->ppb_err_mutex); 914 return (derr->fme_status); 915 } 916