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